[
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]\npatreon: # Replace with a single Patreon username\nopen_collective: # Replace with a single Open Collective username\nko_fi: # Replace with a single Ko-fi username\ntidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel\ncommunity_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry\nliberapay: # Replace with a single Liberapay username\nissuehunt: # Replace with a single IssueHunt username\notechie: # Replace with a single Otechie username\ncustom: ['https://www.xuxueli.com/page/donate.html']  # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE",
    "content": "Please answer some questions before submitting your issue. Thanks!\n\n### Which version of XXL-JOB do you using?\n\n### Expected behavior\n\n### Actual behavior\n\n### Steps to reproduce the behavior\n\n### Other information"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE",
    "content": "**What kind of change does this PR introduce?** (check at least one)\n\n- [ ] Bugfix\n- [ ] Feature\n- [ ] Code style update\n- [ ] Refactor\n- [ ] Build-related changes\n- [ ] Other, please describe:\n\n\n**The description of the PR:**\n\n\n**Other information:**"
  },
  {
    "path": ".github/workflows/maven.yml",
    "content": "name: Java CI\n\non:\n  push:\n    branches: [ \"master\" ]\n  pull_request:\n    branches: [ \"master\" ]\n\njobs:\n  build:\n\n    runs-on: ubuntu-latest\n\n    steps:\n      - uses: actions/checkout@v4\n      - name: Set up JDK 17\n        uses: actions/setup-java@v4\n        with:\n          java-version: '17'\n          distribution: 'temurin'\n          cache: maven\n      - name: Build with Maven\n        run: mvn -B package --file pom.xml\n"
  },
  {
    "path": ".gitignore",
    "content": ".idea\n.classpath\n.project\n*.iml\ntarget/\n.DS_Store\n.gitattributes\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    {project}  Copyright (C) {year}  {fullname}\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": "NOTICE",
    "content": "Copyright (c) 2015-present, xuxueli.\n\nDependencies:\n================================================================\n\nSpring:\n\n  * LICENSE:\n    * http://www.apache.org/licenses/LICENSE-2.0 (Apache License 2.0)\n  * HOMEPAGE:\n    * http://www.springsource.org\n\nNetty:\n\n  * LICENSE:\n    * http://www.apache.org/licenses/LICENSE-2.0 (Apache License 2.0)\n  * HOMEPAGE:\n    * https://github.com/netty/netty\n\nMybatis:\n\n  * LICENSE:\n    * http://www.apache.org/licenses/LICENSE-2.0 (Apache License 2.0)\n  * HOMEPAGE:\n    * https://mybatis.org/mybatis-3/\n\nSLF4J:\n\n  * LICENSE:\n    * http://www.apache.org/licenses/LICENSE-2.0 (Apache License 2.0)\n  * HOMEPAGE:\n    * http://www.slf4j.org\n"
  },
  {
    "path": "README.md",
    "content": "<p align=\"center\" >\n    <img src=\"https://www.xuxueli.com/doc/static/xxl-job/images/xxl-logo.jpg\" width=\"150\">\n    <h3 align=\"center\">XXL-JOB</h3>\n    <p align=\"center\">\n        XXL-JOB, a distributed task scheduling framework.\n        <br>\n        <a href=\"https://www.xuxueli.com/xxl-job/\"><strong>-- Home Page --</strong></a>\n        <br>\n        <br>\n        <a href=\"https://github.com/xuxueli/xxl-job/actions\">\n            <img src=\"https://github.com/xuxueli/xxl-job/workflows/Java%20CI/badge.svg\" >\n        </a>\n        <a href=\"https://central.sonatype.com/artifact/com.xuxueli/xxl-job-core\">\n            <img src=\"https://img.shields.io/maven-central/v/com.xuxueli/xxl-job-core\" >\n        </a>\n        <a href=\"https://github.com/xuxueli/xxl-job/releases\">\n         <img src=\"https://img.shields.io/github/release/xuxueli/xxl-job.svg\" >\n        </a>\n        <a href=\"https://github.com/xuxueli/xxl-job/\">\n            <img src=\"https://img.shields.io/github/stars/xuxueli/xxl-job\" >\n        </a>\n        <a href=\"https://hub.docker.com/r/xuxueli/xxl-job-admin/\">\n            <img src=\"https://img.shields.io/docker/pulls/xuxueli/xxl-job-admin\" >\n        </a>\n        <a href=\"http://www.gnu.org/licenses/gpl-3.0.html\">\n         <img src=\"https://img.shields.io/badge/license-GPLv3-blue.svg\" >\n        </a>\n        <a href=\"https://www.xuxueli.com/page/donate.html\">\n           <img src=\"https://img.shields.io/badge/%24-donate-ff69b4.svg?style=flat\" >\n        </a>\n    </p>\n</p>\n\n\n## Introduction\nXXL-JOB is a distributed task scheduling framework. \nIt's core design goal is to develop quickly and learn simple, lightweight, and easy to expand. \nNow, it's already open source, and many companies use it in production environments, real \"out-of-the-box\".\n\nXXL-JOB是一个分布式任务调度平台，其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线，开箱即用。\n\n\n## Sponsor\nXXL-JOB is an open source and free project, with its ongoing development made possible entirely by the support of these awesome backers.\n\nXXL-JOB 是一个开源且免费项目，其正在进行的开发完全得益于支持者的支持。开源不易，[前往赞助项目开发](https://www.xuxueli.com/page/donate.html )\n\n<!-- supporter start -->\n<h3 style=\"color: #E6BE8A;\" >金牌赞助方</h3>\n<table>\n<tr>\n    <td>\n        <a href=\"https://www.aliyun.com/product/aliware/mse?utm_content=g_1000401794\" title=\"\" target=\"_blank\" >\n            <img width=\"150px\" src=\"http://www.xuxueli.com/page/static/images/logo_aliyun2.png\" >\n            <br>\n            <span style=\"text-decoration:underline;color: #E6BE8A;\" >阿里云 提供云上托管 XXL-JOB</span>\n        </a>\n    </td>\n    <td>\n        <a href=\"https://www.mall4j.com/cn/?statId=10\" title=\"\" target=\"_blank\" >\n            <img width=\"150px\" src=\"http://www.xuxueli.com/page/static/images/logo_mail4j.png\" >\n        </a>\n    </td>\n</tr>\n</table>\n<!-- supporter end -->\n\n\n## Documentation\n- [中文文档](https://www.xuxueli.com/xxl-job/)\n- [English Documentation](https://www.xuxueli.com/xxl-job/en/)\n\n\n## Communication    \n- [社区交流](https://www.xuxueli.com/page/community.html)\n\n\n## Features\n- 1、简单：支持通过Web页面对任务进行CRUD操作，操作简单，一分钟上手；\n- 2、动态：支持动态修改任务状态、启动/停止任务，以及终止运行中任务，即时生效；\n- 3、调度中心HA（中心式）：调度采用中心式设计，“调度中心”自研调度组件并支持集群部署，可保证调度中心HA；\n- 4、执行器HA（分布式）：任务分布式执行，任务\"执行器\"支持集群部署，可保证任务执行HA；\n- 5、注册中心: 执行器会周期性自动注册任务, 调度中心将会自动发现注册的任务并触发执行。同时，也支持手动录入执行器地址；\n- 6、弹性扩容缩容：一旦有新执行器机器上线或者下线，下次调度时将会重新分配任务；\n- 7、触发策略：提供丰富的任务触发策略，包括：Cron触发、固定间隔触发、固定延时触发、API（事件）触发、人工触发、父子任务触发；\n- 8、调度过期策略：调度中心错过调度时间的补偿处理策略，包括：忽略、立即补偿触发一次等；\n- 9、阻塞处理策略：调度过于密集执行器来不及处理时的处理策略，策略包括：单机串行（默认）、丢弃后续调度、覆盖之前调度；\n- 10、任务超时控制：支持自定义任务超时时间，任务运行超时将会主动中断任务；\n- 11、任务失败重试：支持自定义任务失败重试次数，当任务失败时将会按照预设的失败重试次数主动进行重试；其中分片任务支持分片粒度的失败重试；\n- 12、任务失败告警；默认提供邮件方式失败告警，同时预留扩展接口，可方便的扩展短信、钉钉等告警方式；\n- 13、路由策略：执行器集群部署时提供丰富的路由策略，包括：第一个、最后一个、轮询、随机、一致性HASH、最不经常使用、最近最久未使用、故障转移、忙碌转移等；\n- 14、分片广播任务：执行器集群部署时，任务路由策略选择\"分片广播\"情况下，一次任务调度将会广播触发集群中所有执行器执行一次任务，可根据分片参数开发分片任务；\n- 15、动态分片：分片广播任务以执行器为维度进行分片，支持动态扩容执行器集群从而动态增加分片数量，协同进行业务处理；在进行大数据量业务操作时可显著提升任务处理能力和速度。\n- 16、故障转移：任务路由策略选择\"故障转移\"情况下，如果执行器集群中某一台机器故障，将会自动Failover切换到一台正常的执行器发送调度请求。\n- 17、任务进度监控：支持实时监控任务进度；\n- 18、Rolling实时日志：支持在线查看调度结果，并且支持以Rolling方式实时查看执行器输出的完整的执行日志；\n- 19、GLUE：提供Web IDE，支持在线开发任务逻辑代码，动态发布，实时编译生效，省略部署上线的过程。支持30个版本的历史版本回溯。\n- 20、脚本任务：支持以GLUE模式开发和运行脚本任务，包括Shell、Python、NodeJS、PHP、PowerShell等类型脚本;\n- 21、命令行任务：原生提供通用命令行任务Handler（Bean任务，\"CommandJobHandler\"）；业务方只需要提供命令行即可；\n- 22、任务依赖：支持配置子任务依赖，当父任务执行结束且执行成功后将会主动触发一次子任务的执行, 多个子任务用逗号分隔；\n- 23、一致性：“调度中心”通过DB锁保证集群分布式调度的一致性, 一次任务调度只会触发一次执行；\n- 24、自定义任务参数：支持在线配置调度任务入参，即时生效；\n- 25、调度线程池：调度系统多线程触发调度运行，确保调度精确执行，不被堵塞；\n- 26、数据加密：调度中心和执行器之间的通讯进行数据加密，提升调度信息安全性；\n- 27、邮件报警：任务失败时支持邮件报警，支持配置多邮件地址群发报警邮件；\n- 28、推送maven中央仓库: 将会把最新稳定版推送到maven中央仓库, 方便用户接入和使用;\n- 29、运行报表：支持实时查看运行数据，如任务数量、调度次数、执行器数量等；以及调度报表，如调度日期分布图，调度成功分布图等；\n- 30、全异步：任务调度流程全异步化设计实现，如异步调度、异步运行、异步回调等，有效对密集调度进行流量削峰，理论上支持任意时长任务的运行；\n- 31、跨语言/OpenAPI：调度中心与执行器提供语言无关的 OpenApi（RESTful 格式），第三方任意语言可据此对接调度中心或者实现执行器，实现多语言支持。除此之外，还提供了 “多任务模式”和“httpJobHandler”等其他跨语言方案；\n- 32、国际化：调度中心支持国际化设置，提供中文、英文两种可选语言，默认为中文；\n- 33、容器化：提供官方docker镜像，并实时更新推送dockerhub，进一步实现产品开箱即用；\n- 34、线程池隔离：调度线程池进行隔离拆分，慢任务自动降级进入\"Slow\"线程池，避免耗尽调度线程，提高系统稳定性；\n- 35、用户管理：支持在线管理系统用户，存在管理员、普通用户两种角色；\n- 36、权限控制：执行器维度进行权限控制，管理员拥有全量权限，普通用户需要分配执行器权限后才允许相关操作；\n- 37、AI任务：原生提供AI执行器，并内置多个AI任务Handler，与spring-ai、ollama、dify等集成打通，支持快速开发AI类任务。\n- 38、审计日志：记录任务操作敏感信息，用于系统监控、审计和安全分析，可快速追溯异常行为以及定位排查问题。\n- 39、优雅停机：调度中心停机，检测时间轮非空时主动等待调度完成；客户端停机，检测存在运行中任务时，停止接收新任务并主动等待任务执行完成；\n\n## Development\n于2015年中，我在github上创建XXL-JOB项目仓库并提交第一个commit，随之进行系统结构设计，UI选型，交互设计……\n\n于2015-11月，XXL-JOB终于RELEASE了第一个大版本V1.0， 随后我将之发布到OSCHINA，XXL-JOB在OSCHINA上获得了@红薯的热门推荐，同期分别达到了OSCHINA的“热门动弹”排行第一和git.oschina的开源软件月热度排行第一，在此特别感谢红薯，感谢大家的关注和支持。\n\n于2015-12月，我将XXL-JOB发表到我司内部知识库，并且得到内部同事认可。\n\n于2016-01月，我司展开XXL-JOB的内部接入和定制工作，在此感谢袁某和尹某两位同事的贡献，同时也感谢内部其他给与关注与支持的同事。\n\n于2017-05-13，在上海举办的 \"[第62期开源中国源创会](https://www.oschina.net/event/2236961)\" 的 \"放码过来\" 环节，我登台对XXL-JOB做了演讲，台下五百位在场观众反响热烈（[图文回顾](https://www.oschina.net/question/2686220_2242120) ）。\n\n于2017-10-22，又拍云 Open Talk 联合 Spring Cloud 中国社区举办的 \"[进击的微服务实战派上海站](https://opentalk.upyun.com/303.html)\"，我登台对XXL-JOB做了演讲，现场观众反响热烈并在会后与XXL-JOB用户热烈讨论交流。\n\n于2017-12-11，XXL-JOB有幸参会《[InfoQ ArchSummit全球架构师峰会](http://bj2017.archsummit.com/)》，并被拍拍贷架构总监\"杨波老师\"在专题 \"[微服务原理、基础架构和开源实践](http://bj2017.archsummit.com/training/2)\" 中现场介绍。\n\n于2017-12-18，XXL-JOB参与\"[2017年度最受欢迎中国开源软件](http://www.oschina.net/project/top_cn_2017?sort=1)\"评比，在当时已录入的约九千个国产开源项目中角逐，最终进入了前30强。\n\n于2018-01-15，XXL-JOB参与\"[2017码云最火开源项目](https://www.oschina.net/news/92438/2017-mayun-top-50)\"评比，在当时已录入的约六千五百个码云项目中角逐，最终进去了前20强。\n\n于2018-04-14，iTechPlus在上海举办的 \"[2018互联网开发者大会](http://www.itdks.com/eventlist/detail/2065)\"，我登台对XXL-JOB做了演讲，现场观众反响热烈并在会后与XXL-JOB用户热烈讨论交流。\n\n于2018-05-27，在上海举办的 \"[第75期开源中国源创会](https://www.oschina.net/event/2278742)\" 的 \"架构\" 主题专场，我登台进行“基础架构与中间件图谱”主题演讲，台下上千位在场观众反响热烈（[图文回顾](https://www.oschina.net/question/3802184_2280606) ）。\n\n于2018-12-05，XXL-JOB参与\"[2018年度最受欢迎中国开源软件](https://www.oschina.net/project/top_cn_2018?sort=1)\"评比，在当时已录入的一万多个开源项目中角逐，最终排名第19名。\n\n于2019-12-10，XXL-JOB参与\"[2019年度最受欢迎中国开源软件](https://www.oschina.net/project/top_cn_2019)\"评比，在当时已录入的一万多个开源项目中角逐，最终排名\"开发框架和基础组件类\"第9名。\n\n于2020-11-16，XXL-JOB参与\"[2020年度最受欢迎中国开源软件](https://www.oschina.net/project/top_cn_2020)\"评比，在当时已录入的一万多个开源项目中角逐，最终排名\"开发框架和基础组件类\"第8名。\n\n于2021-12-06，XXL-JOB参与\"[2021年度OSC中国开源项目评选](https://www.oschina.net/project/top_cn_2021) \"评比，在当时已录入的一万多个开源项目中角逐，最终当选\"最受欢迎项目\"。\n\n于2024-11-06，XXL-JOB经 GitCode 官方评审，获得 “G-Star项目毕业认证”。\n\n> 我司大众点评目前已接入XXL-JOB，内部别名《Ferrari》（Ferrari基于XXL-JOB的V1.1版本定制而成，新接入应用推荐升级最新版本）。\n据最新统计, 自2016-01-21接入至2017-12-01期间，该系统已调度约100万次，表现优异。新接入应用推荐使用最新版本，因为经过数十个版本的更新，系统的任务模型、UI交互模型以及底层调度通讯模型都有了较大的优化和提升，核心功能更加稳定高效。\n\n至今，XXL-JOB已接入多家公司的线上产品线，接入场景如电商业务，O2O业务和大数据作业等，截止最新统计时间为止，XXL-JOB已接入的公司包括不限于：\n    \n\t- 1、大众点评【美团点评】\n\t- 2、山东学而网络科技有限公司；\n\t- 3、安徽慧通互联科技有限公司；\n\t- 4、人人聚财金服；\n\t- 5、上海棠棣信息科技股份有限公司\n\t- 6、运满满【运满满】\n\t- 7、米其林 (中国区)【米其林】\n\t- 8、妈妈联盟\n\t- 9、九樱天下（北京）信息技术有限公司\n\t- 10、万普拉斯科技有限公司【一加手机】\n\t- 11、上海亿保健康管理有限公司\n\t- 12、海尔馨厨【海尔】\n\t- 13、河南大红包电子商务有限公司\n\t- 14、成都顺点科技有限公司\n\t- 15、深圳市怡亚通\n\t- 16、深圳麦亚信科技股份有限公司\n\t- 17、上海博莹科技信息技术有限公司\n\t- 18、中国平安科技有限公司【中国平安】\n\t- 19、杭州知时信息科技有限公司\n\t- 20、博莹科技（上海）有限公司\n\t- 21、成都依能股份有限责任公司\n\t- 22、湖南高阳通联信息技术有限公司\n\t- 23、深圳市邦德文化发展有限公司\n\t- 24、福建阿思可网络教育有限公司\n\t- 25、优信二手车【优信】\n\t- 26、上海悠游堂投资发展股份有限公司【悠游堂】\n\t- 27、北京粉笔蓝天科技有限公司\n\t- 28、中秀科技(无锡)有限公司\n\t- 29、武汉空心科技有限公司\n\t- 30、北京蚂蚁风暴科技有限公司\n\t- 31、四川互宜达科技有限公司\n\t- 32、钱包行云（北京）科技有限公司\n\t- 33、重庆欣才集团\n    - 34、咪咕互动娱乐有限公司【中国移动】\n    - 35、北京诺亦腾科技有限公司\n    - 36、增长引擎(北京)信息技术有限公司\n    - 37、北京英贝思科技有限公司\n    - 38、刚泰集团\n    - 39、深圳泰久信息系统股份有限公司\n    - 40、随行付支付有限公司\n    - 41、广州瀚农网络科技有限公司\n    - 42、享点科技有限公司\n    - 43、杭州比智科技有限公司\n    - 44、圳临界线网络科技有限公司\n    - 45、广州知识圈网络科技有限公司\n    - 46、国誉商业上海有限公司\n    - 47、海尔消费金融有限公司，嗨付、够花【海尔】\n    - 48、广州巴图鲁信息科技有限公司\n    - 49、深圳市鹏海运电子数据交换有限公司\n    - 50、深圳市亚飞电子商务有限公司\n    - 51、上海趣医网络有限公司\n    - 52、聚金资本\n    - 53、北京父母邦网络科技有限公司\n    - 54、中山元赫软件科技有限公司\n    - 55、中商惠民(北京)电子商务有限公司\n    - 56、凯京集团\n    - 57、华夏票联（北京）科技有限公司\n    - 58、拍拍贷【拍拍贷】\n    - 59、北京尚德机构在线教育有限公司\n    - 60、任子行股份有限公司\n    - 61、北京时态电子商务有限公司\n    - 62、深圳卷皮网络科技有限公司\n    - 63、北京安博通科技股份有限公司\n    - 64、未来无线网\n    - 65、厦门瓷禧网络有限公司\n    - 66、北京递蓝科软件股份有限公司\n    - 67、郑州创海软件科技公司\n    - 68、北京国槐信息科技有限公司\n    - 69、浪潮软件集团\n    - 70、多立恒(北京)信息技术有限公司\n    - 71、广州极迅客信息科技有限公司\n    - 72、赫基（中国）集团股份有限公司\n    - 73、海投汇\n    - 74、上海润益创业孵化器管理股份有限公司\n    - 75、汉纳森（厦门）数据股份有限公司\n    - 76、安信信托\n    - 77、岚儒财富\n    - 78、捷道软件\n    - 79、湖北享七网络科技有限公司\n    - 80、湖南创发科技责任有限公司\n    - 81、深圳小安时代互联网金融服务有限公司\n    - 82、湖北享七网络科技有限公司\n    - 83、钱包行云(北京)科技有限公司\n    - 84、360金融【360】\n    - 85、易企秀\n    - 86、摩贝（上海）生物科技有限公司\n    - 87、广东芯智慧科技有限公司\n    - 88、联想集团【联想】\n    - 89、怪兽充电\n    - 90、行圆汽车\n    - 91、深圳店店通科技邮箱公司\n    - 92、京东【京东】\n    - 93、米庄理财\n    - 94、咖啡易融\n    - 95、梧桐诚选\n    - 96、恒大地产【恒大】\n    - 97、昆明龙慧\n    - 98、上海涩瑶软件\n    - 99、易信【网易】\n    - 100、铜板街\n    - 101、杭州云若网络科技有限公司\n    - 102、特百惠（中国）有限公司\n    - 103、常山众卡运力供应链管理有限公司\n    - 104、深圳立创电子商务有限公司\n    - 105、杭州智诺科技股份有限公司\n    - 106、北京云漾信息科技有限公司\n    - 107、深圳市多银科技有限公司\n    - 108、亲宝宝\n    - 109、上海博卡软件科技有限公司\n    - 110、智慧树在线教育平台\n    - 111、米族金融\n    - 112、北京辰森世纪\n    - 113、云南滇医通\n    - 114、广州市分领网络科技有限责任公司\n    - 115、浙江微能科技有限公司\n    - 116、上海馨飞电子商务有限公司\n    - 117、上海宝尊电子商务有限公司\n    - 118、直客通科技技术有限公司\n    - 119、科度科技有限公司\n    - 120、上海数慧系统技术有限公司\n    - 121、我的医药网\n    - 122、多粉平台\n    - 123、铁甲二手机\n    - 124、上海海新得数据技术有限公司\n    - 125、深圳市珍爱网信息技术有限公司【珍爱网】\n    - 126、小蜜蜂\n    - 127、吉荣数科技\n    - 128、上海恺域信息科技有限公司\n    - 129、广州荔支网络有限公司【荔枝FM】\n    - 130、杭州闪宝科技有限公司\n    - 131、北京互联新网科技发展有限公司\n    - 132、誉道科技\n    - 133、山西兆盛房地产开发有限公司\n    - 134、北京蓝睿通达科技有限公司\n    - 135、月亮小屋（中国）有限公司【蓝月亮】\n    - 136、青岛国瑞信息技术有限公司\n    - 137、博雅云计算（北京）有限公司\n    - 138、华泰证券香港子公司\n    - 139、杭州东方通信软件技术有限公司\n    - 140、武汉博晟安全技术股份有限公司\n    - 141、深圳市六度人和科技有限公司\n    - 142、杭州趣维科技有限公司（小影）\n    - 143、宁波单车侠之家科技有限公司【单车侠】\n    - 144、丁丁云康信息科技（北京）有限公司\n    - 145、云钱袋\n    - 146、南京中兴力维\n    - 147、上海矽昌通信技术有限公司\n    - 148、深圳萨科科技\n    - 149、中通服创立科技有限责任公司\n    - 150、深圳市对庄科技有限公司\n    - 151、上证所信息网络有限公司\n    - 152、杭州火烧云科技有限公司【婚礼纪】\n    - 153、天津青芒果科技有限公司【芒果头条】\n    - 154、长飞光纤光缆股份有限公司\n    - 155、世纪凯歌（北京）医疗科技有限公司\n    - 156、浙江霖梓控股有限公司\n    - 157、江西腾飞网络技术有限公司\n    - 158、安迅物流有限公司\n    - 159、肉联网\n    - 160、北京北广梯影广告传媒有限公司\n    - 161、上海数慧系统技术有限公司\n    - 162、大志天成\n    - 163、上海云鹊医\n    - 164、上海云鹊医\n    - 165、墨迹天气【墨迹天气】\n    - 166、上海逸橙信息科技有限公司\n    - 167、沅朋物联\n    - 168、杭州恒生云融网络科技有限公司\n    - 169、绿米联创\n    - 170、重庆易宠科技有限公司\n    - 171、安徽引航科技有限公司（乐职网）\n    - 172、上海数联医信企业发展有限公司\n    - 173、良彬建材\n    - 174、杭州求是同创网络科技有限公司\n    - 175、荷马国际\n    - 176、点雇网\n    - 177、深圳市华星光电技术有限公司\n    - 178、厦门神州鹰软件科技有限公司\n    - 179、深圳市招商信诺人寿保险有限公司\n    - 180、上海好屋网信息技术有限公司\n    - 181、海信集团【海信】\n    - 182、信凌可信息科技（上海）有限公司\n    - 183、长春天成科技发展有限公司\n    - 184、用友金融信息技术股份有限公司【用友】\n    - 185、北京咖啡易融有限公司\n    - 186、国投瑞银基金管理有限公司\n    - 187、晋松(上海)网络信息技术有限公司\n    - 188、深圳市随手科技有限公司【随手记】\n    - 189、深圳水务科技有限公司\n    - 190、易企秀【易企秀】\n    - 191、北京磁云科技\n    - 192、南京蜂泰互联网科技有限公司\n    - 193、章鱼直播\n    - 194、奖多多科技\n    - 195、天津市神州商龙科技股份有限公司\n    - 196、岩心科技\n    - 197、车码科技（北京）有限公司\n    - 198、贵阳市投资控股集团\n    - 199、康旗股份\n    - 200、龙腾出行\n    - 201、杭州华量软件\n    - 202、合肥顶岭医疗科技有限公司\n    - 203、重庆表达式科技有限公司\n    - 204、上海米道信息科技有限公司\n    - 205、北京益友会科技有限公司\n    - 206、北京融贯电子商务有限公司\n    - 207、中国外汇交易中心\n    - 208、中国外运股份有限公司\n    - 209、中国上海晓圈教育科技有限公司\n    - 210、普联软件股份有限公司\n    - 211、北京科蓝软件股份有限公司\n    - 212、江苏斯诺物联科技有限公司\n    - 213、北京搜狐-狐友【搜狐】\n    - 214、新大陆网商金融\n    - 215、山东神码中税信息科技有限公司\n    - 216、河南汇顺网络科技有限公司\n    - 217、北京华夏思源科技发展有限公司\n    - 218、上海东普信息科技有限公司\n    - 219、上海鸣勃网络科技有限公司\n    - 220、广东学苑教育发展有限公司\n    - 221、深圳强时科技有限公司\n    - 222、上海云砺信息科技有限公司\n    - 223、重庆愉客行网络有限公司\n    - 224、数云\n    - 225、国家电网运检部\n    - 226、杭州找趣\n    - 227、浩鲸云计算科技股份有限公司\n    - 228、科大讯飞【科大讯飞】\n    - 229、杭州行装网络科技有限公司\n    - 230、即有分期金融\n    - 231、深圳法司德信息科技有限公司\n    - 232、上海博复信息科技有限公司\n    - 233、杭州云嘉云计算有限公司\n    - 234、有家民宿(有家美宿)\n    - 235、北京赢销通软件技术有限公司\n    - 236、浙江聚有财金融服务外包有限公司\n    - 237、易族智汇(北京)科技有限公司\n    - 238、合肥顶岭医疗科技开发有限公司\n    - 239、车船宝(深圳)旭珩科技有限公司)\n    - 240、广州富力地产有限公司\n    - 241、氢课（上海）教育科技有限公司\n    - 242、武汉氪细胞网络技术有限公司\n    - 243、杭州有云科技有限公司\n    - 244、上海仙豆智能机器人有限公司\n    - 245、拉卡拉支付股份有限公司【拉卡拉】\n    - 246、虎彩印艺股份有限公司\n    - 247、北京数微科技有限公司\n    - 248、广东智瑞科技有限公司\n    - 249、找钢网\n    - 250、九机网\n    - 251、杭州跑跑网络科技有限公司\n    - 252、深圳未来云集\n    - 253、杭州每日给力科技有限公司\n    - 254、上海齐犇信息科技有限公司\n    - 255、滴滴出行【滴滴】\n    - 256、合肥云诊信息科技有限公司\n    - 257、云知声智能科技股份有限公司\n    - 258、南京坦道科技有限公司\n    - 259、爱乐优（二手平台）\n    - 260、猫眼电影（私有化部署）【猫眼电影】\n    - 261、美团大象（私有化部署）【美团大象】\n    - 262、作业帮教育科技（北京）有限公司【作业帮】\n    - 263、北京小年糕互联网技术有限公司\n    - 264、山东矩阵软件工程股份有限公司\n    - 265、陕西国驿软件科技有限公司\n    - 266、君开信息科技\n    - 267、村鸟网络科技有限责任公司\n    - 268、云南国际信托有限公司\n    - 269、金智教育\n    - 270、珠海市筑巢科技有限公司\n    - 271、上海百胜软件股份有限公司\n    - 272、深圳市科盾科技有限公司\n    - 273、哈啰出行【哈啰】\n    - 274、途虎养车【途虎】\n    - 275、卡思优派人力资源集团\n    - 276、南京观为智慧软件科技有限公司\n    - 277、杭州城市大脑科技有限公司\n    - 278、猿辅导【猿辅导】\n    - 279、洛阳健创网络科技有限公司\n    - 280、魔力耳朵\n    - 281、亿阳信通\n    - 282、上海招鲤科技有限公司\n    - 283、四川商旅无忧科技服务有限公司\n    - 284、UU跑腿\n    - 285、北京老虎证券【老虎证券】\n    - 286、悠活省吧（北京）网络科技有限公司\n    - 287、F5未来商店\n    - 288、深圳环阳通信息技术有限公司\n    - 289、遠傳電信\n    - 290、作业帮（北京）教育科技有限公司【作业帮】\n    - 291、成都科鸿智信科技有限公司\n    - 292、北京木屋时代科技有限公司\n    - 293、大学通（哈尔滨）科技有限责任公司\n    - 294、浙江华坤道威数据科技有限公司\n    - 295、吉祥航空【吉祥航空】\n    - 296、南京圆周网络科技有限公司\n    - 297、广州市洋葱omall电子商务\n    - 298、天津联物科技有限公司\n    - 299、跑哪儿科技（北京）有限公司\n    - 300、深圳市美西西餐饮有限公司(喜茶)\n    - 301、平安不动产有限公司【平安】\n    - 302、江苏中海昇物联科技有限公司\n    - 303、湖南牙医帮科技有限公司\n    - 304、重庆民航凯亚信息技术有限公司（易通航）\n    - 305、递易（上海）智能科技有限公司\n    - 306、亚朵\n    - 307、浙江新课堂教育股份有限公司\n    - 308、北京蜂创科技有限公司\n    - 309、德一智慧城市信息系统有限公司\n    - 310、北京翼点科技有限公司\n    - 311、湖南智数新维度信息科技有限公司\n    - 312、北京玖扬博文文化发展有限公司\n    - 313、上海宇珩信息科技有限公司\n    - 314、全景智联（武汉）科技有限公司\n    - 315、天津易客满国际物流有限公司\n    - 316、南京爱福路汽车科技有限公司\n    - 317、我房旅居集团\n    - 318、湛江亲邻科技有限公司\n    - 319、深圳市姜科网络有限公司\n    - 320、青岛日日顺物流有限公司\n    - 321、南京太川信息技术有限公司\n    - 322、美图之家科技有限公司【美图】\n    - 323、南京太川信息技术有限公司\n    - 324、众薪科技（北京）有限公司\n    - 325、武汉安安物联科技有限公司\n    - 326、北京智客朗道网络科技有限公司\n    - 327、深圳市超级猩猩健身管理管理有限公司\n    - 328、重庆达志科技有限公司\n    - 329、上海享评信息科技有限公司\n    - 330、薪得付信息科技\n    - 331、跟谁学\n    - 332、中道（苏州）旅游网络科技有限公司\n    - 333、广州小卫科技有限公司\n    - 334、上海非码网络科技有限公司\n    - 335、途家网网络技术（北京）有限公司【途家】\n    - 336、广州辉凡信息科技有限公司\n    - 337、天维尔信息科技股份有限公司\n    - 338、上海极豆科技有限公司\n    - 339、苏州触达信息技术有限公司\n    - 340、北京热云科技有限公司\n    - 341、中智企服（北京）科技有限公司\n    - 342、易联云计算（杭州）有限责任公司\n    - 343、青岛航空股份有限公司【青岛航空】\n    - 344、山西博睿通科技有限公司\n    - 345、网易杭州网络有限公司【网易】\n    - 346、北京果果乐学科技有限公司\n    - 347、百望股份有限公司\n    - 348、中保金服（深圳）科技有限公司\n    - 349、天津运友物流科技股份有限公司\n    - 350、广东创能科技股份有限公司\n    - 351、上海倚博信息科技有限公司\n    - 352、深圳百果园实业（集团）股份有限公司\n    - 353、广州细刻网络科技有限公司\n    - 354、武汉鸿业众创科技有限公司\n    - 355、金锡科技（广州）有限公司\n    - 356、易瑞国际电子商务有限公司\n    - 357、奇点云\n    - 358、中视信息科技有限公司\n    - 359、开源项目:datax-web\n    - 360、云知声智能科技股份有限公司\n    - 361、开源项目:bboss\n    - 362、成都深驾科技有限公司\n    - 363、FunPlus【趣加】\n    - 364、杭州创匠信科技有限公司\n    - 365、龙匠（北京）科技发展有限公司\n    - 366、广州一链通互联网科技有限公司\n    - 367、上海星艾网络科技有限公司\n    - 368、虎博网络技术(上海)有限公司\n    - 369、青岛优米信息技术有限公司\n    - 370、八维通科技有限公司\n    - 371、烟台合享智星数据科技有限公司\n    - 372、东吴证券股份有限公司\n    - 373、中通云仓股份有限公司【中通】\n    - 374、北京加菲猫科技有限公司\n    - 375、北京匠心演绎科技有限公司\n    - 376、宝贝走天下\n    - 377、厦门众库科技有限公司\n    - 378、海通证券数据中心\n    - 389、湖南快乐通宝小额贷款有限公司\n    - 380、浙江大华技术股份有限公司\n    - 381、杭州魔筷科技有限公司\n    - 382、青岛掌讯通区块链科技有限公司\n    - 383、新大陆金融科技\n    - 384、常州玺拓软件科技有限公司\n    - 385、北京正保网格教育科技有限公司\n    - 386、统一企业（中国）投资有限公司【统一】\n    - 387、微革网络科技有限公司\n    - 388、杭州融易算科技有限公司\n    - 399、青岛上啥班网络科技有限公司\n    - 390、京东酒世界\n    - 391、杭州爱博仕科技有限公司\n    - 392、五星金服控股有限公司\n    - 393、福建乐摩物联科技有限公司\n    - 394、百炼智能科技有限公司\n    - 395、山东能源数智云科技有限公司\n    - 396、招商局能源运输股份有限公司\n    - 397、三一集团【三一】\n    - 398、东巴文（深圳）健康管理有限公司\n    - 399、索易软件\n    - 400、深圳市宁远科技有限公司\n    - 401、熙牛医疗\n    - 402、南京智鹤电子科技有限公司\n    - 403、嘀嗒出行【嘀嗒出行】\n    - 404、广州虎牙信息科技有限公司【虎牙】\n    - 405、广州欧莱雅百库网络科技有限公司【欧莱雅】\n    - 406、微微科技有限公司\n    - 407、我爱我家房地产经纪有限公司【我爱我家】\n    - 408、九号发现\n    - 409、薪人薪事\n    - 410、武汉氪细胞网络技术有限公司\n    - 411、广州市斯凯奇商业有限公司\n    - 412、微淼商学院\n    - 413、杭州车盛科技有限公司\n    - 414、深兰科技（上海）有限公司\n    - 415、安徽中科美络信息技术有限公司\n    - 416、比亚迪汽车工业有限公司【比亚迪】\n    - 417、湖南小桔信息技术有限公司\n    - 418、安徽科大国创软件科技有限公司\n    - 419、克而瑞\n    - 420、陕西云基华海信息技术有限公司\n    - 421、安徽深宁科技有限公司\n    - 422、广东康爱多数字健康有限公司\n    - 423、嘉里电子商务\n    - 424、上海时代光华教育发展有限公司\n    - 425、CityDo\n    - 426、上海禹知信息科技有限公司\n    - 427、广东智瑞科技有限公司\n    - 428、西安爱铭网络科技有限公司\n    - 429、心医国际数字医疗系统(大连)有限公司\n    - 430、乐其电商\n    - 431、锐达科技\n    - 432、天津长城滨银汽车金融有限公司\n    - 433、代码网\n    - 434、东莞市东城乔伦软件开发工作室\n    - 435、浙江百应科技有限公司\n    - 436、上海力爱帝信息技术有限公司(Red E)\n    - 437、云徙科技有限公司\n    - 438、北京康智乐思网络科技有限公司【大姨吗APP】\n    - 439、安徽开元瞬视科技有限公司\n    - 440、立方\n    - 441、厦门纵行科技\n    - 442、乐山-菲尼克斯半导体有限公司\n    - 443、武汉光谷联合集团有限公司\n    - 444、上海金仕达软件科技有限公司\n    - 445、深圳易世通达科技有限公司\n    - 446、爱动超越人工智能科技（北京）有限责任公司\n    - 447、迪普信（北京）科技有限公司\n    - 448、掌站科技（北京）有限公司\n    - 449、深圳市华云中盛股份有限公司\n    - 450、上海原圈科技有限公司\n    - 451、广州赞赏信息科技有限公司\n    - 452、Amber Group\n    - 453、德威国际货运代理（上海）公司\n    - 454、浙江杰夫兄弟智慧科技有限公司\n    - 455、信也科技\n    - 456、开思时代科技（深圳）有限公司\n    - 457、大连槐德科技有限公司\n    - 458、同程生活\n    - 459、松果出行\n    - 460、企鹅杏仁集团\n    - 461、宁波科云信息科技有限公司\n    - 462、上海格蓝威驰信息科技有限公司\n    - 463、杭州趣淘鲸科技有限公司\n    - 464、湖州市数字惠民科技有限公司\n    - 465、乐普（北京）医疗器械股份有限公司\n    - 466、广州市晴川高新技术开发有限公司\n    - 467、山西缇客科技有限公司\n    - 468、徐州卡西穆电子商务有限公司\n    - 469、格创东智科技有限公司\n    - 470、世纪龙信息网络有限责任公司\n    - 471、邦道科技有限公司\n    - 472、河南中盟新云科技股份有限公司\n    - 473、横琴人寿保险有限公司\n    - 474、上海海隆华钟信息技术有限公司\n    - 475、上海久湛\n    - 476、上海仙豆智能机器人有限公司\n    - 477、广州汇尚网络科技有限公司\n    - 478、深圳市阿卡索资讯股份有限公司\n    - 479、青岛佳家康健康管理有限责任公司\n    - 480、蓝城兄弟\n    - 481、成都天府通金融服务股份有限公司\n    - 482、深圳云镖网络科技有限公司\n    - 483、上海影创科技\n    - 484、成都艾拉物联\n    - 485、北京客邻尚品网络技术有限公司\n    - 486、IT实战联盟\n    - 487、杭州尤拉夫科技有限公司\n    - 488、中大检测(湖南)股份有限公司\n    - 489、江苏电老虎工业互联网股份有限公司\n    - 490、上海助通信息科技有限公司\n    - 491、北京符节科技有限公司\n    - 492、杭州英祐科技有限公司\n    - 493、江苏电老虎工业互联网股份有限公司\n    - 494、深圳市点猫科技有限公司\n    - 495、杭州天音\n    - 496、深圳市二十一科技互联网有限公司\n    - 497、海南海口翎度科技\n    - 498、北京小趣智品科技有限公司\n    - 499、广州石竹计算机软件有限公司\n    - 500、深圳市惟客数据科技有限公司\n    - 501、中国医疗器械有限公司\n    - 502、上海云谦科技有限公司\n    - 503、上海磐农信息科技有限公司\n    - 504、广州领航食品有限公司\n    - 505、青岛掌讯通区块链科技有限公司\n    - 506、北京新网数码信息技术有限公司\n    - 507、超体信息科技(深圳)有限公司\n    - 508、长沙店帮手信息科技有限公司\n    - 509、上海助弓装饰工程有限公司\n    - 510、杭州寻联网络科技有限公司\n    - 511、成都大淘客科技有限公司\n    - 512、松果出行\n    - 513、深圳市唤梦科技有限公司\n    - 514、上汽集团商用车技术中心\n    - 515、北京中航讯科技股份有限公司\n    - 516、北龙中网(北京)科技有限责任公司\n    - 517、前海超级前台(深圳)信息技术有限公司\n    - 518、上海中商网络股份有限公司\n    - 519、上海助通信息科技有限公司\n    - 520、宁波聚臻智能科技有限公司\n    - 521、上海零动数码科技股份有限公司\n    - 522、浙江学海教育科技有限公司\n    - 523、聚学云(山东)信息技术有限公司\n    - 524、多氟多新材料股份有限公司\n    - 525、智慧眼科技股份有限公司\n    - 526、广东智通人才连锁股份有限公司\n    - 527、世纪开元智印互联科技集团股份有限公司\n    - 528、北京理想汽车【理想汽车】\n    - 529、巽逸科技(重庆)有限公司\n    - 530、义乌购电子商务有限公司\n    - 531、深圳市珂莱蒂尔服饰有限公司\n    - 532、江西国泰利民信息科技有限公司\n    - 533、广西广电大数据科技有限公司\n    - 534、杭州艾麦科技有限公司\n    - 535、广州小滴科技有限公司\n    - 536、佳缘科技股份有限公司\n    - 537、上海深擎信息科技有限公司\n    - 538、武商网\n    - 539、福建民本信息科技有限公司\n    - 540、杭州惠合信息科技有限公司\n    - 541、厦门爱立得科技有限公司\n    - 542、成都拟合未来科技有限公司\n    - 543、宁波聚臻智能科技有限公司\n    - 544、广东百慧科技有限公司\n    - 545、笨马网络\n    - 546、深圳市信安数字科技有限公司\n    - 547、深圳市思乐数据技术有限公司\n    - 548、四川绿源集科技有限公司\n    - 549、湖南云医链生物科技有限公司\n    - 550、杭州源诚科技有限公司\n    - 551、北京开课吧科技有限公司\n    - 552、北京多来点信息技术有限公司\n    - 553、JEECG BOOT低代码开发平台\n    - 554、苏州同元软控信息技术有限公司\n    - 555、江苏大泰信息技术有限公司\n    - 556、北京大禹汇智\n    - 557、北京盛哲科技有限公司\n    - 558、广州钛动科技有限公司\n    - 559、北京大禹汇智科技有限公司\n    - 560、湖南鼎翰文化股份有限公司\n    - 561、苏州安软信息科技有限公司\n    - 562、芒果tv\n    - 563、上海艺赛旗软件股份有限公司\n    - 564、中盈优创资讯科技有限公司\n    - 565、乐乎公寓\n    - 566、启明信息\n    - 567、苏州安软\n    - 568、南京富金的软件科技有限公司\n    - 569、深圳市新科聚合网络技术有限公司\n    - 570、你好现在(北京)科技股份有限公司\n    - 571、360考试宝典\n    - 572、北京一零科技有限公司\n    - 573、厦门星纵信息\n    - 574、Dalligent Solusi Indonesia\n    - 575、深圳华普物联科技有限公司\n    - 576、深圳行健自动化股份有限公司\n    - 577、深圳市富融信息科技服务有限公司\n    - 578、蓝鸟云\n    - 579、上海澎博财经资讯有限公司\n    - 580、北京小鸦科技有限公司\n    - 581、杭州盈泉云科技有限公司\n    - 582、惟客数据\n    - 583、GOSO香蜜闺秀\n    - 584、普乐师（上海）数字科技有限公司\n    - 585、西安市雁塔区咖北堂网络科技部\n    - 586、宁波聚臻智能科技有限公司\n    - 587、普乐师数字科技有限公司\n    - 588、江苏蟹联网科技有限公司\n    - 589、杭州未智科技有限公司\n    - 590、安吉智行物流有限公司\n    - 591、华生大家居集团有限公司\n    - 592、美心食品（广州）有限公司\n    - 593、货拉拉【货拉拉APP】\n    - 594、杭州思韬瑞科技有限公司\n    - 595、杭州玖融科技有限公司\n    - 596、北京优海网络科技有限公司\n    - 597、浙江大维高新技术股份有限公司\n    - 598、粤港澳大湾区数字经济研究院\n    - 599、普康（杭州）健康科技有限公司\n    - 600、华西证券股份有限公司【华西证券】\n    - 601、杭州海康机器人股份有限公司【海康】\n    - 602、河南宸邦信息技术有限公司\n    - 603、成都次元节点网络科技有限公司\n    - 604、富士康科技集团【富士康】\n    - 605、青岛东软载波科技股份有限公司\n    - 606、小菊快跑科技有限公司\n    - 607、视源股份\n    - 608、宁波聚臻智能科技有限公司\n    - 609、阔天科技有限公司\n    - 610、网宿科技有限公司\n    - 611、南京梵鼎信息技术有限公司\n    - 612、房天下【房天下】\n    - 613、特瓦特能源科技有限公司\n    - 614、拓迪智能科技有限公司\n    - 615、东软集团【东软】\n    - 616、开普云\n    - 617、领课网络\n    - 618、南京特维软件有限公司\n    - 619、福建易联众保睿通信息科技有限公司\n    - 620、浙江核心同花顺金融科技有限公司【同花顺】\n    - 621、浙江博观瑞思科技有限公司\n    - 622、北京新美互通科技有限公司\n    - 623、北京有生博大软件股份有限公司\n    - 624、时代中国\n    - 625、鱼泡网\n    - 626、一粒方糖（安徽）科技有限公司\n    - 627、北京外研在线数字科技有限公司\n    - 628、德电（中国）通信技术有限公司\n    - 629、杭州寻联网络科技有限公司\n    - 630、橙联（中国）有限公司\n    - 631、北京承启通科技有限公司\n    - 632、银联数据服务有限公司【银联】\n    - 633、上海晶确科技有限公司\n    - 634、亚信科技有限公司\n    - 635、福建新航物联网科技有限公司\n    - 636、上扬软件\n    - 637、深蓝汽车科技有限公司\n    - 638、南昌节点汇智科技有限公司\n    - 639、锐明技术\n    - 640、再造再生健康科技有限公司\n    - 641、华宝证券\n    - 642、卓正医疗\n    - 643、深圳湛信科技\n    - 644、陕西鑫众为软件有限公司\n    - 645、深圳市润农科技有限公司\n    - 646、庚商教育智能科技有限公司\n    - 647、杭州祎声科技\n    - 648、四川久远银海软件股份有限公司\n    - 649、GeeFox极狐低代码\n    - 650、浙江和仁科技股份有限公司\n    - 651、宁波聚臻智能科技有限公司\n    - 652、福建福昕软件开发股份有限公司【福昕】\n    - 653、广州中长康达信息技术有限公司\n    - 654、武汉趣改信息科技有限公司\n    - 655、北京华夏思源科技发展有限公司\n    - 656、宁波关关通科技有限公司\n    - 657、青岛吕氏餐饮有限公司\n    - 658、杭州乐刻网络科技有限公司\n    - 659、上海红瓦信息科技有限公司\n    - 660、陕西旅小宝信息科技有限公司\n    - 661、中科卓恒(大连)科技有限公司\n    - 662、北京华益精点生物技术有限公司\n    - 663、马士基（中国）航运有限公司【马士基】\n    - 664、陕西美咚网络科技有限公司\n    - 665、山东新北洋信息技术股份有限公司 \n    - 666、福建中瑞文化发展集团有限公司\n    - 667、黑龙江省建工集团有限责任公司【黑龙江省建工】\n    - 668、志信能达安全科技(广州)有限公司\n    - 669、重庆开源共创科技有限公司\n    - 670、华泰人寿保险股份有限公司【华泰人寿】\n    - 671、成都盘古纵横集团\n    - 672、北京果果乐学科技有限公司\n    - 673、北京凌云空间科技有限公司\n    - 674、临工重机股份有限公司\n    - 675、上海热风时尚管理集团【热风】\n    - 676、HashKey Exchange\n    - 677、傲基（深圳）跨境商务股份有限公司\n    - 678、青岛文达通科技股份有限公司\n    - 679、杭州普罗云科技有限公司\n    - 680、浙江云鹭科技有限公司\n    - 681、中山市芯宏柿网络科技有限公司\n    - 682、深圳市家家顺物联科技\n    - 683、重庆斑西科技有限公司\n    - 684、福建省泰古信息技术有限公司\n    - 685、贵阳永青仪电科技有限公司\n    - 686、广州博依特智能信息科技有限公司\n    - 687、河南宠呦呦信息技术有限公司\n    - 688、陕西星邑空间技术有限公司\n    - 689、广东西欧克实业有限公司\n    - 690、唱吧麦颂KTV\n    - 691、联通云\n    - 692、北京爱话本科技有限公司\n    - 693、北京起创科技有限公司\n    - 694、平安证券【平安证券】\n    - 695、合肥中科类脑智能技术有限公司\n    - 696、南京同仁堂健康产业有限公司【同仁堂】\n    - 697、铜仁市碧江区智惠加油站\n    - 698、惟客数据\n    - 699、凤凰新闻【凤凰新闻】\n    - 700、深圳王力智能\n    - 701、返利网数字科技股份有限公司\n    - 702、上海阜能信息科技有限公司\n    - 703、深圳市极能超电数字科技有限公司\n    - 704、海目星激光科技集团股份有限公司\n    - 705、安克创新科技股份有限公司【安克】\n    - 706、大庆点神科技有限公司\n    - 707、浙江零跑科技股份有限公司【零跑】\n    - 708、成都成电金盘健康数据技术有限公司\n    - 709、成都极米科技股份有限公司【极米】\n    - 710、顺德职业技术大学\n    - 711、中邮证券有限责任公司【中邮证券】\n    - 712、志豪链云科技有限公司\n    - 713、湖南万鲸科技有限公司\n    - 714、广州万表\n    - 715、再惠（上海）网络科技有限公司\n    - 716、上海爱诚裕信息科技有限公司\n    - 717、杭州迈瑞数字科技有限公司\n    - 718、广州串联网络科技有限公司\n    - ……\n\n> 更多接入的公司，欢迎在 [登记地址](https://github.com/xuxueli/xxl-job/issues/1 ) 登记，登记仅仅为了产品推广。\n\n欢迎大家的关注和使用，XXL-JOB也将拥抱变化，持续发展。\n\n\n## Contributing\nContributions are welcome! Open a pull request to fix a bug, or open an [Issue](https://github.com/xuxueli/xxl-job/issues/) to discuss a new feature or change.\n\n欢迎参与项目贡献！比如提交PR修复一个bug，或者新建 [Issue](https://github.com/xuxueli/xxl-job/issues/) 讨论新特性或者变更。\n\n\n## Copyright and License\nThis product is open source and free, and will continue to provide free community technical support. Individual or enterprise users are free to access and use.\n\n- Licensed under the GNU General Public License (GPL) v3.\n- Copyright (c) 2015-present, xuxueli.\n\n产品开源免费，并且将持续提供免费的社区技术支持。个人或企业内部可自由的接入和使用。如有需要可 [邮件联系](https://www.xuxueli.com/page/community.html) 作者免费获取项目授权。\n"
  },
  {
    "path": "doc/XXL-JOB-English-Documentation.md",
    "content": "## 《Distributed task scheduling framework XXL-JOB》\n\n[![Build Status](https://github.com/xuxueli/xxl-job/workflows/Java%20CI/badge.svg)](https://github.com/xuxueli/xxl-job/actions)\n[![Maven Central](https://img.shields.io/maven-central/v/com.xuxueli/xxl-job-core)](https://central.sonatype.com/artifact/com.xuxueli/xxl-job-core)\n[![GitHub release](https://img.shields.io/github/release/xuxueli/xxl-job.svg)](https://github.com/xuxueli/xxl-job/releases)\n[![GitHub stars](https://img.shields.io/github/stars/xuxueli/xxl-job)](https://github.com/xuxueli/xxl-job/)\n[![Docker pulls](https://img.shields.io/docker/pulls/xuxueli/xxl-job-admin)](https://hub.docker.com/r/xuxueli/xxl-job-admin/)\n[![License](https://img.shields.io/badge/license-GPLv3-blue.svg)](http://www.gnu.org/licenses/gpl-3.0.html)\n[![donate](https://img.shields.io/badge/%24-donate-ff69b4.svg?style=flat)](https://www.xuxueli.com/page/donate.html)\n\n[TOCM]\n\n[TOC]\n\n## 1. Brief introduction\n\n### 1.1 Overview\nXXL-JOB is a distributed task scheduling framework, the core design goal is to develop quickly, learning simple, lightweight, easy to expand. Is now open source and access to a number of companies online product line, download and use it now.\n\n> English document update slightly delayed, Please check the Chinese version for the latest document.\n\n### 1.2 Features\n- 1.Simple: support through the Web page on the task CRUD operation, simple operation, a minute to get started;\n- 2.Dynamic: support dynamic modification of task status, pause / resume tasks, and termination of running tasks,immediate effect;\n- 3.Dispatch center HA (center type): Dispatch with central design, \"dispatch center\" based on the cluster of Quartz implementation, can guarantee the scheduling - center HA;\n- 4.Executor HA (Distributed): Task Distributed Execution, Task \" Executer \" supports cluster deployment to ensure that tasks perform HA;\n- 5.Task Failover: Deploy the Excutor cluster,tasks will be smooth to switch excuter when the strategy of the router choose ‘failover’;\n- 6.Consistency: \"Dispatch Center\" through the DB lock to ensure the consistency of cluster distributed scheduling,one task excuted for once;\n- 7.Custom task parameters: support online configuration scheduling tasks into the parameters, immediate effect;\n- 8.Scheduling thread pool: scheduling system multi-threaded trigger scheduling operation, to ensure accurate scheduling, not blocked;\n- 9.Elastic expansion capacity: once the new executor machine on the line or off the assembly line, the next time scheduling will be re-assigned tasks;\n- 10.Mail alarm: the task fails to support e-mail alarm, support configuring multiple email addresses to send bulk alert messages;\n- 11.Status monitoring: support real-time monitoring of the progress of the task;\n- 12.Rolling execution log: support online view scheduling results, and support Rolling real-time view of the executer output of the complete implementation of the log;\n- 13.GLUE: provide Web IDE, support online development task logic code, dynamic release, real-time compiler effective, omit the deployment of the on-line process. Supports historical versions of 30 versions back;\n- 14.Data Encryption: The communication between the dispatching center and the executor is used for data encryption, Enhancing the security of dispatching information;\n- 15.Task Dependency: Support configuration subtask dependencies, When the parent task executed end and after the success of the implementation will take the initiative to trigger a second task execution, multiple sub tasks are separated by commas;\n- 16.Push the Maven central warehouse: The latest stable version will be sent to the Maven central warehouse to facilitate user access and use;\n- 17.Task registration: The executor automatically registers tasks periodically, and the dispatch center automatically finds the registered tasks and triggers execution. It also supports manual input of executor address;\n- 18.Router strategy: A rich routing strategy is provided when the executor cluster is deployed, these include: first, last, poll, random, consistent HASH, least frequently used, least recently used, failover, busy over, sharding broadcast,etc.;\n- 19.Report monitor: Support real-time view of running data, such as the number of tasks, the number of dispatch, the number of executors, etc .; and scheduling reports, such as scheduling date distribution, scheduling success map;\n- 20.Script task: Support the development and operation of script tasks in GLUE mode, including shell, Python and other types of script;\n- 21.Blocking handling strategy: The scheduling is too dense and the executor is too late to handle. The strategy includes: single machine serial (default), discarding the following scheduling, and Override the previous scheduling;\n- 22.Failure handling strategy:Handling strategy when scheduling fails, the strategy includes: failure alarm (default), failure retry;\n- 23.Sharding broadcast task: When an executor cluster is deployed, task routing strategy select \"sharding broadcast\", a task schedule will broadcast all the actuators in the cluster to perform it once, you can develop sharding tasks based on sharding parameters;\n- 24.Dynamic sharding: The sharding broadcast task is sharded by the executors to support the dynamic expansion of the executor cluster to dynamically increase the number of shardings and cooperate with the business handle; In the large amount of data operations can significantly improve the task processing capacity and speed.\n- 25、Event trigger：In addition to \"Cron\" and \"Task Dependency\" to trigger tasks, support event-based triggering tasks. The dispatch center provides API service that triggers a single execution of the task, it can be triggered flexibly according to business events. \n\n\n###  1.3 Development\nIn 2015, I created the XXL-JOB project repository on github and submitted the first commit, followed by the system structure design, UI selection, interactive design ...\nIn 2015 - November, XXL-JOB finally RELEASE the first big version of V1.0, then I will be released to OSCHINA, XXL-JOB OSCHINA won the popular recommendation of @红薯, the same period reached OSCHINA's \" Popular move \"ranked first and git.oschina open source software monthly heat ranked first, especially thanks for @红薯, thank you for the attention and support.\nIn 2015 - December, I will XXL-JOB published to our internal knowledge base, and get internal colleagues recognized.\nIn 2016 - 01 months, my company started XXL-JOB internal access and custom work, in this thank Yuan and Yin two colleagues contribution, but also to thank the internal other attention and support colleagues.\nIn 2017-05-13, the link of \"let the code run\" in \"[the 62nd source of open source China Genesis](https://www.oschina.net/event/2236961)\" held in Shanghai,, I stepped on and made a speech about the XXL-JOB, five hundred spectators in the audience reacted enthusiastically ([pictorial review](https://www.oschina.net/question/2686220_2242120)).\n> Our company have access to XXL-JOB, internal alias \"Ferrari\" (Ferrari based on XXL-JOB V1.1 version customization, new access application recommended to upgrade the latest version).\nAccording to the latest statistics, from 2016-01-21 to 2017-07-07 period, the system has been scheduled about 600,000 times, outstanding performance. New access applications recommend the latest version, because after several major updates, the system's task model, UI interaction model and the underlying scheduling communication model has a greater optimization and upgrading, the core function more stable and efficient.\n\nSo far, XXL-JOB has access to a number of companies online product line, access to scenes such as electronic commerce, O2O business and large data operations, as of 2016-07-19, XXL-JOB has access to the company But not limited to:\n\n\t- 1、大众点评【美团点评】\n\t- 2、山东学而网络科技有限公司；\n\t- 3、安徽慧通互联科技有限公司；\n\t- 4、人人聚财金服；\n\t- 5、上海棠棣信息科技股份有限公司\n\t- 6、运满满【运满满】\n\t- 7、米其林 (中国区)【米其林】\n\t- 8、妈妈联盟\n\t- 9、九樱天下（北京）信息技术有限公司\n\t- 10、万普拉斯科技有限公司【一加手机】\n\t- 11、上海亿保健康管理有限公司\n\t- 12、海尔馨厨【海尔】\n\t- 13、河南大红包电子商务有限公司\n\t- 14、成都顺点科技有限公司\n\t- 15、深圳市怡亚通\n\t- 16、深圳麦亚信科技股份有限公司\n\t- 17、上海博莹科技信息技术有限公司\n\t- 18、中国平安科技有限公司【中国平安】\n\t- 19、杭州知时信息科技有限公司\n\t- 20、博莹科技（上海）有限公司\n\t- 21、成都依能股份有限责任公司\n\t- 22、湖南高阳通联信息技术有限公司\n\t- 23、深圳市邦德文化发展有限公司\n\t- 24、福建阿思可网络教育有限公司\n\t- 25、优信二手车【优信】\n\t- 26、上海悠游堂投资发展股份有限公司【悠游堂】\n\t- 27、北京粉笔蓝天科技有限公司\n\t- 28、中秀科技(无锡)有限公司\n\t- 29、武汉空心科技有限公司\n\t- 30、北京蚂蚁风暴科技有限公司\n\t- 31、四川互宜达科技有限公司\n\t- 32、钱包行云（北京）科技有限公司\n\t- 33、重庆欣才集团\n    - 34、咪咕互动娱乐有限公司【中国移动】\n    - 35、北京诺亦腾科技有限公司\n    - 36、增长引擎(北京)信息技术有限公司\n    - 37、北京英贝思科技有限公司\n    - 38、刚泰集团\n    - 39、深圳泰久信息系统股份有限公司\n    - 40、随行付支付有限公司\n    - 41、广州瀚农网络科技有限公司\n    - 42、享点科技有限公司\n    - 43、杭州比智科技有限公司\n    - 44、圳临界线网络科技有限公司\n    - 45、广州知识圈网络科技有限公司\n    - 46、国誉商业上海有限公司\n    - 47、海尔消费金融有限公司，嗨付、够花【海尔】\n    - 48、广州巴图鲁信息科技有限公司\n    - 49、深圳市鹏海运电子数据交换有限公司\n    - 50、深圳市亚飞电子商务有限公司\n    - 51、上海趣医网络有限公司\n    - 52、聚金资本\n    - 53、北京父母邦网络科技有限公司\n    - 54、中山元赫软件科技有限公司\n    - 55、中商惠民(北京)电子商务有限公司\n    - 56、凯京集团\n    - 57、华夏票联（北京）科技有限公司\n    - 58、拍拍贷【拍拍贷】\n    - 59、北京尚德机构在线教育有限公司\n    - 60、任子行股份有限公司\n    - 61、北京时态电子商务有限公司\n    - 62、深圳卷皮网络科技有限公司\n    - 63、北京安博通科技股份有限公司\n    - 64、未来无线网\n    - 65、厦门瓷禧网络有限公司\n    - 66、北京递蓝科软件股份有限公司\n    - 67、郑州创海软件科技公司\n    - 68、北京国槐信息科技有限公司\n    - 69、浪潮软件集团\n    - 70、多立恒(北京)信息技术有限公司\n    - 71、广州极迅客信息科技有限公司\n    - 72、赫基（中国）集团股份有限公司\n    - 73、海投汇\n    - 74、上海润益创业孵化器管理股份有限公司\n    - 75、汉纳森（厦门）数据股份有限公司\n    - 76、安信信托\n    - 77、岚儒财富\n    - 78、捷道软件\n    - 79、湖北享七网络科技有限公司\n    - 80、湖南创发科技责任有限公司\n    - 81、深圳小安时代互联网金融服务有限公司\n    - 82、湖北享七网络科技有限公司\n    - 83、钱包行云(北京)科技有限公司\n    - 84、360金融【360】\n    - 85、易企秀\n    - 86、摩贝（上海）生物科技有限公司\n    - 87、广东芯智慧科技有限公司\n    - 88、联想集团【联想】\n    - 89、怪兽充电\n    - 90、行圆汽车\n    - 91、深圳店店通科技邮箱公司\n    - 92、京东【京东】\n    - 93、米庄理财\n    - 94、咖啡易融\n    - 95、梧桐诚选\n    - 96、恒大地产【恒大】\n    - 97、昆明龙慧\n    - 98、上海涩瑶软件\n    - 99、易信【网易】\n    - 100、铜板街\n    - 101、杭州云若网络科技有限公司\n    - 102、特百惠（中国）有限公司\n    - 103、常山众卡运力供应链管理有限公司\n    - 104、深圳立创电子商务有限公司\n    - 105、杭州智诺科技股份有限公司\n    - 106、北京云漾信息科技有限公司\n    - 107、深圳市多银科技有限公司\n    - 108、亲宝宝\n    - 109、上海博卡软件科技有限公司\n    - 110、智慧树在线教育平台\n    - 111、米族金融\n    - 112、北京辰森世纪\n    - 113、云南滇医通\n    - 114、广州市分领网络科技有限责任公司\n    - 115、浙江微能科技有限公司\n    - 116、上海馨飞电子商务有限公司\n    - 117、上海宝尊电子商务有限公司\n    - 118、直客通科技技术有限公司\n    - 119、科度科技有限公司\n    - 120、上海数慧系统技术有限公司\n    - 121、我的医药网\n    - 122、多粉平台\n    - 123、铁甲二手机\n    - 124、上海海新得数据技术有限公司\n    - 125、深圳市珍爱网信息技术有限公司【珍爱网】\n    - 126、小蜜蜂\n    - 127、吉荣数科技\n    - 128、上海恺域信息科技有限公司\n    - 129、广州荔支网络有限公司【荔枝FM】\n    - 130、杭州闪宝科技有限公司\n    - 131、北京互联新网科技发展有限公司\n    - 132、誉道科技\n    - 133、山西兆盛房地产开发有限公司\n    - 134、北京蓝睿通达科技有限公司\n    - 135、月亮小屋（中国）有限公司【蓝月亮】\n    - 136、青岛国瑞信息技术有限公司\n    - 137、博雅云计算（北京）有限公司\n    - 138、华泰证券香港子公司\n    - 139、杭州东方通信软件技术有限公司\n    - 140、武汉博晟安全技术股份有限公司\n    - 141、深圳市六度人和科技有限公司\n    - 142、杭州趣维科技有限公司（小影）\n    - 143、宁波单车侠之家科技有限公司【单车侠】\n    - 144、丁丁云康信息科技（北京）有限公司\n    - 145、云钱袋\n    - 146、南京中兴力维\n    - 147、上海矽昌通信技术有限公司\n    - 148、深圳萨科科技\n    - 149、中通服创立科技有限责任公司\n    - 150、深圳市对庄科技有限公司\n    - 151、上证所信息网络有限公司\n    - 152、杭州火烧云科技有限公司【婚礼纪】\n    - 153、天津青芒果科技有限公司【芒果头条】\n    - 154、长飞光纤光缆股份有限公司\n    - 155、世纪凯歌（北京）医疗科技有限公司\n    - 156、浙江霖梓控股有限公司\n    - 157、江西腾飞网络技术有限公司\n    - 158、安迅物流有限公司\n    - 159、肉联网\n    - 160、北京北广梯影广告传媒有限公司\n    - 161、上海数慧系统技术有限公司\n    - 162、大志天成\n    - 163、上海云鹊医\n    - 164、上海云鹊医\n    - 165、墨迹天气【墨迹天气】\n    - 166、上海逸橙信息科技有限公司\n    - 167、沅朋物联\n    - 168、杭州恒生云融网络科技有限公司\n    - 169、绿米联创\n    - 170、重庆易宠科技有限公司\n    - 171、安徽引航科技有限公司（乐职网）\n    - 172、上海数联医信企业发展有限公司\n    - 173、良彬建材\n    - 174、杭州求是同创网络科技有限公司\n    - 175、荷马国际\n    - 176、点雇网\n    - 177、深圳市华星光电技术有限公司\n    - 178、厦门神州鹰软件科技有限公司\n    - 179、深圳市招商信诺人寿保险有限公司\n    - 180、上海好屋网信息技术有限公司\n    - 181、海信集团【海信】\n    - 182、信凌可信息科技（上海）有限公司\n    - 183、长春天成科技发展有限公司\n    - 184、用友金融信息技术股份有限公司【用友】\n    - 185、北京咖啡易融有限公司\n    - 186、国投瑞银基金管理有限公司\n    - 187、晋松(上海)网络信息技术有限公司\n    - 188、深圳市随手科技有限公司【随手记】\n    - 189、深圳水务科技有限公司\n    - 190、易企秀【易企秀】\n    - 191、北京磁云科技\n    - 192、南京蜂泰互联网科技有限公司\n    - 193、章鱼直播\n    - 194、奖多多科技\n    - 195、天津市神州商龙科技股份有限公司\n    - 196、岩心科技\n    - 197、车码科技（北京）有限公司\n    - 198、贵阳市投资控股集团\n    - 199、康旗股份\n    - 200、龙腾出行\n    - 201、杭州华量软件\n    - 202、合肥顶岭医疗科技有限公司\n    - 203、重庆表达式科技有限公司\n    - 204、上海米道信息科技有限公司\n    - 205、北京益友会科技有限公司\n    - 206、北京融贯电子商务有限公司\n    - 207、中国外汇交易中心\n    - 208、中国外运股份有限公司\n    - 209、中国上海晓圈教育科技有限公司\n    - 210、普联软件股份有限公司\n    - 211、北京科蓝软件股份有限公司\n    - 212、江苏斯诺物联科技有限公司\n    - 213、北京搜狐-狐友【搜狐】\n    - 214、新大陆网商金融\n    - 215、山东神码中税信息科技有限公司\n    - 216、河南汇顺网络科技有限公司\n    - 217、北京华夏思源科技发展有限公司\n    - 218、上海东普信息科技有限公司\n    - 219、上海鸣勃网络科技有限公司\n    - 220、广东学苑教育发展有限公司\n    - 221、深圳强时科技有限公司\n    - 222、上海云砺信息科技有限公司\n    - 223、重庆愉客行网络有限公司\n    - 224、数云\n    - 225、国家电网运检部\n    - 226、杭州找趣\n    - 227、浩鲸云计算科技股份有限公司\n    - 228、科大讯飞【科大讯飞】\n    - 229、杭州行装网络科技有限公司\n    - 230、即有分期金融\n    - 231、深圳法司德信息科技有限公司\n    - 232、上海博复信息科技有限公司\n    - 233、杭州云嘉云计算有限公司\n    - 234、有家民宿(有家美宿)\n    - 235、北京赢销通软件技术有限公司\n    - 236、浙江聚有财金融服务外包有限公司\n    - 237、易族智汇(北京)科技有限公司\n    - 238、合肥顶岭医疗科技开发有限公司\n    - 239、车船宝(深圳)旭珩科技有限公司)\n    - 240、广州富力地产有限公司\n    - 241、氢课（上海）教育科技有限公司\n    - 242、武汉氪细胞网络技术有限公司\n    - 243、杭州有云科技有限公司\n    - 244、上海仙豆智能机器人有限公司\n    - 245、拉卡拉支付股份有限公司【拉卡拉】\n    - 246、虎彩印艺股份有限公司\n    - 247、北京数微科技有限公司\n    - 248、广东智瑞科技有限公司\n    - 249、找钢网\n    - 250、九机网\n    - 251、杭州跑跑网络科技有限公司\n    - 252、深圳未来云集\n    - 253、杭州每日给力科技有限公司\n    - 254、上海齐犇信息科技有限公司\n    - 255、滴滴出行【滴滴】\n    - 256、合肥云诊信息科技有限公司\n    - 257、云知声智能科技股份有限公司\n    - 258、南京坦道科技有限公司\n    - 259、爱乐优（二手平台）\n    - 260、猫眼电影（私有化部署）【猫眼电影】\n    - 261、美团大象（私有化部署）【美团大象】\n    - 262、作业帮教育科技（北京）有限公司【作业帮】\n    - 263、北京小年糕互联网技术有限公司\n    - 264、山东矩阵软件工程股份有限公司\n    - 265、陕西国驿软件科技有限公司\n    - 266、君开信息科技\n    - 267、村鸟网络科技有限责任公司\n    - 268、云南国际信托有限公司\n    - 269、金智教育\n    - 270、珠海市筑巢科技有限公司\n    - 271、上海百胜软件股份有限公司\n    - 272、深圳市科盾科技有限公司\n    - 273、哈啰出行\n    - 274、途虎养车\n    - 275、卡思优派人力资源集团\n    - 276、南京观为智慧软件科技有限公司\n    - 277、杭州城市大脑科技有限公司\n    - 278、猿辅导【猿辅导】\n    - 279、洛阳健创网络科技有限公司\n    - 280、魔力耳朵\n    - 281、亿阳信通\n    - 282、上海招鲤科技有限公司\n    - 283、四川商旅无忧科技服务有限公司\n    - 284、UU跑腿\n    - 285、北京老虎证券【老虎证券】\n    - 286、悠活省吧（北京）网络科技有限公司\n    - 287、F5未来商店\n    - 288、深圳环阳通信息技术有限公司\n    - 289、遠傳電信\n    - 290、作业帮（北京）教育科技有限公司【作业帮】\n    - 291、成都科鸿智信科技有限公司\n    - 292、北京木屋时代科技有限公司\n    - 293、大学通（哈尔滨）科技有限责任公司\n    - 294、浙江华坤道威数据科技有限公司\n    - 295、吉祥航空【吉祥航空】\n    - 296、南京圆周网络科技有限公司\n    - 297、广州市洋葱omall电子商务\n    - 298、天津联物科技有限公司\n    - 299、跑哪儿科技（北京）有限公司\n    - 300、深圳市美西西餐饮有限公司(喜茶)\n    - 301、平安不动产有限公司【平安】\n    - 302、江苏中海昇物联科技有限公司\n    - 303、湖南牙医帮科技有限公司\n    - 304、重庆民航凯亚信息技术有限公司（易通航）\n    - 305、递易（上海）智能科技有限公司\n    - 306、亚朵\n    - 307、浙江新课堂教育股份有限公司\n    - 308、北京蜂创科技有限公司\n    - 309、德一智慧城市信息系统有限公司\n    - 310、北京翼点科技有限公司\n    - 311、湖南智数新维度信息科技有限公司\n    - 312、北京玖扬博文文化发展有限公司\n    - 313、上海宇珩信息科技有限公司\n    - 314、全景智联（武汉）科技有限公司\n    - 315、天津易客满国际物流有限公司\n    - 316、南京爱福路汽车科技有限公司\n    - 317、我房旅居集团\n    - 318、湛江亲邻科技有限公司\n    - 319、深圳市姜科网络有限公司\n    - 320、青岛日日顺物流有限公司\n    - 321、南京太川信息技术有限公司\n    - 322、美图之家科技优先公司【美图】\n    - 323、南京太川信息技术有限公司\n    - 324、众薪科技（北京）有限公司\n    - 325、武汉安安物联科技有限公司\n    - 326、北京智客朗道网络科技有限公司\n    - 327、深圳市超级猩猩健身管理管理有限公司\n    - 328、重庆达志科技有限公司\n    - 329、上海享评信息科技有限公司\n    - 330、薪得付信息科技\n    - 331、跟谁学\n    - 332、中道（苏州）旅游网络科技有限公司\n    - 333、广州小卫科技有限公司\n    - 334、上海非码网络科技有限公司\n    - 335、途家网网络技术（北京）有限公司【途家】\n    - 336、广州辉凡信息科技有限公司\n    - 337、天维尔信息科技股份有限公司\n    - 338、上海极豆科技有限公司\n    - 339、苏州触达信息技术有限公司\n    - 340、北京热云科技有限公司\n    - 341、中智企服（北京）科技有限公司\n    - 342、易联云计算（杭州）有限责任公司\n    - 343、青岛航空股份有限公司【青岛航空】\n    - 344、山西博睿通科技有限公司\n    - 345、网易杭州网络有限公司【网易】\n    - 346、北京果果乐学科技有限公司\n    - 347、百望股份有限公司\n    - 348、中保金服（深圳）科技有限公司\n    - 349、天津运友物流科技股份有限公司\n    - 350、广东创能科技股份有限公司\n    - 351、上海倚博信息科技有限公司\n    - 352、深圳百果园实业（集团）股份有限公司\n    - 353、广州细刻网络科技有限公司\n    - 354、武汉鸿业众创科技有限公司\n    - 355、金锡科技（广州）有限公司\n    - 356、易瑞国际电子商务有限公司\n    - 357、奇点云\n    - 358、中视信息科技有限公司\n    - 359、开源项目:datax-web\n    - 360、云知声智能科技股份有限公司\n    - 361、开源项目:bboss\n    - 362、成都深驾科技有限公司\n    - 363、FunPlus【趣加】\n    - 364、杭州创匠信科技有限公司\n    - 365、龙匠（北京）科技发展有限公司\n    - 366、广州一链通互联网科技有限公司\n    - 367、上海星艾网络科技有限公司\n    - 368、虎博网络技术(上海)有限公司\n    - 369、青岛优米信息技术有限公司\n    - 370、八维通科技有限公司\n    - 371、烟台合享智星数据科技有限公司\n    - 372、东吴证券股份有限公司\n    - 373、中通云仓股份有限公司【中通】\n    - 374、北京加菲猫科技有限公司\n    - 375、北京匠心演绎科技有限公司\n    - 376、宝贝走天下\n    - 377、厦门众库科技有限公司\n    - 378、海通证券数据中心\n    - 389、湖南快乐通宝小额贷款有限公司\n    - 380、浙江大华技术股份有限公司\n    - 381、杭州魔筷科技有限公司\n    - 382、青岛掌讯通区块链科技有限公司\n    - 383、新大陆金融科技\n    - 384、常州玺拓软件科技有限公司\n    - 385、北京正保网格教育科技有限公司\n    - 386、统一企业（中国）投资有限公司【统一】\n    - 387、微革网络科技有限公司\n    - 388、杭州融易算科技有限公司\n    - 399、青岛上啥班网络科技有限公司\n    - 390、京东酒世界\n    - 391、杭州爱博仕科技有限公司\n    - 392、五星金服控股有限公司\n    - 393、福建乐摩物联科技有限公司\n    - 394、百炼智能科技有限公司\n    - 395、山东能源数智云科技有限公司\n    - 396、招商局能源运输股份有限公司\n    - 397、三一集团【三一】\n    - 398、东巴文（深圳）健康管理有限公司\n    - 399、索易软件\n    - 400、深圳市宁远科技有限公司\n    - 401、熙牛医疗\n    - 402、南京智鹤电子科技有限公司\n    - 403、嘀嗒出行【嘀嗒出行】\n    - 404、广州虎牙信息科技有限公司【虎牙】\n    - 405、广州欧莱雅百库网络科技有限公司【欧莱雅】\n    - 406、微微科技有限公司\n    - 407、我爱我家房地产经纪有限公司【我爱我家】\n    - 408、九号发现\n    - 409、薪人薪事\n    - 410、武汉氪细胞网络技术有限公司\n    - 411、广州市斯凯奇商业有限公司\n    - 412、微淼商学院\n    - 413、杭州车盛科技有限公司\n    - 414、深兰科技（上海）有限公司\n    - 415、安徽中科美络信息技术有限公司\n    - 416、比亚迪汽车工业有限公司【比亚迪】\n    - 417、湖南小桔信息技术有限公司\n    - 418、安徽科大国创软件科技有限公司\n    - 419、克而瑞\n    - 420、陕西云基华海信息技术有限公司\n    - 421、安徽深宁科技有限公司\n    - 422、广东康爱多数字健康有限公司\n    - 423、嘉里电子商务\n    - 424、上海时代光华教育发展有限公司\n    - 425、CityDo\n    - 426、上海禹知信息科技有限公司\n    - 427、广东智瑞科技有限公司\n    - 428、西安爱铭网络科技有限公司\n    - 429、心医国际数字医疗系统(大连)有限公司\n    - 430、乐其电商\n    - 431、锐达科技\n    - 432、天津长城滨银汽车金融有限公司\n    - 433、代码网\n    - 434、东莞市东城乔伦软件开发工作室\n    - 435、浙江百应科技有限公司\n    - 436、上海力爱帝信息技术有限公司(Red E)\n    - 437、云徙科技有限公司\n    - 438、北京康智乐思网络科技有限公司【大姨吗APP】\n    - 439、安徽开元瞬视科技有限公司\n    - 440、立方\n    - 441、厦门纵行科技\n    - 442、乐山-菲尼克斯半导体有限公司\n    - 443、武汉光谷联合集团有限公司\n    - 444、上海金仕达软件科技有限公司\n    - 445、深圳易世通达科技有限公司\n    - 446、爱动超越人工智能科技（北京）有限责任公司\n    - 447、迪普信（北京）科技有限公司\n    - 448、掌站科技（北京）有限公司\n    - 449、深圳市华云中盛股份有限公司\n    - 450、上海原圈科技有限公司\n    - 451、广州赞赏信息科技有限公司\n    - 452、Amber Group\n    - 453、德威国际货运代理（上海）公司\n    - 454、浙江杰夫兄弟智慧科技有限公司\n    - 455、信也科技\n    - 456、开思时代科技（深圳）有限公司\n    - 457、大连槐德科技有限公司\n    - 458、同程生活\n    - 459、松果出行\n    - 460、企鹅杏仁集团\n    - 461、宁波科云信息科技有限公司\n    - 462、上海格蓝威驰信息科技有限公司\n    - 463、杭州趣淘鲸科技有限公司\n    - 464、湖州市数字惠民科技有限公司\n    - 465、乐普（北京）医疗器械股份有限公司\n    - 466、广州市晴川高新技术开发有限公司\n    - 467、山西缇客科技有限公司\n    - 468、徐州卡西穆电子商务有限公司\n    - 469、格创东智科技有限公司\n    - 470、世纪龙信息网络有限责任公司\n    - 471、邦道科技有限公司\n    - 472、河南中盟新云科技股份有限公司\n    - 473、横琴人寿保险有限公司\n    - 474、上海海隆华钟信息技术有限公司\n    - 475、上海久湛\n    - 476、上海仙豆智能机器人有限公司\n    - 477、广州汇尚网络科技有限公司\n    - 478、深圳市阿卡索资讯股份有限公司\n    - 479、青岛佳家康健康管理有限责任公司\n    - 480、蓝城兄弟\n    - 481、成都天府通金融服务股份有限公司\n    - 482、深圳云镖网络科技有限公司\n    - 483、上海影创科技\n    - 484、成都艾拉物联\n    - 485、北京客邻尚品网络技术有限公司\n    - 486、IT实战联盟\n    - 487、杭州尤拉夫科技有限公司\n    - 488、中大检测(湖南)股份有限公司\n    - 489、江苏电老虎工业互联网股份有限公司\n    - 490、上海助通信息科技有限公司\n    - 491、北京符节科技有限公司\n    - 492、杭州英祐科技有限公司\n    - 493、江苏电老虎工业互联网股份有限公司\n    - 494、深圳市点猫科技有限公司\n    - 495、杭州天音\n    - 496、深圳市二十一科技互联网有限公司\n    - 497、海南海口翎度科技\n    - 498、北京小趣智品科技有限公司\n    - 499、广州石竹计算机软件有限公司\n    - 500、深圳市惟客数据科技有限公司\n    - 501、中国医疗器械有限公司\n    - 502、上海云谦科技有限公司\n    - 503、上海磐农信息科技有限公司\n    - 504、广州领航食品有限公司\n    - 505、青岛掌讯通区块链科技有限公司\n    - 506、北京新网数码信息技术有限公司\n    - 507、超体信息科技(深圳)有限公司\n    - 508、长沙店帮手信息科技有限公司\n    - 509、上海助弓装饰工程有限公司\n    - 510、杭州寻联网络科技有限公司\n    - 511、成都大淘客科技有限公司\n    - 512、松果出行\n    - 513、深圳市唤梦科技有限公司\n    - 514、上汽集团商用车技术中心\n    - 515、北京中航讯科技股份有限公司\n    - 516、北龙中网(北京)科技有限责任公司\n    - 517、前海超级前台(深圳)信息技术有限公司\n    - 518、上海中商网络股份有限公司\n    - 519、上海助通信息科技有限公司\n    - 520、宁波聚臻智能科技有限公司\n    - 521、上海零动数码科技股份有限公司\n    - 522、浙江学海教育科技有限公司\n    - 523、聚学云(山东)信息技术有限公司\n    - 524、多氟多新材料股份有限公司\n    - 525、智慧眼科技股份有限公司\n    - 526、广东智通人才连锁股份有限公司\n    - 527、世纪开元智印互联科技集团股份有限公司\n    - 528、北京理想汽车【理想汽车】\n    - 529、巽逸科技(重庆)有限公司\n    - 530、义乌购电子商务有限公司\n    - 531、深圳市珂莱蒂尔服饰有限公司\n    - 532、江西国泰利民信息科技有限公司\n    - 533、广西广电大数据科技有限公司\n    - 534、杭州艾麦科技有限公司\n    - 535、广州小滴科技有限公司\n    - 536、佳缘科技股份有限公司\n    - 537、上海深擎信息科技有限公司\n    - 538、武商网\n    - 539、福建民本信息科技有限公司\n    - 540、杭州惠合信息科技有限公司\n    - 541、厦门爱立得科技有限公司\n    - 542、成都拟合未来科技有限公司\n    - 543、宁波聚臻智能科技有限公司\n    - 544、广东百慧科技有限公司\n    - 545、笨马网络\n    - 546、深圳市信安数字科技有限公司\n    - 547、深圳市思乐数据技术有限公司\n    - 548、四川绿源集科技有限公司\n    - 549、湖南云医链生物科技有限公司\n    - 550、杭州源诚科技有限公司\n    - 551、北京开课吧科技有限公司\n    - 552、北京多来点信息技术有限公司\n    - 553、JEECG BOOT低代码开发平台\n    - 554、苏州同元软控信息技术有限公司\n    - 555、江苏大泰信息技术有限公司\n    - 556、北京大禹汇智\n    - 557、北京盛哲科技有限公司\n    - 558、广州钛动科技有限公司\n    - 559、北京大禹汇智科技有限公司\n    - 560、湖南鼎翰文化股份有限公司\n    - 561、苏州安软信息科技有限公司\n    - 562、芒果tv\n    - 563、上海艺赛旗软件股份有限公司\n    - 564、中盈优创资讯科技有限公司\n    - 565、乐乎公寓\n    - 566、启明信息\n    - 567、苏州安软\n    - 568、南京富金的软件科技有限公司\n    - 569、深圳市新科聚合网络技术有限公司\n    - 570、你好现在(北京)科技股份有限公司\n    - 571、360考试宝典\n    - 572、北京一零科技有限公司\n    - 573、厦门星纵信息\n    - 574、Dalligent Solusi Indonesia\n    - 575、深圳华普物联科技有限公司\n    - 576、深圳行健自动化股份有限公司\n    - 577、深圳市富融信息科技服务有限公司\n    - 578、蓝鸟云\n    - 579、上海澎博财经资讯有限公司\n    - 580、北京小鸦科技有限公司\n    - 581、杭州盈泉云科技有限公司\n    - 582、惟客数据\n    - 583、GOSO香蜜闺秀\n    - 584、普乐师（上海）数字科技有限公司\n    - 585、西安市雁塔区咖北堂网络科技部\n    - 586、宁波聚臻智能科技有限公司\n    - 587、普乐师数字科技有限公司\n    - 588、江苏蟹联网科技有限公司\n    - 589、杭州未智科技有限公司\n    - 590、安吉智行物流有限公司\n    - 591、华生大家居集团有限公司\n    - 592、美心食品（广州）有限公司\n    - 593、货拉拉【货拉拉APP】\n    - 594、杭州思韬瑞科技有限公司\n    - 595、杭州玖融科技有限公司\n    - 596、北京优海网络科技有限公司\n    - 597、浙江大维高新技术股份有限公司\n    - 598、粤港澳大湾区数字经济研究院\n    - 599、普康（杭州）健康科技有限公司\n    - 600、华西证券股份有限公司【华西证券】\n    - 601、杭州海康机器人股份有限公司【海康】\n    - 602、河南宸邦信息技术有限公司\n    - 603、成都次元节点网络科技有限公司\n    - 604、富士康科技集团【富士康】\n    - 605、青岛东软载波科技股份有限公司\n    - 606、小菊快跑科技有限公司\n    - 607、视源股份\n    - 608、宁波聚臻智能科技有限公司\n    - 609、阔天科技有限公司\n    - 610、网宿科技有限公司\n    - 611、南京梵鼎信息技术有限公司\n    - 612、房天下【房天下】\n    - 613、特瓦特能源科技有限公司\n    - 614、拓迪智能科技有限公司\n    - 615、东软集团【东软】\n    - 616、开普云\n    - 617、领课网络\n    - 618、南京特维软件有限公司\n    - 619、福建易联众保睿通信息科技有限公司\n    - 620、浙江核心同花顺金融科技有限公司【同花顺】\n    - 621、浙江博观瑞思科技有限公司\n    - 622、北京新美互通科技有限公司\n    - 623、北京有生博大软件股份有限公司\n    - 624、时代中国\n    - 625、鱼泡网\n    - 626、一粒方糖（安徽）科技有限公司\n    - 627、北京外研在线数字科技有限公司\n    - 628、德电（中国）通信技术有限公司\n    - 629、杭州寻联网络科技有限公司\n    - 630、橙联（中国）有限公司\n    - 631、北京承启通科技有限公司\n    - 632、银联数据服务有限公司【银联】\n    - 633、上海晶确科技有限公司\n    - 634、亚信科技有限公司\n    - 635、福建新航物联网科技有限公司\n    - 636、上扬软件\n    - 637、深蓝汽车科技有限公司\n    - 638、南昌节点汇智科技有限公司\n    - 639、锐明技术\n    - 640、再造再生健康科技有限公司\n    - 641、华宝证券\n    - 642、卓正医疗\n    - 643、深圳湛信科技\n    - 644、陕西鑫众为软件有限公司\n    - 645、深圳市润农科技有限公司\n    - 646、庚商教育智能科技有限公司\n    - 647、杭州祎声科技\n    - 648、四川久远银海软件股份有限公司\n    - 649、GeeFox极狐低代码\n    - 650、浙江和仁科技股份有限公司\n    - 651、宁波聚臻智能科技有限公司\n    - 652、福建福昕软件开发股份有限公司【福昕】\n    - 653、广州中长康达信息技术有限公司\n    - 654、武汉趣改信息科技有限公司\n    - 655、北京华夏思源科技发展有限公司\n    - 656、宁波关关通科技有限公司\n    - 657、青岛吕氏餐饮有限公司\n    - 658、杭州乐刻网络科技有限公司\n    - 659、上海红瓦信息科技有限公司\n    - 660、陕西旅小宝信息科技有限公司\n    - 661、中科卓恒(大连)科技有限公司\n    - 662、北京华益精点生物技术有限公司\n    - 663、马士基（中国）航运有限公司【马士基】\n    - 664、陕西美咚网络科技有限公司\n    - 665、山东新北洋信息技术股份有限公司 \n    - 666、福建中瑞文化发展集团有限公司\n    - 667、黑龙江省建工集团有限责任公司【黑龙江省建工】\n    - 668、志信能达安全科技(广州)有限公司\n    - 669、重庆开源共创科技有限公司\n    - 670、华泰人寿保险股份有限公司【华泰人寿】\n    - 671、成都盘古纵横集团\n    - 672、北京果果乐学科技有限公司\n    - 673、北京凌云空间科技有限公司\n    - 674、临工重机股份有限公司\n    - 675、上海热风时尚管理集团【热风】\n    - 676、HashKey Exchange\n    - 677、傲基（深圳）跨境商务股份有限公司\n    - 678、青岛文达通科技股份有限公司\n    - 679、杭州普罗云科技有限公司\n    - 680、浙江云鹭科技有限公司\n    - 681、中山市芯宏柿网络科技有限公司\n    - 682、深圳市家家顺物联科技\n    - 683、重庆斑西科技有限公司\n    - 684、福建省泰古信息技术有限公司\n    - 685、贵阳永青仪电科技有限公司\n    - 686、广州博依特智能信息科技有限公司\n    - 687、河南宠呦呦信息技术有限公司\n    - 688、陕西星邑空间技术有限公司\n    - 689、广东西欧克实业有限公司\n    - 690、唱吧麦颂KTV\n    - 691、联通云\n    - 692、北京爱话本科技有限公司\n    - 693、北京起创科技有限公司\n    - 694、平安证券【平安证券】\n    - 695、合肥中科类脑智能技术有限公司\n    - 696、南京同仁堂健康产业有限公司【同仁堂】\n    - 697、铜仁市碧江区智惠加油站\n    - 698、惟客数据\n    - 699、凤凰新闻【凤凰新闻】\n    - 700、深圳王力智能\n    - 701、返利网数字科技股份有限公司\n    - 702、上海阜能信息科技有限公司\n    - 703、深圳市极能超电数字科技有限公司\n    - 704、海目星激光科技集团股份有限公司\n    - 705、安克创新科技股份有限公司【安克】\n    - 706、大庆点神科技有限公司\n    - 707、浙江零跑科技股份有限公司【零跑】\n    - 708、成都成电金盘健康数据技术有限公司\n    - 709、成都极米科技股份有限公司【极米】\n    - 710、顺德职业技术大学\n    - 711、中邮证券有限责任公司【中邮证券】\n    - 712、志豪链云科技有限公司\n    - 713、湖南万鲸科技有限公司\n    - 714、广州万表\n    - 715、再惠（上海）网络科技有限公司\n    - 716、上海爱诚裕信息科技有限公司\n    - 717、杭州迈瑞数字科技有限公司\n    - 718、广州串联网络科技有限公司\n\t- ……\n\n> The company that access and use this product is welcome to register at the [address](https://github.com/xuxueli/xxl-job/issues/1 ), only for product promotion. \n\nWelcome everyone's attention and use, XXL-JOB will also embrace changes, sustainable development.\n\n### 1.4 Download\n\n#### Documentation\n- [中文文档](https://www.xuxueli.com/xxl-job/)\n- [English Documentation](https://www.xuxueli.com/xxl-job/en/)\n\n#### Source repository address (The latest code will be released in the two git warehouse in the same time)\n\nSource repository address | Release Download\n--- | ---\n[https://github.com/xuxueli/xxl-job](https://github.com/xuxueli/xxl-job) | [Download](https://github.com/xuxueli/xxl-job/releases)  \n[http://gitee.com/xuxueli0323/xxl-job](http://gitee.com/xuxueli0323/xxl-job) | [Download](http://gitee.com/xuxueli0323/xxl-job/releases)\n\n#### Center repository address (The latest Release version：1.8.1)\n```\n<!-- http://repo1.maven.org/maven2/com/xuxueli/xxl-job-core/ -->\n<dependency>\n    <groupId>com.xuxueli</groupId>\n    <artifactId>xxl-job-core</artifactId>\n    <version>${version}</version>\n</dependency>\n```\n\n#### Technical exchange group\n- [社区交流](https://www.xuxueli.com/page/community.html)\n- [Gitter](https://gitter.im/xuxueli/xxl-job)\n\n### 1.5 Environment\n- JDK：1.8+\n- Mysql：5.7+\n- Maven：3+\n\n\n## 2. Quick Start\n\n### 2.1 Init database\nPlease download project source code，get db scripts and execute, it will generate 16 tables if succeed.\n\nThe relative path of db scripts is as follows:\n\n    /xxl-job/doc/db/tables_xxl_job.sql\n\nThe xxl-job-admin can be deployed as a cluster,all nodes of the cluster must connect to the same mysql instance.\n\nIf mysql instances is deployed in master-slave mode,all nodes of the cluster must connect to master instace.\n\n### 2.2 Compile\nSource code is organized by maven,unzip it and structure is as follows:\n\n    xxl-job-admin：schedule admin center\n    xxl-job-core：public common dependent library\n    xxl-job-executor：executor Sample(Select appropriate version of executor,Can be used directly,You can also refer to it and transform existing projects into executors）\n        ：xxl-job-executor-sample-spring：Spring version，executors managed by Spring，general and recommend;\n        ：xxl-job-executor-sample-springboot：Springboot version，executors managed by Springboot;\n\t\n### 2.3 Configure and delploy \"Schedule Center\"\t\n\n    schedule center project:xxl-job-admin\n    target:Centralized management、Schedule and trigger task\n\n#### Step 1:Configure Schedule Center\nConfigure file’s path of schedule center is as follows:\n\n    /xxl-job/xxl-job-admin/src/main/resources/application.properties\n\n\nThe concrete contet describe as follows:\n\n    ### JDBC connection info of schedule center：keep Consistent with chapter 2.1\n    xxl.job.db.driverClass=com.mysql.jdbc.Driver\n    xxl.job.db.url=jdbc:mysql://127.0.0.1:3306/xxl_job?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai\n    xxl.job.db.user=root\n    xxl.job.db.password=root_pwd\n    \n    ### Alarm mailbox\n    xxl.job.mail.host=smtp.163.com\n    xxl.job.mail.port=25\n    xxl.job.mail.username=ovono802302@163.com\n    xxl.job.mail.password=asdfzxcv\n    xxl.job.mail.sendFrom=ovono802302@163.com\n    xxl.job.mail.sendNick=《任务调度平台XXL-JOB》\n    \n    ### Login account\n    xxl.job.login.username=admin\n    xxl.job.login.password=123456\n    \n    ### TOKEN used for communication between the executor and schedule center, enabled if it’s not null\n    xxl.job.accessToken=\n    \n    ### Internationalized Settings, the default is Chinese version，Switch to English when the value is \"en\".\n    xxl.job.i18n=en\n\n#### Step 2:Deploy:\nIf you has finished step 1,then you can compile the project in maven and deploy the war package to tomcat.\nthe url to visit is :http://localhost:8080/xxl-job-admin (this address will be used by executor and use it as callback url),the index page after login in is as follow\n\n![index page after login in](https://www.xuxueli.com/doc/static/xxl-job/images/img_6yC0.png \"index page after login in\")\n\nNow,the “xxl-job-admin” project is deployed success.\n\n#### Step3:schedule center Cluster(Option):\nxxl-job-admin can be deployed as a cluster to improve system availability.\n\nPrerequisites for cluster is to keep all node configuration(db and login account info) consistent with each other. Different xxl-job-admin cluster distinguish with each other by db configuration.\n\nxxl-job-admin can be visited through nginx proxy and configure a domain for nginx,and the domain url can be configured as the executor’s callback url.\n\n### 2.4 Configur and Deploy \"xxl-job-executor-example\"\n\n    Executor Project:xxl-job-executor-example (if you want to create new executor project you can refer this demo);\n    Target:receive xxl-job-admin’s schedule command and execute it;\n    \n#### Step 1:import maven dependence\nPleast confirm import xxl-job-core jar in pom.xml;\n    \n#### Step 2:Executor Configuration\nRelative path of the executor configuration file is as follows:\n\n    /xxl-job/xxl-job-executor-samples/xxl-job-executor-sample-spring/src/main/resources/xxl-job-executor.properties\n\nThe concret content of configuration file as follows:\n\n    ### xxl-job admin address list：xxl-job-admin address list: Multiple addresses are separated by commas,this address is used for \"heart beat and register\" and \"task execution result callback\" between the executor and xxl-job-admin.\n    xxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin\n    \n    ### xxl.job.executor.appname is used to group by executors\n    xxl.job.executor.appname=xxl-job-executor-sample\n    ### xxl.job.executor.ip :1,used to register with xxl-job-admin;2,xxl-job-admin dispatch task to executor through it;3,if it is blank executor will get ip automatically, multi network card need to be configured.\n    xxl.job.executor.ip=\n    ### xxl.job.executor.port :the port of the executor runned by,if multiple executor instance run on the same computer the port must different with each other\n    xxl.job.executor.port=9999\n    \n    ### xxl-job log path：runtime log path of the job instance\n    xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler/\n    \n    ### xxl-job, access token：xxl-job access token,enabled if it not blank\n    xxl.job.accessToken=\n\n\n#### Step 3:executor configuration\n\nconfigure file path of executor:\n\n    /xxl-job/xxl-job-executor-samples/xxl-job-executor-sample-spring/src/main/resources/applicationcontext-xxl-job.xml\n\nConcrete contet describe as follows：\n\n```\n<!-- configure 01、JobHandler scan path：auto scan JobHandler bean managed by container -->\n<context:component-scan base-package=\"com.xxl.job.executor.service.jobhandler\" />\n\n<!-- configure 02、Excutor：executer core configure -->\n<bean id=\"xxlJobExecutor\" class=\"com.xxl.job.core.executor.XxlJobExecutor\" init-method=\"start\" destroy-method=\"destroy\" >\n    <!-- executor IP[required]，auto get if it blank -->\n    <property name=\"ip\" value=\"${xxl.job.executor.ip}\" />\n    <!-- executor port[required] -->\n    <property name=\"port\" value=\"${xxl.job.executor.port}\" />\n    <!-- executor AppName[required]，auto register will be closed if it blank -->\n    <property name=\"appname\" value=\"${xxl.job.executor.appname}\" />\n    <!-- register center address of executor [required]，auto register will be closed if it blank -->\n    <property name=\"adminAddresses\" value=\"${xxl.job.admin.addresses}\" />\n    <!-- log path of executor[required] -->\n    <property name=\"logPath\" value=\"${xxl.job.executor.logpath}\" />\n    <!-- access token, match check enabled if it not blank[required] -->\n    <property name=\"accessToken\" value=\"${xxl.job.accessToken}\" />\n</bean>\n```\n\n#### Step 4:deploy executor project\nYou can compile and package the project If have done all the steps above successfully,the project supply two executor demo projects,you can choose any one to deploy:\n\n    xxl-job-executor-sample-spring:compile and package in WAR,can be deployed to tomcat;\n    xxl-job-executor-sample-springboot:compile and package in JAR,and run in springboot mode;\n\nNow you have deployed the executor project.\n\n#### Step 5:executor cluster(optional)\nIn order to improve system availability and job process capacity,executor project can be deployed as cluster.\n\nPrerequisites:keep all node’s configuration item \"xxl.job.admin.addresses\" exactly the same with each other,all executors can be register automatically. \n\n\n### 2.5 Start first job \"Hello World\"      \nNow let’s create a \"GLUE模式(Java)\" job,if you want to learn more about it , please see “chapter 3：Task details”。( \"GLUE模式(Java)\"'s code is maintained online through xxl-job-admin,compare with \"Bean模式任务\" it’s not need to develop, deploy the code on the executor and it’s not need to restart the executor, so it’s lightweight）\n\n#### Prerequisites:please confirm xxl-job-admin and executor project has been deployed successfully.\n\n#### Step 1:Create new job\nLogin in xxl-job-admin,click on the\"新建任务\" button, configure the job params as follows and click \"保存\" button to save the job info.\n\n![task management](https://www.xuxueli.com/doc/static/xxl-job/images/img_o8HQ.png \"task management\")\n\n![create task](https://www.xuxueli.com/doc/static/xxl-job/images/img_ZAsz.png \"create task\")\n\n#### Step 2：develop “GLUE模式(Java)” job\nClick “GLUE” button on the right of the job to go to GLUE editor view as shown below。“GLUE模式(Java)” mode task has been inited with default task code for printing Hello World。 （ “GLUE模式(Java)” mode task is a java code fragment implements IJobHandler interface,it will be executed in executor,you can use @Resource/@Autowire to inject other java bean instance,if you want to see more info please go to chapter 3）\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_Fgql.png \"在这里输入图片标题\")\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_dNUJ.png \"在这里输入图片标题\")\n\n#### Step 3:trigger task\nIf you want to run the job manually please click \"执行\" button on the right of the job(usually we trigger job by Cron expression)\n\n#### Step 4:view log \nClick “日志” button on the right side of the task you will go to the task log list ,you will see the schedule history records of the task and the schedule detail info,execution info and execution params.If you click the “执行日志” button on the right side of the task log record,you will go to log console and view the execute log in the course of task execution.\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_inc8.png \"在这里输入图片标题\")\n\nOn the log console,you can view task execution log on the executor immediately after it dump to log file,so you can monitor the task execution process by Rolling way.\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_eYrv.png \"在这里输入图片标题\")\n\n## 3. Task details\n\n### Description of configuration item:\n\n    - 执行器：the container where job executed in,it will be discovered automaticly if it has registered success when job was scheduled,and the job will be executed automaticly through this way.On the other side all tasks was grouped by this way.Tasks must be binded to a executor and it can be configured on \"执行器管理\"  page;\n    - 描述：the decription of task\n    - 路由策略：when executors deployed as a cluster,it can configure multi route policys,include:\n        FIRST（第一个）：default select the first executor;\n        LAST（最后一个）：default select the last executor;\n        ROUND（轮询）：round select the executor;；\n        RANDOM（随机）：random select the executor;\n        CONSISTENT_HASH（一致性HASH）：all jobs was evenly scheduled on different machines,make sure load balance of executors under the same group and the same job will be scheduled to the same machine.\n        LEAST_FREQUENTLY_USED（最不经常使用）：default select the least often used executor.\n        LEAST_RECENTLY_USED（最近最久未使用）：defalut select the longest not used executor.\n        FAILOVER（故障转移）：beat with the executor in order and select the first beat success executor as target executor.\n        BUSYOVER（忙碌转移）：check the executor busy or not in order,the first executor checked not busy is to be select as the target scheduled executor.\n        SHARDING_BROADCAST(分片广播)：broadcast all executor nodes under the same executor group execute the job, slice number will be transferred at the same time,shard task will be executed accordate with the shard number.\n        \n    - Cron：Cron expression used to trigger job execution;\n    - 运行模式：\n        BEAN模式：job was maintained on the side of executor by  as JobHandler instance,it will be executed accordate with \"JobHandler\" properties.\n        GLUE模式(Java)：task source code is maintened in the schedule center,it must implement IJobHandler and explain by \"groovy\" in the executor instance,inject other bean instace by annotation @Resource/@Autowire.\n        GLUE模式(Shell)：it’s source code is a shell script and maintained in the schedule center.\n        GLUE模式(Python)：it’s source code is a python script and maintained in the schedule center.\n    - JobHandler：it’s used in  \"BEAN模式\",it’s instance is defined by annotation @JobHandler on the JobHandler class name.\n    - 子任务Key：every task has a unique key (task Key can acquire from task list)，when main task is done successfully it’s child task stand for by this key will be scheduled.\n    - 阻塞处理策略：the stategy handle the task when this task is scheduled too frequently and the task is block to wait for cpu time.\n        单机串行（默认）：task schedule request go into the FIFO queue and execute serially.\n        丢弃后续调度：the schedule request will be discarded and marked as fail when the same task’s  instance scheduled befor is running in the target executor.\n        覆盖之前调度：the schedule request will be executed and clear before task queue when the same task’s  instance scheduled befor is running in the target executor.\n    - 失败处理策略:handle policy for schedule fail\n        失败告警（默认）：it will trigger alarm such as send alarm mail when it’s scheduled fail.\n        失败重试：it will try another time when it’s scheduled fai,if try fail it will trigger alarm for fail.every time it will trigger a new schedule request.\n    - 执行参数：the params needed in the run time of the task, multiple values are separated by commas,it will be passed to task instace as an array when task is scheduled. \n    - 报警邮件：the email used to receive the alarm mail when task is scheduled fail or execute fail, multiple values are separated by commas.\n    - 负责人：The person name response for the task.\n    \n### 3.1 BEAN模式\nThe task logic exist in the executor project as JobHandler,the develop steps as shown below:\n\n#### Step 1:develp obHandler in the executor project\n    - 1, create new java class implent com.xxl.job.core.handler.IJobHandler;\n    - 2, if you add @Component annotation on the top of the class name it’s will be managed as a bean instance by spring container;\n    - 3, add  “@JobHandler(value=\" customize jobhandler name\")” annotation，the value stand for JobHandler name,it will be used as JobHandler property when create a new task in the schedule center.\n\n\n#### Step 2:create task in schedule center\nIf you want learn more about configure item please go and sedd “Description of configuration item”，select  \"BEAN模式\" as run mode，property JobHandler please fill in the value defined by @JobHande.\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_ZAsz.png \"在这里输入图片标题\")\n\n### 3.2 GLUE模式(Java)\nTask source code is maintained in the schedule center and can be updated by Web IDE online, it will be compiled and effective real-time,didn’t need to assign JobHandler,develop flow shown as below:\n\n#### Step 1:create task in schedule center\nIf you want learn more about configure item please go and sedd “Description of configuration item”，select \"GLUE模式(Java)\" as run mode.\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_tJOq.png \"在这里输入图片标题\")\n\n#### Step 2:develop task source code\nSelect the task record and click “GLUE” button on the righe of it,it will go to GLUE task’s WEB IDE page,on this page yo can edit you task code(also can edit in other IDE tools,copy and paste into this page).\n\nVersion backtrack（support 30 versions while backtrack）：on the WEB IDE page of GLUE task,on upper right corner drop down box please select “版本回溯”,it will display GLUE updated history,select the version you want it will display the source code of this version,it will backtrace the version while click save button. \n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_dNUJ.png \"在这里输入图片标题\")\n\n### 3.3 GLUE模式(Shell)\n\n#### Step 1:create new task in schedule center  \nIf you want learn more about configure item please go and sedd “Description of configuration item”，select \"GLUE模式(Shell)\"as run mode.\n\n#### Step 2:develop task source code\nSelect the task record and click “GLUE” button on the righe of it,it will go to GLUE task’s WEB IDE page,on this page yo can edit you task code(also can edit in other IDE tools,copy and paste into this page).\n\nActually it is a shell script fragment.\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_iUw0.png \"在这里输入图片标题\")\n\n### 3.4 GLUE模式(Python)\n\n#### Step 1:create new task in schedule center  \nIf you want learn more about configure item please go and sedd “Description of configuration item”，select \"GLUE模式(Python)\"as run mode.\n\n#### Step 2:develop task source code\nSelect the task record and click “GLUE” button on the righe of it,it will go to GLUE task’s WEB IDE page,on this page yo can edit you task code(also can edit in other IDE tools,copy and paste into this page).\n\nActually it is a python script fragment.\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_BPLG.png \"在这里输入图片标题\")\n\n\n## 4. Task Management\n### 4.0 configure executor\nclick\"执行器管理\" on the left menu,it will go to the page as shown below:\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_Hr2T.png \"在这里输入图片标题\")\n\n    1,\"调度中心OnLine”:display schedule center machine list,when task is scheduled it will callback schedule center for notify the execution result in failover mode, so that it can avoid a single point scheduler;\n    2,\"执行器列表\" :display all nodes under this executor group.\n\nIf you want to create a new executor,please click \"+新增执行器\" button: \n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_V3vF.png \"在这里输入图片标题\")\n\n### Description of executor attributes\n\n    Appname: the unique identity of the executor cluster,executor will registe automatically and periodically by appname so that it can be scheduled.\n    名称: the name of ther executor,it is used to describe the executor.\n    排序: the order of executor,it will be used in the place where need to select executor.\n    注册方式:which way the schedule center used to acquire executor address through;\n        自动注册:executor will register automatically,through this schedule center can discover executor dynamically.\n        手动录入:fill in executor address manually and it will be used by schedule center, multiple address separated by commas. \n    机器地址:only effective when \"注册方式\" is \"手动录入\",support fill in executor address manually.\n\n### 4.1 create new task\nGo to task management list page,click “新增任务” button on the upper right corner，on the pop-up window“新增任务”page configure task property and save.learn more info please go and see \"3,task details\".\n\n### 4.2 edit task\nGo to task management list page and choose the task you want to edit ,click”编辑”button on the right side of the task,on the pop-up window “编辑任务”page edit task property and save.\n\n### 4.3 edit GLUE source code\n\nOnly fit to GLUE task.\n\nchoose the task you want to edit and click” GLUE”button on the right side of the task, it will go to the Web IDE page of GLUE task,then you can edit task source code on this page.you can read \"3.2 GLUE模式(Java)\" for more info.\n\n### 4.4 pause/recover task\nYou can pause or recover task but it just fit to follow up schedule trigger and won’t affect scheduled tasks,if you want to stop tasks which has been triggered,please go and see “4.8 stop the running task”\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_ZAhX.png \"在这里输入图片标题\")\n\n### 4.5 manually trigger\nYou can trigger a task manually by Click “执行”button,it won’t affect original scheduling rules.\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_Z5wp.png \"在这里输入图片标题\")\n\n### 4.6 view schedule log\nYou can view task’s history schedule log by click “日志” button,on the history schedule log list page you can view every time of task’s schedule result,execution result and so on,click “执行日志” button can view the task’s full execute log.\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_9235.png \"在这里输入图片标题\")\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_inc8.png \"在这里输入图片标题\")\n\n    调度时间:schedule center trigger time when schedule and send execution signal to executor;\n    调度结果:schedule center trigger task’s result, 200 represent success,500 or other number stands for fail;\n    调度备注:schedule center trigger task’s remark info;\n    执行器地址:the machine address where the task was executed;\n    运行模式:run mode of triggered task,go and see  \"3,Task Details\" for more info;\n    任务参数:the input params of the executed task;\n    执行时间:the callback time task was done in the executor;\n    执行结果:task’s execute result in the executor, 200 represent success,500 or other number stands for fail;\n    执行备注:task’s execute remark info in the executor;\n    操作:\n        \"执行日志\"button:click this button you can view task’s execution detail log,go and see chapter 4.7 “view execution log” for more info;\n        \"终止任务\"button:click this button you can stop the task’s execution thread on this executor,include bloked task instance which didn’t has started;\n\n### 4.7 view execution log\nClick the “执行日志” button on the right side of the record,you can go to the execution log page,you can view the full execution log of the logic business code, shown as below:\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_tvGI.png \"在这里输入图片标题\")\n\n### 4.8 stop running tasks\nJust fit to running tasks,on the task log list page,click “终止任务” button on the right side of the record, it will send stop command to the executor where the task was executed,finally the task was killed and the task instance execute queue of this task will be clear.\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_hIci.png \"在这里输入图片标题\")\n\nIt is implemented by interrupt execute thread, it will trigger InterruptedException.so if JobHandler catch this execuption and handle this exception this function is unavailable.\n\nSo if you want stop the running task ,the JobHandler need to handle InterruptedException separately by throw this exception.the right logic is as shown below:\n```\ntry{\n    // do something\n} catch (Exception e) {\n    if (e instanceof InterruptedException) {\n        throw e;\n    }\n    logger.warn(\"{}\", e);\n}\n```\n\nIf JobHandler start child thread,child thread also must not catch InterruptedException,and it should throw exception.\n\n\n### 4.9 delete execution log\nOn the task log list page, after you select executor and task, you can click\"删除\" button on the right side and it will pop-up \"日志清理\" window,on the pop-up window you can choose different log delete policy,choose the policy you want to execute and click \"确定\" button it will delele relative logs:\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_Ypik.png \"在这里输入图片标题\")\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_EB65.png \"在这里输入图片标题\")\n\n### 4.10 delete task\nClick the delete button on the right side of the task,the task will be deteted.\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_Z9Qr.png \"在这里输入图片标题\")\n\n## 5. Overall design\n### 5.1 Source directory introduction\n    - /doc :documentation and material\n    - /db :db scripts\n    - /xxl-job-admin :schedule and admin center\n    - /xxl-job-core :common core Jar\n    - /xxl-job-executor-samples :executor，Demo project（you can develop on this demo project or adjust your own exist project to executor project)\n\n### 5.2 configure database\nXXL-JOB schedule module is implemented based on Quartz cluster,it’s “database” is extended based on Quartz’s 11 mysql tables.\n\nXXL-JOB custom Quartz table structure prefix(XXL_JOB_QRTZ_).\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_bNwm.png \"在这里输入图片标题\")\n\nThe added tables as shown below:\n    - XXL_JOB_QRTZ_TRIGGER_GROUP:executor basic table, maintain the info about the executor;\n    - XXL_JOB_QRTZ_TRIGGER_REGISTRY:executor register table, maintain addressed of online executors and schedule center machines.\n    - XXL_JOB_QRTZ_TRIGGER_INFO:schedule extend table,it is used to save XXL-JOB schedule extended info,such as task group,task name,machine address,executor,input params of task and alarm email and so on.\n    - XXL_JOB_QRTZ_TRIGGER_LOG:schedule log table,it is used to save XXL-JOB task’s histry schedule info,such as :schedule result,execution result,input param of scheduled task,scheduled machine and executor and so on.\n    - XXL_JOB_QRTZ_TRIGGER_LOGGLUE:schedule log table,it is used to save XXL-JOB task’s histry schedule info,such as :schedule result,execution result,input param of scheduled task,scheduled machine and executor and so on.\n\nSo XXL-JOB database total has 16 tables.\n\n### 5.3 Architecture design\n#### 5.3.1 Design target\nAll schedule behavior has been abstracted into “schedule center” common platform , it dosen’t include business logic and just responsible for starting schedule requests.\n\nAll tasks was abstracted into separate JobHandler and was managed by executors, executor is responsible for receiving schedule request and execute the relative JobHandler business.\n\nSo schedule and task can be decoupled from each other, by the way it can improve the overall stability and scalability of the system.\n\n#### 5.3.2 System composition\n- **Schedule module（schedule center）**:\n    it is responsible for manage schedule info,send schedule request accord task configuration and it is not include an business code.schedule system decouple with the task, improve the overall stability and scalability of the system, at the same time schedule system performance is no longer limited to task modules. \n    Support visualization, simple and dynamic management schedule information, include create,update,delete, GLUE develop and task alarm and so on, All of the above operations will take effect in real time，support monitor schedule result and execution log and executor failover.\n- **Executor module（Executor）**:\n    it is responsible for receive schedule request and execute task logic,task module focuses on the execution of the task, Development and maintenance is simpler and more efficient.\n    Receive execution request, end request and log request from schedule center.\n\n#### 5.3.3 Architecture diagram\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_Qohm.png \"在这里输入图片标题\")\n\n### 5.4 Schedule module analysis\n#### 5.4.1 Disadvantage of quartz\nQuartz is a good open source project and was often as the first choice for job schedule.Tasks was managed by api in quartz cluster so it can avoid some  disadvantages of single quartz instance,but it also has some disadvantage as shown below:\n    - problem 1:it is not humane while operate task by call apill.\n    - problem 2:it is need to store business QuartzJobBean into database, System Invasion is quite serious.\n    - problem 3:schedule logic and couple with QuartzJobBean in the same project,it will lead a problem in case that if schedule tasks gradually increased and task logic gradually increased,under this situation the performance of the schedule system will be greatly limited by business.\nXXL-JOB solve above problems of quartz.\n\n#### 5.4.2 RemoteHttpJobBean\nUnder Quartz develop,task logic often was maintained by QuartzJobBean, couple is very serious.in XXL-JOB\"Schedule module\" and \"task module\" are completely decoupled,all scheduled tasks in schedule module use the same QuartzJobBean called RemoteHttpJobBean.the params of the tasks was maintained in the extended tables,when trigger RemoteHttpJobBean,it will parse different params and start remote cal l and it wil call relative remote executor.\n\nThis call module is like RPC,RemoteHttpJobBean provide call proxy functionality,the executor is provided as remote service.\n\n#### 5.4.3 Schedule Center HA（Cluster）\nIt is based on Quartz cluster，databse use Mysql；while QUARTZ task schedule is used in Clustered Distributed Concurrent Environment,all nodes will report task info and store into database.it will fetch trigger from database while execute task,if trigger name and execute time is the same only one node will execute the task.\n\n```\n# for cluster\norg.quartz.jobStore.tablePrefix = XXL_JOB_QRTZ_\norg.quartz.scheduler.instanceId: AUTO\norg.quartz.jobStore.class: org.quartz.impl.jdbcjobstore.JobStoreTX\norg.quartz.jobStore.isClustered: true\norg.quartz.jobStore.clusterCheckinInterval: 1000\n```\n\n#### 5.4.4 Schedule threadpool\nDefault threads in the threadpool is 10 so it can avoid task schedule delay because of single thread block.\n\n```\norg.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool\norg.quartz.threadPool.threadCount: 10\norg.quartz.threadPool.threadPriority: 5\norg.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true\n```\n\nbusiness logic was executed on remote executor in XXL-JOB,schedule center just start one schedule request at every schedule time,executor will inqueue the request and response schedule center immediately. There is a huge difference from run business logic in quartz’s  QuartzJobBean directly，just as Elephants and feathers；\n\nthe logic of task in XXL-JOB schedule center is very light and single job average run time alaways under 100ms,（most  is network time consume）.so it can use limited threads to support a large mount of job run concurrently, 10 threads configured above can support at least 100 JOB normal execution.\n\n#### 5.4.5 @DisallowConcurrentExecution\nThis annotation is not used default by the schedule center of XXL-JOB schedule module, it use concurrent policy default,because RemoteHttpJobBean is common QuartzJobBean,so it greatly improve the capacity of schedule system and decrease the blocked chance of schedule module in the case of multi-threaded schedule.\n\nEvery schedule module was scheduled and executed parallel in XXL-JOB,but tasks in executor is executed serially and support stop task.\n\n#### 5.4.6 misfire\nThe handle policy when miss the job’s trigger time.\nhe reason may be:restart service,schedule thread was blocked by QuartzJobBean, threads was exhausted,some task enable @DisallowConcurrentExecution，the last schedule  was blocked and next schedule was missed.\n\nThe default value of misfire in quartz.properties as shown below, unit in milliseconds:\n```\norg.quartz.jobStore.misfireThreshold: 60000\n```\n\nMisfire rule:\n    withMisfireHandlingInstructionDoNothing:does not trigger execute immediately and wait for next time schedule. \n    withMisfireHandlingInstructionIgnoreMisfires:execute immediately at the first frequency of the missed time.\n    withMisfireHandlingInstructionFireAndProceed:trigger task execution immediately at the frequency of the current time.\n\nXXL-JOB’s default misfire rule:withMisfireHandlingInstructionDoNothing\n\n```\nCronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(jobInfo.getJobCron()).withMisfireHandlingInstructionDoNothing();\nCronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(cronScheduleBuilder).build();\n```\n\n#### 5.4.7 log callback service\nWhen schedule center of the schedule module was deployed as web service, on one side it play as schedule center, on the other side it also provide api service for executor. \n\nThe source code location of schedule center’s “log callback api service” as shown below:\n```\nxxl-job-admin#com.xxl.job.admin.controller.JobApiController.callback\n```\n\nExecutor will execute task when it receive task execute request.it will notify the task execute result to schedule center when the task is done. \n\n#### 5.4.8 task HA（Failover）\nIf executor project was deployed as cluster schedule center will known all online executor nodes,such as:“127.0.0.1:9997, 127.0.0.1:9998, 127.0.0.1:9999”.\n\nWhen \"路由策略\" select \"故障转移(FAILOVER)\",it will send heart beat check request in order while schedule center start schedule request.  The first alive checked executor node will be selected and send schedule request to it.\n\n“调度备注” can be viewed on the monitor page when schedule success. As shown below: \n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_jrdI.png \"在这里输入图片标题\")\n\n“调度备注” will display local schedule route path、executor’s \"注册方式\"、\"地址列表\" and task’s \"路由策略\"。Under \"故障转移(FAILOVER)\" policy, schedule center take first address to do heartbeat detection, heat beat fail will automatically skip, the second address heart beat fail…… until the third address “127.0.0.1:9999” heart beat success, it was selected as target executor, then send schedule request to target executor, now the schedule process is end wait for the executor’s callback execution result.\n\n#### 5.4.9 schedule log\nEvery time when task was scheduled in the schedule center it will record a task log, the task log include three part as shown below:\n\n- 任务信息:include executor address、JobHandler and executor params，accord these parameters it can locate specific machine and task code that the task will be executed.\n- 调度信息:include schedule time、schedule result and  schedule log  and so on，accord these parameters you can understand some task schedule info of schedule center.\n- 执行信息:include execute time、execute result and execute log and so on, accord these parameters you can understand the task execution info in the executor.\n\nSchedule log stands fo single task schedule, attribute description is as follows:\n- 执行器地址:machine addresses on which task will be executed.\n- JobHandler:JobHandler name of task under Bean module.\n- 任务参数:the input parameters of task\n- 调度时间:the schedule time started by schedule center.\n- 调度结果:schedule result of schedule center,SUCCESS or FAIL.\n- 调度备注:remark info of task scheduled by schedule center, such as address heart beat log.\n- 执行时间:the callback time when the task is done in the executor.\n- 执行结果:task execute result in the executor,SUCCESS or FAIL.\n- 执行备注:task execute remark info in the executor,such as exception log.\n- 执行日志:full execution log of the business code during execution of the task,go and see “4.7 view execution log”.\n\n#### 5.4.10 Task dependency\nprinciple:every task has a task key in XXL-JOB, every task can configure property “child task Key”,it can match task dependency relationship through task key.\n\nWhen parent task end execute and success, it will match child task dependency accord child task key, it will trigger child task execute once if it matched child task.\n\nOn the task log page ,you can see matched child task and triggered child task’s log info when you “查看”button of “执行备注”,otherwise the child task didin’t execute, as shown beleow:\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_Wb2o.png \"在这里输入图片标题\")\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_jOAU.png \"在这里输入图片标题\")\n\n### 5.5 Task \"run mode\" analysis\n#### 5.5.1 \"Bean模式\" task\nDevelopment steps:go and see \"chapter 3\" . \nprinciple: every Bean mode task is a Spring Bean instance and it is maintained in executor project’s Spring container. task class nedd to add “@JobHandler(value=\"name\")” annotation, because executor identify task bean instance in spring container through annotation. Task class nedd to implements interface IJobHandler, task logic code in method execute(), the task logic in execute() method will be executed when executor received a schedule request from schedule center.\n\n#### 5.5.2 \"GLUE模式(Java)\" task\nDevelopment steps:go and see \"chapter 3\" .\nPrinciple : every \"GLUE模式(Java)\" task code is a class implemets interface IJobHandler, when executor received schedule request from schedule center these code will be loaded by Groovy classloader and instantiate into a Java object and inject spring bean service declared in this code at the same time（please confirm service and class reference in Glue code exist in executor project）, then call the object’s execute() method and execute task logic.\n\n#### 5.5.3 GLUE模式(Shell) + GLUE模式(Python)\nDevelopment steps:go and see \"chapter 3\" .\nprinciple:the source code of script task is maintained in schedule center and script logic will be executed in executor. when script task was triggered, executor will load script source code and generate a script file on the machine where executor was deployed, the script will be called by java code, the script output log will be written to the task log file in real time so that we can monitor script execution in real time through schedule center, the return code 0 stands for success other for fail.\n\nAll supported types of scripts as shown beloes:\n\n    - shell script:shell script task will be enabled when select \"GLUE模式(Shell)\"as task run mode.\n    - python script: python script task will be enabled when select \" GLUE模式(Python)\"as task run mode.\n    \n\n#### 5.5.4 executor\nExecutor is actually an embedded Jetty server with default port 9999, as shown below（parameter:xxl.job.executor.port）.\n\nExecutor will identify Bean mode task in spring container through @JobHandler When project start, it will be managed use the value of annotation as key. \n\nWhen executor received schedule request from schedule center, if task type is “Bean模式” it will match bean mode task in Spring container and call it’s execute() method and execute task logic. if task type is “GLUE模式”, it will load Glue code, instantiate a Java object and inject other spring service（notice: the spring service injected in Glue code must exist in the same executor project）, then call execute() method and execute task logic. \n\n#### 5.5.5 task log\nXXL-JOB will generate a log file for every schedule request, the log info will be recorded by XxlJobLogger.log() method, the log file will be loaded when view log info through schedule center.\n\n(history version is implemented by overriding LOG4J’s Appender so it exists dependency restrictions, The way has been discraded in the new version)\n\nThe location of log file can be specified in executor configuration file, default pattern is : /data/applogs/xxl-job/jobhandler/formatted date/primary key for database scheduling log records.log”.\n\nWhen start child thread in JobHandler, child thread will print log in parent JobHandler thread’s execute log in order to trace execute log.\n\n### 5.6 Communication module analysis\n\n#### 5.6.1 A complete task schedule communication process\n    - 1,schedule center send http request to executor, and the service in executor in fact is a jetty server with default port 9999.\n    - 2,executor execute task logic.\n    - 3,executor http callback with schedule center for schedule result, the service in schedule center used to receive callback request from executor is a set of api opended to executor.\n\n#### 5.6.2 Encrypt Communication data\nWhen scheduler center send request to executor, it will use RequestModel and ResponseModel object to encapsulate schedule request parameters and response data, these two object will be serialized before communication, data protocol and time stamp will be checked so that achieve data encryption target.\n\n### 5.7 task register and task auto discover  \nTask executor machine property has been canceled from v1.5, instead of task register and auto discovery, get remote machine address dynamic.\n\n    AppName: unique identify of executor cluster,  executor is minimal unite of task register, every task recognize machine addresses under the executor on which it was binded.\n    Beat: heartbeat cycle of task register, default is 15s, and the time executor usedto register is twice the time, the time used to auto task discover is twice the beat time, the invalid time of register is twice the Beat time.\n    registry table: see XXL_JOB_QRTZ_TRIGGER_REGISTRY table, it will maintain a register record periodically while task register, such as the bind relationship between machine address and AppName, so that schedule center can recognize machine list by AppName dynamicly.\n\nTo ensure system lightweight and reduce learning costs, it did not use Zookeeper as register center, Use DB as register center to do task registration.\n\n### 5.8 task execute result\nSince v1.6.2, the task execute result is recognized through ReturnT of IJobHandler, it executes success when return value meets the condition \"ReturnT.code == ReturnT.SUCCESS_CODE\" , or it executes fail, and it can callback error message info to schedule center through ReturnT.msg, so it can control task execute results in the task logic.\n\n### 5.9 slice broadcat & dynamic slice   \nWhen “分片广播” is selected as route policy in executor cluster, one task schedule will broadcast all executor node in cluster to trigger task execute in every executor, pass slice parameter at the same time, so we can develop slice task by slice parameters. \n\n\"分片广播\"  break the task by the dimensions of executor, support dynamic extend executor cluster so that it can add slice number dynamically to do business process, In case of large amount of data process can significantly improve task processing capacity and speed.\n\nThe develop process of \"分片广播\" is the same as general task, The difference is that you can get slice parameters，code as shown below（go and see ShardingJobHandler in execuotr example ):\n\n    int shardIndex = XxlJobContext.getXxlJobContext().getShardIndex();\n    int shardTotal = XxlJobContext.getXxlJobContext().getShardTotal();\n    \nThis slice parameter object has two properties:\n\n    index:the current slice number(start with 0)，stands for the number of current executor in the executor cluster.\n    total:total slice number,stands for total slices in the executor cluster.\n\nThis feature applies to scenes as shown below:\n- 1、slice task scene:when 10 executor to handle 10w records,  1w records need to be handled per machine, time-consuming 10 times lower；\n- 2、Broadcast task scene:broadcast all cluster nodes to execute shell script、broadcast all cluster nodes to update cache.\n\n### 5.10 AccessToken\nTo improve system security it is need to check security between schedule center and executor, just allow communication between them when AccessToken of each other matched.\n\nThe AccessToken of scheduler center and executor can be configured by xxl.job.accessToken.\n\nThere are only two settings when communication between scheduler center and executor just:\n\n- one:do not configure AccessToken on both, close security check.\n- two:configure the same AccessToken on both;\n\n### 5.11 Dispatching center API services\nThe scheduling center provides API services for executors and business parties to choose to use, and the currently available API services are available.\n\n    1. Job result callback service;\n    2. Executor registration service;\n    3. Executor registration remove services;\n    4. Triggers a single execution service, and support the task to be triggered according to the business event;\n\nThe scheduling center API service location: com.xxl.job.core.openapi.AdminBiz.java\n\nThe scheduling center API service requests reference code：com.xxl.job.adminbiz.AdminBizTest.java\n\n\n## 6 Version update log\n### 6.1 version V1.1.x，New features [2015-12-05]\n**【since V1.1.x，XXL-JOB was used by company hiring me，alias Ferrari inner company，the latest version is recommended for new project】**\n- 1、simple:support CRUD operation through Web page, simple and one minute to get started;\n- 2、dynamic:support dynamic update task status,pause/recover task and effective in real time;\n- 3、service HA:task info stored in mysql, Job service support cluster to make sure service HA;\n- 4、task HA:when some Job services hangs up, tasks will be assigned to some other alive machines, if all nodes of the cluster hangs up,  it will  compensate for the execution of lost task when restart;\n- 5、one task instance will only be executed on one executor;\n- 6、task is executed serially;\n- 7、support for custom parameters;\n- 8、Support pause task execution remotely .\n\n### 6.2 version V1.2.x，New features [2016-01-17]\n- 1、support task group;\n- 2、suport local task, remote task;\n- 3、support two types underlying communication ,Servlet or JETTY;\n- 4、support task log;\n- 5、support serially execution，parallel execution;\n\t\n\tDescription:system architecture of V1.2 divided by function as shown below:\n\t\n\t\t- schedule module（schedule center）:Responsible for managing schedule information，send schedule request according to the schedule configuration;\n\t\t- execute module（executor）:Responsible for receiving schedule request and execute task logic;\n\t\t- communication module:Responsible for the communication between the schedule module and execute module;\n\tadvantage:\n\t\n\t\t- Decouple:execute module supply task api, schedule module maintains schedule information, The business is independent of each other;\n\t\t- High scalability;\n\t\t- stability;\n\n### 6.3 version V1.3.0，New features [2016-05-19]\n- 1、discard local task module, remote task was recommended, easy to decouple system, the JobHandler of task was called executor.\n- 2、dicard underlying communication type servlet, JETTY was recommended, schedule and callback bidirectional communication, rebuild the communication logic;\n- 3、UI interactive optimization:optimize left menu expansion and menu item selected status , task list opens the table with compression optimization;\n- 4、【important】executor is subdivided into two develop mode:BEAN、GLUE:\n\t\n\tIntroduction to the executor mode:\n\t\t- BEAN mode executor:every executor is a Spring Bean instance，it was recognized and scheduled by XXL-JOB through @JobHandler annotation;\n\t\t -GLUE mode executor:every executor corresponds to a piece of code，edited and maintained online by Web, Dynamic compile and takes effect in real time, executor is responsible for loading GLUE code and executing;\n\n### 6.4 version V1.3.1，New features [2016-05-23]\n- 1、Update project directory structure:\n\t- /xxl-job-admin -------------------- 【schedule center】:Responsible for managing schedule information，send schedule request according to schedule configuration;\n\t- /xxl-job-core -----------------------  Public core dependence\n\t- /xxl-job-executor-example ------ 【executor】:Responsible for receiving scheduling request and execute task logic;\n\t- /db ---------------------------------- create table script\n\t- /doc --------------------------------- user manual\n- 2、Upgrade the user manual under the new directory structure;\n- 3、Optimize some interactions and UI;\n\n### 6.5 version V1.3.2，New features [2016-05-28]\n- 1、Schedule logic for transactional handle;\n- 2、executor asynchronous callback execution log;\n- 3、【important】based on HA support of schedule center，extend executor’s Failover support，Support configure multiple execution addresses;\n\n### 6.6 version V1.4.0 New features [2016-07-24]\n- 1、Task dependency: it is implemented by trigger event, it will automatically trigger a child task schedule after Task execute success and callback, multiple child tasks are separated by commas;\n- 2、executor source code has been reconstructed, optimize underlying db script;\n- 3、optimize task thread group logic of executor, before it is group by executor’s JobHandler so when multiple task reuse Jobhanlder will cause block with each other. Now it is grouped by task of schedule center so tasks are isolated from task execution.\n- 4、optimize communication scheme between executor and schedule center, a simple RPC protocol was implemented through Hex + HC, optimize the maintenance and analysis process of communication parameters.\n- 5、schedule center, create/edit task, page attribute adjustment:\n    - 5.1、the property JobName was removed from task add/edit page and it is changed to automatically generate by system: this field before is used to identify a task in schedule center and did not use in other scenes, so remove it to simplify the task creation;\n    - 5.2、adjust \"GLUE模式\" property in task add/edit page to near JobHandler input box;\n    - 5.3、\"报警阈值\" property was removed from task add/edit page;\n    - 5.4、\"子任务Key\" property was removed from task add/edit page, the key of task can be acquired from task list page, child task will be triggered by child task key when main task execute success.\n- 6、bug fix:\n    - 6.1、optimize jetty executor shutdown,  solve one problem may cause jetty could not shutdown. \n    - 6.2、optimize callback of executor task queue when task execute finish. Solve a problem which may cause task could not callback.\n    - 6.3、Optimize Page List Parameters of Schedule Center, solve one problem which may be caused by post length limit of server.\n    - 6.4、optmize executor Jobhandler annotation, solve a problem that container could not load the JobHandler caused by the transaction proxy.\n    - 6.5、optimize remote schedule, disable retry policy, solve a problem may caused repeat call;\n\nTips: V1.3.x release has been published , enter the maintenance phase, branch  address is [V1.3](https://github.com/xuxueli/xxl-job/tree/v1.3) .New features will be updated continuously in the master branch.\n\n### 6.7 version V1.4.1 New features [2016-09-06]\n- 1、project successfully pushed to maven central warehouse, Central warehouse address and dependency  as shown below:\n    ```\n    <!-- http://repo1.maven.org/maven2/com/xuxueli/xxl-job-core/ -->\n    <dependency>\n        <groupId>com.xuxueli</groupId>\n        <artifactId>xxl-job-core</artifactId>\n        <version>${最新稳定版}</version>\n    </dependency>\n    ```\n- 2、To adapt to the rules of central warehouse, groupId has been changed from com.xxl to com.xuxueli.\n- 3、to resolve the problem that sub-modules can not be compiled separately, system version is not maintained in the project root pom, each sub-module is configured separately for version configuration;\n- 4、optimize data byte length statistics rule of RPC communication it may reduce 50% of data traffic;\n- 5、IJobHandler cancel task return value, before the execution status is judged by the return value, now it instead of task was executed successfully by default only when exception was caught the task execution was judged failed.\n- 6、optimize system public pop-up box as a plugin;\n- 7、optimize table structure and the table name now is upper case;\n- 8、modify ContentType of JSON response from exception handler of schedule center to fix the bug that it is could not recognized by browser.\n\n### 6.8 version V1.4.2 New features [2016-09-29]\n- 1、push V1.4.2 to maven central warehouse, main version V1.4 enter maintenance phase;\n- 2、fix problem task list offset when add task;\n- 3、fix a style disorder problem that caused by bootstrap does not support the modal frame overlap , the problem occurs when the task is edited;\n- 4、optimize schedule status when schedule timeout and Handler could not matched;\n- 5、the task could not stop problem caused by catch exception has given solution;\n\n### 6.9 version V1.5.0 New features [2016-11-13]\n- 1、task register: executor registers the task automatically, schedule center will automatically discover the registered task and trigger execution.\n- 2、add parameter AppName for executor: AppName is the unique identifier of each executor cluster, register periodically and automatically with AppName.\n- 3、add column executor management in schedule center : manage online executors, automatically discover registered executors via the property AppName。Only managed executors are allowed to be used;\n- 4、change Task group attribute to executor : each task needs to be bound to the specified exector, schedule address is obtained by binded executor;\n- 5、discard property task machine: by the way of binding task with executor, automatically discovers registered remote executor address and triggers schedule request.\n- 6、add DBGlueLoader in public dependency, it implement GLUE source code calssloader based on native jdbc, Reduce third party reliance (mybatis,spring-orm etc); simplify and optimize executor configuration (for GLUE task), Reduce the difficulty of getting started;\n- 7、adjust table structure, reconstruct the project;\n- 8、schedule center automatically registered and found, failover: schedule center periodically registered automatically, task callback can recognize all online schedule center addresses, task callback support failover so that it can avoid single point of risk.\n\n### 6.10 version V1.5.1 New features [2016-11-13]\n- 1、Reconstruct the underlying code and optimize logic, clean POM and Clean Code;\n- 2、Servlet/JSP Spec selected 3.0/2.2;\n- 3、Spring updated to 3.2.17.RELEASE version;\n- 4、Jetty updated to version 8.2.0.v20160908;\n- 5、has push V1.5.0 and V1.5.1 to maven central warehouse;\n\n### 6.10 version V1.5.2 New features [2017-02-28]\n- 1、optimize IP tools class which used to gets IP address，IP static cache;\n- 2、both executor and schedule center support customize registered IP address;Solve problem when machine has multiple network card and get the wrong card;\n- 3、solve the problem that it will generate multiple log files when executed across days;\n- 4、the non-sensitive log level is adjusted to debug;\n- 5、Upgrade the database connection pool to c3p0;\n- 6、optimize log4j property of executor，remove invalid attribute;\n- 7、reconstruct underlying code and optimize logic and Clean Code;\n- 8、optimize Dependency Injection Logic of GLUE, support injected as alias;\n\n### 6.11 version V1.6.0 New features [2017-03-13]\n- 1、upgrade communication scheme，the HEX communication model is adjusted to the B-RPC model based on HTTP;\n- 2、executor supports set execution address list manually，provide switch to use automatically registered address or manually set address;\n- 3、executor route rules:第一个、最后一个、轮询、随机、一致性HASH、最不经常使用、最近最久未使用、故障转移;\n- 4、unified thread model and thread destruction scheme (by the way of listener or stop() method，Destroy the thread when container is destroyed;Daemon is sometimes not ideal);\n- 5、unified system configuration data，Unified managed by configuration files;\n- 6、CleanCode，Clean up invalid historical parameters;\n- 7、extend data structure and adjust related table structure;\n- 8、new created task defaults to a non-running state;\n- 9、optimize update logic of GLUE mode task instance , The original update is based on the timeout value and now is updated according to the version number，version number plus one while source changed;\n\n### 6.12 version V1.6.1 New features [2017-03-25]\n- 1、Rolling log;\n- 2、reconstruct WebIDE interactive;\n- 3、enhanced communication check，filter unnormal requests effectively;\n- 4、enhanced permission check，Using dynamic login TOKEN（recommend instead of internal SSO）;\n- 5、optimize database configuration，solve garbled problem;\n\n### 6.13 version V1.6.2 New features [2017-04-25]\n- 1、execution report:support view run time data in real time, such as task number, total schedule number, executor number etc., include schedule report , such as scheduled distribution graph on date, scheduled success distribution graph etc;\n- 2、JobHandler support set return value for tasks, it is easy to control task execute result in task logic;\n- 3、the problem could not view exception info when resource path include space or chinese word casused resource file could not be loaded;\n- 4、optimize route policy:fix problems that Loop and LFU routing policy counters are no limit and first route is focused on the first machine;\n\n### 6.14 version V1.7.0 New features [2017-05-02]\n- 1、script task:support develop and run script task by GLUE, include script type such as Shell、Python and Groovy;\n- 2、add spring-boot type executor example project;\n- 3、upgrade jetty to version 9.2;\n- 4、task execute log remove log4j dependency, instead of self-realization，Thus eliminate the dependency on the log component;\n- 5、executor remove GlueLoader dependency，instead of push mode，thus GLUE source code load no longer rely on JDBC;\n- 6、get the project name when login and redirect, solve 404 problem when it is not deployed by the directory;\n\n### 6.15 version V1.7.1 New features [2017-05-08]\n- 1、unified write and read code of execute log as UTF-8，solve log garbled problem under windows environment;\n- 2、communication timeout period is limited to 10s，To avoid schedule thread is occupied under abnormal situation;\n- 3、adjust executor , server stat, destroy and register logic;\n- 4、optimize Jetty Server shutdown logic, repair port occupation caused by executor could not be closed normally and frequent printe c3p0 log probleam;\n- 5、start child thread in JobHandler，support child thread print execute log and view by Rolling;\n- 6、task log cleanup;\n- 7、pop-up component is replaced by layer;\n- 8、upgrade quartz to version 2.3.0;\n\n### 6.16 version V1.7.2 New features [2017-05-17]\n- 1、block handle policy:the policy when schedule is too frequently and the executor it too late to handle, include multiple strategies:single machine serially execute（default）、discard subsequent schedule、override before schedule;\n- 2、fail handle policy:handle policy when scheduled fail, include :failure alarm（default）、failed to retry;\n- 3、The communication timeout is adjusted to 180s;\n- 4、executor and database are completely decoupled，But the executor needs to configure schedule center cluster address。schedule center provides APIs for executor callbacks and heartbeat registration services，cancel jetty inner schedule center, heartbeat cycle is adjusted to 30s，heartbeat failure is triple heartbeat;\n- 5、fix executor parameters lost bug when edit;\n- 6、add task test Demo to make task logic test easier;\n\n### 6.17 version V1.8.0 New features [2017-07-17]\n- 1、optimize update logic of task Cron，instead of rescheduleJob，at the same time preventing set cron repeatedly;\n- 2、optimize API callback service failed status code，facilitate troubleshooting;\n- 3、XxlJobLogger support multi-parameter;\n- 4、route policy add \"忙碌转移\" mode:Perform idle detection in sequence，The first idle test successfully machine is selected as the target executor and trigger schedule;\n- 5、reconstruct route policy code;\n- 6、fix executor repeat registration problem;\n- 7、Task thread will be destroyed after 30 times idle turn, reduce the inefficient thread consumption of low frequency tasks;\n- 8、Executor task execution result batch callback so that reduce callback frequency to improve actuator performance;\n- 9、cancle XML configuration of springboot executor project，instead of class configuration;\n- 10、supports filter execute log based on running status;\n- 11、optimize scheduling Center Task Registration Detection Logic;\n\n### 6.18 version V1.8.1 New features [2017-07-30]\n- 1、slice broadcast task:When slice broadcast is selected as route policy in executor cluster, one task schedule will broadcast all executor node in cluster to trigger task execute in every executor, pass slice parameter at the same time, so we can develop slice task by slice parameters;\n- 2、dynamic slice: break the task by the dimensions of executor, support dynamic extend executor cluster so that it can add slice number dynamically to do business process, In case of large amount of data process can significantly improve task processing capacity and speed;\n- 3、executor JobHandler disables name conflicts;\n- 4、executor cluster address list for natural sorting;\n- 5、add test cases and optimize DAO layer code for Scheduling center;\n- 6、schedule Center API service change to self-study RPC framework to u nify communication model;\n- 7、add schedule center API service test Demo, convenient in dispatch center API extension and testing;\n- 8、Task list page interaction optimization，The task list is automatically refreshed when the executor group is replaced，create new job defaults to locate current executor position;\n- 9、access Token:To improve system security，it is used for safety check between schedule center and executor, communication allowed just when Both Access Token matched;\n- 10、upgrade springboot version to 1.5.6.RELEASE of executor;\n- 11、unify maven version dependency management;\n\n### 6.19 version V1.8.2 New features[Coding]\n- 1,support configuring the HTTPS for executor callback URL;\n- 2,Standardize project directory for extend multi executors;\n- 3,add JFinal type executor sample project;\n\n### 6.43 version v3.3.2 Release Notes[2026-01-01]\n- 1、【Optimization】Graceful Shutdown: When the scheduling center shuts down, it actively waits for scheduling completion when detecting non-empty time wheels; when the client shuts down, it stops receiving new tasks and actively waits for task execution completion when detecting running tasks;\n- 2、【New Feature】Docker Compose Configuration: Added Docker Compose configuration to support one-click configuration and startup of scheduling center clusters;\n\n<details>\n    <summary>Docker Compose startup steps：</summary>    \n\n    ```\n    // Download XXL-JOB\n    git clone --branch \"$(curl -s https://api.github.com/repos/xuxueli/xxl-job/releases/latest | jq -r .tag_name)\" https://github.com/xuxueli/xxl-job.git\n    // Build XXL-JOB\n    mvn clean package -Dmaven.test.skip=true\n    // Start XXL-JOB\n    MYSQL_PATH={自定义数据库持久化目录} docker compose up -d\n    // Stop XXL-JOB\n    docker compose down\n    ```\n</details>\n\n- 3、【Optimization】 Scheduling Center Operation Experience: Table interaction adjusted to single-row selection mode; disabled pagination cycling; optimized pagination limit text;\n- 4、【Optimization】 Scheduling Thread Transaction Commit Logic: Adjusted to avoid thread abnormal exit under edge conditions, enhancing robustness;\n- 5、【Optimization】 Scheduling Log List Sorting Logic: Optimized for improved readability;\n- 6、【Optimization】 Scheduling Center OpenAPI Communication Token: Adjusted to optional instead of required; merged PR-3892;\n- 7、【Optimization】 Executor Detail Interface Permissions: Adjusted to support regular users viewing registered nodes; merged PR-3882;\n- 8、【Optimization】 Task Parameter LogDateTime Generation Logic: Adjusted to ensure consistency for the same batch of scheduling in sharding broadcast scenarios;\n- 9、【Upgrade】 Maven Dependencies: Upgraded multiple dependencies to newer versions, such as spring, netty, xxl-sso, xxl-tool, etc.;\n- 10、【Optimization】 Unified Project Dependency Management Structure: Unified dependency versions to parent pom for improved maintainability;\n\n\n## 7. Other\n\n### 7.1 Contributing\nContributions are welcome! Open a pull request to fix a bug, or open an [Issue](https://github.com/xuxueli/xxl-job/issues/) to discuss a new feature or change.\n\n### 7.2 used records（record just for spread，Product is open source and free of charge）\nRecord for spread product and product is free and open source. \nWelcome to [check in](https://github.com/xuxueli/xxl-job/issues/1 )on github.\n\n### 7.3 Copyright and License\nThis product is open source and free, and will continue to provide free community technical support. Individual or enterprise users are free to access and use.\n\n- Licensed under the GNU General Public License (GPL) v3.\n- Copyright (c) 2015-present, xuxueli.\n\n---\n### Donate\nNo matter how much the amount is enough to express your thought, thank you very much ：）     [To donate](https://www.xuxueli.com/page/donate.html )\n"
  },
  {
    "path": "doc/XXL-JOB官方文档.md",
    "content": "## 《分布式任务调度平台XXL-JOB》\n\n[![Build Status](https://github.com/xuxueli/xxl-job/workflows/Java%20CI/badge.svg)](https://github.com/xuxueli/xxl-job/actions)\n[![Maven Central](https://img.shields.io/maven-central/v/com.xuxueli/xxl-job-core)](https://central.sonatype.com/artifact/com.xuxueli/xxl-job-core)\n[![GitHub release](https://img.shields.io/github/release/xuxueli/xxl-job.svg)](https://github.com/xuxueli/xxl-job/releases)\n[![GitHub stars](https://img.shields.io/github/stars/xuxueli/xxl-job)](https://github.com/xuxueli/xxl-job/)\n[![Docker pulls](https://img.shields.io/docker/pulls/xuxueli/xxl-job-admin)](https://hub.docker.com/r/xuxueli/xxl-job-admin/)\n[![License](https://img.shields.io/badge/license-GPLv3-blue.svg)](http://www.gnu.org/licenses/gpl-3.0.html)\n[![donate](https://img.shields.io/badge/%24-donate-ff69b4.svg?style=flat)](https://www.xuxueli.com/page/donate.html)\n\n[TOCM]\n\n[TOC]\n\n## 一、简介\n\n### 1.1 概述\nXXL-JOB是一个分布式任务调度平台，其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线，开箱即用。\n\n### 1.2 社区交流\n- [社区交流](https://www.xuxueli.com/page/community.html)\n\n### 1.3 特性\n- 1、简单：支持通过Web页面对任务进行CRUD操作，操作简单，一分钟上手；\n- 2、动态：支持动态修改任务状态、启动/停止任务，以及终止运行中任务，即时生效；\n- 3、调度中心HA（中心式）：调度采用中心式设计，“调度中心”自研调度组件并支持集群部署，可保证调度中心HA；\n- 4、执行器HA（分布式）：任务分布式执行，任务\"执行器\"支持集群部署，可保证任务执行HA；\n- 5、注册中心: 执行器会周期性自动注册任务, 调度中心将会自动发现注册的任务并触发执行。同时，也支持手动录入执行器地址；\n- 6、弹性扩容缩容：一旦有新执行器机器上线或者下线，下次调度时将会重新分配任务；\n- 7、触发策略：提供丰富的任务触发策略，包括：Cron触发、固定间隔触发、固定延时触发、API（事件）触发、人工触发、父子任务触发；\n- 8、调度过期策略：调度中心错过调度时间的补偿处理策略，包括：忽略、立即补偿触发一次等；\n- 9、阻塞处理策略：调度过于密集执行器来不及处理时的处理策略，策略包括：单机串行（默认）、丢弃后续调度、覆盖之前调度；\n- 10、任务超时控制：支持自定义任务超时时间，任务运行超时将会主动中断任务；\n- 11、任务失败重试：支持自定义任务失败重试次数，当任务失败时将会按照预设的失败重试次数主动进行重试；其中分片任务支持分片粒度的失败重试；\n- 12、任务失败告警；默认提供邮件方式失败告警，同时预留扩展接口，可方便的扩展短信、钉钉等告警方式；\n- 13、路由策略：执行器集群部署时提供丰富的路由策略，包括：第一个、最后一个、轮询、随机、一致性HASH、最不经常使用、最近最久未使用、故障转移、忙碌转移等；\n- 14、分片广播任务：执行器集群部署时，任务路由策略选择\"分片广播\"情况下，一次任务调度将会广播触发集群中所有执行器执行一次任务，可根据分片参数开发分片任务；\n- 15、动态分片：分片广播任务以执行器为维度进行分片，支持动态扩容执行器集群从而动态增加分片数量，协同进行业务处理；在进行大数据量业务操作时可显著提升任务处理能力和速度。\n- 16、故障转移：任务路由策略选择\"故障转移\"情况下，如果执行器集群中某一台机器故障，将会自动Failover切换到一台正常的执行器发送调度请求。\n- 17、任务进度监控：支持实时监控任务进度；\n- 18、Rolling实时日志：支持在线查看调度结果，并且支持以Rolling方式实时查看执行器输出的完整的执行日志；\n- 19、GLUE：提供Web IDE，支持在线开发任务逻辑代码，动态发布，实时编译生效，省略部署上线的过程。支持30个版本的历史版本回溯。\n- 20、脚本任务：支持以GLUE模式开发和运行脚本任务，包括Shell、Python、NodeJS、PHP、PowerShell等类型脚本;\n- 21、命令行任务：原生提供通用命令行任务Handler（Bean任务，\"CommandJobHandler\"）；业务方只需要提供命令行即可；\n- 22、任务依赖：支持配置子任务依赖，当父任务执行结束且执行成功后将会主动触发一次子任务的执行, 多个子任务用逗号分隔；\n- 23、一致性：“调度中心”通过DB锁保证集群分布式调度的一致性, 一次任务调度只会触发一次执行；\n- 24、自定义任务参数：支持在线配置调度任务入参，即时生效；\n- 25、调度线程池：调度系统多线程触发调度运行，确保调度精确执行，不被堵塞；\n- 26、数据加密：调度中心和执行器之间的通讯进行数据加密，提升调度信息安全性；\n- 27、邮件报警：任务失败时支持邮件报警，支持配置多邮件地址群发报警邮件；\n- 28、推送maven中央仓库: 将会把最新稳定版推送到maven中央仓库, 方便用户接入和使用;\n- 29、运行报表：支持实时查看运行数据，如任务数量、调度次数、执行器数量等；以及调度报表，如调度日期分布图，调度成功分布图等；\n- 30、全异步：任务调度流程全异步化设计实现，如异步调度、异步运行、异步回调等，有效对密集调度进行流量削峰，理论上支持任意时长任务的运行；\n- 31、跨语言/OpenAPI：调度中心与执行器提供语言无关的 OpenApi（RESTful 格式），第三方任意语言可据此对接调度中心或者实现执行器，实现多语言支持。除此之外，还提供了 “多任务模式”和“httpJobHandler”等其他跨语言方案；\n- 32、国际化：调度中心支持国际化设置，提供中文、英文两种可选语言，默认为中文；\n- 33、容器化：提供官方docker镜像，并实时更新推送dockerhub，进一步实现产品开箱即用；\n- 34、线程池隔离：调度线程池进行隔离拆分，慢任务自动降级进入\"Slow\"线程池，避免耗尽调度线程，提高系统稳定性；\n- 35、用户管理：支持在线管理系统用户，存在管理员、普通用户两种角色；\n- 36、权限控制：执行器维度进行权限控制，管理员拥有全量权限，普通用户需要分配执行器权限后才允许相关操作；\n- 37、AI任务：原生提供AI执行器，并内置多个AI任务Handler，与spring-ai、ollama、dify等集成打通，支持快速开发AI类任务。\n- 38、审计日志：记录任务操作敏感信息，用于系统监控、审计和安全分析，可快速追溯异常行为以及定位排查问题。\n- 39、优雅停机：调度中心停机，检测时间轮非空时主动等待调度完成；客户端停机，检测存在运行中任务时，停止接收新任务并主动等待任务执行完成；\n\n\n### 1.4 发展\n于2015年中，我在github上创建XXL-JOB项目仓库并提交第一个commit，随之进行系统结构设计，UI选型，交互设计……\n\n于2015-11月，XXL-JOB终于RELEASE了第一个大版本V1.0， 随后我将之发布到OSCHINA，XXL-JOB在OSCHINA上获得了@红薯的热门推荐，同期分别达到了OSCHINA的“热门动弹”排行第一和git.oschina的开源软件月热度排行第一，在此特别感谢红薯，感谢大家的关注和支持。\n\n于2015-12月，我将XXL-JOB发表到我司内部知识库，并且得到内部同事认可。\n\n于2016-01月，我司展开XXL-JOB的内部接入和定制工作，在此感谢袁某和尹某两位同事的贡献，同时也感谢内部其他给与关注与支持的同事。\n\n于2017-05-13，在上海举办的 \"[第62期开源中国源创会](https://www.oschina.net/event/2236961)\" 的 \"放码过来\" 环节，我登台对XXL-JOB做了演讲，台下五百位在场观众反响热烈（[图文回顾](https://www.oschina.net/question/2686220_2242120) ）。\n\n于2017-10-22，又拍云 Open Talk 联合 Spring Cloud 中国社区举办的 \"[进击的微服务实战派上海站](https://opentalk.upyun.com/303.html)\"，我登台对XXL-JOB做了演讲，现场观众反响热烈并在会后与XXL-JOB用户热烈讨论交流。\n\n于2017-12-11，XXL-JOB有幸参会《[InfoQ ArchSummit全球架构师峰会](http://bj2017.archsummit.com/)》，并被拍拍贷架构总监\"杨波老师\"在专题 \"[微服务原理、基础架构和开源实践](http://bj2017.archsummit.com/training/2)\" 中现场介绍。\n\n于2017-12-18，XXL-JOB参与\"[2017年度最受欢迎中国开源软件](http://www.oschina.net/project/top_cn_2017?sort=1)\"评比，在当时已录入的约九千个国产开源项目中角逐，最终进入了前30强。\n\n于2018-01-15，XXL-JOB参与\"[2017码云最火开源项目](https://www.oschina.net/news/92438/2017-mayun-top-50)\"评比，在当时已录入的约六千五百个码云项目中角逐，最终进去了前20强。\n\n于2018-04-14，iTechPlus在上海举办的 \"[2018互联网开发者大会](http://www.itdks.com/eventlist/detail/2065)\"，我登台对XXL-JOB做了演讲，现场观众反响热烈并在会后与XXL-JOB用户热烈讨论交流。\n\n于2018-05-27，在上海举办的 \"[第75期开源中国源创会](https://www.oschina.net/event/2278742)\" 的 \"架构\" 主题专场，我登台进行“基础架构与中间件图谱”主题演讲，台下上千位在场观众反响热烈（[图文回顾](https://www.oschina.net/question/3802184_2280606) ）。\n\n于2018-12-05，XXL-JOB参与\"[2018年度最受欢迎中国开源软件](https://www.oschina.net/project/top_cn_2018?sort=1)\"评比，在当时已录入的一万多个开源项目中角逐，最终排名第19名。\n\n于2019-12-10，XXL-JOB参与\"[2019年度最受欢迎中国开源软件](https://www.oschina.net/project/top_cn_2019)\"评比，在当时已录入的一万多个开源项目中角逐，最终排名\"开发框架和基础组件类\"第9名。\n\n于2020-11-16，XXL-JOB参与\"[2020年度最受欢迎中国开源软件](https://www.oschina.net/project/top_cn_2020)\"评比，在当时已录入的一万多个开源项目中角逐，最终排名\"开发框架和基础组件类\"第8名。\n\n于2021-12-06，XXL-JOB参与\"[2021年度OSC中国开源项目评选](https://www.oschina.net/project/top_cn_2021) \"评比，在当时已录入的一万多个开源项目中角逐，最终当选\"最受欢迎项目\"。\n\n> 我司大众点评目前已接入XXL-JOB，内部别名《Ferrari》（Ferrari基于XXL-JOB的V1.1版本定制而成，新接入应用推荐升级最新版本）。\n> 据最新统计, 自2016-01-21接入至2017-12-01期间，该系统已调度约100万次，表现优异。新接入应用推荐使用最新版本，因为经过数十个版本的更新，系统的任务模型、UI交互模型以及底层调度通讯模型都有了较大的优化和提升，核心功能更加稳定高效。\n\n至今，XXL-JOB已接入多家公司的线上产品线，接入场景如电商业务，O2O业务和大数据作业等，截止最新统计时间为止，XXL-JOB已接入的公司包括不限于：\n\n\t- 1、大众点评【美团点评】\n\t- 2、山东学而网络科技有限公司；\n\t- 3、安徽慧通互联科技有限公司；\n\t- 4、人人聚财金服；\n\t- 5、上海棠棣信息科技股份有限公司\n\t- 6、运满满【运满满】\n\t- 7、米其林 (中国区)【米其林】\n\t- 8、妈妈联盟\n\t- 9、九樱天下（北京）信息技术有限公司\n\t- 10、万普拉斯科技有限公司【一加手机】\n\t- 11、上海亿保健康管理有限公司\n\t- 12、海尔馨厨【海尔】\n\t- 13、河南大红包电子商务有限公司\n\t- 14、成都顺点科技有限公司\n\t- 15、深圳市怡亚通\n\t- 16、深圳麦亚信科技股份有限公司\n\t- 17、上海博莹科技信息技术有限公司\n\t- 18、中国平安科技有限公司【中国平安】\n\t- 19、杭州知时信息科技有限公司\n\t- 20、博莹科技（上海）有限公司\n\t- 21、成都依能股份有限责任公司\n\t- 22、湖南高阳通联信息技术有限公司\n\t- 23、深圳市邦德文化发展有限公司\n\t- 24、福建阿思可网络教育有限公司\n\t- 25、优信二手车【优信】\n\t- 26、上海悠游堂投资发展股份有限公司【悠游堂】\n\t- 27、北京粉笔蓝天科技有限公司\n\t- 28、中秀科技(无锡)有限公司\n\t- 29、武汉空心科技有限公司\n\t- 30、北京蚂蚁风暴科技有限公司\n\t- 31、四川互宜达科技有限公司\n\t- 32、钱包行云（北京）科技有限公司\n\t- 33、重庆欣才集团\n    - 34、咪咕互动娱乐有限公司【中国移动】\n    - 35、北京诺亦腾科技有限公司\n    - 36、增长引擎(北京)信息技术有限公司\n    - 37、北京英贝思科技有限公司\n    - 38、刚泰集团\n    - 39、深圳泰久信息系统股份有限公司\n    - 40、随行付支付有限公司\n    - 41、广州瀚农网络科技有限公司\n    - 42、享点科技有限公司\n    - 43、杭州比智科技有限公司\n    - 44、圳临界线网络科技有限公司\n    - 45、广州知识圈网络科技有限公司\n    - 46、国誉商业上海有限公司\n    - 47、海尔消费金融有限公司，嗨付、够花【海尔】\n    - 48、广州巴图鲁信息科技有限公司\n    - 49、深圳市鹏海运电子数据交换有限公司\n    - 50、深圳市亚飞电子商务有限公司\n    - 51、上海趣医网络有限公司\n    - 52、聚金资本\n    - 53、北京父母邦网络科技有限公司\n    - 54、中山元赫软件科技有限公司\n    - 55、中商惠民(北京)电子商务有限公司\n    - 56、凯京集团\n    - 57、华夏票联（北京）科技有限公司\n    - 58、拍拍贷【拍拍贷】\n    - 59、北京尚德机构在线教育有限公司\n    - 60、任子行股份有限公司\n    - 61、北京时态电子商务有限公司\n    - 62、深圳卷皮网络科技有限公司\n    - 63、北京安博通科技股份有限公司\n    - 64、未来无线网\n    - 65、厦门瓷禧网络有限公司\n    - 66、北京递蓝科软件股份有限公司\n    - 67、郑州创海软件科技公司\n    - 68、北京国槐信息科技有限公司\n    - 69、浪潮软件集团\n    - 70、多立恒(北京)信息技术有限公司\n    - 71、广州极迅客信息科技有限公司\n    - 72、赫基（中国）集团股份有限公司\n    - 73、海投汇\n    - 74、上海润益创业孵化器管理股份有限公司\n    - 75、汉纳森（厦门）数据股份有限公司\n    - 76、安信信托\n    - 77、岚儒财富\n    - 78、捷道软件\n    - 79、湖北享七网络科技有限公司\n    - 80、湖南创发科技责任有限公司\n    - 81、深圳小安时代互联网金融服务有限公司\n    - 82、湖北享七网络科技有限公司\n    - 83、钱包行云(北京)科技有限公司\n    - 84、360金融【360】\n    - 85、易企秀\n    - 86、摩贝（上海）生物科技有限公司\n    - 87、广东芯智慧科技有限公司\n    - 88、联想集团【联想】\n    - 89、怪兽充电\n    - 90、行圆汽车\n    - 91、深圳店店通科技邮箱公司\n    - 92、京东【京东】\n    - 93、米庄理财\n    - 94、咖啡易融\n    - 95、梧桐诚选\n    - 96、恒大地产【恒大】\n    - 97、昆明龙慧\n    - 98、上海涩瑶软件\n    - 99、易信【网易】\n    - 100、铜板街\n    - 101、杭州云若网络科技有限公司\n    - 102、特百惠（中国）有限公司\n    - 103、常山众卡运力供应链管理有限公司\n    - 104、深圳立创电子商务有限公司\n    - 105、杭州智诺科技股份有限公司\n    - 106、北京云漾信息科技有限公司\n    - 107、深圳市多银科技有限公司\n    - 108、亲宝宝\n    - 109、上海博卡软件科技有限公司\n    - 110、智慧树在线教育平台\n    - 111、米族金融\n    - 112、北京辰森世纪\n    - 113、云南滇医通\n    - 114、广州市分领网络科技有限责任公司\n    - 115、浙江微能科技有限公司\n    - 116、上海馨飞电子商务有限公司\n    - 117、上海宝尊电子商务有限公司\n    - 118、直客通科技技术有限公司\n    - 119、科度科技有限公司\n    - 120、上海数慧系统技术有限公司\n    - 121、我的医药网\n    - 122、多粉平台\n    - 123、铁甲二手机\n    - 124、上海海新得数据技术有限公司\n    - 125、深圳市珍爱网信息技术有限公司【珍爱网】\n    - 126、小蜜蜂\n    - 127、吉荣数科技\n    - 128、上海恺域信息科技有限公司\n    - 129、广州荔支网络有限公司【荔枝FM】\n    - 130、杭州闪宝科技有限公司\n    - 131、北京互联新网科技发展有限公司\n    - 132、誉道科技\n    - 133、山西兆盛房地产开发有限公司\n    - 134、北京蓝睿通达科技有限公司\n    - 135、月亮小屋（中国）有限公司【蓝月亮】\n    - 136、青岛国瑞信息技术有限公司\n    - 137、博雅云计算（北京）有限公司\n    - 138、华泰证券香港子公司\n    - 139、杭州东方通信软件技术有限公司\n    - 140、武汉博晟安全技术股份有限公司\n    - 141、深圳市六度人和科技有限公司\n    - 142、杭州趣维科技有限公司（小影）\n    - 143、宁波单车侠之家科技有限公司【单车侠】\n    - 144、丁丁云康信息科技（北京）有限公司\n    - 145、云钱袋\n    - 146、南京中兴力维\n    - 147、上海矽昌通信技术有限公司\n    - 148、深圳萨科科技\n    - 149、中通服创立科技有限责任公司\n    - 150、深圳市对庄科技有限公司\n    - 151、上证所信息网络有限公司\n    - 152、杭州火烧云科技有限公司【婚礼纪】\n    - 153、天津青芒果科技有限公司【芒果头条】\n    - 154、长飞光纤光缆股份有限公司\n    - 155、世纪凯歌（北京）医疗科技有限公司\n    - 156、浙江霖梓控股有限公司\n    - 157、江西腾飞网络技术有限公司\n    - 158、安迅物流有限公司\n    - 159、肉联网\n    - 160、北京北广梯影广告传媒有限公司\n    - 161、上海数慧系统技术有限公司\n    - 162、大志天成\n    - 163、上海云鹊医\n    - 164、上海云鹊医\n    - 165、墨迹天气【墨迹天气】\n    - 166、上海逸橙信息科技有限公司\n    - 167、沅朋物联\n    - 168、杭州恒生云融网络科技有限公司\n    - 169、绿米联创\n    - 170、重庆易宠科技有限公司\n    - 171、安徽引航科技有限公司（乐职网）\n    - 172、上海数联医信企业发展有限公司\n    - 173、良彬建材\n    - 174、杭州求是同创网络科技有限公司\n    - 175、荷马国际\n    - 176、点雇网\n    - 177、深圳市华星光电技术有限公司\n    - 178、厦门神州鹰软件科技有限公司\n    - 179、深圳市招商信诺人寿保险有限公司\n    - 180、上海好屋网信息技术有限公司\n    - 181、海信集团【海信】\n    - 182、信凌可信息科技（上海）有限公司\n    - 183、长春天成科技发展有限公司\n    - 184、用友金融信息技术股份有限公司【用友】\n    - 185、北京咖啡易融有限公司\n    - 186、国投瑞银基金管理有限公司\n    - 187、晋松(上海)网络信息技术有限公司\n    - 188、深圳市随手科技有限公司【随手记】\n    - 189、深圳水务科技有限公司\n    - 190、易企秀【易企秀】\n    - 191、北京磁云科技\n    - 192、南京蜂泰互联网科技有限公司\n    - 193、章鱼直播\n    - 194、奖多多科技\n    - 195、天津市神州商龙科技股份有限公司\n    - 196、岩心科技\n    - 197、车码科技（北京）有限公司\n    - 198、贵阳市投资控股集团\n    - 199、康旗股份\n    - 200、龙腾出行\n    - 201、杭州华量软件\n    - 202、合肥顶岭医疗科技有限公司\n    - 203、重庆表达式科技有限公司\n    - 204、上海米道信息科技有限公司\n    - 205、北京益友会科技有限公司\n    - 206、北京融贯电子商务有限公司\n    - 207、中国外汇交易中心\n    - 208、中国外运股份有限公司\n    - 209、中国上海晓圈教育科技有限公司\n    - 210、普联软件股份有限公司\n    - 211、北京科蓝软件股份有限公司\n    - 212、江苏斯诺物联科技有限公司\n    - 213、北京搜狐-狐友【搜狐】\n    - 214、新大陆网商金融\n    - 215、山东神码中税信息科技有限公司\n    - 216、河南汇顺网络科技有限公司\n    - 217、北京华夏思源科技发展有限公司\n    - 218、上海东普信息科技有限公司\n    - 219、上海鸣勃网络科技有限公司\n    - 220、广东学苑教育发展有限公司\n    - 221、深圳强时科技有限公司\n    - 222、上海云砺信息科技有限公司\n    - 223、重庆愉客行网络有限公司\n    - 224、数云\n    - 225、国家电网运检部\n    - 226、杭州找趣\n    - 227、浩鲸云计算科技股份有限公司\n    - 228、科大讯飞【科大讯飞】\n    - 229、杭州行装网络科技有限公司\n    - 230、即有分期金融\n    - 231、深圳法司德信息科技有限公司\n    - 232、上海博复信息科技有限公司\n    - 233、杭州云嘉云计算有限公司\n    - 234、有家民宿(有家美宿)\n    - 235、北京赢销通软件技术有限公司\n    - 236、浙江聚有财金融服务外包有限公司\n    - 237、易族智汇(北京)科技有限公司\n    - 238、合肥顶岭医疗科技开发有限公司\n    - 239、车船宝(深圳)旭珩科技有限公司)\n    - 240、广州富力地产有限公司\n    - 241、氢课（上海）教育科技有限公司\n    - 242、武汉氪细胞网络技术有限公司\n    - 243、杭州有云科技有限公司\n    - 244、上海仙豆智能机器人有限公司\n    - 245、拉卡拉支付股份有限公司【拉卡拉】\n    - 246、虎彩印艺股份有限公司\n    - 247、北京数微科技有限公司\n    - 248、广东智瑞科技有限公司\n    - 249、找钢网\n    - 250、九机网\n    - 251、杭州跑跑网络科技有限公司\n    - 252、深圳未来云集\n    - 253、杭州每日给力科技有限公司\n    - 254、上海齐犇信息科技有限公司\n    - 255、滴滴出行【滴滴】\n    - 256、合肥云诊信息科技有限公司\n    - 257、云知声智能科技股份有限公司\n    - 258、南京坦道科技有限公司\n    - 259、爱乐优（二手平台）\n    - 260、猫眼电影（私有化部署）【猫眼电影】\n    - 261、美团大象（私有化部署）【美团大象】\n    - 262、作业帮教育科技（北京）有限公司【作业帮】\n    - 263、北京小年糕互联网技术有限公司\n    - 264、山东矩阵软件工程股份有限公司\n    - 265、陕西国驿软件科技有限公司\n    - 266、君开信息科技\n    - 267、村鸟网络科技有限责任公司\n    - 268、云南国际信托有限公司\n    - 269、金智教育\n    - 270、珠海市筑巢科技有限公司\n    - 271、上海百胜软件股份有限公司\n    - 272、深圳市科盾科技有限公司\n    - 273、哈啰出行【哈啰】\n    - 274、途虎养车【途虎】\n    - 275、卡思优派人力资源集团\n    - 276、南京观为智慧软件科技有限公司\n    - 277、杭州城市大脑科技有限公司\n    - 278、猿辅导【猿辅导】\n    - 279、洛阳健创网络科技有限公司\n    - 280、魔力耳朵\n    - 281、亿阳信通\n    - 282、上海招鲤科技有限公司\n    - 283、四川商旅无忧科技服务有限公司\n    - 284、UU跑腿\n    - 285、北京老虎证券【老虎证券】\n    - 286、悠活省吧（北京）网络科技有限公司\n    - 287、F5未来商店\n    - 288、深圳环阳通信息技术有限公司\n    - 289、遠傳電信\n    - 290、作业帮（北京）教育科技有限公司【作业帮】\n    - 291、成都科鸿智信科技有限公司\n    - 292、北京木屋时代科技有限公司\n    - 293、大学通（哈尔滨）科技有限责任公司\n    - 294、浙江华坤道威数据科技有限公司\n    - 295、吉祥航空【吉祥航空】\n    - 296、南京圆周网络科技有限公司\n    - 297、广州市洋葱omall电子商务\n    - 298、天津联物科技有限公司\n    - 299、跑哪儿科技（北京）有限公司\n    - 300、深圳市美西西餐饮有限公司(喜茶)\n    - 301、平安不动产有限公司【平安】\n    - 302、江苏中海昇物联科技有限公司\n    - 303、湖南牙医帮科技有限公司\n    - 304、重庆民航凯亚信息技术有限公司（易通航）\n    - 305、递易（上海）智能科技有限公司\n    - 306、亚朵\n    - 307、浙江新课堂教育股份有限公司\n    - 308、北京蜂创科技有限公司\n    - 309、德一智慧城市信息系统有限公司\n    - 310、北京翼点科技有限公司\n    - 311、湖南智数新维度信息科技有限公司\n    - 312、北京玖扬博文文化发展有限公司\n    - 313、上海宇珩信息科技有限公司\n    - 314、全景智联（武汉）科技有限公司\n    - 315、天津易客满国际物流有限公司\n    - 316、南京爱福路汽车科技有限公司\n    - 317、我房旅居集团\n    - 318、湛江亲邻科技有限公司\n    - 319、深圳市姜科网络有限公司\n    - 320、青岛日日顺物流有限公司\n    - 321、南京太川信息技术有限公司\n    - 322、美图之家科技优先公司【美图】\n    - 323、南京太川信息技术有限公司\n    - 324、众薪科技（北京）有限公司\n    - 325、武汉安安物联科技有限公司\n    - 326、北京智客朗道网络科技有限公司\n    - 327、深圳市超级猩猩健身管理管理有限公司\n    - 328、重庆达志科技有限公司\n    - 329、上海享评信息科技有限公司\n    - 330、薪得付信息科技\n    - 331、跟谁学\n    - 332、中道（苏州）旅游网络科技有限公司\n    - 333、广州小卫科技有限公司\n    - 334、上海非码网络科技有限公司\n    - 335、途家网网络技术（北京）有限公司【途家】\n    - 336、广州辉凡信息科技有限公司\n    - 337、天维尔信息科技股份有限公司\n    - 338、上海极豆科技有限公司\n    - 339、苏州触达信息技术有限公司\n    - 340、北京热云科技有限公司\n    - 341、中智企服（北京）科技有限公司\n    - 342、易联云计算（杭州）有限责任公司\n    - 343、青岛航空股份有限公司【青岛航空】\n    - 344、山西博睿通科技有限公司\n    - 345、网易杭州网络有限公司【网易】\n    - 346、北京果果乐学科技有限公司\n    - 347、百望股份有限公司\n    - 348、中保金服（深圳）科技有限公司\n    - 349、天津运友物流科技股份有限公司\n    - 350、广东创能科技股份有限公司\n    - 351、上海倚博信息科技有限公司\n    - 352、深圳百果园实业（集团）股份有限公司\n    - 353、广州细刻网络科技有限公司\n    - 354、武汉鸿业众创科技有限公司\n    - 355、金锡科技（广州）有限公司\n    - 356、易瑞国际电子商务有限公司\n    - 357、奇点云\n    - 358、中视信息科技有限公司\n    - 359、开源项目:datax-web\n    - 360、云知声智能科技股份有限公司\n    - 361、开源项目:bboss\n    - 362、成都深驾科技有限公司\n    - 363、FunPlus【趣加】\n    - 364、杭州创匠信科技有限公司\n    - 365、龙匠（北京）科技发展有限公司\n    - 366、广州一链通互联网科技有限公司\n    - 367、上海星艾网络科技有限公司\n    - 368、虎博网络技术(上海)有限公司\n    - 369、青岛优米信息技术有限公司\n    - 370、八维通科技有限公司\n    - 371、烟台合享智星数据科技有限公司\n    - 372、东吴证券股份有限公司\n    - 373、中通云仓股份有限公司【中通】\n    - 374、北京加菲猫科技有限公司\n    - 375、北京匠心演绎科技有限公司\n    - 376、宝贝走天下\n    - 377、厦门众库科技有限公司\n    - 378、海通证券数据中心\n    - 389、湖南快乐通宝小额贷款有限公司\n    - 380、浙江大华技术股份有限公司\n    - 381、杭州魔筷科技有限公司\n    - 382、青岛掌讯通区块链科技有限公司\n    - 383、新大陆金融科技\n    - 384、常州玺拓软件科技有限公司\n    - 385、北京正保网格教育科技有限公司\n    - 386、统一企业（中国）投资有限公司【统一】\n    - 387、微革网络科技有限公司\n    - 388、杭州融易算科技有限公司\n    - 399、青岛上啥班网络科技有限公司\n    - 390、京东酒世界\n    - 391、杭州爱博仕科技有限公司\n    - 392、五星金服控股有限公司\n    - 393、福建乐摩物联科技有限公司\n    - 394、百炼智能科技有限公司\n    - 395、山东能源数智云科技有限公司\n    - 396、招商局能源运输股份有限公司\n    - 397、三一集团【三一】\n    - 398、东巴文（深圳）健康管理有限公司\n    - 399、索易软件\n    - 400、深圳市宁远科技有限公司\n    - 401、熙牛医疗\n    - 402、南京智鹤电子科技有限公司\n    - 403、嘀嗒出行【嘀嗒出行】\n    - 404、广州虎牙信息科技有限公司【虎牙】\n    - 405、广州欧莱雅百库网络科技有限公司【欧莱雅】\n    - 406、微微科技有限公司\n    - 407、我爱我家房地产经纪有限公司【我爱我家】\n    - 408、九号发现\n    - 409、薪人薪事\n    - 410、武汉氪细胞网络技术有限公司\n    - 411、广州市斯凯奇商业有限公司\n    - 412、微淼商学院\n    - 413、杭州车盛科技有限公司\n    - 414、深兰科技（上海）有限公司\n    - 415、安徽中科美络信息技术有限公司\n    - 416、比亚迪汽车工业有限公司【比亚迪】\n    - 417、湖南小桔信息技术有限公司\n    - 418、安徽科大国创软件科技有限公司\n    - 419、克而瑞\n    - 420、陕西云基华海信息技术有限公司\n    - 421、安徽深宁科技有限公司\n    - 422、广东康爱多数字健康有限公司\n    - 423、嘉里电子商务\n    - 424、上海时代光华教育发展有限公司\n    - 425、CityDo\n    - 426、上海禹知信息科技有限公司\n    - 427、广东智瑞科技有限公司\n    - 428、西安爱铭网络科技有限公司\n    - 429、心医国际数字医疗系统(大连)有限公司\n    - 430、乐其电商\n    - 431、锐达科技\n    - 432、天津长城滨银汽车金融有限公司\n    - 433、代码网\n    - 434、东莞市东城乔伦软件开发工作室\n    - 435、浙江百应科技有限公司\n    - 436、上海力爱帝信息技术有限公司(Red E)\n    - 437、云徙科技有限公司\n    - 438、北京康智乐思网络科技有限公司【大姨吗APP】\n    - 439、安徽开元瞬视科技有限公司\n    - 440、立方\n    - 441、厦门纵行科技\n    - 442、乐山-菲尼克斯半导体有限公司\n    - 443、武汉光谷联合集团有限公司\n    - 444、上海金仕达软件科技有限公司\n    - 445、深圳易世通达科技有限公司\n    - 446、爱动超越人工智能科技（北京）有限责任公司\n    - 447、迪普信（北京）科技有限公司\n    - 448、掌站科技（北京）有限公司\n    - 449、深圳市华云中盛股份有限公司\n    - 450、上海原圈科技有限公司\n    - 451、广州赞赏信息科技有限公司\n    - 452、Amber Group\n    - 453、德威国际货运代理（上海）公司\n    - 454、浙江杰夫兄弟智慧科技有限公司\n    - 455、信也科技\n    - 456、开思时代科技（深圳）有限公司\n    - 457、大连槐德科技有限公司\n    - 458、同程生活\n    - 459、松果出行\n    - 460、企鹅杏仁集团\n    - 461、宁波科云信息科技有限公司\n    - 462、上海格蓝威驰信息科技有限公司\n    - 463、杭州趣淘鲸科技有限公司\n    - 464、湖州市数字惠民科技有限公司\n    - 465、乐普（北京）医疗器械股份有限公司\n    - 466、广州市晴川高新技术开发有限公司\n    - 467、山西缇客科技有限公司\n    - 468、徐州卡西穆电子商务有限公司\n    - 469、格创东智科技有限公司\n    - 470、世纪龙信息网络有限责任公司\n    - 471、邦道科技有限公司\n    - 472、河南中盟新云科技股份有限公司\n    - 473、横琴人寿保险有限公司\n    - 474、上海海隆华钟信息技术有限公司\n    - 475、上海久湛\n    - 476、上海仙豆智能机器人有限公司\n    - 477、广州汇尚网络科技有限公司\n    - 478、深圳市阿卡索资讯股份有限公司\n    - 479、青岛佳家康健康管理有限责任公司\n    - 480、蓝城兄弟\n    - 481、成都天府通金融服务股份有限公司\n    - 482、深圳云镖网络科技有限公司\n    - 483、上海影创科技\n    - 484、成都艾拉物联\n    - 485、北京客邻尚品网络技术有限公司\n    - 486、IT实战联盟\n    - 487、杭州尤拉夫科技有限公司\n    - 488、中大检测(湖南)股份有限公司\n    - 489、江苏电老虎工业互联网股份有限公司\n    - 490、上海助通信息科技有限公司\n    - 491、北京符节科技有限公司\n    - 492、杭州英祐科技有限公司\n    - 493、江苏电老虎工业互联网股份有限公司\n    - 494、深圳市点猫科技有限公司\n    - 495、杭州天音\n    - 496、深圳市二十一科技互联网有限公司\n    - 497、海南海口翎度科技\n    - 498、北京小趣智品科技有限公司\n    - 499、广州石竹计算机软件有限公司\n    - 500、深圳市惟客数据科技有限公司\n    - 501、中国医疗器械有限公司\n    - 502、上海云谦科技有限公司\n    - 503、上海磐农信息科技有限公司\n    - 504、广州领航食品有限公司\n    - 505、青岛掌讯通区块链科技有限公司\n    - 506、北京新网数码信息技术有限公司\n    - 507、超体信息科技(深圳)有限公司\n    - 508、长沙店帮手信息科技有限公司\n    - 509、上海助弓装饰工程有限公司\n    - 510、杭州寻联网络科技有限公司\n    - 511、成都大淘客科技有限公司\n    - 512、松果出行\n    - 513、深圳市唤梦科技有限公司\n    - 514、上汽集团商用车技术中心\n    - 515、北京中航讯科技股份有限公司\n    - 516、北龙中网(北京)科技有限责任公司\n    - 517、前海超级前台(深圳)信息技术有限公司\n    - 518、上海中商网络股份有限公司\n    - 519、上海助通信息科技有限公司\n    - 520、宁波聚臻智能科技有限公司\n    - 521、上海零动数码科技股份有限公司\n    - 522、浙江学海教育科技有限公司\n    - 523、聚学云(山东)信息技术有限公司\n    - 524、多氟多新材料股份有限公司\n    - 525、智慧眼科技股份有限公司\n    - 526、广东智通人才连锁股份有限公司\n    - 527、世纪开元智印互联科技集团股份有限公司\n    - 528、北京理想汽车【理想汽车】\n    - 529、巽逸科技(重庆)有限公司\n    - 530、义乌购电子商务有限公司\n    - 531、深圳市珂莱蒂尔服饰有限公司\n    - 532、江西国泰利民信息科技有限公司\n    - 533、广西广电大数据科技有限公司\n    - 534、杭州艾麦科技有限公司\n    - 535、广州小滴科技有限公司\n    - 536、佳缘科技股份有限公司\n    - 537、上海深擎信息科技有限公司\n    - 538、武商网\n    - 539、福建民本信息科技有限公司\n    - 540、杭州惠合信息科技有限公司\n    - 541、厦门爱立得科技有限公司\n    - 542、成都拟合未来科技有限公司\n    - 543、宁波聚臻智能科技有限公司\n    - 544、广东百慧科技有限公司\n    - 545、笨马网络\n    - 546、深圳市信安数字科技有限公司\n    - 547、深圳市思乐数据技术有限公司\n    - 548、四川绿源集科技有限公司\n    - 549、湖南云医链生物科技有限公司\n    - 550、杭州源诚科技有限公司\n    - 551、北京开课吧科技有限公司\n    - 552、北京多来点信息技术有限公司\n    - 553、JEECG BOOT低代码开发平台\n    - 554、苏州同元软控信息技术有限公司\n    - 555、江苏大泰信息技术有限公司\n    - 556、北京大禹汇智\n    - 557、北京盛哲科技有限公司\n    - 558、广州钛动科技有限公司\n    - 559、北京大禹汇智科技有限公司\n    - 560、湖南鼎翰文化股份有限公司\n    - 561、苏州安软信息科技有限公司\n    - 562、芒果tv\n    - 563、上海艺赛旗软件股份有限公司\n    - 564、中盈优创资讯科技有限公司\n    - 565、乐乎公寓\n    - 566、启明信息\n    - 567、苏州安软\n    - 568、南京富金的软件科技有限公司\n    - 569、深圳市新科聚合网络技术有限公司\n    - 570、你好现在(北京)科技股份有限公司\n    - 571、360考试宝典\n    - 572、北京一零科技有限公司\n    - 573、厦门星纵信息\n    - 574、Dalligent Solusi Indonesia\n    - 575、深圳华普物联科技有限公司\n    - 576、深圳行健自动化股份有限公司\n    - 577、深圳市富融信息科技服务有限公司\n    - 578、蓝鸟云\n    - 579、上海澎博财经资讯有限公司\n    - 580、北京小鸦科技有限公司\n    - 581、杭州盈泉云科技有限公司\n    - 582、惟客数据\n    - 583、GOSO香蜜闺秀\n    - 584、普乐师（上海）数字科技有限公司\n    - 585、西安市雁塔区咖北堂网络科技部\n    - 586、宁波聚臻智能科技有限公司\n    - 587、普乐师数字科技有限公司\n    - 588、江苏蟹联网科技有限公司\n    - 589、杭州未智科技有限公司\n    - 590、安吉智行物流有限公司\n    - 591、华生大家居集团有限公司\n    - 592、美心食品（广州）有限公司\n    - 593、货拉拉【货拉拉APP】\n    - 594、杭州思韬瑞科技有限公司\n    - 595、杭州玖融科技有限公司\n    - 596、北京优海网络科技有限公司\n    - 597、浙江大维高新技术股份有限公司\n    - 598、粤港澳大湾区数字经济研究院\n    - 599、普康（杭州）健康科技有限公司\n    - 600、华西证券股份有限公司【华西证券】\n    - 601、杭州海康机器人股份有限公司【海康】\n    - 602、河南宸邦信息技术有限公司\n    - 603、成都次元节点网络科技有限公司\n    - 604、富士康科技集团【富士康】\n    - 605、青岛东软载波科技股份有限公司\n    - 606、小菊快跑科技有限公司\n    - 607、视源股份\n    - 608、宁波聚臻智能科技有限公司\n    - 609、阔天科技有限公司\n    - 610、网宿科技有限公司\n    - 611、南京梵鼎信息技术有限公司\n    - 612、房天下【房天下】\n    - 613、特瓦特能源科技有限公司\n    - 614、拓迪智能科技有限公司\n    - 615、东软集团【东软】\n    - 616、开普云\n    - 617、领课网络\n    - 618、南京特维软件有限公司\n    - 619、福建易联众保睿通信息科技有限公司\n    - 620、浙江核心同花顺金融科技有限公司【同花顺】\n    - 621、浙江博观瑞思科技有限公司\n    - 622、北京新美互通科技有限公司\n    - 623、北京有生博大软件股份有限公司\n    - 624、时代中国\n    - 625、鱼泡网\n    - 626、一粒方糖（安徽）科技有限公司\n    - 627、北京外研在线数字科技有限公司\n    - 628、德电（中国）通信技术有限公司\n    - 629、杭州寻联网络科技有限公司\n    - 630、橙联（中国）有限公司\n    - 631、北京承启通科技有限公司\n    - 632、银联数据服务有限公司【银联】\n    - 633、上海晶确科技有限公司\n    - 634、亚信科技有限公司\n    - 635、福建新航物联网科技有限公司\n    - 636、上扬软件\n    - 637、深蓝汽车科技有限公司\n    - 638、南昌节点汇智科技有限公司\n    - 639、锐明技术\n    - 640、再造再生健康科技有限公司\n    - 641、华宝证券\n    - 642、卓正医疗\n    - 643、深圳湛信科技\n    - 644、陕西鑫众为软件有限公司\n    - 645、深圳市润农科技有限公司\n    - 646、庚商教育智能科技有限公司\n    - 647、杭州祎声科技\n    - 648、四川久远银海软件股份有限公司\n    - 649、GeeFox极狐低代码\n    - 650、浙江和仁科技股份有限公司\n    - 651、宁波聚臻智能科技有限公司\n    - 652、福建福昕软件开发股份有限公司【福昕】\n    - 653、广州中长康达信息技术有限公司\n    - 654、武汉趣改信息科技有限公司\n    - 655、北京华夏思源科技发展有限公司\n    - 656、宁波关关通科技有限公司\n    - 657、青岛吕氏餐饮有限公司\n    - 658、杭州乐刻网络科技有限公司\n    - 659、上海红瓦信息科技有限公司\n    - 660、陕西旅小宝信息科技有限公司\n    - 661、中科卓恒(大连)科技有限公司\n    - 662、北京华益精点生物技术有限公司\n    - 663、马士基（中国）航运有限公司【马士基】\n    - 664、陕西美咚网络科技有限公司\n    - 665、山东新北洋信息技术股份有限公司 \n    - 666、福建中瑞文化发展集团有限公司\n    - 667、黑龙江省建工集团有限责任公司【黑龙江省建工】\n    - 668、志信能达安全科技(广州)有限公司\n    - 669、重庆开源共创科技有限公司\n    - 670、华泰人寿保险股份有限公司【华泰人寿】\n    - 671、成都盘古纵横集团\n    - 672、北京果果乐学科技有限公司\n    - 673、北京凌云空间科技有限公司\n    - 674、临工重机股份有限公司\n    - 675、上海热风时尚管理集团【热风】\n    - 676、HashKey Exchange\n    - 677、傲基（深圳）跨境商务股份有限公司\n    - 678、青岛文达通科技股份有限公司\n    - 679、杭州普罗云科技有限公司\n    - 680、浙江云鹭科技有限公司\n    - 681、中山市芯宏柿网络科技有限公司\n    - 682、深圳市家家顺物联科技\n    - 683、重庆斑西科技有限公司\n    - 684、福建省泰古信息技术有限公司\n    - 685、贵阳永青仪电科技有限公司\n    - 686、广州博依特智能信息科技有限公司\n    - 687、河南宠呦呦信息技术有限公司\n    - 688、陕西星邑空间技术有限公司\n    - 689、广东西欧克实业有限公司\n    - 690、唱吧麦颂KTV\n    - 691、联通云\n    - 692、北京爱话本科技有限公司\n    - 693、北京起创科技有限公司\n    - 694、平安证券【平安证券】\n    - 695、合肥中科类脑智能技术有限公司\n    - 696、南京同仁堂健康产业有限公司【同仁堂】\n    - 697、铜仁市碧江区智惠加油站\n    - 698、惟客数据\n    - 699、凤凰新闻【凤凰新闻】\n    - 700、深圳王力智能\n    - 701、返利网数字科技股份有限公司\n    - 702、上海阜能信息科技有限公司\n    - 703、深圳市极能超电数字科技有限公司\n    - 704、海目星激光科技集团股份有限公司\n    - 705、安克创新科技股份有限公司【安克】\n    - 706、大庆点神科技有限公司\n    - 707、浙江零跑科技股份有限公司【零跑】\n    - 708、成都成电金盘健康数据技术有限公司\n    - 709、成都极米科技股份有限公司【极米】\n    - 710、顺德职业技术大学\n    - 711、中邮证券有限责任公司【中邮证券】\n    - 712、志豪链云科技有限公司\n    - 713、湖南万鲸科技有限公司\n    - 714、广州万表\n    - 715、再惠（上海）网络科技有限公司\n    - 716、上海爱诚裕信息科技有限公司\n    - 717、杭州迈瑞数字科技有限公司\n    - 718、广州串联网络科技有限公司\n    - ……\n\n> 更多接入的公司，欢迎在 [登记地址](https://github.com/xuxueli/xxl-job/issues/1 ) 登记，登记仅仅为了产品推广。\n\n欢迎大家的关注和使用，XXL-JOB也将拥抱变化，持续发展。\n\n\n### 1.5 下载\n\n#### 文档地址\n\n- [中文文档](https://www.xuxueli.com/xxl-job/)\n- [English Documentation](https://www.xuxueli.com/xxl-job/en/)\n\n#### 源码仓库地址\n\n源码仓库地址 | Release Download\n--- | ---\n[https://github.com/xuxueli/xxl-job](https://github.com/xuxueli/xxl-job) | [Download](https://github.com/xuxueli/xxl-job/releases)  \n[http://gitee.com/xuxueli0323/xxl-job](http://gitee.com/xuxueli0323/xxl-job) | [Download](http://gitee.com/xuxueli0323/xxl-job/releases)\n[https://gitcode.com/xuxueli/xxl-job](https://gitcode.com/xuxueli/xxl-job) | [Download](https://gitcode.com/xuxueli/xxl-job/tags)\n\n\n#### 中央仓库地址\n\n```\n<!-- http://repo1.maven.org/maven2/com/xuxueli/xxl-job-core/ -->\n<dependency>\n    <groupId>com.xuxueli</groupId>\n    <artifactId>xxl-job-core</artifactId>\n    <version>${最新稳定版本}</version>\n</dependency>\n```\n\n\n### 1.6 环境\n- Maven：3+\n- Jdk：17+ (说明：版本3.x及以上要求Jdk17+；版本2.x及以下支持Jdk1.8)\n- Mysql：8.0+\n\n\n## 二、快速入门\n\n### 2.1 初始化“调度数据库”\n请下载项目源码并解压，获取 \"调度数据库初始化SQL脚本\" 并执行即可。\n\n\"调度数据库初始化SQL脚本\" 位置为:\n\n    /xxl-job/doc/db/tables_xxl_job.sql\n\n调度中心支持集群部署，集群情况下各节点务必连接同一个mysql实例;\n\n如果mysql做主从,调度中心集群节点务必强制走主库;\n\n### 2.2 编译源码\n解压源码,按照maven格式将源码导入IDE, 使用maven进行编译即可，源码结构如下：\n\n    xxl-job-admin：调度中心\n    xxl-job-core：公共依赖\n    xxl-job-executor-samples：执行器Sample示例（选择合适的版本执行器，可直接使用，也可以参考其并将现有项目改造成执行器）\n        ：xxl-job-executor-sample-springboot：Springboot版本，通过Springboot管理执行器，推荐这种方式；\n        ：xxl-job-executor-sample-frameless：无框架版本；\n\n\n### 2.3 配置部署“调度中心”\n\n    调度中心项目：xxl-job-admin\n    作用：统一管理任务调度平台上调度任务，负责触发调度执行，并且提供任务管理平台。\n\n#### 步骤一：调度中心配置：\n调度中心配置文件地址：\n\n```\n/xxl-job/xxl-job-admin/src/main/resources/application.properties\n```\n\n调度中心配置内容说明：\n\n```\n### 调度中心JDBC链接：链接地址请保持和 2.1章节 所创建的调度数据库的地址一致\nspring.datasource.url=jdbc:mysql://127.0.0.1:3306/xxl_job?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai\nspring.datasource.username=root\nspring.datasource.password=root_pwd\nspring.datasource.driver-class-name=com.mysql.jdbc.Driver\n\n### 报警邮箱\nspring.mail.host=smtp.qq.com\nspring.mail.port=25\nspring.mail.username=xxx@qq.com\nspring.mail.password=xxx\nspring.mail.properties.mail.smtp.auth=true\nspring.mail.properties.mail.smtp.starttls.enable=true\nspring.mail.properties.mail.smtp.starttls.required=true\nspring.mail.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory\n\n### 调度中心通讯TOKEN [选填]：非空时启用；\nxxl.job.accessToken=\n\n### 调度中心通讯超时时间[选填]，单位秒；默认3s；\nxxl.job.timeout=3\n\n### 调度中心国际化配置 [必填]： 默认为 \"zh_CN\"/中文简体, 可选范围为 \"zh_CN\"/中文简体, \"zh_TC\"/中文繁体 and \"en\"/英文；\nxxl.job.i18n=zh_CN\n\n## 调度线程池最大线程配置【必填】\nxxl.job.triggerpool.fast.max=300\nxxl.job.triggerpool.slow.max=200\n\n### 调度中心日志表数据保存天数 [必填]：过期日志自动清理；限制大于等于7时生效，否则, 如-1，关闭自动清理功能；\nxxl.job.logretentiondays=30\n```\n\n\n#### 步骤二：部署项目：\n如果已经正确进行上述配置，可将项目编译打包部署。\n\n调度中心访问地址：http://localhost:8080/xxl-job-admin (该地址执行器将会使用到，作为回调地址)\n\n默认登录账号 \"admin/123456\", 登录后运行界面如下图所示。\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_6yC0.png \"在这里输入图片标题\")\n\n至此“调度中心”项目已经部署成功。\n\n#### 步骤三：调度中心集群（可选）：\n调度中心支持集群部署，提升调度系统容灾和可用性。\n\n调度中心集群部署时，几点要求和建议：\n- DB配置保持一致；\n- 集群机器时钟保持一致（单机集群忽视）；\n- 建议：推荐通过nginx为调度中心集群做负载均衡，分配域名。调度中心访问、执行器回调配置、调用API服务等操作均通过该域名进行。\n\n\n#### 其他：Docker 镜像方式搭建调度中心：\n\n- 下载镜像\n\n```\n/**\n* Docker地址：https://hub.docker.com/r/xuxueli/xxl-job-admin/     \n* 建议指定版本号拉取镜像；\n*/ \ndocker pull xuxueli/xxl-job-admin:{指定版本}\n```\n\n- 创建容器并运行\n\n```\n/**\n* 如需自定义 “项目配置文件” 中配置项，比如 mysql 配置，可通过 \"-e PARAMS\" 指定，参数格式: -e PARAMS=\"--key=value --key2=value2\"；\n* （配置项参考文件：/xxl-job/xxl-job-admin/src/main/resources/application.properties）\n* 如需自定义 “JVM内存参数”，可通过 \"-e JAVA_OPTS\" 指定，参数格式: -e JAVA_OPTS=\"-Xmx512m\"\n* 如需自定义 “日志文件目录”，可通过 \"-e LOG_HOME\" 指定，参数格式: -e LOG_HOME=/data/applogs\n*/\ndocker run -d \\\n-e PARAMS=\"--spring.datasource.url=jdbc:mysql://127.0.0.1:3306/xxl_job?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai\" \\\n-p 8080:8080 \\\n-v /tmp:/data/applogs \\\n--name xxl-job-admin \\\nxuxueli/xxl-job-admin:{指定版本}\n```\n\n\n### 2.4 配置部署“执行器项目”\n\n    “执行器”项目：xxl-job-executor-sample-springboot (提供多种版本执行器供选择，现以 springboot 版本为例，可直接使用，也可以参考其并将现有项目改造成执行器)\n    作用：负责接收“调度中心”的调度并执行；可直接部署执行器，也可以将执行器集成到现有业务项目中。\n\n#### 步骤一：maven依赖\n确认pom文件中引入了 \"xxl-job-core\" 的maven依赖；\n\n#### 步骤二：执行器配置\n执行器配置，配置文件地址：\n\n```\n/xxl-job/xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/resources/application.properties\n```\n\n执行器配置，配置内容说明：\n\n```\n### 调度中心部署根地址 [选填]：如调度中心集群部署存在多个地址则用逗号分隔。执行器将会使用该地址进行\"执行器心跳注册\"和\"任务结果回调\"；为空则关闭自动注册；\nxxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin\n### 调度中心通讯TOKEN [选填]：非空时启用；\nxxl.job.admin.accessToken=default_token\n### 调度中心通讯超时时间[选填]，单位秒；默认3s；\nxxl.job.admin.timeout=3\n\n### 执行器启用开关 [选填]：默认开启，关闭时不进行执行器初始化；\nxxl.job.executor.enabled=true\n### 执行器AppName [选填]：执行器心跳注册分组依据；为空则关闭自动注册\nxxl.job.executor.appname=xxl-job-executor-sample\n### 执行器注册 [选填]：优先使用该配置作为注册地址，为空时使用内嵌服务 ”IP:PORT“ 作为注册地址。从而更灵活的支持容器类型执行器动态IP和动态映射端口问题。\nxxl.job.executor.address=\n### 执行器IP [选填]：默认为空表示自动获取IP，多网卡时可手动设置指定IP，该IP不会绑定Host仅作为通讯使用；地址信息用于 \"执行器注册\" 和 \"调度中心请求并触发任务\"；\nxxl.job.executor.ip=\n### 执行器端口号 [选填]：小于等于0则自动获取；默认端口为9999，单机部署多个执行器时，注意要配置不同执行器端口；\nxxl.job.executor.port=9999\n### 执行器运行日志文件存储磁盘路径 [选填] ：需要对该路径拥有读写权限；为空则使用默认路径；\nxxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler\n### 执行器日志文件保存天数 [选填] ： 过期日志自动清理, 限制值大于等于3时生效; 否则, 如-1, 关闭自动清理功能；\nxxl.job.executor.logretentiondays=30\n### 任务扫描排除路径 [选填] ：任务扫描时忽略指定包路径下的Bean；支持配置包路径前缀，多个逗号分隔；\nxxl.job.executor.excludedpackage=org.springframework,spring\n```\n\n#### 步骤三：执行器组件配置\n\n执行器组件，配置文件地址：\n\n    /xxl-job/xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/java/com/xxl/job/executor/core/config/XxlJobConfig.java\n\n执行器组件，配置内容说明：\n\n```\n@Bean\npublic XxlJobSpringExecutor xxlJobExecutor() {\n    logger.info(\">>>>>>>>>>> xxl-job config init.\");\n    XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();\n    xxlJobSpringExecutor.setAdminAddresses(adminAddresses);\n    xxlJobSpringExecutor.setAppname(appname);\n    xxlJobSpringExecutor.setIp(ip);\n    xxlJobSpringExecutor.setPort(port);\n    xxlJobSpringExecutor.setAccessToken(accessToken);\n    xxlJobSpringExecutor.setLogPath(logPath);\n    xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);\n\n    return xxlJobSpringExecutor;\n}\n```\n\n#### 步骤四：部署执行器项目：\n如果已经正确进行上述配置，可将执行器项目编译打包部署，系统提供多种执行器Sample示例项目，选择其中一个即可，各自的部署方式如下。\n\n    xxl-job-executor-sample-springboot：项目编译打包成springboot类型的可执行JAR包，命令启动即可；\n    xxl-job-executor-sample-frameless：项目编译打包成JAR包，命令启动即可；\n\n\n至此“执行器”项目已经部署结束。\n\n#### 步骤五：执行器集群（可选）：\n执行器支持集群部署，提升调度系统可用性，同时提升任务处理能力。\n\n执行器集群部署时，几点要求和建议：\n- 执行器回调地址（xxl.job.admin.addresses）需要保持一致；执行器根据该配置进行执行器自动注册等操作。\n- 同一个执行器集群内AppName（xxl.job.executor.appname）需要保持一致；调度中心根据该配置动态发现不同集群的在线执行器列表。\n\n\n### 2.5 开发第一个任务“Hello World”\n本示例以新建一个 “GLUE模式(Java)” 运行模式的任务为例。更多有关任务的详细配置，请查看“章节三：任务详解”。\n（ “GLUE模式(Java)”的执行代码托管到调度中心在线维护，相比“Bean模式任务”需要在执行器项目开发部署上线，更加简便轻量）\n\n> 前提：请确认“调度中心”和“执行器”项目已经成功部署并启动；\n\n#### 步骤一：新建任务：\n登录调度中心，点击下图所示“新建任务”按钮，新建示例任务。然后，参考下面截图中任务的参数配置，点击保存。\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_o8HQ.png \"在这里输入图片标题\")\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_ZAsz.png \"在这里输入图片标题\")\n\n\n#### 步骤二：“GLUE模式(Java)” 任务开发：\n请点击任务右侧 “GLUE IDE” 按钮，进入 “GLUE编辑器开发界面” ，见下图。“GLUE模式(Java)” 运行模式的任务默认已经初始化了示例任务代码，即打印Hello World。\n（ “GLUE模式(Java)” 运行模式的任务实际上是一段继承自IJobHandler的Java类代码，它在执行器项目中运行，可使用@Resource/@Autowire注入执行器中的其他服务，详细介绍请查看第三章节）\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_Fgql.png \"在这里输入图片标题\")\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_dNUJ.png \"在这里输入图片标题\")\n\n#### 步骤三：触发执行：\n请点击任务右侧 “执行” 按钮，可手动触发一次任务执行（通常情况下，通过配置Cron表达式进行任务调度触发）。\n\n#### 步骤四：查看日志：\n请点击任务右侧 “日志” 按钮，可前往任务日志界面查看任务日志。\n在任务日志界面中，可查看该任务的历史调度记录以及每一次调度的任务调度信息、执行参数和执行信息。运行中的任务点击右侧的“执行日志”按钮，可进入日志控制台查看实时执行日志。\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_inc8.png \"在这里输入图片标题\")\n\n在日志控制台，可以Rolling方式实时查看任务在执行器一侧运行输出的日志信息，实时监控任务进度；\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_eYrv.png \"在这里输入图片标题\")\n\n\n## 三、任务详解\n\n### 配置属性详细说明：\n\n    基础配置：\n        - 执行器：任务的绑定的执行器，任务触发调度时将会自动发现注册成功的执行器, 实现任务自动发现功能; 另一方面也可以方便的进行任务分组。每个任务必须绑定一个执行器, 可在 \"执行器管理\" 进行设置;\n        - 任务描述：任务的描述信息，便于任务管理；\n        - 负责人：任务的负责人；\n        - 报警邮件：任务调度失败时邮件通知的邮箱地址，支持配置多邮箱地址，配置多个邮箱地址时用逗号分隔；\n        \n    触发配置：\n        - 调度类型：\n            无：该类型不会主动触发调度；\n            CRON：该类型将会通过CRON，触发任务调度；\n            固定速度：该类型将会以固定速度，触发任务调度；按照固定的间隔时间，周期性触发；\n            固定延迟：该类型将会以固定延迟，触发任务调度；按照固定的延迟时间，从上次调度结束后开始计算延迟时间，到达延迟时间后触发下次调度；\n        - CRON：触发任务执行的Cron表达式；\n        - 固定速度：固定速度的时间间隔，单位为秒；\n        - 固定延迟：固定延迟的时间间隔，单位为秒；\n        \n    任务配置：\n        - 运行模式：\n            BEAN模式：任务以JobHandler方式维护在执行器端；需要结合 \"JobHandler\" 属性匹配执行器中任务；\n            GLUE模式(Java)：任务以源码方式维护在调度中心；该模式的任务实际上是一段继承自IJobHandler的Java类代码并以 \"groovy\" 源码方式维护，它在执行器项目中运行，可使用@Resource/@Autowire注入执行器中的其他服务；\n            GLUE模式(Shell)：任务以源码方式维护在调度中心；该模式的任务实际上是一段 \"shell\" 脚本；\n            GLUE模式(Python)：任务以源码方式维护在调度中心；该模式的任务实际上是一段 \"python\" 脚本；\n            GLUE模式(PHP)：任务以源码方式维护在调度中心；该模式的任务实际上是一段 \"php\" 脚本；\n            GLUE模式(NodeJS)：任务以源码方式维护在调度中心；该模式的任务实际上是一段 \"nodejs\" 脚本；\n            GLUE模式(PowerShell)：任务以源码方式维护在调度中心；该模式的任务实际上是一段 \"PowerShell\" 脚本；\n        - JobHandler：运行模式为 \"BEAN模式\" 时生效，对应执行器中新开发的JobHandler类“@XxlJob”注解自定义的value值；\n        - 执行参数：任务执行所需的参数；     \n        \n    高级配置：\n        - 路由策略：当执行器集群部署时，提供丰富的路由策略，包括；\n            FIRST（第一个）：固定选择第一个机器；\n            LAST（最后一个）：固定选择最后一个机器；\n            ROUND（轮询）：；\n            RANDOM（随机）：随机选择在线的机器；\n            CONSISTENT_HASH（一致性HASH）：每个任务按照Hash算法固定选择某一台机器，且所有任务均匀散列在不同机器上。\n            LEAST_FREQUENTLY_USED（最不经常使用）：使用频率最低的机器优先被选举；\n            LEAST_RECENTLY_USED（最近最久未使用）：最久未使用的机器优先被选举；\n            FAILOVER（故障转移）：按照顺序依次进行心跳检测，第一个心跳检测成功的机器选定为目标执行器并发起调度；\n            BUSYOVER（忙碌转移）：按照顺序依次进行空闲检测，第一个空闲检测成功的机器选定为目标执行器并发起调度；\n            SHARDING_BROADCAST(分片广播)：广播触发对应集群中所有机器执行一次任务，同时系统自动传递分片参数；可根据分片参数开发分片任务；\n        - 子任务：每个任务都拥有一个唯一的任务ID(任务ID可以从任务列表获取)，当本任务执行结束并且执行成功时，将会触发子任务ID所对应的任务的一次主动调度。\n        - 调度过期策略：\n            - 忽略：调度过期后，忽略过期的任务，从当前时间开始重新计算下次触发时间；\n            - 立即执行一次：调度过期后，立即执行一次，并从当前时间开始重新计算下次触发时间；\n        - 阻塞处理策略：调度过于密集执行器来不及处理时的处理策略；\n            单机串行（默认）：调度请求进入单机执行器后，调度请求进入FIFO队列并以串行方式运行；\n            丢弃后续调度：调度请求进入单机执行器后，发现执行器存在运行的调度任务，本次请求将会被丢弃并标记为失败；\n            覆盖之前调度：调度请求进入单机执行器后，发现执行器存在运行的调度任务，将会终止运行中的调度任务并清空队列，然后运行本地调度任务；\n        - 任务超时时间：支持自定义任务超时时间，任务运行超时将会主动中断任务；\n        - 失败重试次数；支持自定义任务失败重试次数，当任务失败时将会按照预设的失败重试次数主动进行重试；\n\n\n\n\n\n### 3.1 BEAN模式（类形式）\n\nBean模式任务，支持基于类的开发方式，每个任务对应一个Java类。\n\n- 优点：不限制项目环境，兼容性好。即使是无框架项目，如main方法直接启动的项目也可以提供支持，可以参考示例项目 \"xxl-job-executor-sample-frameless\"；\n- 缺点：\n    - 每个任务需要占用一个Java类，造成类的浪费；\n    - 不支持自动扫描任务并注入到执行器容器，需要手动注入。\n\n#### 步骤一：执行器项目中，开发Job类：\n\n    1、开发一个继承自\"com.xxl.job.core.handler.IJobHandler\"的JobHandler类，实现其中任务方法。\n    2、手动通过如下方式注入到执行器容器。\n    ```\n    XxlJobExecutor.registJobHandler(\"demoJobHandler\", new DemoJobHandler());\n    ```\n\n#### 步骤二：调度中心，新建调度任务\n后续步骤和 \"3.2 BEAN模式（方法形式）\"一致，可以前往参考。\n\n\n### 3.2 BEAN模式（方法形式）\n\nBean模式任务，支持基于方法的开发方式，每个任务对应一个方法。\n\n- 优点：\n    - 每个任务只需要开发一个方法，并添加\"@XxlJob\"注解即可，更加方便、快速。\n    - 支持自动扫描任务并注入到执行器容器。\n- 缺点：略。\n\n>基于方法开发的任务，底层会生成JobHandler代理，和基于类的方式一样，任务也会以JobHandler的形式存在于执行器任务容器中。\n\n#### 步骤一：执行器项目中，开发Job方法：\n\n    1、任务开发：在Spring Bean实例中，开发Job方法；\n    2、注解配置：为Job方法添加注解 \"@XxlJob(value=\"自定义jobhandler名称\", init = \"JobHandler初始化方法\", destroy = \"JobHandler销毁方法\")\"，注解value值对应的是调度中心新建任务的JobHandler属性的值。\n    3、执行日志：需要通过 \"XxlJobHelper.log\" 打印执行日志；\n    4、任务结果：默认任务结果为 \"成功\" 状态，不需要主动设置；如有诉求，比如设置任务结果为失败，可以通过 \"XxlJobHelper.handleFail/handleSuccess\" 自主设置任务结果；\n\n```\n// 可参考Sample示例执行器中的 \"com.xxl.job.executor.jobhandler.SampleXxlJob\" ，如下：\n@XxlJob(\"demoJobHandler\")\npublic void demoJobHandler() throws Exception {\n    XxlJobHelper.log(\"XXL-JOB, Hello World.\");\n}\n```\n\n#### 步骤二：调度中心，新建调度任务\n参考上文“配置属性详细说明”对新建的任务进行参数配置，运行模式选中 \"BEAN模式\"，JobHandler属性填写任务注解“@XxlJob”中定义的值；\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_ZAsz.png \"在这里输入图片标题\")\n\n#### 原生内置Bean模式任务（通用执行器）\n为方便用户参考与快速使用，提供 “通用执行器” 并内置多个Bean模式任务Handler，可以直接配置使用，如下：\n\n**通用执行器说明：**\n- AppName：xxl-job-executor-sample\n- 执行器代码：\n  - xxl-job-executor-sample-springboot：springboot版本\n  - xxl-job-executor-sample-frameless：无框架版本\n\n**执行器内置任务列表：**\n- a、demoJobHandler：简单示例任务，任务内部模拟耗时任务逻辑，用户可在线体验Rolling Log等功能；\n- b、shardingJobHandler：分片示例任务，任务内部模拟处理分片参数，可参考熟悉分片任务；\n- c、httpJobHandler：通用HTTP任务Handler；业务方只需要提供HTTP链接等信息即可，不限制语言、平台。任务入参示例如下：\n\n```\n// 1、简单示例：\n{\n    \"url\": \"http://www.baidu.com\",\n    \"method\": \"GET\",\n    \"data\": \"hello world\"\n}\n\n// 2、完整参数示例：\n{\n    \"url\": \"http://www.baidu.com\",              // 请求URL\n    \"method\": \"POST\",                           // 请求方法，支持：GET、POST、HEAD、OPTIONS、PUT、DELETE、TRACE\n    \"contentType\": \"application/json\",          // 请求内容类型，支持：application/json、application/x-www-form-urlencoded、application/xml、text/html、text/xml、text/plain\n    \"headers\": {                                // 请求Header，key-value结构\n        \"header01\": \"value01\"\n    },\n    \"cookies\": {                                // 请求Cookie，key-value结构\n        \"cookie01\": \"value01\"\n    },\n    \"timeout\": 3000,                            // 请求超时时间，默认 3000；单位：毫秒；\n    \"data\": \"request body data\",                // 请求Body数据，仅针对 POST 请求有效\n    \"form\": {                                   // 请求Form数据，仅针对 GET 请求有效\n        \"key01\": \"value01\"\n    },\n    \"auth\": \"auth data\"                         // 请求认证信息, 通过Basic Auth方式认证\n}\n```\n\n- d、commandJobHandler：通用命令行任务Handler；业务方只需要提供命令行即可，命令及参数之间通过空格隔开；如任务参数 \"ls la\" 或 \"pwd\" 将会执行命令并输出数据；\n\n#### 原生内置Bean模式任务（AI执行器）\n为方便用户参考与快速使用，提供 “AI执行器” 并内置多个Bean模式 AI任务Handler，与spring-ai、ollama、dify等集成打通，支持快速开发AI类任务，如下：\n\n**AI执行器说明：**\n- AppName：xxl-job-executor-sample-ai\n- 执行器代码：xxl-job-executor-sample-springboot-ai\n\n**执行器内置任务列表：**\n- a、ollamaJobHandler： OllamaChat任务，支持自定义prompt、input等输入信息。示例任务入参如下：\n```\n{\n    \"input\": \"{输入信息，必填信息}\",\n    \"prompt\": \"{模型prompt，可选信息}\",\n    \"model\": \"{模型实现，如qwen3:0.6b，可选信息}\"\n}\n```\n- b、difyWorkflowJobHandler：DifyWorkflow 任务，支持自定义inputs、user、baseUrl、apiKey 等输入信息，示例参数如下；\n```\n{\n    \"inputs\":{                          // inputs 为dify工作流任务参数；参数不固定，结合各自 workflow 自行定义。\n        \"input\":\"{用户输入信息}\"          // 该参数为示例变量，需要 workflow 的“开始”节点 自定义参数 “input”，可自行调整或删除。\n    },\n    \"user\": \"xxl-job\",                  // 用户标识，选填\n    \"baseUrl\": \"http://localhost/v1\",   // Dify应用的 访问API 地址，需要从 Dify 系统获取；\n    \"apiKey\": \"xxx\"                     // Dify应用的 API-Key，需要从 Dify 系统获取；\n}\n```\n\n- 依赖1：参考 [Ollama本地化部署大模型](https://www.xuxueli.com/blog/?blog=./notebook/13-AI/%E4%BD%BF%E7%94%A8Ollama%E6%9C%AC%E5%9C%B0%E5%8C%96%E9%83%A8%E7%BD%B2DeepSeek.md) ，执行器示例部署“qwen2.5:1.5b”模型，也可自定选择其他模型版本。\n- 依赖2：参考 [使用DeepSeek与Dify搭建AI助手](https://www.xuxueli.com/blog/?blog=./notebook/13-AI/%E4%BD%BF%E7%94%A8DeepSeek%E4%B8%8EDify%E6%90%AD%E5%BB%BAAI%E5%8A%A9%E6%89%8B.md)，执行器示例新建Dify DifyWork应用，并在开始节点添加“input”参数，可结合实际情况调整。\n- 依赖3：启动示例 “AI执行器” 相关配置文件说明如下：\n\n```\n// ollama 配置\nspring.ai.ollama.base-url=http://localhost:11434\nspring.ai.ollama.chat.enabled=true\n// Model模型配置；注意，此处配置模型版本、必须本地先通过ollama进行安装运行。\nspring.ai.ollama.chat.options.model=qwen2.5:1.5b\nspring.ai.ollama.chat.options.temperature=0.8\n\n// dify 配置；选择相关 workflow 应用，切换 “访问API” 页面获取 url 地址信息.\ndify.base-url=http://localhost/v1\n// dify api-key；选择相关 workflow 应用并进入 “访问API” 页面，右上角 “API 密钥” 入口获取 api-key。\ndify.api-key={自行获取并修改}\n\n```\n\n\n### 3.3 GLUE模式(Java)\n任务以源码方式维护在调度中心，支持通过Web IDE在线更新，实时编译和生效，因此不需要指定JobHandler。开发流程如下：\n\n#### 步骤一：调度中心，新建调度任务：\n参考上文“配置属性详细说明”对新建的任务进行参数配置，运行模式选中 \"GLUE模式(Java)\"；\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_tJOq.png \"在这里输入图片标题\")\n\n#### 步骤二：开发任务代码：\n选中指定任务，点击该任务右侧“GLUE”按钮，将会前往GLUE任务的Web IDE界面，在该界面支持对任务代码进行开发（也可以在IDE中开发完成后，复制粘贴到编辑器中）。\n\n版本回溯功能（支持30个版本的版本回溯）：在GLUE任务的Web IDE界面，选择右上角下拉框“版本回溯”，会列出该GLUE的更新历史，选择相应版本即可显示该版本代码，保存后GLUE代码即回退到对应的历史版本；\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_dNUJ.png \"在这里输入图片标题\")\n\n### 3.4 GLUE模式(Shell)\n\n#### 步骤一：调度中心，新建调度任务\n参考上文“配置属性详细说明”对新建的任务进行参数配置，运行模式选中 \"GLUE模式(Shell)\"；\n\n#### 步骤二：开发任务代码：\n选中指定任务，点击该任务右侧“GLUE”按钮，将会前往GLUE任务的Web IDE界面，在该界面支持对任务代码进行开发（也可以在IDE中开发完成后，复制粘贴到编辑器中）。\n\n该模式的任务实际上是一段 \"shell\" 脚本；\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_iUw0.png \"在这里输入图片标题\")\n\n### 3.4 GLUE模式(Python)\n\n#### 步骤一：调度中心，新建调度任务\n参考上文“配置属性详细说明”对新建的任务进行参数配置，运行模式选中 \"GLUE模式(Python)\"；\n\n#### 步骤二：开发任务代码：\n选中指定任务，点击该任务右侧“GLUE”按钮，将会前往GLUE任务的Web IDE界面，在该界面支持对任务代码进行开发（也可以在IDE中开发完成后，复制粘贴到编辑器中）。\n\n该模式的任务实际上是一段 \"python\" 脚本；\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_BPLG.png \"在这里输入图片标题\")\n\n### 3.5 GLUE模式(NodeJS)\n\n#### 步骤一：调度中心，新建调度任务\n参考上文“配置属性详细说明”对新建的任务进行参数配置，运行模式选中 \"GLUE模式(NodeJS)\"；\n\n#### 步骤二：开发任务代码：\n选中指定任务，点击该任务右侧“GLUE”按钮，将会前往GLUE任务的Web IDE界面，在该界面支持对任务代码进行开发（也可以在IDE中开发完成后，复制粘贴到编辑器中）。\n\n该模式的任务实际上是一段 \"nodeJS\" 脚本；\n\n### 3.6 GLUE模式(PHP)\n同上\n\n### 3.7 GLUE模式(PowerShell)\n同上\n\n\n\n## 四、操作指南\n\n### 4.1 配置执行器\n点击进入\"执行器管理\"界面, 如下图:\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_Hr2T.png \"在这里输入图片标题\")\n\n    1、\"调度中心OnLine:\"右侧显示在线的\"调度中心\"列表, 任务执行结束后, 将会以failover的模式进行回调调度中心通知执行结果, 避免回调的单点风险;\n    2、\"执行器列表\" 中显示在线的执行器列表, 可通过\"OnLine 机器\"查看对应执行器的集群机器。\n\n点击按钮 \"+新增执行器\" 弹框如下图, 可新增执行器配置:\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_V3vF.png \"在这里输入图片标题\")\n\n执行器属性说明\n\n    AppName: 是每个执行器集群的唯一标示AppName, 执行器会周期性以AppName为对象进行自动注册。可通过该配置自动发现注册成功的执行器, 供任务调度时使用;\n    名称: 执行器的名称, 因为AppName限制字母数字等组成,可读性不强, 名称为了提高执行器的可读性;\n    排序: 执行器的排序, 系统中需要执行器的地方,如任务新增, 将会按照该排序读取可用的执行器列表;\n    注册方式：调度中心获取执行器地址的方式；\n        自动注册：执行器自动进行执行器注册，调度中心通过底层注册表可以动态发现执行器机器地址；\n        手动录入：人工手动录入执行器的地址信息，多地址逗号分隔，供调度中心使用；\n    机器地址：\"注册方式\"为\"手动录入\"时有效，支持人工维护执行器的地址信息；注册地址格式可参考“http://127.0.0.1:9999/”，为执行器内嵌服务地址；\n\n### 4.2 新建任务\n进入任务管理界面，点击“新增任务”按钮，在弹出的“新增任务”界面配置任务属性后保存即可。详情页参考章节 \"三、任务详解\"。\n\n### 4.3 编辑任务\n进入任务管理界面，选中指定任务。点击该任务右侧“编辑”按钮，在弹出的“编辑任务”界面更新任务属性后保存即可，可以修改设置的任务属性信息：\n\n### 4.4 编辑GLUE代码\n\n该操作仅针对GLUE任务。\n\n选中指定任务，点击该任务右侧“GLUE”按钮，将会前往GLUE任务的Web IDE界面，在该界面支持对任务代码进行开发。可参考章节 \"3.3 GLUE模式(Java)\"。\n\n### 4.5 启动/停止任务\n可对任务进行“启动”和“停止”操作。\n需要注意的是，此处的启动/停止仅针对任务的后续调度触发行为，不会影响到已经触发的调度任务，如需终止已经触发的调度任务，可查看“4.9 终止运行中的任务”\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_ZAhX.png \"在这里输入图片标题\")\n\n### 4.6 手动触发一次调度\n点击“执行”按钮，可手动触发一次任务调度，不影响原有调度规则。\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_ZAhX.png \"在这里输入图片标题\")\n\n### 4.7 查看调度日志\n点击“日志”按钮，可以查看任务历史调度日志。在历史调度日志界面可查看每次任务调度的调度结果、执行结果等，点击“执行日志”按钮可查看执行器完整日志。\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_ZAhX.png \"在这里输入图片标题\")\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_UDSo.png \"在这里输入图片标题\")\n\n    调度时间：\"调度中心\"触发本次调度并向\"执行器\"发送任务执行信号的时间；\n    调度结果：\"调度中心\"触发本次调度的结果，200表示成功，500或其他表示失败；\n    调度备注：\"调度中心\"触发本次调度的日志信息；\n    执行器地址：本次任务执行的机器地址\n    运行模式：触发调度时任务的运行模式，运行模式可参考章节 \"三、任务详解\"；\n    任务参数：本地任务执行的入参\n    执行时间：\"执行器\"中本次任务执行结束后回调的时间；\n    执行结果：\"执行器\"中本次任务执行的结果，200表示成功，500或其他表示失败；\n    执行备注：\"执行器\"中本次任务执行的日志信息；\n    操作：\n        \"执行日志\"按钮：点击可查看本地任务执行的详细日志信息；详见“4.8 查看执行日志”；\n        \"终止任务\"按钮：点击可终止本地调度对应执行器上本任务的执行线程，包括未执行的阻塞任务一并被终止；\n\n### 4.8 查看执行日志\n点击执行日志右侧的 “执行日志” 按钮，可跳转至执行日志界面，可以查看业务代码中打印的完整日志，如下图；\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_tvGI.png \"在这里输入图片标题\")\n\n### 4.9 终止运行中的任务\n仅针对执行中的任务。\n在任务日志界面，点击右侧的“终止任务”按钮，将会向本次任务对应的执行器发送任务终止请求，将会终止掉本次任务，同时会清空掉整个任务执行队列。\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_hIci.png \"在这里输入图片标题\")\n\n任务终止时通过 \"interrupt\" 执行线程的方式实现, 将会触发 \"InterruptedException\" 异常。因此如果JobHandler内部catch到了该异常并消化掉的话, 任务终止功能将不可用。\n\n因此, 如果遇到上述任务终止不可用的情况, 需要在JobHandler中应该针对 \"InterruptedException\" 异常进行特殊处理 (向上抛出) , 正确逻辑如下:\n```\ntry{\n    // do something\n} catch (Exception e) {\n    if (e instanceof InterruptedException) {\n        throw e;\n    }\n    logger.warn(\"{}\", e);\n}\n```\n\n而且，在JobHandler中开启子线程时，子线程也不可catch处理\"InterruptedException\"，应该主动向上抛出。\n\n任务终止时会执行对应JobHandler的\"destroy()\"方法，可以借助该方法处理一些资源回收的逻辑。\n\n\n### 4.10 删除执行日志\n在任务日志界面，选中执行器和任务之后，点击右侧的\"删除\"按钮将会出现\"日志清理\"弹框，弹框中支持选择不同类型的日志清理策略，选中后点击\"确定\"按钮即可进行日志清理操作；\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_Ypik.png \"在这里输入图片标题\")\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_EB65.png \"在这里输入图片标题\")\n\n### 4.11 删除任务\n点击删除按钮，可以删除对应任务。\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_Z9Qr.png \"在这里输入图片标题\")\n\n### 4.12 用户管理\n进入 \"用户管理\" 界面，可查看和管理用户信息；\n\n目前用户分为两种角色：\n- 管理员：拥有全量权限，支持在线管理用户信息，为用户分配权限，权限分配粒度为执行器；\n- 普通用户：仅拥有被分配权限的执行器，及相关任务的操作权限；\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_1001.png \"在这里输入图片标题\")\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_1002.png \"在这里输入图片标题\")\n\n\n\n## 五、总体设计\n### 5.1 源码目录介绍\n    - /doc :文档资料\n    - /db :“调度数据库”建表脚本\n    - /xxl-job-admin :调度中心，项目源码\n    - /xxl-job-core :公共Jar依赖\n    - /xxl-job-executor-samples :执行器，Sample示例项目（大家可以在该项目上进行开发，也可以将现有项目改造生成执行器项目）\n\n### 5.2 “调度数据库”配置\nXXL-JOB调度模块基于自研调度组件并支持集群部署，调度数据库表说明如下：\n\n    - xxl_job_lock：任务调度锁表；\n    - xxl_job_group：执行器信息表，维护任务执行器信息；\n    - xxl_job_info：调度扩展信息表： 用于保存XXL-JOB调度任务的扩展信息，如任务分组、任务名、机器地址、执行器、执行入参和报警邮件等等；\n    - xxl_job_log：调度日志表： 用于保存XXL-JOB任务调度的历史信息，如调度结果、执行结果、调度入参、调度机器和执行器等等；\n    - xxl_job_log_report：调度日志报表：用户存储XXL-JOB任务调度日志的报表，调度中心报表功能页面会用到；\n    - xxl_job_logglue：任务GLUE日志：用于保存GLUE更新历史，用于支持GLUE的版本回溯功能；\n    - xxl_job_registry：执行器注册表，维护在线的执行器和调度中心机器地址信息；\n    - xxl_job_user：系统用户表；\n\n\n### 5.3 架构设计\n#### 5.3.1 设计思想\n将调度行为抽象形成“调度中心”公共平台，而平台自身并不承担业务逻辑，“调度中心”负责发起调度请求。\n\n将任务抽象成分散的JobHandler，交由“执行器”统一管理，“执行器”负责接收调度请求并执行对应的JobHandler中的业务逻辑。\n\n因此，“调度”和“任务”两部分可以相互解耦，提高系统整体稳定性和扩展性；\n\n#### 5.3.2 系统组成\n- **调度模块（调度中心）**：\n  负责管理调度信息，按照调度配置发出调度请求，自身不承担业务代码。调度系统与任务解耦，提高了系统可用性和稳定性，同时调度系统性能不再受限于任务模块；\n  支持可视化、简单且动态的管理调度信息，包括任务新建，更新，删除，GLUE开发和任务报警等，所有上述操作都会实时生效，同时支持监控调度结果以及执行日志，支持执行器Failover。\n- **执行模块（执行器）**：\n  负责接收调度请求并执行任务逻辑。任务模块专注于任务的执行等操作，开发和维护更加简单和高效；\n  接收“调度中心”的执行请求、终止请求和日志请求等。\n\n#### 5.3.3 架构图\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_Qohm.png \"在这里输入图片标题\")\n\n### 5.4 调度模块剖析\n#### 5.4.1 quartz的不足\nQuartz作为开源作业调度中的佼佼者，是作业调度的首选。但是集群环境中Quartz采用API的方式对任务进行管理，从而可以避免上述问题，但是同样存在以下问题：\n\n- 问题一：调用API的方式操作任务，不人性化；\n- 问题二：需要持久化业务QuartzJobBean到底层数据表中，系统侵入性相当严重。\n- 问题三：调度逻辑和QuartzJobBean耦合在同一个项目中，这将导致一个问题，在调度任务数量逐渐增多，同时调度任务逻辑逐渐加重的情况下，此时调度系统的性能将大大受限于业务；\n- 问题四：quartz底层以“抢占式”获取DB锁并由抢占成功节点负责运行任务，会导致节点负载悬殊非常大；而XXL-JOB通过执行器实现“协同分配式”运行任务，充分发挥集群优势，负载各节点均衡。\n\nXXL-JOB弥补了quartz的上述不足之处。\n\n#### 5.4.2 自研调度模块\nXXL-JOB最终选择自研调度组件（早期调度组件基于Quartz）；一方面是为了精简系统降低冗余依赖，另一方面是为了提供系统的可控度与稳定性；\n\nXXL-JOB中“调度模块”和“任务模块”完全解耦，调度模块进行任务调度时，将会解析不同的任务参数发起远程调用，调用各自的远程执行器服务。这种调用模型类似RPC调用，调度中心提供调用代理的功能，而执行器提供远程服务的功能。\n\n#### 5.4.3 调度中心HA（集群）\n基于数据库的集群方案，数据库选用Mysql；集群分布式并发环境中进行定时任务调度时，会在各个节点上报任务，存到数据库中，执行时会从数据库中取出触发器来执行，如果触发器的名称和执行时间相同，则只有一个节点去执行此任务。\n\n#### 5.4.4 调度线程池\n调度采用线程池方式实现，避免单线程因阻塞而引起任务调度延迟。\n\n#### 5.4.5 并行调度\nXXL-JOB调度模块默认采用并行机制，在多线程调度的情况下，调度模块被阻塞的几率很低，大大提高了调度系统的承载量。\n\nXXL-JOB的不同任务之间并行调度、并行执行。\nXXL-JOB的单个任务，针对多个执行器是并行运行的，针对单个执行器是串行执行的。同时支持任务终止。\n\n#### 5.4.6 过期处理策略\n任务调度错过触发时间时的处理策略：\n- 可能原因：服务重启；调度线程被阻塞，线程被耗尽；上次调度持续阻塞，下次调度被错过；\n- 处理策略：\n    - 过期超5s：本次忽略，当前时间开始计算下次触发时间\n    - 过期5s内：立即触发一次，当前时间开始计算下次触发时间\n\n\n#### 5.4.7 日志回调服务\n调度模块的“调度中心”作为Web服务部署时，一方面承担调度中心功能，另一方面也为执行器提供API服务。\n\n调度中心提供的\"日志回调服务API服务\"代码位置如下：\n```\nxxl-job-admin#com.xxl.job.admin.controller.JobApiController.callback\n```\n\n“执行器”在接收到任务执行请求后，执行任务，在执行结束之后会将执行结果回调通知“调度中心”：\n\n#### 5.4.8 任务HA（Failover）\n执行器如若集群部署，调度中心将会感知到在线的所有执行器，如“127.0.0.1:9997, 127.0.0.1:9998, 127.0.0.1:9999”。\n\n当任务\"路由策略\"选择\"故障转移(FAILOVER)\"时，当调度中心每次发起调度请求时，会按照顺序对执行器发出心跳检测请求，第一个检测为存活状态的执行器将会被选定并发送调度请求。\n\n调度成功后，可在日志监控界面查看“调度备注”，如下；\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_jrdI.png \"在这里输入图片标题\")\n\n“调度备注”可以看出本地调度运行轨迹，执行器的\"注册方式\"、\"地址列表\"和任务的\"路由策略\"。\"故障转移(FAILOVER)\"路由策略下，调度中心首先对第一个地址进行心跳检测，心跳失败因此自动跳过，第二个依然心跳检测失败……\n直至心跳检测第三个地址“127.0.0.1:9999”成功，选定为“目标执行器”；然后对“目标执行器”发送调度请求，调度流程结束，等待执行器回调执行结果。\n\n#### 5.4.9 调度日志\n调度中心每次进行任务调度，都会记录一条任务日志，任务日志主要包括以下三部分内容：\n\n- 任务信息：包括“执行器地址”、“JobHandler”和“执行参数”等属性，点击任务ID按钮可查看，根据这些参数，可以精确的定位任务执行的具体机器和任务代码；\n- 调度信息：包括“调度时间”、“调度结果”和“调度日志”等，根据这些参数，可以了解“调度中心”发起调度请求时的具体情况。\n- 执行信息：包括“执行时间”、“执行结果”和“执行日志”等，根据这些参数，可以了解在“执行器”端任务执行的具体情况；\n\n调度日志，针对单次调度，属性说明如下：\n- 执行器地址：任务执行的机器地址；\n- JobHandler：Bean模式表示任务执行的JobHandler名称；\n- 任务参数：任务执行的入参；\n- 调度时间：调度中心，发起调度的时间；\n- 调度结果：调度中心，发起调度的结果，SUCCESS或FAIL；\n- 调度备注：调度中心，发起调度的备注信息，如地址心跳检测日志等；\n- 执行时间：执行器，任务执行结束后回调的时间；\n- 执行结果：执行器，任务执行的结果，SUCCESS或FAIL；\n- 执行备注：执行器，任务执行的备注信息，如异常日志等；\n- 执行日志：任务执行过程中，业务代码中打印的完整执行日志，见“4.8 查看执行日志”；\n\n#### 5.4.10 任务依赖\n原理：XXL-JOB中每个任务都对应有一个任务ID，同时，每个任务支持设置属性“子任务ID”，因此，通过“任务ID”可以匹配任务依赖关系。\n\n当父任务执行结束并且执行成功时，将会根据“子任务ID”匹配子任务依赖，如果匹配到子任务，将会主动触发一次子任务的执行。\n\n在任务日志界面，点击任务的“执行备注”的“查看”按钮，可以看到匹配子任务以及触发子任务执行的日志信息，如无信息则表示未触发子任务执行，可参考下图。\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_Wb2o.png \"在这里输入图片标题\")\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-job/images/img_jOAU.png \"在这里输入图片标题\")\n\n#### 5.4.11  全异步化 & 轻量级\n\n- 全异步化设计：XXL-JOB系统中业务逻辑在远程执行器执行，触发流程全异步化设计。相比直接在调度中心内部执行业务逻辑，极大的降低了调度线程占用时间；\n    - 异步调度：调度中心每次任务触发时仅发送一次调度请求，该调度请求首先推送“异步调度队列”，然后异步推送给远程执行器\n    - 异步执行：执行器会将请求存入“异步执行队列”并且立即响应调度中心，异步运行。\n- 轻量级设计：XXL-JOB调度中心中每个JOB逻辑非常 “轻”，在全异步化的基础上，单个JOB一次运行平均耗时基本在 \"10ms\" 之内（基本为一次请求的网络开销）；因此，可以保证使用有限的线程支撑大量的JOB并发运行；\n\n得益于上述两点优化，理论上默认配置下的调度中心，单机能够支撑 5000 任务并发运行稳定运行；\n\n实际场景中，由于调度中心与执行器网络ping延迟不同、DB读写耗时不同、任务调度密集程度不同，会导致任务量上限上下波动。\n\n如若需要支撑更多的任务量，可以通过 \"调大调度线程数\" 、\"降低调度中心与执行器ping延迟\" 和 \"提升机器配置\" 几种方式优化。\n\n#### 5.4.12 均衡调度\n调度中心在集群部署时会自动进行任务平均分配，触发组件每次获取与线程池数量（调度中心支持自定义调度线程池大小）相关数量的任务，避免大量任务集中在单个调度中心集群节点；\n\n### 5.5 任务 \"运行模式\" 剖析\n#### 5.5.1 \"Bean模式\" 任务\n开发步骤：可参考 \"章节三\" ；\n原理：每个Bean模式任务都是一个Spring的Bean类实例，它被维护在“执行器”项目的Spring容器中。任务类需要加“@JobHandler(value=\"名称\")”注解，因为“执行器”会根据该注解识别Spring容器中的任务。任务类需要继承统一接口“IJobHandler”，任务逻辑在execute方法中开发，因为“执行器”在接收到调度中心的调度请求时，将会调用“IJobHandler”的execute方法，执行任务逻辑。\n\n#### 5.5.2 \"GLUE模式(Java)\" 任务\n开发步骤：可参考 \"章节三\" ；\n原理：每个 \"GLUE模式(Java)\" 任务的代码，实际上是“一个继承自“IJobHandler”的实现类的类代码”，“执行器”接收到“调度中心”的调度请求时，会通过Groovy类加载器加载此代码，实例化成Java对象，同时注入此代码中声明的Spring服务（请确保Glue代码中的服务和类引用在“执行器”项目中存在），然后调用该对象的execute方法，执行任务逻辑。\n\n#### 5.5.3 GLUE模式(Shell) + GLUE模式(Python) + GLUE模式(PHP) + GLUE模式(NodeJS) + GLUE模式(Powershell)\n开发步骤：可参考 \"章节三\" ；\n原理：脚本任务的源码托管在调度中心，脚本逻辑在执行器运行。当触发脚本任务时，执行器会加载脚本源码在执行器机器上生成一份脚本文件，然后通过Java代码调用该脚本；并且实时将脚本输出日志写到任务日志文件中，从而在调度中心可以实时监控脚本运行情况；\n\n目前支持的脚本类型如下：\n\n    - shell脚本：任务运行模式选择为 \"GLUE模式(Shell)\"时支持 \"Shell\" 脚本任务；\n    - python脚本：任务运行模式选择为 \"GLUE模式(Python)\"时支持 \"Python\" 脚本任务；\n    - php脚本：任务运行模式选择为 \"GLUE模式(PHP)\"时支持 \"PHP\" 脚本任务；\n    - nodejs脚本：任务运行模式选择为 \"GLUE模式(NodeJS)\"时支持 \"NodeJS\" 脚本任务；\n    - powershell：任务运行模式选择为 \"GLUE模式(PowerShell)\"时支持 \"PowerShell\" 脚本任务；\n\n脚本任务通过 Exit Code 判断任务执行结果，状态码可参考章节 \"5.15 任务执行结果说明\"；\n\n#### 5.5.4 执行器\n执行器实际上是一个内嵌的Server，默认端口9999（配置项：xxl.job.executor.port）。\n\n在项目启动时，执行器会通过“@XxlJob”识别Spring容器中“Bean模式任务”，以注解的value属性为key管理起来。\n\n“执行器”接收到“调度中心”的调度请求时，如果任务类型为“Bean模式”，将会匹配Spring容器中的“Bean模式任务”，然后调用其execute方法，执行任务逻辑。如果任务类型为“GLUE模式”，将会加载GLue代码，实例化Java对象，注入依赖的Spring服务（注意：Glue代码中注入的Spring服务，必须存在与该“执行器”项目的Spring容器中），然后调用execute方法，执行任务逻辑。\n\n#### 5.5.5 任务日志\nXXL-JOB会为每次调度请求生成一个单独的日志文件，需要通过 \"XxlJobHelper.log\" 打印执行日志，“调度中心”查看执行日志时将会加载对应的日志文件。\n\n(历史版本通过重写LOG4J的Appender实现，存在依赖限制，该方式在新版本已经被抛弃)\n\n日志文件存放的位置可在“执行器”配置文件进行自定义，默认目录格式为：/data/applogs/xxl-job/jobhandler/“格式化日期”/“数据库调度日志记录的主键ID.log”。\n\n在JobHandler中开启子线程时，子线程将会把日志打印在父线程即JobHandler的执行日志中，方便日志追踪。\n\n### 5.6 通讯模块剖析\n\n#### 5.6.1 一次完整的任务调度通讯流程\n    - 1、“调度中心”向“执行器”发送http调度请求: “执行器”中接收请求的服务，实际上是一台内嵌Server，默认端口9999;\n    - 2、“执行器”执行任务逻辑；\n    - 3、“执行器”http回调“调度中心”调度结果: “调度中心”中接收回调的服务，是针对执行器开放一套API服务;\n\n#### 5.6.2 通讯数据加密\n调度中心向执行器发送的调度请求时使用RequestModel和ResponseModel两个对象封装调度请求参数和响应数据, 在进行通讯之前底层会将上述两个对象对象序列化，并进行数据协议以及时间戳检验,从而达到数据加密的功能;\n\n### 5.7 任务注册, 任务自动发现\n自v1.5版本之后, 任务取消了\"任务执行机器\"属性, 改为通过任务注册和自动发现的方式, 动态获取远程执行器地址并执行。\n\n    AppName: 每个执行器机器集群的唯一标示, 任务注册以 \"执行器\" 为最小粒度进行注册; 每个任务通过其绑定的执行器可感知对应的执行器机器列表;\n    注册表: 见\"xxl_job_registry\"表, \"执行器\" 在进行任务注册时将会周期性维护一条注册记录，即机器地址和AppName的绑定关系; \"调度中心\" 从而可以动态感知每个AppName在线的机器列表;\n    执行器注册: 任务注册Beat周期默认30s; 执行器以一倍Beat进行执行器注册, 调度中心以一倍Beat进行动态任务发现; 注册信息的失效时间为三倍Beat; \n    执行器注册摘除：执行器销毁时，将会主动上报调度中心并摘除对应的执行器机器信息，提高心跳注册的实时性；\n\n\n为保证系统\"轻量级\"并且降低学习部署成本，没有采用Zookeeper作为注册中心，采用DB方式进行任务注册发现；\n\n### 5.8 任务执行结果\n自v1.6.2之后，任务执行结果通过 \"IJobHandler\" 的返回值 \"ReturnT\" 进行判断；\n当返回值符合 \"ReturnT#code == 200\" 时表示任务执行成功，否则表示任务执行失败，而且可以通过 \"ReturnT#msg\" 回调错误信息给调度中心；\n从而，在任务逻辑中可以方便的控制任务执行结果；\n\n### 5.9 分片广播 & 动态分片\n执行器集群部署时，任务路由策略选择\"分片广播\"情况下，一次任务调度将会广播触发对应集群中所有执行器执行一次任务，同时系统自动传递分片参数；可根据分片参数开发分片任务；\n\n\"分片广播\" 以执行器为维度进行分片，支持动态扩容执行器集群从而动态增加分片数量，协同进行业务处理；在进行大数据量业务操作时可显著提升任务处理能力和速度。\n\n\"分片广播\" 和普通任务开发流程一致，不同之处在于可以获取分片参数，获取分片参数进行分片业务处理。\n\n- Java语言任务获取分片参数方式：BEAN、GLUE模式(Java)\n```\n// 可参考Sample示例执行器中的示例任务\"ShardingJobHandler\"了解试用 \nint shardIndex = XxlJobHelper.getShardIndex();\nint shardTotal = XxlJobHelper.getShardTotal();\n```\n- 脚本语言任务获取分片参数方式：GLUE模式(Shell)、GLUE模式(Python)、GLUE模式(Nodejs)\n```\n// 脚本任务入参固定为三个，依次为：任务传参、分片序号、分片总数。以Shell模式任务为例，获取分片参数代码如下\necho \"分片序号 index = $2\"\necho \"分片总数 total = $3\"\n```  \n\n分片参数属性说明：\n\n    index：当前分片序号(从0开始)，执行器集群列表中当前执行器的序号；\n    total：总分片数，执行器集群的总机器数量；\n\n该特性适用场景如：\n- 1、分片任务场景：10个执行器的集群来处理10w条数据，每台机器只需要处理1w条数据，耗时降低10倍；\n- 2、广播任务场景：广播执行器机器运行shell脚本、广播集群节点进行缓存更新等\n\n### 5.10 访问令牌（AccessToken）\n为提升系统安全性，调度中心和执行器进行安全性校验，双方AccessToken匹配才允许通讯；\n\n调度中心和执行器，可通过配置项 \"xxl.job.accessToken\" 进行AccessToken的设置。\n\n调度中心和执行器，如果需要正常通讯，只有两种设置；\n\n- 设置一：调度中心和执行器，均不设置AccessToken；关闭安全性校验；\n- 设置二：调度中心和执行器，设置了相同的AccessToken；\n\n### 5.11 故障转移 & 失败重试\n一次完整任务流程包括\"调度（调度中心） + 执行（执行器）\"两个阶段。\n\n- \"故障转移\"发生在调度阶段，在执行器集群部署时，如果某一台执行器发生故障，该策略支持自动进行Failover切换到一台正常的执行器机器并且完成调度请求流程。\n- \"失败重试\"发生在\"调度 + 执行\"两个阶段，支持通过自定义任务失败重试次数，当任务失败时将会按照预设的失败重试次数主动进行重试；\n\n### 5.12 执行器灰度上线\n调度中心与业务解耦，只需部署一次后常年不需要维护。但是，执行器中托管运行着业务作业，作业上线和变更需要重启执行器，尤其是Bean模式任务。\n执行器重启可能会中断运行中的任务。但是，XXL-JOB得益于自建执行器与自建注册中心，可以通过灰度上线的方式，避免因重启导致的任务中断的问题。\n\n步骤如下：\n- 1、执行器改为手动注册，下线一半机器列表（A组），线上运行另一半机器列表（B组）；\n- 2、等待A组机器任务运行结束并编译上线；执行器注册地址替换为A组；\n- 3、等待B组机器任务运行结束并编译上线；执行器注册地址替换为A组+B组；\n  操作结束；\n\n### 5.13 任务执行结果说明\n系统根据以下标准判断任务执行结果，可参考之。\n\n-- | Bean/Glue(Java) | Glue(Shell) 等脚本任务\n--- | --- | ---\n成功 | IJobHandler.SUCCESS | 0\n失败 | IJobHandler.FAIL | -1（非0状态码）\n\n### 5.14 任务超时控制\n支持设置任务超时时间，任务运行超时的情况下，将会主动中断任务；\n\n需要注意的是，任务超时中断时与任务终止机制（可查看“4.9 终止运行中的任务”）类似，也是通过 \"interrupt\" 中断任务，因此业务代码需要将 \"InterruptedException\" 外抛，否则功能不可用。\n\n### 5.15 跨语言\nXXL-JOB是一个跨语言的任务调度平台，主要体现在如下几个方面：\n- 1、OpenApi（RESTful 格式）：调度中心与执行器提供语言无关的 RESTful API 服务，第三方任意语言可据此对接调度中心或者实现执行器，实现多语言支持。（可参考章节 “调度中心/执行器 RESTful API” ）\n- 2、多任务模式：提供Java、Python、PHP……等十来种任务模式，可参考章节 “5.5 任务 \"运行模式\" ”；理论上可扩展任意语言任务模式；\n- 2、提供基于HTTP的任务Handler（Bean任务，JobHandler=\"httpJobHandler\"）；业务方只需要提供HTTP链接等相关信息即可，不限制语言、平台；（可参考章节 “原生内置Bean模式任务” ）\n\n### 5.16 任务失败告警\n默认提供邮件失败告警，可扩展短信、钉钉等方式。如果需要新增一种告警方式，只需要新增一个实现 \"com.xxl.job.admin.core.alarm.JobAlarm\" 接口的告警实现即可。可以参考默认提供邮箱告警实现 \"EmailJobAlarm\"。\n\n### 5.17 调度中心Docker镜像构建\n可以通过以下命令快速构建调度中心，并启动运行；\n\n```\n/**\n* build package\n*/ \nmvn clean package\n\n/**\n* build docker image\n*/ \ndocker build -t xuxueli/xxl-job-admin:{指定版本} ./xxl-job-admin\n\n/**\n* 如需自定义 “项目配置文件” 中配置项，比如 mysql 配置，可通过 \"-e PARAMS\" 指定，参数格式: -e PARAMS=\"--key=value --key2=value2\"；\n* （配置项参考文件：/xxl-job/xxl-job-admin/src/main/resources/application.properties）\n* 如需自定义 “JVM内存参数”，可通过 \"-e JAVA_OPTS\" 指定，参数格式: -e JAVA_OPTS=\"-Xmx512m\"\n* 如需自定义 “日志文件目录”，可通过 \"-e LOG_HOME\" 指定，参数格式: -e LOG_HOME=/data/applogs\n*/\ndocker run -d \\\n-e PARAMS=\"--spring.datasource.url=jdbc:mysql://127.0.0.1:3306/xxl_job?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai\" \\\n-p 8080:8080 \\\n-v /tmp:/data/applogs \\\n--name xxl-job-admin \\\nxuxueli/xxl-job-admin:{指定版本}\n```\n\n### 5.20 避免任务重复执行\n调度密集或者耗时任务可能会导致任务阻塞，集群情况下调度组件小概率情况下会重复触发；\n针对上述情况，可以通过结合 \"单机路由策略（如：第一台、一致性哈希）\" + \"阻塞策略（如：单机串行、丢弃后续调度）\" 来规避，最终避免任务重复执行。\n\n### 5.21 命令行任务\n原生提供通用命令行任务Handler（Bean任务，\"CommandJobHandler\"）；业务方只需要提供命令行即可，命令及参数之间通过空格隔开；\n如任务参数 \"ls la\" 或 \"pwd\" 将会执行命令并输出数据；\n\n### 5.22 日志自动清理\nXXL-JOB日志主要包含如下两部分，均支持日志自动清理，说明如下：\n- 调度中心日志表数据：可借助配置项 \"xxl.job.logretentiondays\" 设置日志表数据保存天数，过期日志自动清理；详情可查看上文配置说明；\n- 执行器日志文件数据：可借助配置项 \"xxl.job.executor.logretentiondays\" 设置日志文件数据保存天数，过期日志自动清理；详情可查看上文配置说明；\n\n### 5.23 调度结果丢失处理\n执行器因网络抖动回调失败或宕机等异常情况，会导致任务调度结果丢失。由于调度中心依赖执行器回调来感知调度结果，因此会导致调度日志永远处于 \"运行中\" 状态。\n\n针对该问题，调度中心提供内置组件进行处理，逻辑为：调度记录停留在 \"运行中\" 状态超过10min，且对应执行器心跳注册失败不在线，则将本地调度主动标记失败；\n\n### 5.24 Docker Compose 快速部署    \n支持通过 Docker Compose 方式部署并启动 XXL-JOB，包括：数据库、调度中心、示例执行器。\n\n- 第一步：克隆 XXL-JOB    \n```\ngit clone --branch \"$(curl -s https://api.github.com/repos/xuxueli/xxl-job/releases/latest | jq -r .tag_name)\" https://github.com/xuxueli/xxl-job.git\n```\n\n- 第二步：构建 XXL-JOB    \n```\n// 注意：如下命令需要在项目仓库根目录执行\nmvn clean package -Dmaven.test.skip=true\n```\n\n- 第三步：配置 XXL-JOB    \n```\n// 注意：前往docker目录，自定义 .env 配置；如修改 MYSQL_PATH 配置设置Mysql数据持久化目录；\ncd ./docker\ncat .env\n```\n\n- 第四步：启动 XXL-JOB    \n```\n// 启动 \ndocker compose up -d\n\n// 停止\ndocker compose down\n```\n\n### 5.25 优雅停机   \n针对任务调度场景，优雅停机包括调度中心与执行器两部分：\n- 调度中心优雅停机：调度中心停机时，如果检测到时间轮非空则主动等待等待一段时间，等待调度处理完成；否则立即停机；\n- 执行器优雅停机：执行器停机时，如果检测到存在运行中任务，在停止接收新任务后会主动等待一段时间，等待任务执行完成；否则立即停机；\n\n\n## 六、调度中心/执行器 OpenApi\nXXL-JOB 目标是一种跨平台、跨语言的任务调度规范和协议。\n\n针对Java应用，可以直接通过官方提供的调度中心与执行器，方便快速的接入和使用调度中心，可以参考上文 “快速入门” 章节。\n\n针对非Java应用，可借助 XXL-JOB 的标准 OpenApi（RESTful API） 方便的实现多语言支持。\n\n- 调度中心 RESTful API：\n    - 说明：调度中心提供给执行器使用的API；不局限于官方执行器使用，第三方可使用该API来实现执行器；\n    - API列表：执行器注册、任务结果回调等；\n- 执行器 RESTful API ：\n    - 说明：执行器提供给调度中心使用的API；官方执行器默认已实现，第三方执行器需要实现并对接提供给调度中心；\n    - API列表：任务触发、任务终止、任务日志查询……等；\n\n此处 RESTful API 主要用于非Java语言定制个性化执行器使用，实现跨语言。除此之外，如果有需要通过API操作调度中心，可以个性化扩展 “调度中心 RESTful API” 并使用。\n\n### 6.1 调度中心 RESTful API\n\nAPI服务位置：com.xxl.job.core.openapi.AdminBiz （ com.xxl.job.admin.controller.JobApiController ）\nAPI服务请求参考代码：com.xxl.job.adminbiz.AdminBizTest\n\n#### a、任务回调\n```\n说明：执行器执行完任务后，回调任务结果时使用\n\n------\n\n地址格式：{调度中心根地址}/api/callback\n\nHeader：\n    XXL-JOB-ACCESS-TOKEN : {请求令牌}\n \n请求数据格式如下，放置在 RequestBody 中，JSON格式：\n    [{\n        \"logId\":1,              // 本次调度日志ID\n        \"logDateTim\":0,         // 本次调度日志时间\n        \"handleCode\":200,       // 200 表示任务执行正常，500表示失败\n        \"handleMsg\": null\n        }\n    }]\n\n响应数据格式：\n    {\n      \"code\": 200,      // 200 表示正常、其他失败\n      \"msg\": null      // 错误提示消息\n    }\n```\n\n#### b、执行器注册\n```\n说明：执行器注册时使用，调度中心会实时感知注册成功的执行器并发起任务调度\n\n------\n\n地址格式：{调度中心根地址}/api/registry\n\nHeader：\n    XXL-JOB-ACCESS-TOKEN : {请求令牌}\n \n请求数据格式如下，放置在 RequestBody 中，JSON格式：\n    {\n        \"registryGroup\":\"EXECUTOR\",                     // 固定值\n        \"registryKey\":\"xxl-job-executor-example\",       // 执行器AppName\n        \"registryValue\":\"http://127.0.0.1:9999/\"        // 执行器地址，内置服务跟地址\n    }\n\n响应数据格式：\n    {\n      \"code\": 200,      // 200 表示正常、其他失败\n      \"msg\": null      // 错误提示消息\n    }\n```\n\n#### c、执行器注册摘除\n```\n说明：执行器注册摘除时使用，注册摘除后的执行器不参与任务调度与执行\n\n------\n\n地址格式：{调度中心根地址}/api/registryRemove\n\nHeader：\n    XXL-JOB-ACCESS-TOKEN : {请求令牌}\n \n请求数据格式如下，放置在 RequestBody 中，JSON格式：\n    {\n        \"registryGroup\":\"EXECUTOR\",                     // 固定值\n        \"registryKey\":\"xxl-job-executor-example\",       // 执行器AppName\n        \"registryValue\":\"http://127.0.0.1:9999/\"        // 执行器地址，内置服务跟地址\n    }\n\n响应数据格式：\n    {\n      \"code\": 200,      // 200 表示正常、其他失败\n      \"msg\": null      // 错误提示消息\n    }\n```\n\n### 6.2 执行器 RESTful API\n\nAPI服务位置：com.xxl.job.core.openapi.ExecutorBiz\nAPI服务请求参考代码：com.xxl.job.executorbiz.ExecutorBizTest\n\n#### a、心跳检测\n```\n说明：调度中心检测执行器是否在线时使用\n\n------\n\n地址格式：{执行器内嵌服务根地址}/beat\n\nHeader：\n    XXL-JOB-ACCESS-TOKEN : {请求令牌}\n \n请求数据格式如下，放置在 RequestBody 中，JSON格式：\n\n响应数据格式：\n    {\n      \"code\": 200,      // 200 表示正常、其他失败\n      \"msg\": null       // 错误提示消息\n    }\n```\n\n#### b、忙碌检测\n```\n说明：调度中心检测指定执行器上指定任务是否忙碌（运行中）时使用\n\n------\n\n地址格式：{执行器内嵌服务根地址}/idleBeat\n\nHeader：\n    XXL-JOB-ACCESS-TOKEN : {请求令牌}\n \n请求数据格式如下，放置在 RequestBody 中，JSON格式：\n    {\n        \"jobId\":1       // 任务ID\n    }\n\n响应数据格式：\n    {\n      \"code\": 200,      // 200 表示正常、其他失败\n      \"msg\": null       // 错误提示消息\n    }\n```\n\n#### c、触发任务\n```\n说明：触发任务执行\n\n------\n\n地址格式：{执行器内嵌服务根地址}/run\n\nHeader：\n    XXL-JOB-ACCESS-TOKEN : {请求令牌}\n \n请求数据格式如下，放置在 RequestBody 中，JSON格式：\n    {\n        \"jobId\":1,                                  // 任务ID\n        \"executorHandler\":\"demoJobHandler\",         // 任务标识\n        \"executorParams\":\"demoJobHandler\",          // 任务参数\n        \"executorBlockStrategy\":\"COVER_EARLY\",      // 任务阻塞策略，可选值参考 com.xxl.job.core.constant.ExecutorBlockStrategyEnum\n        \"executorTimeout\":0,                        // 任务超时时间，单位秒，大于零时生效\n        \"logId\":1,                                  // 本次调度日志ID\n        \"logDateTime\":1586629003729,                // 本次调度日志时间\n        \"glueType\":\"BEAN\",                          // 任务模式，可选值参考 com.xxl.job.core.glue.GlueTypeEnum\n        \"glueSource\":\"xxx\",                         // GLUE脚本代码\n        \"glueUpdatetime\":1586629003727,             // GLUE脚本更新时间，用于判定脚本是否变更以及是否需要刷新\n        \"broadcastIndex\":0,                         // 分片参数：当前分片\n        \"broadcastTotal\":0                          // 分片参数：总分片\n    }\n\n响应数据格式：\n    {\n      \"code\": 200,      // 200 表示正常、其他失败\n      \"msg\": null       // 错误提示消息\n    }\n```\n\n#### f、终止任务\n```\n说明：终止任务\n\n------\n\n地址格式：{执行器内嵌服务根地址}/kill\n\nHeader：\n    XXL-JOB-ACCESS-TOKEN : {请求令牌}\n \n请求数据格式如下，放置在 RequestBody 中，JSON格式：\n    {\n        \"jobId\":1       // 任务ID\n    }\n    \n\n响应数据格式：\n    {\n      \"code\": 200,      // 200 表示正常、其他失败\n      \"msg\": null       // 错误提示消息\n    }\n```\n\n#### d、查看执行日志\n```\n说明：查看任务日志，滚动方式加载\n\n------\n\n地址格式：{执行器内嵌服务根地址}/log\n\nHeader：\n    XXL-JOB-ACCESS-TOKEN : {请求令牌}\n \n请求数据格式如下，放置在 RequestBody 中，JSON格式：\n    {\n        \"logDateTim\":0,     // 本次调度日志时间\n        \"logId\":0,          // 本次调度日志ID\n        \"fromLineNum\":0     // 日志开始行号，滚动加载日志\n    }\n\n响应数据格式：\n    {\n        \"code\":200,         // 200 表示正常、其他失败\n        \"msg\": null         // 错误提示消息\n        \"content\":{\n            \"fromLineNum\":0,        // 本次请求，日志开始行数\n            \"toLineNum\":100,        // 本次请求，日志结束行号\n            \"logContent\":\"xxx\",     // 本次请求日志内容\n            \"isEnd\":true            // 日志是否全部加载完\n        }\n    }\n```\n\n\n\n## 七、版本更新日志\n### 7.1 版本 V1.1.x，新特性[2015-12-05]\n**【于V1.1.x版本，XXL-JOB正式应用于我司，内部定制别名为 “Ferrari”，新接入应用推荐使用最新版本】**\n- 1、简单：支持通过Web页面对任务进行CRUD操作，操作简单，一分钟上手；\n- 2、动态：支持动态修改任务状态，动态暂停/恢复任务，即时生效；\n- 3、服务HA：任务信息持久化到mysql中，Job服务天然支持集群，保证服务HA；\n- 4、任务HA：某台Job服务挂掉，任务会平滑分配给其他的某一台存活服务，即使所有服务挂掉，重启时或补偿执行丢失任务；\n- 5、一个任务只会在其中一台服务器上执行；\n- 6、任务串行执行；\n- 7、支持自定义参数；\n- 8、支持远程任务执行终止；\n\n### 7.2 版本 V1.2.x，新特性[2016-01-17]\n- 1、支持任务分组；\n- 2、支持“本地任务”、“远程任务”；\n- 3、底层通讯支持两种方式，Servlet方式 + JETTY方式；\n- 4、支持“任务日志”；\n- 5、支持“串行执行”，并行执行；\n\n  说明：V1.2版本将系统架构按功能拆分为：\n\n  \t- 调度模块（调度中心）：负责管理调度信息，按照调度配置发出调度请求；\n  \t- 执行模块（执行器）：负责接收调度请求并执行任务逻辑；\n  \t- 通讯模块：负责调度模块和任务模块之间的信息通讯；\n  优点：\n\n  \t- 解耦：任务模块提供任务接口，调度模块维护调度信息，业务相互独立；\n  \t- 高扩展性；\n  \t- 稳定性；\n\n### 7.3 版本 V1.3.0，新特性[2016-05-19]\n- 1、遗弃“本地任务”模式，推荐使用“远程任务”，易于系统解耦，任务对应的JobHandler统称为“执行器”；\n- 2、遗弃“servlet”方式底层系统通讯，推荐使用JETTY方式，调度+回调双向通讯，重构通讯逻辑；\n- 3、UI交互优化：左侧菜单展开状态优化，菜单项选中状态优化，任务列表打开表格有压缩优化；\n- 4、【重要】“执行器”细分为：BEAN、GLUE两种开发模式，简介见下文：\n\n  “执行器” 模式简介：\n    - BEAN模式执行器：每个执行器都是Spring的一个Bean实例，XXL-JOB通过注解@JobHandler识别和调度执行器；\n    - GLUE模式执行器：每个执行器对应一段代码，在线Web编辑和维护，动态编译生效，执行器负责加载GLUE代码和执行；\n\n### 7.4 版本 V1.3.1，新特性[2016-05-23]\n- 1、更新项目目录结构：\n    - /xxl-job-admin -------------------- 【调度中心】：负责管理调度信息，按照调度配置发出调度请求；\n    - /xxl-job-core ----------------------- 公共依赖\n    - /xxl-job-executor-example ------ 【执行器】：负责接收调度请求并执行任务逻辑；\n    - /db ---------------------------------- 建表脚本\n    - /doc --------------------------------- 用户手册\n- 2、在新的目录结构上，升级了用户手册；\n- 3、优化了一些交互和UI；\n\n### 7.5 版本 V1.3.2，新特性[2016-05-28]\n- 1、调度逻辑进行事务包裹；\n- 2、执行器异步回调执行日志；\n- 3、【重要】在 “调度中心” 支持HA的基础上，扩展执行器的Failover支持，支持配置多执行期地址；\n\n### 7.6 版本 V1.4.0 新特性[2016-07-24]\n- 1、任务依赖: 通过事件触发方式实现, 任务执行成功并回调时会主动触发一次子任务的调度, 多个子任务用逗号分隔;\n- 2、执行器底层实现代码进行重度重构, 优化底层建表脚本;\n- 3、执行器中任务线程分组逻辑优化: 之前根据执行器JobHandler进行线程分组,当多个任务复用Jobhanlder会导致相互阻塞。现改为根据调度中心任务进行任务线程分组,任务与任务执行相互隔离;\n- 4、执行器调度通讯方案优化, 通过Hex + HC实现建议RPC通讯协议, 优化了通讯参数的维护和解析流程;\n- 5、调度中心, 新建/编辑任务, 界面属性调整:\n    - 5.1、任务新增/编辑界面中去除 \"任务名JobName\"属性 ,该属性改为系统自动生成: 该字段之前主要用于在 \"调度中心\" 唯一标示一个任务, 现实意义不大, 因此计划淡化掉该字段,改为系统生成UUID,从而简化任务新建的操作;\n    - 5.2、任务新增/编辑界面中去除 \"GLUE模式\" 复选框位置调整, 改为贴近\"JobHandler\"输入框右侧;\n    - 5.3、任务新增/编辑界面中去除 \"报警阈值\" 属性;\n    - 5.4、任务新增/编辑界面中去除 \"子任务Key\" 属性, 每个任务全局任务Key可以从任务列表获取, 当本任务执行结束且成功后, 将会根据子任务Key匹配子任务并主动触发一次子任务执行;\n- 6、问题修复:\n    - 6.1、执行器jetty关闭优化,解决一处可能导致jetty无法关闭的问题;\n    - 6.2、执行器任务终止时,执行队列回调优化,解决一处导致任务无法回调的问题；\n    - 6.3、调度中心中列表分页参数优化,解决一处因服务器限制post长度而引起的问题;\n    - 6.4、执行器Jobhandler注解优化,解决一处因事务代理导致的容器无法加载JobHandler的问题;\n    - 6.5、远程调度优化,禁用retry策略,解决一处可能导致重复调用的问题;\n\nTips: 历史版本(V1.3.x)目前已经Release至稳定版本, 进入维护阶段, 地址见分支 [V1.3](https://github.com/xuxueli/xxl-job/tree/v1.3) 。新特性将会在master分支持续更新。\n\n### 7.7 版本 V1.4.1 新特性[2016-09-06]\n- 1、项目成功推送maven中央仓库, 中央仓库地址以及依赖如下:\n    ```\n    <!-- http://repo1.maven.org/maven2/com/xuxueli/xxl-job-core/ -->\n    <dependency>\n        <groupId>com.xuxueli</groupId>\n        <artifactId>xxl-job-core</artifactId>\n        <version>${最新稳定版}</version>\n    </dependency>\n    ```\n- 2、为适配中央仓库规则, 项目groupId从com.xxl改为com.xuxueli。\n- 3、系统版本不在维护在项目跟pom中,各个子模块单独配置版本配置,解决子模块无法单独编译的问题;\n- 4、底层RPC通讯,传输数据的字节长度统计规则优化,可节省50%数据传输量;\n- 5、IJobHandler取消任务返回值,原通过返回值判断执行状态,逻辑改为:默认任务执行成功,仅在捕获异常时认定任务执行失败。\n- 6、系统公共弹框功能,插件化;\n- 7、底层表结构,表明统一大写;\n- 8、调度中心,异常处理器JSON响应的ContentType修改,修复浏览器不识别的问题;\n\n### 7.8 版本 V1.4.2 新特性[2016-09-29]\n- 1、推送新版本 V1.4.2 至中央仓库, 大版本 V1.4 进入维护阶段;\n- 2、任务新增时,任务列表偏移问题修复;\n- 3、修复一处因bootstrap不支持模态框重叠而导致的样式错乱的问题, 在任务编辑时会出现该问题;\n- 4、调度超时和Handler匹配不到时,调度状态优化;\n- 5、因catch异常,导致任务不可终止的问题,给出解决方案, 见文档;\n\n### 7.9 版本 V1.5.0 特性[2016-11-13]\n- 1、任务注册: 执行器会周期性自动注册任务, 调度中心将会自动发现注册的任务并触发执行。\n- 2、\"执行器\" 新增参数 \"AppName\" : 是每个执行器集群的唯一标示AppName, 并周期性以AppName为对象进行自动注册。\n- 3、调度中心新增栏目 \"执行器管理\" : 管理在线的执行器, 通过属性AppName自动发现注册的执行器。只有被管理的执行器才允许被使用;\n- 4、\"任务组\"属性改为\"执行器\": 每个任务需要绑定指定的执行器, 调度地址通过绑定的执行器获取;\n- 5、抛弃\"任务机器\"属性: 通过任务绑定的执行器, 自动发现注册的远程执行器地址并触发调度请求。\n- 6、\"公共依赖\"中新增DBGlueLoader,基于原生jdbc实现GLUE源码的加载器,减少第三方依赖(mybatis,spring-orm等);精简和优化执行器测配置(针对GLUE任务),降低上手难度;\n- 7、表结构调整,底层重构优化;\n- 8、\"调度中心\"自动注册和发现,failover: 调度中心周期性自动注册, 任务回调时可以感知在线的所有调度中心地址, 通过failover的方式进行任务回调,避免回调单点风险。\n\n### 7.10 版本 V1.5.1 特性[2016-11-13]\n- 1、底层代码重构和逻辑优化，POM清理以及CleanCode；\n- 2、Servlet/JSP Spec设定为3.0/2.2\n- 3、Spring升级至3.2.17.RELEASE版本；\n- 4、Jetty升级版本至8.2.0.v20160908；\n- 5、已推送V1.5.0和V1.5.1至Maven中央仓库；\n\n### 7.11 版本 V1.5.2 特性[2017-02-28]\n- 1、IP工具类获取IP逻辑优化，IP静态缓存；\n- 2、执行器、调度中心，均支持自定义注册IP地址；解决机器多网卡时错误网卡注册的情况；\n- 3、任务跨天执行时生成多份日志文件的问题修复；\n- 4、底层日志底层日志调整，非敏感日志level调整为debug；\n- 5、升级数据库连接池c3p0版本；\n- 6、执行器log4j配置优化，去除无效属性；\n- 7、底层代码重构和逻辑优化以及CleanCode；\n- 8、GLUE依赖注入逻辑优化，支持别名注入；\n\n### 7.12 版本 V1.6.0 特性[2017-03-13]\n- 1、通讯方案升级，原基于HEX的通讯模型调整为基于HTTP的B-RPC的通讯模型；\n- 2、执行器支持手动设置执行地址列表，提供开关切换使用注册地址还是手动设置的地址；\n- 3、执行器路由规则：第一个、最后一个、轮询、随机、一致性HASH、最不经常使用、最近最久未使用、故障转移；\n- 4、规范线程模型统一，统一线程销毁方案(通过listener或stop方法，容器销毁时销毁线程；Daemon方式有时不太理想)；\n- 5、规范系统配置数据，通过配置文件统一管理；\n- 6、CleanCode，清理无效的历史参数；\n- 7、底层扩展数据结构以及相关表结构调整；\n- 8、新建任务默认为非运行状态；\n- 9、GLUE模式任务实例更新逻辑优化，原根据超时时间更新改为根据版本号更新，源码变动版本号加一；\n\n### 7.13 版本 V1.6.1 特性[2017-03-25]\n- 1、Rolling日志；\n- 2、WebIDE交互重构；\n- 3、通讯增强校验，有效过滤非正常请求；\n- 4、权限增强校验，采用动态登录TOKEN（推荐接入内部SSO）；\n- 5、数据库配置优化，解决乱码问题；\n\n### 7.14 版本 V1.6.2 特性[2017-04-25]\n- 1、运行报表：支持实时查看运行数据，如任务数量、调度次数、执行器数量等；以及调度报表，如调度日期分布图，调度成功分布图等；\n- 2、JobHandler支持设置任务返回值，在任务逻辑中可以方便的控制任务执行结果；\n- 3、资源路径包含空格或中文时资源文件无法加载时，无法准确查看异常信息的问题处理。\n- 4、路由策越优化：循环和LFU路由策略计数器自增无上限问题和首次路由压力集中在首台机器的问题修复；\n\n### 7.15 版本 V1.7.0 特性[2017-05-02]\n- 1、脚本任务：支持以GLUE模式开发和运行脚本任务，包括Shell、Python和Groovy等类型脚本;\n- 2、新增spring-boot类型执行器example项目；\n- 3、升级jetty版本至9.2；\n- 4、任务运行日志移除log4j组件依赖，改为底层自主实现，从而取消了对日志组件的依赖限制；\n- 5、执行器移除GlueLoader依赖，改为推送方式实现，从而GLUE源码加载不再依赖JDBC；\n- 6、登录拦截Redirect时获取项目名，解决非根据目录发布时跳转404问题；\n\n### 7.16 版本 V1.7.1 特性[2017-05-08]\n- 1、运行日志读写编码统一为UTF-8，解决windows环境下日志乱码问题；\n- 2、通讯超时时间限定为10s，避免异常情况下调度线程占用；\n- 3、执行器，server启动、销毁和注册逻辑调整；\n- 4、JettyServer关闭逻辑优化，修复执行器无法正常关闭导致端口占用和频繁打印c3p0日志的问题；\n- 5、JobHandler中开启子线程时，支持子线程输出执行日志并通过Rolling查看。\n- 6、任务日志清理功能；\n- 7、弹框组件统一替换为layer；\n- 8、升级quartz版本至2.3.0；\n\n### 7.17 版本 V1.7.2 特性[2017-05-17]\n- 1、阻塞处理策略：调度过于密集执行器来不及处理时的处理策略，策略包括：单机串行（默认）、丢弃后续调度、覆盖之前调度；\n- 2、失败处理策略；调度失败时的处理策略，策略包括：失败告警（默认）、失败重试；\n- 3、通讯时间戳超时时间调整为180s；\n- 4、执行器与数据库彻底解耦，但是执行器需要配置调度中心集群地址。调度中心提供API供执行器回调和心跳注册服务，取消调度中心内部jetty，心跳周期调整为30s，心跳失效为三倍心跳；\n- 5、执行参数编辑时丢失问题修复；\n- 6、新增任务测试Demo，方便在开发时进行任务逻辑测试；\n\n### 7.18 版本 V1.8.0 特性[2017-07-17]\n- 1、任务Cron更新逻辑优化，改为rescheduleJob，同时防止cron重复设置；\n- 2、API回调服务失败状态码优化，方便问题排查；\n- 3、XxlJobLogger的日志多参数支持；\n- 4、路由策略新增 \"忙碌转移\" 模式：按照顺序依次进行空闲检测，第一个空闲检测成功的机器选定为目标执行器并发起调度；\n- 5、路由策略代码重构；\n- 6、执行器重复注册问题修复；\n- 7、任务线程轮空30次后自动销毁，降低低频任务的无效线程消耗。\n- 8、执行器任务执行结果批量回调，降低回调频率提升执行器性能；\n- 9、springboot版本执行器，取消XML配置，改为类配置方式；\n- 10、执行日志，支持根据运行 \"状态\" 筛选日志；\n- 11、调度中心任务注册检测逻辑优化；\n\n### 7.19 版本 V1.8.1 特性[2017-07-30]\n- 1、分片广播任务：执行器集群部署时，任务路由策略选择\"分片广播\"情况下，一次任务调度将会广播触发集群中所有执行器执行一次任务，可根据分片参数处理分片任务；\n- 2、动态分片：分片广播任务以执行器为维度进行分片，支持动态扩容执行器集群从而动态增加分片数量，协同进行业务处理；在进行大数据量业务操作时可显著提升任务处理能力和速度。\n- 3、执行器JobHandler禁止命名冲突；\n- 4、执行器集群地址列表进行自然排序；\n- 5、调度中心，DAO层代码精简优化并且新增测试用例覆盖；\n- 6、调度中心API服务改为自研RPC形式，统一底层通讯模型；\n- 7、新增调度中心API服务测试Demo，方便在调度中心API扩展和测试；\n- 8、任务列表页交互优化，更换执行器分组时自动刷新任务列表，新建任务时默认定位在当前执行器位置；\n- 9、访问令牌（accessToken）：为提升系统安全性，调度中心和执行器进行安全性校验，双方AccessToken匹配才允许通讯；\n- 10、springboot版本执行器，升级至1.5.6.RELEASE版本；\n- 11、统一maven依赖版本管理；\n\n### 7.20 版本 V1.8.2 特性[2017-09-04]\n- 1、项目主页搭建：提供中英文文档：https://www.xuxueli.com/xxl-job\n- 2、JFinal执行器Sample示例项目；\n- 3、事件触发：除了\"Cron方式\"和\"任务依赖方式\"触发任务执行之外，支持基于事件的触发任务方式。调度中心提供触发任务单次执行的API服务，可根据业务事件灵活触发。\n- 4、执行器摘除：执行器销毁时，主动通知调度中心并摘除对应执行器节点，提高执行器状态感知的时效性。\n- 5、执行器手动设置IP时将会绑定Host；\n- 6、规范项目目录，方便扩展多执行器；\n- 7、解决执行器回调URL不支持配置HTTPS时问题；\n- 8、执行器回调线程销毁前, 批量回调队列中数据，防止任务结果丢失；\n- 9、调度中心任务监控线程销毁时，批量对失败任务告警，防止告警信息丢失；\n- 10、任务日志文件路径时间戳格式化时SimpleDateFormat并发问题解决；\n\n### 7.21 版本 V1.9.0 特性[2017-12-29]\n- 1、新增Nutz执行器Sample示例项目；\n- 2、新增任务运行模式 \"GLUE模式(NodeJS) \"，支持NodeJS脚本任务；\n- 3、脚本任务Shell、Python和Nodejs等支持获取分片参数；\n- 4、失败重试，完整支持：调度中心调度失败且启用\"失败重试\"策略时，将会自动重试一次；执行器执行失败且回调失败重试状态（新增失败重试状态返回值）时，也将会自动重试一次；\n- 5、失败告警策略扩展：默认提供邮件失败告警，可扩展短信等，扩展代码位置为 \"JobFailMonitorHelper.failAlarm\"；\n- 6、执行器端口支持自动生成(小于等于0时)，避免端口定义冲突；\n- 7、调度报表优化，支持时间区间筛选；\n- 8、Log组件支持输出异常栈信息，底层实现优化；\n- 9、告警邮件样式优化，调整为表格形式，邮件组件调整为commons-email简化邮件操作；\n- 10、项目依赖全量升级至较新稳定版本，如spring、jackson等等；\n- 11、任务日志，记录发起调度的机器信息；\n- 12、交互优化，如登录注销；\n- 13、任务Cron长度扩展支持至128位，支持负责类型Cron设置；\n- 14、执行器地址录入交互优化，地址长度扩展支持至512位，支持大规模执行器集群配置；\n- 15、任务参数“IJobHandler.execute”入参改为“String params”，增强入参通用性。\n- 16、IJobHandler提供init/destroy方法，支持在相应任务线程初始化和销毁时进行附加操作；\n- 17、任务注解调整为 “@JobHandler”，与任务抽象接口统一；\n- 18、修复任务监控线程被耗时任务阻塞的问题；\n- 19、修复任务监控线程无法监控任务触发和执行状态均未0的问题；\n- 20、执行器动态代理对象，拦截非业务方法的执行；\n- 21、修复JobThread捕获Error错误不更新JobLog的问题；\n- 22、修复任务列表界面左侧菜单合并时样式错乱问题；\n- 23、调度中心项目日志配置改为xml文件格式；\n- 24、Log地址格式兼容，支持非\"/\"结尾路径配置；\n- 25、底层系统日志级别规范调整，清理遗留代码；\n- 26、建表SQL优化，支持同步创建制定编码的库和表；\n- 27、系统安全性优化，登录Token写Cookie时进行MD5加密，同时Cookie启用HttpOnly；\n- 28、新增\"任务ID\"属性，移除\"JobKey\"属性，前者承担所有功能，方便后续增强任务依赖功能。\n- 29、任务循环依赖问题修复，避免子任务与父任务重复导致的调度死循环；\n- 30、任务列表新增筛选条件 \"任务描述\"，快速检索任务；\n- 31、执行器Log文件定期清理功能：执行器新增配置项（\"xxl.job.executor.logretentiondays\"）日志保存天数，日志文件过期自动删除。\n\n### 7.22 版本 V1.9.1 特性[2018-02-22]\n- 1、国际化：调度中心实现国际化，支持中文、英文两种语言，默认为中文。\n- 2、调度报表新增\"运行中\"中状态项；\n- 3、调度报表优化，报表SQL调优并且新增LocalCache缓存（缓存时间60s），提高大数据量下报表加载速度；\n- 4、修复打包部署时资源文件乱码问题；\n- 5、修复新版本chrome滚动到顶部失效问题；\n- 6、调度中心配置加载优化，取消对配置文件名的强依赖，支持加载磁盘配置；\n- 7、修复脚本任务Log文件未正常close的问题；\n- 8、项目依赖全量升级至较新稳定版本，如spring、jackson等等；\n\n### 7.23 版本 V1.9.2 特性[2018-10-05]\n- 1、任务超时控制：新增任务属性 \"任务超时时间\"，并支持自定义，任务运行超时将会主动中断任务；\n- 2、任务失败重试次数：新增任务属性 \"失败重试次数\"，并支持自定义，当任务失败时将会按照预设的失败重试次数主动进行重试；同时收敛废弃其他失败重试策略，如调度失败、执行失败、状态码失败等；\n- 3、新增任务运行模式 \"GLUE模式(PHP) \"，支持php脚本任务；\n- 4、新增任务运行模式 \"GLUE模式(PowerShell) \"，支持PowerShell脚本任务；\n- 5、调度全异步处理：任务触发之后，推送到调度队列，多线程并发处理调度请求，提高任务调度速率的同时，避免因网络问题导致quartz调度线程阻塞的问题；\n- 6、执行器任务结果落盘优化：执行器回调失败时将任务结果写磁盘，待重启或网络恢复时重试回调任务结果，防止任务执行结果丢失；\n- 7、任务日志查询速度大幅提升：百万级别数据量搜索速度提升1000倍；\n- 8、调度中心提供API服务，支持通过API服务对任务进行查询、新增、更新、启停等操作；\n- 9、底层自研Log组件参数占位符改为\"{}\"，并修复打印有参日志时参数不匹配导致报错的问题；\n- 10、任务回调结果优化，支持展示在Rolling log中，方便问题排查；\n- 11、底层LocalCache组件兼容性优化，支持jdk9、jdk10及以上版本编译部署；\n- 12、告警邮件固定使用 UTF-8 编码格式，修复由机器编码导致的邮件乱码问题；\n- 13、告警邮件中展示失败告警信息；\n- 14、告警邮箱支持SSL配置；\n- 15、Window机器下File.separator不兼容问题修复；\n- 16、脚本任务异常Log输出优化；\n- 17、任务线程停止变量修饰符优化；\n- 18、脚本任务Log文件流关闭优化；\n- 19、任务报表成功、失败和进行中统计问题修复；\n- 20、核心依赖Core内部国际化处理；\n- 21、默认Quartz线程数调整为50；\n- 22、新增左侧菜单\"运行报表\"；\n- 23、执行器手动设置IP时取消绑定Host的操作，该IP仅供执行器注册使用；修复指定外网IP时无法绑定执行器Host的问题；\n- 24、取消父子任务不可重复的限制，支持循环任务触发等特殊场景；\n- 25、任务调度备注中标注任务触发类型，如Cron触发、父任务触发、API触发等等，方便排查调度日志；\n- 26、底层日志组件SimpleDateFormat线程安全问题修复；\n- 27、执行器通讯线程优化，corePoolSize从256降低至32；\n- 28、任务日志表状态字段类型优化；\n- 29、GLUE脚本文件自动清理功能，及时清理过期脚本文件；\n- 30、执行器注册方式切换优化，切换自动注册时主动同步在线机器，避免执行器为空的问题；\n- 31、跨平台：除了提供Java、Python、PHP等十来种任务模式之外，新增提供基于HTTP的任务模式；\n- 32、底层RPC序列化协议调整为hessian2；\n- 33、修复表字段 “t.order”与数据库关键字冲突查询失败的问题，\n- 34、任务属性枚举 \"任务模式、阻塞策略\" 国际化优化；\n- 35、分片任务失败重试优化，仅重试当前失败的分片；\n- 36、任务触发时支持动态传参，调度中心与API服务均提供提供动态参数功能；\n- 37、任务执行日志、调度日志字段类型调整，改为text类型并取消字数限制；\n- 38、GLUE任务脚本字段类型调整，改为mediumtext类型，提高GLUE长度上限；\n- 39、任务监控线程Log输出优化，运行中任务的监控Log改为debug级别，减少非核心日志量；\n- 40、项目依赖全量升级至较新稳定版本，如spring、Jackson、groovy等等；\n- 41、docker支持：调度中心提供 Dockerfile 方便快速构建docker镜像；\n\n### 7.24 版本 V2.0.0 Release Notes[2018-11-04]\n- 1、调度中心迁移到 springboot；\n- 2、底层通讯组件迁移至 xxl-rpc；\n- 3、容器化：提供官方docker镜像，并实时更新推送dockerhub（docker pull xuxueli/xxl-job-admin），进一步实现产品开箱即用；\n- 4、新增无框架执行器Sample示例项目 \"xxl-job-executor-sample-frameless\"。不依赖第三方框架，只需main方法即可启动运行执行器；\n- 5、命令行任务：原生提供通用命令行任务Handler（Bean任务，\"CommandJobHandler\"）；业务方只需要提供命令行即可；\n- 6、任务状态优化，仅运行状态\"NORMAL\"任务关联至quartz，降低quartz底层数据存储与调度压力；\n- 7、任务状态规范：新增任务默认停止状态，任务更新时保持任务状态不变；\n- 8、IP获取逻辑优化，优先遍历网卡来获取可用IP；\n- 9、任务新增的API服务接口返回任务ID，方便调用方使用；\n- 10、组件化优化，移除对 spring 的依赖：非spring应用选用 \"XxlJobExecutor\" 、spring应用选用 \"XxlJobSpringExecutor\" 作为执行器组件；\n- 11、任务RollingLog展示逻辑优化，修复超时任务无法查看的问题；\n- 12、多项UI组件升级到最新版本，如：CodeMirror、Echarts、Jquery 等；\n- 13、项目依赖升级 groovy 至较新稳定版本；pom清理；\n- 14、子任务失败重试重试逻辑优化，子任务失败时将会按照其预设的失败重试次数主动进行重试\n\n### 7.25 版本 v2.0.1 Release Notes[2018-11-09]\n- 1、左侧菜单折叠动画问题修复；\n- 2、调度报表日期分布图默认值统一；\n- 3、freemarker对数字默认加千分位问题修复，解决日志ID被分隔导致查看日志失败问题；\n- 4、底层通讯组件升级，修复通讯异常时无效等待的问题；\n- 5、执行器启动之后jetty停止的问题修复；\n\n### 7.26 版本 v2.0.2 Release Notes[2019-04-20]\n- 1、底层通讯方案优化：升级较新版本xxl-rpc，由\"JETTY\"方案调整为\"NETTY_HTTP\"方案，执行器内嵌netty-http-server提供服务，调度中心复用容器端口提供服务；\n- 2、任务告警逻辑调整，改为通过扫描失败日志方式触发。一方面精确扫描失败任务，降低扫描范围；另一方面取消内存队列，降低线程内存消耗；\n- 3、Quartz触发线程池废弃并替换为 \"XxlJobThreadPool\"，降低线程切换、内存占用带来的消耗，提高调度性能；\n- 4、调度线程池隔离，拆分为\"Fast\"和\"Slow\"两个线程池，1分钟窗口期内任务耗时达500ms超过10次，该窗口期内判定为慢任务，慢任务自动降级进入\"Slow\"线程池，避免耗尽调度线程，提高系统稳定性；\n- 5、执行器热部署时JobHandler重新初始化，修复由此导致的 \"jobhandler naming conflicts.\" 问题；\n- 6、新增Class的加载缓存，解决频繁加载Class会使jvm的方法区空间不足导致OOM的问题；\n- 7、任务支持更换绑定执行器，方便任务分组转移和管理；\n- 8、调度中心告警邮件发送组件改为 “spring-boot-starter-mail”；\n- 9、记住密码功能优化，选中时永久记住；非选中时关闭浏览器即登出；\n- 10、项目依赖升级至较新稳定版本，如quartz、spring、jackson、groovy、xxl-rpc等等；\n- 11、精简项目，取消第三方依赖，如 commons-collections4、commons-lang3 ;\n- 12、执行器回调日志落盘方案复用RPC序列化方案，并移除Jackson依赖；\n- 13、底层Log调优，应用正常终止取消异常栈信息打印；\n- 14、交互优化，尽量避免新开页面窗口；仅WebIDE支持新开页，并提供窗口快速关闭按钮；任务启、停、删除、触发等轻操作提示改为toast方式，\n- 15、任务暂停、删除优化，避免quartz delete不完整导致任务脏数据；\n- 16、任务回调、心跳注册成功日志优化，非核心常规日志调整为debug级别，降低冗余日志输出；\n- 17、调整首页报表默认区间为本周，避免日志量太大查询缓慢；\n- 18、LRU路由更新不及时问题修复；\n- 19、任务失败告警邮件发送逻辑优化；\n- 20、调度日志排序逻辑调整为按照调度时间倒序，兼容TIDB等主键不连续日志存储组件；\n- 21、执行器优雅停机优化；\n- 22、连接池配置优化，增强连接有效性验证；\n- 23、JobHandler#msg长度限制，修复异常情况下日志超长导致内存溢出的问题；\n- 24、升级xxl-rpc至较新版本，修复springboot 2.x版本兼容性问题；\n\n### 7.27 版本 v2.1.0 Release Notes[2019-07-07]\n- 1、自研调度组件，移除quartz依赖：一方面是为了精简系统降低冗余依赖，另一方面是为了提供系统的可控度与稳定性；\n    - 触发：单节点周期性触发，运行事件如delayqueue；\n    - 调度：集群竞争，负载方式协同处理，锁竞争-更新触发信息-推送时间轮-锁释放-锁竞争；\n- 2、底层表结构重构：移除11张quartz相关表，并对现有表结构优化梳理；\n- 3、任务日志主键调整为long数据类型，防止海量日志情况下数据溢出；\n- 4、底层线程模型重构：移除Quartz线程池，降低系统线程与内存开销；\n- 5、用户管理：支持在线管理系统用户，存在管理员、普通用户两种角色；\n- 6、权限管理：执行器维度进行权限控制，管理员拥有全量权限，普通用户需要分配执行器权限后才允许相关操作；\n- 7、调度线程池参数调优；\n- 8、注册表索引优化，缓解锁表问题；\n- 9、新增Jboot执行器Sample示例项目；\n- 10、任务列表优化，支持根据 \"任务状态\"、\"负责人\" 属性筛选任务；\n- 11、任务日志列表交互优化，操作按钮合并为分割按钮；\n- 12、项目依赖升级至较新稳定版本，如spring、springboot、groovy、xxl-rpc等等；并清理冗余POM；\n- 13、升级xxl-rpc至较新版本，修复代理服务初始化时远程服务不可用导致长连冗余创建的问题;\n- 14、首页调度报表的日期排序在TIDB下乱序问题修复；\n- 15、调度中心与执行器双向通讯超时时间调整为3s；\n- 16、调度组件销毁流程优化，先停止调度线程，然后等待时间轮内存量任务处理完成，最终销毁时间轮线程；\n- 17、执行器回调线程优化，回调地址为空时销毁问题修复；\n- 18、HttpJobHandler优化，响应数据指定UTF-8格式，避免中文乱码；\n- 19、代码优化，ConcurrentHashMap变量类型改为ConcurrentMap，避免因不同版本实现不同导致的兼容性问题；\n\n### 7.28 版本 v2.1.1 Release Notes[2019-11-24]\n- 1、 调度中心日志自动清理功能（至此，调度中心/执行器均支持日志自动清理，过期天数均默认设置为30天）：调度中心新增配置项（\"xxl.job.logretentiondays\"）日志保存天数，过期日志自动清理；解决海量日志情况下日志表慢SQL问题；限制大于等于7时生效，否则关闭清理功能，默认为30；\n- 2、 调度报表优化：新增日志报表的存储表，三天内的任务日志会以每分钟一次的频率异步同步至报表中；任务报表仅读取报表数据，极大提升加载速度；\n- 3、 Cron在线生成工具：任务新增、编辑框通过组件在线生成Cron表达式；\n- 4、 Cron下次执行时间查询：支持通过界面在线查看后续连续5次执行时间；\n- 5、 调度中心新增应用健康检查功能，借助“spring-boot-starter-actuator”，相对地址 “/actuator/health”；\n- 6、 DB脚本默认编码改为utf8mb4，修复字符乱码问题(建议Mysql版本5.7+)；\n- 7、 调度中心任务平均分配，触发组件每次获取与线程池数量相关数量的任务，避免大量任务集中在单个调度中心集群节点；\n- 8、 任务触发组件优化，预加载频率正常1s一次，当预加载轮空时主动休眠一个加载周期，动态降低加载频率从而降低DB压力；\n- 9、 调度组件优化：针对永远不会触发的Cron禁止配置和启动；任务Cron最后一次触发后再也不会触发时，比如一次性任务，主动停止相关任务；\n- 10、DB重连优化，修复DB宕机重连后任务调度停止的问题，重连后自动加入调度集群触发任务调度；\n- 11、注册监控线程优化，降低死锁几率；\n- 12、调度中心日志删除优化，改为分页获取ID并根据ID删除的方式，避免批量删除海量日志导致死锁问题；\n- 13、任务重试时参数丢失的问题修复；\n- 14、调度中心移除SQL中的 \"now()\" 函数；集群部署时不再依赖DB时钟，仅需要保证调度中心应用节点时钟一致即可；\n- 15、任务触发组件加载顺序调整，避免小概率情况下组件随机加载顺序导致的I18N的NPE问题;\n- 16、JobThread自销毁优化，避免并发触发导致triggerQueue中任务丢失问题；\n- 17、调度中心密码限制18位，修复修改密码超过18位无法登录的问题；\n- 18、任务告警组件分页参数无效问题修复；\n- 19、升级xxl-rpc版本：服务端线程优化，降低线程内存开销；IpUtil优化：增加连通性校，过滤明确非法的网卡；\n- 20、调度中心回调API服务改为restful方式；\n- 21、UI优化，任务列表和日志列表数据表格宽度比例调整，避免数据换行提升体验；\n- 22、登录界面取消默认填写的登录账号密码；\n- 23、执行器表属性调整，\"顺序\" 属性调整为整型，解决执行器数据较多时无法正确排序的问题；\n- 24、任务列表交互优化，支持查看任务所属执行器的注册节点；\n- 25、项目依赖升级至较新稳定版本，如spring、spring-boot、mybatis、slf4j、groovy等等；\n- 26、日志组件优化：调度中心支持控制每次请求最大加载行数，日志量太大时分批请求，避免单次加载日志量太大阻塞页面；\n\n### 7.29 版本 v2.1.2 Release Notes[2019-12-12]\n- 1、方法任务支持：由原来基于JobHandler类任务开发方式，优化为支持基于方法的任务开发方式；因此，可以支持单个类中开发多个任务方法，进行类复用\n```\n@XxlJob(\"demoJobHandler\")\npublic ReturnT<String> execute(String param) {\n    XxlJobLogger.log(\"hello world\");\n    return ReturnT.ofSuccess();\n}\n```\n- 2、移除commons-exec，采用原生方式实现，降低第三方依赖；\n- 3、执行器回调乱码问题修复；\n- 4、调度中心dispatcher servlet加载顺序优化；\n- 5、执行器回调地址https兼容支持；\n- 6、多个项目依赖升级至较新稳定版本；\n- 注意：最新版本 \"XxlJobSpringExecutor\" 逻辑有调整，历史项目中该组件的配置方式请参考Sample示例项目进行调整，尤其注意需要移除组件的init和destroy方法；\n\n### 7.30 版本 v2.2.0 Release Notes[2020-04-14]\n- 1、RESTful API：调度中心与执行器提供语言无关的 RESTful API 服务，第三方任意语言可据此对接调度中心或者实现执行器。\n- 2、任务复制功能：点击复制是弹出新建任务弹框，并初始化被复制任务信息；\n- 3、任务手动执行一次的时候，支持指定本次执行的机器地址，为空则从执行器获取；\n- 4、任务结果丢失处理：调度记录停留在 \"运行中\" 状态超过10min，且对应执行器心跳注册失败不在线，则将本地调度主动标记失败；\n- 5、调度中心升级springboot2.x；因此，系统要求JDK8+；\n- 6、XxlJob注解扫描方式优化，支持查找父类以及接口和基于类代理等常见情况；修复任务为空时小概率NPE问题；\n- 7、移除旧类注解JobHandler，推荐使用基于方法注解 \"@XxlJob\" 的方式进行任务开发；(如需保留类注解JobHandler使用方式，可以参考旧版逻辑定制开发);\n- 8、任务告警组件模块化：如果需要新增一种告警方式，只需要新增一个实现 \"com.xxl.job.admin.core.alarm.JobAlarm\" 接口的告警实现即可，更加灵活、方便定制；\n- 9、调度中心国际化完善：新增 \"中文繁体\" 支持。默认为 \"zh_CN\"/中文简体, 可选范围为 \"zh_CN\"/中文简体, \"zh_TC\"/中文繁体 and \"en\"/英文；\n- 10、执行器注册逻辑优化：新增配置项 ”注册地址 / xxl.job.executor.address“，优先使用该配置作为注册地址，为空时使用内嵌服务 ”IP:PORT“ 作为注册地址。从而更灵活的支持容器类型执行器动态IP和动态映射端口问题。\n- 11、默认数据库连接池调整为hikari，移除tomcat-jdbc依赖；\n- 12、多个项目依赖升级至较新稳定版本，如mybatis、groovy和mysql驱动等；\n- 13、执行器优雅停机优化，修复任务线程中断未join导致回调丢失的问题；\n- 14、一致性哈希路由策略优化：默认虚拟节点数量调整为100，提高路由的均衡性；\n- 15、通用HTTP任务Handler（httpJobHandler）优化，扩展自定义参数信息，示例参数如下；\n```\nurl: http://www.xxx.com\nmethod: get 或 post\ndata: post-data\n```\n- 16、SQL脚本编码默认utf8mb4执行，避免小概率下容器环境中乱码问题；\n- 17、Web IDE交互问题修复：输入源码备注之后按回车跳转error问题处理；\n- 18、执行器初始化逻辑优化：修复懒加载的Bean被提前初始化问题；\n- 19、执行器注册默认值优化；\n- 20、修复bootstrap.min.css.map 404问题；\n- 21、执行器UI交互优化,移除冗余order属性；\n- 22、执行备注消息长度限制，修复数据超长无法存储导致导致回调失败的问题；\n注意：XxlJobSpringExecutor组件个别字段调整：“appName” 调整为 “appname” ，升级时该组件时需要注意；\n\n### 7.31 版本 v2.3.0 Release Notes[2021-02-09]\n- 1、【新增】调度过期策略：调度中心错过调度时间的补偿处理策略，包括：忽略、立即补偿触发一次等；\n- 2、【新增】触发策略：除了常规Cron、API、父子任务触发方式外，新增提供 \"固定间隔触发、（固定延时触发，实验中）\" 新触发方式；\n- 3、【新增】新增任务辅助工具 \"XxlJobHelper\"：提供统一任务辅助能力，包括：任务上下文信息维护获取（任务参数、任务ID、分片参数）、日志输出、任务结果设置……等；\n    - 3.1、\"ShardingUtil\" 组件废弃：改用 \"XxlJobHelper.getShardIndex()/getShardTotal();\" 获取分片参数；\n    - 3.2、\"XxlJobLogger\" 组件废弃：改用 \"XxlJobHelper.log\" 进行日志输出；\n- 4、【优化】任务核心类 \"IJobHandler\" 的 \"execute\" 方法取消出入参设计。改为通过 \"XxlJobHelper.getJobParam\" 获取任务参数并替代方法入参，通过 \"XxlJobHelper.handleSuccess/handleFail\" 设置任务结果并替代方法出参，示例代码如下；\n```\n@XxlJob(\"demoJobHandler\")\npublic void execute() {\n  String param = XxlJobHelper.getJobParam();    // 获取参数\n  XxlJobHelper.handleSuccess();                 // 设置任务结果\n}\n``` \n- 5、【优化】Cron编辑器增强：Cron编辑器修改cron时可实时查看最近运行时间;\n- 6、【优化】执行器示例项目规范整理；\n- 7、【优化】任务调度生命周期重构：调度（schedule）、触发(trigger)、执行（handle）、回调(callback)、结束（complete）；\n- 8、【优化】执行器注册组件优化：注册逻辑调整为异步方式，提高注册性能；\n- 9、【优化】执行器鉴权校验：执行器启动时主动校验accessToken，为空则主动Warn告警；（已规划安全强化：AccessToken动态生成、动态启停等）\n- 10、【优化】邮箱告警配置优化：将\"spring.mail.from\"与\"spring.mail.username\"属性拆分开，更加灵活的支持一些无密码邮箱服务；\n- 11、【优化】多个项目依赖升级至较新稳定版本，如netty、groovy、spring、springboot、mybatis等；\n- 12、【优化】UI组件常规升级，提升组件稳定性；\n- 13、【优化】调度中心页面交互优化：用户管理模块密码列取消；多处表达autocomplete取消；执行器管理模块XSS拦截校验等；\n- 14、【优化】调度中心任务状态探测慢SQL问题优化；\n- 15、【修复】GLUE-Java模式任务，init/destroy无法执行问题修复；\n- 16、【修复】Cron编辑器问题修复：修复小概率情况下cron单个字段修改时导致其他字段被重置问题；\n- 17、【修复】通用HTTP任务Handler（httpJobHandler）优化：修复 \"setDoOutput(true)\" 导致任务请求GetMethod失效问题；\n- 18、【修复】执行器Commandhandler示例任务优化，修复极端情况下脚本进程挂起问题；\n- 19、【修复】调度通讯组件优化，修复RestFul方式调用 DotNet 版本执行器时心跳检测失败问题；\n- 20、【修复】调度中心远程执行日志查询乱码问题修复；\n- 21、【修复】调度中心组件加载顺序优化，修复极端情况下调度组件初始慢导致的调度失败问题；\n- 22、【修复】执行器注册线程优化，修复极端情况下初始化失败时导致NPE问题；\n- 23、【修复】调度线程连接池优化，修复连接有效性校验超时问题；\n- 24、【修复】执行器注册表字段优化，解决执行器注册节点过多导致注册信息存储和更新失败的问题；\n- 25、【修复】轮训路由策略优化，修复小概率下并发问题；\n- 26、【修复】页面redirect跳转后https变为http问题修复；\n- 27、【修复】执行器日志清理优化，修复小概率下日志文件为空导致清理异常问题；\n\n### 7.32 版本 v2.3.1 Release Notes[2022-05-21]\n- 1、【修复】修复风险漏洞，升级问题低版本项目依赖：CVE-2021-2471、CVE-2022-22965等。\n- 2、【修复】修复故障告警逻辑，邮箱校验逻辑下放至EmailJobAlarm中，避免对其他告警方式的干扰。\n- 3、【优化】调度通讯默认启用accessToken，提升系统安全性（建议生产环境自定义accessToken）。\n- 4、【优化】合并多项PR，项目代码结构、健壮性优化：PR-2833、PR-2812、PR-2541、PR-2537、PR-2514、PR-2509、PR-2591。\n- 5、【优化】任务线程名优化，提升可读性与问题定位效率(ISSUE-2527)。\n\n### 7.33 版本 v2.4.0 Release Notes[2023-03-23]\n- 1、【优化】执行器任务Bean扫描逻辑优化：解决懒加载注解失效问题；\n- 2、【优化】多个项目依赖升级至较新稳定版本，涉及netty、groovy、spring、springboot、mybatis等；\n- 3、【修复】漏洞修复，包括：\"CVE-2022-36157\" 授权漏洞修复；\"CVE-2022-43183\" SSRF漏洞修复；\n\n### 7.34 版本 v2.4.1 Release Notes[2024-04-17]\n- 1、【优化】多个项目依赖升级至较新稳定版本，涉及netty、groovy、springboot、mybatis等；\n- 2、【优化】执行器注册节点显示交互调整，优化注册节点过多时展示不全体验；\n- 3、【修复】漏洞修复，包括：\"CVE-2022-43402\" groovy低版本漏洞修复；\"CVE-2024-29025\" netty低版本漏洞修复；\"CVE-2024-3366\" freemarker模板注入漏洞修复；\"CVE-2022-43183\" 越权漏洞增强修复；\n- 4、【修复】调度日志页面XSS问题修复(ISSUE-3360)。\n\n\n### 7.35 版本 v2.4.2 Release Notes[2024-11-16]\n- 1、【优化】调度中心任务Next计算逻辑调整，避免Cron解析失败导致重复执行问题。\n- 2、【优化】Cron解析组件代码重构微调，健壮性提升；\n- 3、【优化】修改密码交互调整，避免CSRF隐患；\n- 4、【优化】JdkSerializeTool流关闭逻辑优化；\n- 5、【优化】任务信息、执行日志API非功能设计完善，避免越权隐患；\n- 6、【修复】漏洞修复，包括 \"CVE-2024-42681\" 子任务越权漏洞修复、\"CVE-2023-33779\" 任务API越权问题修复；\n- 7、【升级】多个项目依赖升级至较新稳定版本，涉及netty、groovy、gson、springboot、mybatis等；\n\n### 7.36 版本 v2.5.0 Release Notes[2025-01-11]\n- 1、【优化】框架基础守护线程异常处理逻辑优化，避免极端情况下因Error导致调度终止问题；\n- 2、【优化】底层通讯超时时间支持自定义，默认3秒，缓解网络抖动导致任务通讯超时问题；可参考 xxl-job-admin 和 samples 示例代码自行配置；\n- 3、【修复】调度中心快慢线程池优化拒绝策略，避免因默认AbortPolicy导致调度结果丢失问题；\n- 4、【优化】调度中心快慢线程池队列长度调整，优化激增调度时任务积压问题；\n- 5、【重构】调度线程任务信息更新逻辑优化，避免极端情况下已关闭任务被启动问题；\n- 6、【重构】执行器注册逻辑重构，降低多调度中心地址时并发注册问题；任务注册表新增唯一索引，避免冗余注册信息存储；\n- 7、【优化】部分系统日志优化，提升可读性；\n- 8、【优化】合并PR-3616，代码结构注释优化；\n- 9、【优化】合并PR-3619，避免调度过程中任务停止边界情况处理逻辑；\n- 10、【优化】合并PR-3605，避免子任务是任务本身导致死循环；\n- 11、【修复】合并PR-3585，修复全局密码长度不一致问题；\n- 12、【优化】合并PR-3518，SQL列别名反引号包裹，提升跨数据迁移兼容性；\n- 13、【优化】合并PR-3518、PR-3400，日志表索引优化，提升大日志量情况下日志查询及清理速度；\n- 14、【升级】多个项目依赖升级至较新稳定版本，涉及netty、slf4j、junit等；\n\n**备注：**\n- a、本次升级数据模型及通讯协议向前兼容，v2.4.*代码和系统可无缝升级（该版本优化了“xxl_job_log”表索引，建议低版本参考调整）；\n- b、版本v2.5.x为基于jdk8的最后的大版本，将会长期持续维护，问题及漏洞将会及时跟进修复。\n- c、下个大版本（v3.0）将会基于 jdk17 与 springboot3.x 构建；\n\n### 7.37 版本 v3.0.0 Release Notes[2025-02-07]\n- 1、【升级】调度中心升级至 SpringBoot3 + JDK17；\n- 2、【升级】Docker镜像升级，镜像构建基于JDK17；\n- 3、【优化】IP获取逻辑优化，优先遍历网卡来获取可用IP；\n- 4、【优化】通用命令行任务(“commandJobHandler”)优化，支持多参数执行，命令及参数之间通过空格隔开；如任务参数 \"ls la\" 或 \"pwd\" 将会执行命令并输出数据；\n- 5、【优化】通用HTTP任务（httpJobHandler）优化，任务参数格式调整为json格式；\n- 6、【升级】多个项目依赖升级至较新稳定版本，涉及 netty、groovy、spring/springboot 等；\n\n**备注：**\n- a、本次升级数据模型及通讯协议向前兼容，v2.4.*及后续版本可无缝升级；\n- b、版本3.x开始要求Jdk17；版本2.x及以下支持Jdk1.8。如对Jdk版本有诉求，可选择接入不同版本;\n\n### 7.38 版本 v3.1.0 Release Notes[2025-05-01]\n- 1、【新增】新增提供 “AI执行器” 并内置多个Bean模式 AI任务Handler，与spring-ai、ollama、dify等集成打通，支持快速开发AI类任务。\n    - AppName：xxl-job-executor-sample-ai\n    - 执行器代码：xxl-job-executor-sample-springboot-ai\n    - 执行器初始化脚本：执行参考SQL脚本，或自行人工创建：\n        ```\n        INSERT INTO `xxl_job_group`(`app_name`, `title`, `address_type`, `address_list`, `update_time`)\n            VALUES ('xxl-job-executor-sample-ai', 'AI执行器Sample', 0, NULL, now());\n        ```\n- 2、【新增】新增多个 Bean模式 AI任务Handler，如 ollamaJobHandler、difyWorkflowJobHandler 等，支持快速集成开发AI任务。任务配置可参考 [AI执行器](https://www.xuxueli.com/xxl-job/#原生内置Bean模式任务（AI执行器）)\n  - a、ollamaJobHandler： OllamaChat任务，支持自定义prompt、input等输入信息。\n  - b、difyWorkflowJobHandler：DifyWorkflow 任务，支持自定义inputs、user、baseUrl、apiKey等输入信息。\n- 3、【修复】合并PR-3708、PR-3704，解决固定速度调度模式下，下次计算执行时间小概率（间隔超长时）不准问题。\n- 4、【修复】任务操作逻辑优化，修复边界情况下逻辑中断问题 (ISSUE-2081)。\n- 5、【修复】调度中心Cron前端组件优化，解决week配置与后端兼容性问题 (ISSUE-2220)。\n- 6、【修复】任务RollingLog权限逻辑调整：修复非管理员账号越权访问问题 (ISSUE-3705)。\n- 7、【优化】Glue IDE调整，版本回溯支持查看修改时间；\n- 8、【优化】任务RollingLog调整，XSS过滤支持白名单排出，提升日志易读性；\n- 9、【优化】执行器日志文件保存天数（logretentiondays）调整，最小保留时间调整至3天。\n- 10、【升级】多个项目依赖升级至较新稳定版本，涉及 gson、groovy、spring/springboot、mysql 等；\n\n### 7.39 版本 v3.1.1 Release Notes[2025-06-23]\n- 1、【调整】AI任务（difyWorkflowJobHandler）优化：针对 “baseUrl、apiKey” 等Dify配置信息，从执行器侧文件类配置调整至调度中心“任务参数”动态配置，支持多Dify应用集成并提升研发效率；\n- 2、【优化】合并PR-2417，修复任务管理时JobHandler录入空格问题；\n- 3、【优化】合并PR-2504，规避SQL注入问题；\n- 4、【升级】多个项目依赖升级至较新稳定版本，涉及 netty、spring/springboot、groovy 等；\n\n### 7.40 版本 v3.2.0 Release Notes[2025-08-24]\n- 1、【强化】AI任务（ollamaJobHandler）优化：针对 “model” 模型配置信息，从执行器侧文件类配置调整至调度中心“任务参数”动态配置，支持集成多模型、并结合任务动态配置切换。\n- 2、【安全】登录认证重构：密码加密算法从Md5改为Sha256；登录态改为登录后动态随机生成；提升系统安全性；（需要针对用户表进行字段调整，同时需要重新初始化密码信息；相关SQL脚本如下）\n    ```\n    // 1、用户表password字段需要调整长度，执行如下命令\n    ALTER TABLE xxl_job_user\n        MODIFY COLUMN `password` varchar(100) NOT NULL COMMENT '密码加密信息';\n    ALTER TABLE xxl_job_user\n        ADD COLUMN `token` varchar(100) DEFAULT NULL COMMENT '登录token';\n        \n    // 2、存量用户密码需要修改，可执行如下命令将密码初始化 “123456”；也可以自行通过 “SHA256Tool.sha256” 工具生成其他初始化密码；\n    UPDATE xxl_job_user t SET t.password = '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92' WHERE t.username = {用户名};\n    ```\n- 3、【强化】GLUE模式(Python) 扩展，支持 \"GLUE(Python3)\" 与 \"GLUE(Python2)\" 两种模式，分别支持 python3/2 多版本；\n- 4、【强化】调度中心系统日志调整，支持启动时指定 -DLOG_HOME 参数自定义日志位置；同时优化日志格式提升易读性；\n- 5、【优化】任务Bean扫描规则调整，过滤冗余不必要扫描，避免系统组件提前初始化；\n- 6、【优化】登录信息页面空值处理优化，避免空值影响ftl渲染；\n- 7、【优化】异常页面处理逻辑优化，新增兜底落地页配置；\n- 8、【重构】ReturnT 重构，简化代码结构，提升API易用性以及可维护性；\n- 9、【重构】项目结构重构，提升可维护性与易读性；\n- 10、【修复】漏洞修复（CVE-2025-7787），针对 httpJobHandler 支持配置URL白名单限制，防止服务器端请求伪造（SSRF）攻击。\n- 11、【修复】合并PR-3738，修复拼写问题；\n- 12、【修复】合并PR-3506，修复小概率情况下任务重复调度问题；\n- 13、【修复】合并PR-3747，修复异常情况下资源泄漏风险；\n- 14、【修复】IDOR越权问题修复，提升任务操作及日志管理安全性；\n- 15、【升级】升级多项maven依赖至较新版本，如 netty、groovy、mybatis、spring、spring-ai、dify 等；\n\n### 7.41 版本 v3.3.0 Release Notes[2025-11-29]\n- 1、【新增】执行器新增“任务扫描排除路径”配置项(xxl.job.executor.excludedpackage)，任务扫描时忽略指定包路径下的任务；\n- 2、【优化】执行器任务Bean扫描逻辑调整，优化懒加载Bean检测及过滤机制，避免提前初始化类问题；\n- 3、【新增】合并PR-3840，执行器支持通过XxlJobHelper获取任务触发时间戳；XxlJobHelper组件完善，支持通过“XxlJobHelper.getLogId/getLogDateTime/getLogFileName”方法获取执行日志相关信息；\n- 4、【升级】调度中心UI框架升级，统一交互组件，支持多主题、多标签与局部渲染等，升级UI组件及性能；\n- 5、【优化】调度时间轮组件强化，保障不重不漏：调度时间轮单刻度数据去重，避免极端情况下任务重复执行；时间轮转动时校验临近刻度，避免极端情况下遗漏刻度；\n- 6、【优化】调度任务锁逻辑优化，事务SQL下沉至Mapper层统一管理，并增加测试用例，提升代码可读性以及可维护性；\n- 7、【优化】调度快慢线程池默认配置上调，提升默认配置单机负载；调度预读任务数计算系数下调，降低事务颗粒度，提升性能及稳定性； \n- 8、【性能】调度中心调整资源加载逻辑，移除不必要的拦截器，提升页面加载性能；\n- 9、【优化】优化日志列表页面展示逻辑，新增展示“日志ID”与“任务名称”信息；\n- 10、【优化】报表统计SQL优化，修复小概率情况下查询null值问题；报表初始化SQL优化，修复小概率情况增改竞争问题；\n- 11、【优化】优日志报告与清理逻辑，增加清理过期日志的异常捕获，避免线程异常退出；\n- 12、【优化】任务回调失败日志读写磁盘逻辑优化，解决极端情况下大文件读写内存问题；\n- 13、【升级】Http通讯组件升级，基于接口代理方式重构通讯组件，提升组件性能及扩展性；\n- 14、【重构】规范API交互协议，通用响应结构体调整为Response，调度中心API统一为Response封装数据；\n  （注意：响应结构体从ReturnT升级为Response，其中属性值“content”会调整为“data”，通过openapi交互场景需要关注） \n- 15、【重构】调度过期策略、调度类型策略逻辑重构，代码组件化拆分并完善日志，提升健壮性及可维护性；\n- 16、【重构】调度中心底层组件重构，组件初始化以及销毁逻辑统一处理，任务触发及和回调逻辑优化，避免资源泄漏风险；\n- 17、【重构】调度中心底层组件模块化拆分，移除组件单例以及静态代码逻辑，提升组件可维护性；\n- 18、【重构】重构Rolling日志读写逻辑，解决边界条件下异常情况，优化读写性能；\n- 19、【修复】脚本任务process销毁逻辑优化，解决风险情况下脚本进程无法终止问题；\n- 20、【修复】合并PR-2369，修复脚本任务参数取值问题；\n- 21、【新增】任务审计日志，记录任务操作敏感日志信息，如任务新建/更新/删除/启停/触发以及GLUE代码更新等，用于系统监控、审计和安全分析，可快速追溯异常行为以及定位排查问题等。\n  （当前任务审计日志以Info级别输出在系统日志中，可通过关键词 \"xxl-job operation log:\" 检索过滤）\n- 22、【强化】通用HTTP任务（httpJobHandler）强化，支持更丰富请求参数设置，完整参数示例如下：    \n\n<details>\n    <summary>完整参数示例参考：</summary>    \n    \n    ```\n    {\n        \"url\": \"http://www.baidu.com\",\n        \"method\": \"POST\",\n        \"contentType\": \"application/json\",\n        \"headers\": {\n            \"header01\": \"value01\"\n        },\n        \"cookies\": {\n            \"cookie01\": \"value01\"\n        },\n        \"timeout\": 3000,\n        \"data\": \"request body data\",\n        \"form\": {\n            \"key01\": \"value01\"\n        },\n        \"auth\": \"auth data\"\n    }\n    ```\n</details>\n\n- 23、【优化】调度组件日志完善，提升边界情况下问题定位效率；\n- 24、【升级】升级多项maven依赖至较新版本，如 netty、groovy、springboot、spring-ai、dify、mybatis、xxl-sso 等；\n\n**备注：**\n- a、本次升级数据模型向前兼容，v3.2.*版本可直接升级不需要进行数据库表调整；\n- b、本次升级针对客户端rollinglog依赖字段做规范约束，如不关注该功能 v2.4.* 及后续版本客户端不需要升级/可兼容，否则需要升级客户端版本；\n\n### 7.42 版本 v3.3.1 Release Notes[2025-12-06]\n- 1、【新增】新增“执行器启用开关”配置项(xxl.job.executor.enabled)，默认开启，关闭时不进行执行器初始化；\n- 2、【修复】调度组件事务代码调整，修复DB超时等小概率情况下调度终止问题；\n- 3、【修复】合并PR-3869，修复底层通讯超时设置无效问题；\n- 4、【优化】执行器删除逻辑优化，删除时一并清理注册表数据，避免小概率情况下注册数据堆积（ISSUE-3669）；\n- 5、【升级】调度中心升级至 SpringBoot4；升级多项maven依赖至较新版本，如 mybatis、groovy 等；\n\n### 7.43 版本 v3.3.2 Release Notes[2026-01-01]\n- 1、【优化】优雅停机：调度中心停机，检测时间轮非空时主动等待调度完成；客户端停机，检测存在运行中任务时，停止接收新任务并主动等待任务执行完成；\n- 2、【新增】新增 Docker Compose 配置，支持一键配置启动调度中心集群；\n\n<details>\n    <summary>Docker Compose启动步骤：</summary>    \n\n    ```\n    // 下载 XXL-JOB\n    git clone --branch \"$(curl -s https://api.github.com/repos/xuxueli/xxl-job/releases/latest | jq -r .tag_name)\" https://github.com/xuxueli/xxl-job.git\n    // 构建 XXL-JOB\n    mvn clean package -Dmaven.test.skip=true\n    // 配置 XXL-JOB（前往docker目录，自定义 .env）\n    cd ./docker\n    cat .env\n    // 启动 XXL-JOB\n    docker compose up -d\n    // 停止 XXL-JOB\n    docker compose down\n    ```\n</details>\n\n- 3、【优化】调度中心操作体验优化：表格交互调整为单行选中模式；禁用分页循环；优化分页限制文案；\n- 4、【优化】调度线程事务提交逻辑调整，避免边界条件下线程异常退出，增强健壮性；\n- 5、【优化】调度日志列表排序逻辑优化，提升易读性；\n- 6、【优化】调度中心OpenAPI通讯token调整为非必填；合并PR-3892；\n- 7、【优化】执行器详情接口权限调整，支持普通用户查看注册节点；合并PR-3882；\n- 8、【优化】任务参数LogDateTime生成逻辑调整，分片广播场景下保障同一批调度一致；\n- 9、【升级】升级多项maven依赖至较新版本，如 spring、netty、xxl-sso、xxl-tool 等；\n- 10、【优化】统一项目依赖管理结构，依赖版本统一到父级pom提升可维护性；\n\n### 7.44 版本 v3.4.0 Release Notes[ING]\n- 1、【TODO】调度触发性能优化：调度触发后任务分批批量更新，提升调度性能；\n- 2、【TODO】执行器内嵌容器调整：由Netty调整为Tomcat，简化项目依赖；\n\n\n### TODO LIST\n- 1、调度隔离：调度中心针对不同执行器，各自维护不同的调度和远程触发组件。\n- 2、任务优先级：调度与执行阶段按照优先级分配资源。\n- 3、多数据库支持，DAO层通过JPA实现，不限制数据库类型。\n- 4、OpenApi：\n  - 执行器Log文件清理：支持调度中心远程删除执行器中指定任务的Log文件；\n- 5、性能优化：任务、执行器数据全量本地缓存；新增消息表广播通知；\n- 6、DAG流程任务\n    - 子任务：废弃\n    - DAG任务创建、管理，DAG任务日志查看、操作；\n    - 支持参数传递，共享数据；\n    - 分片任务：全部完成后才会出发后置节点；\n    - 配置并列的\"a-b、b-c\"路径列表，构成串行、并行、dag任务流程，\"dagre-d3\"绘图；任务依赖，流程图，子任务+会签任务，各节点日志；支持根据成功、失败选择分支；\n- 7、任务标签：方便搜索；\n- 8、GLUE 模式 Web Ide 版本对比功能；\n- 9、自定义失败重试时间间隔；\n- 10、任务导入导出工具，灵活支持版本升级、迁移等场景。\n- 11、任务日志重构：一次调度只记录一条主任务，维护起止时间和状态。\n    - 普通任务：只记录一条主任务；\n    - 广播任务：记录一条主任务，每个分片任务记录一条次任务，关联在主任务上；\n    - 重试任务：失败时，新增主任务。所有调度记录，包括入口调度和重试调度，均挂载主任务上。\n- 12、分片任务：全部完成后才会出发后置节点；\n- 13、日期过滤：支持多个时间段排除；\n- 14、提供执行器Docker镜像；\n- 15、脚本任务，支持数据参数，新版本仅支持单参数不支持需要兼容；\n- 17、批量调度：调度请求入queue，调度线程批量获取调度请求并发起远程调度；提高线程效率；\n- 18、执行器端口复用，复用容器端口提供通讯服务；\n- 19、安全功能增强，通讯加密参数改用加密数据避免AccessToken明文， 降低token泄漏风险；\n- 20、告警增强：\n    - 邮件告警：支持自定义标题、模板格式；\n    - webhook告警：支持自定义告警URL、请求体格式；\n- 21、公共告警策略：执行器维度设置多告警策略，任务勾选启用；待评估任务或执行器维度；\n- 20、日志策略：\n  - 调度日志：全局配置：废弃； 新增“调度日志策略”：任务维度自定义，保留3天、7天、1个月、3个月、一年、永久；\n  - 执行日志：新增“执行RollingLog开关”：任务维度自定义，支持：RollingLog、普通日志（slf4j输出）、关闭（不输出）；\n- 21、AccessToken：废弃全局配置；支持在线管理，动态生成、动态启停；\n- 22、任务执行后分批批量更新，提升调度性能；\n- 23、任务管理OpenAPI;\n- 24、调度中心启动参数线上配置：告警发送邮箱、Token，支持线上配置生效，修改不需重启机器；\n- 25、执行器内嵌server切换tomcat，精简依赖；\n- 26、日志策略新增：\n  - 调度日志策略：任务级设置，最少保留1天。 \n  - 执行日志策略：可选 RollingLog、slf4jLog；\n  - 清理逻辑，性能重构。\n\n\n## 八、其他\n\n### 8.1 项目贡献\n欢迎参与项目贡献！比如提交PR修复一个bug，或者新建 [Issue](https://github.com/xuxueli/xxl-job/issues/) 讨论新特性或者变更。\n\n### 8.2 用户接入登记\n更多接入的公司，欢迎在 [登记地址](https://github.com/xuxueli/xxl-job/issues/1 ) 登记，登记仅仅为了产品推广。\n\n### 8.3 开源协议和版权\n产品开源免费，并且将持续提供免费的社区技术支持。个人或企业内部可自由的接入和使用。如有需要可邮件联系作者免费获取项目授权。\n\n- Licensed under the GNU General Public License (GPL) v3.\n- Copyright (c) 2015-present, xuxueli.\n\n---\n### 捐赠\n无论捐赠金额多少都足够表达您这份心意，非常感谢 ：）      [前往捐赠](https://www.xuxueli.com/page/donate.html )\n"
  },
  {
    "path": "doc/db/tables_xxl_job.sql",
    "content": "#\n# XXL-JOB\n# Copyright (c) 2015-present, xuxueli.\n\nCREATE database if NOT EXISTS `xxl_job` default character set utf8mb4 collate utf8mb4_unicode_ci;\nuse `xxl_job`;\n\nSET NAMES utf8mb4;\n\n## —————————————————————— job group and registry ——————————————————\n\nCREATE TABLE `xxl_job_group`\n(\n    `id`           int(11)     NOT NULL AUTO_INCREMENT,\n    `app_name`     varchar(64) NOT NULL COMMENT '执行器AppName',\n    `title`        varchar(12) NOT NULL COMMENT '执行器名称',\n    `address_type` tinyint(4)  NOT NULL DEFAULT '0' COMMENT '执行器地址类型：0=自动注册、1=手动录入',\n    `address_list` text COMMENT '执行器地址列表，多地址逗号分隔',\n    `update_time`  datetime             DEFAULT NULL,\n    PRIMARY KEY (`id`)\n) ENGINE = InnoDB\n  DEFAULT CHARSET = utf8mb4;\n\nCREATE TABLE `xxl_job_registry`\n(\n    `id`             int(11)      NOT NULL AUTO_INCREMENT,\n    `registry_group` varchar(50)  NOT NULL,\n    `registry_key`   varchar(255) NOT NULL,\n    `registry_value` varchar(255) NOT NULL,\n    `update_time`    datetime DEFAULT NULL,\n    PRIMARY KEY (`id`),\n    UNIQUE KEY `i_g_k_v` (`registry_group`, `registry_key`, `registry_value`) USING BTREE\n) ENGINE = InnoDB\n  DEFAULT CHARSET = utf8mb4;\n\n## —————————————————————— job info ——————————————————\n\nCREATE TABLE `xxl_job_info`\n(\n    `id`                        int(11)      NOT NULL AUTO_INCREMENT,\n    `job_group`                 int(11)      NOT NULL COMMENT '执行器主键ID',\n    `job_desc`                  varchar(255) NOT NULL,\n    `add_time`                  datetime              DEFAULT NULL,\n    `update_time`               datetime              DEFAULT NULL,\n    `author`                    varchar(64)           DEFAULT NULL COMMENT '作者',\n    `alarm_email`               varchar(255)          DEFAULT NULL COMMENT '报警邮件',\n    `schedule_type`             varchar(50)  NOT NULL DEFAULT 'NONE' COMMENT '调度类型',\n    `schedule_conf`             varchar(128)          DEFAULT NULL COMMENT '调度配置，值含义取决于调度类型',\n    `misfire_strategy`          varchar(50)  NOT NULL DEFAULT 'DO_NOTHING' COMMENT '调度过期策略',\n    `executor_route_strategy`   varchar(50)           DEFAULT NULL COMMENT '执行器路由策略',\n    `executor_handler`          varchar(255)          DEFAULT NULL COMMENT '执行器任务handler',\n    `executor_param`            varchar(512)          DEFAULT NULL COMMENT '执行器任务参数',\n    `executor_block_strategy`   varchar(50)           DEFAULT NULL COMMENT '阻塞处理策略',\n    `executor_timeout`          int(11)      NOT NULL DEFAULT '0' COMMENT '任务执行超时时间，单位秒',\n    `executor_fail_retry_count` int(11)      NOT NULL DEFAULT '0' COMMENT '失败重试次数',\n    `glue_type`                 varchar(50)  NOT NULL COMMENT 'GLUE类型',\n    `glue_source`               mediumtext COMMENT 'GLUE源代码',\n    `glue_remark`               varchar(128)          DEFAULT NULL COMMENT 'GLUE备注',\n    `glue_updatetime`           datetime              DEFAULT NULL COMMENT 'GLUE更新时间',\n    `child_jobid`               varchar(255)          DEFAULT NULL COMMENT '子任务ID，多个逗号分隔',\n    `trigger_status`            tinyint(4)   NOT NULL DEFAULT '0' COMMENT '调度状态：0-停止，1-运行',\n    `trigger_last_time`         bigint(13)   NOT NULL DEFAULT '0' COMMENT '上次调度时间',\n    `trigger_next_time`         bigint(13)   NOT NULL DEFAULT '0' COMMENT '下次调度时间',\n    PRIMARY KEY (`id`)\n) ENGINE = InnoDB\n  DEFAULT CHARSET = utf8mb4;\n\nCREATE TABLE `xxl_job_logglue`\n(\n    `id`          int(11)      NOT NULL AUTO_INCREMENT,\n    `job_id`      int(11)      NOT NULL COMMENT '任务，主键ID',\n    `glue_type`   varchar(50) DEFAULT NULL COMMENT 'GLUE类型',\n    `glue_source` mediumtext COMMENT 'GLUE源代码',\n    `glue_remark` varchar(128) NOT NULL COMMENT 'GLUE备注',\n    `add_time`    datetime    DEFAULT NULL,\n    `update_time` datetime    DEFAULT NULL,\n    PRIMARY KEY (`id`)\n) ENGINE = InnoDB\n  DEFAULT CHARSET = utf8mb4;\n\n## —————————————————————— job log and report ——————————————————\n\nCREATE TABLE `xxl_job_log`\n(\n    `id`                        bigint(20) NOT NULL AUTO_INCREMENT,\n    `job_group`                 int(11)    NOT NULL COMMENT '执行器主键ID',\n    `job_id`                    int(11)    NOT NULL COMMENT '任务，主键ID',\n    `executor_address`          varchar(255)        DEFAULT NULL COMMENT '执行器地址，本次执行的地址',\n    `executor_handler`          varchar(255)        DEFAULT NULL COMMENT '执行器任务handler',\n    `executor_param`            varchar(512)        DEFAULT NULL COMMENT '执行器任务参数',\n    `executor_sharding_param`   varchar(20)         DEFAULT NULL COMMENT '执行器任务分片参数，格式如 1/2',\n    `executor_fail_retry_count` int(11)    NOT NULL DEFAULT '0' COMMENT '失败重试次数',\n    `trigger_time`              datetime            DEFAULT NULL COMMENT '调度-时间',\n    `trigger_code`              int(11)    NOT NULL COMMENT '调度-结果',\n    `trigger_msg`               text COMMENT '调度-日志',\n    `handle_time`               datetime            DEFAULT NULL COMMENT '执行-时间',\n    `handle_code`               int(11)    NOT NULL COMMENT '执行-状态',\n    `handle_msg`                text COMMENT '执行-日志',\n    `alarm_status`              tinyint(4) NOT NULL DEFAULT '0' COMMENT '告警状态：0-默认、1-无需告警、2-告警成功、3-告警失败',\n    PRIMARY KEY (`id`),\n    KEY `I_trigger_time` (`trigger_time`),\n    KEY `I_handle_code` (`handle_code`),\n    KEY `I_jobid_jobgroup` (`job_id`,`job_group`),\n    KEY `I_job_id` (`job_id`)\n) ENGINE = InnoDB\n  DEFAULT CHARSET = utf8mb4;\n\nCREATE TABLE `xxl_job_log_report`\n(\n    `id`            int(11) NOT NULL AUTO_INCREMENT,\n    `trigger_day`   datetime         DEFAULT NULL COMMENT '调度-时间',\n    `running_count` int(11) NOT NULL DEFAULT '0' COMMENT '运行中-日志数量',\n    `suc_count`     int(11) NOT NULL DEFAULT '0' COMMENT '执行成功-日志数量',\n    `fail_count`    int(11) NOT NULL DEFAULT '0' COMMENT '执行失败-日志数量',\n    `update_time`   datetime         DEFAULT NULL,\n    PRIMARY KEY (`id`),\n    UNIQUE KEY `i_trigger_day` (`trigger_day`) USING BTREE\n) ENGINE = InnoDB\n  DEFAULT CHARSET = utf8mb4;\n\n## —————————————————————— lock ——————————————————\n\nCREATE TABLE `xxl_job_lock`\n(\n    `lock_name` varchar(50) NOT NULL COMMENT '锁名称',\n    PRIMARY KEY (`lock_name`)\n) ENGINE = InnoDB\n  DEFAULT CHARSET = utf8mb4;\n\n## —————————————————————— user ——————————————————\n\nCREATE TABLE `xxl_job_user`\n(\n    `id`         int(11)     NOT NULL AUTO_INCREMENT,\n    `username`   varchar(50) NOT NULL COMMENT '账号',\n    `password`   varchar(100) NOT NULL COMMENT '密码加密信息',\n    `token`      varchar(100) DEFAULT NULL COMMENT '登录token',\n    `role`       tinyint(4)  NOT NULL COMMENT '角色：0-普通用户、1-管理员',\n    `permission` varchar(255) DEFAULT NULL COMMENT '权限：执行器ID列表，多个逗号分割',\n    PRIMARY KEY (`id`),\n    UNIQUE KEY `i_username` (`username`) USING BTREE\n) ENGINE = InnoDB\n  DEFAULT CHARSET = utf8mb4;\n\n\n## —————————————————————— for default data ——————————————————\n\nINSERT INTO `xxl_job_group`(`id`, `app_name`, `title`, `address_type`, `address_list`, `update_time`)\n    VALUES (1, 'xxl-job-executor-sample', '通用执行器Sample', 0, NULL, now()),\n           (2, 'xxl-job-executor-sample-ai', 'AI执行器Sample', 0, NULL, now());\n\nINSERT INTO `xxl_job_info`(`id`, `job_group`, `job_desc`, `add_time`, `update_time`, `author`, `alarm_email`,\n                           `schedule_type`, `schedule_conf`, `misfire_strategy`, `executor_route_strategy`,\n                           `executor_handler`, `executor_param`, `executor_block_strategy`, `executor_timeout`,\n                           `executor_fail_retry_count`, `glue_type`, `glue_source`, `glue_remark`, `glue_updatetime`,\n                           `child_jobid`)\nVALUES (1, 1, '示例任务01', now(), now(), 'XXL', '', 'CRON', '0 0 0 * * ? *',\n        'DO_NOTHING', 'FIRST', 'demoJobHandler', '', 'SERIAL_EXECUTION', 0, 0, 'BEAN', '', 'GLUE代码初始化',\n        now(), ''),\n       (2, 2, 'Ollama示例任务01', now(), now(), 'XXL', '', 'NONE', '',\n        'DO_NOTHING', 'FIRST', 'ollamaJobHandler', '{\n    \"input\": \"慢SQL问题分析思路\",\n    \"prompt\": \"你是一个研发工程师，擅长解决技术类问题。\",\n    \"model\": \"qwen3:0.6b\"\n}', 'SERIAL_EXECUTION', 0, 0, 'BEAN', '', 'GLUE代码初始化',\n        now(), ''),\n       (3, 2, 'Dify示例任务', now(), now(), 'XXL', '', 'NONE', '',\n        'DO_NOTHING', 'FIRST', 'difyWorkflowJobHandler', '{\n    \"inputs\":{\n        \"input\":\"查询班级各学科前三名\"\n    },\n    \"user\": \"xxl-job\",\n    \"baseUrl\": \"http://localhost/v1\",\n    \"apiKey\": \"app-OUVgNUOQRIMokfmuJvBJoUTN\"\n}', 'SERIAL_EXECUTION', 0, 0, 'BEAN', '', 'GLUE代码初始化',\n        now(), '');\n\nINSERT INTO `xxl_job_user`(`id`, `username`, `password`, `role`, `permission`)\nVALUES (1, 'admin', '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92', 1, NULL);\n\nINSERT INTO `xxl_job_lock` (`lock_name`)\nVALUES ('schedule_lock');\n\ncommit;\n"
  },
  {
    "path": "docker/docker-compose.yml",
    "content": "# docker-compose version\nversion: '3.8'\n\nservices:\n  mysql:\n    image: mysql:8.4\n    container_name: xxl-job-mysql\n    environment:\n      # 1、数据库密码设置，需要与Admin中配置一致：\n      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}\n      # 2、数据库实例名称，需要与Admin中配置一致；\n      MYSQL_DATABASE: xxl_job\n    ports:\n      - \"3306:3306\"\n    volumes:\n      # 说明：仅数据库首次初始化时执行；\n      - ../doc/db/tables_xxl_job.sql:/docker-entrypoint-initdb.d/tables_xxl_job.sql:ro\n      # 3、数据库持久化目录位置，建议自定义：\n      - ${MYSQL_PATH}/conf:/etc/mysql/conf.d\n      - ${MYSQL_PATH}/logs:/var/log/mysql\n      - ${MYSQL_PATH}/data:/var/lib/mysql\n    command: >-\n      --character-set-server=utf8mb4\n      --collation-server=utf8mb4_unicode_ci\n    healthcheck:\n      test: [\"CMD\", \"mysqladmin\", \"ping\", \"-h\", \"localhost\"]\n      timeout: 20s\n      retries: 10\n    networks:\n      - xxl-job-network\n\n  xxl-job-admin:\n    # 4、本地Build设置，如果期望使用推动DockerHub的镜像，可以注释当前启用的image、build配置，并启用如下设置版本的image配置；\n    #image: xuxueli/xxl-job-admin:{version}\n    image: xuxueli/xxl-job-admin:local\n    build:\n      context: ../xxl-job-admin\n      dockerfile: Dockerfile\n    container_name: xxl-job-admin\n    environment:\n      # 5、数据库密码设置，需要与上文Mysql中保持一致：\n      PARAMS: >-\n        --spring.datasource.url=jdbc:mysql://mysql:3306/xxl_job?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai\n        --spring.datasource.username=root \n        --spring.datasource.password=${MYSQL_ROOT_PASSWORD}\n        --server.port=${XXL_JOB_ADMIN_PORT}\n        --server.servlet.context-path=${XXL_JOB_ADMIN_CONTEXT_PATH}\n    ports:\n      - \"${XXL_JOB_ADMIN_PORT}:${XXL_JOB_ADMIN_PORT}\"\n    depends_on:\n      mysql:\n        condition: service_healthy\n    networks:\n      - xxl-job-network\n\n  xxl-job-executor-sample-springboot:\n    image: xuxueli/xxl-job-executor-sample-springboot:local\n    build:\n      context: ./xxl-job-executor-samples/xxl-job-executor-sample-springboot\n      dockerfile: Dockerfile\n    container_name: xxl-job-executor-sample-springboot\n    environment:\n      PARAMS: >-\n        --xxl.job.admin.addresses=http://xxl-job-admin:${XXL_JOB_ADMIN_PORT}${XXL_JOB_ADMIN_CONTEXT_PATH:-/}\n    ports:\n      - \"9999:9999\"\n    depends_on:\n      xxl-job-admin:\n        condition: service_started\n    networks:\n      - xxl-job-network\n\nnetworks:\n  xxl-job-network:\n    driver: bridge\n"
  },
  {
    "path": "pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>com.xuxueli</groupId>\n\t<artifactId>xxl-job</artifactId>\n\t<version>3.4.0-SNAPSHOT</version>\n\t<packaging>pom</packaging>\n\n\t<name>${project.artifactId}</name>\n\t<description>A distributed task scheduling framework.</description>\n\t<url>https://www.xuxueli.com/</url>\n\n\t<modules>\n\t\t<module>xxl-job-core</module>\n\t\t<module>xxl-job-admin</module>\n\t\t<module>xxl-job-executor-samples</module>\n    </modules>\n\n\t<properties>\n\t\t<!-- env -->\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n\t\t<maven.compiler.encoding>UTF-8</maven.compiler.encoding>\n\t\t<maven.compiler.source>17</maven.compiler.source>\n\t\t<maven.compiler.target>17</maven.compiler.target>\n\t\t<maven.test.skip>true</maven.test.skip>\n\t\t<!-- plugin -->\n\t\t<maven-compiler-plugin.version>3.14.1</maven-compiler-plugin.version>\n\t\t<maven-source-plugin.version>3.4.0</maven-source-plugin.version>\n\t\t<maven-javadoc-plugin.version>3.12.0</maven-javadoc-plugin.version>\n\t\t<maven-gpg-plugin.version>3.2.8</maven-gpg-plugin.version>\n\t\t<central-publishing-maven-plugin.version>0.9.0</central-publishing-maven-plugin.version>\n\t\t<!-- base -->\n\t\t<slf4j-api.version>2.0.17</slf4j-api.version>\n\t\t<junit-jupiter.version>6.0.1</junit-jupiter.version>\n\n\t\t<!-- jakarta.annotation-api -->\n\t\t<jakarta.annotation-api.version>3.0.0</jakarta.annotation-api.version>\n\n\t\t<!-- spring -->\n\t\t<spring-boot.version>4.0.1</spring-boot.version>\n\t\t<spring.version>7.0.2</spring.version>\n\t\t<!-- mybatis & db -->\n\t\t<mybatis-spring-boot-starter.version>4.0.1</mybatis-spring-boot-starter.version>\n\t\t<mysql-connector-j.version>9.5.0</mysql-connector-j.version>\n\n\t\t<!-- net -->\n\t\t<netty.version>4.2.9.Final</netty.version>\n\t\t<!-- groovy -->\n\t\t<groovy.version>5.0.3</groovy.version>\n\n\t\t<!-- xxl-sso -->\n\t\t<xxl-sso.version>2.3.2</xxl-sso.version>\n\t\t<!-- xxl-tool -->\n\t\t<xxl-tool.version>2.4.2</xxl-tool.version>\n\t\t<!-- gson -->\n\t\t<gson.version>2.13.2</gson.version>\n\n\t\t<!-- spring-ai -->\n\t\t<spring-ai.version>2.0.0-M1</spring-ai.version>\n\t\t<!-- dify -->\n\t\t<dify-java-client.version>1.2.3</dify-java-client.version>\n\t</properties>\n\n\t<dependencyManagement>\n\t\t<dependencies>\n\t\t\t<!-- springboot -->\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-dependencies</artifactId>\n\t\t\t\t<version>${spring-boot.version}</version>\n\t\t\t\t<type>pom</type>\n\t\t\t\t<scope>import</scope>\n\t\t\t</dependency>\n\n\t\t\t<!-- slf4j -->\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t\t<artifactId>slf4j-api</artifactId>\n\t\t\t\t<version>${slf4j-api.version}</version>\n\t\t\t</dependency>\n\t\t\t<!-- slf4j-reload4j -->\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t\t<artifactId>slf4j-reload4j</artifactId>\n\t\t\t\t<version>${slf4j-api.version}</version>\n\t\t\t</dependency>\n\n\t\t\t<!-- junit -->\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.junit.jupiter</groupId>\n\t\t\t\t<artifactId>junit-jupiter-engine</artifactId>\n\t\t\t\t<version>${junit-jupiter.version}</version>\n\t\t\t</dependency>\n\n\t\t\t<!-- jakarta -->\n\t\t\t<dependency>\n\t\t\t\t<groupId>jakarta.annotation</groupId>\n\t\t\t\t<artifactId>jakarta.annotation-api</artifactId>\n\t\t\t\t<version>${jakarta.annotation-api.version}</version>\n\t\t\t</dependency>\n\n\t\t\t<!-- netty -->\n\t\t\t<dependency>\n\t\t\t\t<groupId>io.netty</groupId>\n\t\t\t\t<artifactId>netty-codec-http</artifactId>\n\t\t\t\t<version>${netty.version}</version>\n\t\t\t</dependency>\n\t\t\t<!-- gson -->\n\t\t\t<dependency>\n\t\t\t\t<groupId>com.google.code.gson</groupId>\n\t\t\t\t<artifactId>gson</artifactId>\n\t\t\t\t<version>${gson.version}</version>\n\t\t\t</dependency>\n\n\t\t\t<!-- xxl-tool -->\n\t\t\t<dependency>\n\t\t\t\t<groupId>com.xuxueli</groupId>\n\t\t\t\t<artifactId>xxl-tool</artifactId>\n\t\t\t\t<version>${xxl-tool.version}</version>\n\t\t\t</dependency>\n\n\t\t\t<!-- groovy -->\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.apache.groovy</groupId>\n\t\t\t\t<artifactId>groovy</artifactId>\n\t\t\t\t<version>${groovy.version}</version>\n\t\t\t</dependency>\n\n\t\t\t<!-- spring-context -->\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.springframework</groupId>\n\t\t\t\t<artifactId>spring-context</artifactId>\n\t\t\t\t<version>${spring.version}</version>\n\t\t\t\t<scope>provided</scope>\n\t\t\t</dependency>\n\n\t\t\t<!-- mybatis-starter：mybatis + mybatis-spring + hikari（default） -->\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.mybatis.spring.boot</groupId>\n\t\t\t\t<artifactId>mybatis-spring-boot-starter</artifactId>\n\t\t\t\t<version>${mybatis-spring-boot-starter.version}</version>\n\t\t\t</dependency>\n\t\t\t<!-- mysql -->\n\t\t\t<dependency>\n\t\t\t\t<groupId>com.mysql</groupId>\n\t\t\t\t<artifactId>mysql-connector-j</artifactId>\n\t\t\t\t<version>${mysql-connector-j.version}</version>\n\t\t\t</dependency>\n\n\t\t\t<!-- xxl-job-core -->\n\t\t\t<dependency>\n\t\t\t\t<groupId>com.xuxueli</groupId>\n\t\t\t\t<artifactId>xxl-job-core</artifactId>\n\t\t\t\t<version>${project.parent.version}</version>\n\t\t\t</dependency>\n\n\t\t\t<!-- xxl-sso (xxl-tool、gson) -->\n\t\t\t<dependency>\n\t\t\t\t<groupId>com.xuxueli</groupId>\n\t\t\t\t<artifactId>xxl-sso-core</artifactId>\n\t\t\t\t<version>${xxl-sso.version}</version>\n\t\t\t</dependency>\n\n\t\t\t<!-- spring-ai -->\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.springframework.ai</groupId>\n\t\t\t\t<artifactId>spring-ai-starter-model-ollama</artifactId>\n\t\t\t\t<version>${spring-ai.version}</version>\n\t\t\t</dependency>\n\t\t\t<!-- dify -->\n\t\t\t<dependency>\n\t\t\t\t<groupId>io.github.imfangs</groupId>\n\t\t\t\t<artifactId>dify-java-client</artifactId>\n\t\t\t\t<version>${dify-java-client.version}</version>\n\t\t\t</dependency>\n\n\t\t</dependencies>\n\t</dependencyManagement>\n\n\t<licenses>\n\t\t<license>\n\t\t\t<name>GNU General Public License version 3</name>\n\t\t\t<url>https://opensource.org/licenses/GPL-3.0</url>\n\t\t</license>\n\t</licenses>\n\t<scm>\n\t\t<tag>master</tag>\n\t\t<url>https://github.com/xuxueli/xxl-job.git</url>\n\t\t<connection>scm:git:https://github.com/xuxueli/xxl-job.git</connection>\n\t\t<developerConnection>scm:git:git@github.com:xuxueli/xxl-job.git</developerConnection>\n\t</scm>\n\t<developers>\n\t\t<developer>\n\t\t\t<id>XXL</id>\n\t\t\t<name>xuxueli</name>\n\t\t\t<email>931591021@qq.com</email>\n\t\t\t<url>https://github.com/xuxueli</url>\n\t\t</developer>\n\t</developers>\n\n\t<build>\n\t\t<plugins>\n\t\t</plugins>\n\t</build>\n\n\t<profiles>\n\n\t\t<profile>\n\t\t\t<id>release</id>\n\t\t\t<activation>\n\t\t\t\t<activeByDefault>true</activeByDefault>\n\t\t\t</activation>\n\t\t\t<modules>\n\t\t\t\t<module>xxl-job-core</module>\n\t\t\t</modules>\n\t\t\t<build>\n\t\t\t\t<plugins>\n\t\t\t\t\t<!-- Compiler -->\n\t\t\t\t\t<plugin>\n\t\t\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t\t\t<artifactId>maven-compiler-plugin</artifactId>\n\t\t\t\t\t\t<version>${maven-compiler-plugin.version}</version>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<source>${maven.compiler.source}</source>\n\t\t\t\t\t\t\t<target>${maven.compiler.target}</target>\n\t\t\t\t\t\t\t<parameters>true</parameters>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</plugin>\n\t\t\t\t\t<!-- Source -->\n\t\t\t\t\t<plugin>\n\t\t\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t\t\t<artifactId>maven-source-plugin</artifactId>\n\t\t\t\t\t\t<version>${maven-source-plugin.version}</version>\n\t\t\t\t\t\t<executions>\n\t\t\t\t\t\t\t<execution>\n\t\t\t\t\t\t\t\t<phase>package</phase>\n\t\t\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t\t\t<goal>jar-no-fork</goal>\n\t\t\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t\t</execution>\n\t\t\t\t\t\t</executions>\n\t\t\t\t\t</plugin>\n\t\t\t\t\t<!-- Javadoc -->\n\t\t\t\t\t<plugin>\n\t\t\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t\t\t<artifactId>maven-javadoc-plugin</artifactId>\n\t\t\t\t\t\t<version>${maven-javadoc-plugin.version}</version>\n\t\t\t\t\t\t<executions>\n\t\t\t\t\t\t\t<execution>\n\t\t\t\t\t\t\t\t<phase>package</phase>\n\t\t\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t\t\t<goal>jar</goal>\n\t\t\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t\t\t<doclint>none</doclint>\n\t\t\t\t\t\t\t\t</configuration>\n\t\t\t\t\t\t\t</execution>\n\t\t\t\t\t\t</executions>\n\t\t\t\t\t</plugin>\n\t\t\t\t\t<!-- GPG -->\n                    <plugin>\n                        <groupId>org.apache.maven.plugins</groupId>\n                        <artifactId>maven-gpg-plugin</artifactId>\n                        <version>${maven-gpg-plugin.version}</version>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<useAgent>false</useAgent>\n\t\t\t\t\t\t</configuration>\n                        <executions>\n                            <execution>\n                                <phase>verify</phase>\n                                <goals>\n                                    <goal>sign</goal>\n                                </goals>\n                            </execution>\n                        </executions>\n                    </plugin>\n\t\t\t\t\t<!-- maven central -->\n\t\t\t\t\t<plugin>\n\t\t\t\t\t\t<groupId>org.sonatype.central</groupId>\n\t\t\t\t\t\t<artifactId>central-publishing-maven-plugin</artifactId>\n\t\t\t\t\t\t<version>${central-publishing-maven-plugin.version}</version>\n\t\t\t\t\t\t<extensions>true</extensions>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<publishingServerId>central</publishingServerId>\n\t\t\t\t\t\t\t<excludeArtifacts>\n\t\t\t\t\t\t\t\t<artifact>xxl-job-admin</artifact>\n\t\t\t\t\t\t\t\t<artifact>xxl-job-executor-samples</artifact>\n\t\t\t\t\t\t\t\t<artifact>xxl-job-executor-sample-frameless</artifact>\n\t\t\t\t\t\t\t\t<artifact>xxl-job-executor-sample-springboot</artifact>\n\t\t\t\t\t\t\t\t<artifact>xxl-job-executor-sample-springboot-ai</artifact>\n\t\t\t\t\t\t\t</excludeArtifacts>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</plugin>\n\t\t\t\t</plugins>\n\t\t\t</build>\n\t\t</profile>\n\t</profiles>\n\n</project>"
  },
  {
    "path": "xxl-job-admin/Dockerfile",
    "content": "# base image\nFROM openjdk:21-jdk-slim\n\n# maintainer\nMAINTAINER xuxueli\n\n# set params\nENV PARAMS=\"\"\n\n# set timezone\nENV TZ=PRC\nRUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone\n\n# copy jar\nADD target/xxl-job-admin-*.jar /app.jar\n\n# command\n# log home: -e LOG_HOME=/data/applogs\n# jvm options: -e JAVA_OPTS=\"-Xms128m -Xmx128m\"\n# app params: -e PARAMS=\"--server.port=8080\"\nENTRYPOINT [\"sh\",\"-c\",\"java ${LOG_HOME:+-DLOG_HOME=$LOG_HOME} -jar $JAVA_OPTS /app.jar $PARAMS\"]"
  },
  {
    "path": "xxl-job-admin/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>com.xuxueli</groupId>\n\t\t<artifactId>xxl-job</artifactId>\n\t\t<version>3.4.0-SNAPSHOT</version>\n\t</parent>\n\t<artifactId>xxl-job-admin</artifactId>\n\t<packaging>jar</packaging>\n\n\t<properties>\n\t\t<maven.deploy.skip>true</maven.deploy.skip>\n\t</properties>\n\n\t<dependencies>\n\n\t\t<!-- starter-web -->\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-web</artifactId>\n\t\t</dependency>\n\t\t<!-- starter-test -->\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\n\t\t<!-- freemarker-starter -->\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-freemarker</artifactId>\n\t\t</dependency>\n\t\t<!-- mail-starter -->\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-mail</artifactId>\n\t\t</dependency>\n\t\t<!-- starter-actuator -->\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-actuator</artifactId>\n\t\t</dependency>\n\n\t\t<!-- mybatis-starter -->\n\t\t<dependency>\n\t\t\t<groupId>org.mybatis.spring.boot</groupId>\n\t\t\t<artifactId>mybatis-spring-boot-starter</artifactId>\n\t\t</dependency>\n\t\t<!-- mysql -->\n\t\t<dependency>\n\t\t\t<groupId>com.mysql</groupId>\n\t\t\t<artifactId>mysql-connector-j</artifactId>\n\t\t</dependency>\n\n\t\t<!-- xxl-job-core -->\n\t\t<dependency>\n\t\t\t<groupId>com.xuxueli</groupId>\n\t\t\t<artifactId>xxl-job-core</artifactId>\n\t\t</dependency>\n\n\t\t<!-- xxl-sso -->\n\t\t<dependency>\n\t\t\t<groupId>com.xuxueli</groupId>\n\t\t\t<artifactId>xxl-sso-core</artifactId>\n\t\t</dependency>\n\n\t</dependencies>\n\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<version>${spring-boot.version}</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\n\t\t</plugins>\n\t</build>\n\n</project>\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/XxlJobAdminApplication.java",
    "content": "package com.xxl.job.admin;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * @author xuxueli 2018-10-28 00:38:13\n */\n@SpringBootApplication\npublic class XxlJobAdminApplication {\n\n\tpublic static void main(String[] args) {\n        SpringApplication.run(XxlJobAdminApplication.class, args);\n\t}\n\n}"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/constant/Consts.java",
    "content": "package com.xxl.job.admin.constant;\n\npublic class Consts {\n\n    public static final String ADMIN_ROLE = \"ADMIN\";\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/constant/TriggerStatus.java",
    "content": "package com.xxl.job.admin.constant;\n\npublic enum TriggerStatus {\n\n    STOPPED(0, \"stopped\"),\n    RUNNING(1, \"running\");\n\n    private int value;\n    private String desc;\n\n    TriggerStatus(int value, String desc) {\n        this.value = value;\n        this.desc = desc;\n    }\n\n    public int getValue() {\n        return value;\n    }\n\n    public void setValue(int value) {\n        this.value = value;\n    }\n\n    public String getDesc() {\n        return desc;\n    }\n\n    public void setDesc(String desc) {\n        this.desc = desc;\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/controller/base/IndexController.java",
    "content": "package com.xxl.job.admin.controller.base;\n\nimport com.xxl.job.admin.constant.Consts;\nimport com.xxl.job.admin.model.dto.XxlBootResourceDTO;\nimport com.xxl.job.admin.service.XxlJobService;\nimport com.xxl.job.admin.util.I18nUtil;\nimport com.xxl.sso.core.annotation.XxlSso;\nimport com.xxl.sso.core.helper.XxlSsoHelper;\nimport com.xxl.sso.core.model.LoginInfo;\nimport com.xxl.tool.core.StringTool;\nimport com.xxl.tool.response.Response;\nimport jakarta.annotation.Resource;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.springframework.beans.propertyeditors.CustomDateEditor;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.Model;\nimport org.springframework.web.bind.WebDataBinder;\nimport org.springframework.web.bind.annotation.InitBinder;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.ResponseBody;\nimport org.springframework.web.servlet.ModelAndView;\n\nimport java.text.SimpleDateFormat;\nimport java.util.*;\nimport java.util.stream.Collectors;\n\n/**\n * index controller\n *\n * @author xuxueli 2015-12-19 16:13:16\n */\n@Controller\npublic class IndexController {\n\n\t@Resource\n\tprivate XxlJobService xxlJobService;\n\n\t/**\n\t * index\n\t */\n\t@RequestMapping(\"/\")\n\t@XxlSso\n\tpublic String index(HttpServletRequest request, Model model) {\n\n\t\t// menu resource\n\t\tList<XxlBootResourceDTO> resourceList = findResourceList(request);\n\t\tmodel.addAttribute(\"resourceList\", resourceList);\n\n\t\treturn \"base/index\";\n\t}\n\n\t/**\n\t * fill menu data\n\t */\n\tprivate List<XxlBootResourceDTO> findResourceList(HttpServletRequest request){\n\t\t// login check\n\t\tResponse<LoginInfo> loginInfoResponse = XxlSsoHelper.loginCheckWithAttr(request);\n\t\t// init menu-list\n\t\tList<XxlBootResourceDTO> resourceDTOList = Arrays.asList(\n\t\t\t\tnew XxlBootResourceDTO(1, 0, I18nUtil.getString(\"job_dashboard_name\"),1, \"\", \"/dashboard\", \"fa-home\", 1, 0, null),\n\t\t\t\tnew XxlBootResourceDTO(2, 0, I18nUtil.getString(\"jobinfo_name\"),1, \"\", \"/jobinfo\", \" fa-clock-o\", 2, 0, null),\n\t\t\t\tnew XxlBootResourceDTO(3, 0, I18nUtil.getString(\"joblog_name\"),1, \"\", \"/joblog\", \" fa-database\", 3, 0, null),\n\t\t\t\tnew XxlBootResourceDTO(4, 0, I18nUtil.getString(\"jobgroup_name\"),1, Consts.ADMIN_ROLE, \"/jobgroup\", \" fa-cloud\", 4, 0,null),\n\t\t\t\tnew XxlBootResourceDTO(5, 0, I18nUtil.getString(\"user_manage\"),1, Consts.ADMIN_ROLE, \"/user\", \"fa-users\", 5, 0, null),\n\t\t\t\tnew XxlBootResourceDTO(9, 0, I18nUtil.getString(\"admin_help\"),1, \"\", \"/help\", \"fa-book\", 6, 0, null)\n\t\t);\n\n\t\t// filter by role\n\t\tif (!XxlSsoHelper.hasRole(loginInfoResponse.getData(), Consts.ADMIN_ROLE).isSuccess()) {\n\t\t\tresourceDTOList = resourceDTOList.stream()\n\t\t\t\t\t.filter(resourceDTO -> StringTool.isBlank(resourceDTO.getPermission() ))\t// normal user had no permission\n\t\t\t\t\t.collect(Collectors.toList());\n\t\t}\n\t\tresourceDTOList.stream().sorted(Comparator.comparing(XxlBootResourceDTO::getOrder)).toList();\n\t\treturn resourceDTOList;\n\t}\n\n\t/**\n\t * dashboard\n\t */\n\t@RequestMapping(\"/dashboard\")\n\t@XxlSso\n\tpublic String dashboard(HttpServletRequest request, Model model) {\n\n\t\tMap<String, Object> dashboardMap = xxlJobService.dashboardInfo();\n\t\tmodel.addAllAttributes(dashboardMap);\n\n\t\treturn \"base/dashboard\";\n\t}\n\n\t@RequestMapping(\"/chartInfo\")\n\t@ResponseBody\n\tpublic Response<Map<String, Object>> chartInfo(@RequestParam(\"startDate\") Date startDate, @RequestParam(\"endDate\") Date endDate) {\n\t\tResponse<Map<String, Object>> chartInfo = xxlJobService.chartInfo(startDate, endDate);\n\t\treturn chartInfo;\n\t}\n\n\t/**\n\t * help\n\t */\n\t@RequestMapping(\"/help\")\n\t@XxlSso\n\tpublic String help() {\n\t\treturn \"base/help\";\n\t}\n\n\t@RequestMapping(value = \"/errorpage\")\n\t@XxlSso(login = false)\n\tpublic ModelAndView errorPage(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) {\n\n\t\tString exceptionMsg = \"HTTP Status Code: \"+response.getStatus();\n\n\t\tmv.addObject(\"exceptionMsg\", exceptionMsg);\n\t\tmv.setViewName(\"common/common.errorpage\");\n\t\treturn mv;\n\t}\n\n\t@InitBinder\n\tpublic void initBinder(WebDataBinder binder) {\n\t\tSimpleDateFormat dateFormat = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\");\n\t\tdateFormat.setLenient(false);\n\t\tbinder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));\n\t}\n\t\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/controller/base/LoginController.java",
    "content": "package com.xxl.job.admin.controller.base;\n\nimport com.xxl.job.admin.mapper.XxlJobUserMapper;\nimport com.xxl.job.admin.model.XxlJobUser;\nimport com.xxl.job.admin.util.I18nUtil;\nimport com.xxl.sso.core.annotation.XxlSso;\nimport com.xxl.sso.core.helper.XxlSsoHelper;\nimport com.xxl.sso.core.model.LoginInfo;\nimport com.xxl.tool.core.StringTool;\nimport com.xxl.tool.crypto.Sha256Tool;\nimport com.xxl.tool.id.UUIDTool;\nimport com.xxl.tool.response.Response;\nimport jakarta.annotation.Resource;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.ResponseBody;\nimport org.springframework.web.servlet.ModelAndView;\nimport org.springframework.web.servlet.view.RedirectView;\n\n/**\n * index controller\n * @author xuxueli 2015-12-19 16:13:16\n */\n@Controller\n@RequestMapping(\"/auth\")\npublic class LoginController {\n\n\t@Resource\n\tprivate XxlJobUserMapper xxlJobUserMapper;\n\n\t@RequestMapping(\"/login\")\n\t@XxlSso(login = false)\n\tpublic ModelAndView login(HttpServletRequest request, HttpServletResponse response, ModelAndView modelAndView) {\n\n\t\t// xxl-sso, logincheck\n\t\tResponse<LoginInfo> loginInfoResponse = XxlSsoHelper.loginCheckWithCookie(request, response);\n\n\t\tif (loginInfoResponse.isSuccess()) {\n\t\t\tmodelAndView.setView(new RedirectView(\"/\",true,false));\n\t\t\treturn modelAndView;\n\t\t}\n\t\treturn new ModelAndView(\"base/login\");\n\t}\n\n\t@RequestMapping(value=\"/doLogin\", method=RequestMethod.POST)\n\t@ResponseBody\n\t@XxlSso(login=false)\n\tpublic Response<String> doLogin(HttpServletRequest request, HttpServletResponse response, String userName, String password, String ifRemember){\n\n\t\t// param\n\t\tboolean ifRem = StringTool.isNotBlank(ifRemember) && \"on\".equals(ifRemember);\n\t\tif (StringTool.isBlank(userName) || StringTool.isBlank(password)){\n\t\t\treturn Response.ofFail( I18nUtil.getString(\"login_param_empty\") );\n\t\t}\n\n\t\t// valid user、status\n\t\tXxlJobUser xxlJobUser = xxlJobUserMapper.loadByUserName(userName);\n\t\tif (xxlJobUser == null) {\n\t\t\treturn Response.ofFail( I18nUtil.getString(\"login_param_unvalid\") );\n\t\t}\n\n\t\t// valid passowrd\n\t\tString passwordHash = Sha256Tool.sha256(password);\n\t\tif (!passwordHash.equals(xxlJobUser.getPassword())) {\n\t\t\treturn Response.ofFail( I18nUtil.getString(\"login_param_unvalid\") );\n\t\t}\n\n\t\t// xxl-sso, do login\n\t\tLoginInfo loginInfo = new LoginInfo(String.valueOf(xxlJobUser.getId()), UUIDTool.getSimpleUUID());\n\t\tResponse<String> result= XxlSsoHelper.loginWithCookie(loginInfo, response, ifRem);\n\n\t\treturn Response.of(result.getCode(), result.getMsg());\n\t}\n\t\n\t@RequestMapping(value=\"/logout\", method=RequestMethod.POST)\n\t@ResponseBody\n\t@XxlSso(login=false)\n\tpublic Response<String> logout(HttpServletRequest request, HttpServletResponse response){\n\n\t\t// xxl-sso, do logout\n\t\tResponse<String> result = XxlSsoHelper.logoutWithCookie(request, response);\n\n\t\treturn Response.of(result.getCode(), result.getMsg());\n\t}\n\n\t@RequestMapping(\"/updatePwd\")\n\t@ResponseBody\n\t@XxlSso\n\tpublic Response<String> updatePwd(HttpServletRequest request, String oldPassword, String password){\n\n\t\t// valid\n\t\tif (oldPassword==null || oldPassword.trim().isEmpty()){\n\t\t\treturn Response.ofFail(I18nUtil.getString(\"system_please_input\") + I18nUtil.getString(\"change_pwd_field_oldpwd\"));\n\t\t}\n\t\tif (password==null || password.trim().isEmpty()){\n\t\t\treturn Response.ofFail(I18nUtil.getString(\"system_please_input\") + I18nUtil.getString(\"change_pwd_field_oldpwd\"));\n\t\t}\n\t\tpassword = password.trim();\n\t\tif (!(password.length()>=4 && password.length()<=20)) {\n\t\t\treturn Response.ofFail(I18nUtil.getString(\"system_lengh_limit\")+\"[4-20]\" );\n\t\t}\n\n\t\t// md5 password\n\t\tString oldPasswordHash = Sha256Tool.sha256(oldPassword);\n\t\tString passwordHash = Sha256Tool.sha256(password);\n\n\t\t// valid old pwd\n\t\tResponse<LoginInfo> loginInfoResponse = XxlSsoHelper.loginCheckWithAttr(request);\n\t\tXxlJobUser existUser = xxlJobUserMapper.loadByUserName(loginInfoResponse.getData().getUserName());\n\t\tif (!oldPasswordHash.equals(existUser.getPassword())) {\n\t\t\treturn Response.ofFail(I18nUtil.getString(\"change_pwd_field_oldpwd\") + I18nUtil.getString(\"system_unvalid\"));\n\t\t}\n\n\t\t// write new\n\t\texistUser.setPassword(passwordHash);\n\t\txxlJobUserMapper.update(existUser);\n\n\t\treturn Response.ofSuccess();\n\t}\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/controller/biz/JobCodeController.java",
    "content": "package com.xxl.job.admin.controller.biz;\n\nimport com.xxl.job.admin.mapper.XxlJobInfoMapper;\nimport com.xxl.job.admin.mapper.XxlJobLogGlueMapper;\nimport com.xxl.job.admin.model.XxlJobInfo;\nimport com.xxl.job.admin.model.XxlJobLogGlue;\nimport com.xxl.job.admin.util.I18nUtil;\nimport com.xxl.job.admin.util.JobGroupPermissionUtil;\nimport com.xxl.job.core.glue.GlueTypeEnum;\nimport com.xxl.sso.core.model.LoginInfo;\nimport com.xxl.tool.core.StringTool;\nimport com.xxl.tool.json.GsonTool;\nimport com.xxl.tool.response.Response;\nimport jakarta.annotation.Resource;\nimport jakarta.servlet.http.HttpServletRequest;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.Model;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\nimport java.util.Date;\nimport java.util.List;\n\n/**\n * job code controller\n * @author xuxueli 2015-12-19 16:13:16\n */\n@Controller\n@RequestMapping(\"/jobcode\")\npublic class JobCodeController {\n\tprivate static final Logger logger = LoggerFactory.getLogger(JobCodeController.class);\n\t\n\t@Resource\n\tprivate XxlJobInfoMapper xxlJobInfoMapper;\n\t@Resource\n\tprivate XxlJobLogGlueMapper xxlJobLogGlueMapper;\n\n\t@RequestMapping\n\tpublic String index(HttpServletRequest request, Model model, @RequestParam(\"jobId\") int jobId) {\n\t\tXxlJobInfo jobInfo = xxlJobInfoMapper.loadById(jobId);\n\t\tList<XxlJobLogGlue> jobLogGlues = xxlJobLogGlueMapper.findByJobId(jobId);\n\n\t\tif (jobInfo == null) {\n\t\t\tthrow new RuntimeException(I18nUtil.getString(\"jobinfo_glue_jobid_unvalid\"));\n\t\t}\n\t\tif (GlueTypeEnum.BEAN == GlueTypeEnum.match(jobInfo.getGlueType())) {\n\t\t\tthrow new RuntimeException(I18nUtil.getString(\"jobinfo_glue_gluetype_unvalid\"));\n\t\t}\n\n\t\t// valid jobGroup permission\n\t\tJobGroupPermissionUtil.validJobGroupPermission(request, jobInfo.getJobGroup());\n\n\t\t// Glue类型-字典\n\t\tmodel.addAttribute(\"GlueTypeEnum\", GlueTypeEnum.values());\n\n\t\tmodel.addAttribute(\"jobInfo\", jobInfo);\n\t\tmodel.addAttribute(\"jobLogGlues\", jobLogGlues);\n\t\treturn \"biz/job.code\";\n\t}\n\t\n\t@RequestMapping(\"/save\")\n\t@ResponseBody\n\tpublic Response<String> save(HttpServletRequest request,\n\t\t\t\t\t\t\t\t @RequestParam(\"id\") int id,\n\t\t\t\t\t\t\t\t @RequestParam(\"glueSource\") String glueSource,\n\t\t\t\t\t\t\t\t @RequestParam(\"glueRemark\") String glueRemark) {\n\n\t\t// valid\n\t\tif (StringTool.isBlank(glueSource)) {\n\t\t\treturn Response.ofFail( (I18nUtil.getString(\"system_please_input\") + I18nUtil.getString(\"jobinfo_glue_source\")) );\n\t\t}\n\t\tif (glueRemark==null) {\n\t\t\treturn Response.ofFail( (I18nUtil.getString(\"system_please_input\") + I18nUtil.getString(\"jobinfo_glue_remark\")) );\n\t\t}\n\t\tif (glueRemark.length()<4 || glueRemark.length()>100) {\n\t\t\treturn Response.ofFail(I18nUtil.getString(\"jobinfo_glue_remark_limit\"));\n\t\t}\n\t\tXxlJobInfo existsJobInfo = xxlJobInfoMapper.loadById(id);\n\t\tif (existsJobInfo == null) {\n\t\t\treturn Response.ofFail( I18nUtil.getString(\"jobinfo_glue_jobid_unvalid\"));\n\t\t}\n\n\t\t// valid jobGroup permission\n\t\tLoginInfo loginInfo = JobGroupPermissionUtil.validJobGroupPermission(request, existsJobInfo.getJobGroup());\n\n\t\t// update new code\n\t\texistsJobInfo.setGlueSource(glueSource);\n\t\texistsJobInfo.setGlueRemark(glueRemark);\n\t\texistsJobInfo.setGlueUpdatetime(new Date());\n\n\t\texistsJobInfo.setUpdateTime(new Date());\n\t\txxlJobInfoMapper.update(existsJobInfo);\n\n\t\t// log old code\n\t\tXxlJobLogGlue xxlJobLogGlue = new XxlJobLogGlue();\n\t\txxlJobLogGlue.setJobId(existsJobInfo.getId());\n\t\txxlJobLogGlue.setGlueType(existsJobInfo.getGlueType());\n\t\txxlJobLogGlue.setGlueSource(glueSource);\n\t\txxlJobLogGlue.setGlueRemark(glueRemark);\n\n\t\txxlJobLogGlue.setAddTime(new Date());\n\t\txxlJobLogGlue.setUpdateTime(new Date());\n\t\txxlJobLogGlueMapper.save(xxlJobLogGlue);\n\n\t\t// remove code backup more than 30\n\t\txxlJobLogGlueMapper.removeOld(existsJobInfo.getId(), 30);\n\n\t\t// write operation log\n\t\tlogger.info(\">>>>>>>>>>> xxl-job operation log: operator = {}, type = {}, content = {}\",\n\t\t\t\tloginInfo.getUserName(), \"jobcode-update\", GsonTool.toJson(xxlJobLogGlue));\n\t\treturn Response.ofSuccess();\n\t}\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/controller/biz/JobGroupController.java",
    "content": "package com.xxl.job.admin.controller.biz;\n\nimport com.xxl.job.admin.constant.Consts;\nimport com.xxl.job.admin.model.XxlJobGroup;\nimport com.xxl.job.admin.model.XxlJobRegistry;\nimport com.xxl.job.admin.util.I18nUtil;\nimport com.xxl.job.admin.mapper.XxlJobGroupMapper;\nimport com.xxl.job.admin.mapper.XxlJobInfoMapper;\nimport com.xxl.job.admin.mapper.XxlJobRegistryMapper;\nimport com.xxl.job.core.constant.Const;\nimport com.xxl.job.core.constant.RegistType;\nimport com.xxl.sso.core.annotation.XxlSso;\nimport com.xxl.tool.core.CollectionTool;\nimport com.xxl.tool.core.StringTool;\nimport com.xxl.tool.http.HttpTool;\nimport com.xxl.tool.response.PageModel;\nimport com.xxl.tool.response.Response;\nimport jakarta.annotation.Resource;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.Model;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\nimport java.util.*;\n\n/**\n * job group controller\n * @author xuxueli 2016-10-02 20:52:56\n */\n@Controller\n@RequestMapping(\"/jobgroup\")\npublic class JobGroupController {\n\n\t@Resource\n\tpublic XxlJobInfoMapper xxlJobInfoMapper;\n\t@Resource\n\tpublic XxlJobGroupMapper xxlJobGroupMapper;\n\t@Resource\n\tprivate XxlJobRegistryMapper xxlJobRegistryMapper;\n\n\t@RequestMapping\n\t@XxlSso(role = Consts.ADMIN_ROLE)\n\tpublic String index(Model model) {\n\t\treturn \"biz/group.list\";\n\t}\n\n\t@RequestMapping(\"/pageList\")\n\t@ResponseBody\n\t@XxlSso(role = Consts.ADMIN_ROLE)\n\tpublic Response<PageModel<XxlJobGroup>> pageList(@RequestParam(required = false, defaultValue = \"0\") int offset,\n\t\t\t\t\t\t\t\t\t\t\t\t\t @RequestParam(required = false, defaultValue = \"10\") int pagesize,\n\t\t\t\t\t\t\t\t\t\t\t\t\t String appname,\n\t\t\t\t\t\t\t\t\t\t\t\t\t String title) {\n\n\t\t// page query\n\t\tList<XxlJobGroup> list = xxlJobGroupMapper.pageList(offset, pagesize, appname, title);\n\t\tint list_count = xxlJobGroupMapper.pageListCount(offset, pagesize, appname, title);\n\n\t\t// package result\n\t\tPageModel<XxlJobGroup> pageModel = new PageModel<>();\n\t\tpageModel.setData(list);\n\t\tpageModel.setTotal(list_count);\n\n\t\treturn Response.ofSuccess(pageModel);\n\t}\n\n\t@RequestMapping(\"/insert\")\n\t@ResponseBody\n\t@XxlSso(role = Consts.ADMIN_ROLE)\n\tpublic Response<String> insert(XxlJobGroup xxlJobGroup){\n\n\t\t// valid\n\t\tif (StringTool.isBlank(xxlJobGroup.getAppname())) {\n\t\t\treturn Response.ofFail((I18nUtil.getString(\"system_please_input\")+\"AppName\") );\n\t\t}\n\t\tif (xxlJobGroup.getAppname().length()<4 || xxlJobGroup.getAppname().length()>64) {\n\t\t\treturn Response.ofFail( I18nUtil.getString(\"jobgroup_field_appname_length\") );\n\t\t}\n\t\tif (xxlJobGroup.getAppname().contains(\">\") || xxlJobGroup.getAppname().contains(\"<\")) {\n\t\t\treturn Response.ofFail( \"AppName\"+I18nUtil.getString(\"system_unvalid\") );\n\t\t}\n\t\tif (StringTool.isBlank(xxlJobGroup.getTitle())) {\n\t\t\treturn Response.ofFail((I18nUtil.getString(\"system_please_input\") + I18nUtil.getString(\"jobgroup_field_title\")) );\n\t\t}\n\t\tif (xxlJobGroup.getTitle().contains(\">\") || xxlJobGroup.getTitle().contains(\"<\")) {\n\t\t\treturn Response.ofFail(I18nUtil.getString(\"jobgroup_field_title\")+I18nUtil.getString(\"system_unvalid\") );\n\t\t}\n\t\tif (xxlJobGroup.getAddressType()!=0) {\n\t\t\tif (StringTool.isBlank(xxlJobGroup.getAddressList())) {\n\t\t\t\treturn Response.ofFail( I18nUtil.getString(\"jobgroup_field_addressType_limit\") );\n\t\t\t}\n\t\t\tif (xxlJobGroup.getAddressList().contains(\">\") || xxlJobGroup.getAddressList().contains(\"<\")) {\n\t\t\t\treturn Response.ofFail(I18nUtil.getString(\"jobgroup_field_registryList\")+I18nUtil.getString(\"system_unvalid\") );\n\t\t\t}\n\n\t\t\tString[] addresss = xxlJobGroup.getAddressList().split(\",\");\n\t\t\tfor (String item: addresss) {\n\t\t\t\tif (StringTool.isBlank(item)) {\n\t\t\t\t\treturn Response.ofFail( I18nUtil.getString(\"jobgroup_field_registryList_unvalid\") );\n\t\t\t\t}\n                if (!(HttpTool.isHttp(item) || HttpTool.isHttps(item))) {\n                    return Response.ofFail( I18nUtil.getString(\"jobgroup_field_registryList_unvalid\")+\"[2]\" );\n                }\n\t\t\t}\n\t\t}\n\n\t\t// process\n\t\txxlJobGroup.setUpdateTime(new Date());\n\n\t\tint ret = xxlJobGroupMapper.save(xxlJobGroup);\n\t\treturn (ret>0)?Response.ofSuccess():Response.ofFail();\n\t}\n\n\t@RequestMapping(\"/update\")\n\t@ResponseBody\n\t@XxlSso(role = Consts.ADMIN_ROLE)\n\tpublic Response<String> update(XxlJobGroup xxlJobGroup){\n\t\t// valid\n\t\tif (StringTool.isBlank(xxlJobGroup.getAppname())) {\n\t\t\treturn Response.ofFail((I18nUtil.getString(\"system_please_input\")+\"AppName\") );\n\t\t}\n\t\tif (xxlJobGroup.getAppname().length()<4 || xxlJobGroup.getAppname().length()>64) {\n\t\t\treturn Response.ofFail( I18nUtil.getString(\"jobgroup_field_appname_length\") );\n\t\t}\n\t\tif (StringTool.isBlank(xxlJobGroup.getTitle())) {\n\t\t\treturn Response.ofFail( (I18nUtil.getString(\"system_please_input\") + I18nUtil.getString(\"jobgroup_field_title\")) );\n\t\t}\n\t\tif (xxlJobGroup.getAddressType() == 0) {\n\t\t\t// 0=自动注册\n\t\t\tList<String> registryList = findRegistryByAppName(xxlJobGroup.getAppname());\n\t\t\tString addressListStr = null;\n\t\t\tif (CollectionTool.isNotEmpty(registryList)) {\n\t\t\t\tCollections.sort(registryList);\n\t\t\t\taddressListStr = String.join(\",\", registryList);\n\t\t\t}\n\t\t\txxlJobGroup.setAddressList(addressListStr);\n\t\t} else {\n\t\t\t// 1=手动录入\n\t\t\tif (StringTool.isBlank(xxlJobGroup.getAddressList())) {\n\t\t\t\treturn Response.ofFail( I18nUtil.getString(\"jobgroup_field_addressType_limit\") );\n\t\t\t}\n\t\t\tString[] addresss = xxlJobGroup.getAddressList().split(\",\");\n\t\t\tfor (String item: addresss) {\n\t\t\t\tif (StringTool.isBlank(item)) {\n\t\t\t\t\treturn Response.ofFail(I18nUtil.getString(\"jobgroup_field_registryList_unvalid\") );\n\t\t\t\t}\n                if (!(HttpTool.isHttp(item) || HttpTool.isHttps(item))) {\n                    return Response.ofFail( I18nUtil.getString(\"jobgroup_field_registryList_unvalid\")+\"[2]\" );\n                }\n\t\t\t}\n\t\t}\n\n\t\t// process\n\t\txxlJobGroup.setUpdateTime(new Date());\n\n\t\tint ret = xxlJobGroupMapper.update(xxlJobGroup);\n\t\treturn (ret>0)?Response.ofSuccess():Response.ofFail();\n\t}\n\n\tprivate List<String> findRegistryByAppName(String appnameParam){\n\t\tHashMap<String, List<String>> appAddressMap = new HashMap<>();\n\t\tList<XxlJobRegistry> list = xxlJobRegistryMapper.findAll(Const.DEAD_TIMEOUT, new Date());\n\t\tif (CollectionTool.isNotEmpty(list)) {\n\t\t\tfor (XxlJobRegistry item: list) {\n\t\t\t\tif (!RegistType.EXECUTOR.name().equals(item.getRegistryGroup())) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tString appname = item.getRegistryKey();\n                List<String> registryList = appAddressMap.computeIfAbsent(appname, k -> new ArrayList<>());\n\n                if (!registryList.contains(item.getRegistryValue())) {\n\t\t\t\t\tregistryList.add(item.getRegistryValue());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn appAddressMap.get(appnameParam);\n\t}\n\n\t@RequestMapping(\"/delete\")\n\t@ResponseBody\n\t@XxlSso(role = Consts.ADMIN_ROLE)\n\tpublic Response<String> delete(@RequestParam(\"ids[]\") List<Integer> ids){\n\n\t\t// parse id\n\t\tif (CollectionTool.isEmpty(ids) || ids.size()!=1) {\n\t\t\treturn Response.ofFail(I18nUtil.getString(\"system_please_choose\") + I18nUtil.getString(\"system_one\") + I18nUtil.getString(\"system_data\"));\n\t\t}\n\t\tint id = ids.get(0);\n\n        // valid repeat operation\n        XxlJobGroup xxlJobGroup = xxlJobGroupMapper.load(id);\n        if (xxlJobGroup == null) {\n            return Response.ofSuccess();\n        }\n\n\t\t// whether exists job\n\t\tint count = xxlJobInfoMapper.pageListCount(0, 10, id, -1,  null, null, null);\n\t\tif (count > 0) {\n\t\t\treturn Response.ofFail( I18nUtil.getString(\"jobgroup_del_limit_0\") );\n\t\t}\n\n        // whether only exists one group\n\t\tList<XxlJobGroup> allList = xxlJobGroupMapper.findAll();\n\t\tif (allList.size() == 1) {\n\t\t\treturn Response.ofFail( I18nUtil.getString(\"jobgroup_del_limit_1\") );\n\t\t}\n\n        // remove group\n\t\tint ret = xxlJobGroupMapper.remove(id);\n        // remove registry-data\n        xxlJobRegistryMapper.removeByRegistryGroupAndKey(RegistType.EXECUTOR.name(), xxlJobGroup.getAppname());\n\t\treturn (ret>0)?Response.ofSuccess():Response.ofFail();\n\t}\n\n\t@RequestMapping(\"/loadById\")\n\t@ResponseBody\n\t//@XxlSso(role = Consts.ADMIN_ROLE)\t\t// open to default user, support show registry nodes\n\tpublic Response<XxlJobGroup> loadById(@RequestParam(\"id\") int id){\n\t\tXxlJobGroup jobGroup = xxlJobGroupMapper.load(id);\n\t\treturn jobGroup!=null?Response.ofSuccess(jobGroup):Response.ofFail();\n\t}\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/controller/biz/JobInfoController.java",
    "content": "package com.xxl.job.admin.controller.biz;\n\nimport com.xxl.job.admin.mapper.XxlJobGroupMapper;\nimport com.xxl.job.admin.model.XxlJobGroup;\nimport com.xxl.job.admin.model.XxlJobInfo;\nimport com.xxl.job.admin.scheduler.exception.XxlJobException;\nimport com.xxl.job.admin.scheduler.misfire.MisfireStrategyEnum;\nimport com.xxl.job.admin.scheduler.route.ExecutorRouteStrategyEnum;\nimport com.xxl.job.admin.scheduler.type.ScheduleTypeEnum;\nimport com.xxl.job.admin.service.XxlJobService;\nimport com.xxl.job.admin.util.I18nUtil;\nimport com.xxl.job.admin.util.JobGroupPermissionUtil;\nimport com.xxl.job.core.constant.ExecutorBlockStrategyEnum;\nimport com.xxl.job.core.glue.GlueTypeEnum;\nimport com.xxl.sso.core.helper.XxlSsoHelper;\nimport com.xxl.sso.core.model.LoginInfo;\nimport com.xxl.tool.core.CollectionTool;\nimport com.xxl.tool.core.DateTool;\nimport com.xxl.tool.core.StringTool;\nimport com.xxl.tool.response.PageModel;\nimport com.xxl.tool.response.Response;\nimport jakarta.annotation.Resource;\nimport jakarta.servlet.http.HttpServletRequest;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.Model;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.List;\n\n/**\n * index controller\n * @author xuxueli 2015-12-19 16:13:16\n */\n@Controller\n@RequestMapping(\"/jobinfo\")\npublic class JobInfoController {\n\tprivate static Logger logger = LoggerFactory.getLogger(JobInfoController.class);\n\n\t@Resource\n\tprivate XxlJobGroupMapper xxlJobGroupMapper;\n\t@Resource\n\tprivate XxlJobService xxlJobService;\n\t\n\t@RequestMapping\n\tpublic String index(HttpServletRequest request, Model model, @RequestParam(value = \"jobGroup\", required = false, defaultValue = \"-1\") int jobGroup) {\n\n\t\t// 枚举-字典\n\t\tmodel.addAttribute(\"ExecutorRouteStrategyEnum\", ExecutorRouteStrategyEnum.values());\t    // 路由策略-列表\n\t\tmodel.addAttribute(\"GlueTypeEnum\", GlueTypeEnum.values());\t\t\t\t\t\t\t\t// Glue类型-字典\n\t\tmodel.addAttribute(\"ExecutorBlockStrategyEnum\", ExecutorBlockStrategyEnum.values());\t    // 阻塞处理策略-字典\n\t\tmodel.addAttribute(\"ScheduleTypeEnum\", ScheduleTypeEnum.values());\t    \t\t\t\t// 调度类型\n\t\tmodel.addAttribute(\"MisfireStrategyEnum\", MisfireStrategyEnum.values());\t    \t\t\t// 调度过期策略\n\n\t\t// 执行器列表\n\t\tList<XxlJobGroup> jobGroupListTotal =  xxlJobGroupMapper.findAll();\n\n\t\t// filter group\n\t\tList<XxlJobGroup> jobGroupList = JobGroupPermissionUtil.filterJobGroupByPermission(request, jobGroupListTotal);\n\t\tif (CollectionTool.isEmpty(jobGroupList)) {\n\t\t\tthrow new XxlJobException(I18nUtil.getString(\"jobgroup_empty\"));\n\t\t}\n\n\t\t// parse jobGroup\n\t\tif (!(CollectionTool.isNotEmpty(jobGroupList)\n\t\t\t\t&& jobGroupList.stream().map(XxlJobGroup::getId).toList().contains(jobGroup))) {\n\t\t\tjobGroup = -1;\n\t\t}\n\n\t\tmodel.addAttribute(\"JobGroupList\", jobGroupList);\n\t\tmodel.addAttribute(\"jobGroup\", jobGroup);\n\n\t\treturn \"biz/job.list\";\n\t}\n\n\t@RequestMapping(\"/pageList\")\n\t@ResponseBody\n\tpublic Response<PageModel<XxlJobInfo>> pageList(HttpServletRequest request,\n\t\t\t\t\t\t\t\t\t\t\t\t\t@RequestParam(required = false, defaultValue = \"0\") int offset,\n\t\t\t\t\t\t\t\t\t\t\t\t\t@RequestParam(required = false, defaultValue = \"10\") int pagesize,\n\t\t\t\t\t\t\t\t\t\t\t\t\t@RequestParam int jobGroup,\n\t\t\t\t\t\t\t\t\t\t\t\t\t@RequestParam int triggerStatus,\n\t\t\t\t\t\t\t\t\t\t\t\t\t@RequestParam String jobDesc,\n\t\t\t\t\t\t\t\t\t\t\t\t\t@RequestParam String executorHandler,\n\t\t\t\t\t\t\t\t\t\t\t\t\t@RequestParam String author) {\n\n\t\t// valid jobGroup permission\n\t\tJobGroupPermissionUtil.validJobGroupPermission(request, jobGroup);\n\n\t\t// page\n\t\treturn xxlJobService.pageList(offset, pagesize, jobGroup, triggerStatus, jobDesc, executorHandler, author);\n\t}\n\t\n\t@RequestMapping(\"/insert\")\n\t@ResponseBody\n\tpublic Response<String> add(HttpServletRequest request, XxlJobInfo jobInfo) {\n\t\t// valid permission\n\t\tLoginInfo loginInfo = JobGroupPermissionUtil.validJobGroupPermission(request, jobInfo.getJobGroup());\n\n\t\t// opt\n\t\treturn xxlJobService.add(jobInfo, loginInfo);\n\t}\n\n\t@RequestMapping(\"/update\")\n\t@ResponseBody\n\tpublic Response<String> update(HttpServletRequest request, XxlJobInfo jobInfo) {\n\t\t// valid permission\n\t\tLoginInfo loginInfo = JobGroupPermissionUtil.validJobGroupPermission(request, jobInfo.getJobGroup());\n\n\t\t// opt\n\t\treturn xxlJobService.update(jobInfo, loginInfo);\n\t}\n\t\n\t@RequestMapping(\"/delete\")\n\t@ResponseBody\n\tpublic Response<String> delete(HttpServletRequest request, @RequestParam(\"ids[]\") List<Integer> ids) {\n\n\t\t// valid\n\t\tif (CollectionTool.isEmpty(ids) || ids.size()!=1) {\n\t\t\treturn Response.ofFail(I18nUtil.getString(\"system_please_choose\") + I18nUtil.getString(\"system_one\") + I18nUtil.getString(\"system_data\"));\n\t\t}\n\n\t\t// invoke\n\t\tResponse<LoginInfo> loginInfoResponse = XxlSsoHelper.loginCheckWithAttr(request);\n\t\treturn xxlJobService.remove(ids.get(0), loginInfoResponse.getData());\n\t}\n\t\n\t@RequestMapping(\"/stop\")\n\t@ResponseBody\n\tpublic Response<String> pause(HttpServletRequest request, @RequestParam(\"ids[]\") List<Integer> ids) {\n\n\t\t// valid\n\t\tif (CollectionTool.isEmpty(ids) || ids.size()!=1) {\n\t\t\treturn Response.ofFail(I18nUtil.getString(\"system_please_choose\") + I18nUtil.getString(\"system_one\") + I18nUtil.getString(\"system_data\"));\n\t\t}\n\n\t\t// invoke\n\t\tResponse<LoginInfo> loginInfoResponse = XxlSsoHelper.loginCheckWithAttr(request);\n\t\treturn xxlJobService.stop(ids.get(0), loginInfoResponse.getData());\n\t}\n\t\n\t@RequestMapping(\"/start\")\n\t@ResponseBody\n\tpublic Response<String> start(HttpServletRequest request, @RequestParam(\"ids[]\") List<Integer> ids) {\n\n\t\t// valid\n\t\tif (CollectionTool.isEmpty(ids) || ids.size()!=1) {\n\t\t\treturn Response.ofFail(I18nUtil.getString(\"system_please_choose\") + I18nUtil.getString(\"system_one\") + I18nUtil.getString(\"system_data\"));\n\t\t}\n\n\t\t// invoke\n\t\tResponse<LoginInfo> loginInfoResponse = XxlSsoHelper.loginCheckWithAttr(request);\n\t\treturn xxlJobService.start(ids.get(0), loginInfoResponse.getData());\n\t}\n\t\n\t@RequestMapping(\"/trigger\")\n\t@ResponseBody\n\tpublic Response<String> triggerJob(HttpServletRequest request,\n\t\t\t\t\t\t\t\t\t  @RequestParam(\"id\") int id,\n\t\t\t\t\t\t\t\t\t  @RequestParam(\"executorParam\") String executorParam,\n\t\t\t\t\t\t\t\t\t  @RequestParam(\"addressList\") String addressList) {\n\t\tResponse<LoginInfo> loginInfoResponse = XxlSsoHelper.loginCheckWithAttr(request);\n\t\treturn xxlJobService.trigger(loginInfoResponse.getData(), id, executorParam, addressList);\n\t}\n\n\t@RequestMapping(\"/nextTriggerTime\")\n\t@ResponseBody\n\tpublic Response<List<String>> nextTriggerTime(@RequestParam(\"scheduleType\") String scheduleType,\n\t\t\t\t\t\t\t\t\t\t\t\t @RequestParam(\"scheduleConf\") String scheduleConf) {\n\n\t\t// valid\n\t\tif (StringTool.isBlank(scheduleType) || StringTool.isBlank(scheduleConf)) {\n\t\t\treturn Response.ofSuccess(new ArrayList<>());\n\t\t}\n\n\t\t// param\n\t\tXxlJobInfo paramXxlJobInfo = new XxlJobInfo();\n\t\tparamXxlJobInfo.setScheduleType(scheduleType);\n\t\tparamXxlJobInfo.setScheduleConf(scheduleConf);\n\n\t\t// generate\n\t\tList<String> result = new ArrayList<>();\n\t\ttry {\n\t\t\tDate lastTime = new Date();\n\t\t\tfor (int i = 0; i < 5; i++) {\n\n\t\t\t\t// generate next trigger time\n\t\t\t\tScheduleTypeEnum scheduleTypeEnum = ScheduleTypeEnum.match(paramXxlJobInfo.getScheduleType(), ScheduleTypeEnum.NONE);\n\t\t\t\tlastTime = scheduleTypeEnum.getScheduleType().generateNextTriggerTime(paramXxlJobInfo, lastTime);\n\n\t\t\t\t// collect data\n\t\t\t\tif (lastTime != null) {\n\t\t\t\t\tresult.add(DateTool.formatDateTime(lastTime));\n\t\t\t\t} else {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\tlogger.error(\">>>>>>>>>>> nextTriggerTime error. scheduleType = {}, scheduleConf= {}, error:{} \", scheduleType, scheduleConf, e.getMessage());\n\t\t\treturn Response.ofFail((I18nUtil.getString(\"schedule_type\")+I18nUtil.getString(\"system_unvalid\")) + e.getMessage());\n\t\t}\n\t\treturn Response.ofSuccess(result);\n\n\t}\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/controller/biz/JobLogController.java",
    "content": "package com.xxl.job.admin.controller.biz;\n\nimport com.xxl.job.admin.mapper.XxlJobGroupMapper;\nimport com.xxl.job.admin.mapper.XxlJobInfoMapper;\nimport com.xxl.job.admin.mapper.XxlJobLogMapper;\nimport com.xxl.job.admin.model.XxlJobGroup;\nimport com.xxl.job.admin.model.XxlJobInfo;\nimport com.xxl.job.admin.model.XxlJobLog;\nimport com.xxl.job.admin.scheduler.config.XxlJobAdminBootstrap;\nimport com.xxl.job.admin.scheduler.exception.XxlJobException;\nimport com.xxl.job.admin.service.XxlJobService;\nimport com.xxl.job.admin.util.I18nUtil;\nimport com.xxl.job.admin.util.JobGroupPermissionUtil;\nimport com.xxl.job.core.context.XxlJobContext;\nimport com.xxl.job.core.openapi.ExecutorBiz;\nimport com.xxl.job.core.openapi.model.KillRequest;\nimport com.xxl.job.core.openapi.model.LogRequest;\nimport com.xxl.job.core.openapi.model.LogResult;\nimport com.xxl.tool.core.CollectionTool;\nimport com.xxl.tool.core.DateTool;\nimport com.xxl.tool.core.StringTool;\nimport com.xxl.tool.response.PageModel;\nimport com.xxl.tool.response.Response;\nimport jakarta.annotation.Resource;\nimport jakarta.servlet.http.HttpServletRequest;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.Model;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.ResponseBody;\nimport org.springframework.web.util.HtmlUtils;\n\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * index controller\n * @author xuxueli 2015-12-19 16:13:16\n */\n@Controller\n@RequestMapping(\"/joblog\")\npublic class JobLogController {\n\tprivate static final Logger logger = LoggerFactory.getLogger(JobLogController.class);\n\n\t@Resource\n\tprivate XxlJobGroupMapper xxlJobGroupMapper;\n\t@Resource\n\tpublic XxlJobInfoMapper xxlJobInfoMapper;\n\t@Resource\n\tpublic XxlJobLogMapper xxlJobLogMapper;\n    @Autowired\n    private XxlJobService xxlJobService;\n\n\t@RequestMapping\n\tpublic String index(HttpServletRequest request,\n\t\t\t\t\t\tModel model,\n\t\t\t\t\t\t@RequestParam(value = \"jobGroup\", required = false, defaultValue = \"0\") Integer jobGroup,\n\t\t\t\t\t\t@RequestParam(value = \"jobId\", required = false, defaultValue = \"0\") Integer jobId) {\n\n\t\t// find all jobGroup\n\t\tList<XxlJobGroup> jobGroupListTotal =  xxlJobGroupMapper.findAll();\n\n\t\t// filter JobGroupList\n\t\tList<XxlJobGroup> jobGroupList = JobGroupPermissionUtil.filterJobGroupByPermission(request, jobGroupListTotal);\n\t\tif (CollectionTool.isEmpty(jobGroupList)) {\n\t\t\tthrow new XxlJobException(I18nUtil.getString(\"jobgroup_empty\"));\n\t\t}\n\n\t\t// parse jobGroup\n\t\tif (jobId > 0) {\n\t\t\t// assign jobId (+ jobGroup)\n\t\t\tXxlJobInfo jobInfo = xxlJobInfoMapper.loadById(jobId);\n\t\t\tif (jobInfo == null) {\n\t\t\t\t// jobId not exist, inteceptor\n\t\t\t\tthrow new RuntimeException(I18nUtil.getString(\"jobinfo_field_id\") + I18nUtil.getString(\"system_unvalid\"));\n\t\t\t}\n\t\t\tjobGroup = jobInfo.getJobGroup();\n\t\t} else if (jobGroup > 0) {\n\t\t\t// assign jobGroup\n\t\t\tInteger finalJobGroup = jobGroup;\n\t\t\tif (CollectionTool.isEmpty(jobGroupListTotal.stream().filter(item -> item.getId() == finalJobGroup).toList())) {\n\t\t\t\t// jobGroup not exist, use first\n\t\t\t\tjobGroup = jobGroupList.get(0).getId();\n\t\t\t}\n\t\t\tjobId = 0;\n\t\t} else {\n\t\t\t// default first valid jobGroup\n\t\t\tjobGroup = jobGroupList.get(0).getId();\n\t\t\tjobId = 0;\n\t\t}\n\n\t\t/*// valid permission\n\t\tJobGroupPermissionUtil.validJobGroupPermission(request, jobGroup);*/\n\n\t\t// find jobList\n\t\tList<XxlJobInfo> jobInfoList = xxlJobInfoMapper.getJobsByGroup(jobGroup);\n\n\t\t// parse jobId\n\t\tif (CollectionTool.isEmpty(jobInfoList)) {\n\t\t\tjobId = 0;\n\t\t} else {\n\t\t\tif (!jobInfoList.stream().map(XxlJobInfo::getId).toList().contains(jobId)) {\n\t\t\t\t// jobId not exist, use first\n\t\t\t\tjobId = jobInfoList.get(0).getId();\n\t\t\t}\n\t\t}\n\n\t\t// write\n\t\tmodel.addAttribute(\"JobGroupList\", jobGroupList);\n\t\tmodel.addAttribute(\"jobInfoList\", jobInfoList);\n\t\tmodel.addAttribute(\"jobGroup\", jobGroup);\n\t\tmodel.addAttribute(\"jobId\", jobId);\n\n\t\treturn \"biz/log.list\";\n\t}\n\t\n\t@RequestMapping(\"/pageList\")\n\t@ResponseBody\n\tpublic Response<PageModel<XxlJobLog>> pageList(HttpServletRequest request,\n\t\t\t\t\t\t\t\t\t\t@RequestParam(required = false, defaultValue = \"0\") int offset,\n\t\t\t\t\t\t\t\t\t\t@RequestParam(required = false, defaultValue = \"10\") int pagesize,\n\t\t\t\t\t\t\t\t\t\t@RequestParam int jobGroup,\n\t\t\t\t\t\t\t\t\t\t@RequestParam int jobId,\n\t\t\t\t\t\t\t\t\t\t@RequestParam int logStatus,\n\t\t\t\t\t\t\t\t\t\t@RequestParam String filterTime) {\n\n\t\t// valid jobGroup permission\n\t\tJobGroupPermissionUtil.validJobGroupPermission(request, jobGroup);\n\n\t\t// valid jobId\n\t\tif (jobId < 1) {\n\t\t\treturn Response.ofFail(I18nUtil.getString(\"system_please_choose\") + I18nUtil.getString(\"jobinfo_job\"));\n\t\t}\n\n\t\t// parse param\n\t\tDate triggerTimeStart = null;\n\t\tDate triggerTimeEnd = null;\n\t\tif (StringTool.isNotBlank(filterTime)) {\n\t\t\tString[] temp = filterTime.split(\" - \");\n\t\t\tif (temp.length == 2) {\n\t\t\t\ttriggerTimeStart = DateTool.parseDateTime(temp[0]);\n\t\t\t\ttriggerTimeEnd = DateTool.parseDateTime(temp[1]);\n\t\t\t}\n\t\t}\n\t\t\n\t\t// page query\n\t\tList<XxlJobLog> list = xxlJobLogMapper.pageList(offset, pagesize, jobGroup, jobId, triggerTimeStart, triggerTimeEnd, logStatus);\n\t\tint list_count = xxlJobLogMapper.pageListCount(offset, pagesize, jobGroup, jobId, triggerTimeStart, triggerTimeEnd, logStatus);\n\n\t\t// package result\n\t\tPageModel<XxlJobLog> pageModel = new PageModel<>();\n\t\tpageModel.setData(list);\n\t\tpageModel.setTotal(list_count);\n\n\t\treturn Response.ofSuccess(pageModel);\n\t}\n\n\t/**\n\t * filter xss tag\n\t */\n\tprivate String filter(String originData){\n\n\t\t// exclude tag\n\t\tMap<String, String> excludeTagMap = new HashMap<String, String>();\n\t\texcludeTagMap.put(\"<br>\", \"###TAG_BR###\");\n\t\texcludeTagMap.put(\"<b>\", \"###TAG_BOLD###\");\n\t\texcludeTagMap.put(\"</b>\", \"###TAG_BOLD_END###\");\n\n\t\t// replace\n\t\tfor (String key : excludeTagMap.keySet()) {\n\t\t\tString value = excludeTagMap.get(key);\n\t\t\toriginData = originData.replaceAll(key, value);\n\t\t}\n\n\t\t// htmlEscape\n\t\toriginData = HtmlUtils.htmlEscape(originData, \"UTF-8\");\n\n\t\t// replace back\n\t\tfor (String key : excludeTagMap.keySet()) {\n\t\t\tString value = excludeTagMap.get(key);\n\t\t\toriginData = originData.replaceAll(value, key);\n\t\t}\n\n\t\treturn originData;\n\t}\n\n\t@RequestMapping(\"/logKill\")\n\t@ResponseBody\n\tpublic Response<String> logKill(HttpServletRequest request, @RequestParam(\"id\") long id){\n\t\t// base check\n\t\tXxlJobLog log = xxlJobLogMapper.load(id);\n\t\tXxlJobInfo jobInfo = xxlJobInfoMapper.loadById(log.getJobId());\n\t\tif (jobInfo==null) {\n\t\t\treturn Response.ofFail(I18nUtil.getString(\"jobinfo_glue_jobid_unvalid\"));\n\t\t}\n\t\tif (XxlJobContext.HANDLE_CODE_SUCCESS != log.getTriggerCode()) {\n\t\t\treturn Response.ofFail( I18nUtil.getString(\"joblog_kill_log_limit\"));\n\t\t}\n\n\t\t// valid JobGroup permission\n\t\tJobGroupPermissionUtil.validJobGroupPermission(request, jobInfo.getJobGroup());\n\n\t\t// request of kill\n\t\tResponse<String> runResult = null;\n\t\ttry {\n\t\t\tExecutorBiz executorBiz = XxlJobAdminBootstrap.getExecutorBiz(log.getExecutorAddress());\n\t\t\trunResult = executorBiz.kill(new KillRequest(jobInfo.getId()));\n\t\t} catch (Exception e) {\n\t\t\tlogger.error(e.getMessage(), e);\n\t\t\trunResult = Response.ofFail( e.getMessage());\n\t\t}\n\n\t\tif (XxlJobContext.HANDLE_CODE_SUCCESS == runResult.getCode()) {\n\t\t\tlog.setHandleCode(XxlJobContext.HANDLE_CODE_FAIL);\n\t\t\tlog.setHandleMsg( I18nUtil.getString(\"joblog_kill_log_byman\")+\":\" + (runResult.getMsg()!=null?runResult.getMsg():\"\"));\n\t\t\tlog.setHandleTime(new Date());\n\t\t\tXxlJobAdminBootstrap.getInstance().getJobCompleter().complete(log);\n\t\t\treturn Response.ofSuccess(runResult.getMsg());\n\t\t} else {\n\t\t\treturn Response.ofFail(runResult.getMsg());\n\t\t}\n\t}\n\n\t@RequestMapping(\"/clearLog\")\n\t@ResponseBody\n\tpublic Response<String> clearLog(HttpServletRequest request,\n\t\t\t\t\t\t\t\t\t@RequestParam(\"jobGroup\") int jobGroup,\n\t\t\t\t\t\t\t\t\t@RequestParam(\"jobId\") int jobId,\n\t\t\t\t\t\t\t\t\t@RequestParam(\"type\") int type){\n\t\t// valid JobGroup permission\n\t\tJobGroupPermissionUtil.validJobGroupPermission(request, jobGroup);\n\n\t\t// valid jobId\n\t\tif (jobId < 1) {\n\t\t\treturn Response.ofFail(I18nUtil.getString(\"system_please_choose\") + I18nUtil.getString(\"jobinfo_job\"));\n\t\t}\n\n\t\t// opt\n\t\tDate clearBeforeTime = null;\n\t\tint clearBeforeNum = 0;\n\t\tif (type == 1) {\n\t\t\tclearBeforeTime = DateTool.addMonths(new Date(), -1);\t// 清理一个月之前日志数据\n\t\t} else if (type == 2) {\n\t\t\tclearBeforeTime = DateTool.addMonths(new Date(), -3);\t// 清理三个月之前日志数据\n\t\t} else if (type == 3) {\n\t\t\tclearBeforeTime = DateTool.addMonths(new Date(), -6);\t// 清理六个月之前日志数据\n\t\t} else if (type == 4) {\n\t\t\tclearBeforeTime = DateTool.addYears(new Date(), -1);\t// 清理一年之前日志数据\n\t\t} else if (type == 5) {\n\t\t\tclearBeforeNum = 1000;\t\t// 清理一千条以前日志数据\n\t\t} else if (type == 6) {\n\t\t\tclearBeforeNum = 10000;\t\t// 清理一万条以前日志数据\n\t\t} else if (type == 7) {\n\t\t\tclearBeforeNum = 30000;\t\t// 清理三万条以前日志数据\n\t\t} else if (type == 8) {\n\t\t\tclearBeforeNum = 100000;\t// 清理十万条以前日志数据\n\t\t} else if (type == 9) {\n\t\t\tclearBeforeNum = 0;\t\t\t// 清理所有日志数据\n\t\t} else {\n\t\t\treturn Response.ofFail(I18nUtil.getString(\"joblog_clean_type_unvalid\"));\n\t\t}\n\n\t\tList<Long> logIds = null;\n\t\tdo {\n\t\t\tlogIds = xxlJobLogMapper.findClearLogIds(jobGroup, jobId, clearBeforeTime, clearBeforeNum, 1000);\n\t\t\tif (logIds!=null && !logIds.isEmpty()) {\n\t\t\t\txxlJobLogMapper.clearLog(logIds);\n\t\t\t}\n\t\t} while (logIds!=null && !logIds.isEmpty());\n\n\t\treturn Response.ofSuccess();\n\t}\n\n\t@RequestMapping(\"/logDetailPage\")\n\tpublic String logDetailPage(HttpServletRequest request, @RequestParam(\"id\") long id, Model model){\n\n\t\t// base check\n\t\tXxlJobLog jobLog = xxlJobLogMapper.load(id);\n\t\tif (jobLog == null) {\n\t\t\tthrow new RuntimeException(I18nUtil.getString(\"joblog_logid_unvalid\"));\n\t\t}\n\n\t\t// valid permission\n\t\tJobGroupPermissionUtil.validJobGroupPermission(request, jobLog.getJobGroup());\n\n\t\t// load jobInfo\n\t\tXxlJobInfo jobInfo = xxlJobInfoMapper.loadById(jobLog.getJobId());\n\n\t\t// data\n\t\tmodel.addAttribute(\"triggerCode\", jobLog.getTriggerCode());\n\t\tmodel.addAttribute(\"handleCode\", jobLog.getHandleCode());\n\t\tmodel.addAttribute(\"logId\", jobLog.getId());\n\t\tmodel.addAttribute(\"jobInfo\", jobInfo);\n\t\treturn \"biz/log.detail\";\n\t}\n\n\t@RequestMapping(\"/logDetailCat\")\n\t@ResponseBody\n\tpublic Response<LogResult> logDetailCat(@RequestParam(\"logId\") long logId, @RequestParam(\"fromLineNum\") int fromLineNum){\n\t\ttry {\n\t\t\t// valid\n\t\t\tXxlJobLog jobLog = xxlJobLogMapper.load(logId);\t// todo, need to improve performance\n\t\t\tif (jobLog == null) {\n\t\t\t\treturn Response.ofFail(I18nUtil.getString(\"joblog_logid_unvalid\"));\n\t\t\t}\n\n\t\t\t// log cat\n\t\t\tExecutorBiz executorBiz = XxlJobAdminBootstrap.getExecutorBiz(jobLog.getExecutorAddress());\n\t\t\tResponse<LogResult> logResult = executorBiz.log(new LogRequest(jobLog.getTriggerTime().getTime(), logId, fromLineNum));\n\n\t\t\t// is end\n\t\t\tif (logResult.getData()!=null && logResult.getData().getFromLineNum() > logResult.getData().getToLineNum()) {\n\t\t\t\tif (jobLog.getHandleCode() > 0) {\n\t\t\t\t\tlogResult.getData().setEnd(true);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// fix xss\n\t\t\tif (logResult.getData()!=null && StringTool.isNotBlank(logResult.getData().getLogContent())) {\n\t\t\t\tString newLogContent = filter(logResult.getData().getLogContent());\n\t\t\t\tlogResult.getData().setLogContent(newLogContent);\n\t\t\t}\n\n\t\t\treturn logResult;\n\t\t} catch (Exception e) {\n\t\t\tlogger.error(\"logId({}) logDetailCat error: {}\", logId, e.getMessage(), e);\n\t\t\treturn Response.ofFail(e.getMessage());\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/controller/biz/JobUserController.java",
    "content": "package com.xxl.job.admin.controller.biz;\n\nimport com.xxl.job.admin.constant.Consts;\nimport com.xxl.job.admin.mapper.XxlJobGroupMapper;\nimport com.xxl.job.admin.mapper.XxlJobUserMapper;\nimport com.xxl.job.admin.model.XxlJobGroup;\nimport com.xxl.job.admin.model.XxlJobUser;\nimport com.xxl.job.admin.util.I18nUtil;\nimport com.xxl.sso.core.annotation.XxlSso;\nimport com.xxl.sso.core.helper.XxlSsoHelper;\nimport com.xxl.sso.core.model.LoginInfo;\nimport com.xxl.tool.core.CollectionTool;\nimport com.xxl.tool.core.StringTool;\nimport com.xxl.tool.crypto.Sha256Tool;\nimport com.xxl.tool.response.PageModel;\nimport com.xxl.tool.response.Response;\nimport jakarta.annotation.Resource;\nimport jakarta.servlet.http.HttpServletRequest;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.Model;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * @author xuxueli 2019-05-04 16:39:50\n */\n@Controller\n@RequestMapping(\"/user\")\npublic class JobUserController {\n\n    @Resource\n    private XxlJobUserMapper xxlJobUserMapper;\n    @Resource\n    private XxlJobGroupMapper xxlJobGroupMapper;\n\n    @RequestMapping\n    @XxlSso(role = Consts.ADMIN_ROLE)\n    public String index(Model model) {\n\n        // 执行器列表\n        List<XxlJobGroup> groupList = xxlJobGroupMapper.findAll();\n        model.addAttribute(\"groupList\", groupList);\n\n        return \"biz/user.list\";\n    }\n\n    @RequestMapping(\"/pageList\")\n    @ResponseBody\n    @XxlSso(role = Consts.ADMIN_ROLE)\n    public Response<PageModel<XxlJobUser>> pageList(@RequestParam(required = false, defaultValue = \"0\") int offset,\n                                                    @RequestParam(required = false, defaultValue = \"10\") int pagesize,\n                                                    @RequestParam String username,\n                                                    @RequestParam int role) {\n\n        // page list\n        List<XxlJobUser> list = xxlJobUserMapper.pageList(offset, pagesize, username, role);\n        int list_count = xxlJobUserMapper.pageListCount(offset, pagesize, username, role);\n\n        // filter\n        if (list!=null && !list.isEmpty()) {\n            for (XxlJobUser item: list) {\n                item.setPassword(null);\n            }\n        }\n\n        // package result\n        PageModel<XxlJobUser> pageModel = new PageModel<>();\n        pageModel.setData(list);\n        pageModel.setTotal(list_count);\n\n        return Response.ofSuccess(pageModel);\n    }\n\n    @RequestMapping(\"/insert\")\n    @ResponseBody\n    @XxlSso(role = Consts.ADMIN_ROLE)\n    public Response<String> insert(XxlJobUser xxlJobUser) {\n\n        // valid username\n        if (StringTool.isBlank(xxlJobUser.getUsername())) {\n            return Response.ofFail(I18nUtil.getString(\"system_please_input\")+I18nUtil.getString(\"user_username\") );\n        }\n        xxlJobUser.setUsername(xxlJobUser.getUsername().trim());\n        if (!(xxlJobUser.getUsername().length()>=4 && xxlJobUser.getUsername().length()<=20)) {\n            return Response.ofFail(I18nUtil.getString(\"system_lengh_limit\")+\"[4-20]\" );\n        }\n        // valid password\n        if (StringTool.isBlank(xxlJobUser.getPassword())) {\n            return Response.ofFail(I18nUtil.getString(\"system_please_input\")+I18nUtil.getString(\"user_password\") );\n        }\n        xxlJobUser.setPassword(xxlJobUser.getPassword().trim());\n        if (!(xxlJobUser.getPassword().length()>=4 && xxlJobUser.getPassword().length()<=20)) {\n            return Response.ofFail(I18nUtil.getString(\"system_lengh_limit\")+\"[4-20]\" );\n        }\n        // md5 password\n        String passwordHash = Sha256Tool.sha256(xxlJobUser.getPassword());\n        xxlJobUser.setPassword(passwordHash);\n\n        // check repeat\n        XxlJobUser existUser = xxlJobUserMapper.loadByUserName(xxlJobUser.getUsername());\n        if (existUser != null) {\n            return Response.ofFail( I18nUtil.getString(\"user_username_repeat\") );\n        }\n\n        // write\n        xxlJobUserMapper.save(xxlJobUser);\n        return Response.ofSuccess();\n    }\n\n    @RequestMapping(\"/update\")\n    @ResponseBody\n    @XxlSso(role = Consts.ADMIN_ROLE)\n    public Response<String> update(HttpServletRequest request, XxlJobUser xxlJobUser) {\n\n        // avoid opt login seft\n        Response<LoginInfo> loginInfoResponse = XxlSsoHelper.loginCheckWithAttr(request);\n        if (loginInfoResponse.getData().getUserName().equals(xxlJobUser.getUsername())) {\n            return Response.ofFail(I18nUtil.getString(\"user_update_loginuser_limit\"));\n        }\n\n        // valid password\n        if (StringTool.isNotBlank(xxlJobUser.getPassword())) {\n            xxlJobUser.setPassword(xxlJobUser.getPassword().trim());\n            if (!(xxlJobUser.getPassword().length()>=4 && xxlJobUser.getPassword().length()<=20)) {\n                return Response.ofFail(I18nUtil.getString(\"system_lengh_limit\")+\"[4-20]\" );\n            }\n            // md5 password\n            String passwordHash = Sha256Tool.sha256(xxlJobUser.getPassword());\n            xxlJobUser.setPassword(passwordHash);\n        } else {\n            xxlJobUser.setPassword(null);\n        }\n\n        // write\n        xxlJobUserMapper.update(xxlJobUser);\n        return Response.ofSuccess();\n    }\n\n    @RequestMapping(\"/delete\")\n    @ResponseBody\n    @XxlSso(role = Consts.ADMIN_ROLE)\n    public Response<String> delete(HttpServletRequest request, @RequestParam(\"ids[]\") List<Integer> ids) {\n\n        // valid\n        if (CollectionTool.isEmpty(ids) || ids.size()!=1) {\n            return Response.ofFail(I18nUtil.getString(\"system_please_choose\") + I18nUtil.getString(\"system_one\") + I18nUtil.getString(\"system_data\"));\n        }\n\n        // avoid opt login seft\n        Response<LoginInfo> loginInfoResponse = XxlSsoHelper.loginCheckWithAttr(request);\n        if (ids.contains(Integer.parseInt(loginInfoResponse.getData().getUserId()))) {\n            return Response.ofFail(I18nUtil.getString(\"user_update_loginuser_limit\"));\n        }\n\n        xxlJobUserMapper.delete(ids.get(0));\n        return Response.ofSuccess();\n    }\n\n    /*@RequestMapping(\"/updatePwd\")\n    @ResponseBody\n    public Response<String> updatePwd(HttpServletRequest request,\n                                     @RequestParam(\"password\") String password,\n                                     @RequestParam(\"oldPassword\") String oldPassword){\n\n        // valid\n        if (oldPassword==null || oldPassword.trim().isEmpty()){\n            return Response.ofFail(I18nUtil.getString(\"system_please_input\") + I18nUtil.getString(\"change_pwd_field_oldpwd\"));\n        }\n        if (password==null || password.trim().isEmpty()){\n            return Response.ofFail(I18nUtil.getString(\"system_please_input\") + I18nUtil.getString(\"change_pwd_field_oldpwd\"));\n        }\n        password = password.trim();\n        if (!(password.length()>=4 && password.length()<=20)) {\n            return Response.ofFail(I18nUtil.getString(\"system_lengh_limit\")+\"[4-20]\" );\n        }\n\n        // md5 password\n        String oldPasswordHash = Sha256Tool.sha256(oldPassword);\n        String passwordHash = Sha256Tool.sha256(password);\n\n        // valid old pwd\n        Response<LoginInfo> loginInfoResponse = XxlSsoHelper.loginCheckWithAttr(request);\n        XxlJobUser existUser = xxlJobUserMapper.loadByUserName(loginInfoResponse.getData().getUserName());\n        if (!oldPasswordHash.equals(existUser.getPassword())) {\n            return Response.ofFail(I18nUtil.getString(\"change_pwd_field_oldpwd\") + I18nUtil.getString(\"system_unvalid\"));\n        }\n\n        // write new\n        existUser.setPassword(passwordHash);\n        xxlJobUserMapper.update(existUser);\n\n        return Response.ofSuccess();\n    }*/\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/mapper/XxlJobGroupMapper.java",
    "content": "package com.xxl.job.admin.mapper;\n\nimport com.xxl.job.admin.model.XxlJobGroup;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.apache.ibatis.annotations.Param;\n\nimport java.util.List;\n\n/**\n * Created by xuxueli on 16/9/30.\n */\n@Mapper\npublic interface XxlJobGroupMapper {\n\n    public List<XxlJobGroup> findAll();\n\n    public List<XxlJobGroup> findByAddressType(@Param(\"addressType\") int addressType);\n\n    public int save(XxlJobGroup xxlJobGroup);\n\n    public int update(XxlJobGroup xxlJobGroup);\n\n    public int remove(@Param(\"id\") int id);\n\n    public XxlJobGroup load(@Param(\"id\") int id);\n\n    public List<XxlJobGroup> pageList(@Param(\"offset\") int offset,\n                                      @Param(\"pagesize\") int pagesize,\n                                      @Param(\"appname\") String appname,\n                                      @Param(\"title\") String title);\n\n    public int pageListCount(@Param(\"offset\") int offset,\n                             @Param(\"pagesize\") int pagesize,\n                             @Param(\"appname\") String appname,\n                             @Param(\"title\") String title);\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/mapper/XxlJobInfoMapper.java",
    "content": "package com.xxl.job.admin.mapper;\n\nimport com.xxl.job.admin.model.XxlJobInfo;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.apache.ibatis.annotations.Param;\n\nimport java.util.List;\n\n\n/**\n * job info\n * @author xuxueli 2016-1-12 18:03:45\n */\n@Mapper\npublic interface XxlJobInfoMapper {\n\n\tpublic List<XxlJobInfo> pageList(@Param(\"offset\") int offset,\n\t\t\t\t\t\t\t\t\t @Param(\"pagesize\") int pagesize,\n\t\t\t\t\t\t\t\t\t @Param(\"jobGroup\") int jobGroup,\n\t\t\t\t\t\t\t\t\t @Param(\"triggerStatus\") int triggerStatus,\n\t\t\t\t\t\t\t\t\t @Param(\"jobDesc\") String jobDesc,\n\t\t\t\t\t\t\t\t\t @Param(\"executorHandler\") String executorHandler,\n\t\t\t\t\t\t\t\t\t @Param(\"author\") String author);\n\tpublic int pageListCount(@Param(\"offset\") int offset,\n\t\t\t\t\t\t\t @Param(\"pagesize\") int pagesize,\n\t\t\t\t\t\t\t @Param(\"jobGroup\") int jobGroup,\n\t\t\t\t\t\t\t @Param(\"triggerStatus\") int triggerStatus,\n\t\t\t\t\t\t\t @Param(\"jobDesc\") String jobDesc,\n\t\t\t\t\t\t\t @Param(\"executorHandler\") String executorHandler,\n\t\t\t\t\t\t\t @Param(\"author\") String author);\n\t\n\tpublic int save(XxlJobInfo info);\n\n\tpublic XxlJobInfo loadById(@Param(\"id\") int id);\n\t\n\tpublic int update(XxlJobInfo xxlJobInfo);\n\t\n\tpublic int delete(@Param(\"id\") long id);\n\n\tpublic List<XxlJobInfo> getJobsByGroup(@Param(\"jobGroup\") int jobGroup);\n\n\tpublic int findAllCount();\n\n\t/**\n\t * find schedule job, limit \"trigger_status = 1\"\n\t *\n\t * @param maxNextTime\n\t * @param pagesize\n\t * @return\n\t */\n\tpublic List<XxlJobInfo> scheduleJobQuery(@Param(\"maxNextTime\") long maxNextTime, @Param(\"pagesize\") int pagesize );\n\n\t/**\n\t * update schedule job\n\t *\n\t * \t1、can only update \"trigger_status = 1\", Avoid stopping tasks from being opened\n\t * \t2、valid \"triggerStatus gte 0\", filter illegal state\n\t *\n\t * @param xxlJobInfo\n\t * @return\n\t */\n\tpublic int scheduleUpdate(XxlJobInfo xxlJobInfo);\n\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/mapper/XxlJobLockMapper.java",
    "content": "package com.xxl.job.admin.mapper;\n\nimport org.apache.ibatis.annotations.Mapper;\n\n/**\n * job lock\n *\n * @author xuxueli 2016-1-12 18:03:45\n */\n@Mapper\npublic interface XxlJobLockMapper {\n\n    /**\n     * get schedule lock\n     */\n    String scheduleLock();\n\n}"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/mapper/XxlJobLogGlueMapper.java",
    "content": "package com.xxl.job.admin.mapper;\n\nimport com.xxl.job.admin.model.XxlJobLogGlue;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.apache.ibatis.annotations.Param;\n\nimport java.util.List;\n\n/**\n * job log for glue\n * @author xuxueli 2016-5-19 18:04:56\n */\n@Mapper\npublic interface XxlJobLogGlueMapper {\n\t\n\tpublic int save(XxlJobLogGlue xxlJobLogGlue);\n\t\n\tpublic List<XxlJobLogGlue> findByJobId(@Param(\"jobId\") int jobId);\n\n\tpublic int removeOld(@Param(\"jobId\") int jobId, @Param(\"limit\") int limit);\n\n\tpublic int deleteByJobId(@Param(\"jobId\") int jobId);\n\t\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/mapper/XxlJobLogMapper.java",
    "content": "package com.xxl.job.admin.mapper;\n\nimport com.xxl.job.admin.model.XxlJobLog;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.apache.ibatis.annotations.Param;\n\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * job log\n * @author xuxueli 2016-1-12 18:03:06\n */\n@Mapper\npublic interface XxlJobLogMapper {\n\n\t// exist jobId not use jobGroup, not exist use jobGroup\n\tpublic List<XxlJobLog> pageList(@Param(\"offset\") int offset,\n\t\t\t\t\t\t\t\t\t@Param(\"pagesize\") int pagesize,\n\t\t\t\t\t\t\t\t\t@Param(\"jobGroup\") int jobGroup,\n\t\t\t\t\t\t\t\t\t@Param(\"jobId\") int jobId,\n\t\t\t\t\t\t\t\t\t@Param(\"triggerTimeStart\") Date triggerTimeStart,\n\t\t\t\t\t\t\t\t\t@Param(\"triggerTimeEnd\") Date triggerTimeEnd,\n\t\t\t\t\t\t\t\t\t@Param(\"logStatus\") int logStatus);\n\tpublic int pageListCount(@Param(\"offset\") int offset,\n\t\t\t\t\t\t\t @Param(\"pagesize\") int pagesize,\n\t\t\t\t\t\t\t @Param(\"jobGroup\") int jobGroup,\n\t\t\t\t\t\t\t @Param(\"jobId\") int jobId,\n\t\t\t\t\t\t\t @Param(\"triggerTimeStart\") Date triggerTimeStart,\n\t\t\t\t\t\t\t @Param(\"triggerTimeEnd\") Date triggerTimeEnd,\n\t\t\t\t\t\t\t @Param(\"logStatus\") int logStatus);\n\t\n\tpublic XxlJobLog load(@Param(\"id\") long id);\n\n\tpublic long save(XxlJobLog xxlJobLog);\n\n\tpublic int updateTriggerInfo(XxlJobLog xxlJobLog);\n\n\tpublic int updateHandleInfo(XxlJobLog xxlJobLog);\n\t\n\tpublic int delete(@Param(\"jobId\") int jobId);\n\n\tpublic Map<String, Object> findLogReport(@Param(\"from\") Date from,\n\t\t\t\t\t\t\t\t\t\t\t @Param(\"to\") Date to);\n\n\tpublic List<Long> findClearLogIds(@Param(\"jobGroup\") int jobGroup,\n\t\t\t\t\t\t\t\t\t  @Param(\"jobId\") int jobId,\n\t\t\t\t\t\t\t\t\t  @Param(\"clearBeforeTime\") Date clearBeforeTime,\n\t\t\t\t\t\t\t\t\t  @Param(\"clearBeforeNum\") int clearBeforeNum,\n\t\t\t\t\t\t\t\t\t  @Param(\"pagesize\") int pagesize);\n\tpublic int clearLog(@Param(\"logIds\") List<Long> logIds);\n\n\tpublic List<Long> findFailJobLogIds(@Param(\"pagesize\") int pagesize);\n\n\tpublic int updateAlarmStatus(@Param(\"logId\") long logId,\n\t\t\t\t\t\t\t\t @Param(\"oldAlarmStatus\") int oldAlarmStatus,\n\t\t\t\t\t\t\t\t @Param(\"newAlarmStatus\") int newAlarmStatus);\n\n\tpublic List<Long> findLostJobIds(@Param(\"losedTime\") Date losedTime);\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/mapper/XxlJobLogReportMapper.java",
    "content": "package com.xxl.job.admin.mapper;\n\nimport com.xxl.job.admin.model.XxlJobLogReport;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.apache.ibatis.annotations.Param;\n\nimport java.util.Date;\nimport java.util.List;\n\n/**\n * job log\n * @author xuxueli 2019-11-22\n */\n@Mapper\npublic interface XxlJobLogReportMapper {\n\n\t/*public int save(XxlJobLogReport xxlJobLogReport);\n\n\tpublic int update(XxlJobLogReport xxlJobLogReport);*/\n\n\tpublic int saveOrUpdate(XxlJobLogReport xxlJobLogReport);\n\n\tpublic List<XxlJobLogReport> queryLogReport(@Param(\"triggerDayFrom\") Date triggerDayFrom,\n\t\t\t\t\t\t\t\t\t\t\t\t@Param(\"triggerDayTo\") Date triggerDayTo);\n\n\tpublic XxlJobLogReport queryLogReportTotal();\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/mapper/XxlJobRegistryMapper.java",
    "content": "package com.xxl.job.admin.mapper;\n\nimport com.xxl.job.admin.model.XxlJobRegistry;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.apache.ibatis.annotations.Param;\n\nimport java.util.Date;\nimport java.util.List;\n\n/**\n * Created by xuxueli on 16/9/30.\n */\n@Mapper\npublic interface XxlJobRegistryMapper {\n\n    public List<Integer> findDead(@Param(\"timeout\") int timeout,\n                                  @Param(\"nowTime\") Date nowTime);\n\n    public int removeDead(@Param(\"ids\") List<Integer> ids);\n\n    public List<XxlJobRegistry> findAll(@Param(\"timeout\") int timeout,\n                                        @Param(\"nowTime\") Date nowTime);\n\n    public int registrySaveOrUpdate(@Param(\"registryGroup\") String registryGroup,\n                            @Param(\"registryKey\") String registryKey,\n                            @Param(\"registryValue\") String registryValue,\n                            @Param(\"updateTime\") Date updateTime);\n\n    /*public int registryUpdate(@Param(\"registryGroup\") String registryGroup,\n                              @Param(\"registryKey\") String registryKey,\n                              @Param(\"registryValue\") String registryValue,\n                              @Param(\"updateTime\") Date updateTime);\n\n    public int registrySave(@Param(\"registryGroup\") String registryGroup,\n                            @Param(\"registryKey\") String registryKey,\n                            @Param(\"registryValue\") String registryValue,\n                            @Param(\"updateTime\") Date updateTime);*/\n\n    public int registryDelete(@Param(\"registryGroup\") String registryGroup,\n                          @Param(\"registryKey\") String registryKey,\n                          @Param(\"registryValue\") String registryValue);\n\n    public int removeByRegistryGroupAndKey(@Param(\"registryGroup\") String registryGroup,\n                                           @Param(\"registryKey\") String registryKey);\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/mapper/XxlJobUserMapper.java",
    "content": "package com.xxl.job.admin.mapper;\n\nimport com.xxl.job.admin.model.XxlJobUser;\nimport com.xxl.tool.response.Response;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.apache.ibatis.annotations.Param;\nimport java.util.List;\n\n/**\n * @author xuxueli 2019-05-04 16:44:59\n */\n@Mapper\npublic interface XxlJobUserMapper {\n\n\tpublic List<XxlJobUser> pageList(@Param(\"offset\") int offset,\n                                     @Param(\"pagesize\") int pagesize,\n                                     @Param(\"username\") String username,\n\t\t\t\t\t\t\t\t\t @Param(\"role\") int role);\n\tpublic int pageListCount(@Param(\"offset\") int offset,\n\t\t\t\t\t\t\t @Param(\"pagesize\") int pagesize,\n\t\t\t\t\t\t\t @Param(\"username\") String username,\n\t\t\t\t\t\t\t @Param(\"role\") int role);\n\n\tpublic XxlJobUser loadByUserName(@Param(\"username\") String username);\n\n\tpublic XxlJobUser loadById(@Param(\"id\") int id);\n\n\tpublic int save(XxlJobUser xxlJobUser);\n\n\tpublic int update(XxlJobUser xxlJobUser);\n\t\n\tpublic int delete(@Param(\"id\") int id);\n\n\tpublic int updateToken(@Param(\"id\") int id, @Param(\"token\") String token);\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/model/XxlJobGroup.java",
    "content": "package com.xxl.job.admin.model;\n\nimport com.xxl.tool.core.StringTool;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Date;\nimport java.util.List;\n\n/**\n * Created by xuxueli on 16/9/30.\n */\npublic class XxlJobGroup {\n\n    private int id;\n    private String appname;\n    private String title;\n    private int addressType;        // 执行器地址类型：0=自动注册、1=手动录入\n    private String addressList;     // 执行器地址列表，多地址逗号分隔(手动录入)\n    private Date updateTime;\n\n    // registry list\n    private List<String> registryList;  // 执行器地址列表(系统注册)\n    public List<String> getRegistryList() {\n        if (StringTool.isNotBlank(addressList)) {\n            registryList = new ArrayList<>(Arrays.asList(addressList.split(\",\")));\n        }\n        return registryList;\n    }\n\n    public int getId() {\n        return id;\n    }\n\n    public void setId(int id) {\n        this.id = id;\n    }\n\n    public String getAppname() {\n        return appname;\n    }\n\n    public void setAppname(String appname) {\n        this.appname = appname;\n    }\n\n    public String getTitle() {\n        return title;\n    }\n\n    public void setTitle(String title) {\n        this.title = title;\n    }\n\n    public int getAddressType() {\n        return addressType;\n    }\n\n    public void setAddressType(int addressType) {\n        this.addressType = addressType;\n    }\n\n    public String getAddressList() {\n        return addressList;\n    }\n\n    public Date getUpdateTime() {\n        return updateTime;\n    }\n\n    public void setUpdateTime(Date updateTime) {\n        this.updateTime = updateTime;\n    }\n\n    public void setAddressList(String addressList) {\n        this.addressList = addressList;\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/model/XxlJobInfo.java",
    "content": "package com.xxl.job.admin.model;\n\nimport java.util.Date;\n\n/**\n * xxl-job info\n *\n * @author xuxueli  2016-1-12 18:25:49\n */\npublic class XxlJobInfo {\n\t\n\tprivate int id;\t\t\t\t// 主键ID\n\t\n\tprivate int jobGroup;\t\t// 执行器主键ID\n\tprivate String jobDesc;\n\t\n\tprivate Date addTime;\n\tprivate Date updateTime;\n\t\n\tprivate String author;\t\t// 负责人\n\tprivate String alarmEmail;\t// 报警邮件\n\n\tprivate String scheduleType;\t\t\t// 调度类型：ScheduleTypeEnum\n\tprivate String scheduleConf;\t\t\t// 调度配置，值含义取决于调度类型\n\tprivate String misfireStrategy;\t\t\t// 调度过期策略：MisfireStrategyEnum\n\n\tprivate String executorRouteStrategy;\t// 执行器路由策略：ExecutorRouteStrategyEnum\n\tprivate String executorHandler;\t\t    // 执行器，任务Handler名称\n\tprivate String executorParam;\t\t    // 执行器，任务参数\n\tprivate String executorBlockStrategy;\t// 阻塞处理策略：ExecutorBlockStrategyEnum\n\tprivate int executorTimeout;     \t\t// 任务执行超时时间，单位秒\n\tprivate int executorFailRetryCount;\t\t// 失败重试次数\n\t\n\tprivate String glueType;\t\t// GLUE类型：GlueTypeEnum\n\tprivate String glueSource;\t\t// GLUE源代码\n\tprivate String glueRemark;\t\t// GLUE备注\n\tprivate Date glueUpdatetime;\t// GLUE更新时间\n\n\tprivate String childJobId;\t\t// 子任务ID，多个逗号分隔\n\n\tprivate int triggerStatus;\t\t// 调度状态：TriggerStatus\n\tprivate long triggerLastTime;\t// 上次调度时间\n\tprivate long triggerNextTime;\t// 下次调度时间\n\n\n\tpublic int getId() {\n\t\treturn id;\n\t}\n\n\tpublic void setId(int id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic int getJobGroup() {\n\t\treturn jobGroup;\n\t}\n\n\tpublic void setJobGroup(int jobGroup) {\n\t\tthis.jobGroup = jobGroup;\n\t}\n\n\tpublic String getJobDesc() {\n\t\treturn jobDesc;\n\t}\n\n\tpublic void setJobDesc(String jobDesc) {\n\t\tthis.jobDesc = jobDesc;\n\t}\n\n\tpublic Date getAddTime() {\n\t\treturn addTime;\n\t}\n\n\tpublic void setAddTime(Date addTime) {\n\t\tthis.addTime = addTime;\n\t}\n\n\tpublic Date getUpdateTime() {\n\t\treturn updateTime;\n\t}\n\n\tpublic void setUpdateTime(Date updateTime) {\n\t\tthis.updateTime = updateTime;\n\t}\n\n\tpublic String getAuthor() {\n\t\treturn author;\n\t}\n\n\tpublic void setAuthor(String author) {\n\t\tthis.author = author;\n\t}\n\n\tpublic String getAlarmEmail() {\n\t\treturn alarmEmail;\n\t}\n\n\tpublic void setAlarmEmail(String alarmEmail) {\n\t\tthis.alarmEmail = alarmEmail;\n\t}\n\n\tpublic String getScheduleType() {\n\t\treturn scheduleType;\n\t}\n\n\tpublic void setScheduleType(String scheduleType) {\n\t\tthis.scheduleType = scheduleType;\n\t}\n\n\tpublic String getScheduleConf() {\n\t\treturn scheduleConf;\n\t}\n\n\tpublic void setScheduleConf(String scheduleConf) {\n\t\tthis.scheduleConf = scheduleConf;\n\t}\n\n\tpublic String getMisfireStrategy() {\n\t\treturn misfireStrategy;\n\t}\n\n\tpublic void setMisfireStrategy(String misfireStrategy) {\n\t\tthis.misfireStrategy = misfireStrategy;\n\t}\n\n\tpublic String getExecutorRouteStrategy() {\n\t\treturn executorRouteStrategy;\n\t}\n\n\tpublic void setExecutorRouteStrategy(String executorRouteStrategy) {\n\t\tthis.executorRouteStrategy = executorRouteStrategy;\n\t}\n\n\tpublic String getExecutorHandler() {\n\t\treturn executorHandler;\n\t}\n\n\tpublic void setExecutorHandler(String executorHandler) {\n\t\tthis.executorHandler = executorHandler;\n\t}\n\n\tpublic String getExecutorParam() {\n\t\treturn executorParam;\n\t}\n\n\tpublic void setExecutorParam(String executorParam) {\n\t\tthis.executorParam = executorParam;\n\t}\n\n\tpublic String getExecutorBlockStrategy() {\n\t\treturn executorBlockStrategy;\n\t}\n\n\tpublic void setExecutorBlockStrategy(String executorBlockStrategy) {\n\t\tthis.executorBlockStrategy = executorBlockStrategy;\n\t}\n\n\tpublic int getExecutorTimeout() {\n\t\treturn executorTimeout;\n\t}\n\n\tpublic void setExecutorTimeout(int executorTimeout) {\n\t\tthis.executorTimeout = executorTimeout;\n\t}\n\n\tpublic int getExecutorFailRetryCount() {\n\t\treturn executorFailRetryCount;\n\t}\n\n\tpublic void setExecutorFailRetryCount(int executorFailRetryCount) {\n\t\tthis.executorFailRetryCount = executorFailRetryCount;\n\t}\n\n\tpublic String getGlueType() {\n\t\treturn glueType;\n\t}\n\n\tpublic void setGlueType(String glueType) {\n\t\tthis.glueType = glueType;\n\t}\n\n\tpublic String getGlueSource() {\n\t\treturn glueSource;\n\t}\n\n\tpublic void setGlueSource(String glueSource) {\n\t\tthis.glueSource = glueSource;\n\t}\n\n\tpublic String getGlueRemark() {\n\t\treturn glueRemark;\n\t}\n\n\tpublic void setGlueRemark(String glueRemark) {\n\t\tthis.glueRemark = glueRemark;\n\t}\n\n\tpublic Date getGlueUpdatetime() {\n\t\treturn glueUpdatetime;\n\t}\n\n\tpublic void setGlueUpdatetime(Date glueUpdatetime) {\n\t\tthis.glueUpdatetime = glueUpdatetime;\n\t}\n\n\tpublic String getChildJobId() {\n\t\treturn childJobId;\n\t}\n\n\tpublic void setChildJobId(String childJobId) {\n\t\tthis.childJobId = childJobId;\n\t}\n\n\tpublic int getTriggerStatus() {\n\t\treturn triggerStatus;\n\t}\n\n\tpublic void setTriggerStatus(int triggerStatus) {\n\t\tthis.triggerStatus = triggerStatus;\n\t}\n\n\tpublic long getTriggerLastTime() {\n\t\treturn triggerLastTime;\n\t}\n\n\tpublic void setTriggerLastTime(long triggerLastTime) {\n\t\tthis.triggerLastTime = triggerLastTime;\n\t}\n\n\tpublic long getTriggerNextTime() {\n\t\treturn triggerNextTime;\n\t}\n\n\tpublic void setTriggerNextTime(long triggerNextTime) {\n\t\tthis.triggerNextTime = triggerNextTime;\n\t}\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/model/XxlJobLog.java",
    "content": "package com.xxl.job.admin.model;\n\nimport java.util.Date;\n\n/**\n * xxl-job log, used to track trigger process\n * @author xuxueli  2015-12-19 23:19:09\n */\npublic class XxlJobLog {\n\t\n\tprivate long id;\n\t\n\t// job info\n\tprivate int jobGroup;\n\tprivate int jobId;\n\n\t// execute info\n\tprivate String executorAddress;\n\tprivate String executorHandler;\n\tprivate String executorParam;\n\tprivate String executorShardingParam;\n\tprivate int executorFailRetryCount;\n\t\n\t// trigger info\n\tprivate Date triggerTime;\n\tprivate int triggerCode;\n\tprivate String triggerMsg;\n\t\n\t// handle info\n\tprivate Date handleTime;\n\tprivate int handleCode;\n\tprivate String handleMsg;\n\n\t// alarm info\n\tprivate int alarmStatus;\n\n\tpublic long getId() {\n\t\treturn id;\n\t}\n\n\tpublic void setId(long id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic int getJobGroup() {\n\t\treturn jobGroup;\n\t}\n\n\tpublic void setJobGroup(int jobGroup) {\n\t\tthis.jobGroup = jobGroup;\n\t}\n\n\tpublic int getJobId() {\n\t\treturn jobId;\n\t}\n\n\tpublic void setJobId(int jobId) {\n\t\tthis.jobId = jobId;\n\t}\n\n\tpublic String getExecutorAddress() {\n\t\treturn executorAddress;\n\t}\n\n\tpublic void setExecutorAddress(String executorAddress) {\n\t\tthis.executorAddress = executorAddress;\n\t}\n\n\tpublic String getExecutorHandler() {\n\t\treturn executorHandler;\n\t}\n\n\tpublic void setExecutorHandler(String executorHandler) {\n\t\tthis.executorHandler = executorHandler;\n\t}\n\n\tpublic String getExecutorParam() {\n\t\treturn executorParam;\n\t}\n\n\tpublic void setExecutorParam(String executorParam) {\n\t\tthis.executorParam = executorParam;\n\t}\n\n\tpublic String getExecutorShardingParam() {\n\t\treturn executorShardingParam;\n\t}\n\n\tpublic void setExecutorShardingParam(String executorShardingParam) {\n\t\tthis.executorShardingParam = executorShardingParam;\n\t}\n\n\tpublic int getExecutorFailRetryCount() {\n\t\treturn executorFailRetryCount;\n\t}\n\n\tpublic void setExecutorFailRetryCount(int executorFailRetryCount) {\n\t\tthis.executorFailRetryCount = executorFailRetryCount;\n\t}\n\n\tpublic Date getTriggerTime() {\n\t\treturn triggerTime;\n\t}\n\n\tpublic void setTriggerTime(Date triggerTime) {\n\t\tthis.triggerTime = triggerTime;\n\t}\n\n\tpublic int getTriggerCode() {\n\t\treturn triggerCode;\n\t}\n\n\tpublic void setTriggerCode(int triggerCode) {\n\t\tthis.triggerCode = triggerCode;\n\t}\n\n\tpublic String getTriggerMsg() {\n\t\treturn triggerMsg;\n\t}\n\n\tpublic void setTriggerMsg(String triggerMsg) {\n\t\tthis.triggerMsg = triggerMsg;\n\t}\n\n\tpublic Date getHandleTime() {\n\t\treturn handleTime;\n\t}\n\n\tpublic void setHandleTime(Date handleTime) {\n\t\tthis.handleTime = handleTime;\n\t}\n\n\tpublic int getHandleCode() {\n\t\treturn handleCode;\n\t}\n\n\tpublic void setHandleCode(int handleCode) {\n\t\tthis.handleCode = handleCode;\n\t}\n\n\tpublic String getHandleMsg() {\n\t\treturn handleMsg;\n\t}\n\n\tpublic void setHandleMsg(String handleMsg) {\n\t\tthis.handleMsg = handleMsg;\n\t}\n\n\tpublic int getAlarmStatus() {\n\t\treturn alarmStatus;\n\t}\n\n\tpublic void setAlarmStatus(int alarmStatus) {\n\t\tthis.alarmStatus = alarmStatus;\n\t}\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/model/XxlJobLogGlue.java",
    "content": "package com.xxl.job.admin.model;\n\nimport java.util.Date;\n\n/**\n * xxl-job log for glue, used to track job code process\n * @author xuxueli 2016-5-19 17:57:46\n */\npublic class XxlJobLogGlue {\n\t\n\tprivate int id;\n\tprivate int jobId;\t\t\t\t// 任务主键ID\n\tprivate String glueType;\t\t// GLUE类型\t#com.xxl.job.core.glue.GlueTypeEnum\n\tprivate String glueSource;\n\tprivate String glueRemark;\n\tprivate Date addTime;\n\tprivate Date updateTime;\n\n\tpublic int getId() {\n\t\treturn id;\n\t}\n\n\tpublic void setId(int id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic int getJobId() {\n\t\treturn jobId;\n\t}\n\n\tpublic void setJobId(int jobId) {\n\t\tthis.jobId = jobId;\n\t}\n\n\tpublic String getGlueType() {\n\t\treturn glueType;\n\t}\n\n\tpublic void setGlueType(String glueType) {\n\t\tthis.glueType = glueType;\n\t}\n\n\tpublic String getGlueSource() {\n\t\treturn glueSource;\n\t}\n\n\tpublic void setGlueSource(String glueSource) {\n\t\tthis.glueSource = glueSource;\n\t}\n\n\tpublic String getGlueRemark() {\n\t\treturn glueRemark;\n\t}\n\n\tpublic void setGlueRemark(String glueRemark) {\n\t\tthis.glueRemark = glueRemark;\n\t}\n\n\tpublic Date getAddTime() {\n\t\treturn addTime;\n\t}\n\n\tpublic void setAddTime(Date addTime) {\n\t\tthis.addTime = addTime;\n\t}\n\n\tpublic Date getUpdateTime() {\n\t\treturn updateTime;\n\t}\n\n\tpublic void setUpdateTime(Date updateTime) {\n\t\tthis.updateTime = updateTime;\n\t}\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/model/XxlJobLogReport.java",
    "content": "package com.xxl.job.admin.model;\n\nimport java.util.Date;\n\npublic class XxlJobLogReport {\n\n    private int id;\n\n    private Date triggerDay;\n\n    private int runningCount;\n    private int sucCount;\n    private int failCount;\n\n    public int getId() {\n        return id;\n    }\n\n    public void setId(int id) {\n        this.id = id;\n    }\n\n    public Date getTriggerDay() {\n        return triggerDay;\n    }\n\n    public void setTriggerDay(Date triggerDay) {\n        this.triggerDay = triggerDay;\n    }\n\n    public int getRunningCount() {\n        return runningCount;\n    }\n\n    public void setRunningCount(int runningCount) {\n        this.runningCount = runningCount;\n    }\n\n    public int getSucCount() {\n        return sucCount;\n    }\n\n    public void setSucCount(int sucCount) {\n        this.sucCount = sucCount;\n    }\n\n    public int getFailCount() {\n        return failCount;\n    }\n\n    public void setFailCount(int failCount) {\n        this.failCount = failCount;\n    }\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/model/XxlJobRegistry.java",
    "content": "package com.xxl.job.admin.model;\n\nimport java.util.Date;\n\n/**\n * Created by xuxueli on 16/9/30.\n */\npublic class XxlJobRegistry {\n\n    private int id;\n    private String registryGroup;\n    private String registryKey;\n    private String registryValue;\n    private Date updateTime;\n\n    public int getId() {\n        return id;\n    }\n\n    public void setId(int id) {\n        this.id = id;\n    }\n\n    public String getRegistryGroup() {\n        return registryGroup;\n    }\n\n    public void setRegistryGroup(String registryGroup) {\n        this.registryGroup = registryGroup;\n    }\n\n    public String getRegistryKey() {\n        return registryKey;\n    }\n\n    public void setRegistryKey(String registryKey) {\n        this.registryKey = registryKey;\n    }\n\n    public String getRegistryValue() {\n        return registryValue;\n    }\n\n    public void setRegistryValue(String registryValue) {\n        this.registryValue = registryValue;\n    }\n\n    public Date getUpdateTime() {\n        return updateTime;\n    }\n\n    public void setUpdateTime(Date updateTime) {\n        this.updateTime = updateTime;\n    }\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/model/XxlJobUser.java",
    "content": "package com.xxl.job.admin.model;\n\n/**\n * @author xuxueli 2019-05-04 16:43:12\n */\npublic class XxlJobUser {\n\t\n\tprivate int id;\n\tprivate String username;\t\t// 账号\n\tprivate String password;\t\t// 密码\n\tprivate String token;\t\t\t// 登录token\n\tprivate int role;\t\t\t\t// 角色：0-普通用户、1-管理员\n\tprivate String permission;\t\t// 权限：执行器ID列表，多个逗号分割\n\n\tpublic int getId() {\n\t\treturn id;\n\t}\n\n\tpublic void setId(int id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic String getUsername() {\n\t\treturn username;\n\t}\n\n\tpublic void setUsername(String username) {\n\t\tthis.username = username;\n\t}\n\n\tpublic String getPassword() {\n\t\treturn password;\n\t}\n\n\tpublic void setPassword(String password) {\n\t\tthis.password = password;\n\t}\n\n\tpublic String getToken() {\n\t\treturn token;\n\t}\n\n\tpublic void setToken(String token) {\n\t\tthis.token = token;\n\t}\n\n\tpublic int getRole() {\n\t\treturn role;\n\t}\n\n\tpublic void setRole(int role) {\n\t\tthis.role = role;\n\t}\n\n\tpublic String getPermission() {\n\t\treturn permission;\n\t}\n\n\tpublic void setPermission(String permission) {\n\t\tthis.permission = permission;\n\t}\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/model/dto/XxlBootResourceDTO.java",
    "content": "package com.xxl.job.admin.model.dto;\n\nimport java.io.Serializable;\nimport java.util.Date;\nimport java.util.List;\n\n/**\n *  XxlBootResource DTO\n *\n *  Created by xuxueli on 2024-08-04\n */\npublic class XxlBootResourceDTO implements Serializable {\n    private static final long serialVersionUID = 42L;\n\n    /**\n     * 资源ID\n     */\n    private int id;\n\n    /**\n     * 父节点ID\n     */\n    private int parentId;\n\n    /**\n     * 名称\n     */\n    private String name;\n\n    /**\n     * 类型：0-目录, 1-菜单, 2-按钮\n     */\n    private int type;\n\n    /**\n     * 权限标识\n     */\n    private String permission;\n\n    /**\n     * 菜单地址\n     */\n    private String url;\n\n    /**\n     * ICON\n     */\n    private String icon;\n\n    /**\n     * 顺序\n     */\n    private int order;\n\n    /**\n     * 状态：0-正常、1-禁用\n     */\n    private int status;\n\n    /**\n     * 新增时间\n     */\n    private Date addTime;\n\n    /**\n     * 更新时间\n     */\n    private Date updateTime;\n\n    /**\n     * child data\n     */\n    private List<XxlBootResourceDTO> children;\n\n    public XxlBootResourceDTO() {\n    }\n    public XxlBootResourceDTO(int id, int parentId, String name, int type, String permission, String url, String icon, int order, int status, List<XxlBootResourceDTO> children) {\n        this.id = id;\n        this.parentId = parentId;\n        this.name = name;\n        this.type = type;\n        this.permission = permission;\n        this.url = url;\n        this.icon = icon;\n        this.order = order;\n        this.status = status;\n        this.children = children;\n    }\n\n    public int getId() {\n        return id;\n    }\n\n    public void setId(int id) {\n        this.id = id;\n    }\n\n    public int getParentId() {\n        return parentId;\n    }\n\n    public void setParentId(int parentId) {\n        this.parentId = parentId;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public int getType() {\n        return type;\n    }\n\n    public void setType(int type) {\n        this.type = type;\n    }\n\n    public String getPermission() {\n        return permission;\n    }\n\n    public void setPermission(String permission) {\n        this.permission = permission;\n    }\n\n    public String getUrl() {\n        return url;\n    }\n\n    public void setUrl(String url) {\n        this.url = url;\n    }\n\n    public String getIcon() {\n        return icon;\n    }\n\n    public void setIcon(String icon) {\n        this.icon = icon;\n    }\n\n    public int getOrder() {\n        return order;\n    }\n\n    public void setOrder(int order) {\n        this.order = order;\n    }\n\n    public int getStatus() {\n        return status;\n    }\n\n    public void setStatus(int status) {\n        this.status = status;\n    }\n\n    public Date getAddTime() {\n        return addTime;\n    }\n\n    public void setAddTime(Date addTime) {\n        this.addTime = addTime;\n    }\n\n    public Date getUpdateTime() {\n        return updateTime;\n    }\n\n    public void setUpdateTime(Date updateTime) {\n        this.updateTime = updateTime;\n    }\n\n    public List<XxlBootResourceDTO> getChildren() {\n        return children;\n    }\n\n    public void setChildren(List<XxlBootResourceDTO> children) {\n        this.children = children;\n    }\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/alarm/JobAlarm.java",
    "content": "package com.xxl.job.admin.scheduler.alarm;\n\nimport com.xxl.job.admin.model.XxlJobInfo;\nimport com.xxl.job.admin.model.XxlJobLog;\n\n/**\n * @author xuxueli 2020-01-19\n */\npublic interface JobAlarm {\n\n    /**\n     * job alarm\n     *\n     * @param info\n     * @param jobLog\n     * @return\n     */\n    public boolean doAlarm(XxlJobInfo info, XxlJobLog jobLog);\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/alarm/JobAlarmer.java",
    "content": "package com.xxl.job.admin.scheduler.alarm;\n\nimport com.xxl.job.admin.model.XxlJobInfo;\nimport com.xxl.job.admin.model.XxlJobLog;\nimport com.xxl.tool.core.CollectionTool;\nimport com.xxl.tool.core.MapTool;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.stereotype.Component;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * xxl-job alarmer\n *\n * @author xuxueli 17/7/13.\n */\n@Component\npublic class JobAlarmer implements ApplicationContextAware, InitializingBean {\n    private static final Logger logger = LoggerFactory.getLogger(JobAlarmer.class);\n\n    private ApplicationContext applicationContext;\n    private List<JobAlarm> jobAlarmList;\n\n    @Override\n    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {\n        this.applicationContext = applicationContext;\n    }\n\n    @Override\n    public void afterPropertiesSet() throws Exception {\n        Map<String, JobAlarm> serviceBeanMap = applicationContext.getBeansOfType(JobAlarm.class);\n        if (MapTool.isNotEmpty(serviceBeanMap)) {\n            jobAlarmList = new ArrayList<>(serviceBeanMap.values());\n        }\n    }\n\n    /**\n     * job alarm\n     */\n    public boolean alarm(XxlJobInfo info, XxlJobLog jobLog) {\n\n        boolean result = false;\n        if (CollectionTool.isNotEmpty(jobAlarmList)) {\n            result = true;  // success means all-success\n            for (JobAlarm alarm: jobAlarmList) {\n                boolean resultItem = false;\n                try {\n                    resultItem = alarm.doAlarm(info, jobLog);\n                } catch (Exception e) {\n                    logger.error(e.getMessage(), e);\n                }\n                if (!resultItem) {\n                    result = false;\n                }\n            }\n        }\n\n        return result;\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/alarm/impl/EmailJobAlarm.java",
    "content": "package com.xxl.job.admin.scheduler.alarm.impl;\n\nimport com.xxl.job.admin.scheduler.alarm.JobAlarm;\nimport com.xxl.job.admin.scheduler.config.XxlJobAdminBootstrap;\nimport com.xxl.job.admin.model.XxlJobGroup;\nimport com.xxl.job.admin.model.XxlJobInfo;\nimport com.xxl.job.admin.model.XxlJobLog;\nimport com.xxl.job.admin.util.I18nUtil;\nimport com.xxl.job.core.context.XxlJobContext;\nimport jakarta.mail.internet.MimeMessage;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.mail.javamail.MimeMessageHelper;\nimport org.springframework.stereotype.Component;\n\nimport java.text.MessageFormat;\nimport java.util.Arrays;\nimport java.util.HashSet;\nimport java.util.Set;\n\n/**\n * job alarm by email\n *\n * @author xuxueli 2020-01-19\n */\n@Component\npublic class EmailJobAlarm implements JobAlarm {\n    private static Logger logger = LoggerFactory.getLogger(EmailJobAlarm.class);\n\n    /**\n     * fail alarm\n     *\n     * @param jobLog\n     */\n    @Override\n    public boolean doAlarm(XxlJobInfo info, XxlJobLog jobLog){\n        boolean alarmResult = true;\n\n        // send monitor email\n        if (info!=null && info.getAlarmEmail()!=null && !info.getAlarmEmail().trim().isEmpty()) {\n\n            // alarmContent\n            String alarmContent = \"Alarm Job LogId=\" + jobLog.getId();\n            if (jobLog.getTriggerCode() != XxlJobContext.HANDLE_CODE_SUCCESS) {\n                alarmContent += \"<br>TriggerMsg=<br>\" + jobLog.getTriggerMsg();\n            }\n            if (jobLog.getHandleCode()>0 && jobLog.getHandleCode() != XxlJobContext.HANDLE_CODE_SUCCESS) {\n                alarmContent += \"<br>HandleCode=\" + jobLog.getHandleMsg();\n            }\n\n            // email info\n            XxlJobGroup group = XxlJobAdminBootstrap.getInstance().getXxlJobGroupMapper().load(Integer.valueOf(info.getJobGroup()));\n            String personal = I18nUtil.getString(\"admin_name_full\");\n            String title = I18nUtil.getString(\"jobconf_monitor\");\n            String content = MessageFormat.format(loadEmailJobAlarmTemplate(),\n                    group!=null?group.getTitle():\"null\",\n                    info.getId(),\n                    info.getJobDesc(),\n                    alarmContent);\n\n            Set<String> emailSet = new HashSet<String>(Arrays.asList(info.getAlarmEmail().split(\",\")));\n            for (String email: emailSet) {\n\n                // make mail\n                try {\n                    MimeMessage mimeMessage = XxlJobAdminBootstrap.getInstance().getMailSender().createMimeMessage();\n\n                    MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);\n                    helper.setFrom(XxlJobAdminBootstrap.getInstance().getEmailFrom(), personal);\n                    helper.setTo(email);\n                    helper.setSubject(title);\n                    helper.setText(content, true);\n\n                    XxlJobAdminBootstrap.getInstance().getMailSender().send(mimeMessage);\n                } catch (Exception e) {\n                    logger.error(\">>>>>>>>>>> xxl-job, job fail alarm email send error, JobLogId:{}\", jobLog.getId(), e);\n\n                    alarmResult = false;\n                }\n\n            }\n        }\n\n        return alarmResult;\n    }\n\n    /**\n     * load email job alarm template\n     *\n     * @return\n     */\n    private static final String loadEmailJobAlarmTemplate(){\n        String mailBodyTemplate = \"<h5>\" + I18nUtil.getString(\"jobconf_monitor_detail\") + \"：</span>\" +\n                \"<table border=\\\"1\\\" cellpadding=\\\"3\\\" style=\\\"border-collapse:collapse; width:80%;\\\" >\\n\" +\n                \"   <thead style=\\\"font-weight: bold;color: #ffffff;background-color: #ff8c00;\\\" >\" +\n                \"      <tr>\\n\" +\n                \"         <td width=\\\"20%\\\" >\"+ I18nUtil.getString(\"jobinfo_field_jobgroup\") +\"</td>\\n\" +\n                \"         <td width=\\\"10%\\\" >\"+ I18nUtil.getString(\"jobinfo_field_id\") +\"</td>\\n\" +\n                \"         <td width=\\\"20%\\\" >\"+ I18nUtil.getString(\"jobinfo_field_jobdesc\") +\"</td>\\n\" +\n                \"         <td width=\\\"10%\\\" >\"+ I18nUtil.getString(\"jobconf_monitor_alarm_title\") +\"</td>\\n\" +\n                \"         <td width=\\\"40%\\\" >\"+ I18nUtil.getString(\"jobconf_monitor_alarm_content\") +\"</td>\\n\" +\n                \"      </tr>\\n\" +\n                \"   </thead>\\n\" +\n                \"   <tbody>\\n\" +\n                \"      <tr>\\n\" +\n                \"         <td>{0}</td>\\n\" +\n                \"         <td>{1}</td>\\n\" +\n                \"         <td>{2}</td>\\n\" +\n                \"         <td>\"+ I18nUtil.getString(\"jobconf_monitor_alarm_type\") +\"</td>\\n\" +\n                \"         <td>{3}</td>\\n\" +\n                \"      </tr>\\n\" +\n                \"   </tbody>\\n\" +\n                \"</table>\";\n\n        return mailBodyTemplate;\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/complete/JobCompleter.java",
    "content": "package com.xxl.job.admin.scheduler.complete;\n\nimport com.xxl.job.admin.mapper.XxlJobInfoMapper;\nimport com.xxl.job.admin.mapper.XxlJobLogMapper;\nimport com.xxl.job.admin.model.XxlJobInfo;\nimport com.xxl.job.admin.model.XxlJobLog;\nimport com.xxl.job.admin.scheduler.config.XxlJobAdminBootstrap;\nimport com.xxl.job.admin.scheduler.trigger.TriggerTypeEnum;\nimport com.xxl.job.admin.util.I18nUtil;\nimport com.xxl.job.core.context.XxlJobContext;\nimport com.xxl.tool.core.StringTool;\nimport com.xxl.tool.response.Response;\nimport jakarta.annotation.Resource;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.stereotype.Component;\n\nimport java.text.MessageFormat;\n\n/**\n * xxl-job job log complete\n *\n * @author xuxueli 2020-10-30 20:43:10\n */\n@Component\npublic class JobCompleter {\n    private static final Logger logger = LoggerFactory.getLogger(JobCompleter.class);\n\n\n    @Resource\n    private XxlJobInfoMapper xxlJobInfoMapper;\n    @Resource\n    private XxlJobLogMapper xxlJobLogMapper;\n\n\n    /**\n     * complate job (limit only once)\n     */\n    public int complete(XxlJobLog xxlJobLog) {\n\n        // 1、process child-job\n        processChildJob(xxlJobLog);\n\n        // text最大64kb 避免长度过长\n        if (xxlJobLog.getHandleMsg().length() > 15000) {\n            xxlJobLog.setHandleMsg( xxlJobLog.getHandleMsg().substring(0, 15000) );\n        }\n\n        // 2、fix_delay trigger next\n        // on the way\n\n        // 3、update job handle-info\n        return xxlJobLogMapper.updateHandleInfo(xxlJobLog);\n    }\n\n\n    /**\n     * do somethind to finish job\n     */\n    private void processChildJob(XxlJobLog xxlJobLog){\n\n        // 1、handle success, to trigger child job\n        String triggerChildMsg = null;\n        if (XxlJobContext.HANDLE_CODE_SUCCESS == xxlJobLog.getHandleCode()) {\n            XxlJobInfo xxlJobInfo = xxlJobInfoMapper.loadById(xxlJobLog.getJobId());\n\n            // process child job\n            if (xxlJobInfo!=null && StringTool.isNotBlank(xxlJobInfo.getChildJobId())) {\n                triggerChildMsg = \"<br><br><span style=\\\"color:#00c0ef;\\\" > >>>>>>>>>>>\"+ I18nUtil.getString(\"jobconf_trigger_child_run\") +\"<<<<<<<<<<< </span><br>\";\n                String[] childJobIds = xxlJobInfo.getChildJobId().split(\",\");\n                for (int i = 0; i < childJobIds.length; i++) {\n\n                    // process eath child\n                    int childJobId = (StringTool.isNotBlank(childJobIds[i]) && StringTool.isNumeric(childJobIds[i]))\n                            ?Integer.parseInt(childJobIds[i])\n                            :-1;\n                    if (childJobId > 0) {\n                        // valid\n                        if (childJobId == xxlJobLog.getJobId()) {\n                            logger.debug(\">>>>>>>>>>> xxl-job, XxlJobCompleter-finishJob ignore childJobId,  childJobId {} is self.\", childJobId);\n                            continue;\n                        }\n\n                        // trigger child job\n                        XxlJobAdminBootstrap.getInstance().getJobTriggerPoolHelper().trigger(childJobId, TriggerTypeEnum.PARENT, -1, null, null, null);\n                        Response<String> triggerChildResult = Response.ofSuccess();\n\n                        // add msg\n                        triggerChildMsg += MessageFormat.format(I18nUtil.getString(\"jobconf_callback_child_msg1\"),\n                                (i+1),\n                                childJobIds.length,\n                                childJobIds[i],\n                                (triggerChildResult.isSuccess()?I18nUtil.getString(\"system_success\"):I18nUtil.getString(\"system_fail\")),\n                                triggerChildResult.getMsg());\n                    } else {\n                        triggerChildMsg += MessageFormat.format(I18nUtil.getString(\"jobconf_callback_child_msg2\"),\n                                (i+1),\n                                childJobIds.length,\n                                childJobIds[i]);\n                    }\n                }\n\n            }\n        }\n\n        // 2、append trigger-child message\n        if (StringTool.isNotBlank(triggerChildMsg)) {\n            xxlJobLog.setHandleMsg( xxlJobLog.getHandleMsg() + triggerChildMsg );\n        }\n\n    }\n\n    /*private static boolean isNumeric(String str){\n        try {\n            int result = Integer.valueOf(str);\n            return true;\n        } catch (NumberFormatException e) {\n            return false;\n        }\n    }*/\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/config/XxlJobAdminBootstrap.java",
    "content": "package com.xxl.job.admin.scheduler.config;\n\nimport com.xxl.job.admin.mapper.*;\nimport com.xxl.job.admin.scheduler.alarm.JobAlarmer;\nimport com.xxl.job.admin.scheduler.complete.JobCompleter;\nimport com.xxl.job.admin.scheduler.thread.*;\nimport com.xxl.job.admin.scheduler.trigger.JobTrigger;\nimport com.xxl.job.core.constant.Const;\nimport com.xxl.job.core.openapi.ExecutorBiz;\nimport com.xxl.tool.core.StringTool;\nimport com.xxl.tool.http.HttpTool;\nimport jakarta.annotation.Resource;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.DisposableBean;\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.mail.javamail.JavaMailSender;\nimport org.springframework.stereotype.Component;\nimport org.springframework.transaction.PlatformTransactionManager;\n\nimport java.util.Arrays;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\n/**\n * xxl-job config\n *\n * @author xuxueli 2017-04-28\n */\n\n@Component\npublic class XxlJobAdminBootstrap implements InitializingBean, DisposableBean {\n    private static final Logger logger = LoggerFactory.getLogger(XxlJobAdminBootstrap.class);\n\n    // ---------------------- instance ----------------------\n\n    private static XxlJobAdminBootstrap adminConfig = null;\n    public static XxlJobAdminBootstrap getInstance() {\n        return adminConfig;\n    }\n\n\n    // ---------------------- start / stop ----------------------\n\n    @Override\n    public void afterPropertiesSet() throws Exception {\n        // init instance\n        adminConfig = this;\n\n        // start\n        doStart();\n    }\n\n    @Override\n    public void destroy() throws Exception {\n        // stop\n        doStop();\n    }\n\n    // job module\n    private JobTriggerPoolHelper jobTriggerPoolHelper;\n    private JobRegistryHelper jobRegistryHelper;\n    private JobFailAlarmMonitorHelper jobFailAlarmMonitorHelper;\n    private JobCompleteHelper jobCompleteHelper;\n    private JobLogReportHelper jobLogReportHelper;\n    private JobScheduleHelper jobScheduleHelper;\n\n    public JobTriggerPoolHelper getJobTriggerPoolHelper() {\n        return jobTriggerPoolHelper;\n    }\n    public JobRegistryHelper getJobRegistryHelper() {\n        return jobRegistryHelper;\n    }\n    public JobCompleteHelper getJobCompleteHelper() {\n        return jobCompleteHelper;\n    }\n\n    /**\n     * do start\n     */\n    private void doStart() throws Exception {\n        // trigger-pool start\n        jobTriggerPoolHelper = new JobTriggerPoolHelper();\n        jobTriggerPoolHelper.start();\n\n        // registry monitor start\n        jobRegistryHelper = new JobRegistryHelper();\n        jobRegistryHelper.start();\n\n        // fail-alarm monitor start\n        jobFailAlarmMonitorHelper = new JobFailAlarmMonitorHelper();\n        jobFailAlarmMonitorHelper.start();\n\n        // job complate start  ( depend on JobTriggerPoolHelper ) for callback and result-lost\n        jobCompleteHelper = new JobCompleteHelper();\n        jobCompleteHelper.start();\n\n        // log-report start\n        jobLogReportHelper = new JobLogReportHelper();\n        jobLogReportHelper.start();\n\n        // job-schedule start  ( depend on JobTriggerPoolHelper )\n        jobScheduleHelper = new JobScheduleHelper();\n        jobScheduleHelper.start();\n\n        logger.info(\">>>>>>>>> xxl-job admin start success.\");\n    }\n\n    /**\n     * do stop\n     */\n    private void doStop(){\n        // job-schedule stop\n        jobScheduleHelper.stop();\n\n        // log-report stop\n        jobLogReportHelper.stop();\n\n        // job complate stop\n        jobCompleteHelper.stop();\n\n        // fail-alarm monitor stop\n        jobFailAlarmMonitorHelper.stop();\n\n        // registry monitor stop\n        jobRegistryHelper.stop();\n\n        // trigger-pool stop\n        jobTriggerPoolHelper.stop();\n\n        logger.info(\">>>>>>>>> xxl-job admin stopped.\");\n    }\n\n\n    // ---------------------- executor-client ----------------------\n\n    private static ConcurrentMap<String, ExecutorBiz> executorBizRepository = new ConcurrentHashMap<String, ExecutorBiz>();\n    public static ExecutorBiz getExecutorBiz(String address) throws Exception {\n        // valid\n        if (StringTool.isBlank(address)) {\n            return null;\n        }\n\n        // load-cache\n        address = address.trim();\n        ExecutorBiz executorBiz = executorBizRepository.get(address);\n        if (executorBiz != null) {\n            return executorBiz;\n        }\n\n        // set-cache\n        executorBiz = HttpTool.createClient()\n                .url(address)\n                .timeout(XxlJobAdminBootstrap.getInstance().getTimeout() * 1000)\n                .header(Const.XXL_JOB_ACCESS_TOKEN, XxlJobAdminBootstrap.getInstance().getAccessToken())\n                .proxy(ExecutorBiz.class);\n        executorBizRepository.put(address, executorBiz);\n        return executorBiz;\n    }\n\n\n    // ---------------------- field ----------------------\n\n    // conf\n    @Value(\"${xxl.job.i18n}\")\n    private String i18n;\n\n    @Value(\"${xxl.job.accessToken}\")\n    private String accessToken;\n\n    @Value(\"${xxl.job.timeout}\")\n    private int timeout;\n\n    @Value(\"${spring.mail.from}\")\n    private String emailFrom;\n\n    @Value(\"${xxl.job.triggerpool.fast.max}\")\n    private int triggerPoolFastMax;\n\n    @Value(\"${xxl.job.triggerpool.slow.max}\")\n    private int triggerPoolSlowMax;\n\n    @Value(\"${xxl.job.logretentiondays}\")\n    private int logretentiondays;\n\n    // service, mapper\n    @Resource\n    private XxlJobLogMapper xxlJobLogMapper;\n    @Resource\n    private XxlJobInfoMapper xxlJobInfoMapper;\n    @Resource\n    private XxlJobRegistryMapper xxlJobRegistryMapper;\n    @Resource\n    private XxlJobGroupMapper xxlJobGroupMapper;\n    @Resource\n    private XxlJobLogReportMapper xxlJobLogReportMapper;\n    @Resource\n    private XxlJobLockMapper xxlJobLockMapper;\n    @Resource\n    private JavaMailSender mailSender;\n    /*@Resource\n    private DataSource dataSource;*/\n    @Resource\n    private PlatformTransactionManager transactionManager;\n    @Resource\n    private JobAlarmer jobAlarmer;\n    @Resource\n    private JobTrigger jobTrigger;\n    @Resource\n    private JobCompleter jobCompleter;\n\n\n    public String getI18n() {\n        if (!Arrays.asList(\"zh_CN\", \"zh_TC\", \"en\").contains(i18n)) {\n            return \"zh_CN\";\n        }\n        return i18n;\n    }\n\n    public String getAccessToken() {\n        return accessToken;\n    }\n\n    public int getTimeout() {\n        return timeout;\n    }\n\n    public String getEmailFrom() {\n        return emailFrom;\n    }\n\n    public int getTriggerPoolFastMax() {\n        if (triggerPoolFastMax < 200) {\n            return 200;\n        }\n        return triggerPoolFastMax;\n    }\n\n    public int getTriggerPoolSlowMax() {\n        if (triggerPoolSlowMax < 100) {\n            return 100;\n        }\n        return triggerPoolSlowMax;\n    }\n\n    public int getLogretentiondays() {\n        if (logretentiondays < 3) {\n            return -1;  // Limit greater than or equal to 3, otherwise close\n        }\n        return logretentiondays;\n    }\n\n    public XxlJobLogMapper getXxlJobLogMapper() {\n        return xxlJobLogMapper;\n    }\n\n    public XxlJobInfoMapper getXxlJobInfoMapper() {\n        return xxlJobInfoMapper;\n    }\n\n    public XxlJobRegistryMapper getXxlJobRegistryMapper() {\n        return xxlJobRegistryMapper;\n    }\n\n    public XxlJobGroupMapper getXxlJobGroupMapper() {\n        return xxlJobGroupMapper;\n    }\n\n    public XxlJobLogReportMapper getXxlJobLogReportMapper() {\n        return xxlJobLogReportMapper;\n    }\n\n    public XxlJobLockMapper getXxlJobLockMapper() {\n        return xxlJobLockMapper;\n    }\n\n    public JavaMailSender getMailSender() {\n        return mailSender;\n    }\n\n    /*public DataSource getDataSource() {\n        return dataSource;\n    }*/\n\n    public PlatformTransactionManager getTransactionManager() {\n        return transactionManager;\n    }\n\n    public JobAlarmer getJobAlarmer() {\n        return jobAlarmer;\n    }\n\n    public JobTrigger getJobTrigger() {\n        return jobTrigger;\n    }\n\n    public JobCompleter getJobCompleter() {\n        return jobCompleter;\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/cron/CronExpression.java",
    "content": "package com.xxl.job.admin.scheduler.cron;\n\nimport java.io.Serializable;\nimport java.text.ParseException;\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.SortedSet;\nimport java.util.StringTokenizer;\nimport java.util.TimeZone;\nimport java.util.TreeSet;\n\n/**\n * Provides a parser and evaluator for unix-like cron expressions. Cron\n * expressions provide the ability to specify complex time combinations such as\n * &quot;At 8:00am every Monday through Friday&quot; or &quot;At 1:30am every\n * last Friday of the month&quot;.\n * <p>\n * Cron expressions are comprised of 6 required fields and one optional field\n * separated by white space. The fields respectively are described as follows:\n * </p>\n * <table>\n * <caption>Examples of cron expressions and their meanings.</caption>\n * <tr>\n * <th>Field Name</th>\n * <th>&nbsp;</th>\n * <th>Allowed Values</th>\n * <th>&nbsp;</th>\n * <th>Allowed Special Characters</th>\n * </tr>\n * <tr>\n * <td><code>Seconds</code></td>\n * <td>&nbsp;</td>\n * <td><code>0-59</code></td>\n * <td>&nbsp;</td>\n * <td><code>, - * /</code></td>\n * </tr>\n * <tr>\n * <td><code>Minutes</code></td>\n * <td>&nbsp;</td>\n * <td><code>0-59</code></td>\n * <td>&nbsp;</td>\n * <td><code>, - * /</code></td>\n * </tr>\n * <tr>\n * <td><code>Hours</code></td>\n * <td>&nbsp;</td>\n * <td><code>0-23</code></td>\n * <td>&nbsp;</td>\n * <td><code>, - * /</code></td>\n * </tr>\n * <tr>\n * <td><code>Day-of-month</code></td>\n * <td>&nbsp;</td>\n * <td><code>1-31</code></td>\n * <td>&nbsp;</td>\n * <td><code>, - * ? / L W</code></td>\n * </tr>\n * <tr>\n * <td><code>Month</code></td>\n * <td>&nbsp;</td>\n * <td><code>0-11 or JAN-DEC</code></td>\n * <td>&nbsp;</td>\n * <td><code>, - * /</code></td>\n * </tr>\n * <tr>\n * <td><code>Day-of-Week</code></td>\n * <td>&nbsp;</td>\n * <td><code>1-7 or SUN-SAT</code></td>\n * <td>&nbsp;</td>\n * <td><code>, - * ? / L #</code></td>\n * </tr>\n * <tr>\n * <td><code>Year (Optional)</code></td>\n * <td>&nbsp;</td>\n * <td><code>empty, 1970-2199</code></td>\n * <td>&nbsp;</td>\n * <td><code>, - * /</code></td>\n * </tr>\n * </table>\n * <p>\n * The '*' character is used to specify all values. For example, &quot;*&quot;\n * in the minute field means &quot;every minute&quot;.\n * </p>\n * <p>\n * The '?' character is allowed for the day-of-month and day-of-week fields. It\n * is used to specify 'no specific value'. This is useful when you need to\n * specify something in one of the two fields, but not the other.\n * <p>\n * The '-' character is used to specify ranges For example &quot;10-12&quot; in\n * the hour field means &quot;the hours 10, 11 and 12&quot;.\n * <p>\n * The ',' character is used to specify additional values. For example\n * &quot;MON,WED,FRI&quot; in the day-of-week field means &quot;the days Monday,\n * Wednesday, and Friday&quot;.\n * </p>\n * <p>\n * The '/' character is used to specify increments. For example &quot;0/15&quot;\n * in the seconds field means &quot;the seconds 0, 15, 30, and 45&quot;. And\n * &quot;5/15&quot; in the seconds field means &quot;the seconds 5, 20, 35, and\n * 50&quot;.  Specifying '*' before the  '/' is equivalent to specifying 0 is\n * the value to start with. Essentially, for each field in the expression, there\n * is a set of numbers that can be turned on or off. For seconds and minutes,\n * the numbers range from 0 to 59. For hours 0 to 23, for days of the month 0 to\n * 31, and for months 0 to 11 (JAN to DEC). The &quot;/&quot; character simply helps you turn\n * on every &quot;nth&quot; value in the given set. Thus &quot;7/6&quot; in the\n * month field only turns on month &quot;7&quot;, it does NOT mean every 6th\n * month, please note that subtlety.\n * </p>\n * <p>\n * The 'L' character is allowed for the day-of-month and day-of-week fields.\n * This character is short-hand for &quot;last&quot;, but it has different\n * meaning in each of the two fields. For example, the value &quot;L&quot; in\n * the day-of-month field means &quot;the last day of the month&quot; - day 31\n * for January, day 28 for February on non-leap years. If used in the\n * day-of-week field by itself, it simply means &quot;7&quot; or\n * &quot;SAT&quot;. But if used in the day-of-week field after another value, it\n * means &quot;the last xxx day of the month&quot; - for example &quot;6L&quot;\n * means &quot;the last friday of the month&quot;. You can also specify an offset\n * from the last day of the month, such as \"L-3\" which would mean the third-to-last\n * day of the calendar month. <i>When using the 'L' option, it is important not to\n * specify lists, or ranges of values, as you'll get confusing/unexpected results.</i>\n * </p>\n * <p>\n * The 'W' character is allowed for the day-of-month field.  This character\n * is used to specify the weekday (Monday-Friday) nearest the given day.  As an\n * example, if you were to specify &quot;15W&quot; as the value for the\n * day-of-month field, the meaning is: &quot;the nearest weekday to the 15th of\n * the month&quot;. So if the 15th is a Saturday, the trigger will fire on\n * Friday the 14th. If the 15th is a Sunday, the trigger will fire on Monday the\n * 16th. If the 15th is a Tuesday, then it will fire on Tuesday the 15th.\n * However if you specify &quot;1W&quot; as the value for day-of-month, and the\n * 1st is a Saturday, the trigger will fire on Monday the 3rd, as it will not\n * 'jump' over the boundary of a month's days.  The 'W' character can only be\n * specified when the day-of-month is a single day, not a range or list of days.\n * </p>\n * <p>\n * The 'L' and 'W' characters can also be combined for the day-of-month\n * expression to yield 'LW', which translates to &quot;last weekday of the\n * month&quot;.\n * </p>\n * <p>\n * The '#' character is allowed for the day-of-week field. This character is\n * used to specify &quot;the nth&quot; XXX day of the month. For example, the\n * value of &quot;6#3&quot; in the day-of-week field means the third Friday of\n * the month (day 6 = Friday and &quot;#3&quot; = the 3rd one in the month).\n * Other examples: &quot;2#1&quot; = the first Monday of the month and\n * &quot;4#5&quot; = the fifth Wednesday of the month. Note that if you specify\n * &quot;#5&quot; and there is not 5 of the given day-of-week in the month, then\n * no firing will occur that month.  If the '#' character is used, there can\n * only be one expression in the day-of-week field (&quot;3#1,6#3&quot; is\n * not valid, since there are two expressions).\n * </p>\n * <!--The 'C' character is allowed for the day-of-month and day-of-week fields.\n * This character is short-hand for \"calendar\". This means values are\n * calculated against the associated calendar, if any. If no calendar is\n * associated, then it is equivalent to having an all-inclusive calendar. A\n * value of \"5C\" in the day-of-month field means \"the first day included by the\n * calendar on or after the 5th\". A value of \"1C\" in the day-of-week field\n * means \"the first day included by the calendar on or after Sunday\".-->\n * <p>\n * The legal characters and the names of months and days of the week are not\n * case sensitive.\n *\n * <p>\n * <b>NOTES:</b>\n * </p>\n * <ul>\n * <li>Support for specifying both a day-of-week and a day-of-month value is\n * not complete (you'll need to use the '?' character in one of these fields).\n * </li>\n * <li>Overflowing ranges is supported - that is, having a larger number on\n * the left hand side than the right. You might do 22-2 to catch 10 o'clock\n * at night until 2 o'clock in the morning, or you might have NOV-FEB. It is\n * very important to note that overuse of overflowing ranges creates ranges\n * that don't make sense and no effort has been made to determine which\n * interpretation CronExpression chooses. An example would be\n * \"0 0 14-6 ? * FRI-MON\". </li>\n * </ul>\n *\n *\n * @author Sharada Jambula, James House\n * @author Contributions from Mads Henderson\n * @author Refactoring from CronTrigger to CronExpression by Aaron Craven\n *\n * Borrowed from quartz v2.5.0\n */\npublic final class CronExpression implements Serializable, Cloneable {\n\n    private static final long serialVersionUID = 12423409423L;\n\n    protected static final int SECOND = 0;\n    protected static final int MINUTE = 1;\n    protected static final int HOUR = 2;\n    protected static final int DAY_OF_MONTH = 3;\n    protected static final int MONTH = 4;\n    protected static final int DAY_OF_WEEK = 5;\n    protected static final int YEAR = 6;\n    protected static final int ALL_SPEC_INT = 99; // '*'\n    protected static final int NO_SPEC_INT = 98; // '?'\n    protected static final int MAX_LAST_DAY_OFFSET = 30;\n    protected static final int LAST_DAY_OFFSET_START = 32; // \"L-30\"\n    protected static final int LAST_DAY_OFFSET_END = LAST_DAY_OFFSET_START + MAX_LAST_DAY_OFFSET; // 'L'\n    protected static final Integer ALL_SPEC = ALL_SPEC_INT;\n    protected static final Integer NO_SPEC = NO_SPEC_INT;\n\n    protected static final Map<String, Integer> monthMap = new HashMap<>(20);\n    protected static final Map<String, Integer> dayMap = new HashMap<>(60);\n    static {\n        monthMap.put(\"JAN\", 0);\n        monthMap.put(\"FEB\", 1);\n        monthMap.put(\"MAR\", 2);\n        monthMap.put(\"APR\", 3);\n        monthMap.put(\"MAY\", 4);\n        monthMap.put(\"JUN\", 5);\n        monthMap.put(\"JUL\", 6);\n        monthMap.put(\"AUG\", 7);\n        monthMap.put(\"SEP\", 8);\n        monthMap.put(\"OCT\", 9);\n        monthMap.put(\"NOV\", 10);\n        monthMap.put(\"DEC\", 11);\n\n        dayMap.put(\"SUN\", 1);\n        dayMap.put(\"MON\", 2);\n        dayMap.put(\"TUE\", 3);\n        dayMap.put(\"WED\", 4);\n        dayMap.put(\"THU\", 5);\n        dayMap.put(\"FRI\", 6);\n        dayMap.put(\"SAT\", 7);\n    }\n\n    private final String cronExpression;\n    private TimeZone timeZone = null;\n    protected transient TreeSet<Integer> seconds;\n    protected transient TreeSet<Integer> minutes;\n    protected transient TreeSet<Integer> hours;\n    protected transient TreeSet<Integer> daysOfMonth;\n    protected transient TreeSet<Integer> nearestWeekdays;\n    protected transient TreeSet<Integer> months;\n    protected transient TreeSet<Integer> daysOfWeek;\n    protected transient TreeSet<Integer> years;\n\n    protected transient boolean lastDayOfWeek = false;\n    protected transient int nthDayOfWeek = 0;\n    protected transient boolean expressionParsed = false;\n\n    public static final int MAX_YEAR = Calendar.getInstance().get(Calendar.YEAR) + 100;\n\n    /**\n     * Constructs a new <CODE>CronExpression</CODE> based on the specified\n     * parameter.\n     *\n     * @param cronExpression String representation of the cron expression the\n     *                       new object should represent\n     * @throws java.text.ParseException\n     *         if the string expression cannot be parsed into a valid\n     *         <CODE>CronExpression</CODE>\n     */\n    public CronExpression(String cronExpression) throws ParseException {\n        if (cronExpression == null) {\n            throw new IllegalArgumentException(\"cronExpression cannot be null\");\n        }\n\n        this.cronExpression = cronExpression.toUpperCase(Locale.US);\n\n        buildExpression(this.cronExpression);\n    }\n\n    /**\n     * Constructs a new {@code CronExpression} as a copy of an existing\n     * instance.\n     *\n     * @param expression\n     *            The existing cron expression to be copied\n     */\n    public CronExpression(CronExpression expression) {\n        /*\n         * We don't call the other constructor here since we need to swallow the\n         * ParseException. We also elide some of the sanity checking as it is\n         * not logically trippable.\n         */\n        this.cronExpression = expression.getCronExpression();\n        try {\n            buildExpression(cronExpression);\n        } catch (ParseException ex) {\n            throw new AssertionError(\"Could not parse expression!\", ex);\n        }\n        if (expression.getTimeZone() != null) {\n            setTimeZone((TimeZone) expression.getTimeZone().clone());\n        }\n    }\n\n    /**\n     * Indicates whether the given date satisfies the cron expression. Note that\n     * milliseconds are ignored, so two Dates falling on different milliseconds\n     * of the same second will always have the same result here.\n     *\n     * @param date the date to evaluate\n     * @return a boolean indicating whether the given date satisfies the cron\n     *         expression\n     */\n    public boolean isSatisfiedBy(Date date) {\n        Calendar testDateCal = Calendar.getInstance(getTimeZone());\n        testDateCal.setTime(date);\n        testDateCal.set(Calendar.MILLISECOND, 0);\n        Date originalDate = testDateCal.getTime();\n\n        testDateCal.add(Calendar.SECOND, -1);\n\n        Date timeAfter = getTimeAfter(testDateCal.getTime());\n\n        return ((timeAfter != null) && (timeAfter.equals(originalDate)));\n    }\n\n    /**\n     * Returns the next date/time <I>after</I> the given date/time which\n     * satisfies the cron expression.\n     *\n     * @param date the date/time at which to begin the search for the next valid\n     *             date/time\n     * @return the next valid date/time\n     */\n    public Date getNextValidTimeAfter(Date date) {\n        return getTimeAfter(date);\n    }\n\n    /**\n     * Returns the next date/time <I>after</I> the given date/time which does\n     * <I>not</I> satisfy the expression\n     *\n     * @param date the date/time at which to begin the search for the next\n     *             invalid date/time\n     * @return the next valid date/time\n     */\n    public Date getNextInvalidTimeAfter(Date date) {\n        long difference = 1000;\n\n        //move back to the nearest second so differences will be accurate\n        Calendar adjustCal = Calendar.getInstance(getTimeZone());\n        adjustCal.setTime(date);\n        adjustCal.set(Calendar.MILLISECOND, 0);\n        Date lastDate = adjustCal.getTime();\n\n        Date newDate;\n\n        //FUTURE_TODO: (QUARTZ-481) IMPROVE THIS! The following is a BAD solution to this problem. Performance will be very bad here, depending on the cron expression. It is, however A solution.\n\n        //keep getting the next included time until it's farther than one second\n        // apart. At that point, lastDate is the last valid fire time. We return\n        // the second immediately following it.\n        while (difference == 1000) {\n            newDate = getTimeAfter(lastDate);\n            if(newDate == null)\n                break;\n\n            difference = newDate.getTime() - lastDate.getTime();\n\n            if (difference == 1000) {\n                lastDate = newDate;\n            }\n        }\n\n        return new Date(lastDate.getTime() + 1000);\n    }\n\n    /**\n     * Returns the time zone for which this <code>CronExpression</code>\n     * will be resolved.\n     */\n    public TimeZone getTimeZone() {\n        if (timeZone == null) {\n            timeZone = TimeZone.getDefault();\n        }\n\n        return timeZone;\n    }\n\n    /**\n     * Sets the time zone for which  this <code>CronExpression</code>\n     * will be resolved.\n     */\n    public void setTimeZone(TimeZone timeZone) {\n        this.timeZone = timeZone;\n    }\n\n    /**\n     * Returns the string representation of the <CODE>CronExpression</CODE>\n     *\n     * @return a string representation of the <CODE>CronExpression</CODE>\n     */\n    @Override\n    public String toString() {\n        return cronExpression;\n    }\n\n    /**\n     * Indicates whether the specified cron expression can be parsed into a\n     * valid cron expression\n     *\n     * @param cronExpression the expression to evaluate\n     * @return a boolean indicating whether the given expression is a valid cron\n     *         expression\n     */\n    public static boolean isValidExpression(String cronExpression) {\n\n        try {\n            new CronExpression(cronExpression);\n        } catch (ParseException pe) {\n            return false;\n        }\n\n        return true;\n    }\n\n    public static void validateExpression(String cronExpression) throws ParseException {\n\n        new CronExpression(cronExpression);\n    }\n\n\n    ////////////////////////////////////////////////////////////////////////////\n    //\n    // Expression Parsing Functions\n    //\n    ////////////////////////////////////////////////////////////////////////////\n\n    protected void buildExpression(String expression) throws ParseException {\n        expressionParsed = true;\n\n        try {\n\n            if (seconds == null) {\n                seconds = new TreeSet<>();\n            }\n            if (minutes == null) {\n                minutes = new TreeSet<>();\n            }\n            if (hours == null) {\n                hours = new TreeSet<>();\n            }\n            if (daysOfMonth == null) {\n                daysOfMonth = new TreeSet<>();\n            }\n            if (nearestWeekdays == null) {\n                nearestWeekdays = new TreeSet<>();\n            }\n            if (months == null) {\n                months = new TreeSet<>();\n            }\n            if (daysOfWeek == null) {\n                daysOfWeek = new TreeSet<>();\n            }\n            if (years == null) {\n                years = new TreeSet<>();\n            }\n\n            int exprOn = SECOND;\n\n            StringTokenizer exprsTok = new StringTokenizer(expression, \" \\t\",\n                    false);\n\n            if(exprsTok.countTokens() > 7) {\n                throw new ParseException(\"Invalid expression has too many terms: \" + expression, -1);\n            }\n\n            while (exprsTok.hasMoreTokens() && exprOn <= YEAR) {\n                String expr = exprsTok.nextToken().trim();\n\n                // throw an exception if L is used with other days of the week\n                if(exprOn == DAY_OF_WEEK && expr.indexOf('L') != -1 && expr.length() > 1  && expr.contains(\",\")) {\n                    throw new ParseException(\"Support for specifying 'L' with other days of the week is not implemented\", -1);\n                }\n                if(exprOn == DAY_OF_WEEK && expr.indexOf('#') != -1 && expr.indexOf('#', expr.indexOf('#') +1) != -1) {\n                    throw new ParseException(\"Support for specifying multiple \\\"nth\\\" days is not implemented.\", -1);\n                }\n\n                StringTokenizer vTok = new StringTokenizer(expr, \",\");\n                while (vTok.hasMoreTokens()) {\n                    String v = vTok.nextToken();\n                    storeExpressionVals(0, v, exprOn);\n                }\n\n                exprOn++;\n            }\n\n            if (exprOn <= DAY_OF_WEEK) {\n                throw new ParseException(\"Unexpected end of expression.\",\n                        expression.length());\n            }\n\n            if (exprOn <= YEAR) {\n                storeExpressionVals(0, \"*\", YEAR);\n            }\n\n            TreeSet<Integer> dow = getSet(DAY_OF_WEEK);\n            TreeSet<Integer> dom = getSet(DAY_OF_MONTH);\n\n            // Copying the logic from the UnsupportedOperationException below\n            boolean dayOfMSpec = !dom.contains(NO_SPEC);\n            boolean dayOfWSpec = !dow.contains(NO_SPEC);\n\n            if (!dayOfMSpec || dayOfWSpec) {\n                if (!dayOfWSpec || dayOfMSpec) {\n                    throw new ParseException(\n                            \"Support for specifying both a day-of-week AND a day-of-month parameter is not implemented.\", 0);\n                }\n            }\n        } catch (ParseException pe) {\n            throw pe;\n        } catch (Exception e) {\n            throw new ParseException(\"Illegal cron expression format (\"\n                    + e + \")\", 0);\n        }\n    }\n\n    protected int storeExpressionVals(int pos, String s, int type)\n            throws ParseException {\n\n        int incr = 0;\n        int i = skipWhiteSpace(pos, s);\n        if (i >= s.length()) {\n            return i;\n        }\n        char c = s.charAt(i);\n        if ((c >= 'A') && (c <= 'Z') && (!s.equals(\"L\")) && (!s.equals(\"LW\")) && (!s.matches(\"^L-[0-9]*[W]?\"))) {\n            String sub = s.substring(i, i + 3);\n            int sval = -1;\n            int eval = -1;\n            if (type == MONTH) {\n                sval = getMonthNumber(sub) + 1;\n                if (sval <= 0) {\n                    throw new ParseException(\"Invalid Month value: '\" + sub + \"'\", i);\n                }\n                if (s.length() > i + 3) {\n                    c = s.charAt(i + 3);\n                    if (c == '-') {\n                        i += 4;\n                        sub = s.substring(i, i + 3);\n                        eval = getMonthNumber(sub) + 1;\n                        if (eval <= 0) {\n                            throw new ParseException(\"Invalid Month value: '\" + sub + \"'\", i);\n                        }\n                    }\n                }\n            } else if (type == DAY_OF_WEEK) {\n                sval = getDayOfWeekNumber(sub);\n                if (sval < 0) {\n                    throw new ParseException(\"Invalid Day-of-Week value: '\"\n                            + sub + \"'\", i);\n                }\n                if (s.length() > i + 3) {\n                    c = s.charAt(i + 3);\n                    if (c == '-') {\n                        i += 4;\n                        sub = s.substring(i, i + 3);\n                        eval = getDayOfWeekNumber(sub);\n                        if (eval < 0) {\n                            throw new ParseException(\n                                    \"Invalid Day-of-Week value: '\" + sub\n                                            + \"'\", i);\n                        }\n                    } else if (c == '#') {\n                        try {\n                            i += 4;\n                            nthDayOfWeek = Integer.parseInt(s.substring(i));\n                            if (nthDayOfWeek < 1 || nthDayOfWeek > 5) {\n                                throw new Exception();\n                            }\n                        } catch (Exception e) {\n                            throw new ParseException(\n                                    \"A numeric value between 1 and 5 must follow the '#' option\",\n                                    i);\n                        }\n                    } else if (c == 'L') {\n                        lastDayOfWeek = true;\n                        i++;\n                    }\n                }\n\n            } else {\n                throw new ParseException(\n                        \"Illegal characters for this position: '\" + sub + \"'\",\n                        i);\n            }\n            if (eval != -1) {\n                incr = 1;\n            }\n            addToSet(sval, eval, incr, type);\n            return (i + 3);\n        }\n\n        if (c == '?') {\n            i++;\n            if ((i + 1) < s.length()\n                    && (s.charAt(i) != ' ' && s.charAt(i + 1) != '\\t')) {\n                throw new ParseException(\"Illegal character after '?': \"\n                        + s.charAt(i), i);\n            }\n            if (type != DAY_OF_WEEK && type != DAY_OF_MONTH) {\n                throw new ParseException(\n                        \"'?' can only be specified for Day-of-Month or Day-of-Week.\",\n                        i);\n            }\n            if (type == DAY_OF_WEEK) {\n                if (!daysOfMonth.isEmpty() && daysOfMonth.last() == NO_SPEC_INT) {\n                    throw new ParseException(\n                            \"'?' can only be specified for Day-of-Month -OR- Day-of-Week.\",\n                            i);\n                }\n            }\n\n            addToSet(NO_SPEC_INT, -1, 0, type);\n            return i;\n        }\n\n        if (c == '*' || c == '/') {\n            if (c == '*' && (i + 1) >= s.length()) {\n                addToSet(ALL_SPEC_INT, -1, incr, type);\n                return i + 1;\n            } else if (c == '/'\n                    && ((i + 1) >= s.length() || s.charAt(i + 1) == ' ' || s\n                    .charAt(i + 1) == '\\t')) {\n                throw new ParseException(\"'/' must be followed by an integer.\", i);\n            } else if (c == '*') {\n                i++;\n            }\n            c = s.charAt(i);\n            if (c == '/') { // is an increment specified?\n                i++;\n                if (i >= s.length()) {\n                    throw new ParseException(\"Unexpected end of string.\", i);\n                }\n\n                incr = getNumericValue(s, i);\n\n                i++;\n                if (incr > 10) {\n                    i++;\n                }\n                checkIncrementRange(incr, type, i);\n            } else {\n                incr = 1;\n            }\n\n            addToSet(ALL_SPEC_INT, -1, incr, type);\n            return i;\n        } else if (c == 'L') {\n            i++;\n            if (type == DAY_OF_WEEK) {\n                addToSet(7, 7, 0, type);\n            }\n            if (type == DAY_OF_MONTH) {\n                int dom = LAST_DAY_OFFSET_END;\n                boolean nearestWeekday = false;\n                if (s.length() > i) {\n                    c = s.charAt(i);\n                    if (c == '-') {\n                        ValueSet vs = getValue(0, s, i + 1);\n                        int offset = vs.value;\n                        if (offset > MAX_LAST_DAY_OFFSET)\n                            throw new ParseException(\"Offset from last day must be <= \" + MAX_LAST_DAY_OFFSET, i + 1);\n                        dom -= offset;\n                        i = vs.pos;\n                    }\n                    if (s.length() > i) {\n                        c = s.charAt(i);\n                        if (c == 'W') {\n                            nearestWeekday = true;\n                            i++;\n                        }\n                    }\n                }\n                if (nearestWeekday) {\n                    nearestWeekdays.add(dom);\n                } else {\n                    daysOfMonth.add(dom);\n                }\n            }\n            return i;\n        } else if (c >= '0' && c <= '9') {\n            int val = Integer.parseInt(String.valueOf(c));\n            i++;\n            if (i >= s.length()) {\n                addToSet(val, -1, -1, type);\n            } else {\n                c = s.charAt(i);\n                if (c >= '0' && c <= '9') {\n                    ValueSet vs = getValue(val, s, i);\n                    val = vs.value;\n                    i = vs.pos;\n                }\n                i = checkNext(i, s, val, type);\n                return i;\n            }\n        } else {\n            throw new ParseException(\"Unexpected character: \" + c, i);\n        }\n\n        return i;\n    }\n\n    private void checkIncrementRange(int incr, int type, int idxPos) throws ParseException {\n        if (incr > 59 && (type == SECOND || type == MINUTE)) {\n            throw new ParseException(\"Increment > 60 : \" + incr, idxPos);\n        } else if (incr > 23 && (type == HOUR)) {\n            throw new ParseException(\"Increment > 24 : \" + incr, idxPos);\n        } else if (incr > 31 && (type == DAY_OF_MONTH)) {\n            throw new ParseException(\"Increment > 31 : \" + incr, idxPos);\n        } else if (incr > 7 && (type == DAY_OF_WEEK)) {\n            throw new ParseException(\"Increment > 7 : \" + incr, idxPos);\n        } else if (incr > 12 && (type == MONTH)) {\n            throw new ParseException(\"Increment > 12 : \" + incr, idxPos);\n        }\n    }\n\n    protected int checkNext(int pos, String s, int val, int type)\n            throws ParseException {\n\n        int end = -1;\n        int i = pos;\n\n        if (i >= s.length()) {\n            addToSet(val, end, -1, type);\n            return i;\n        }\n\n        char c = s.charAt(pos);\n\n        if (c == 'L') {\n            if (type == DAY_OF_WEEK) {\n                if(val < 1 || val > 7)\n                    throw new ParseException(\"Day-of-Week values must be between 1 and 7\", -1);\n                lastDayOfWeek = true;\n            } else {\n                throw new ParseException(\"'L' option is not valid here. (pos=\" + i + \")\", i);\n            }\n            TreeSet<Integer> set = getSet(type);\n            set.add(val);\n            i++;\n            return i;\n        }\n\n        if (c == 'W') {\n            if (type != DAY_OF_MONTH) {\n                throw new ParseException(\"'W' option is not valid here. (pos=\" + i + \")\", i);\n            }\n            if(val > 31)\n                throw new ParseException(\"The 'W' option does not make sense with values larger than 31 (max number of days in a month)\", i);\n            nearestWeekdays.add(val);\n            i++;\n            return i;\n        }\n\n        if (c == '#') {\n            if (type != DAY_OF_WEEK) {\n                throw new ParseException(\"'#' option is not valid here. (pos=\" + i + \")\", i);\n            }\n            i++;\n            try {\n                nthDayOfWeek = Integer.parseInt(s.substring(i));\n                if (nthDayOfWeek < 1 || nthDayOfWeek > 5) {\n                    throw new Exception();\n                }\n            } catch (Exception e) {\n                throw new ParseException(\n                        \"A numeric value between 1 and 5 must follow the '#' option\",\n                        i);\n            }\n\n            TreeSet<Integer> set = getSet(type);\n            set.add(val);\n            i++;\n            return i;\n        }\n\n        if (c == '-') {\n            i++;\n            c = s.charAt(i);\n            int v = Integer.parseInt(String.valueOf(c));\n            end = v;\n            i++;\n            if (i >= s.length()) {\n                addToSet(val, end, 1, type);\n                return i;\n            }\n            c = s.charAt(i);\n            if (c >= '0' && c <= '9') {\n                ValueSet vs = getValue(v, s, i);\n                end = vs.value;\n                i = vs.pos;\n            }\n            if (i < s.length() && ((c = s.charAt(i)) == '/')) {\n                i++;\n                c = s.charAt(i);\n                int v2 = Integer.parseInt(String.valueOf(c));\n                i++;\n                if (i >= s.length()) {\n                    addToSet(val, end, v2, type);\n                    return i;\n                }\n                c = s.charAt(i);\n                if (c >= '0' && c <= '9') {\n                    ValueSet vs = getValue(v2, s, i);\n                    int v3 = vs.value;\n                    addToSet(val, end, v3, type);\n                    i = vs.pos;\n                    return i;\n                } else {\n                    addToSet(val, end, v2, type);\n                    return i;\n                }\n            } else {\n                addToSet(val, end, 1, type);\n                return i;\n            }\n        }\n\n        if (c == '/') {\n            if ((i + 1) >= s.length() || s.charAt(i + 1) == ' ' || s.charAt(i + 1) == '\\t') {\n                throw new ParseException(\"'/' must be followed by an integer.\", i);\n            }\n\n            i++;\n            c = s.charAt(i);\n            int v2 = Integer.parseInt(String.valueOf(c));\n            i++;\n            if (i >= s.length()) {\n                checkIncrementRange(v2, type, i);\n                addToSet(val, end, v2, type);\n                return i;\n            }\n            c = s.charAt(i);\n            if (c >= '0' && c <= '9') {\n                ValueSet vs = getValue(v2, s, i);\n                int v3 = vs.value;\n                checkIncrementRange(v3, type, i);\n                addToSet(val, end, v3, type);\n                i = vs.pos;\n                return i;\n            } else {\n                throw new ParseException(\"Unexpected character '\" + c + \"' after '/'\", i);\n            }\n        }\n\n        addToSet(val, end, 0, type);\n        i++;\n        return i;\n    }\n\n    public String getCronExpression() {\n        return cronExpression;\n    }\n\n    public String getExpressionSummary() {\n        StringBuilder buf = new StringBuilder();\n\n        buf.append(\"seconds: \");\n        buf.append(getExpressionSetSummary(seconds));\n        buf.append(\"\\n\");\n        buf.append(\"minutes: \");\n        buf.append(getExpressionSetSummary(minutes));\n        buf.append(\"\\n\");\n        buf.append(\"hours: \");\n        buf.append(getExpressionSetSummary(hours));\n        buf.append(\"\\n\");\n        buf.append(\"daysOfMonth: \");\n        buf.append(getExpressionSetSummary(daysOfMonth));\n        buf.append(\"\\n\");\n        buf.append(\"nearestWeekdays: \");\n        buf.append(getExpressionSetSummary(nearestWeekdays));\n        buf.append(\"\\n\");\n        buf.append(\"months: \");\n        buf.append(getExpressionSetSummary(months));\n        buf.append(\"\\n\");\n        buf.append(\"daysOfWeek: \");\n        buf.append(getExpressionSetSummary(daysOfWeek));\n        buf.append(\"\\n\");\n        buf.append(\"lastDayOfWeek: \");\n        buf.append(lastDayOfWeek);\n        buf.append(\"\\n\");\n        buf.append(\"NthDayOfWeek: \");\n        buf.append(nthDayOfWeek);\n        buf.append(\"\\n\");\n        buf.append(\"years: \");\n        buf.append(getExpressionSetSummary(years));\n        buf.append(\"\\n\");\n\n        return buf.toString();\n    }\n\n    protected String getExpressionSetSummary(java.util.Set<Integer> set) {\n\n        if (set.contains(NO_SPEC)) {\n            return \"?\";\n        }\n        if (set.contains(ALL_SPEC)) {\n            return \"*\";\n        }\n\n        StringBuilder buf = new StringBuilder();\n\n        Iterator<Integer> itr = set.iterator();\n        boolean first = true;\n        while (itr.hasNext()) {\n            Integer iVal = itr.next();\n            String val = iVal.toString();\n            if (!first) {\n                buf.append(\",\");\n            }\n            buf.append(val);\n            first = false;\n        }\n\n        return buf.toString();\n    }\n\n    protected String getExpressionSetSummary(java.util.ArrayList<Integer> list) {\n\n        if (list.contains(NO_SPEC)) {\n            return \"?\";\n        }\n        if (list.contains(ALL_SPEC)) {\n            return \"*\";\n        }\n\n        StringBuilder buf = new StringBuilder();\n\n        Iterator<Integer> itr = list.iterator();\n        boolean first = true;\n        while (itr.hasNext()) {\n            Integer iVal = itr.next();\n            String val = iVal.toString();\n            if (!first) {\n                buf.append(\",\");\n            }\n            buf.append(val);\n            first = false;\n        }\n\n        return buf.toString();\n    }\n\n    protected int skipWhiteSpace(int i, String s) {\n        for (; i < s.length() && (s.charAt(i) == ' ' || s.charAt(i) == '\\t'); i++) {\n        }\n\n        return i;\n    }\n\n    protected int findNextWhiteSpace(int i, String s) {\n        for (; i < s.length() && (s.charAt(i) != ' ' || s.charAt(i) != '\\t'); i++) {\n        }\n\n        return i;\n    }\n\n    protected void addToSet(int val, int end, int incr, int type)\n            throws ParseException {\n\n        TreeSet<Integer> set = getSet(type);\n\n        if (type == SECOND || type == MINUTE) {\n            if ((val < 0 || val > 59 || end > 59) && (val != ALL_SPEC_INT)) {\n                throw new ParseException(\n                        \"Minute and Second values must be between 0 and 59\",\n                        -1);\n            }\n        } else if (type == HOUR) {\n            if ((val < 0 || val > 23 || end > 23) && (val != ALL_SPEC_INT)) {\n                throw new ParseException(\n                        \"Hour values must be between 0 and 23\", -1);\n            }\n        } else if (type == DAY_OF_MONTH) {\n            if ((val < 1 || val > 31 || end > 31) && (val != ALL_SPEC_INT)\n                    && (val != NO_SPEC_INT)) {\n                throw new ParseException(\n                        \"Day of month values must be between 1 and 31\", -1);\n            }\n        } else if (type == MONTH) {\n            if ((val < 1 || val > 12 || end > 12) && (val != ALL_SPEC_INT)) {\n                throw new ParseException(\n                        \"Month values must be between 1 and 12\", -1);\n            }\n        } else if (type == DAY_OF_WEEK) {\n            if ((val == 0 || val > 7 || end > 7) && (val != ALL_SPEC_INT)\n                    && (val != NO_SPEC_INT)) {\n                throw new ParseException(\n                        \"Day-of-Week values must be between 1 and 7\", -1);\n            }\n        }\n\n        if ((incr == 0 || incr == -1) && val != ALL_SPEC_INT) {\n            if (val != -1) {\n                set.add(val);\n            } else {\n                set.add(NO_SPEC);\n            }\n\n            return;\n        }\n\n        int startAt = val;\n        int stopAt = end;\n\n        if (val == ALL_SPEC_INT && incr <= 0) {\n            incr = 1;\n            set.add(ALL_SPEC); // put in a marker, but also fill values\n        }\n\n        if (type == SECOND || type == MINUTE) {\n            if (stopAt == -1) {\n                stopAt = 59;\n            }\n            if (startAt == -1 || startAt == ALL_SPEC_INT) {\n                startAt = 0;\n            }\n        } else if (type == HOUR) {\n            if (stopAt == -1) {\n                stopAt = 23;\n            }\n            if (startAt == -1 || startAt == ALL_SPEC_INT) {\n                startAt = 0;\n            }\n        } else if (type == DAY_OF_MONTH) {\n            if (stopAt == -1) {\n                stopAt = 31;\n            }\n            if (startAt == -1 || startAt == ALL_SPEC_INT) {\n                startAt = 1;\n            }\n        } else if (type == MONTH) {\n            if (stopAt == -1) {\n                stopAt = 12;\n            }\n            if (startAt == -1 || startAt == ALL_SPEC_INT) {\n                startAt = 1;\n            }\n        } else if (type == DAY_OF_WEEK) {\n            if (stopAt == -1) {\n                stopAt = 7;\n            }\n            if (startAt == -1 || startAt == ALL_SPEC_INT) {\n                startAt = 1;\n            }\n        } else if (type == YEAR) {\n            if (stopAt == -1) {\n                stopAt = MAX_YEAR;\n            }\n            if (startAt == -1 || startAt == ALL_SPEC_INT) {\n                startAt = 1970;\n            }\n        }\n\n        // if the end of the range is before the start, then we need to overflow into\n        // the next day, month etc. This is done by adding the maximum amount for that\n        // type, and using modulus max to determine the value being added.\n        int max = -1;\n        if (stopAt < startAt) {\n            switch (type) {\n                case       SECOND : max = 60; break;\n                case       MINUTE : max = 60; break;\n                case         HOUR : max = 24; break;\n                case        MONTH : max = 12; break;\n                case  DAY_OF_WEEK : max = 7;  break;\n                case DAY_OF_MONTH : max = 31; break;\n                case         YEAR : throw new IllegalArgumentException(\"Start year must be less than stop year\");\n                default           : throw new IllegalArgumentException(\"Unexpected type encountered\");\n            }\n            stopAt += max;\n        }\n\n        for (int i = startAt; i <= stopAt; i += incr) {\n            if (max == -1) {\n                // ie: there's no max to overflow over\n                set.add(i);\n            } else {\n                // take the modulus to get the real value\n                int i2 = i % max;\n\n                // 1-indexed ranges should not include 0, and should include their max\n                if (i2 == 0 && (type == MONTH || type == DAY_OF_WEEK || type == DAY_OF_MONTH) ) {\n                    i2 = max;\n                }\n\n                set.add(i2);\n            }\n        }\n    }\n\n    TreeSet<Integer> getSet(int type) {\n        switch (type) {\n            case SECOND:\n                return seconds;\n            case MINUTE:\n                return minutes;\n            case HOUR:\n                return hours;\n            case DAY_OF_MONTH:\n                return daysOfMonth;\n            case MONTH:\n                return months;\n            case DAY_OF_WEEK:\n                return daysOfWeek;\n            case YEAR:\n                return years;\n            default:\n                return null;\n        }\n    }\n\n    protected ValueSet getValue(int v, String s, int i) {\n        char c = s.charAt(i);\n        StringBuilder s1 = new StringBuilder(String.valueOf(v));\n        while (c >= '0' && c <= '9') {\n            s1.append(c);\n            i++;\n            if (i >= s.length()) {\n                break;\n            }\n            c = s.charAt(i);\n        }\n        ValueSet val = new ValueSet();\n\n        val.pos = (i < s.length()) ? i : i + 1;\n        val.value = Integer.parseInt(s1.toString());\n        return val;\n    }\n\n    protected int getNumericValue(String s, int i) {\n        int endOfVal = findNextWhiteSpace(i, s);\n        String val = s.substring(i, endOfVal);\n        return Integer.parseInt(val);\n    }\n\n    protected int getMonthNumber(String s) {\n        Integer integer = monthMap.get(s);\n\n        if (integer == null) {\n            return -1;\n        }\n\n        return integer;\n    }\n\n    protected int getDayOfWeekNumber(String s) {\n        Integer integer = dayMap.get(s);\n\n        if (integer == null) {\n            return -1;\n        }\n\n        return integer;\n    }\n\n    ////////////////////////////////////////////////////////////////////////////\n    //\n    // Computation Functions\n    //\n    ////////////////////////////////////////////////////////////////////////////\n\n    public Date getTimeAfter(Date afterTime) {\n\n        // Computation is based on Gregorian year only.\n        Calendar cl = new java.util.GregorianCalendar(getTimeZone());\n\n        // move ahead one second, since we're computing the time *after* the\n        // given time\n        afterTime = new Date(afterTime.getTime() + 1000);\n        // CronTrigger does not deal with milliseconds\n        cl.setTime(afterTime);\n        cl.set(Calendar.MILLISECOND, 0);\n\n        boolean gotOne = false;\n        // loop until we've computed the next time, or we've past the endTime\n        while (!gotOne) {\n\n            //if (endTime != null && cl.getTime().after(endTime)) return null;\n            if(cl.get(Calendar.YEAR) > 2999) { // prevent endless loop...\n                return null;\n            }\n\n            SortedSet<Integer> st = null;\n            int t = 0;\n\n            int sec = cl.get(Calendar.SECOND);\n            int min = cl.get(Calendar.MINUTE);\n\n            // get second.................................................\n            st = seconds.tailSet(sec);\n            if (st != null && !st.isEmpty()) {\n                sec = st.first();\n            } else {\n                sec = seconds.first();\n                min++;\n                cl.set(Calendar.MINUTE, min);\n            }\n            cl.set(Calendar.SECOND, sec);\n\n            min = cl.get(Calendar.MINUTE);\n            int hr = cl.get(Calendar.HOUR_OF_DAY);\n            t = -1;\n\n            // get minute.................................................\n            st = minutes.tailSet(min);\n            if (st != null && !st.isEmpty()) {\n                t = min;\n                min = st.first();\n            } else {\n                min = minutes.first();\n                hr++;\n            }\n            if (min != t) {\n                cl.set(Calendar.SECOND, 0);\n                cl.set(Calendar.MINUTE, min);\n                setCalendarHour(cl, hr);\n                continue;\n            }\n            cl.set(Calendar.MINUTE, min);\n\n            hr = cl.get(Calendar.HOUR_OF_DAY);\n            int day = cl.get(Calendar.DAY_OF_MONTH);\n            t = -1;\n\n            // get hour...................................................\n            st = hours.tailSet(hr);\n            if (st != null && !st.isEmpty()) {\n                t = hr;\n                hr = st.first();\n            } else {\n                hr = hours.first();\n                day++;\n            }\n            if (hr != t) {\n                cl.set(Calendar.SECOND, 0);\n                cl.set(Calendar.MINUTE, 0);\n                cl.set(Calendar.DAY_OF_MONTH, day);\n                setCalendarHour(cl, hr);\n                continue;\n            }\n            cl.set(Calendar.HOUR_OF_DAY, hr);\n\n            day = cl.get(Calendar.DAY_OF_MONTH);\n            int mon = cl.get(Calendar.MONTH) + 1;\n            // '+ 1' because calendar is 0-based for this field, and we are\n            // 1-based\n            t = -1;\n            int tmon = mon;\n\n            // get day...................................................\n            boolean dayOfMSpec = !daysOfMonth.contains(NO_SPEC);\n            boolean dayOfWSpec = !daysOfWeek.contains(NO_SPEC);\n            if (dayOfMSpec && !dayOfWSpec) { // get day by day of month rule\n                Optional<Integer> smallestDay = findSmallestDay(day, mon, cl.get(Calendar.YEAR), daysOfMonth);\n                Optional<Integer> smallestDayForWeekday = findSmallestDay(day, mon, cl.get(Calendar.YEAR), nearestWeekdays);\n                t = day;\n                day = -1;\n                if (smallestDayForWeekday.isPresent()) {\n                    day = smallestDayForWeekday.get();\n\n                    java.util.Calendar tcal = java.util.Calendar.getInstance(getTimeZone());\n                    tcal.set(Calendar.SECOND, 0);\n                    tcal.set(Calendar.MINUTE, 0);\n                    tcal.set(Calendar.HOUR_OF_DAY, 0);\n                    tcal.set(Calendar.DAY_OF_MONTH, day);\n                    tcal.set(Calendar.MONTH, mon - 1);\n                    tcal.set(Calendar.YEAR, cl.get(Calendar.YEAR));\n\n                    int ldom = getLastDayOfMonth(mon, cl.get(Calendar.YEAR));\n                    int dow = tcal.get(Calendar.DAY_OF_WEEK);\n\n                    if(dow == Calendar.SATURDAY && day == 1) {\n                        day += 2;\n                    } else if(dow == Calendar.SATURDAY) {\n                        day -= 1;\n                    } else if(dow == Calendar.SUNDAY && day == ldom) {\n                        day -= 2;\n                    } else if(dow == Calendar.SUNDAY) {\n                        day += 1;\n                    }\n\n\n                    tcal.set(Calendar.SECOND, sec);\n                    tcal.set(Calendar.MINUTE, min);\n                    tcal.set(Calendar.HOUR_OF_DAY, hr);\n                    tcal.set(Calendar.DAY_OF_MONTH, day);\n                    tcal.set(Calendar.MONTH, mon - 1);\n                    Date nTime = tcal.getTime();\n                    if(nTime.before(afterTime)) {\n                        day = -1;\n                    }\n                }\n                if (smallestDay.isPresent()) {\n                    if (day == -1 || smallestDay.get() < day) {\n                        day = smallestDay.get();\n                    }\n                } else if (day == -1) {\n                    day = 1;\n                    mon++;\n                }\n                if (day != t || mon != tmon) {\n                    cl.set(Calendar.SECOND, 0);\n                    cl.set(Calendar.MINUTE, 0);\n                    cl.set(Calendar.HOUR_OF_DAY, 0);\n                    cl.set(Calendar.DAY_OF_MONTH, day);\n                    cl.set(Calendar.MONTH, mon - 1);\n                    // '- 1' because calendar is 0-based for this field, and we\n                    // are 1-based\n                    continue;\n                }\n            } else if (dayOfWSpec && !dayOfMSpec) { // get day by day of week rule\n                if (lastDayOfWeek) { // are we looking for the last XXX day of\n                    // the month?\n                    int dow = daysOfWeek.first(); // desired\n                    // d-o-w\n                    int cDow = cl.get(Calendar.DAY_OF_WEEK); // current d-o-w\n                    int daysToAdd = 0;\n                    if (cDow < dow) {\n                        daysToAdd = dow - cDow;\n                    }\n                    if (cDow > dow) {\n                        daysToAdd = dow + (7 - cDow);\n                    }\n\n                    int lDay = getLastDayOfMonth(mon, cl.get(Calendar.YEAR));\n\n                    if (day + daysToAdd > lDay) { // did we already miss the\n                        // last one?\n                        cl.set(Calendar.SECOND, 0);\n                        cl.set(Calendar.MINUTE, 0);\n                        cl.set(Calendar.HOUR_OF_DAY, 0);\n                        cl.set(Calendar.DAY_OF_MONTH, 1);\n                        cl.set(Calendar.MONTH, mon);\n                        // no '- 1' here because we are promoting the month\n                        continue;\n                    }\n\n                    // find date of last occurrence of this day in this month...\n                    while ((day + daysToAdd + 7) <= lDay) {\n                        daysToAdd += 7;\n                    }\n\n                    day += daysToAdd;\n\n                    if (daysToAdd > 0) {\n                        cl.set(Calendar.SECOND, 0);\n                        cl.set(Calendar.MINUTE, 0);\n                        cl.set(Calendar.HOUR_OF_DAY, 0);\n                        cl.set(Calendar.DAY_OF_MONTH, day);\n                        cl.set(Calendar.MONTH, mon - 1);\n                        // '- 1' here because we are not promoting the month\n                        continue;\n                    }\n\n                } else if (nthDayOfWeek != 0) {\n                    // are we looking for the Nth XXX day in the month?\n                    int dow = daysOfWeek.first(); // desired\n                    // d-o-w\n                    int cDow = cl.get(Calendar.DAY_OF_WEEK); // current d-o-w\n                    int daysToAdd = 0;\n                    if (cDow < dow) {\n                        daysToAdd = dow - cDow;\n                    } else if (cDow > dow) {\n                        daysToAdd = dow + (7 - cDow);\n                    }\n\n                    boolean dayShifted = daysToAdd > 0;\n\n                    day += daysToAdd;\n                    int weekOfMonth = day / 7;\n                    if (day % 7 > 0) {\n                        weekOfMonth++;\n                    }\n\n                    daysToAdd = (nthDayOfWeek - weekOfMonth) * 7;\n                    day += daysToAdd;\n                    if (daysToAdd < 0\n                            || day > getLastDayOfMonth(mon, cl\n                            .get(Calendar.YEAR))) {\n                        cl.set(Calendar.SECOND, 0);\n                        cl.set(Calendar.MINUTE, 0);\n                        cl.set(Calendar.HOUR_OF_DAY, 0);\n                        cl.set(Calendar.DAY_OF_MONTH, 1);\n                        cl.set(Calendar.MONTH, mon);\n                        // no '- 1' here because we are promoting the month\n                        continue;\n                    } else if (daysToAdd > 0 || dayShifted) {\n                        cl.set(Calendar.SECOND, 0);\n                        cl.set(Calendar.MINUTE, 0);\n                        cl.set(Calendar.HOUR_OF_DAY, 0);\n                        cl.set(Calendar.DAY_OF_MONTH, day);\n                        cl.set(Calendar.MONTH, mon - 1);\n                        // '- 1' here because we are NOT promoting the month\n                        continue;\n                    }\n                } else {\n                    int cDow = cl.get(Calendar.DAY_OF_WEEK); // current d-o-w\n                    int dow = daysOfWeek.first(); // desired\n                    // d-o-w\n                    st = daysOfWeek.tailSet(cDow);\n                    if (st != null && !st.isEmpty()) {\n                        dow = st.first();\n                    }\n\n                    int daysToAdd = 0;\n                    if (cDow < dow) {\n                        daysToAdd = dow - cDow;\n                    }\n                    if (cDow > dow) {\n                        daysToAdd = dow + (7 - cDow);\n                    }\n\n                    int lDay = getLastDayOfMonth(mon, cl.get(Calendar.YEAR));\n\n                    if (day + daysToAdd > lDay) { // will we pass the end of\n                        // the month?\n                        cl.set(Calendar.SECOND, 0);\n                        cl.set(Calendar.MINUTE, 0);\n                        cl.set(Calendar.HOUR_OF_DAY, 0);\n                        cl.set(Calendar.DAY_OF_MONTH, 1);\n                        cl.set(Calendar.MONTH, mon);\n                        // no '- 1' here because we are promoting the month\n                        continue;\n                    } else if (daysToAdd > 0) { // are we switching days?\n                        cl.set(Calendar.SECOND, 0);\n                        cl.set(Calendar.MINUTE, 0);\n                        cl.set(Calendar.HOUR_OF_DAY, 0);\n                        cl.set(Calendar.DAY_OF_MONTH, day + daysToAdd);\n                        cl.set(Calendar.MONTH, mon - 1);\n                        // '- 1' because calendar is 0-based for this field,\n                        // and we are 1-based\n                        continue;\n                    }\n                }\n            } else { // dayOfWSpec && !dayOfMSpec\n                throw new UnsupportedOperationException(\n                        \"Support for specifying both a day-of-week AND a day-of-month parameter is not implemented.\");\n            }\n            cl.set(Calendar.DAY_OF_MONTH, day);\n\n            mon = cl.get(Calendar.MONTH) + 1;\n            // '+ 1' because calendar is 0-based for this field, and we are\n            // 1-based\n            int year = cl.get(Calendar.YEAR);\n            t = -1;\n\n            // test for expressions that never generate a valid fire date,\n            // but keep looping...\n            if (year > MAX_YEAR) {\n                return null;\n            }\n\n            // get month...................................................\n            st = months.tailSet(mon);\n            if (st != null && !st.isEmpty()) {\n                t = mon;\n                mon = st.first();\n            } else {\n                mon = months.first();\n                year++;\n            }\n            if (mon != t) {\n                cl.set(Calendar.SECOND, 0);\n                cl.set(Calendar.MINUTE, 0);\n                cl.set(Calendar.HOUR_OF_DAY, 0);\n                cl.set(Calendar.DAY_OF_MONTH, 1);\n                cl.set(Calendar.MONTH, mon - 1);\n                // '- 1' because calendar is 0-based for this field, and we are\n                // 1-based\n                cl.set(Calendar.YEAR, year);\n                continue;\n            }\n            cl.set(Calendar.MONTH, mon - 1);\n            // '- 1' because calendar is 0-based for this field, and we are\n            // 1-based\n\n            year = cl.get(Calendar.YEAR);\n            t = -1;\n\n            // get year...................................................\n            st = years.tailSet(year);\n            if (st != null && !st.isEmpty()) {\n                t = year;\n                year = st.first();\n            } else {\n                return null; // ran out of years...\n            }\n\n            if (year != t) {\n                cl.set(Calendar.SECOND, 0);\n                cl.set(Calendar.MINUTE, 0);\n                cl.set(Calendar.HOUR_OF_DAY, 0);\n                cl.set(Calendar.DAY_OF_MONTH, 1);\n                cl.set(Calendar.MONTH, 0);\n                // '- 1' because calendar is 0-based for this field, and we are\n                // 1-based\n                cl.set(Calendar.YEAR, year);\n                continue;\n            }\n            cl.set(Calendar.YEAR, year);\n\n            gotOne = true;\n        } // while( !done )\n\n        return cl.getTime();\n    }\n\n    /**\n     * Advance the calendar to the particular hour paying particular attention\n     * to daylight saving problems.\n     *\n     * @param cal the calendar to operate on\n     * @param hour the hour to set\n     */\n    protected void setCalendarHour(Calendar cal, int hour) {\n        cal.set(java.util.Calendar.HOUR_OF_DAY, hour);\n        if (cal.get(java.util.Calendar.HOUR_OF_DAY) != hour && hour != 24) {\n            cal.set(java.util.Calendar.HOUR_OF_DAY, hour + 1);\n        }\n    }\n\n    /**\n     * NOT YET IMPLEMENTED: Returns the time before the given time\n     * that the <code>CronExpression</code> matches.\n     */\n    public Date getTimeBefore(Date endTime) {\n        // FUTURE_TODO: implement QUARTZ-423\n        return null;\n    }\n\n    /**\n     * NOT YET IMPLEMENTED: Returns the final time that the\n     * <code>CronExpression</code> will match.\n     */\n    public Date getFinalFireTime() {\n        // FUTURE_TODO: implement QUARTZ-423\n        return null;\n    }\n\n    protected boolean isLeapYear(int year) {\n        return ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0));\n    }\n\n    protected int getLastDayOfMonth(int monthNum, int year) {\n\n        switch (monthNum) {\n            case 1:\n                return 31;\n            case 2:\n                return (isLeapYear(year)) ? 29 : 28;\n            case 3:\n                return 31;\n            case 4:\n                return 30;\n            case 5:\n                return 31;\n            case 6:\n                return 30;\n            case 7:\n                return 31;\n            case 8:\n                return 31;\n            case 9:\n                return 30;\n            case 10:\n                return 31;\n            case 11:\n                return 30;\n            case 12:\n                return 31;\n            default:\n                throw new IllegalArgumentException(\"Illegal month number: \"\n                        + monthNum);\n        }\n    }\n\n\n    private Optional<Integer> findSmallestDay(int day, int mon, int year, TreeSet<Integer> set) {\n        if (set.isEmpty()) {\n            return Optional.empty();\n        }\n\n        final int lastDay = getLastDayOfMonth(mon, year);\n        // For \"L\", \"L-1\", etc.\n        int smallestDay = Optional.ofNullable(set.ceiling(LAST_DAY_OFFSET_END - (lastDay - day)))\n                .map(d -> d - LAST_DAY_OFFSET_START + 1)\n                .orElse(Integer.MAX_VALUE);\n\n        // For \"1\", \"2\", etc.\n        SortedSet<Integer> st = set.subSet(day, LAST_DAY_OFFSET_START);\n        // make sure we don't over-run a short month, such as february\n        if (!st.isEmpty() && st.first() < smallestDay && st.first() <= lastDay) {\n            smallestDay = st.first();\n        }\n\n        return smallestDay == Integer.MAX_VALUE ? Optional.empty() : Optional.of(smallestDay);\n    }\n\n    private void readObject(java.io.ObjectInputStream stream)\n            throws java.io.IOException, ClassNotFoundException {\n\n        stream.defaultReadObject();\n        try {\n            buildExpression(cronExpression);\n        } catch (Exception ignore) {\n        } // never happens\n    }\n\n    @Override\n    @Deprecated\n    public Object clone() {\n        return new CronExpression(this);\n    }\n}\n\nclass ValueSet {\n    public int value;\n\n    public int pos;\n}"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/exception/XxlJobException.java",
    "content": "package com.xxl.job.admin.scheduler.exception;\n\n/**\n * @author xuxueli 2019-05-04 23:19:29\n */\npublic class XxlJobException extends RuntimeException {\n\n    public XxlJobException() {\n    }\n    public XxlJobException(String message) {\n        super(message);\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/misfire/MisfireHandler.java",
    "content": "package com.xxl.job.admin.scheduler.misfire;\n\n/**\n * Misfire Handler\n *\n * @author xuxueli 2020-10-29\n */\npublic abstract class MisfireHandler {\n\n    /**\n     * misfire handle\n     *\n     * @param jobId jobId\n     */\n    public abstract void handle(final int jobId);\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/misfire/MisfireStrategyEnum.java",
    "content": "package com.xxl.job.admin.scheduler.misfire;\n\nimport com.xxl.job.admin.scheduler.misfire.strategy.MisfireDoNothing;\nimport com.xxl.job.admin.scheduler.misfire.strategy.MisfireFireOnceNow;\nimport com.xxl.job.admin.util.I18nUtil;\n\n/**\n * @author xuxueli 2020-10-29 21:11:23\n */\npublic enum MisfireStrategyEnum {\n\n    /**\n     * do nothing\n     */\n    DO_NOTHING(I18nUtil.getString(\"misfire_strategy_do_nothing\"), new MisfireDoNothing()),\n\n    /**\n     * fire once now\n     */\n    FIRE_ONCE_NOW(I18nUtil.getString(\"misfire_strategy_fire_once_now\"), new MisfireFireOnceNow());\n\n    private final String title;\n    private final MisfireHandler misfireHandler;\n\n    MisfireStrategyEnum(String title, MisfireHandler misfireHandler) {\n        this.title = title;\n        this.misfireHandler = misfireHandler;\n    }\n\n    public String getTitle() {\n        return title;\n    }\n\n    public MisfireHandler getMisfireHandler() {\n        return misfireHandler;\n    }\n\n    /**\n     * match misfire strategy\n     *\n     * @param name          name of misfire strategy\n     * @param defaultItem   default misfire strategy\n     * @return misfire strategy\n     */\n    public static MisfireStrategyEnum match(String name, MisfireStrategyEnum defaultItem){\n        for (MisfireStrategyEnum item: MisfireStrategyEnum.values()) {\n            if (item.name().equals(name)) {\n                return item;\n            }\n        }\n        return defaultItem;\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/misfire/strategy/MisfireDoNothing.java",
    "content": "package com.xxl.job.admin.scheduler.misfire.strategy;\n\nimport com.xxl.job.admin.scheduler.misfire.MisfireHandler;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class MisfireDoNothing extends MisfireHandler {\n    private static final Logger logger = LoggerFactory.getLogger(MisfireDoNothing.class);\n\n    @Override\n    public void handle(int jobId) {\n        logger.warn(\">>>>>>>>>>> xxl-job, schedule MisfireDoNothing: jobId = \" + jobId );\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/misfire/strategy/MisfireFireOnceNow.java",
    "content": "package com.xxl.job.admin.scheduler.misfire.strategy;\n\nimport com.xxl.job.admin.scheduler.config.XxlJobAdminBootstrap;\nimport com.xxl.job.admin.scheduler.misfire.MisfireHandler;\nimport com.xxl.job.admin.scheduler.trigger.TriggerTypeEnum;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class MisfireFireOnceNow extends MisfireHandler {\n    protected static Logger logger = LoggerFactory.getLogger(MisfireFireOnceNow.class);\n\n    @Override\n    public void handle(int jobId) {\n        // FIRE_ONCE_NOW 》 trigger\n        XxlJobAdminBootstrap.getInstance().getJobTriggerPoolHelper().trigger(jobId, TriggerTypeEnum.MISFIRE, -1, null, null, null);\n        logger.warn(\">>>>>>>>>>> xxl-job, schedule MisfireFireOnceNow: jobId = \" + jobId );\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/openapi/OpenApiController.java",
    "content": "package com.xxl.job.admin.scheduler.openapi;\n\nimport com.xxl.job.admin.scheduler.config.XxlJobAdminBootstrap;\nimport com.xxl.job.core.constant.Const;\nimport com.xxl.job.core.openapi.AdminBiz;\nimport com.xxl.job.core.openapi.model.CallbackRequest;\nimport com.xxl.job.core.openapi.model.RegistryRequest;\nimport com.xxl.sso.core.annotation.XxlSso;\nimport com.xxl.tool.core.StringTool;\nimport com.xxl.tool.json.GsonTool;\nimport com.xxl.tool.response.Response;\nimport jakarta.annotation.Resource;\nimport jakarta.servlet.http.HttpServletRequest;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.*;\n\nimport java.util.List;\n\n/**\n * Created by xuxueli on 17/5/10.\n */\n@Controller\npublic class OpenApiController {\n\n    @Resource\n    private AdminBiz adminBiz;\n\n    /**\n     * api\n     */\n    @RequestMapping(\"/api/{uri}\")\n    @ResponseBody\n    @XxlSso(login = false)\n    public Object api(HttpServletRequest request,\n                               @PathVariable(\"uri\") String uri,\n                               @RequestHeader(value = Const.XXL_JOB_ACCESS_TOKEN, required = false) String accesstoken,\n                               @RequestBody(required = false) String requestBody) {\n\n        // valid\n        if (!\"POST\".equalsIgnoreCase(request.getMethod())) {\n            return Response.ofFail(\"invalid request, HttpMethod not support.\");\n        }\n        if (StringTool.isBlank(uri)) {\n            return Response.ofFail(\"invalid request, uri-mapping empty.\");\n        }\n        if (StringTool.isBlank(requestBody)) {\n            return Response.ofFail(\"invalid request, requestBody empty.\");\n        }\n\n        // valid token\n        if (StringTool.isNotBlank(XxlJobAdminBootstrap.getInstance().getAccessToken())\n                && !XxlJobAdminBootstrap.getInstance().getAccessToken().equals(accesstoken)) {\n            return Response.ofFail(\"The access token is wrong.\");\n        }\n\n        // dispatch request\n        try {\n            switch (uri) {\n                case \"callback\": {\n                    List<CallbackRequest> callbackParamList = GsonTool.fromJson(requestBody, List.class, CallbackRequest.class);\n                    return adminBiz.callback(callbackParamList);\n                }\n                case \"registry\": {\n                    RegistryRequest registryParam = GsonTool.fromJson(requestBody, RegistryRequest.class);\n                    return adminBiz.registry(registryParam);\n                }\n                case \"registryRemove\": {\n                    RegistryRequest registryParam = GsonTool.fromJson(requestBody, RegistryRequest.class);\n                    return adminBiz.registryRemove(registryParam);\n                    }\n                default:\n                    return Response.ofFail(\"invalid request, uri-mapping(\"+ uri +\") not found.\");\n            }\n        } catch (Exception e) {\n            return Response.ofFail(\"openapi invoke error: \" + e.getMessage());\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/route/ExecutorRouteStrategyEnum.java",
    "content": "package com.xxl.job.admin.scheduler.route;\n\nimport com.xxl.job.admin.scheduler.route.strategy.*;\nimport com.xxl.job.admin.util.I18nUtil;\n\n/**\n * Created by xuxueli on 17/3/10.\n */\npublic enum ExecutorRouteStrategyEnum {\n\n    FIRST(I18nUtil.getString(\"jobconf_route_first\"), new ExecutorRouteFirst()),\n    LAST(I18nUtil.getString(\"jobconf_route_last\"), new ExecutorRouteLast()),\n    ROUND(I18nUtil.getString(\"jobconf_route_round\"), new ExecutorRouteRound()),\n    RANDOM(I18nUtil.getString(\"jobconf_route_random\"), new ExecutorRouteRandom()),\n    CONSISTENT_HASH(I18nUtil.getString(\"jobconf_route_consistenthash\"), new ExecutorRouteConsistentHash()),\n    LEAST_FREQUENTLY_USED(I18nUtil.getString(\"jobconf_route_lfu\"), new ExecutorRouteLFU()),\n    LEAST_RECENTLY_USED(I18nUtil.getString(\"jobconf_route_lru\"), new ExecutorRouteLRU()),\n    FAILOVER(I18nUtil.getString(\"jobconf_route_failover\"), new ExecutorRouteFailover()),\n    BUSYOVER(I18nUtil.getString(\"jobconf_route_busyover\"), new ExecutorRouteBusyover()),\n    SHARDING_BROADCAST(I18nUtil.getString(\"jobconf_route_shard\"), null);\n\n    ExecutorRouteStrategyEnum(String title, ExecutorRouter router) {\n        this.title = title;\n        this.router = router;\n    }\n\n    private String title;\n    private ExecutorRouter router;\n\n    public String getTitle() {\n        return title;\n    }\n    public ExecutorRouter getRouter() {\n        return router;\n    }\n\n    /**\n     * match router\n     */\n    public static ExecutorRouteStrategyEnum match(String name, ExecutorRouteStrategyEnum defaultItem){\n        if (name != null) {\n            for (ExecutorRouteStrategyEnum item: ExecutorRouteStrategyEnum.values()) {\n                if (item.name().equals(name)) {\n                    return item;\n                }\n            }\n        }\n        return defaultItem;\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/route/ExecutorRouter.java",
    "content": "package com.xxl.job.admin.scheduler.route;\n\nimport com.xxl.job.core.openapi.model.TriggerRequest;\nimport com.xxl.tool.response.Response;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.List;\n\n/**\n * Created by xuxueli on 17/3/10.\n */\npublic abstract class ExecutorRouter {\n    protected static Logger logger = LoggerFactory.getLogger(ExecutorRouter.class);\n\n    /**\n     * route address\n     *\n     * @param addressList  executor address list\n     * @return  ReturnT.content=address\n     */\n    public abstract Response<String> route(TriggerRequest triggerParam, List<String> addressList);\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/route/strategy/ExecutorRouteBusyover.java",
    "content": "package com.xxl.job.admin.scheduler.route.strategy;\n\nimport com.xxl.job.admin.scheduler.config.XxlJobAdminBootstrap;\nimport com.xxl.job.admin.scheduler.route.ExecutorRouter;\nimport com.xxl.job.admin.util.I18nUtil;\nimport com.xxl.job.core.openapi.ExecutorBiz;\nimport com.xxl.job.core.openapi.model.IdleBeatRequest;\nimport com.xxl.job.core.openapi.model.TriggerRequest;\nimport com.xxl.tool.response.Response;\n\nimport java.util.List;\n\n/**\n * Created by xuxueli on 17/3/10.\n */\npublic class ExecutorRouteBusyover extends ExecutorRouter {\n\n    @Override\n    public Response<String> route(TriggerRequest triggerParam, List<String> addressList) {\n        StringBuffer idleBeatResultSB = new StringBuffer();\n        for (String address : addressList) {\n            // beat\n            Response<String> idleBeatResult = null;\n            try {\n                ExecutorBiz executorBiz = XxlJobAdminBootstrap.getExecutorBiz(address);\n                idleBeatResult = executorBiz.idleBeat(new IdleBeatRequest(triggerParam.getJobId()));\n            } catch (Exception e) {\n                logger.error(e.getMessage(), e);\n                idleBeatResult = Response.ofFail( \"\"+e );\n            }\n            idleBeatResultSB.append( (idleBeatResultSB.length()>0)?\"<br><br>\":\"\")\n                    .append(I18nUtil.getString(\"jobconf_idleBeat\") + \"：\")\n                    .append(\"<br>address：\").append(address)\n                    .append(\"<br>code：\").append(idleBeatResult.getCode())\n                    .append(\"<br>msg：\").append(idleBeatResult.getMsg());\n\n            // beat success\n            if (idleBeatResult.isSuccess()) {\n                idleBeatResult.setMsg(idleBeatResultSB.toString());\n                idleBeatResult.setData(address);\n                return idleBeatResult;\n            }\n        }\n\n        return Response.ofFail( idleBeatResultSB.toString());\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/route/strategy/ExecutorRouteConsistentHash.java",
    "content": "package com.xxl.job.admin.scheduler.route.strategy;\n\nimport com.xxl.job.admin.scheduler.route.ExecutorRouter;\nimport com.xxl.job.core.openapi.model.TriggerRequest;\nimport com.xxl.tool.response.Response;\n\nimport java.nio.charset.StandardCharsets;\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.List;\nimport java.util.SortedMap;\nimport java.util.TreeMap;\n\n/**\n * 分组下机器地址相同，不同JOB均匀散列在不同机器上，保证分组下机器分配JOB平均；且每个JOB固定调度其中一台机器；\n *      a、virtual node：解决不均衡问题\n *      b、hash method replace hashCode：String的hashCode可能重复，需要进一步扩大hashCode的取值范围\n *\n * Created by xuxueli on 17/3/10.\n */\npublic class ExecutorRouteConsistentHash extends ExecutorRouter {\n\n    private static final int VIRTUAL_NODE_NUM = 100;\n\n    /**\n     * get hash code on 2^32 ring (md5散列的方式计算hash值)\n     *\n     * @param key key\n     * @return hash code\n     */\n    private static long hash(String key) {\n\n        // md5 byte\n        MessageDigest md5;\n        try {\n            md5 = MessageDigest.getInstance(\"MD5\");\n        } catch (NoSuchAlgorithmException e) {\n            throw new RuntimeException(\"MD5 not supported\", e);\n        }\n        md5.reset();\n        byte[] keyBytes = null;\n        keyBytes = key.getBytes(StandardCharsets.UTF_8);\n\n        md5.update(keyBytes);\n        byte[] digest = md5.digest();\n\n        // hash code, Truncate to 32-bits\n        long hashCode = ((long) (digest[3] & 0xFF) << 24)\n                | ((long) (digest[2] & 0xFF) << 16)\n                | ((long) (digest[1] & 0xFF) << 8)\n                | (digest[0] & 0xFF);\n\n        return hashCode & 0xffffffffL;\n    }\n\n    /**\n     * get address by jobId\n     *\n     * @param jobId         job id\n     * @param addressList   address list\n     * @return address\n     */\n    public String hashJob(int jobId, List<String> addressList) {\n\n        // ------A1------A2-------A3------\n        // -----------J1------------------\n        TreeMap<Long, String> addressRing = new TreeMap<Long, String>();\n        for (String address: addressList) {\n            for (int i = 0; i < VIRTUAL_NODE_NUM; i++) {\n                long addressHash = hash(\"SHARD-\" + address + \"-NODE-\" + i);\n                addressRing.put(addressHash, address);\n            }\n        }\n\n        long jobHash = hash(String.valueOf(jobId));\n        SortedMap<Long, String> lastRing = addressRing.tailMap(jobHash);\n        if (!lastRing.isEmpty()) {\n            return lastRing.get(lastRing.firstKey());\n        }\n        return addressRing.firstEntry().getValue();\n    }\n\n    @Override\n    public Response<String> route(TriggerRequest triggerParam, List<String> addressList) {\n        String address = hashJob(triggerParam.getJobId(), addressList);\n        return Response.ofSuccess(address);\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/route/strategy/ExecutorRouteFailover.java",
    "content": "package com.xxl.job.admin.scheduler.route.strategy;\n\nimport com.xxl.job.admin.scheduler.config.XxlJobAdminBootstrap;\nimport com.xxl.job.admin.scheduler.route.ExecutorRouter;\nimport com.xxl.job.admin.util.I18nUtil;\nimport com.xxl.job.core.openapi.ExecutorBiz;\nimport com.xxl.job.core.openapi.model.TriggerRequest;\nimport com.xxl.tool.response.Response;\n\nimport java.util.List;\n\n/**\n * Created by xuxueli on 17/3/10.\n */\npublic class ExecutorRouteFailover extends ExecutorRouter {\n\n    @Override\n    public Response<String> route(TriggerRequest triggerParam, List<String> addressList) {\n\n        StringBuffer beatResultSB = new StringBuffer();\n        for (String address : addressList) {\n            // beat\n            Response<String> beatResult = null;\n            try {\n                ExecutorBiz executorBiz = XxlJobAdminBootstrap.getExecutorBiz(address);\n                beatResult = executorBiz.beat();\n            } catch (Exception e) {\n                logger.error(e.getMessage(), e);\n                beatResult = Response.ofFail(e.getMessage() );\n            }\n            beatResultSB.append( (beatResultSB.length()>0)?\"<br><br>\":\"\")\n                    .append(I18nUtil.getString(\"jobconf_beat\") + \"：\")\n                    .append(\"<br>address：\").append(address)\n                    .append(\"<br>code：\").append(beatResult.getCode())\n                    .append(\"<br>msg：\").append(beatResult.getMsg());\n\n            // beat success\n            if (beatResult.isSuccess()) {\n\n                beatResult.setMsg(beatResultSB.toString());\n                beatResult.setData(address);\n                return beatResult;\n            }\n        }\n        return Response.ofFail( beatResultSB.toString());\n\n    }\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/route/strategy/ExecutorRouteFirst.java",
    "content": "package com.xxl.job.admin.scheduler.route.strategy;\n\nimport com.xxl.job.admin.scheduler.route.ExecutorRouter;\nimport com.xxl.job.core.openapi.model.TriggerRequest;\nimport com.xxl.tool.response.Response;\n\nimport java.util.List;\n\n/**\n * Created by xuxueli on 17/3/10.\n */\npublic class ExecutorRouteFirst extends ExecutorRouter {\n\n    @Override\n    public Response<String> route(TriggerRequest triggerParam, List<String> addressList){\n        return Response.ofSuccess(addressList.get(0));\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/route/strategy/ExecutorRouteLFU.java",
    "content": "package com.xxl.job.admin.scheduler.route.strategy;\n\nimport com.xxl.job.admin.scheduler.route.ExecutorRouter;\nimport com.xxl.job.core.openapi.model.TriggerRequest;\nimport com.xxl.tool.response.Response;\n\nimport java.util.*;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\n/**\n * 单个JOB对应的每个执行器，使用频率最低的优先被选举\n *      a(*)、LFU(Least Frequently Used)：最不经常使用，频率/次数\n *      b、LRU(Least Recently Used)：最近最久未使用，时间\n *\n * Created by xuxueli on 17/3/10.\n */\npublic class ExecutorRouteLFU extends ExecutorRouter {\n\n    /**\n     * job lfu map\n     *\n     * <jobId, <address, count>>\n     */\n    private static ConcurrentMap<Integer, HashMap<String, Integer>> jobLfuMap = new ConcurrentHashMap<Integer, HashMap<String, Integer>>();\n    private static long CACHE_VALID_TIME = 0;\n\n    public String route(int jobId, List<String> addressList) {\n\n        // cache clear\n        if (System.currentTimeMillis() > CACHE_VALID_TIME) {\n            jobLfuMap.clear();\n            CACHE_VALID_TIME = System.currentTimeMillis() + 1000*60*60*24;\n        }\n\n        // lfu item init\n        HashMap<String, Integer> lfuItemMap = jobLfuMap.get(jobId);     // Key排序可以用TreeMap+构造入参Compare；Value排序暂时只能通过ArrayList；\n        if (lfuItemMap == null) {\n            lfuItemMap = new HashMap<>();\n            jobLfuMap.putIfAbsent(jobId, lfuItemMap);   // 避免重复覆盖\n        }\n\n        // put new\n        for (String address: addressList) {\n            if (!lfuItemMap.containsKey(address) || lfuItemMap.get(address) >1000000 ) {\n                lfuItemMap.put(address, new Random().nextInt(addressList.size()));  // 初始化时主动Random一次，缓解首次压力\n            }\n        }\n        // remove old\n        List<String> delKeys = new ArrayList<>();\n        for (String existKey: lfuItemMap.keySet()) {\n            if (!addressList.contains(existKey)) {\n                delKeys.add(existKey);\n            }\n        }\n        if (!delKeys.isEmpty()) {\n            for (String delKey: delKeys) {\n                lfuItemMap.remove(delKey);\n            }\n        }\n\n        // load least userd count address\n        List<Map.Entry<String, Integer>> lfuItemList = new ArrayList<>(lfuItemMap.entrySet());\n        lfuItemList.sort(Map.Entry.comparingByValue());     // 默认升序, 获取 Value 最小值\n\n        Map.Entry<String, Integer> addressItem = lfuItemList.get(0);\n        addressItem.setValue(addressItem.getValue() + 1);\n\n        return addressItem.getKey();\n    }\n\n    @Override\n    public Response<String> route(TriggerRequest triggerParam, List<String> addressList) {\n        String address = route(triggerParam.getJobId(), addressList);\n        return Response.ofSuccess(address);\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/route/strategy/ExecutorRouteLRU.java",
    "content": "package com.xxl.job.admin.scheduler.route.strategy;\n\nimport com.xxl.job.admin.scheduler.route.ExecutorRouter;\nimport com.xxl.job.core.openapi.model.TriggerRequest;\nimport com.xxl.tool.response.Response;\n\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\n/**\n * 单个JOB对应的每个执行器，最久为使用的优先被选举\n *      a、LFU(Least Frequently Used)：最不经常使用，频率/次数\n *      b(*)、LRU(Least Recently Used)：最近最久未使用，时间\n *\n * Created by xuxueli on 17/3/10.\n */\npublic class ExecutorRouteLRU extends ExecutorRouter {\n\n    /**\n     * job lru map\n     *\n     * <jobId, <address, address>>\n     */\n    private static ConcurrentMap<Integer, LinkedHashMap<String, String>> jobLRUMap = new ConcurrentHashMap<Integer, LinkedHashMap<String, String>>();\n    private static long CACHE_VALID_TIME = 0;\n\n    public String route(int jobId, List<String> addressList) {\n\n        // cache clear\n        if (System.currentTimeMillis() > CACHE_VALID_TIME) {\n            jobLRUMap.clear();\n            CACHE_VALID_TIME = System.currentTimeMillis() + 1000*60*60*24;\n        }\n\n        // init lru\n        LinkedHashMap<String, String> lruItem = jobLRUMap.get(jobId);\n        if (lruItem == null) {\n            /**\n             * LinkedHashMap\n             *      a、accessOrder：true=访问顺序排序（get/put时排序）；false=插入顺序排期；\n             *      b、removeEldestEntry：新增元素时将会调用，返回true时会删除最老元素；可封装LinkedHashMap并重写该方法，比如定义最大容量，超出是返回true即可实现固定长度的LRU算法；\n             */\n            lruItem = new LinkedHashMap<>(16, 0.75f, true);\n            jobLRUMap.putIfAbsent(jobId, lruItem);\n        }\n\n        // put new\n        for (String address: addressList) {\n            if (!lruItem.containsKey(address)) {\n                lruItem.put(address, address);\n            }\n        }\n        // remove old\n        List<String> delKeys = new ArrayList<>();\n        for (String existKey: lruItem.keySet()) {\n            if (!addressList.contains(existKey)) {\n                delKeys.add(existKey);\n            }\n        }\n        if (!delKeys.isEmpty()) {\n            for (String delKey: delKeys) {\n                lruItem.remove(delKey);\n            }\n        }\n\n        // load first elment, eldest entry\n        String eldestKey = lruItem.entrySet().iterator().next().getKey();\n        return lruItem.get(eldestKey);\n    }\n\n    @Override\n    public Response<String> route(TriggerRequest triggerParam, List<String> addressList) {\n        String address = route(triggerParam.getJobId(), addressList);\n        return Response.ofSuccess(address);\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/route/strategy/ExecutorRouteLast.java",
    "content": "package com.xxl.job.admin.scheduler.route.strategy;\n\nimport com.xxl.job.admin.scheduler.route.ExecutorRouter;\nimport com.xxl.job.core.openapi.model.TriggerRequest;\nimport com.xxl.tool.response.Response;\n\nimport java.util.List;\n\n/**\n * Created by xuxueli on 17/3/10.\n */\npublic class ExecutorRouteLast extends ExecutorRouter {\n\n    @Override\n    public Response<String> route(TriggerRequest triggerParam, List<String> addressList) {\n        return Response.ofSuccess(addressList.get(addressList.size()-1));\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/route/strategy/ExecutorRouteRandom.java",
    "content": "package com.xxl.job.admin.scheduler.route.strategy;\n\nimport com.xxl.job.admin.scheduler.route.ExecutorRouter;\nimport com.xxl.job.core.openapi.model.TriggerRequest;\nimport com.xxl.tool.response.Response;\n\nimport java.util.List;\nimport java.util.Random;\n\n/**\n * Created by xuxueli on 17/3/10.\n */\npublic class ExecutorRouteRandom extends ExecutorRouter {\n\n    private static Random localRandom = new Random();\n\n    @Override\n    public Response<String> route(TriggerRequest triggerParam, List<String> addressList) {\n        String address = addressList.get(localRandom.nextInt(addressList.size()));\n        return Response.ofSuccess(address);\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/route/strategy/ExecutorRouteRound.java",
    "content": "package com.xxl.job.admin.scheduler.route.strategy;\n\nimport com.xxl.job.admin.scheduler.route.ExecutorRouter;\nimport com.xxl.job.core.openapi.model.TriggerRequest;\nimport com.xxl.tool.response.Response;\n\nimport java.util.List;\nimport java.util.Random;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.atomic.AtomicInteger;\n\n/**\n * Created by xuxueli on 17/3/10.\n */\npublic class ExecutorRouteRound extends ExecutorRouter {\n\n    private static ConcurrentMap<Integer, AtomicInteger> routeCountEachJob = new ConcurrentHashMap<>();\n    private static long CACHE_VALID_TIME = 0;\n\n    private static int count(int jobId) {\n        // cache clear\n        if (System.currentTimeMillis() > CACHE_VALID_TIME) {\n            routeCountEachJob.clear();\n            CACHE_VALID_TIME = System.currentTimeMillis() + 1000*60*60*24;\n        }\n\n        AtomicInteger count = routeCountEachJob.get(jobId);\n        if (count == null || count.get() > 1000000) {\n            // 初始化时主动Random一次，缓解首次压力\n            count = new AtomicInteger(new Random().nextInt(100));\n        } else {\n            // count++\n            count.addAndGet(1);\n        }\n        routeCountEachJob.put(jobId, count);\n        return count.get();\n    }\n\n    @Override\n    public Response<String> route(TriggerRequest triggerParam, List<String> addressList) {\n        String address = addressList.get(count(triggerParam.getJobId())%addressList.size());\n        return Response.ofSuccess(address);\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/thread/JobCompleteHelper.java",
    "content": "package com.xxl.job.admin.scheduler.thread;\n\nimport com.xxl.job.admin.model.XxlJobLog;\nimport com.xxl.job.admin.scheduler.config.XxlJobAdminBootstrap;\nimport com.xxl.job.admin.util.I18nUtil;\nimport com.xxl.job.core.openapi.model.CallbackRequest;\nimport com.xxl.job.core.context.XxlJobContext;\nimport com.xxl.tool.core.DateTool;\nimport com.xxl.tool.response.Response;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.Date;\nimport java.util.List;\nimport java.util.concurrent.*;\n\n/**\n * job complate, for callback and result-lost\n *\n * @author xuxueli 2015-9-1 18:05:56\n */\npublic class JobCompleteHelper {\n\tprivate static final Logger logger = LoggerFactory.getLogger(JobCompleteHelper.class);\n\t\n\t// ---------------------- monitor ----------------------\n\n\tprivate ThreadPoolExecutor callbackThreadPool = null;\n\tprivate Thread monitorThread;\n\tprivate volatile boolean toStop = false;\n\n\t/**\n\t * start\n\t */\n\tpublic void start(){\n\n\t\t// for callback\n\t\tcallbackThreadPool = new ThreadPoolExecutor(\n\t\t\t\t2,\n\t\t\t\t20,\n\t\t\t\t30L,\n\t\t\t\tTimeUnit.SECONDS,\n\t\t\t\tnew LinkedBlockingQueue<Runnable>(3000),\n\t\t\t\tnew ThreadFactory() {\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic Thread newThread(Runnable r) {\n\t\t\t\t\t\treturn new Thread(r, \"xxl-job, admin JobLosedMonitorHelper-callbackThreadPool-\" + r.hashCode());\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tnew RejectedExecutionHandler() {\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {\n\t\t\t\t\t\tr.run();\n\t\t\t\t\t\tlogger.warn(\">>>>>>>>>>> xxl-job, callback too fast, match threadpool rejected handler(run now).\");\n\t\t\t\t\t}\n\t\t\t\t});\n\n\n\t\t// for monitor\n\t\tmonitorThread = new Thread(new Runnable() {\n\n\t\t\t@Override\n\t\t\tpublic void run() {\n\n\t\t\t\t// wait for JobTriggerPoolHelper-init\n\t\t\t\ttry {\n\t\t\t\t\tTimeUnit.MILLISECONDS.sleep(50);\n\t\t\t\t} catch (Throwable e) {\n\t\t\t\t\tif (!toStop) {\n\t\t\t\t\t\tlogger.error(e.getMessage(), e);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// monitor\n\t\t\t\twhile (!toStop) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\t// 任务结果丢失处理：调度记录停留在 \"运行中\" 状态超过10min，且对应执行器心跳注册失败不在线，则将本地调度主动标记失败；\n\t\t\t\t\t\tDate losedTime = DateTool.addMinutes(new Date(), -10);\n\t\t\t\t\t\tList<Long> losedJobIds  = XxlJobAdminBootstrap.getInstance().getXxlJobLogMapper().findLostJobIds(losedTime);\n\n\t\t\t\t\t\tif (losedJobIds!=null && losedJobIds.size()>0) {\n\t\t\t\t\t\t\tfor (Long logId: losedJobIds) {\n\n\t\t\t\t\t\t\t\tXxlJobLog jobLog = new XxlJobLog();\n\t\t\t\t\t\t\t\tjobLog.setId(logId);\n\n\t\t\t\t\t\t\t\tjobLog.setHandleTime(new Date());\n\t\t\t\t\t\t\t\tjobLog.setHandleCode(XxlJobContext.HANDLE_CODE_FAIL);\n\t\t\t\t\t\t\t\tjobLog.setHandleMsg( I18nUtil.getString(\"joblog_lost_fail\") );\n\n\t\t\t\t\t\t\t\tXxlJobAdminBootstrap.getInstance().getJobCompleter().complete(jobLog);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (Throwable e) {\n\t\t\t\t\t\tif (!toStop) {\n\t\t\t\t\t\t\tlogger.error(\">>>>>>>>>>> xxl-job, job fail monitor thread error:{}\", e);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n                    try {\n                        TimeUnit.SECONDS.sleep(60);\n                    } catch (Throwable e) {\n                        if (!toStop) {\n                            logger.error(e.getMessage(), e);\n                        }\n                    }\n\n                }\n\n\t\t\t\tlogger.info(\">>>>>>>>>>> xxl-job, JobLosedMonitorHelper stop\");\n\n\t\t\t}\n\t\t});\n\t\tmonitorThread.setDaemon(true);\n\t\tmonitorThread.setName(\"xxl-job, admin JobLosedMonitorHelper\");\n\t\tmonitorThread.start();\n\t}\n\n\t/**\n\t * stop\n\t */\n\tpublic void stop(){\n\t\ttoStop = true;\n\n\t\t// stop registryOrRemoveThreadPool\n\t\tcallbackThreadPool.shutdownNow();\n\n\t\t// stop monitorThread (interrupt and wait)\n\t\tmonitorThread.interrupt();\n\t\ttry {\n\t\t\tmonitorThread.join();\n\t\t} catch (Throwable e) {\n\t\t\tlogger.error(e.getMessage(), e);\n\t\t}\n\t}\n\n\n\t// ---------------------- helper ----------------------\n\n\tpublic Response<String> callback(List<CallbackRequest> callbackParamList) {\n\n\t\tcallbackThreadPool.execute(new Runnable() {\n\t\t\t@Override\n\t\t\tpublic void run() {\n\t\t\t\tfor (CallbackRequest callbackRequest: callbackParamList) {\n\t\t\t\t\tResponse<String> callbackResult = doCallback(callbackRequest);\n\t\t\t\t\tlogger.debug(\">>>>>>>>> JobApiController.callback {}, callbackRequest={}, callbackResult={}\",\n\t\t\t\t\t\t\t(callbackResult.isSuccess()?\"success\":\"fail\"), callbackRequest, callbackResult);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\treturn Response.ofSuccess();\n\t}\n\n\tprivate Response<String> doCallback(CallbackRequest handleCallbackParam) {\n\t\t// valid log item\n\t\tXxlJobLog log = XxlJobAdminBootstrap.getInstance().getXxlJobLogMapper().load(handleCallbackParam.getLogId());\n\t\tif (log == null) {\n\t\t\treturn Response.ofFail( \"log item not found.\");\n\t\t}\n\t\tif (log.getHandleCode() > 0) {\n\t\t\treturn Response.ofFail(\"log repeate callback.\");     // avoid repeat callback, trigger child job etc\n\t\t}\n\n\t\t// handle msg\n\t\tStringBuffer handleMsg = new StringBuffer();\n\t\tif (log.getHandleMsg()!=null) {\n\t\t\thandleMsg.append(log.getHandleMsg()).append(\"<br>\");\n\t\t}\n\t\tif (handleCallbackParam.getHandleMsg() != null) {\n\t\t\thandleMsg.append(handleCallbackParam.getHandleMsg());\n\t\t}\n\n\t\t// success, save log\n\t\tlog.setHandleTime(new Date());\n\t\tlog.setHandleCode(handleCallbackParam.getHandleCode());\n\t\tlog.setHandleMsg(handleMsg.toString());\n\t\tXxlJobAdminBootstrap.getInstance().getJobCompleter().complete(log);\n\n\t\treturn Response.ofSuccess();\n\t}\n\n\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/thread/JobFailAlarmMonitorHelper.java",
    "content": "package com.xxl.job.admin.scheduler.thread;\n\nimport com.xxl.job.admin.model.XxlJobInfo;\nimport com.xxl.job.admin.model.XxlJobLog;\nimport com.xxl.job.admin.scheduler.config.XxlJobAdminBootstrap;\nimport com.xxl.job.admin.scheduler.trigger.TriggerTypeEnum;\nimport com.xxl.job.admin.util.I18nUtil;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * job fail-monitor helper\n *\n * @author xuxueli 2015-9-1 18:05:56\n */\npublic class JobFailAlarmMonitorHelper {\n\tprivate static Logger logger = LoggerFactory.getLogger(JobFailAlarmMonitorHelper.class);\n\t\n\n\t// ---------------------- monitor ----------------------\n\n\tprivate Thread monitorThread;\n\tprivate volatile boolean toStop = false;\n\n\t/**\n\t * start\n\t */\n\tpublic void start(){\n\t\tmonitorThread = new Thread(new Runnable() {\n\n\t\t\t@Override\n\t\t\tpublic void run() {\n\n\t\t\t\t// monitor\n\t\t\t\twhile (!toStop) {\n\t\t\t\t\ttry {\n\n\t\t\t\t\t\tList<Long> failLogIds = XxlJobAdminBootstrap.getInstance().getXxlJobLogMapper().findFailJobLogIds(1000);\n\t\t\t\t\t\tif (failLogIds!=null && !failLogIds.isEmpty()) {\n\t\t\t\t\t\t\tfor (long failLogId: failLogIds) {\n\n\t\t\t\t\t\t\t\t// lock log\n\t\t\t\t\t\t\t\tint lockRet = XxlJobAdminBootstrap.getInstance().getXxlJobLogMapper().updateAlarmStatus(failLogId, 0, -1);\n\t\t\t\t\t\t\t\tif (lockRet < 1) {\n\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tXxlJobLog log = XxlJobAdminBootstrap.getInstance().getXxlJobLogMapper().load(failLogId);\n\t\t\t\t\t\t\t\tXxlJobInfo info = XxlJobAdminBootstrap.getInstance().getXxlJobInfoMapper().loadById(log.getJobId());\n\n\t\t\t\t\t\t\t\t// 1、fail retry monitor\n\t\t\t\t\t\t\t\tif (log.getExecutorFailRetryCount() > 0) {\n\t\t\t\t\t\t\t\t\tXxlJobAdminBootstrap.getInstance().getJobTriggerPoolHelper().trigger(log.getJobId(), TriggerTypeEnum.RETRY, (log.getExecutorFailRetryCount()-1), log.getExecutorShardingParam(), log.getExecutorParam(), null);\n\t\t\t\t\t\t\t\t\tString retryMsg = \"<br><br><span style=\\\"color:#00c0ef;\\\" > >>>>>>>>>>>\"+ I18nUtil.getString(\"jobconf_trigger_type_retry\") +\"<<<<<<<<<<< </span><br>\";\n\t\t\t\t\t\t\t\t\tlog.setTriggerMsg(log.getTriggerMsg() + retryMsg);\n\t\t\t\t\t\t\t\t\tXxlJobAdminBootstrap.getInstance().getXxlJobLogMapper().updateTriggerInfo(log);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// 2、fail alarm monitor\n\t\t\t\t\t\t\t\tint newAlarmStatus = 0;\t\t// 告警状态：0-默认、-1=锁定状态、1-无需告警、2-告警成功、3-告警失败\n\t\t\t\t\t\t\t\tif (info != null) {\n\t\t\t\t\t\t\t\t\tboolean alarmResult = XxlJobAdminBootstrap.getInstance().getJobAlarmer().alarm(info, log);\n\t\t\t\t\t\t\t\t\tnewAlarmStatus = alarmResult?2:3;\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tnewAlarmStatus = 1;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tXxlJobAdminBootstrap.getInstance().getXxlJobLogMapper().updateAlarmStatus(failLogId, -1, newAlarmStatus);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} catch (Throwable e) {\n\t\t\t\t\t\tif (!toStop) {\n\t\t\t\t\t\t\tlogger.error(\">>>>>>>>>>> xxl-job, job fail monitor thread error:{}\", e.getMessage(), e);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n                    try {\n                        TimeUnit.SECONDS.sleep(10);\n                    } catch (Throwable e) {\n                        if (!toStop) {\n                            logger.error(e.getMessage(), e);\n                        }\n                    }\n\n                }\n\n\t\t\t\tlogger.info(\">>>>>>>>>>> xxl-job, job fail monitor thread stop\");\n\n\t\t\t}\n\t\t});\n\t\tmonitorThread.setDaemon(true);\n\t\tmonitorThread.setName(\"xxl-job, admin JobFailMonitorHelper\");\n\t\tmonitorThread.start();\n\t}\n\n\t/**\n\t * stop\n\t */\n\tpublic void stop(){\n\t\ttoStop = true;\n\t\t// interrupt and wait\n\t\tmonitorThread.interrupt();\n\t\ttry {\n\t\t\tmonitorThread.join();\n\t\t} catch (Throwable e) {\n\t\t\tlogger.error(e.getMessage(), e);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/thread/JobLogReportHelper.java",
    "content": "package com.xxl.job.admin.scheduler.thread;\n\nimport com.xxl.job.admin.scheduler.config.XxlJobAdminBootstrap;\nimport com.xxl.job.admin.model.XxlJobLogReport;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * job log report helper\n *\n * @author xuxueli 2019-11-22\n */\npublic class JobLogReportHelper {\n    private static final Logger logger = LoggerFactory.getLogger(JobLogReportHelper.class);\n\n\n    private Thread logReportThread;\n    private volatile boolean toStop = false;\n\n    /**\n     * start\n     */\n    public void start(){\n        logReportThread = new Thread(new Runnable() {\n\n            @Override\n            public void run() {\n\n                // last clean log time\n                long lastCleanLogTime = 0;\n\n\n                while (!toStop) {\n\n                    // 1、log-report refresh: refresh log report in 3 days\n                    try {\n\n                        for (int i = 0; i < 3; i++) {\n\n                            // today\n                            Calendar itemDay = Calendar.getInstance();\n                            itemDay.add(Calendar.DAY_OF_MONTH, -i);\n                            itemDay.set(Calendar.HOUR_OF_DAY, 0);\n                            itemDay.set(Calendar.MINUTE, 0);\n                            itemDay.set(Calendar.SECOND, 0);\n                            itemDay.set(Calendar.MILLISECOND, 0);\n\n                            Date todayFrom = itemDay.getTime();\n\n                            itemDay.set(Calendar.HOUR_OF_DAY, 23);\n                            itemDay.set(Calendar.MINUTE, 59);\n                            itemDay.set(Calendar.SECOND, 59);\n                            itemDay.set(Calendar.MILLISECOND, 999);\n\n                            Date todayTo = itemDay.getTime();\n\n                            // refresh log-report every minute\n                            XxlJobLogReport xxlJobLogReport = new XxlJobLogReport();\n                            xxlJobLogReport.setTriggerDay(todayFrom);\n                            xxlJobLogReport.setRunningCount(0);\n                            xxlJobLogReport.setSucCount(0);\n                            xxlJobLogReport.setFailCount(0);\n\n                            Map<String, Object> triggerCountMap = XxlJobAdminBootstrap.getInstance().getXxlJobLogMapper().findLogReport(todayFrom, todayTo);\n                            if (triggerCountMap!=null && !triggerCountMap.isEmpty()) {\n                                int triggerDayCount = triggerCountMap.containsKey(\"triggerDayCount\")?Integer.parseInt(String.valueOf(triggerCountMap.get(\"triggerDayCount\"))):0;\n                                int triggerDayCountRunning = triggerCountMap.containsKey(\"triggerDayCountRunning\")?Integer.parseInt(String.valueOf(triggerCountMap.get(\"triggerDayCountRunning\"))):0;\n                                int triggerDayCountSuc = triggerCountMap.containsKey(\"triggerDayCountSuc\")?Integer.parseInt(String.valueOf(triggerCountMap.get(\"triggerDayCountSuc\"))):0;\n                                int triggerDayCountFail = triggerDayCount - triggerDayCountRunning - triggerDayCountSuc;\n\n                                xxlJobLogReport.setRunningCount(triggerDayCountRunning);\n                                xxlJobLogReport.setSucCount(triggerDayCountSuc);\n                                xxlJobLogReport.setFailCount(triggerDayCountFail);\n                            }\n\n                            // do refresh:\n                            XxlJobAdminBootstrap.getInstance().getXxlJobLogReportMapper().saveOrUpdate(xxlJobLogReport);      // 0-fail; 1-save suc; 2-update suc;\n                            /*if (ret < 1) {\n                                XxlJobAdminBootstrap.getInstance().getXxlJobLogReportMapper().save(xxlJobLogReport);\n                            }*/\n                        }\n\n                    } catch (Throwable e) {\n                        if (!toStop) {\n                            logger.error(\">>>>>>>>>>> xxl-job, JobLogReportHelper(log-report refresh) error:{}\", e.getMessage(), e);\n                        }\n                    }\n\n                    // 2、log-clean: switch open & once each day\n                    try {\n                        if (XxlJobAdminBootstrap.getInstance().getLogretentiondays()>0\n                                && System.currentTimeMillis() - lastCleanLogTime > 24*60*60*1000) {\n\n                            // expire-time\n                            Calendar expiredDay = Calendar.getInstance();\n                            expiredDay.add(Calendar.DAY_OF_MONTH, -1 * XxlJobAdminBootstrap.getInstance().getLogretentiondays());\n                            expiredDay.set(Calendar.HOUR_OF_DAY, 0);\n                            expiredDay.set(Calendar.MINUTE, 0);\n                            expiredDay.set(Calendar.SECOND, 0);\n                            expiredDay.set(Calendar.MILLISECOND, 0);\n                            Date clearBeforeTime = expiredDay.getTime();\n\n                            // clean expired log\n                            List<Long> logIds = null;\n                            do {\n                                logIds = XxlJobAdminBootstrap.getInstance().getXxlJobLogMapper().findClearLogIds(0, 0, clearBeforeTime, 0, 1000);\n                                if (logIds!=null && !logIds.isEmpty()) {\n                                    XxlJobAdminBootstrap.getInstance().getXxlJobLogMapper().clearLog(logIds);\n                                }\n                            } while (logIds!=null && !logIds.isEmpty());\n\n                            // update clean time\n                            lastCleanLogTime = System.currentTimeMillis();\n                        }\n                    } catch (Throwable e) {\n                        if (!toStop) {\n                            logger.error(\">>>>>>>>>>> xxl-job, JobLogReportHelper(log-clean) error:{}\", e.getMessage(), e);\n                        }\n                    }\n\n                    try {\n                        TimeUnit.MINUTES.sleep(1);\n                    } catch (Throwable e) {\n                        if (!toStop) {\n                            logger.error(e.getMessage(), e);\n                        }\n                    }\n\n                }\n\n                logger.info(\">>>>>>>>>>> xxl-job, job log report thread stop\");\n\n            }\n        });\n        logReportThread.setDaemon(true);\n        logReportThread.setName(\"xxl-job, admin JobLogReportHelper\");\n        logReportThread.start();\n    }\n\n    /**\n     * stop\n     */\n    public void stop(){\n        toStop = true;\n        // interrupt and wait\n        logReportThread.interrupt();\n        try {\n            logReportThread.join();\n        } catch (Throwable e) {\n            logger.error(e.getMessage(), e);\n        }\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/thread/JobRegistryHelper.java",
    "content": "package com.xxl.job.admin.scheduler.thread;\n\nimport com.xxl.job.admin.model.XxlJobGroup;\nimport com.xxl.job.admin.model.XxlJobRegistry;\nimport com.xxl.job.admin.scheduler.config.XxlJobAdminBootstrap;\nimport com.xxl.job.core.constant.RegistType;\nimport com.xxl.job.core.openapi.model.RegistryRequest;\nimport com.xxl.job.core.constant.Const;\nimport com.xxl.tool.core.StringTool;\nimport com.xxl.tool.response.Response;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.*;\nimport java.util.concurrent.*;\n\n/**\n * job registry instance helper\n *\n * @author xuxueli 2016-10-02 19:10:24\n */\npublic class JobRegistryHelper {\n\tprivate static Logger logger = LoggerFactory.getLogger(JobRegistryHelper.class);\n\n\n\tprivate ThreadPoolExecutor registryOrRemoveThreadPool = null;\n\tprivate Thread registryMonitorThread;\n\tprivate volatile boolean toStop = false;\n\n\n\t/**\n\t * start\n\t */\n\tpublic void start(){\n\n\t\t// for registry or remove\n\t\tregistryOrRemoveThreadPool = new ThreadPoolExecutor(\n\t\t\t\t2,\n\t\t\t\t10,\n\t\t\t\t30L,\n\t\t\t\tTimeUnit.SECONDS,\n\t\t\t\tnew LinkedBlockingQueue<Runnable>(2000),\n\t\t\t\tnew ThreadFactory() {\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic Thread newThread(Runnable r) {\n\t\t\t\t\t\treturn new Thread(r, \"xxl-job, admin JobRegistryMonitorHelper-registryOrRemoveThreadPool-\" + r.hashCode());\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tnew RejectedExecutionHandler() {\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {\n\t\t\t\t\t\tr.run();\n\t\t\t\t\t\tlogger.warn(\">>>>>>>>>>> xxl-job, registry or remove too fast, match threadpool rejected handler(run now).\");\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t// for monitor\n\t\tregistryMonitorThread = new Thread(new Runnable() {\n\t\t\t@Override\n\t\t\tpublic void run() {\n\t\t\t\twhile (!toStop) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\t// auto registry group\n\t\t\t\t\t\tList<XxlJobGroup> groupList = XxlJobAdminBootstrap.getInstance().getXxlJobGroupMapper().findByAddressType(0);\n\t\t\t\t\t\tif (groupList!=null && !groupList.isEmpty()) {\n\n\t\t\t\t\t\t\t// remove dead address (admin/executor)\n\t\t\t\t\t\t\tList<Integer> ids = XxlJobAdminBootstrap.getInstance().getXxlJobRegistryMapper().findDead(Const.DEAD_TIMEOUT, new Date());\n\t\t\t\t\t\t\tif (ids!=null && !ids.isEmpty()) {\n\t\t\t\t\t\t\t\tXxlJobAdminBootstrap.getInstance().getXxlJobRegistryMapper().removeDead(ids);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// fresh online address (admin/executor)\n\t\t\t\t\t\t\tHashMap<String, List<String>> appAddressMap = new HashMap<String, List<String>>();\n\t\t\t\t\t\t\tList<XxlJobRegistry> list = XxlJobAdminBootstrap.getInstance().getXxlJobRegistryMapper().findAll(Const.DEAD_TIMEOUT, new Date());\n\t\t\t\t\t\t\tif (list != null) {\n\t\t\t\t\t\t\t\tfor (XxlJobRegistry item: list) {\n\t\t\t\t\t\t\t\t\tif (RegistType.EXECUTOR.name().equals(item.getRegistryGroup())) {\n\t\t\t\t\t\t\t\t\t\tString appname = item.getRegistryKey();\n\t\t\t\t\t\t\t\t\t\tList<String> registryList = appAddressMap.get(appname);\n\t\t\t\t\t\t\t\t\t\tif (registryList == null) {\n\t\t\t\t\t\t\t\t\t\t\tregistryList = new ArrayList<String>();\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\tif (!registryList.contains(item.getRegistryValue())) {\n\t\t\t\t\t\t\t\t\t\t\tregistryList.add(item.getRegistryValue());\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\tappAddressMap.put(appname, registryList);\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// fresh group address\n\t\t\t\t\t\t\tfor (XxlJobGroup group: groupList) {\n\t\t\t\t\t\t\t\tList<String> registryList = appAddressMap.get(group.getAppname());\n\t\t\t\t\t\t\t\tString addressListStr = null;\n\t\t\t\t\t\t\t\tif (registryList!=null && !registryList.isEmpty()) {\n\t\t\t\t\t\t\t\t\tCollections.sort(registryList);\n\t\t\t\t\t\t\t\t\tStringBuilder addressListSB = new StringBuilder();\n\t\t\t\t\t\t\t\t\tfor (String item:registryList) {\n\t\t\t\t\t\t\t\t\t\taddressListSB.append(item).append(\",\");\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\taddressListStr = addressListSB.toString();\n\t\t\t\t\t\t\t\t\taddressListStr = addressListStr.substring(0, addressListStr.length()-1);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tgroup.setAddressList(addressListStr);\n\t\t\t\t\t\t\t\tgroup.setUpdateTime(new Date());\n\n\t\t\t\t\t\t\t\tXxlJobAdminBootstrap.getInstance().getXxlJobGroupMapper().update(group);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (Throwable e) {\n\t\t\t\t\t\tif (!toStop) {\n\t\t\t\t\t\t\tlogger.error(\">>>>>>>>>>> xxl-job, job registry monitor thread error:{}\", e);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\ttry {\n\t\t\t\t\t\tTimeUnit.SECONDS.sleep(Const.BEAT_TIMEOUT);\n\t\t\t\t\t} catch (Throwable e) {\n\t\t\t\t\t\tif (!toStop) {\n\t\t\t\t\t\t\tlogger.error(\">>>>>>>>>>> xxl-job, job registry monitor thread error:{}\", e);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tlogger.info(\">>>>>>>>>>> xxl-job, job registry monitor thread stop\");\n\t\t\t}\n\t\t});\n\t\tregistryMonitorThread.setDaemon(true);\n\t\tregistryMonitorThread.setName(\"xxl-job, admin JobRegistryMonitorHelper-registryMonitorThread\");\n\t\tregistryMonitorThread.start();\n\t}\n\n\n\t/**\n\t * stop\n\t */\n\tpublic void stop(){\n\t\ttoStop = true;\n\n\t\t// stop registryOrRemoveThreadPool\n\t\tregistryOrRemoveThreadPool.shutdownNow();\n\n\t\t// stop monitor (interrupt and wait)\n\t\tregistryMonitorThread.interrupt();\n\t\ttry {\n\t\t\tregistryMonitorThread.join();\n\t\t} catch (Throwable e) {\n\t\t\tlogger.error(e.getMessage(), e);\n\t\t}\n\t}\n\n\n\t// ---------------------- tool ----------------------\n\n\t/**\n\t * registry\n\t */\n\tpublic Response<String> registry(RegistryRequest registryParam) {\n\n\t\t// valid\n\t\tif (StringTool.isBlank(registryParam.getRegistryGroup())\n\t\t\t\t|| StringTool.isBlank(registryParam.getRegistryKey())\n\t\t\t\t|| StringTool.isBlank(registryParam.getRegistryValue())) {\n\t\t\treturn Response.ofFail(\"Illegal Argument.\");\n\t\t}\n\n\t\t// async execute\n\t\tregistryOrRemoveThreadPool.execute(new Runnable() {\n\t\t\t@Override\n\t\t\tpublic void run() {\n\t\t\t\t// 0-fail; 1-save suc; 2-update suc;\n\t\t\t\tint ret = XxlJobAdminBootstrap.getInstance().getXxlJobRegistryMapper().registrySaveOrUpdate(registryParam.getRegistryGroup(), registryParam.getRegistryKey(), registryParam.getRegistryValue(), new Date());\n\t\t\t\tif (ret == 1) {\n\t\t\t\t\t// fresh (add)\n\t\t\t\t\tfreshGroupRegistryInfo(registryParam);\n\t\t\t\t}\n\t\t\t\t/*int ret = XxlJobAdminConfig.getAdminConfig().getXxlJobRegistryDao().registryUpdate(registryParam.getRegistryGroup(), registryParam.getRegistryKey(), registryParam.getRegistryValue(), new Date());\n\t\t\t\tif (ret < 1) {\n\t\t\t\t\tXxlJobAdminConfig.getAdminConfig().getXxlJobRegistryDao().registrySave(registryParam.getRegistryGroup(), registryParam.getRegistryKey(), registryParam.getRegistryValue(), new Date());\n\n\t\t\t\t\t// fresh\n\t\t\t\t\tfreshGroupRegistryInfo(registryParam);\n\t\t\t\t}*/\n\t\t\t}\n\t\t});\n\n\t\treturn Response.ofSuccess();\n\t}\n\n\t/**\n\t * registry remove\n\t */\n\tpublic Response<String> registryRemove(RegistryRequest registryParam) {\n\n\t\t// valid\n\t\tif (StringTool.isBlank(registryParam.getRegistryGroup())\n\t\t\t\t|| StringTool.isBlank(registryParam.getRegistryKey())\n\t\t\t\t|| StringTool.isBlank(registryParam.getRegistryValue())) {\n\t\t\treturn Response.ofFail(\"Illegal Argument.\");\n\t\t}\n\n\t\t// async execute\n\t\tregistryOrRemoveThreadPool.execute(new Runnable() {\n\t\t\t@Override\n\t\t\tpublic void run() {\n\t\t\t\tint ret = XxlJobAdminBootstrap.getInstance().getXxlJobRegistryMapper().registryDelete(registryParam.getRegistryGroup(), registryParam.getRegistryKey(), registryParam.getRegistryValue());\n\t\t\t\tif (ret > 0) {\n\t\t\t\t\t// fresh (delete)\n\t\t\t\t\tfreshGroupRegistryInfo(registryParam);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\treturn Response.ofSuccess();\n\t}\n\n\tprivate void freshGroupRegistryInfo(RegistryRequest registryParam){\n\t\t// Under consideration, prevent affecting core tables\n\t}\n\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/thread/JobScheduleHelper.java",
    "content": "package com.xxl.job.admin.scheduler.thread;\n\nimport com.xxl.job.admin.constant.TriggerStatus;\nimport com.xxl.job.admin.model.XxlJobInfo;\nimport com.xxl.job.admin.scheduler.config.XxlJobAdminBootstrap;\nimport com.xxl.job.admin.scheduler.misfire.MisfireStrategyEnum;\nimport com.xxl.job.admin.scheduler.trigger.TriggerTypeEnum;\nimport com.xxl.job.admin.scheduler.type.ScheduleTypeEnum;\nimport com.xxl.tool.core.CollectionTool;\nimport com.xxl.tool.core.MapTool;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.transaction.TransactionStatus;\nimport org.springframework.transaction.support.DefaultTransactionDefinition;\n\nimport java.util.*;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * @author xuxueli 2019-05-21\n */\npublic class JobScheduleHelper {\n    private static final Logger logger = LoggerFactory.getLogger(JobScheduleHelper.class);\n\n\n    /**\n     * pre-read time for scheduler, increase efficiency\n     */\n    public static final long PRE_READ_MS = 5000;\n    /*\n    * elegant shutdown wait seconds\n     */\n    private static final long ELEGANT_SHUTDOWN_WAITING_SECONDS = 10;\n\n    private Thread scheduleThread;\n    private Thread ringThread;\n    private volatile boolean scheduleThreadToStop = false;\n    private volatile boolean ringThreadToStop = false;\n    private final Map<Integer, List<Integer>> ringData = new ConcurrentHashMap<>();\n\n    /**\n     * start\n     */\n    public void start(){\n\n        // schedule thread\n        scheduleThread = new Thread(new Runnable() {\n            @Override\n            public void run() {\n\n                // align time\n                try {\n                    TimeUnit.MILLISECONDS.sleep(5000 - System.currentTimeMillis()%1000 );\n                } catch (Throwable e) {\n                    if (!scheduleThreadToStop) {\n                        logger.error(e.getMessage(), e);\n                    }\n                }\n                logger.info(\">>>>>>>>> init xxl-job admin scheduler success.\");\n\n                // pre-read count: treadpool-size * trigger-qps (each trigger cost 100ms, qps = 1000/100 = 100)\n                int preReadCount = (XxlJobAdminBootstrap.getInstance().getTriggerPoolFastMax() + XxlJobAdminBootstrap.getInstance().getTriggerPoolSlowMax()) * 10;\n\n                // do schedule\n                while (!scheduleThreadToStop) {\n\n                    // param\n                    long start = System.currentTimeMillis();\n                    boolean preReadSuc = true;\n\n                    // transaction start\n                    TransactionStatus transactionStatus = null;\n                    try {\n                        transactionStatus = XxlJobAdminBootstrap.getInstance().getTransactionManager().getTransaction(new DefaultTransactionDefinition());\n                        // 1、job lock\n                        String lockedRecord = XxlJobAdminBootstrap.getInstance().getXxlJobLockMapper().scheduleLock();\n                        long nowTime = System.currentTimeMillis();\n\n                        // scan and process job\n                        List<XxlJobInfo> scheduleList = XxlJobAdminBootstrap.getInstance().getXxlJobInfoMapper().scheduleJobQuery(nowTime + PRE_READ_MS, preReadCount);\n                        if (CollectionTool.isNotEmpty(scheduleList)) {\n\n                            // 2、push time-ring\n                            for (XxlJobInfo jobInfo: scheduleList) {\n\n                                // time-ring jump\n                                if (nowTime > jobInfo.getTriggerNextTime() + PRE_READ_MS) {\n                                    // 2.1、trigger-expire > 5s：pass && make next-trigger-time\n\n                                    // 1、misfire handle\n                                    MisfireStrategyEnum misfireStrategyEnum = MisfireStrategyEnum.match(jobInfo.getMisfireStrategy(), MisfireStrategyEnum.DO_NOTHING);\n                                    misfireStrategyEnum.getMisfireHandler().handle(jobInfo.getId());\n\n                                    // 2、fresh next\n                                    refreshNextTriggerTime(jobInfo, new Date());\n\n                                } else if (nowTime > jobInfo.getTriggerNextTime()) {\n                                    // 2.2、trigger-expire < 5s：direct-trigger && make next-trigger-time\n\n                                    // 1、trigger direct\n                                    XxlJobAdminBootstrap.getInstance().getJobTriggerPoolHelper().trigger(jobInfo.getId(), TriggerTypeEnum.CRON, -1, null, null, null);\n                                    logger.debug(\">>>>>>>>>>> xxl-job, schedule expire, direct trigger : jobId = \" + jobInfo.getId() );\n\n                                    // 2、fresh next\n                                    refreshNextTriggerTime(jobInfo, new Date());\n\n                                    // next-trigger-time in 5s, pre-read again\n                                    if (jobInfo.getTriggerStatus()== TriggerStatus.RUNNING.getValue() && nowTime + PRE_READ_MS > jobInfo.getTriggerNextTime()) {\n\n                                        // 1、make ring second\n                                        int ringSecond = (int)((jobInfo.getTriggerNextTime()/1000)%60);\n\n                                        // 2、push time ring (pre read)\n                                        pushTimeRing(ringSecond, jobInfo.getId());\n                                        logger.debug(\">>>>>>>>>>> xxl-job, schedule pre-read, push trigger : jobId = \" + jobInfo.getId() );\n\n                                        // 3、fresh next\n                                        refreshNextTriggerTime(jobInfo, new Date(jobInfo.getTriggerNextTime()));\n\n                                    }\n\n                                } else {\n                                    // 2.3、trigger-pre-read：time-ring trigger && make next-trigger-time\n\n                                    // 1、make ring second\n                                    int ringSecond = (int)((jobInfo.getTriggerNextTime()/1000)%60);\n\n                                    // 2、push time ring\n                                    pushTimeRing(ringSecond, jobInfo.getId());\n                                    logger.debug(\">>>>>>>>>>> xxl-job, schedule normal, push trigger : jobId = \" + jobInfo.getId() );\n\n                                    // 3、fresh next\n                                    refreshNextTriggerTime(jobInfo, new Date(jobInfo.getTriggerNextTime()));\n\n                                }\n\n                            }\n\n                            // 3、update trigger info\n                            for (XxlJobInfo jobInfo: scheduleList) {\n                                XxlJobAdminBootstrap.getInstance().getXxlJobInfoMapper().scheduleUpdate(jobInfo);\n                            }\n\n                        } else {\n                            preReadSuc = false;\n                        }\n\n                    } catch (Throwable e) {\n                        if (!scheduleThreadToStop) {\n                            logger.error(\">>>>>>>>>>> xxl-job, JobScheduleHelper#scheduleThread error:{}\", e.getMessage(), e);\n                        }\n                    } finally {\n                        // transaction commit\n                        try {\n                            if (transactionStatus != null) {\n                                XxlJobAdminBootstrap.getInstance().getTransactionManager().commit(transactionStatus);   // avlid schedule repeat\n                            }\n                        } catch (Throwable e) {\n                            logger.error(\">>>>>>>>>>> xxl-job, JobScheduleHelper#scheduleThread transaction commit error:{}\", e.getMessage(), e);\n                        }\n                    }\n                    // transaction end\n                    long cost = System.currentTimeMillis()-start;\n\n\n                    // Wait seconds, align second\n                    if (cost < 1000) {  // scan-overtime, not wait\n                        try {\n                            // pre-read period: success > scan each second; fail > skip this period;\n                            TimeUnit.MILLISECONDS.sleep((preReadSuc?1000:PRE_READ_MS) - System.currentTimeMillis()%1000);\n                        } catch (Throwable e) {\n                            if (!scheduleThreadToStop) {\n                                logger.error(e.getMessage(), e);\n                            }\n                        }\n                    }\n\n                }\n\n                logger.info(\">>>>>>>>>>> xxl-job, JobScheduleHelper#scheduleThread stop\");\n            }\n        });\n        scheduleThread.setDaemon(true);\n        scheduleThread.setName(\"xxl-job, admin JobScheduleHelper#scheduleThread\");\n        scheduleThread.start();\n\n\n        // ring thread\n        ringThread = new Thread(new Runnable() {\n            @Override\n            public void run() {\n\n                while (!ringThreadToStop) {\n\n                    // align second\n                    try {\n                        TimeUnit.MILLISECONDS.sleep(1000 - System.currentTimeMillis() % 1000);\n                    } catch (Throwable e) {\n                        if (!ringThreadToStop) {\n                            logger.error(e.getMessage(), e);\n                        }\n                    }\n\n                    try {\n                        // second data\n                        List<Integer> ringItemData = new ArrayList<>();\n\n                        // collect rind data, by second\n                        int nowSecond = Calendar.getInstance().get(Calendar.SECOND);\n                        for (int i = 0; i <= 2; i++) {                                                              // 避免调度遗漏：处理耗时太长、跨过刻度，除当前刻度外 + 向前校验2个刻度；\n                            List<Integer> ringItemList = ringData.remove( (nowSecond+60-i)%60 );\n                            if (CollectionTool.isNotEmpty(ringItemList)) {\n                                // distinct for each second\n                                List<Integer> ringItemListDistinct = ringItemList.stream().distinct().toList();     // 避免调度重复：重复推送时间轮刻度，去重只保留一个；；\n                                if (ringItemListDistinct.size() < ringItemList.size()) {\n                                    logger.warn(\">>>>>>>>>>> xxl-job, time-ring found job repeat beat : \" + nowSecond + \" = \" + ringItemData);\n                                }\n\n                                // collect ring item\n                                ringItemData.addAll(ringItemListDistinct);\n                            }\n                        }\n\n                        // ring trigger\n                        logger.debug(\">>>>>>>>>>> xxl-job, time-ring beat : \" + nowSecond + \" = \" + ringItemData);\n                        if (CollectionTool.isNotEmpty(ringItemData)) {\n                            // do trigger\n                            for (int jobId: ringItemData) {\n                                // do trigger\n                                XxlJobAdminBootstrap.getInstance().getJobTriggerPoolHelper().trigger(jobId, TriggerTypeEnum.CRON, -1, null, null, null);\n                            }\n                            // clear\n                            ringItemData.clear();\n                        }\n                    } catch (Throwable e) {\n                        if (!ringThreadToStop) {\n                            logger.error(\">>>>>>>>>>> xxl-job, JobScheduleHelper#ringThread error:{}\", e.getMessage(), e);\n                        }\n                    }\n                }\n                logger.info(\">>>>>>>>>>> xxl-job, JobScheduleHelper#ringThread stop\");\n            }\n        });\n        ringThread.setDaemon(true);\n        ringThread.setName(\"xxl-job, admin JobScheduleHelper#ringThread\");\n        ringThread.start();\n    }\n\n    /**\n     * refresh next trigger time of job\n     *\n     * @param jobInfo   job info\n     * @param fromTime  from time\n     */\n    private void refreshNextTriggerTime(XxlJobInfo jobInfo, Date fromTime) {\n        try {\n            // generate next trigger time\n            ScheduleTypeEnum scheduleTypeEnum = ScheduleTypeEnum.match(jobInfo.getScheduleType(), ScheduleTypeEnum.NONE);\n            Date nextTriggerTime = scheduleTypeEnum.getScheduleType().generateNextTriggerTime(jobInfo, fromTime);\n\n            // refresh next trigger-time + status\n            if (nextTriggerTime != null) {\n                // generate success\n                jobInfo.setTriggerStatus(-1);                               // pass, may be Inaccurate\n                jobInfo.setTriggerLastTime(jobInfo.getTriggerNextTime());\n                jobInfo.setTriggerNextTime(nextTriggerTime.getTime());\n            } else {\n                // generate fail, stop job\n                jobInfo.setTriggerStatus(TriggerStatus.STOPPED.getValue());\n                jobInfo.setTriggerLastTime(0);\n                jobInfo.setTriggerNextTime(0);\n                logger.error(\">>>>>>>>>>> xxl-job, refreshNextValidTime fail for job: jobId={}, scheduleType={}, scheduleConf={}\",\n                        jobInfo.getId(), jobInfo.getScheduleType(), jobInfo.getScheduleConf());\n            }\n        } catch (Throwable e) {\n            // generate error, stop job\n            jobInfo.setTriggerStatus(TriggerStatus.STOPPED.getValue());\n            jobInfo.setTriggerLastTime(0);\n            jobInfo.setTriggerNextTime(0);\n\n            logger.error(\">>>>>>>>>>> xxl-job, refreshNextValidTime error for job: jobId={}, scheduleType={}, scheduleConf={}\",\n                    jobInfo.getId(), jobInfo.getScheduleType(), jobInfo.getScheduleConf(), e);\n        }\n    }\n\n    /**\n     * push time ring\n     *\n     * @param ringSecond    ring second\n     * @param jobId         job id\n     */\n    private void pushTimeRing(int ringSecond, int jobId){\n        // get ringItemData, init when not exists\n        List<Integer> ringItemList = ringData.computeIfAbsent(\n                ringSecond,\n                k -> new ArrayList<>());\n\n        // push async rind\n        ringItemList.add(jobId);\n        logger.debug(\">>>>>>>>>>> xxl-job, schedule push time-ring : \" + ringSecond + \" = \" + List.of(ringItemList));\n    }\n\n    /**\n     * stop\n     */\n    public void stop(){\n\n        // 1、stop schedule\n        scheduleThreadToStop = true;\n        try {\n            TimeUnit.SECONDS.sleep(1);  // wait\n        } catch (Throwable e) {\n            logger.error(e.getMessage(), e);\n        }\n        if (scheduleThread.getState() != Thread.State.TERMINATED){\n            // interrupt and wait\n            scheduleThread.interrupt();\n            try {\n                scheduleThread.join();\n            } catch (Throwable e) {\n                logger.error(e.getMessage(), e);\n            }\n        }\n\n        // if has ring data, wait for elegent shutdown\n        boolean hasRingData = false;\n        if (MapTool.isNotEmpty(ringData)) {\n            for (int second : ringData.keySet()) {\n                List<Integer> ringItemList = ringData.get(second);\n                if (CollectionTool.isNotEmpty(ringItemList)) {\n                    hasRingData = true;\n                    break;\n                }\n            }\n        }\n        if (hasRingData) {\n            try {\n                TimeUnit.SECONDS.sleep(ELEGANT_SHUTDOWN_WAITING_SECONDS);\n            } catch (Throwable e) {\n                logger.error(e.getMessage(), e);\n            }\n        }\n\n        // stop ring (wait job-in-memory stop)\n        ringThreadToStop = true;\n        try {\n            TimeUnit.SECONDS.sleep(1);\n        } catch (Throwable e) {\n            logger.error(e.getMessage(), e);\n        }\n        if (ringThread.getState() != Thread.State.TERMINATED){\n            // interrupt and wait\n            ringThread.interrupt();\n            try {\n                ringThread.join();\n            } catch (Throwable e) {\n                logger.error(e.getMessage(), e);\n            }\n        }\n\n        logger.info(\">>>>>>>>>>> xxl-job, JobScheduleHelper stop\");\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/thread/JobTriggerPoolHelper.java",
    "content": "package com.xxl.job.admin.scheduler.thread;\n\nimport com.xxl.job.admin.scheduler.config.XxlJobAdminBootstrap;\nimport com.xxl.job.admin.scheduler.trigger.TriggerTypeEnum;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.concurrent.*;\nimport java.util.concurrent.atomic.AtomicInteger;\n\n/**\n * job trigger thread pool helper\n *\n * @author xuxueli 2018-07-03 21:08:07\n */\npublic class JobTriggerPoolHelper {\n    private static final Logger logger = LoggerFactory.getLogger(JobTriggerPoolHelper.class);\n\n\n    // ---------------------- trigger pool ----------------------\n\n    // fast/slow thread pool\n    private ThreadPoolExecutor fastTriggerPool = null;\n    private ThreadPoolExecutor slowTriggerPool = null;\n\n    /**\n     * start\n     */\n    public void start(){\n        fastTriggerPool = new ThreadPoolExecutor(\n                10,\n                XxlJobAdminBootstrap.getInstance().getTriggerPoolFastMax(),\n                60L,\n                TimeUnit.SECONDS,\n                new LinkedBlockingQueue<Runnable>(2000),\n                new ThreadFactory() {\n                    @Override\n                    public Thread newThread(Runnable r) {\n                        return new Thread(r, \"xxl-job, admin JobTriggerPoolHelper-fastTriggerPool-\" + r.hashCode());\n                    }\n                },\n                new RejectedExecutionHandler() {\n                    @Override\n                    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {\n                        logger.error(\">>>>>>>>>>> xxl-job, admin JobTriggerPoolHelper-fastTriggerPool execute too fast, Runnable=\"+r.toString() );\n                    }\n                });\n\n        slowTriggerPool = new ThreadPoolExecutor(\n                10,\n                XxlJobAdminBootstrap.getInstance().getTriggerPoolSlowMax(),\n                60L,\n                TimeUnit.SECONDS,\n                new LinkedBlockingQueue<Runnable>(5000),\n                new ThreadFactory() {\n                    @Override\n                    public Thread newThread(Runnable r) {\n                        return new Thread(r, \"xxl-job, admin JobTriggerPoolHelper-slowTriggerPool-\" + r.hashCode());\n                    }\n                },\n                new RejectedExecutionHandler() {\n                    @Override\n                    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {\n                        logger.error(\">>>>>>>>>>> xxl-job, admin JobTriggerPoolHelper-slowTriggerPool execute too fast, Runnable=\"+r.toString() );\n                    }\n                });\n    }\n\n    /**\n     * stop\n     */\n    public void stop() {\n        //triggerPool.shutdown();\n        fastTriggerPool.shutdownNow();\n        slowTriggerPool.shutdownNow();\n        logger.info(\">>>>>>>>> xxl-job trigger thread pool shutdown success.\");\n    }\n\n\n    // job timeout count\n    private volatile long minTim = System.currentTimeMillis()/60000;     // ms > min\n    private volatile ConcurrentMap<Integer, AtomicInteger> jobTimeoutCountMap = new ConcurrentHashMap<>();\n\n\n    // ---------------------- tool ----------------------\n\n    /**\n     * trigger job\n     *\n     * @param jobId\n     * @param triggerType\n     * @param failRetryCount\n     * \t\t\t>=0: use this param\n     * \t\t\t<0: use param from job info config\n     * @param executorShardingParam\n     * @param executorParam\n     *          null: use job param\n     *          not null: cover job param\n     */\n    public void trigger(final int jobId,\n                        final TriggerTypeEnum triggerType,\n                        final int failRetryCount,\n                        final String executorShardingParam,\n                        final String executorParam,\n                        final String addressList) {\n\n        // choose thread pool\n        ThreadPoolExecutor triggerPool_ = fastTriggerPool;\n        AtomicInteger jobTimeoutCount = jobTimeoutCountMap.get(jobId);\n        if (jobTimeoutCount!=null && jobTimeoutCount.get() > 10) {      // job-timeout 10 times in 1 min\n            triggerPool_ = slowTriggerPool;\n        }\n\n        // trigger\n        triggerPool_.execute(new Runnable() {\n            @Override\n            public void run() {\n\n                long start = System.currentTimeMillis();\n\n                try {\n                    // do trigger\n                    XxlJobAdminBootstrap.getInstance().getJobTrigger().trigger(jobId, triggerType, failRetryCount, executorShardingParam, executorParam, addressList);\n                } catch (Throwable e) {\n                    logger.error(e.getMessage(), e);\n                } finally {\n\n                    // check timeout-count-map\n                    long minTim_now = System.currentTimeMillis()/60000;\n                    if (minTim != minTim_now) {\n                        minTim = minTim_now;\n                        jobTimeoutCountMap.clear();\n                    }\n\n                    // incr timeout-count-map\n                    long cost = System.currentTimeMillis()-start;\n                    if (cost > 500) {       // ob-timeout threshold 500ms\n                        AtomicInteger timeoutCount = jobTimeoutCountMap.putIfAbsent(jobId, new AtomicInteger(1));\n                        if (timeoutCount != null) {\n                            timeoutCount.incrementAndGet();\n                        }\n                    }\n\n                }\n\n            }\n            @Override\n            public String toString() {\n                return \"Job Runnable, jobId:\"+jobId;\n            }\n        });\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/trigger/JobTrigger.java",
    "content": "package com.xxl.job.admin.scheduler.trigger;\n\nimport com.xxl.job.admin.mapper.XxlJobGroupMapper;\nimport com.xxl.job.admin.mapper.XxlJobInfoMapper;\nimport com.xxl.job.admin.mapper.XxlJobLogMapper;\nimport com.xxl.job.admin.model.XxlJobGroup;\nimport com.xxl.job.admin.model.XxlJobInfo;\nimport com.xxl.job.admin.model.XxlJobLog;\nimport com.xxl.job.admin.scheduler.config.XxlJobAdminBootstrap;\nimport com.xxl.job.admin.scheduler.route.ExecutorRouteStrategyEnum;\nimport com.xxl.job.admin.util.I18nUtil;\nimport com.xxl.job.core.constant.ExecutorBlockStrategyEnum;\nimport com.xxl.job.core.context.XxlJobContext;\nimport com.xxl.job.core.openapi.ExecutorBiz;\nimport com.xxl.job.core.openapi.model.TriggerRequest;\nimport com.xxl.tool.core.StringTool;\nimport com.xxl.tool.error.ThrowableTool;\nimport com.xxl.tool.http.IPTool;\nimport com.xxl.tool.response.Response;\nimport jakarta.annotation.Resource;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.stereotype.Component;\n\nimport java.util.Date;\n\n/**\n * xxl-job trigger\n *\n * @author xuxueli 17/7/13.\n */\n@Component\npublic class JobTrigger {\n    private static final Logger logger = LoggerFactory.getLogger(JobTrigger.class);\n\n\n    @Resource\n    private XxlJobInfoMapper xxlJobInfoMapper;\n    @Resource\n    private XxlJobGroupMapper xxlJobGroupMapper;\n    @Resource\n    private XxlJobLogMapper xxlJobLogMapper;\n\n\n    /**\n     * trigger job\n     *\n     * @param jobId\n     * @param triggerType\n     * @param failRetryCount\n     * \t\t\t>=0: use this param\n     * \t\t\t<0: use param from job info config\n     * @param executorShardingParam\n     *          null: new sharding, all nodes\n     *          not null: for retry, only one node\n     * @param executorParam\n     *          null: use job param\n     *          not null: cover job param\n     * @param addressList\n     *          null: use executor addressList\n     *          not null: cover\n     */\n    public void trigger(int jobId,\n                               TriggerTypeEnum triggerType,\n                               int failRetryCount,\n                               String executorShardingParam,\n                               String executorParam,\n                               String addressList) {\n\n        // load data\n        XxlJobInfo jobInfo = xxlJobInfoMapper.loadById(jobId);\n        if (jobInfo == null) {\n            logger.warn(\">>>>>>>>>>>> trigger fail, jobId invalid，jobId={}\", jobId);\n            return;\n        }\n        if (executorParam != null) {\n            jobInfo.setExecutorParam(executorParam);\n        }\n        int finalFailRetryCount = failRetryCount>=0?failRetryCount:jobInfo.getExecutorFailRetryCount();\n        XxlJobGroup group = xxlJobGroupMapper.load(jobInfo.getJobGroup());\n\n        // cover addressList\n        if (StringTool.isNotBlank(addressList)) {\n            group.setAddressType(1);\n            group.setAddressList(addressList.trim());\n        }\n\n        // sharding param\n        int[] shardingParam = null;\n        Date triggerTime = new Date();\n        if (executorShardingParam!=null){\n            String[] shardingArr = executorShardingParam.split(\"/\");\n            if (shardingArr.length==2 && StringTool.isNumeric(shardingArr[0]) && StringTool.isNumeric(shardingArr[1])) {\n                shardingParam = new int[2];\n                shardingParam[0] = Integer.parseInt(shardingArr[0]);\n                shardingParam[1] = Integer.parseInt(shardingArr[1]);\n            }\n        }\n        if (ExecutorRouteStrategyEnum.SHARDING_BROADCAST==ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null)\n                && group.getRegistryList()!=null && !group.getRegistryList().isEmpty()\n                && shardingParam==null) {\n            for (int i = 0; i < group.getRegistryList().size(); i++) {\n                processTrigger(group, jobInfo, finalFailRetryCount, triggerType, triggerTime, i, group.getRegistryList().size());\n            }\n        } else {\n            if (shardingParam == null) {\n                shardingParam = new int[]{0, 1};\n            }\n            processTrigger(group, jobInfo, finalFailRetryCount, triggerType, triggerTime, shardingParam[0], shardingParam[1]);\n        }\n\n    }\n\n    /*private static boolean isNumeric(String str){\n        try {\n            int result = Integer.valueOf(str);\n            return true;\n        } catch (NumberFormatException e) {\n            return false;\n        }\n    }*/\n\n    /**\n     * process trigger with log\n     *\n     * @param group                     job group, registry list may be empty\n     * @param jobInfo                   job info\n     * @param finalFailRetryCount       the fail-retry count\n     * @param triggerType               trigger type\n     * @param triggerTime               trigger time\n     * @param index                     sharding index\n     * @param total                     sharding index\n     */\n    private void processTrigger(XxlJobGroup group,\n                                XxlJobInfo jobInfo,\n                                int finalFailRetryCount,\n                                TriggerTypeEnum triggerType,\n                                Date triggerTime,\n                                int index,\n                                int total){\n\n        // param\n        ExecutorBlockStrategyEnum blockStrategy = ExecutorBlockStrategyEnum.match(jobInfo.getExecutorBlockStrategy(), ExecutorBlockStrategyEnum.SERIAL_EXECUTION);  // block strategy\n        ExecutorRouteStrategyEnum executorRouteStrategyEnum = ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null);    // route strategy\n        String shardingParam = (ExecutorRouteStrategyEnum.SHARDING_BROADCAST==executorRouteStrategyEnum)?String.valueOf(index).concat(\"/\").concat(String.valueOf(total)):null;\n\n        // 1、save log-id\n        XxlJobLog jobLog = new XxlJobLog();\n        jobLog.setJobGroup(jobInfo.getJobGroup());\n        jobLog.setJobId(jobInfo.getId());\n        jobLog.setTriggerTime(triggerTime);\n        xxlJobLogMapper.save(jobLog);\n        logger.debug(\">>>>>>>>>>> xxl-job trigger start, jobId:{}\", jobLog.getId());\n\n        // 2、init trigger-param\n        TriggerRequest triggerParam = new TriggerRequest();\n        triggerParam.setJobId(jobInfo.getId());\n        triggerParam.setExecutorHandler(jobInfo.getExecutorHandler());\n        triggerParam.setExecutorParams(jobInfo.getExecutorParam());\n        triggerParam.setExecutorBlockStrategy(jobInfo.getExecutorBlockStrategy());\n        triggerParam.setExecutorTimeout(jobInfo.getExecutorTimeout());\n        triggerParam.setLogId(jobLog.getId());\n        triggerParam.setLogDateTime(jobLog.getTriggerTime().getTime());\n        triggerParam.setGlueType(jobInfo.getGlueType());\n        triggerParam.setGlueSource(jobInfo.getGlueSource());\n        triggerParam.setGlueUpdatetime(jobInfo.getGlueUpdatetime().getTime());\n        triggerParam.setBroadcastIndex(index);\n        triggerParam.setBroadcastTotal(total);\n\n        // 3、init address\n        String address = null;\n        Response<String> routeAddressResult = null;\n        if (group.getRegistryList()!=null && !group.getRegistryList().isEmpty()) {\n            if (ExecutorRouteStrategyEnum.SHARDING_BROADCAST == executorRouteStrategyEnum) {\n                if (index < group.getRegistryList().size()) {\n                    address = group.getRegistryList().get(index);\n                } else {\n                    address = group.getRegistryList().get(0);\n                }\n            } else {\n                routeAddressResult = executorRouteStrategyEnum.getRouter().route(triggerParam, group.getRegistryList());\n                if (routeAddressResult.isSuccess()) {\n                    address = routeAddressResult.getData();\n                }\n            }\n        } else {\n            routeAddressResult = Response.of(XxlJobContext.HANDLE_CODE_FAIL, I18nUtil.getString(\"jobconf_trigger_address_empty\"));\n        }\n\n        // 4、trigger remote executor\n        Response<String> triggerResult = null;\n        if (address != null) {\n            triggerResult = doTrigger(triggerParam, address);\n        } else {\n            triggerResult = Response.of(XxlJobContext.HANDLE_CODE_FAIL, \"Address Router Fail.\");\n        }\n\n        // 5、collection trigger info\n        // trigger config\n        StringBuilder triggerMsgSb = new StringBuilder();\n        triggerMsgSb.append(I18nUtil.getString(\"jobconf_trigger_type\")).append(\"：\").append(triggerType.getTitle());\n        triggerMsgSb.append(\"<br>\").append(I18nUtil.getString(\"jobconf_trigger_admin_adress\")).append(\"：\").append(IPTool.getIp());\n        triggerMsgSb.append(\"<br>\").append(I18nUtil.getString(\"jobconf_trigger_exe_regtype\")).append(\"：\")\n                .append( (group.getAddressType() == 0)?I18nUtil.getString(\"jobgroup_field_addressType_0\"):I18nUtil.getString(\"jobgroup_field_addressType_1\") );\n        triggerMsgSb.append(\"<br>\").append(I18nUtil.getString(\"jobconf_trigger_exe_regaddress\")).append(\"：\").append(group.getRegistryList());\n        triggerMsgSb.append(\"<br>\").append(I18nUtil.getString(\"jobinfo_field_executorRouteStrategy\")).append(\"：\").append(executorRouteStrategyEnum.getTitle());\n        if (shardingParam != null) {\n            triggerMsgSb.append(\"(\").append(shardingParam).append(\")\");\n        }\n        triggerMsgSb.append(\"<br>\").append(I18nUtil.getString(\"jobinfo_field_executorBlockStrategy\")).append(\"：\").append(blockStrategy.getTitle());\n        triggerMsgSb.append(\"<br>\").append(I18nUtil.getString(\"jobinfo_field_timeout\")).append(\"：\").append(jobInfo.getExecutorTimeout());\n        triggerMsgSb.append(\"<br>\").append(I18nUtil.getString(\"jobinfo_field_executorFailRetryCount\")).append(\"：\").append(finalFailRetryCount);\n\n        // trigger data\n        triggerMsgSb.append(\"<br><br><span style=\\\"color:#00c0ef;\\\" > >>>>>>>>>>>\").append(I18nUtil.getString(\"jobconf_trigger_run\")).append(\"<<<<<<<<<<< </span><br>\");\n        triggerMsgSb.append(\"<br>\").append(I18nUtil.getString(\"joblog_field_executorAddress\")).append(\"：\");\n        if (StringTool.isNotBlank(address)) {\n            triggerMsgSb.append(address);\n        } else if (routeAddressResult!=null && !routeAddressResult.isSuccess() && routeAddressResult.getMsg()!=null) {\n            triggerMsgSb.append(\"address route fail, \").append(routeAddressResult.getMsg());\n        } else {\n            triggerMsgSb.append(\"address route fail.\");\n        }\n        if (StringTool.isNotBlank(jobInfo.getExecutorHandler())) {\n            triggerMsgSb.append(\"<br>\").append(\"JobHandler\").append(\"：\").append(jobInfo.getExecutorHandler());\n        }\n        triggerMsgSb.append(\"<br>\").append(I18nUtil.getString(\"jobinfo_field_executorparam\")).append(\"：\").append(jobInfo.getExecutorParam());\n        triggerMsgSb.append(\"<br>\").append(I18nUtil.getString(\"joblog_field_triggerMsg\")).append(\"：\");\n        if (triggerResult.isSuccess()) {\n            triggerMsgSb.append(\"success\");\n        } else if (triggerResult.getMsg()!=null) {\n            triggerMsgSb.append(\"error, \").append(triggerResult.getMsg());\n        } else {\n            triggerMsgSb.append(\"fail\");\n        }\n\n        // 6、save log trigger-info\n        jobLog.setExecutorAddress(address);\n        jobLog.setExecutorHandler(jobInfo.getExecutorHandler());\n        jobLog.setExecutorParam(jobInfo.getExecutorParam());\n        jobLog.setExecutorShardingParam(shardingParam);\n        jobLog.setExecutorFailRetryCount(finalFailRetryCount);\n        //jobLog.setTriggerTime();\n        jobLog.setTriggerCode(triggerResult.getCode());\n        jobLog.setTriggerMsg(triggerMsgSb.toString());\n        xxlJobLogMapper.updateTriggerInfo(jobLog);\n\n        logger.debug(\">>>>>>>>>>> xxl-job trigger end, jobId:{}\", jobLog.getId());\n    }\n\n    /**\n     * do trigger with address\n     *\n     * @param triggerParam  trigger param\n     * @param address       the address\n     * @return return\n     */\n    private Response<String> doTrigger(TriggerRequest triggerParam, String address){\n        try {\n            // build client\n            ExecutorBiz executorBiz = XxlJobAdminBootstrap.getExecutorBiz(address);\n\n            // invoke\n            Response<String> runResult = executorBiz.run(triggerParam);\n\n            // build result\n            StringBuffer runResultSB = new StringBuffer(I18nUtil.getString(\"jobconf_trigger_run\") + \"：\");\n            runResultSB.append(\"<br>address：\").append(address);\n            runResultSB.append(\"<br>code：\").append(runResult.getCode());\n            runResultSB.append(\"<br>msg：\").append(runResult.getMsg());\n\n            // return\n            runResult.setMsg(runResultSB.toString());\n            return runResult;\n        } catch (Exception e) {\n            logger.error(\">>>>>>>>>>> xxl-job trigger error, please check if the executor[{}] is running.\", address, e);\n            return Response.of(XxlJobContext.HANDLE_CODE_FAIL, ThrowableTool.toString(e));\n        }\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/trigger/TriggerTypeEnum.java",
    "content": "package com.xxl.job.admin.scheduler.trigger;\n\nimport com.xxl.job.admin.util.I18nUtil;\n\n/**\n * trigger type enum\n *\n * @author xuxueli 2018-09-16 04:56:41\n */\npublic enum TriggerTypeEnum {\n\n    MANUAL(I18nUtil.getString(\"jobconf_trigger_type_manual\")),\n    CRON(I18nUtil.getString(\"jobconf_trigger_type_cron\")),\n    RETRY(I18nUtil.getString(\"jobconf_trigger_type_retry\")),\n    PARENT(I18nUtil.getString(\"jobconf_trigger_type_parent\")),\n    API(I18nUtil.getString(\"jobconf_trigger_type_api\")),\n    MISFIRE(I18nUtil.getString(\"jobconf_trigger_type_misfire\"));\n\n    private TriggerTypeEnum(String title){\n        this.title = title;\n    }\n    private String title;\n    public String getTitle() {\n        return title;\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/type/ScheduleType.java",
    "content": "package com.xxl.job.admin.scheduler.type;\n\nimport com.xxl.job.admin.model.XxlJobInfo;\n\nimport java.util.Date;\n\n/**\n * Schedule Type\n *\n * @author xuxueli 2020-10-29\n */\npublic abstract class ScheduleType {\n\n    /**\n     * generate next trigger time\n     *\n     * @param jobInfo       job info\n     * @param fromTime      from time\n     */\n    public abstract Date generateNextTriggerTime(XxlJobInfo jobInfo, Date fromTime) throws Exception;\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/type/ScheduleTypeEnum.java",
    "content": "package com.xxl.job.admin.scheduler.type;\n\nimport com.xxl.job.admin.scheduler.type.strategy.CronScheduleType;\nimport com.xxl.job.admin.scheduler.type.strategy.FixRateScheduleType;\nimport com.xxl.job.admin.scheduler.type.strategy.NoneScheduleType;\nimport com.xxl.job.admin.util.I18nUtil;\n\n/**\n * @author xuxueli 2020-10-29 21:11:23\n */\npublic enum ScheduleTypeEnum {\n\n    NONE(I18nUtil.getString(\"schedule_type_none\"), new NoneScheduleType()),\n\n    /**\n     * schedule by cron\n     */\n    CRON(I18nUtil.getString(\"schedule_type_cron\"), new CronScheduleType()),\n\n    /**\n     * schedule by fixed rate (in seconds)\n     */\n    FIX_RATE(I18nUtil.getString(\"schedule_type_fix_rate\"), new FixRateScheduleType()),\n\n    /**\n     * schedule by fix delay (in seconds)， after the last time\n     */\n    /*FIX_DELAY(I18nUtil.getString(\"schedule_type_fix_delay\"))*/;\n\n    private final String title;\n    private final ScheduleType scheduleType;;\n\n    ScheduleTypeEnum(String title, ScheduleType scheduleType) {\n        this.title = title;\n        this.scheduleType = scheduleType;\n    }\n\n    public String getTitle() {\n        return title;\n    }\n\n    public ScheduleType getScheduleType() {\n        return scheduleType;\n    }\n\n    /**\n     * match by name\n     *\n     * @param name          name of ScheduleTypeEnum\n     * @param defaultItem   default item\n     * @return ScheduleTypeEnum\n     */\n    public static ScheduleTypeEnum match(String name, ScheduleTypeEnum defaultItem){\n        for (ScheduleTypeEnum item: ScheduleTypeEnum.values()) {\n            if (item.name().equals(name)) {\n                return item;\n            }\n        }\n        return defaultItem;\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/type/strategy/CronScheduleType.java",
    "content": "package com.xxl.job.admin.scheduler.type.strategy;\n\nimport com.xxl.job.admin.model.XxlJobInfo;\nimport com.xxl.job.admin.scheduler.cron.CronExpression;\nimport com.xxl.job.admin.scheduler.type.ScheduleType;\n\nimport java.util.Date;\n\npublic class CronScheduleType extends ScheduleType {\n\n    @Override\n    public Date generateNextTriggerTime(XxlJobInfo jobInfo, Date fromTime) throws Exception {\n        // generate next trigger time, with cron\n        return new CronExpression(jobInfo.getScheduleConf()).getNextValidTimeAfter(fromTime);\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/type/strategy/FixRateScheduleType.java",
    "content": "package com.xxl.job.admin.scheduler.type.strategy;\n\nimport com.xxl.job.admin.model.XxlJobInfo;\nimport com.xxl.job.admin.scheduler.type.ScheduleType;\n\nimport java.util.Date;\n\npublic class FixRateScheduleType extends ScheduleType {\n\n    @Override\n    public Date generateNextTriggerTime(XxlJobInfo jobInfo, Date fromTime) throws Exception {\n        // generate next trigger time, fix rate delay\n        return new Date(fromTime.getTime() + Long.parseLong(jobInfo.getScheduleConf()) * 1000L);\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/type/strategy/NoneScheduleType.java",
    "content": "package com.xxl.job.admin.scheduler.type.strategy;\n\nimport com.xxl.job.admin.model.XxlJobInfo;\nimport com.xxl.job.admin.scheduler.type.ScheduleType;\n\nimport java.util.Date;\n\npublic class NoneScheduleType extends ScheduleType {\n\n    @Override\n    public Date generateNextTriggerTime(XxlJobInfo jobInfo, Date fromTime) throws Exception {\n        // generate none trigger-time\n        return null;\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/service/XxlJobService.java",
    "content": "package com.xxl.job.admin.service;\n\nimport com.xxl.job.admin.model.XxlJobInfo;\nimport com.xxl.sso.core.model.LoginInfo;\nimport com.xxl.tool.response.PageModel;\nimport com.xxl.tool.response.Response;\n\nimport java.util.Date;\nimport java.util.Map;\n\n/**\n * core job action for xxl-job\n * \n * @author xuxueli 2016-5-28 15:30:33\n */\npublic interface XxlJobService {\n\n\t/**\n\t * page list\n\t */\n\tpublic Response<PageModel<XxlJobInfo>> pageList(int offset, int pagesize, int jobGroup, int triggerStatus, String jobDesc, String executorHandler, String author);\n\n\t/**\n\t * add job\n\t */\n\tpublic Response<String> add(XxlJobInfo jobInfo, LoginInfo loginInfo);\n\n\t/**\n\t * update job\n\t */\n\tpublic Response<String> update(XxlJobInfo jobInfo, LoginInfo loginInfo);\n\n\t/**\n\t * remove job\n\t */\n\tpublic Response<String> remove(int id, LoginInfo loginInfo);\n\n\t/**\n\t * start job\n\t */\n\tpublic Response<String> start(int id, LoginInfo loginInfo);\n\n\t/**\n\t * stop job\n\t */\n\tpublic Response<String> stop(int id, LoginInfo loginInfo);\n\n\t/**\n\t * trigger\n\t */\n\tpublic Response<String> trigger(LoginInfo loginInfo, int jobId, String executorParam, String addressList);\n\n\t/**\n\t * dashboard info\n\t */\n\tpublic Map<String,Object> dashboardInfo();\n\n\t/**\n\t * chart info\n\t */\n\tpublic Response<Map<String,Object>> chartInfo(Date startDate, Date endDate);\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/AdminBizImpl.java",
    "content": "package com.xxl.job.admin.service.impl;\n\nimport com.xxl.job.admin.scheduler.config.XxlJobAdminBootstrap;\nimport com.xxl.job.core.openapi.AdminBiz;\nimport com.xxl.job.core.openapi.model.CallbackRequest;\nimport com.xxl.job.core.openapi.model.RegistryRequest;\nimport com.xxl.tool.response.Response;\nimport org.springframework.stereotype.Service;\n\nimport java.util.List;\n\n/**\n * @author xuxueli 2017-07-27 21:54:20\n */\n@Service\npublic class AdminBizImpl implements AdminBiz {\n\n    @Override\n    public Response<String> callback(List<CallbackRequest> callbackRequestList) {\n        return XxlJobAdminBootstrap.getInstance().getJobCompleteHelper().callback(callbackRequestList);\n    }\n\n    @Override\n    public Response<String> registry(RegistryRequest registryRequest) {\n        return XxlJobAdminBootstrap.getInstance().getJobRegistryHelper().registry(registryRequest);\n    }\n\n    @Override\n    public Response<String> registryRemove(RegistryRequest registryRequest) {\n        return XxlJobAdminBootstrap.getInstance().getJobRegistryHelper().registryRemove(registryRequest);\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/XxlJobServiceImpl.java",
    "content": "package com.xxl.job.admin.service.impl;\n\nimport com.xxl.job.admin.constant.TriggerStatus;\nimport com.xxl.job.admin.mapper.*;\nimport com.xxl.job.admin.model.XxlJobGroup;\nimport com.xxl.job.admin.model.XxlJobInfo;\nimport com.xxl.job.admin.model.XxlJobLogReport;\nimport com.xxl.job.admin.scheduler.config.XxlJobAdminBootstrap;\nimport com.xxl.job.admin.scheduler.cron.CronExpression;\nimport com.xxl.job.admin.scheduler.misfire.MisfireStrategyEnum;\nimport com.xxl.job.admin.scheduler.route.ExecutorRouteStrategyEnum;\nimport com.xxl.job.admin.scheduler.thread.JobScheduleHelper;\nimport com.xxl.job.admin.scheduler.trigger.TriggerTypeEnum;\nimport com.xxl.job.admin.scheduler.type.ScheduleTypeEnum;\nimport com.xxl.job.admin.service.XxlJobService;\nimport com.xxl.job.admin.util.I18nUtil;\nimport com.xxl.job.admin.util.JobGroupPermissionUtil;\nimport com.xxl.job.core.constant.ExecutorBlockStrategyEnum;\nimport com.xxl.job.core.glue.GlueTypeEnum;\nimport com.xxl.sso.core.model.LoginInfo;\nimport com.xxl.tool.core.DateTool;\nimport com.xxl.tool.core.StringTool;\nimport com.xxl.tool.json.GsonTool;\nimport com.xxl.tool.response.PageModel;\nimport com.xxl.tool.response.Response;\nimport jakarta.annotation.Resource;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.stereotype.Service;\n\nimport java.text.MessageFormat;\nimport java.util.*;\n\n/**\n * core job action for xxl-job\n * @author xuxueli 2016-5-28 15:30:33\n */\n@Service\npublic class XxlJobServiceImpl implements XxlJobService {\n\tprivate static Logger logger = LoggerFactory.getLogger(XxlJobServiceImpl.class);\n\n\t@Resource\n\tprivate XxlJobGroupMapper xxlJobGroupMapper;\n\t@Resource\n\tprivate XxlJobInfoMapper xxlJobInfoMapper;\n\t@Resource\n\tpublic XxlJobLogMapper xxlJobLogMapper;\n\t@Resource\n\tprivate XxlJobLogGlueMapper xxlJobLogGlueMapper;\n\t@Resource\n\tprivate XxlJobLogReportMapper xxlJobLogReportMapper;\n\t\n\t@Override\n\tpublic Response<PageModel<XxlJobInfo>> pageList(int offset, int pagesize, int jobGroup, int triggerStatus, String jobDesc, String executorHandler, String author) {\n\n\t\t// page list\n\t\tList<XxlJobInfo> list = xxlJobInfoMapper.pageList(offset, pagesize, jobGroup, triggerStatus, jobDesc, executorHandler, author);\n\t\tint list_count = xxlJobInfoMapper.pageListCount(offset, pagesize, jobGroup, triggerStatus, jobDesc, executorHandler, author);\n\n\t\t// package result\n\t\tPageModel<XxlJobInfo> pageModel = new PageModel<>();\n\t\tpageModel.setData(list);\n\t\tpageModel.setTotal(list_count);\n\n\t\treturn Response.ofSuccess(pageModel);\n\t}\n\n\t@Override\n\tpublic Response<String> add(XxlJobInfo jobInfo, LoginInfo loginInfo) {\n\n\t\t// valid base\n\t\tXxlJobGroup group = xxlJobGroupMapper.load(jobInfo.getJobGroup());\n\t\tif (group == null) {\n\t\t\treturn Response.ofFail (I18nUtil.getString(\"system_please_choose\")+I18nUtil.getString(\"jobinfo_field_jobgroup\"));\n\t\t}\n\t\tif (StringTool.isBlank(jobInfo.getJobDesc())) {\n\t\t\treturn Response.ofFail ( (I18nUtil.getString(\"system_please_input\")+I18nUtil.getString(\"jobinfo_field_jobdesc\")) );\n\t\t}\n\t\tif (StringTool.isBlank(jobInfo.getAuthor())) {\n\t\t\treturn Response.ofFail ( (I18nUtil.getString(\"system_please_input\")+I18nUtil.getString(\"jobinfo_field_author\")) );\n\t\t}\n\n\t\t// valid trigger\n\t\tScheduleTypeEnum scheduleTypeEnum = ScheduleTypeEnum.match(jobInfo.getScheduleType(), null);\n\t\tif (scheduleTypeEnum == null) {\n\t\t\treturn Response.ofFail ( (I18nUtil.getString(\"schedule_type\")+I18nUtil.getString(\"system_unvalid\")) );\n\t\t}\n\t\tif (scheduleTypeEnum == ScheduleTypeEnum.CRON) {\n\t\t\tif (jobInfo.getScheduleConf()==null || !CronExpression.isValidExpression(jobInfo.getScheduleConf())) {\n\t\t\t\treturn Response.ofFail ( \"Cron\"+I18nUtil.getString(\"system_unvalid\"));\n\t\t\t}\n\t\t} else if (scheduleTypeEnum == ScheduleTypeEnum.FIX_RATE/* || scheduleTypeEnum == ScheduleTypeEnum.FIX_DELAY*/) {\n\t\t\tif (jobInfo.getScheduleConf() == null) {\n\t\t\t\treturn Response.ofFail ( (I18nUtil.getString(\"schedule_type\")) );\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tint fixSecond = Integer.parseInt(jobInfo.getScheduleConf());\n\t\t\t\tif (fixSecond < 1) {\n\t\t\t\t\treturn Response.ofFail ( (I18nUtil.getString(\"schedule_type\")+I18nUtil.getString(\"system_unvalid\")) );\n\t\t\t\t}\n\t\t\t} catch (Exception e) {\n\t\t\t\treturn Response.ofFail ( (I18nUtil.getString(\"schedule_type\")+I18nUtil.getString(\"system_unvalid\")) );\n\t\t\t}\n\t\t}\n\n\t\t// valid job\n\t\tif (GlueTypeEnum.match(jobInfo.getGlueType()) == null) {\n\t\t\treturn Response.ofFail ( (I18nUtil.getString(\"jobinfo_field_gluetype\")+I18nUtil.getString(\"system_unvalid\")) );\n\t\t}\n\t\tif (GlueTypeEnum.BEAN==GlueTypeEnum.match(jobInfo.getGlueType()) && StringTool.isBlank(jobInfo.getExecutorHandler()) ) {\n\t\t\treturn Response.ofFail ( (I18nUtil.getString(\"system_please_input\")+\"JobHandler\") );\n\t\t}\n\t\t// 》fix \"\\r\" in shell\n\t\tif (GlueTypeEnum.GLUE_SHELL==GlueTypeEnum.match(jobInfo.getGlueType()) && jobInfo.getGlueSource()!=null) {\n\t\t\tjobInfo.setGlueSource(jobInfo.getGlueSource().replaceAll(\"\\r\", \"\"));\n\t\t}\n\n\t\t// valid advanced\n\t\tif (ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null) == null) {\n\t\t\treturn Response.ofFail ( (I18nUtil.getString(\"jobinfo_field_executorRouteStrategy\")+I18nUtil.getString(\"system_unvalid\")) );\n\t\t}\n\t\tif (MisfireStrategyEnum.match(jobInfo.getMisfireStrategy(), null) == null) {\n\t\t\treturn Response.ofFail ( (I18nUtil.getString(\"misfire_strategy\")+I18nUtil.getString(\"system_unvalid\")) );\n\t\t}\n\t\tif (ExecutorBlockStrategyEnum.match(jobInfo.getExecutorBlockStrategy(), null) == null) {\n\t\t\treturn Response.ofFail ( (I18nUtil.getString(\"jobinfo_field_executorBlockStrategy\")+I18nUtil.getString(\"system_unvalid\")) );\n\t\t}\n\n\t\t// 》ChildJobId valid\n\t\tif (StringTool.isNotBlank(jobInfo.getChildJobId())) {\n\t\t\tString[] childJobIds = jobInfo.getChildJobId().split(\",\");\n\t\t\tfor (String childJobIdItem: childJobIds) {\n\t\t\t\tif (StringTool.isNotBlank(childJobIdItem) && StringTool.isNumeric(childJobIdItem)) {\n\t\t\t\t\tXxlJobInfo childJobInfo = xxlJobInfoMapper.loadById(Integer.parseInt(childJobIdItem));\n\t\t\t\t\tif (childJobInfo==null) {\n\t\t\t\t\t\treturn Response.ofFail (\n\t\t\t\t\t\t\t\tMessageFormat.format((I18nUtil.getString(\"jobinfo_field_childJobId\")+\"({0})\"+I18nUtil.getString(\"system_not_found\")), childJobIdItem));\n\t\t\t\t\t}\n\t\t\t\t\t// valid jobGroup permission\n\t\t\t\t\tif (!JobGroupPermissionUtil.hasJobGroupPermission(loginInfo, childJobInfo.getJobGroup())) {\n\t\t\t\t\t\treturn Response.ofFail (\n\t\t\t\t\t\t\t\tMessageFormat.format((I18nUtil.getString(\"jobinfo_field_childJobId\")+\"({0})\"+I18nUtil.getString(\"system_permission_limit\")), childJobIdItem));\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\treturn Response.ofFail (\n\t\t\t\t\t\t\tMessageFormat.format((I18nUtil.getString(\"jobinfo_field_childJobId\")+\"({0})\"+I18nUtil.getString(\"system_unvalid\")), childJobIdItem));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// join , avoid \"xxx,,\"\n\t\t\tString temp = \"\";\n\t\t\tfor (String item:childJobIds) {\n\t\t\t\ttemp += item + \",\";\n\t\t\t}\n\t\t\ttemp = temp.substring(0, temp.length()-1);\n\n\t\t\tjobInfo.setChildJobId(temp);\n\t\t}\n\n\t\t// add in db\n\t\tjobInfo.setAddTime(new Date());\n\t\tjobInfo.setUpdateTime(new Date());\n\t\tjobInfo.setGlueUpdatetime(new Date());\n\t\t// remove the whitespace\n\t\tjobInfo.setExecutorHandler(jobInfo.getExecutorHandler().trim());\n\t\txxlJobInfoMapper.save(jobInfo);\n\t\tif (jobInfo.getId() < 1) {\n\t\t\treturn Response.ofFail ( (I18nUtil.getString(\"jobinfo_field_add\")+I18nUtil.getString(\"system_fail\")) );\n\t\t}\n\n\t\t// write operation log\n\t\tlogger.info(\">>>>>>>>>>> xxl-job operation log: operator = {}, type = {}, content = {}\",\n\t\t\t\tloginInfo.getUserName(), \"jobinfo-save\", GsonTool.toJson(jobInfo));\n\n\t\treturn Response.ofSuccess(String.valueOf(jobInfo.getId()));\n\t}\n\n\t@Override\n\tpublic Response<String> update(XxlJobInfo jobInfo, LoginInfo loginInfo) {\n\n\t\t// valid base\n\t\tif (StringTool.isBlank(jobInfo.getJobDesc())) {\n\t\t\treturn Response.ofFail ( (I18nUtil.getString(\"system_please_input\")+I18nUtil.getString(\"jobinfo_field_jobdesc\")) );\n\t\t}\n\t\tif (StringTool.isBlank(jobInfo.getAuthor())) {\n\t\t\treturn Response.ofFail ( (I18nUtil.getString(\"system_please_input\")+I18nUtil.getString(\"jobinfo_field_author\")) );\n\t\t}\n\n\t\t// valid trigger\n\t\tScheduleTypeEnum scheduleTypeEnum = ScheduleTypeEnum.match(jobInfo.getScheduleType(), null);\n\t\tif (scheduleTypeEnum == null) {\n\t\t\treturn Response.ofFail ( (I18nUtil.getString(\"schedule_type\")+I18nUtil.getString(\"system_unvalid\")) );\n\t\t}\n\t\tif (scheduleTypeEnum == ScheduleTypeEnum.CRON) {\n\t\t\tif (jobInfo.getScheduleConf()==null || !CronExpression.isValidExpression(jobInfo.getScheduleConf())) {\n\t\t\t\treturn Response.ofFail ( \"Cron\"+I18nUtil.getString(\"system_unvalid\") );\n\t\t\t}\n\t\t} else if (scheduleTypeEnum == ScheduleTypeEnum.FIX_RATE /*|| scheduleTypeEnum == ScheduleTypeEnum.FIX_DELAY*/) {\n\t\t\tif (jobInfo.getScheduleConf() == null) {\n\t\t\t\treturn Response.ofFail ( (I18nUtil.getString(\"schedule_type\")+I18nUtil.getString(\"system_unvalid\")) );\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tint fixSecond = Integer.parseInt(jobInfo.getScheduleConf());\n\t\t\t\tif (fixSecond < 1) {\n\t\t\t\t\treturn Response.ofFail ( (I18nUtil.getString(\"schedule_type\")+I18nUtil.getString(\"system_unvalid\")) );\n\t\t\t\t}\n\t\t\t} catch (Exception e) {\n\t\t\t\treturn Response.ofFail ( (I18nUtil.getString(\"schedule_type\")+I18nUtil.getString(\"system_unvalid\")) );\n\t\t\t}\n\t\t}\n\n\t\t// valid advanced\n\t\tif (ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null) == null) {\n\t\t\treturn Response.ofFail ( (I18nUtil.getString(\"jobinfo_field_executorRouteStrategy\")+I18nUtil.getString(\"system_unvalid\")) );\n\t\t}\n\t\tif (MisfireStrategyEnum.match(jobInfo.getMisfireStrategy(), null) == null) {\n\t\t\treturn Response.ofFail ( (I18nUtil.getString(\"misfire_strategy\")+I18nUtil.getString(\"system_unvalid\")) );\n\t\t}\n\t\tif (ExecutorBlockStrategyEnum.match(jobInfo.getExecutorBlockStrategy(), null) == null) {\n\t\t\treturn Response.ofFail ( (I18nUtil.getString(\"jobinfo_field_executorBlockStrategy\")+I18nUtil.getString(\"system_unvalid\")) );\n\t\t}\n\n\t\t// 》ChildJobId valid\n\t\tif (StringTool.isNotBlank(jobInfo.getChildJobId())) {\n\t\t\tString[] childJobIds = jobInfo.getChildJobId().split(\",\");\n\t\t\tfor (String childJobIdItem: childJobIds) {\n\t\t\t\tif (StringTool.isNotBlank(childJobIdItem) && StringTool.isNumeric(childJobIdItem)) {\n\t\t\t\t\t// parse child\n\t\t\t\t\tint childJobId = Integer.parseInt(childJobIdItem);\n\t\t\t\t\tif (childJobId == jobInfo.getId()) {\n\t\t\t\t\t\treturn Response.ofFail ( (I18nUtil.getString(\"jobinfo_field_childJobId\")+\"(\"+childJobId+\")\"+I18nUtil.getString(\"system_unvalid\")) );\n\t\t\t\t\t}\n\n\t\t\t\t\t// valid child\n\t\t\t\t\tXxlJobInfo childJobInfo = xxlJobInfoMapper.loadById(childJobId);\n\t\t\t\t\tif (childJobInfo==null) {\n\t\t\t\t\t\treturn Response.ofFail (\n\t\t\t\t\t\t\t\tMessageFormat.format((I18nUtil.getString(\"jobinfo_field_childJobId\")+\"({0})\"+I18nUtil.getString(\"system_not_found\")), childJobIdItem));\n\t\t\t\t\t}\n\t\t\t\t\t// valid jobGroup permission\n\t\t\t\t\tif (!JobGroupPermissionUtil.hasJobGroupPermission(loginInfo, childJobInfo.getJobGroup())) {\n\t\t\t\t\t\treturn Response.ofFail (\n\t\t\t\t\t\t\t\tMessageFormat.format((I18nUtil.getString(\"jobinfo_field_childJobId\")+\"({0})\"+I18nUtil.getString(\"system_permission_limit\")), childJobIdItem));\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\treturn Response.ofFail (\n\t\t\t\t\t\t\tMessageFormat.format((I18nUtil.getString(\"jobinfo_field_childJobId\")+\"({0})\"+I18nUtil.getString(\"system_unvalid\")), childJobIdItem));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// join , avoid \"xxx,,\"\n\t\t\tString temp = \"\";\n\t\t\tfor (String item:childJobIds) {\n\t\t\t\ttemp += item + \",\";\n\t\t\t}\n\t\t\ttemp = temp.substring(0, temp.length()-1);\n\n\t\t\tjobInfo.setChildJobId(temp);\n\t\t}\n\n\t\t// group valid\n\t\tXxlJobGroup jobGroup = xxlJobGroupMapper.load(jobInfo.getJobGroup());\n\t\tif (jobGroup == null) {\n\t\t\treturn Response.ofFail ( (I18nUtil.getString(\"jobinfo_field_jobgroup\")+I18nUtil.getString(\"system_unvalid\")) );\n\t\t}\n\n\t\t// stage job info\n\t\tXxlJobInfo exists_jobInfo = xxlJobInfoMapper.loadById(jobInfo.getId());\n\t\tif (exists_jobInfo == null) {\n\t\t\treturn Response.ofFail ( (I18nUtil.getString(\"jobinfo_field_id\")+I18nUtil.getString(\"system_not_found\")) );\n\t\t}\n\n\t\t// next trigger time (5s后生效，避开预读周期)\n\t\tlong nextTriggerTime = exists_jobInfo.getTriggerNextTime();\n\t\tboolean scheduleDataNotChanged = jobInfo.getScheduleType().equals(exists_jobInfo.getScheduleType())\n\t\t\t\t&& jobInfo.getScheduleConf().equals(exists_jobInfo.getScheduleConf());\t\t// 触发配置如果不变，避免重复计算；\n\t\tif (exists_jobInfo.getTriggerStatus() == TriggerStatus.RUNNING.getValue() && !scheduleDataNotChanged) {\n\t\t\ttry {\n\t\t\t\t// generate next trigger time\n\t\t\t\tDate nextValidTime = scheduleTypeEnum.getScheduleType().generateNextTriggerTime(jobInfo, new Date(System.currentTimeMillis() + JobScheduleHelper.PRE_READ_MS));\n\t\t\t\tif (nextValidTime == null) {\n\t\t\t\t\treturn Response.ofFail ( (I18nUtil.getString(\"schedule_type\")+I18nUtil.getString(\"system_unvalid\")) );\n\t\t\t\t}\n\t\t\t\tnextTriggerTime = nextValidTime.getTime();\n\t\t\t} catch (Exception e) {\n\t\t\t\tlogger.error(e.getMessage(), e);\n\t\t\t\treturn Response.ofFail ( (I18nUtil.getString(\"schedule_type\")+I18nUtil.getString(\"system_unvalid\")) );\n\t\t\t}\n\t\t}\n\n\t\texists_jobInfo.setJobGroup(jobInfo.getJobGroup());\n\t\texists_jobInfo.setJobDesc(jobInfo.getJobDesc());\n\t\texists_jobInfo.setAuthor(jobInfo.getAuthor());\n\t\texists_jobInfo.setAlarmEmail(jobInfo.getAlarmEmail());\n\t\texists_jobInfo.setScheduleType(jobInfo.getScheduleType());\n\t\texists_jobInfo.setScheduleConf(jobInfo.getScheduleConf());\n\t\texists_jobInfo.setMisfireStrategy(jobInfo.getMisfireStrategy());\n\t\texists_jobInfo.setExecutorRouteStrategy(jobInfo.getExecutorRouteStrategy());\n\t\t// remove the whitespace\n\t\texists_jobInfo.setExecutorHandler(jobInfo.getExecutorHandler().trim());\n\t\texists_jobInfo.setExecutorParam(jobInfo.getExecutorParam());\n\t\texists_jobInfo.setExecutorBlockStrategy(jobInfo.getExecutorBlockStrategy());\n\t\texists_jobInfo.setExecutorTimeout(jobInfo.getExecutorTimeout());\n\t\texists_jobInfo.setExecutorFailRetryCount(jobInfo.getExecutorFailRetryCount());\n\t\texists_jobInfo.setChildJobId(jobInfo.getChildJobId());\n\t\texists_jobInfo.setTriggerNextTime(nextTriggerTime);\n\n\t\texists_jobInfo.setUpdateTime(new Date());\n        xxlJobInfoMapper.update(exists_jobInfo);\n\n\t\t// write operation log\n\t\tlogger.info(\">>>>>>>>>>> xxl-job operation log: operator = {}, type = {}, content = {}\",\n\t\t\t\tloginInfo.getUserName(), \"jobinfo-update\", GsonTool.toJson(exists_jobInfo));\n\n\t\treturn Response.ofSuccess();\n\t}\n\n\t@Override\n\tpublic Response<String> remove(int id, LoginInfo loginInfo) {\n\t\t// valid job\n\t\tXxlJobInfo xxlJobInfo = xxlJobInfoMapper.loadById(id);\n\t\tif (xxlJobInfo == null) {\n\t\t\treturn Response.ofSuccess();\n\t\t}\n\n\t\t// valid jobGroup permission\n\t\tif (!JobGroupPermissionUtil.hasJobGroupPermission(loginInfo, xxlJobInfo.getJobGroup())) {\n\t\t\treturn Response.ofFail(I18nUtil.getString(\"system_permission_limit\"));\n\t\t}\n\n\t\txxlJobInfoMapper.delete(id);\n\t\txxlJobLogMapper.delete(id);\n\t\txxlJobLogGlueMapper.deleteByJobId(id);\n\n\t\t// write operation log\n\t\tlogger.info(\">>>>>>>>>>> xxl-job operation log: operator = {}, type = {}, content = {}\",\n\t\t\t\tloginInfo.getUserName(), \"jobinfo-remove\", id);\n\n\t\treturn Response.ofSuccess();\n\t}\n\n\t@Override\n\tpublic Response<String> start(int id, LoginInfo loginInfo) {\n\t\t// load and valid\n\t\tXxlJobInfo xxlJobInfo = xxlJobInfoMapper.loadById(id);\n\t\tif (xxlJobInfo == null) {\n\t\t\treturn Response.ofFail(I18nUtil.getString(\"jobinfo_glue_jobid_unvalid\"));\n\t\t}\n\n\t\t// valid jobGroup permission\n\t\tif (!JobGroupPermissionUtil.hasJobGroupPermission(loginInfo, xxlJobInfo.getJobGroup())) {\n\t\t\treturn Response.ofFail(I18nUtil.getString(\"system_permission_limit\"));\n\t\t}\n\n\t\t// valid ScheduleType: can not be none\n\t\tScheduleTypeEnum scheduleTypeEnum = ScheduleTypeEnum.match(xxlJobInfo.getScheduleType(), ScheduleTypeEnum.NONE);\n\t\tif (ScheduleTypeEnum.NONE == scheduleTypeEnum) {\n\t\t\treturn Response.ofFail(I18nUtil.getString(\"schedule_type_none_limit_start\"));\n\t\t}\n\n\t\t// next trigger time (5s后生效，避开预读周期)\n\t\tlong nextTriggerTime = 0;\n\t\ttry {\n\t\t\t// generate next trigger time\n\t\t\tDate nextValidTime = scheduleTypeEnum.getScheduleType().generateNextTriggerTime(xxlJobInfo, new Date(System.currentTimeMillis() + JobScheduleHelper.PRE_READ_MS));\n\n\t\t\tif (nextValidTime == null) {\n\t\t\t\treturn Response.ofFail ( (I18nUtil.getString(\"schedule_type\")+I18nUtil.getString(\"system_unvalid\")) );\n\t\t\t}\n\t\t\tnextTriggerTime = nextValidTime.getTime();\n\t\t} catch (Exception e) {\n\t\t\tlogger.error(e.getMessage(), e);\n\t\t\treturn Response.ofFail ( (I18nUtil.getString(\"schedule_type\")+I18nUtil.getString(\"system_unvalid\")) );\n\t\t}\n\n\t\txxlJobInfo.setTriggerStatus(TriggerStatus.RUNNING.getValue());\n\t\txxlJobInfo.setTriggerLastTime(0);\n\t\txxlJobInfo.setTriggerNextTime(nextTriggerTime);\n\n\t\txxlJobInfo.setUpdateTime(new Date());\n\t\txxlJobInfoMapper.update(xxlJobInfo);\n\n\t\t// write operation log\n\t\tlogger.info(\">>>>>>>>>>> xxl-job operation log: operator = {}, type = {}, content = {}\",\n\t\t\t\tloginInfo.getUserName(), \"jobinfo-start\", id);\n\n\t\treturn Response.ofSuccess();\n\t}\n\n\t@Override\n\tpublic Response<String> stop(int id, LoginInfo loginInfo) {\n\t\t// load and valid\n        XxlJobInfo xxlJobInfo = xxlJobInfoMapper.loadById(id);\n\t\tif (xxlJobInfo == null) {\n\t\t\treturn Response.ofFail(I18nUtil.getString(\"jobinfo_glue_jobid_unvalid\"));\n\t\t}\n\n\t\t// valid jobGroup permission\n\t\tif (!JobGroupPermissionUtil.hasJobGroupPermission(loginInfo, xxlJobInfo.getJobGroup())) {\n\t\t\treturn Response.ofFail(I18nUtil.getString(\"system_permission_limit\"));\n\t\t}\n\n\t\t// stop\n\t\txxlJobInfo.setTriggerStatus(TriggerStatus.STOPPED.getValue());\n\t\txxlJobInfo.setTriggerLastTime(0);\n\t\txxlJobInfo.setTriggerNextTime(0);\n\n\t\txxlJobInfo.setUpdateTime(new Date());\n\t\txxlJobInfoMapper.update(xxlJobInfo);\n\n\t\t// write operation log\n\t\tlogger.info(\">>>>>>>>>>> xxl-job operation log: operator = {}, type = {}, content = {}\",\n\t\t\t\tloginInfo.getUserName(), \"jobinfo-stop\", id);\n\n\t\treturn Response.ofSuccess();\n\t}\n\n\t@Override\n\tpublic Response<String> trigger(LoginInfo loginInfo, int jobId, String executorParam, String addressList) {\n\t\t// valid job\n\t\tXxlJobInfo xxlJobInfo = xxlJobInfoMapper.loadById(jobId);\n\t\tif (xxlJobInfo == null) {\n\t\t\treturn Response.ofFail(I18nUtil.getString(\"jobinfo_glue_jobid_unvalid\"));\n\t\t}\n\n\t\t// valid jobGroup permission\n\t\tif (!JobGroupPermissionUtil.hasJobGroupPermission(loginInfo, xxlJobInfo.getJobGroup())) {\n\t\t\treturn Response.ofFail(I18nUtil.getString(\"system_permission_limit\"));\n\t\t}\n\n\t\t// force cover job param\n\t\tif (executorParam == null) {\n\t\t\texecutorParam = \"\";\n\t\t}\n\n\t\tXxlJobAdminBootstrap.getInstance().getJobTriggerPoolHelper().trigger(jobId, TriggerTypeEnum.MANUAL, -1, null, executorParam, addressList);\n\n\t\t// write operation log\n\t\tlogger.info(\">>>>>>>>>>> xxl-job operation log: operator = {}, type = {}, content = {}\",\n\t\t\t\tloginInfo.getUserName(), \"jobinfo-trigger\", jobId);\n\n\t\treturn Response.ofSuccess();\n\t}\n\n\t@Override\n\tpublic Map<String, Object> dashboardInfo() {\n\n\t\tint jobInfoCount = xxlJobInfoMapper.findAllCount();\n\t\tint jobLogCount = 0;\n\t\tint jobLogSuccessCount = 0;\n\t\tXxlJobLogReport xxlJobLogReport = xxlJobLogReportMapper.queryLogReportTotal();\n\t\tif (xxlJobLogReport != null) {\n\t\t\tjobLogCount = xxlJobLogReport.getRunningCount() + xxlJobLogReport.getSucCount() + xxlJobLogReport.getFailCount();\n\t\t\tjobLogSuccessCount = xxlJobLogReport.getSucCount();\n\t\t}\n\n\t\t// executor count\n\t\tSet<String> executorAddressSet = new HashSet<String>();\n\t\tList<XxlJobGroup> groupList = xxlJobGroupMapper.findAll();\n\n\t\tif (groupList!=null && !groupList.isEmpty()) {\n\t\t\tfor (XxlJobGroup group: groupList) {\n\t\t\t\tif (group.getRegistryList()!=null && !group.getRegistryList().isEmpty()) {\n\t\t\t\t\texecutorAddressSet.addAll(group.getRegistryList());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tint executorCount = executorAddressSet.size();\n\n\t\tMap<String, Object> dashboardMap = new HashMap<String, Object>();\n\t\tdashboardMap.put(\"jobInfoCount\", jobInfoCount);\n\t\tdashboardMap.put(\"jobLogCount\", jobLogCount);\n\t\tdashboardMap.put(\"jobLogSuccessCount\", jobLogSuccessCount);\n\t\tdashboardMap.put(\"executorCount\", executorCount);\n\t\treturn dashboardMap;\n\t}\n\n\t@Override\n\tpublic Response<Map<String, Object>> chartInfo(Date startDate, Date endDate) {\n\n\t\t// process\n\t\tList<String> triggerDayList = new ArrayList<String>();\n\t\tList<Integer> triggerDayCountRunningList = new ArrayList<Integer>();\n\t\tList<Integer> triggerDayCountSucList = new ArrayList<Integer>();\n\t\tList<Integer> triggerDayCountFailList = new ArrayList<Integer>();\n\t\tint triggerCountRunningTotal = 0;\n\t\tint triggerCountSucTotal = 0;\n\t\tint triggerCountFailTotal = 0;\n\n\t\tList<XxlJobLogReport> logReportList = xxlJobLogReportMapper.queryLogReport(startDate, endDate);\n\n\t\tif (logReportList!=null && !logReportList.isEmpty()) {\n\t\t\tfor (XxlJobLogReport item: logReportList) {\n\t\t\t\tString day = DateTool.formatDate(item.getTriggerDay());\n\t\t\t\tint triggerDayCountRunning = item.getRunningCount();\n\t\t\t\tint triggerDayCountSuc = item.getSucCount();\n\t\t\t\tint triggerDayCountFail = item.getFailCount();\n\n\t\t\t\ttriggerDayList.add(day);\n\t\t\t\ttriggerDayCountRunningList.add(triggerDayCountRunning);\n\t\t\t\ttriggerDayCountSucList.add(triggerDayCountSuc);\n\t\t\t\ttriggerDayCountFailList.add(triggerDayCountFail);\n\n\t\t\t\ttriggerCountRunningTotal += triggerDayCountRunning;\n\t\t\t\ttriggerCountSucTotal += triggerDayCountSuc;\n\t\t\t\ttriggerCountFailTotal += triggerDayCountFail;\n\t\t\t}\n\t\t} else {\n\t\t\tfor (int i = -6; i <= 0; i++) {\n\t\t\t\ttriggerDayList.add(DateTool.formatDate(DateTool.addDays(new Date(), i)));\n\t\t\t\ttriggerDayCountRunningList.add(0);\n\t\t\t\ttriggerDayCountSucList.add(0);\n\t\t\t\ttriggerDayCountFailList.add(0);\n\t\t\t}\n\t\t}\n\n\t\tMap<String, Object> result = new HashMap<String, Object>();\n\t\tresult.put(\"triggerDayList\", triggerDayList);\n\t\tresult.put(\"triggerDayCountRunningList\", triggerDayCountRunningList);\n\t\tresult.put(\"triggerDayCountSucList\", triggerDayCountSucList);\n\t\tresult.put(\"triggerDayCountFailList\", triggerDayCountFailList);\n\n\t\tresult.put(\"triggerCountRunningTotal\", triggerCountRunningTotal);\n\t\tresult.put(\"triggerCountSucTotal\", triggerCountSucTotal);\n\t\tresult.put(\"triggerCountFailTotal\", triggerCountFailTotal);\n\n\t\treturn Response.ofSuccess(result);\n\t}\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/util/I18nUtil.java",
    "content": "package com.xxl.job.admin.util;\n\nimport com.xxl.job.core.constant.ExecutorBlockStrategyEnum;\nimport com.xxl.tool.core.PropTool;\nimport com.xxl.tool.freemarker.FtlTool;\nimport com.xxl.tool.json.GsonTool;\nimport freemarker.template.Configuration;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.stereotype.Component;\n\nimport java.text.MessageFormat;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Properties;\n\n/**\n * i18n util\n *\n * @author xuxueli 2018-01-17 20:39:06\n */\n@Component\npublic class I18nUtil implements InitializingBean {\n    private static Logger logger = LoggerFactory.getLogger(I18nUtil.class);\n\n    // ---------------------- for i18n config ----------------------\n\n    /**\n     * i18n config\n     */\n    @Value(\"${xxl.job.i18n}\")\n    private String i18n;\n\n    /**\n     * freemarker config\n     */\n    @Autowired\n    private Configuration configuration;\n\n    @Override\n    public void afterPropertiesSet() throws Exception {\n        // init freemarker shared variable\n        configuration.setSharedVariable(\"I18nUtil\", FtlTool.generateStaticModel(I18nUtil.class.getName()));\n        // init single\n        single = this;\n\n        // init i18n-enum\n        initI18nEnum();\n    }\n\n    /**\n     * get i18n\n     */\n    public String getI18n() {\n        if (!Arrays.asList(\"zh_CN\", \"zh_TC\", \"en\").contains(i18n)) {\n            return \"zh_CN\";\n        }\n        return i18n;\n    }\n\n    private static I18nUtil single = null;\n    private static I18nUtil getSingle() {\n        return single;\n    }\n\n    // ---------------------- tool ----------------------\n\n    private static Properties prop = null;\n    public static Properties loadI18nProp(){\n        if (prop != null) {\n            return prop;\n        }\n        // build i18n filepath\n        String i18n = getSingle().getI18n();\n        String i18nFile = MessageFormat.format(\"i18n/message_{0}.properties\", i18n);\n\n        // load prop\n        prop = PropTool.loadProp(i18nFile);\n        return prop;\n    }\n\n    /**\n     * get val of i18n key\n     *\n     * @param key\n     * @return\n     */\n    public static String getString(String key) {\n        return loadI18nProp().getProperty(key);\n    }\n\n    /**\n     * get mult val of i18n mult key, as json\n     *\n     * @param keys\n     * @return\n     */\n    public static String getMultString(String... keys) {\n        Map<String, String> map = new HashMap<>();\n\n        Properties prop = loadI18nProp();\n        if (keys!=null && keys.length>0) {\n            for (String key: keys) {\n                map.put(key, prop.getProperty(key));\n            }\n        } else {\n            for (String key: prop.stringPropertyNames()) {\n                map.put(key, prop.getProperty(key));\n            }\n        }\n\n        return GsonTool.toJson(map);\n    }\n\n\n    // ---------------------- init I18n-enum ----------------------\n\n    /**\n     * init i18n-enum\n     */\n    private void initI18nEnum(){\n        for (ExecutorBlockStrategyEnum item : ExecutorBlockStrategyEnum.values()) {\n            item.setTitle(I18nUtil.getString(\"jobconf_block_\".concat(item.name())));\n        }\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/util/JobGroupPermissionUtil.java",
    "content": "package com.xxl.job.admin.util;\n\nimport com.xxl.job.admin.constant.Consts;\nimport com.xxl.job.admin.model.XxlJobGroup;\nimport com.xxl.sso.core.helper.XxlSsoHelper;\nimport com.xxl.sso.core.model.LoginInfo;\nimport com.xxl.tool.core.StringTool;\nimport com.xxl.tool.response.Response;\nimport jakarta.servlet.http.HttpServletRequest;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * jobGroup permission util\n *\n * @author xuxueli 2025-08-24\n */\npublic class JobGroupPermissionUtil {\n\n    /**\n     * check if has jobgroup permission\n     */\n    public static boolean hasJobGroupPermission(LoginInfo loginInfo, int jobGroup){\n        if (XxlSsoHelper.hasRole(loginInfo, Consts.ADMIN_ROLE).isSuccess()) {\n            return true;\n        } else {\n            List<String> jobGroups = (loginInfo.getExtraInfo()!=null && loginInfo.getExtraInfo().containsKey(\"jobGroups\"))\n                    ? StringTool.split(loginInfo.getExtraInfo().get(\"jobGroups\"), \",\") :new ArrayList<>();\n            return jobGroups.contains(String.valueOf(jobGroup));\n        }\n    }\n\n    /**\n     * valid jobGroup permission\n     */\n    public static LoginInfo validJobGroupPermission(HttpServletRequest request, int jobGroup) {\n        Response<LoginInfo> loginInfoResponse = XxlSsoHelper.loginCheckWithAttr(request);\n        if (!(loginInfoResponse.isSuccess() && hasJobGroupPermission(loginInfoResponse.getData(), jobGroup))) {\n            throw new RuntimeException(I18nUtil.getString(\"system_permission_limit\") + \"[username=\"+ loginInfoResponse.getData().getUserName() +\"]\");\n        }\n        return loginInfoResponse.getData();\n    }\n\n    /**\n     * filter jobGroupList by permission\n     */\n    public static List<XxlJobGroup> filterJobGroupByPermission(HttpServletRequest request, List<XxlJobGroup> jobGroupListTotal){\n        Response<LoginInfo>  loginInfoResponse = XxlSsoHelper.loginCheckWithAttr(request);\n\n        if (XxlSsoHelper.hasRole(loginInfoResponse.getData(), Consts.ADMIN_ROLE).isSuccess()) {\n            return jobGroupListTotal;\n        } else {\n            List<String> jobGroups = (loginInfoResponse.getData().getExtraInfo()!=null\n                    && loginInfoResponse.getData().getExtraInfo().get(\"jobGroups\")!=null\n            )\n                    ? StringTool.split(loginInfoResponse.getData().getExtraInfo().get(\"jobGroups\"), \",\")\n                    :new ArrayList<>();\n\n            return jobGroupListTotal\n                    .stream()\n                    .filter(jobGroup -> jobGroups.contains(String.valueOf(jobGroup.getId())))\n                    .toList();\n        }\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/util/old/CommonDataInterceptor.java",
    "content": "//package com.xxl.job.admin.web.interceptor;\n//\n//import com.xxl.job.admin.util.I18nUtil;\n//import com.xxl.tool.freemarker.FtlTool;\n//import jakarta.servlet.http.HttpServletRequest;\n//import jakarta.servlet.http.HttpServletResponse;\n//import org.springframework.context.annotation.Configuration;\n//import org.springframework.web.servlet.AsyncHandlerInterceptor;\n//import org.springframework.web.servlet.ModelAndView;\n//import org.springframework.web.servlet.config.annotation.InterceptorRegistry;\n//import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;\n//\n///**\n// * push cookies to model as cookieMap\n// *\n// * @author xuxueli 2015-12-12 18:09:04\n// */\n//@Configuration\n//public class CommonDataInterceptor implements WebMvcConfigurer {\n//\n//\t@Override\n//\tpublic void addInterceptors(InterceptorRegistry registry) {\n//\t\tregistry.addInterceptor(new AsyncHandlerInterceptor() {\n//\t\t\t@Override\n//\t\t\tpublic void postHandle(HttpServletRequest request,\n//\t\t\t\t\t\t\t\t   HttpServletResponse response,\n//\t\t\t\t\t\t\t\t   Object handler,\n//\t\t\t\t\t\t\t\t   ModelAndView modelAndView) throws Exception {\n//\n//\t\t\t\t// static method\n//\t\t\t\tif (modelAndView != null) {\n//\t\t\t\t\tmodelAndView.addObject(\"I18nUtil\", FtlTool.generateStaticModel(I18nUtil.class.getName()));\n//\t\t\t\t}\n//\n//\t\t\t}\n//\t\t}).addPathPatterns(\"/**\");\n//\t}\n//\n//}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/util/old/CookieUtil.java",
    "content": "//package com.xxl.job.admin.util;\n//\n//import jakarta.servlet.http.Cookie;\n//import jakarta.servlet.http.HttpServletRequest;\n//import jakarta.servlet.http.HttpServletResponse;\n//\n///**\n// * Cookie.Util\n// *\n// * @author xuxueli 2015-12-12 18:01:06\n// */\n//public class CookieUtil {\n//\n//\t// 默认缓存时间,单位/秒, 2H\n//\tprivate static final int COOKIE_MAX_AGE = Integer.MAX_VALUE;\n//\t// 保存路径,根路径\n//\tprivate static final String COOKIE_PATH = \"/\";\n//\n//\t/**\n//\t * 保存\n//\t *\n//\t * @param response\n//\t * @param key\n//\t * @param value\n//\t * @param ifRemember\n//\t */\n//\tpublic static void set(HttpServletResponse response, String key, String value, boolean ifRemember) {\n//\t\tint age = ifRemember?COOKIE_MAX_AGE:-1;\n//\t\tset(response, key, value, null, COOKIE_PATH, age, true);\n//\t}\n//\n//\t/**\n//\t * 保存\n//\t *\n//\t * @param response\n//\t * @param key\n//\t * @param value\n//\t * @param maxAge\n//\t */\n//\tprivate static void set(HttpServletResponse response, String key, String value, String domain, String path, int maxAge, boolean isHttpOnly) {\n//\t\tCookie cookie = new Cookie(key, value);\n//\t\tif (domain != null) {\n//\t\t\tcookie.setDomain(domain);\n//\t\t}\n//\t\tcookie.setPath(path);\n//\t\tcookie.setMaxAge(maxAge);\n//\t\tcookie.setHttpOnly(isHttpOnly);\n//\t\tresponse.addCookie(cookie);\n//\t}\n//\n//\t/**\n//\t * 查询value\n//\t *\n//\t * @param request\n//\t * @param key\n//\t * @return\n//\t */\n//\tpublic static String getValue(HttpServletRequest request, String key) {\n//\t\tCookie cookie = get(request, key);\n//\t\tif (cookie != null) {\n//\t\t\treturn cookie.getValue();\n//\t\t}\n//\t\treturn null;\n//\t}\n//\n//\t/**\n//\t * 查询Cookie\n//\t *\n//\t * @param request\n//\t * @param key\n//\t */\n//\tprivate static Cookie get(HttpServletRequest request, String key) {\n//\t\tCookie[] arr_cookie = request.getCookies();\n//\t\tif (arr_cookie != null && arr_cookie.length > 0) {\n//\t\t\tfor (Cookie cookie : arr_cookie) {\n//\t\t\t\tif (cookie.getName().equals(key)) {\n//\t\t\t\t\treturn cookie;\n//\t\t\t\t}\n//\t\t\t}\n//\t\t}\n//\t\treturn null;\n//\t}\n//\n//\t/**\n//\t * 删除Cookie\n//\t *\n//\t * @param request\n//\t * @param response\n//\t * @param key\n//\t */\n//\tpublic static void remove(HttpServletRequest request, HttpServletResponse response, String key) {\n//\t\tCookie cookie = get(request, key);\n//\t\tif (cookie != null) {\n//\t\t\tset(response, key, \"\", null, COOKIE_PATH, 0, true);\n//\t\t}\n//\t}\n//\n//}"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/util/old/FtlUtil.java",
    "content": "//package com.xxl.job.admin.util;\n//\n//import freemarker.ext.beans.BeansWrapper;\n//import freemarker.ext.beans.BeansWrapperBuilder;\n//import freemarker.template.Configuration;\n//import freemarker.template.TemplateHashModel;\n//import org.slf4j.Logger;\n//import org.slf4j.LoggerFactory;\n//\n///**\n// * ftl util\n// *\n// * @author xuxueli 2018-01-17 20:37:48\n// */\n//public class FtlUtil {\n//    private static Logger logger = LoggerFactory.getLogger(FtlUtil.class);\n//\n//    private static BeansWrapper wrapper = new BeansWrapperBuilder(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS).build();     //BeansWrapper.getDefaultInstance();\n//\n//    public static TemplateHashModel generateStaticModel(String packageName) {\n//        try {\n//            TemplateHashModel staticModels = wrapper.getStaticModels();\n//            TemplateHashModel fileStatics = (TemplateHashModel) staticModels.get(packageName);\n//            return fileStatics;\n//        } catch (Exception e) {\n//            logger.error(e.getMessage(), e);\n//        }\n//        return null;\n//    }\n//\n//}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/util/old/JacksonUtil.java",
    "content": "//package com.xxl.job.admin.util.old;\n//\n//import com.fasterxml.jackson.core.JsonGenerationException;\n//import com.fasterxml.jackson.core.JsonParseException;\n//import com.fasterxml.jackson.databind.JavaType;\n//import com.fasterxml.jackson.databind.JsonMappingException;\n//import com.fasterxml.jackson.databind.ObjectMapper;\n//import org.slf4j.Logger;\n//import org.slf4j.LoggerFactory;\n//\n//import java.io.IOException;\n//\n///**\n// * Jackson util\n// *\n// * 1、obj need private and set/get；\n// * 2、do not support inner class；\n// *\n// * @author xuxueli 2015-9-25 18:02:56\n// */\n//public class JacksonUtil {\n//\tprivate static Logger logger = LoggerFactory.getLogger(JacksonUtil.class);\n//\n//    private final static ObjectMapper objectMapper = new ObjectMapper();\n//    public static ObjectMapper getInstance() {\n//        return objectMapper;\n//    }\n//\n//    /**\n//     * bean、array、List、Map --> json\n//     *\n//     * @param obj\n//     * @return json string\n//     * @throws Exception\n//     */\n//    public static String writeValueAsString(Object obj) {\n//    \ttry {\n//\t\t\treturn getInstance().writeValueAsString(obj);\n//\t\t} catch (JsonGenerationException e) {\n//\t\t\tlogger.error(e.getMessage(), e);\n//\t\t} catch (JsonMappingException e) {\n//\t\t\tlogger.error(e.getMessage(), e);\n//\t\t} catch (IOException e) {\n//\t\t\tlogger.error(e.getMessage(), e);\n//\t\t}\n//        return null;\n//    }\n//\n//    /**\n//     * string --> bean、Map、List(array)\n//     *\n//     * @param jsonStr\n//     * @param clazz\n//     * @return obj\n//     * @throws Exception\n//     */\n//    public static <T> T readValue(String jsonStr, Class<T> clazz) {\n//    \ttry {\n//\t\t\treturn getInstance().readValue(jsonStr, clazz);\n//\t\t} catch (JsonParseException e) {\n//\t\t\tlogger.error(e.getMessage(), e);\n//\t\t} catch (JsonMappingException e) {\n//\t\t\tlogger.error(e.getMessage(), e);\n//\t\t} catch (IOException e) {\n//\t\t\tlogger.error(e.getMessage(), e);\n//\t\t}\n//    \treturn null;\n//    }\n//\n//\t/**\n//\t * string --> List<Bean>...\n//\t *\n//\t * @param jsonStr\n//\t * @param parametrized\n//\t * @param parameterClasses\n//\t * @param <T>\n//\t * @return\n//\t */\n//\tpublic static <T> T readValue(String jsonStr, Class<?> parametrized, Class<?>... parameterClasses) {\n//\t\ttry {\n//\t\t\tJavaType javaType = getInstance().getTypeFactory().constructParametricType(parametrized, parameterClasses);\n//\t\t\treturn getInstance().readValue(jsonStr, javaType);\n//\t\t} catch (JsonParseException e) {\n//\t\t\tlogger.error(e.getMessage(), e);\n//\t\t} catch (JsonMappingException e) {\n//\t\t\tlogger.error(e.getMessage(), e);\n//\t\t} catch (IOException e) {\n//\t\t\tlogger.error(e.getMessage(), e);\n//\t\t}\n//\t\treturn null;\n//\t}\n//}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/util/old/LocalCacheUtil.java",
    "content": "//package com.xxl.job.admin.util;\n//\n//import java.util.concurrent.ConcurrentHashMap;\n//import java.util.concurrent.ConcurrentMap;\n//\n///**\n// * local cache tool\n// *\n// * @author xuxueli 2018-01-22 21:37:34\n// */\n//public class LocalCacheUtil {\n//\n//    private static ConcurrentMap<String, LocalCacheData> cacheRepository = new ConcurrentHashMap<String, LocalCacheData>();   // 类型建议用抽象父类，兼容性更好；\n//    private static class LocalCacheData{\n//        private String key;\n//        private Object val;\n//        private long timeoutTime;\n//\n//        public LocalCacheData() {\n//        }\n//\n//        public LocalCacheData(String key, Object val, long timeoutTime) {\n//            this.key = key;\n//            this.val = val;\n//            this.timeoutTime = timeoutTime;\n//        }\n//\n//        public String getKey() {\n//            return key;\n//        }\n//\n//        public void setKey(String key) {\n//            this.key = key;\n//        }\n//\n//        public Object getVal() {\n//            return val;\n//        }\n//\n//        public void setVal(Object val) {\n//            this.val = val;\n//        }\n//\n//        public long getTimeoutTime() {\n//            return timeoutTime;\n//        }\n//\n//        public void setTimeoutTime(long timeoutTime) {\n//            this.timeoutTime = timeoutTime;\n//        }\n//    }\n//\n//\n//    /**\n//     * set cache\n//     *\n//     * @param key\n//     * @param val\n//     * @param cacheTime\n//     * @return\n//     */\n//    public static boolean set(String key, Object val, long cacheTime){\n//\n//        // clean timeout cache, before set new cache (avoid cache too much)\n//        cleanTimeoutCache();\n//\n//        // set new cache\n//        if (key==null || key.trim().length()==0) {\n//            return false;\n//        }\n//        if (val == null) {\n//            remove(key);\n//        }\n//        if (cacheTime <= 0) {\n//            remove(key);\n//        }\n//        long timeoutTime = System.currentTimeMillis() + cacheTime;\n//        LocalCacheData localCacheData = new LocalCacheData(key, val, timeoutTime);\n//        cacheRepository.put(localCacheData.getKey(), localCacheData);\n//        return true;\n//    }\n//\n//    /**\n//     * remove cache\n//     *\n//     * @param key\n//     * @return\n//     */\n//    public static boolean remove(String key){\n//        if (key==null || key.trim().length()==0) {\n//            return false;\n//        }\n//        cacheRepository.remove(key);\n//        return true;\n//    }\n//\n//    /**\n//     * get cache\n//     *\n//     * @param key\n//     * @return\n//     */\n//    public static Object get(String key){\n//        if (key==null || key.trim().length()==0) {\n//            return null;\n//        }\n//        LocalCacheData localCacheData = cacheRepository.get(key);\n//        if (localCacheData!=null && System.currentTimeMillis()<localCacheData.getTimeoutTime()) {\n//            return localCacheData.getVal();\n//        } else {\n//            remove(key);\n//            return null;\n//        }\n//    }\n//\n//    /**\n//     * clean timeout cache\n//     *\n//     * @return\n//     */\n//    public static boolean cleanTimeoutCache(){\n//        if (!cacheRepository.keySet().isEmpty()) {\n//            for (String key: cacheRepository.keySet()) {\n//                LocalCacheData localCacheData = cacheRepository.get(key);\n//                if (localCacheData!=null && System.currentTimeMillis()>=localCacheData.getTimeoutTime()) {\n//                    cacheRepository.remove(key);\n//                }\n//            }\n//        }\n//        return true;\n//    }\n//\n//}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/util/old/RemoteHttpJobBean.java",
    "content": "//package com.xxl.job.admin.core.jobbean;\n//\n//import com.xxl.job.admin.core.thread.JobTriggerPoolHelper;\n//import com.xxl.job.admin.core.trigger.TriggerTypeEnum;\n//import org.quartz.JobExecutionContext;\n//import org.quartz.JobExecutionException;\n//import org.quartz.JobKey;\n//import org.slf4j.Logger;\n//import org.slf4j.LoggerFactory;\n//import org.springframework.scheduling.quartz.QuartzJobBean;\n//\n///**\n// * http job bean\n// * “@DisallowConcurrentExecution” disable concurrent, thread size can not be only one, better given more\n// * @author xuxueli 2015-12-17 18:20:34\n// */\n////@DisallowConcurrentExecution\n//public class RemoteHttpJobBean extends QuartzJobBean {\n//\tprivate static Logger logger = LoggerFactory.getLogger(RemoteHttpJobBean.class);\n//\n//\t@Override\n//\tprotected void executeInternal(JobExecutionContext context)\n//\t\t\tthrows JobExecutionException {\n//\n//\t\t// load jobId\n//\t\tJobKey jobKey = context.getTrigger().getJobKey();\n//\t\tInteger jobId = Integer.valueOf(jobKey.getName());\n//\n//\n//\t}\n//\n//}"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/util/old/XxlJobDynamicScheduler.java",
    "content": "//package com.xxl.job.admin.core.schedule;\n//\n//import com.xxl.job.admin.core.conf.XxlJobAdminConfig;\n//import com.xxl.job.admin.core.jobbean.RemoteHttpJobBean;\n//import com.xxl.job.admin.core.model.XxlJobInfo;\n//import com.xxl.job.admin.core.thread.JobFailMonitorHelper;\n//import com.xxl.job.admin.core.thread.JobRegistryMonitorHelper;\n//import com.xxl.job.admin.core.thread.JobTriggerPoolHelper;\n//import com.xxl.job.admin.core.util.I18nUtil;\n//import com.xxl.job.core.biz.AdminBiz;\n//import com.xxl.job.core.biz.ExecutorBiz;\n//import com.xxl.job.core.enums.ExecutorBlockStrategyEnum;\n//import com.xxl.rpc.remoting.invoker.XxlRpcInvokerFactory;\n//import com.xxl.rpc.remoting.invoker.call.CallType;\n//import com.xxl.rpc.remoting.invoker.reference.XxlRpcReferenceBean;\n//import com.xxl.rpc.remoting.invoker.route.LoadBalance;\n//import com.xxl.rpc.remoting.net.NetEnum;\n//import com.xxl.rpc.remoting.net.impl.servlet.server.ServletServerHandler;\n//import com.xxl.rpc.remoting.provider.XxlRpcProviderFactory;\n//import com.xxl.rpc.serialize.Serializer;\n//import org.quartz.*;\n//import org.quartz.Trigger.TriggerState;\n//import org.quartz.impl.triggers.CronTriggerImpl;\n//import org.slf4j.Logger;\n//import org.slf4j.LoggerFactory;\n//import org.springframework.util.Assert;\n//\n//import javax.servlet.ServletException;\n//import javax.servlet.http.HttpServletRequest;\n//import javax.servlet.http.HttpServletResponse;\n//import java.io.IOException;\n//import java.util.Date;\n//import java.util.concurrent.ConcurrentHashMap;\n//\n///**\n// * base quartz scheduler util\n// * @author xuxueli 2015-12-19 16:13:53\n// */\n//public final class XxlJobDynamicScheduler {\n//    private static final Logger logger = LoggerFactory.getLogger(XxlJobDynamicScheduler_old.class);\n//\n//    // ---------------------- param ----------------------\n//\n//    // scheduler\n//    private static Scheduler scheduler;\n//    public void setScheduler(Scheduler scheduler) {\n//\t\tXxlJobDynamicScheduler_old.scheduler = scheduler;\n//\t}\n//\n//\n//    // ---------------------- init + destroy ----------------------\n//    public void start() throws Exception {\n//        // valid\n//        Assert.notNull(scheduler, \"quartz scheduler is null\");\n//\n//        // init i18n\n//        initI18n();\n//\n//        // admin registry monitor run\n//        JobRegistryMonitorHelper.getInstance().start();\n//\n//        // admin monitor run\n//        JobFailMonitorHelper.getInstance().start();\n//\n//        // admin-server\n//        initRpcProvider();\n//\n//        logger.info(\">>>>>>>>> init xxl-job admin success.\");\n//    }\n//\n//\n//    public void destroy() throws Exception {\n//        // admin trigger pool stop\n//        JobTriggerPoolHelper.toStop();\n//\n//        // admin registry stop\n//        JobRegistryMonitorHelper.getInstance().toStop();\n//\n//        // admin monitor stop\n//        JobFailMonitorHelper.getInstance().toStop();\n//\n//        // admin-server\n//        stopRpcProvider();\n//    }\n//\n//\n//    // ---------------------- I18n ----------------------\n//\n//    private void initI18n(){\n//        for (ExecutorBlockStrategyEnum item:ExecutorBlockStrategyEnum.values()) {\n//            item.setTitle(I18nUtil.getString(\"jobconf_block_\".concat(item.name())));\n//        }\n//    }\n//\n//\n//    // ---------------------- admin rpc provider (no server version) ----------------------\n//    private static ServletServerHandler servletServerHandler;\n//    private void initRpcProvider(){\n//        // init\n//        XxlRpcProviderFactory xxlRpcProviderFactory = new XxlRpcProviderFactory();\n//        xxlRpcProviderFactory.initConfig(\n//                NetEnum.NETTY_HTTP,\n//                Serializer.SerializeEnum.HESSIAN.getSerializer(),\n//                null,\n//                0,\n//                XxlJobAdminConfig.getAdminConfig().getAccessToken(),\n//                null,\n//                null);\n//\n//        // add services\n//        xxlRpcProviderFactory.addService(AdminBiz.class.getName(), null, XxlJobAdminConfig.getAdminConfig().getAdminBiz());\n//\n//        // servlet handler\n//        servletServerHandler = new ServletServerHandler(xxlRpcProviderFactory);\n//    }\n//    private void stopRpcProvider() throws Exception {\n//        XxlRpcInvokerFactory.getInstance().stop();\n//    }\n//    public static void invokeAdminService(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {\n//        servletServerHandler.handle(null, request, response);\n//    }\n//\n//\n//    // ---------------------- executor-client ----------------------\n//    private static ConcurrentHashMap<String, ExecutorBiz> executorBizRepository = new ConcurrentHashMap<String, ExecutorBiz>();\n//    public static ExecutorBiz getExecutorBiz(String address) throws Exception {\n//        // valid\n//        if (address==null || address.trim().length()==0) {\n//            return null;\n//        }\n//\n//        // load-cache\n//        address = address.trim();\n//        ExecutorBiz executorBiz = executorBizRepository.get(address);\n//        if (executorBiz != null) {\n//            return executorBiz;\n//        }\n//\n//        // set-cache\n//        executorBiz = (ExecutorBiz) new XxlRpcReferenceBean(\n//                NetEnum.NETTY_HTTP,\n//                Serializer.SerializeEnum.HESSIAN.getSerializer(),\n//                CallType.SYNC,\n//                LoadBalance.ROUND,\n//                ExecutorBiz.class,\n//                null,\n//                5000,\n//                address,\n//                XxlJobAdminConfig.getAdminConfig().getAccessToken(),\n//                null,\n//                null).getObject();\n//\n//        executorBizRepository.put(address, executorBiz);\n//        return executorBiz;\n//    }\n//\n//\n//    // ---------------------- schedule util ----------------------\n//\n//    /**\n//     * fill job info\n//     *\n//     * @param jobInfo\n//     */\n//\tpublic static void fillJobInfo(XxlJobInfo jobInfo) {\n//\n//        String name = String.valueOf(jobInfo.getId());\n//\n//        // trigger key\n//        TriggerKey triggerKey = TriggerKey.triggerKey(name);\n//        try {\n//\n//            // trigger cron\n//\t\t\tTrigger trigger = scheduler.getTrigger(triggerKey);\n//\t\t\tif (trigger!=null && trigger instanceof CronTriggerImpl) {\n//\t\t\t\tString cronExpression = ((CronTriggerImpl) trigger).getCronExpression();\n//\t\t\t\tjobInfo.setJobCron(cronExpression);\n//\t\t\t}\n//\n//            // trigger state\n//            TriggerState triggerState = scheduler.getTriggerState(triggerKey);\n//\t\t\tif (triggerState!=null) {\n//\t\t\t\tjobInfo.setJobStatus(triggerState.name());\n//\t\t\t}\n//\n//            //JobKey jobKey = new JobKey(jobInfo.getJobName(), String.valueOf(jobInfo.getJobGroup()));\n//            //JobDetail jobDetail = scheduler.getJobDetail(jobKey);\n//            //String jobClass = jobDetail.getJobClass().getName();\n//\n//\t\t} catch (SchedulerException e) {\n//\t\t\tlogger.error(e.getMessage(), e);\n//\t\t}\n//\t}\n//\n//\n//    /**\n//     * add trigger + job\n//     *\n//     * @param jobName\n//     * @param cronExpression\n//     * @return\n//     * @throws SchedulerException\n//     */\n//\tpublic static boolean addJob(String jobName, String cronExpression) throws SchedulerException {\n//    \t// 1、job key\n//        TriggerKey triggerKey = TriggerKey.triggerKey(jobName);\n//        JobKey jobKey = new JobKey(jobName);\n//\n//        // 2、valid\n//        if (scheduler.checkExists(triggerKey)) {\n//            return true;    // PASS\n//        }\n//\n//        // 3、corn trigger\n//        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing();   // withMisfireHandlingInstructionDoNothing 忽略掉调度终止过程中忽略的调度\n//        CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(cronScheduleBuilder).build();\n//\n//        // 4、job detail\n//\t\tClass<? extends Job> jobClass_ = RemoteHttpJobBean.class;   // Class.forName(jobInfo.getJobClass());\n//\t\tJobDetail jobDetail = JobBuilder.newJob(jobClass_).withIdentity(jobKey).build();\n//\n//        /*if (jobInfo.getJobData()!=null) {\n//        \tJobDataMap jobDataMap = jobDetail.getJobDataMap();\n//        \tjobDataMap.putAll(JacksonUtil.readValue(jobInfo.getJobData(), Map.class));\n//        \t// JobExecutionContext context.getMergedJobDataMap().get(\"mailGuid\");\n//\t\t}*/\n//\n//        // 5、schedule job\n//        Date date = scheduler.scheduleJob(jobDetail, cronTrigger);\n//\n//        logger.info(\">>>>>>>>>>> addJob success(quartz), jobDetail:{}, cronTrigger:{}, date:{}\", jobDetail, cronTrigger, date);\n//        return true;\n//    }\n//\n//\n//    /**\n//     * remove trigger + job\n//     *\n//     * @param jobName\n//     * @return\n//     * @throws SchedulerException\n//     */\n//    public static boolean removeJob(String jobName) throws SchedulerException {\n//\n//        JobKey jobKey = new JobKey(jobName);\n//        scheduler.deleteJob(jobKey);\n//\n//        /*TriggerKey triggerKey = TriggerKey.triggerKey(jobName);\n//        if (scheduler.checkExists(triggerKey)) {\n//            scheduler.unscheduleJob(triggerKey);    // trigger + job\n//        }*/\n//\n//        logger.info(\">>>>>>>>>>> removeJob success(quartz), jobKey:{}\", jobKey);\n//        return true;\n//    }\n//\n//\n//    /**\n//     * updateJobCron\n//     *\n//     * @param jobName\n//     * @param cronExpression\n//     * @return\n//     * @throws SchedulerException\n//     */\n//\tpublic static boolean updateJobCron(String jobName, String cronExpression) throws SchedulerException {\n//\n//        // 1、job key\n//        TriggerKey triggerKey = TriggerKey.triggerKey(jobName);\n//\n//        // 2、valid\n//        if (!scheduler.checkExists(triggerKey)) {\n//            return true;    // PASS\n//        }\n//\n//        CronTrigger oldTrigger = (CronTrigger) scheduler.getTrigger(triggerKey);\n//\n//        // 3、avoid repeat cron\n//        String oldCron = oldTrigger.getCronExpression();\n//        if (oldCron.equals(cronExpression)){\n//            return true;    // PASS\n//        }\n//\n//        // 4、new cron trigger\n//        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing();\n//        oldTrigger = oldTrigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(cronScheduleBuilder).build();\n//\n//        // 5、rescheduleJob\n//        scheduler.rescheduleJob(triggerKey, oldTrigger);\n//\n//        /*\n//        JobKey jobKey = new JobKey(jobName);\n//\n//        // old job detail\n//        JobDetail jobDetail = scheduler.getJobDetail(jobKey);\n//\n//        // new trigger\n//        HashSet<Trigger> triggerSet = new HashSet<Trigger>();\n//        triggerSet.add(cronTrigger);\n//        // cover trigger of job detail\n//        scheduler.scheduleJob(jobDetail, triggerSet, true);*/\n//\n//        logger.info(\">>>>>>>>>>> resumeJob success, JobName:{}\", jobName);\n//        return true;\n//    }\n//\n//\n//    /**\n//     * pause\n//     *\n//     * @param jobName\n//     * @return\n//     * @throws SchedulerException\n//     */\n//    /*public static boolean pauseJob(String jobName) throws SchedulerException {\n//\n//    \tTriggerKey triggerKey = TriggerKey.triggerKey(jobName);\n//\n//        boolean result = false;\n//        if (scheduler.checkExists(triggerKey)) {\n//            scheduler.pauseTrigger(triggerKey);\n//            result =  true;\n//        }\n//\n//        logger.info(\">>>>>>>>>>> pauseJob {}, triggerKey:{}\", (result?\"success\":\"fail\"),triggerKey);\n//        return result;\n//    }*/\n//\n//\n//    /**\n//     * resume\n//     *\n//     * @param jobName\n//     * @return\n//     * @throws SchedulerException\n//     */\n//    /*public static boolean resumeJob(String jobName) throws SchedulerException {\n//\n//        TriggerKey triggerKey = TriggerKey.triggerKey(jobName);\n//\n//        boolean result = false;\n//        if (scheduler.checkExists(triggerKey)) {\n//            scheduler.resumeTrigger(triggerKey);\n//            result = true;\n//        }\n//\n//        logger.info(\">>>>>>>>>>> resumeJob {}, triggerKey:{}\", (result?\"success\":\"fail\"), triggerKey);\n//        return result;\n//    }*/\n//\n//\n//    /**\n//     * run\n//     *\n//     * @param jobName\n//     * @return\n//     * @throws SchedulerException\n//     */\n//    /*public static boolean triggerJob(String jobName) throws SchedulerException {\n//    \t// TriggerKey : name + group\n//    \tJobKey jobKey = new JobKey(jobName);\n//        TriggerKey triggerKey = TriggerKey.triggerKey(jobName);\n//\n//        boolean result = false;\n//        if (scheduler.checkExists(triggerKey)) {\n//            scheduler.triggerJob(jobKey);\n//            result = true;\n//            logger.info(\">>>>>>>>>>> runJob success, jobKey:{}\", jobKey);\n//        } else {\n//        \tlogger.info(\">>>>>>>>>>> runJob fail, jobKey:{}\", jobKey);\n//        }\n//        return result;\n//    }*/\n//\n//\n//    /**\n//     * finaAllJobList\n//     *\n//     * @return\n//     *//*\n//    @Deprecated\n//    public static List<Map<String, Object>> finaAllJobList(){\n//        List<Map<String, Object>> jobList = new ArrayList<Map<String,Object>>();\n//\n//        try {\n//            if (scheduler.getJobGroupNames()==null || scheduler.getJobGroupNames().size()==0) {\n//                return null;\n//            }\n//            String groupName = scheduler.getJobGroupNames().get(0);\n//            Set<JobKey> jobKeys = scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName));\n//            if (jobKeys!=null && jobKeys.size()>0) {\n//                for (JobKey jobKey : jobKeys) {\n//                    TriggerKey triggerKey = TriggerKey.triggerKey(jobKey.getName(), Scheduler.DEFAULT_GROUP);\n//                    Trigger trigger = scheduler.getTrigger(triggerKey);\n//                    JobDetail jobDetail = scheduler.getJobDetail(jobKey);\n//                    TriggerState triggerState = scheduler.getTriggerState(triggerKey);\n//                    Map<String, Object> jobMap = new HashMap<String, Object>();\n//                    jobMap.put(\"TriggerKey\", triggerKey);\n//                    jobMap.put(\"Trigger\", trigger);\n//                    jobMap.put(\"JobDetail\", jobDetail);\n//                    jobMap.put(\"TriggerState\", triggerState);\n//                    jobList.add(jobMap);\n//                }\n//            }\n//\n//        } catch (SchedulerException e) {\n//            logger.error(e.getMessage(), e);\n//            return null;\n//        }\n//        return jobList;\n//    }*/\n//\n//}"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/util/old/XxlJobThreadPool.java",
    "content": "//package com.xxl.job.admin.core.quartz;\n//\n//import org.quartz.SchedulerConfigException;\n//import org.quartz.spi.ThreadPool;\n//\n///**\n// * single thread pool, for async trigger\n// *\n// * @author xuxueli 2019-03-06\n// */\n//public class XxlJobThreadPool implements ThreadPool {\n//\n//    @Override\n//    public boolean runInThread(Runnable runnable) {\n//\n//        // async run\n//        runnable.run();\n//        return true;\n//\n//        //return false;\n//    }\n//\n//    @Override\n//    public int blockForAvailableThreads() {\n//        return 1;\n//    }\n//\n//    @Override\n//    public void initialize() throws SchedulerConfigException {\n//\n//    }\n//\n//    @Override\n//    public void shutdown(boolean waitForJobsToComplete) {\n//\n//    }\n//\n//    @Override\n//    public int getPoolSize() {\n//        return 1;\n//    }\n//\n//    @Override\n//    public void setInstanceId(String schedInstId) {\n//\n//    }\n//\n//    @Override\n//    public void setInstanceName(String schedName) {\n//\n//    }\n//\n//    // support\n//    public void setThreadCount(int count) {\n//        //\n//    }\n//\n//}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/web/error/WebErrorPageRegistrar.java",
    "content": "package com.xxl.job.admin.web.error;\n\nimport org.springframework.boot.web.error.ErrorPage;\nimport org.springframework.boot.web.error.ErrorPageRegistrar;\nimport org.springframework.boot.web.error.ErrorPageRegistry;\nimport org.springframework.stereotype.Component;\n\n/**\n * error page\n */\n@Component\npublic class WebErrorPageRegistrar implements ErrorPageRegistrar {\n\n    @Override\n    public void registerErrorPages(ErrorPageRegistry registry) {\n        ErrorPage errorPage = new ErrorPage(\"/errorpage\");\n        registry.addErrorPages(errorPage);\n    }\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/web/error/WebHandlerExceptionResolver.java",
    "content": "package com.xxl.job.admin.web.error;\n\nimport com.xxl.job.admin.scheduler.exception.XxlJobException;\nimport com.xxl.tool.json.GsonTool;\nimport com.xxl.tool.response.Response;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.stereotype.Component;\nimport org.springframework.web.bind.annotation.ResponseBody;\nimport org.springframework.web.method.HandlerMethod;\nimport org.springframework.web.servlet.HandlerExceptionResolver;\nimport org.springframework.web.servlet.ModelAndView;\n\nimport java.io.IOException;\n\n/**\n * common exception resolver\n *\n * @author xuxueli 2016-1-6 19:22:18\n */\n@Component\npublic class WebHandlerExceptionResolver implements HandlerExceptionResolver {\n\tprivate static transient Logger logger = LoggerFactory.getLogger(WebHandlerExceptionResolver.class);\n\n\t@Override\n\tpublic ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {\n\n\t\tif (!(ex instanceof XxlJobException)) {\n\t\t\tlogger.error(\"WebExceptionResolver:{}\", ex);\n\t\t}\n\n\t\t// parse isJson\n\t\tboolean isJson = false;\n\t\tif (handler instanceof HandlerMethod) {\n\t\t\tHandlerMethod method = (HandlerMethod)handler;\n\t\t\tisJson = method.getMethodAnnotation(ResponseBody.class)!=null;\n\t\t}\n\n\t\t// process error\n\t\tModelAndView mv = new ModelAndView();\n\t\tif (isJson) {\n\t\t\ttry {\n\t\t\t\t// errorMsg\n\t\t\t\tString errorMsg = GsonTool.toJson(Response.ofFail(ex.toString()));\n\n\t\t\t\t// write response\n\t\t\t\tresponse.setStatus(HttpServletResponse.SC_OK);\n\t\t\t\tresponse.setContentType(\"application/json;charset=UTF-8\");\n\t\t\t\tresponse.getWriter().println(errorMsg);\n\t\t\t} catch (IOException e) {\n\t\t\t\tlogger.error(e.getMessage(), e);\n\t\t\t}\n\t\t\treturn mv;\n\t\t} else {\n\n\t\t\tmv.addObject(\"exceptionMsg\", ex.toString());\n\t\t\tmv.setViewName(\"common/common.errorpage\");\n\t\t\treturn mv;\n\t\t}\n\n\t}\n\t\n}"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/web/xxlsso/SimpleLoginStore.java",
    "content": "package com.xxl.job.admin.web.xxlsso;\n\nimport com.xxl.job.admin.constant.Consts;\nimport com.xxl.job.admin.mapper.XxlJobUserMapper;\nimport com.xxl.job.admin.model.XxlJobUser;\nimport com.xxl.sso.core.model.LoginInfo;\nimport com.xxl.sso.core.store.LoginStore;\nimport com.xxl.tool.core.MapTool;\nimport com.xxl.tool.response.Response;\nimport jakarta.annotation.Resource;\nimport org.springframework.stereotype.Component;\n\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * Simple LoginStore\n *\n * 1、store by database；\n * 2、If you have higher performance requirements, it is recommended to use RedisLoginStore；\n *\n * @author xuxueli 2025-08-03\n */\n@Component\npublic class SimpleLoginStore implements LoginStore {\n\n\n    @Resource\n    private XxlJobUserMapper xxlJobUserMapper;\n\n\n    @Override\n    public Response<String> set(LoginInfo loginInfo) {\n\n        // parse token-signature\n        String token_sign = loginInfo.getSignature();\n\n        // write token by UserId\n        int ret = xxlJobUserMapper.updateToken(Integer.parseInt(loginInfo.getUserId()), token_sign);\n        return ret > 0 ? Response.ofSuccess() : Response.ofFail(\"token set fail\");\n    }\n\n    @Override\n    public Response<String> update(LoginInfo loginInfo) {\n        return Response.ofFail(\"not support\");\n    }\n\n    @Override\n    public Response<String> remove(String userId) {\n        // delete token-signature\n        int ret = xxlJobUserMapper.updateToken(Integer.parseInt(userId), \"\");\n        return ret > 0 ? Response.ofSuccess() : Response.ofFail(\"token remove fail\");\n    }\n\n    /**\n     * check through DB query\n     */\n    @Override\n    public Response<LoginInfo> get(String userId) {\n\n        // load login-user\n        XxlJobUser user = xxlJobUserMapper.loadById(Integer.parseInt(userId));\n        if (user == null) {\n            return Response.ofFail(\"userId invalid.\");\n        }\n\n        // parse role\n        List<String> roleList = user.getRole()==1? List.of(Consts.ADMIN_ROLE):null;\n\n        // parse jobGroup permission\n        Map<String, String> extraInfo = MapTool.newMap(\n                \"jobGroups\", user.getPermission()\n        );\n\n        // build LoginInfo\n        LoginInfo loginInfo = new LoginInfo(userId, user.getToken());\n        loginInfo.setUserName(user.getUsername());\n        loginInfo.setRoleList(roleList);\n        loginInfo.setExtraInfo(extraInfo);\n\n        return Response.ofSuccess(loginInfo);\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/java/com/xxl/job/admin/web/xxlsso/XxlSsoConfig.java",
    "content": "package com.xxl.job.admin.web.xxlsso;\n\nimport com.xxl.sso.core.auth.interceptor.XxlSsoWebInterceptor;\nimport com.xxl.sso.core.bootstrap.XxlSsoBootstrap;\nimport jakarta.annotation.Resource;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.servlet.config.annotation.InterceptorRegistry;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurer;\n\n/**\n * @author xuxueli 2018-11-15\n */\n@Configuration\npublic class XxlSsoConfig implements WebMvcConfigurer {\n\n\n    @Value(\"${xxl-sso.token.key}\")\n    private String tokenKey;\n\n    @Value(\"${xxl-sso.token.timeout}\")\n    private long tokenTimeout;\n\n    @Value(\"${xxl-sso.client.excluded.paths}\")\n    private String excludedPaths;\n\n    @Value(\"${xxl-sso.client.login.path}\")\n    private String loginPath;\n\n\n    @Resource\n    private SimpleLoginStore loginStore;\n\n\n    /**\n     * 1、配置 XxlSsoBootstrap\n     */\n    @Bean(initMethod = \"start\", destroyMethod = \"stop\")\n    public XxlSsoBootstrap xxlSsoBootstrap() {\n\n        XxlSsoBootstrap bootstrap = new XxlSsoBootstrap();\n        bootstrap.setLoginStore(loginStore);\n        bootstrap.setTokenKey(tokenKey);\n        bootstrap.setTokenTimeout(tokenTimeout);\n        return bootstrap;\n    }\n\n    /**\n     * 2、配置 XxlSso 拦截器\n     */\n    @Override\n    public void addInterceptors(InterceptorRegistry registry) {\n\n        // 2.1、build xxl-sso interceptor\n        XxlSsoWebInterceptor webInterceptor = new XxlSsoWebInterceptor(excludedPaths, loginPath);\n\n        // 2.2、add interceptor\n        registry.addInterceptor(webInterceptor).addPathPatterns(\"/**\");\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/resources/application.properties",
    "content": "### web\nserver.port=8080\nserver.servlet.context-path=/xxl-job-admin\n\n### actuator\nmanagement.endpoints.web.base-path=/actuator\nmanagement.health.mail.enabled=false\n\n### resources\nspring.mvc.servlet.load-on-startup=0\nspring.mvc.static-path-pattern=/static/**\nspring.web.resources.static-locations=classpath:/static/\n\n### freemarker\nspring.freemarker.templateLoaderPath=classpath:/templates/\nspring.freemarker.suffix=.ftl\nspring.freemarker.charset=UTF-8\nspring.freemarker.request-context-attribute=request\nspring.freemarker.settings.number_format=0.##########\nspring.freemarker.settings.new_builtin_class_resolver=safer\n\n### mybatis\nmybatis.mapper-locations=classpath:/mapper/*Mapper.xml\n\n### datasource-pool\nspring.datasource.type=com.zaxxer.hikari.HikariDataSource\nspring.datasource.hikari.minimum-idle=10\nspring.datasource.hikari.maximum-pool-size=30\nspring.datasource.hikari.auto-commit=true\nspring.datasource.hikari.idle-timeout=30000\nspring.datasource.hikari.pool-name=HikariCP\nspring.datasource.hikari.max-lifetime=900000\nspring.datasource.hikari.connection-timeout=10000\nspring.datasource.hikari.connection-test-query=SELECT 1\nspring.datasource.hikari.validation-timeout=1000\n\n### xxl-job, datasource\nspring.datasource.url=jdbc:mysql://127.0.0.1:3306/xxl_job?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai\nspring.datasource.username=root\nspring.datasource.password=root_pwd\nspring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver\n\n### xxl-job, email\nspring.mail.host=smtp.qq.com\nspring.mail.port=25\nspring.mail.username=xxx@qq.com\nspring.mail.from=xxx@qq.com\nspring.mail.password=xxx\nspring.mail.properties.mail.smtp.auth=true\nspring.mail.properties.mail.smtp.starttls.enable=true\nspring.mail.properties.mail.smtp.starttls.required=true\nspring.mail.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory\n\n### xxl-job, access token\nxxl.job.accessToken=default_token\n\n### xxl-job, timeout by second, default 3s\nxxl.job.timeout=3\n\n### xxl-job, i18n (default is zh_CN, and you can choose \"zh_CN\", \"zh_TC\" and \"en\")\nxxl.job.i18n=zh_CN\n\n## xxl-job, triggerpool max size\nxxl.job.triggerpool.fast.max=300\nxxl.job.triggerpool.slow.max=200\n\n### xxl-job, log retention days\nxxl.job.logretentiondays=30\n\n### xxl-sso\nxxl-sso.token.key=xxl_job_login_token\nxxl-sso.token.timeout=604800000\nxxl-sso.client.excluded.paths=\nxxl-sso.client.login.path=/auth/login\n"
  },
  {
    "path": "xxl-job-admin/src/main/resources/i18n/message_en.properties",
    "content": "admin_name=Scheduling Center\nadmin_name_full=Distributed Task Scheduling Platform｜XXL-JOB\nadmin_version=3.4.0-SNAPSHOT\nadmin_i18n=en\n\n## system\nsystem_tips=System message\nsystem_ok=Confirm \nsystem_close=Close\nsystem_save=Save \nsystem_cancel=Cancel\nsystem_search=Search\nsystem_reset=Reset\nsystem_status=Status\nsystem_opt=Operate\nsystem_opt_add=Add\nsystem_please_input=please input \nsystem_please_choose=please choose \nsystem_success=success\nsystem_fail=fail\nsystem_error=error\nsystem_all=All\nsystem_show=Show\nsystem_empty=Empty\nsystem_opt_suc=operate success\nsystem_opt_fail=operate fail\nsystem_opt_edit=Edit\nsystem_opt_del=Delete\nsystem_opt_copy=Copy\nsystem_unvalid=illegal\nsystem_not_found=not exist\nsystem_nav=Navigation\nsystem_digits=digits\nsystem_lengh_limit=Length limit\nsystem_permission_limit=Permission limit\nsystem_welcome=Welcome\nsystem_num_range=Numerical range limit\nsystem_one=One\nsystem_data=Data\nsystem_selected_nothing=No data selected\n\n## tab\ntab_opt=Tab Operation\ntab_close_current=Close Current Tabs\ntab_close_other=Close Other Tabs\ntab_close_all=Close All Tabs\ntab_refresh=Refresh Tab\n\n## daterangepicker\ndaterangepicker_ranges_today=today\ndaterangepicker_ranges_yesterday=yesterday\ndaterangepicker_ranges_this_month=this month\ndaterangepicker_ranges_last_month=last month\ndaterangepicker_ranges_recent_week=recent one week\ndaterangepicker_ranges_recent_month=recent one month\ndaterangepicker_custom_name=custom\ndaterangepicker_custom_starttime=start time\ndaterangepicker_custom_endtime=end time\ndaterangepicker_custom_daysofweek=Sun,Mon,Tue,Wed,Thu,Fri,Sat\ndaterangepicker_custom_monthnames=Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec\n\n## login\nlogin_btn=Login\nlogin_remember_me=Remember Me\nlogin_username_placeholder=Please enter username\nlogin_password_placeholder=Please enter password\nlogin_username_empty=Please enter username\nlogin_username_lt_4=Username length should not be less than 4\nlogin_password_empty=Please enter password\nlogin_password_lt_4=Password length should not be less than 4\nlogin_success=Login success\nlogin_fail=Login fail\nlogin_param_empty=Username or password is empty\nlogin_param_unvalid=Username or password error\n\n## logout\nlogout_btn=Logout\nlogout_confirm=Confirm logout?\nlogout_success=Logout success\nlogout_fail=Logout fail\n\n## change pwd\nchange_pwd=Change password\nchange_pwd_suc_to_logout=Change password successful, about to log out login\nchange_pwd_field_oldpwd=old password\nchange_pwd_field_newpwd=new password\n\n## change skin\nchange_skin=Change Theme\n\n## help\nadmin_help=User Guide\nadmin_help_document=Official Documentation\n\n## dashboard\njob_dashboard_name=Run report\njob_dashboard_job_num=Job number\njob_dashboard_job_num_tip=The number of tasks running in the scheduling center\njob_dashboard_trigger_num=trigger number\njob_dashboard_trigger_num_tip=The number of trigger record scheduled by the scheduling center\njob_dashboard_jobgroup_num=Executor number\njob_dashboard_jobgroup_num_tip=The number of online executor machines perceived by the scheduling center\njob_dashboard_report=Scheduling report\njob_dashboard_report_loaddata_fail=Scheduling report load data error\njob_dashboard_date_report=Date distribution\njob_dashboard_rate_report=Percentage distribution\n\n## job info\njobinfo_name=Job Manage\njobinfo_job=Job\njobinfo_field_add=Add Job\njobinfo_field_update=Edit Job\njobinfo_field_id=Job ID\njobinfo_field_jobgroup=Executor\njobinfo_field_jobdesc=Job description\njobinfo_field_timeout=Job timeout period\njobinfo_field_gluetype=GLUE Type\njobinfo_field_executorparam=Param\njobinfo_field_author=Author\njobinfo_field_alarmemail=Alarm email\njobinfo_field_alarmemail_placeholder=Please enter alarm mail, if there are more than one comma separated\njobinfo_field_executorRouteStrategy=Route Strategy\njobinfo_field_childJobId=Child Job ID\njobinfo_field_childJobId_placeholder=Please enter the Child job ID, if there are more than one comma separated\njobinfo_field_executorBlockStrategy=Block Strategy\njobinfo_field_executorFailRetryCount=Fail Retry Count\njobinfo_field_executorFailRetryCount_placeholder=Fail Retry Count. effect if greater than zero\njobinfo_script_location=Script location\njobinfo_shard_index=Shard index\njobinfo_shard_total=Shard total\njobinfo_opt_stop=Stop\njobinfo_opt_start=Start\njobinfo_opt_log=Query Log\njobinfo_opt_run=Run Once\njobinfo_opt_run_tips=Please input the address for this trigger. Null will be obtained from the executor\njobinfo_opt_registryinfo=Registry Info\njobinfo_opt_next_time=Next trigger time\njobinfo_glue_source=GLUE Source\njobinfo_glue_remark=Resource Remark\njobinfo_glue_remark_limit=Resource Remark length is limited to 4~100\njobinfo_glue_rollback=Version Backtrack\njobinfo_glue_jobid_unvalid=Job ID is illegal\njobinfo_glue_gluetype_unvalid=The job is not GLUE Type\njobinfo_field_executorTimeout_placeholder=Job Timeout period，in seconds. effect if greater than zero\nschedule_type=Schedule Type\nschedule_type_none=None\nschedule_type_cron=Cron\nschedule_type_fix_rate=Fix rate\nschedule_type_fix_delay=Fix delay\nschedule_type_none_limit_start=The current schedule type disables startup\nmisfire_strategy=Misfire strategy\nmisfire_strategy_do_nothing=Do nothing\nmisfire_strategy_fire_once_now=Fire once now\njobinfo_conf_base=Base configuration\njobinfo_conf_schedule=Schedule configuration\njobinfo_conf_job=Job configuration\njobinfo_conf_advanced=Advanced configuration\n\n## job log\njoblog_name=Trigger Log\njoblog_status=Status\njoblog_status_all=All\njoblog_status_suc=Success\njoblog_status_fail=Fail\njoblog_status_running=Running\njoblog_field_triggerTime=Trigger Time\njoblog_field_triggerCode=Trigger Result\njoblog_field_triggerMsg=Trigger Msg\njoblog_field_handleTime=Handle Time\njoblog_field_handleCode=Handle Result\njoblog_field_handleMsg=Trigger Msg\njoblog_field_executorAddress=Executor Address\njoblog_clean=Clean\njoblog_clean_log=Clean Log\njoblog_clean_type=Clean Type\njoblog_clean_type_1=Clean up log data a month ago\njoblog_clean_type_2=Clean up log data three month ago\njoblog_clean_type_3=Clean up log data six month ago\njoblog_clean_type_4=Clean up log data a year ago\njoblog_clean_type_5=Clean up log data a thousand record ago\njoblog_clean_type_6=Clean up log data ten thousand record ago\njoblog_clean_type_7=Clean up log data thirty thousand record ago\njoblog_clean_type_8=Clean up log data hundred thousand record ago\njoblog_clean_type_9=Clean up all log data\njoblog_clean_type_unvalid=Clean type is illegal\njoblog_handleCode_200=Success\njoblog_handleCode_500=Fail\njoblog_handleCode_502=Timeout\njoblog_kill_log=Kill Job\njoblog_kill_log_limit=Trigger Fail, can not kill job\njoblog_kill_log_byman=Manual operation, kill job\njoblog_lost_fail=Job result lost, marked as failure\njoblog_rolling_log=Rolling log\njoblog_rolling_log_refresh=Refresh \njoblog_rolling_log_triggerfail=The job trigger fail, can not view the rolling log\njoblog_rolling_log_failoften=The request for the Rolling log is terminated, the number of failed requests exceeds the limit, Reload the log on the refresh page\njoblog_logid_unvalid=Log ID is illegal\n\n## job group\njobgroup_name=Executor Manage\njobgroup_list=Executor List\njobgroup_add=Add Executor\njobgroup_edit=Edit Executor\njobgroup_del=Delete Executor\njobgroup_field_title=Title\njobgroup_field_addressType=Registry Type\njobgroup_field_addressType_0=Automatic registration\njobgroup_field_addressType_1=Manual registration\njobgroup_field_addressType_limit=Manually registration type, the machine address must not be empty\njobgroup_field_registryList=machine address\njobgroup_field_registryList_unvalid=registry machine address is illegal\njobgroup_field_registryList_placeholder=Please enter the machine address, if there are more than one comma separated\njobgroup_field_appname_limit=Limit the beginning of a lowercase letter, consists of lowercase letters、number and hyphen.\njobgroup_field_appname_length=AppName length is limited to 4~64\njobgroup_field_title_length=Title length is limited to 4~12\njobgroup_field_order_digits=Please enter a positive integer\njobgroup_field_orderrange=Order is limited to 1~1000\njobgroup_del_limit_0=Refuse to delete, the executor is being used\njobgroup_del_limit_1=Refuses to delete, the system retains at least one executor\njobgroup_empty=There is no valid executor. Please contact the administrator\n\n## job conf\njobconf_block_SERIAL_EXECUTION=Serial execution\njobconf_block_DISCARD_LATER=Discard Later\njobconf_block_COVER_EARLY=Cover Early\njobconf_route_first=First\njobconf_route_last=Last\njobconf_route_round=Round\njobconf_route_random=Random\njobconf_route_consistenthash=Consistent Hash\njobconf_route_lfu=Least Frequently Used\njobconf_route_lru=Least Recently Used\njobconf_route_failover=Failover\njobconf_route_busyover=Busyover\njobconf_route_shard=Sharding Broadcast\njobconf_idleBeat=Idle check\njobconf_beat=Heartbeats\njobconf_monitor=Task Scheduling Center monitor alarm\njobconf_monitor_detail=monitor alarm details\njobconf_monitor_alarm_title=Alarm Type\njobconf_monitor_alarm_type=Trigger Fail\njobconf_monitor_alarm_content=Alarm Content\njobconf_trigger_admin_adress=Trigger machine address\njobconf_trigger_exe_regtype=Execotor-Registry Type\njobconf_trigger_exe_regaddress=Execotor-Registry Address\njobconf_trigger_address_empty=Trigger Fail：registry address is empty\njobconf_trigger_run=Trigger Job\njobconf_trigger_child_run=Trigger child job\njobconf_callback_child_msg1={0}/{1} [Job ID={2}], Trigger {3}, Trigger msg: {4} <br>\njobconf_callback_child_msg2={0}/{1} [Job ID={2}], Trigger Fail, Trigger msg: Job ID is illegal <br>\njobconf_trigger_type=Job trigger type\njobconf_trigger_type_cron=Cron trigger\njobconf_trigger_type_manual=Manual trigger\njobconf_trigger_type_parent=Parent job trigger\njobconf_trigger_type_api=Api trigger\njobconf_trigger_type_retry=Fail retry trigger\njobconf_trigger_type_misfire=Misfire compensation trigger\n\n## user\nuser_manage=User Manage\nuser_username=Username\nuser_password=Password\nuser_role=Role\nuser_role_admin=Admin User\nuser_role_normal=Normal User\nuser_permission=Permission\nuser_add=Add User\nuser_update=Edit User\nuser_username_repeat=Username Repeat\nuser_username_valid=Restrictions start with a lowercase letter and consist of lowercase letters and Numbers\nuser_password_update_placeholder=Please input password, empty means not update\nuser_update_loginuser_limit=Operation of current login account is not allowed\n"
  },
  {
    "path": "xxl-job-admin/src/main/resources/i18n/message_zh_CN.properties",
    "content": "admin_name=任务调度中心\nadmin_name_full=分布式任务调度平台｜XXL-JOB\nadmin_version=3.4.0-SNAPSHOT\nadmin_i18n=\n\n## system\nsystem_tips=系统提示\nsystem_ok=确定\nsystem_close=关闭\nsystem_save=保存\nsystem_cancel=取消\nsystem_search=搜索\nsystem_reset=重置\nsystem_status=状态\nsystem_opt=操作\nsystem_opt_add=新增\nsystem_please_input=请输入\nsystem_please_choose=请选择\nsystem_success=成功\nsystem_fail=失败\nsystem_error=错误\nsystem_all=全部\nsystem_show=查看\nsystem_empty=无\nsystem_opt_suc=操作成功\nsystem_opt_fail=操作失败\nsystem_opt_edit=编辑\nsystem_opt_del=删除\nsystem_opt_copy=复制\nsystem_unvalid=非法\nsystem_not_found=不存在\nsystem_nav=导航\nsystem_digits=整数\nsystem_lengh_limit=长度限制\nsystem_permission_limit=权限拦截\nsystem_welcome=欢迎\nsystem_num_range=数值范围限制\nsystem_one=一条\nsystem_data=数据\nsystem_selected_nothing=未选择\n\n## tab\ntab_opt=页签操作\ntab_close_current=关闭当前\ntab_close_other=关闭其他\ntab_close_all=全部关闭\ntab_refresh=刷新\n\n## daterangepicker\ndaterangepicker_ranges_today=今日\ndaterangepicker_ranges_yesterday=昨日\ndaterangepicker_ranges_this_month=本月\ndaterangepicker_ranges_last_month=上个月\ndaterangepicker_ranges_recent_week=最近一周\ndaterangepicker_ranges_recent_month=最近一月\ndaterangepicker_custom_name=自定义\ndaterangepicker_custom_starttime=起始时间\ndaterangepicker_custom_endtime=结束时间\ndaterangepicker_custom_daysofweek=日,一,二,三,四,五,六\ndaterangepicker_custom_monthnames=一月,二月,三月,四月,五月,六月,七月,八月,九月,十月,十一月,十二月\n\n## login\nlogin_btn=登录\nlogin_remember_me=记住密码\nlogin_username_placeholder=请输入登录账号\nlogin_password_placeholder=请输入登录密码\nlogin_username_empty=请输入登录账号\nlogin_username_lt_4=登录账号不应低于4位\nlogin_password_empty=请输入登录密码\nlogin_password_lt_4=登录密码不应低于4位\nlogin_success=登录成功\nlogin_fail=登录失败\nlogin_param_empty=账号或密码为空\nlogin_param_unvalid=账号或密码错误\n\n## logout\nlogout_btn=注销\nlogout_confirm=确认注销登录?\nlogout_success=注销成功\nlogout_fail=注销失败\n\n## change pwd\nchange_pwd=修改密码\nchange_pwd_suc_to_logout=修改密码成功，即将注销登陆\nchange_pwd_field_oldpwd=旧密码\nchange_pwd_field_newpwd=新密码\n\n## change skin\nchange_skin=切换主题\n\n## help\nadmin_help=使用教程\nadmin_help_document=官方文档\n\n## dashboard\njob_dashboard_name=运行报表\njob_dashboard_job_num=任务数量\njob_dashboard_job_num_tip=调度中心运行的任务数量\njob_dashboard_trigger_num=调度次数\njob_dashboard_trigger_num_tip=调度中心触发的调度次数\njob_dashboard_jobgroup_num=执行器数量\njob_dashboard_jobgroup_num_tip=调度中心在线的执行器机器数量\njob_dashboard_report=调度报表\njob_dashboard_report_loaddata_fail=调度报表数据加载异常\njob_dashboard_date_report=日期分布图\njob_dashboard_rate_report=成功比例图\n\n## job info\njobinfo_name=任务管理\njobinfo_job=任务\njobinfo_field_add=新增\njobinfo_field_update=更新任务\njobinfo_field_id=任务ID\njobinfo_field_jobgroup=执行器\njobinfo_field_jobdesc=任务描述\njobinfo_field_gluetype=运行模式\njobinfo_field_executorparam=任务参数\njobinfo_field_author=负责人\njobinfo_field_timeout=任务超时时间\njobinfo_field_alarmemail=报警邮件\njobinfo_field_alarmemail_placeholder=请输入报警邮件，多个邮件地址则逗号分隔\njobinfo_field_executorRouteStrategy=路由策略\njobinfo_field_childJobId=子任务ID\njobinfo_field_childJobId_placeholder=请输入子任务的任务ID,如存在多个则逗号分隔\njobinfo_field_executorBlockStrategy=阻塞处理策略\njobinfo_field_executorFailRetryCount=失败重试次数\njobinfo_field_executorFailRetryCount_placeholder=失败重试次数，大于零时生效\njobinfo_script_location=脚本位置\njobinfo_shard_index=分片序号\njobinfo_shard_total=分片总数\njobinfo_opt_stop=停止\njobinfo_opt_start=启动\njobinfo_opt_log=查询日志\njobinfo_opt_run=执行一次\njobinfo_opt_run_tips=请输入本次执行的机器地址，为空则从执行器获取\njobinfo_opt_registryinfo=注册节点\njobinfo_opt_next_time=下次执行时间\njobinfo_glue_source=GLUE源码\njobinfo_glue_remark=源码备注\njobinfo_glue_remark_limit=源码备注长度限制为4~100\njobinfo_glue_rollback=版本回溯\njobinfo_glue_jobid_unvalid=任务ID非法\njobinfo_glue_gluetype_unvalid=该任务非GLUE模式\njobinfo_field_executorTimeout_placeholder=任务超时时间，单位秒，大于零时生效\nschedule_type=调度类型\nschedule_type_none=无\nschedule_type_cron=CRON\nschedule_type_fix_rate=固定速度\nschedule_type_fix_delay=固定延迟\nschedule_type_none_limit_start=当前调度类型禁止启动\nmisfire_strategy=调度过期策略\nmisfire_strategy_do_nothing=忽略\nmisfire_strategy_fire_once_now=立即执行一次\njobinfo_conf_base=基础配置\njobinfo_conf_schedule=调度配置\njobinfo_conf_job=任务配置\njobinfo_conf_advanced=高级配置\n\n## job log\njoblog_name=调度日志\njoblog_status=状态\njoblog_status_all=全部\njoblog_status_suc=成功\njoblog_status_fail=失败\njoblog_status_running=进行中\njoblog_field_triggerTime=调度时间\njoblog_field_triggerCode=调度结果\njoblog_field_triggerMsg=调度备注\njoblog_field_handleTime=执行时间\njoblog_field_handleCode=执行结果\njoblog_field_handleMsg=执行备注\njoblog_field_executorAddress=执行器地址\njoblog_clean=清理\njoblog_clean_log=日志清理\njoblog_clean_type=清理方式\njoblog_clean_type_1=清理一个月之前日志数据\njoblog_clean_type_2=清理三个月之前日志数据\njoblog_clean_type_3=清理六个月之前日志数据\njoblog_clean_type_4=清理一年之前日志数据\njoblog_clean_type_5=清理一千条以前日志数据\njoblog_clean_type_6=清理一万条以前日志数据\njoblog_clean_type_7=清理三万条以前日志数据\njoblog_clean_type_8=清理十万条以前日志数据\njoblog_clean_type_9=清理所有日志数据\njoblog_clean_type_unvalid=清理类型参数异常\njoblog_handleCode_200=成功\njoblog_handleCode_500=失败\njoblog_handleCode_502=失败(超时)\njoblog_kill_log=终止任务\njoblog_kill_log_limit=调度失败，无法终止日志\njoblog_kill_log_byman=人为操作，主动终止\njoblog_lost_fail=任务结果丢失，标记失败\njoblog_rolling_log=执行日志\njoblog_rolling_log_refresh=刷新\njoblog_rolling_log_triggerfail=任务发起调度失败，无法查看执行日志\njoblog_rolling_log_failoften=终止请求Rolling日志,请求失败次数超上限,可刷新页面重新加载日志\njoblog_logid_unvalid=日志ID非法\n\n## job group\njobgroup_name=执行器管理\njobgroup_list=执行器列表\njobgroup_add=新增执行器\njobgroup_edit=编辑执行器\njobgroup_del=删除执行器\njobgroup_field_title=名称\njobgroup_field_addressType=注册方式\njobgroup_field_addressType_0=自动注册\njobgroup_field_addressType_1=手动录入\njobgroup_field_addressType_limit=手动录入注册方式，机器地址不可为空\njobgroup_field_registryList=机器地址\njobgroup_field_registryList_unvalid=机器地址格式非法\njobgroup_field_registryList_placeholder=请输入执行器地址列表，多地址逗号分隔\njobgroup_field_appname_limit=限制以小写字母开头，由小写字母、数字和中划线组成\njobgroup_field_appname_length=AppName长度限制为4~64\njobgroup_field_title_length=名称长度限制为4~12\njobgroup_field_order_digits=请输入整数\njobgroup_field_orderrange=取值范围为1~1000\njobgroup_del_limit_0=拒绝删除，该执行器使用中\njobgroup_del_limit_1=拒绝删除, 系统至少保留一个执行器\njobgroup_empty=不存在有效执行器,请联系管理员\n\n## job conf\njobconf_block_SERIAL_EXECUTION=单机串行\njobconf_block_DISCARD_LATER=丢弃后续调度\njobconf_block_COVER_EARLY=覆盖之前调度\njobconf_route_first=第一个\njobconf_route_last=最后一个\njobconf_route_round=轮询\njobconf_route_random=随机\njobconf_route_consistenthash=一致性HASH\njobconf_route_lfu=最不经常使用\njobconf_route_lru=最近最久未使用\njobconf_route_failover=故障转移\njobconf_route_busyover=忙碌转移\njobconf_route_shard=分片广播\njobconf_idleBeat=空闲检测\njobconf_beat=心跳检测\njobconf_monitor=任务调度中心监控报警\njobconf_monitor_detail=监控告警明细\njobconf_monitor_alarm_title=告警类型\njobconf_monitor_alarm_type=调度失败\njobconf_monitor_alarm_content=告警内容\njobconf_trigger_admin_adress=调度机器\njobconf_trigger_exe_regtype=执行器-注册方式\njobconf_trigger_exe_regaddress=执行器-地址列表\njobconf_trigger_address_empty=调度失败：执行器地址为空\njobconf_trigger_run=触发调度\njobconf_trigger_child_run=触发子任务\njobconf_callback_child_msg1={0}/{1} [任务ID={2}], 触发{3}, 触发备注: {4} <br>\njobconf_callback_child_msg2={0}/{1} [任务ID={2}], 触发失败, 触发备注: 任务ID格式错误 <br>\njobconf_trigger_type=任务触发类型\njobconf_trigger_type_cron=Cron触发\njobconf_trigger_type_manual=手动触发\njobconf_trigger_type_parent=父任务触发\njobconf_trigger_type_api=API触发\njobconf_trigger_type_retry=失败重试触发\njobconf_trigger_type_misfire=调度过期补偿\n\n## user\nuser_manage=用户管理\nuser_username=账号\nuser_password=密码\nuser_role=角色\nuser_role_admin=管理员\nuser_role_normal=普通用户\nuser_permission=权限\nuser_add=新增用户\nuser_update=更新用户\nuser_username_repeat=账号重复\nuser_username_valid=限制以小写字母开头，由小写字母、数字组成\nuser_password_update_placeholder=请输入新密码，为空则不更新密码\nuser_update_loginuser_limit=禁止操作当前登录账号\n"
  },
  {
    "path": "xxl-job-admin/src/main/resources/i18n/message_zh_TC.properties",
    "content": "admin_name=任務調度中心\nadmin_name_full=分布式任務調度平臺｜XXL-JOB\nadmin_version=3.4.0-SNAPSHOT\nadmin_i18n=\n\n## system\nsystem_tips=系統提示\nsystem_ok=確定\nsystem_close=關閉\nsystem_save=儲存\nsystem_cancel=取消\nsystem_search=搜尋\nsystem_reset=重置\nsystem_status=狀態\nsystem_opt=操作\nsystem_opt_add=新增\nsystem_please_input=請輸入\nsystem_please_choose=请選擇\nsystem_success=成功\nsystem_fail=失敗\nsystem_error=錯誤\nsystem_all=全部\nsystem_show=查看\nsystem_empty=無\nsystem_opt_suc=操作成功\nsystem_opt_fail=操作失敗\nsystem_opt_edit=編輯\nsystem_opt_del=刪除\nsystem_opt_copy=復制\nsystem_unvalid=非法\nsystem_not_found=不存在\nsystem_nav=導航\nsystem_digits=整數\nsystem_lengh_limit=長度限制\nsystem_permission_limit=權限控管\nsystem_welcome=歡迎\nsystem_num_range=數值範圍限制\nsystem_one=一條\nsystem_data=數據\nsystem_selected_nothing=请選擇\n\n## tab\ntab_opt=頁籤操作\ntab_close_current=關閉當前\ntab_close_other=關閉其他\ntab_close_all=全部關閉\ntab_refresh=刷新\n\n## daterangepicker\ndaterangepicker_ranges_today=今日\ndaterangepicker_ranges_yesterday=昨日\ndaterangepicker_ranges_this_month=本月\ndaterangepicker_ranges_last_month=上個月\ndaterangepicker_ranges_recent_week=最近一周\ndaterangepicker_ranges_recent_month=最近一月\ndaterangepicker_custom_name=自定義\ndaterangepicker_custom_starttime=起始時間\ndaterangepicker_custom_endtime=結束時間\ndaterangepicker_custom_daysofweek=日,一,二,三,四,五,六\ndaterangepicker_custom_monthnames=一月,二月,三月,四月,五月,六月,七月,八月,九月,十月,十一月,十二月\n\n## login\nlogin_btn=登入\nlogin_remember_me=記住密碼\nlogin_username_placeholder=請輸入登入帳號\nlogin_password_placeholder=請輸入登入密碼\nlogin_username_empty=請輸入登入帳號\nlogin_username_lt_4=登入帳號不應低於4位數\nlogin_password_empty=請輸入登入密碼\nlogin_password_lt_4=登入密碼不應低於4位數\nlogin_success=登入成功\nlogin_fail=登入失敗\nlogin_param_empty=帳號或密碼為空值\nlogin_param_unvalid=帳號或密碼錯誤\n\n## logout\nlogout_btn=登出\nlogout_confirm=確認登出?\nlogout_success=登出成功\nlogout_fail=登出失敗\n\n## change pwd\nchange_pwd=修改密碼\nchange_pwd_suc_to_logout=修改密碼成功，即將登出\nchange_pwd_field_oldpwd=舊密碼\nchange_pwd_field_newpwd=新密碼\n\n## change skin\nchange_skin=切換主題\n\n## help\nadmin_help=使用教程\nadmin_help_document=官方文檔\n\n## dashboard\njob_dashboard_name=運行報表\njob_dashboard_job_num=任務數量\njob_dashboard_job_num_tip=調度中心運行的任務數量\njob_dashboard_trigger_num=調度次數\njob_dashboard_trigger_num_tip=調度中心觸發的調度次數\njob_dashboard_jobgroup_num=執行器數量\njob_dashboard_jobgroup_num_tip=調度中心在線的執行器機器數量\njob_dashboard_report=調度報表\njob_dashboard_report_loaddata_fail=調度報表資料加載異常\njob_dashboard_date_report=日期分布圖\njob_dashboard_rate_report=成功比例圖\n\n## job info\njobinfo_name=任務管理\njobinfo_job=任務\njobinfo_field_add=新增\njobinfo_field_update=更新任務\njobinfo_field_id=任務ID\njobinfo_field_jobgroup=執行器\njobinfo_field_jobdesc=任務描述\njobinfo_field_gluetype=運行模式\njobinfo_field_executorparam=任務參數\njobinfo_field_author=負責人\njobinfo_field_timeout=任務超時秒數\njobinfo_field_alarmemail=告警郵件\njobinfo_field_alarmemail_placeholder=輸入多個告警郵件地址，請以逗號分隔\njobinfo_field_executorRouteStrategy=路由策略\njobinfo_field_childJobId=子任務ID\njobinfo_field_childJobId_placeholder=輸入子任務ID，如有多個請以逗號分隔\njobinfo_field_executorBlockStrategy=阻塞處理策略\njobinfo_field_executorFailRetryCount=失敗重試次數\njobinfo_field_executorFailRetryCount_placeholder=失敗重試次數，大於零時生效\njobinfo_script_location=腳本位置\njobinfo_shard_index=分片序號\njobinfo_shard_total=分片總數\njobinfo_opt_stop=停止\njobinfo_opt_start=啟動\njobinfo_opt_log=查詢日誌\njobinfo_opt_run=執行一次\njobinfo_opt_run_tips=請輸入本次執行的機器地址，為空則從執行器獲取\njobinfo_opt_registryinfo=注冊節點\njobinfo_opt_next_time=下次執行時間\njobinfo_glue_source=GLUE源碼\njobinfo_glue_remark=源碼備註\njobinfo_glue_remark_limit=源碼備註長度限制為4~100\njobinfo_glue_rollback=版本回復\njobinfo_glue_jobid_unvalid=任務ID非法\njobinfo_glue_gluetype_unvalid=該任務非GLUE模式\njobinfo_field_executorTimeout_placeholder=任務超時時間，單位秒，大於零時生效\nschedule_type=調度類型\nschedule_type_none=無\nschedule_type_cron=CRON\nschedule_type_fix_rate=固定速度\nschedule_type_fix_delay=固定延遲\nschedule_type_none_limit_start=當前調度類型禁止啟動\nmisfire_strategy=調度過期策略\nmisfire_strategy_do_nothing=忽略\nmisfire_strategy_fire_once_now=立即執行壹次\njobinfo_conf_base=基礎配置\njobinfo_conf_schedule=調度配置\njobinfo_conf_job=任務配置\njobinfo_conf_advanced=高級配置\n\n## job log\njoblog_name=調度日誌\njoblog_status=狀態\njoblog_status_all=全部\njoblog_status_suc=成功\njoblog_status_fail=失敗\njoblog_status_running=進行中\njoblog_field_triggerTime=調度時間\njoblog_field_triggerCode=調度結果\njoblog_field_triggerMsg=調度備註\njoblog_field_handleTime=執行時間\njoblog_field_handleCode=執行结果\njoblog_field_handleMsg=執行備註\njoblog_field_executorAddress=執行器地址\njoblog_clean=清理\njoblog_clean_log=日誌清理\njoblog_clean_type=清理方式\njoblog_clean_type_1=清理一個月之前日誌資料\njoblog_clean_type_2=清理三個月之前日誌資料\njoblog_clean_type_3=清理六個月之前日誌資料\njoblog_clean_type_4=清理一年之前日誌資料\njoblog_clean_type_5=清理一千條以前日誌資料\njoblog_clean_type_6=清理一萬條以前日誌資料\njoblog_clean_type_7=清理三萬條以前日誌資料\njoblog_clean_type_8=清理十萬條以前日誌資料\njoblog_clean_type_9=清理所有日誌資料\njoblog_clean_type_unvalid=清理類型參数異常\njoblog_handleCode_200=成功\njoblog_handleCode_500=失敗\njoblog_handleCode_502=失敗(超時)\njoblog_kill_log=终止任務\njoblog_kill_log_limit=調度失敗，無法终止日誌\njoblog_kill_log_byman=人為操作，主動終止\njoblog_lost_fail=任務結果丟失，標記失敗\njoblog_rolling_log=執行日誌\njoblog_rolling_log_refresh=更新\njoblog_rolling_log_triggerfail=任務發起調度失敗，無法查看執行日誌\njoblog_rolling_log_failoften=終止請求Rolling日誌，請求失敗次數超上限，可刷新頁面重新加載日誌\njoblog_logid_unvalid=日誌ID非法\n\n## job group\njobgroup_name=執行器管理\njobgroup_list=執行器列表\njobgroup_add=新增執行器\njobgroup_edit=編輯執行器\njobgroup_del=刪除執行器\njobgroup_field_title=名稱\njobgroup_field_addressType=注冊方式\njobgroup_field_addressType_0=自動注冊\njobgroup_field_addressType_1=手動登錄\njobgroup_field_addressType_limit=手動登錄注冊方式，機器地址不可為空\njobgroup_field_registryList=機器地址\njobgroup_field_registryList_unvalid=機器地址格式非法\njobgroup_field_registryList_placeholder=請輸入執行器地址列表，多個地址請以逗號分隔\njobgroup_field_appname_limit=限制以小寫字母開頭，由小寫字母、數字和中划線組成\njobgroup_field_appname_length=AppName長度限制為4~64\njobgroup_field_title_length=名稱長度限制為4~12\njobgroup_field_order_digits=請輸入整數\njobgroup_field_orderrange=取值範圍為1~1000\njobgroup_del_limit_0=拒絕刪除，該執行器使用中\njobgroup_del_limit_1=拒絕删除，系统至少保留一個執行器\njobgroup_empty=不存在有效執行器，請聯絡系統管理員\n\n## job conf\njobconf_block_SERIAL_EXECUTION=單機串行\njobconf_block_DISCARD_LATER=丢棄后續調度\njobconf_block_COVER_EARLY=覆蓋之前調度\njobconf_route_first=第一個\njobconf_route_last=最後一個\njobconf_route_round=輪詢\njobconf_route_random=隨機\njobconf_route_consistenthash=一致性HASH\njobconf_route_lfu=最不經常使用\njobconf_route_lru=最近最久未使用\njobconf_route_failover=故障轉移\njobconf_route_busyover=忙碌轉移\njobconf_route_shard=分片廣播\njobconf_idleBeat=空閒檢測\njobconf_beat=心跳檢測\njobconf_monitor=任務調度中心監控告警\njobconf_monitor_detail=監控告警明细\njobconf_monitor_alarm_title=告警類型\njobconf_monitor_alarm_type=調度失敗\njobconf_monitor_alarm_content=告警内容\njobconf_trigger_admin_adress=調度機器\njobconf_trigger_exe_regtype=執行器-注冊方式\njobconf_trigger_exe_regaddress=執行器-地址列表\njobconf_trigger_address_empty=調度失敗：執行器地址為空\njobconf_trigger_run=觸發調度\njobconf_trigger_child_run=觸發子任務\njobconf_callback_child_msg1={0}/{1} [任務ID={2}], 觸發{3}, 觸發備註: {4} <br>\njobconf_callback_child_msg2={0}/{1} [任務ID={2}], 觸發失败, 觸發備註: 任務ID格式錯誤 <br>\njobconf_trigger_type=任務觸發類型\njobconf_trigger_type_cron=Cron觸發\njobconf_trigger_type_manual=手動觸發\njobconf_trigger_type_parent=父任務觸發\njobconf_trigger_type_api=API觸發\njobconf_trigger_type_retry=失敗重試觸發\njobconf_trigger_type_misfire=調度過期補償\n\n## user\nuser_manage=用户管理\nuser_username=帳號\nuser_password=密碼\nuser_role=角色\nuser_role_admin=管理員\nuser_role_normal=普通用戶\nuser_permission=權限\nuser_add=新增用戶\nuser_update=更新用戶\nuser_username_repeat=帳號重複\nuser_username_valid=限制以小寫字母開頭，由小寫字母、數字組成\nuser_password_update_placeholder=請輸入新密碼，為空則不更新密碼\nuser_update_loginuser_limit=禁止操作當前登入帳號\n"
  },
  {
    "path": "xxl-job-admin/src/main/resources/logback.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration debug=\"false\" scan=\"true\" scanPeriod=\"1 seconds\">\n\n    <contextName>logback</contextName>\n    <property name=\"log.path\" value=\"${LOG_HOME:-/data/applogs}/xxl-job/xxl-job-admin.log\" />\n    <appender name=\"console\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <encoder>\n            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>\n        </encoder>\n    </appender>\n\n    <appender name=\"file\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n        <file>${log.path}</file>\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n            <fileNamePattern>${log.path}.%d{yyyy-MM-dd}.log</fileNamePattern>\n        </rollingPolicy>\n        <encoder>\n            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>\n        </encoder>\n    </appender>\n\n    <root level=\"info\">\n        <appender-ref ref=\"console\"/>\n        <appender-ref ref=\"file\"/>\n    </root>\n\n</configuration>"
  },
  {
    "path": "xxl-job-admin/src/main/resources/mapper/XxlJobGroupMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \n\t\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"com.xxl.job.admin.mapper.XxlJobGroupMapper\">\n\t\n\t<resultMap id=\"XxlJobGroup\" type=\"com.xxl.job.admin.model.XxlJobGroup\" >\n\t\t<result column=\"id\" property=\"id\" />\n\t    <result column=\"app_name\" property=\"appname\" />\n\t    <result column=\"title\" property=\"title\" />\n\t\t<result column=\"address_type\" property=\"addressType\" />\n\t\t<result column=\"address_list\" property=\"addressList\" />\n\t\t<result column=\"update_time\" property=\"updateTime\" />\n\t</resultMap>\n\n\t<sql id=\"Base_Column_List\">\n\t\tt.id,\n\t\tt.app_name,\n\t\tt.title,\n\t\tt.address_type,\n\t\tt.address_list,\n\t\tt.update_time\n\t</sql>\n\n\t<select id=\"findAll\" resultMap=\"XxlJobGroup\">\n\t\tSELECT <include refid=\"Base_Column_List\" />\n\t\tFROM xxl_job_group AS t\n\t\tORDER BY t.app_name, t.title, t.id ASC\n\t</select>\n\n\t<select id=\"findByAddressType\" parameterType=\"java.lang.Integer\" resultMap=\"XxlJobGroup\">\n\t\tSELECT <include refid=\"Base_Column_List\" />\n\t\tFROM xxl_job_group AS t\n\t\tWHERE t.address_type = #{addressType}\n\t\tORDER BY t.app_name, t.title, t.id ASC\n\t</select>\n\n\t<insert id=\"save\" parameterType=\"com.xxl.job.admin.model.XxlJobGroup\" useGeneratedKeys=\"true\" keyProperty=\"id\" >\n\t\tINSERT INTO xxl_job_group ( `app_name`, `title`, `address_type`, `address_list`, `update_time`)\n\t\tvalues ( #{appname}, #{title}, #{addressType}, #{addressList}, #{updateTime} );\n\t</insert>\n\n\t<update id=\"update\" parameterType=\"com.xxl.job.admin.model.XxlJobGroup\" >\n\t\tUPDATE xxl_job_group\n\t\tSET `app_name` = #{appname},\n\t\t\t`title` = #{title},\n\t\t\t`address_type` = #{addressType},\n\t\t\t`address_list` = #{addressList},\n\t\t\t`update_time` = #{updateTime}\n\t\tWHERE id = #{id}\n\t</update>\n\n\t<delete id=\"remove\" parameterType=\"java.lang.Integer\" >\n\t\tDELETE FROM xxl_job_group\n\t\tWHERE id = #{id}\n\t</delete>\n\n\t<select id=\"load\" parameterType=\"java.lang.Integer\" resultMap=\"XxlJobGroup\">\n\t\tSELECT <include refid=\"Base_Column_List\" />\n\t\tFROM xxl_job_group AS t\n\t\tWHERE t.id = #{id}\n\t</select>\n\n\t<select id=\"pageList\" parameterType=\"java.util.HashMap\" resultMap=\"XxlJobGroup\">\n\t\tSELECT <include refid=\"Base_Column_List\" />\n\t\tFROM xxl_job_group AS t\n\t\t<trim prefix=\"WHERE\" prefixOverrides=\"AND | OR\" >\n\t\t\t<if test=\"appname != null and appname != ''\">\n\t\t\t\tAND t.app_name like CONCAT(CONCAT('%', #{appname}), '%')\n\t\t\t</if>\n\t\t\t<if test=\"title != null and title != ''\">\n\t\t\t\tAND t.title like CONCAT(CONCAT('%', #{title}), '%')\n\t\t\t</if>\n\t\t</trim>\n\t\tORDER BY t.app_name, t.title, t.id ASC\n\t\tLIMIT #{offset}, #{pagesize}\n\t</select>\n\n\t<select id=\"pageListCount\" parameterType=\"java.util.HashMap\" resultType=\"int\">\n\t\tSELECT count(1)\n\t\tFROM xxl_job_group AS t\n\t\t<trim prefix=\"WHERE\" prefixOverrides=\"AND | OR\" >\n\t\t\t<if test=\"appname != null and appname != ''\">\n\t\t\t\tAND t.app_name like CONCAT(CONCAT('%', #{appname}), '%')\n\t\t\t</if>\n\t\t\t<if test=\"title != null and title != ''\">\n\t\t\t\tAND t.title like CONCAT(CONCAT('%', #{title}), '%')\n\t\t\t</if>\n\t\t</trim>\n\t</select>\n\n</mapper>"
  },
  {
    "path": "xxl-job-admin/src/main/resources/mapper/XxlJobInfoMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n\t\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"com.xxl.job.admin.mapper.XxlJobInfoMapper\">\n\n\t<resultMap id=\"XxlJobInfo\" type=\"com.xxl.job.admin.model.XxlJobInfo\" >\n\t\t<result column=\"id\" property=\"id\" />\n\n\t\t<result column=\"job_group\" property=\"jobGroup\" />\n\t    <result column=\"job_desc\" property=\"jobDesc\" />\n\n\t    <result column=\"add_time\" property=\"addTime\" />\n\t    <result column=\"update_time\" property=\"updateTime\" />\n\n\t    <result column=\"author\" property=\"author\" />\n\t    <result column=\"alarm_email\" property=\"alarmEmail\" />\n\n\t\t<result column=\"schedule_type\" property=\"scheduleType\" />\n\t\t<result column=\"schedule_conf\" property=\"scheduleConf\" />\n\t\t<result column=\"misfire_strategy\" property=\"misfireStrategy\" />\n\n\t\t<result column=\"executor_route_strategy\" property=\"executorRouteStrategy\" />\n\t\t<result column=\"executor_handler\" property=\"executorHandler\" />\n\t    <result column=\"executor_param\" property=\"executorParam\" />\n\t\t<result column=\"executor_block_strategy\" property=\"executorBlockStrategy\" />\n\t\t<result column=\"executor_timeout\" property=\"executorTimeout\" />\n\t\t<result column=\"executor_fail_retry_count\" property=\"executorFailRetryCount\" />\n\n\t    <result column=\"glue_type\" property=\"glueType\" />\n\t    <result column=\"glue_source\" property=\"glueSource\" />\n\t    <result column=\"glue_remark\" property=\"glueRemark\" />\n\t\t<result column=\"glue_updatetime\" property=\"glueUpdatetime\" />\n\n\t\t<result column=\"child_jobid\" property=\"childJobId\" />\n\n\t\t<result column=\"trigger_status\" property=\"triggerStatus\" />\n\t\t<result column=\"trigger_last_time\" property=\"triggerLastTime\" />\n\t\t<result column=\"trigger_next_time\" property=\"triggerNextTime\" />\n\t</resultMap>\n\n\t<sql id=\"Base_Column_List\">\n\t\tt.id,\n\t\tt.job_group,\n\t\tt.job_desc,\n\t\tt.add_time,\n\t\tt.update_time,\n\t\tt.author,\n\t\tt.alarm_email,\n\t\tt.schedule_type,\n\t\tt.schedule_conf,\n\t\tt.misfire_strategy,\n\t\tt.executor_route_strategy,\n\t\tt.executor_handler,\n\t\tt.executor_param,\n\t\tt.executor_block_strategy,\n\t\tt.executor_timeout,\n\t\tt.executor_fail_retry_count,\n\t\tt.glue_type,\n\t\tt.glue_source,\n\t\tt.glue_remark,\n\t\tt.glue_updatetime,\n\t\tt.child_jobid,\n\t\tt.trigger_status,\n\t\tt.trigger_last_time,\n\t\tt.trigger_next_time\n\t</sql>\n\n\t<select id=\"pageList\" parameterType=\"java.util.HashMap\" resultMap=\"XxlJobInfo\">\n\t\tSELECT <include refid=\"Base_Column_List\" />\n\t\tFROM xxl_job_info AS t\n\t\t<trim prefix=\"WHERE\" prefixOverrides=\"AND | OR\" >\n\t\t\t<if test=\"jobGroup gt 0\">\n\t\t\t\tAND t.job_group = #{jobGroup}\n\t\t\t</if>\n            <if test=\"triggerStatus gte 0\">\n                AND t.trigger_status = #{triggerStatus}\n            </if>\n\t\t\t<if test=\"jobDesc != null and jobDesc != ''\">\n\t\t\t\tAND t.job_desc like CONCAT(CONCAT('%', #{jobDesc}), '%')\n\t\t\t</if>\n\t\t\t<if test=\"executorHandler != null and executorHandler != ''\">\n\t\t\t\tAND t.executor_handler like CONCAT(CONCAT('%', #{executorHandler}), '%')\n\t\t\t</if>\n\t\t\t<if test=\"author != null and author != ''\">\n\t\t\t\tAND t.author like CONCAT(CONCAT('%', #{author}), '%')\n\t\t\t</if>\n\t\t</trim>\n\t\tORDER BY id DESC\n\t\tLIMIT #{offset}, #{pagesize}\n\t</select>\n\n\t<select id=\"pageListCount\" parameterType=\"java.util.HashMap\" resultType=\"int\">\n\t\tSELECT count(1)\n\t\tFROM xxl_job_info AS t\n\t\t<trim prefix=\"WHERE\" prefixOverrides=\"AND | OR\" >\n\t\t\t<if test=\"jobGroup gt 0\">\n\t\t\t\tAND t.job_group = #{jobGroup}\n\t\t\t</if>\n            <if test=\"triggerStatus gte 0\">\n                AND t.trigger_status = #{triggerStatus}\n            </if>\n\t\t\t<if test=\"jobDesc != null and jobDesc != ''\">\n\t\t\t\tAND t.job_desc like CONCAT(CONCAT('%', #{jobDesc}), '%')\n\t\t\t</if>\n\t\t\t<if test=\"executorHandler != null and executorHandler != ''\">\n\t\t\t\tAND t.executor_handler like CONCAT(CONCAT('%', #{executorHandler}), '%')\n\t\t\t</if>\n\t\t\t<if test=\"author != null and author != ''\">\n\t\t\t\tAND t.author like CONCAT(CONCAT('%', #{author}), '%')\n\t\t\t</if>\n\t\t</trim>\n\t</select>\n\n\t<insert id=\"save\" parameterType=\"com.xxl.job.admin.model.XxlJobInfo\" useGeneratedKeys=\"true\" keyProperty=\"id\" >\n\t\tINSERT INTO xxl_job_info (\n\t\t\tjob_group,\n\t\t\tjob_desc,\n\t\t\tadd_time,\n\t\t\tupdate_time,\n\t\t\tauthor,\n\t\t\talarm_email,\n\t\t\tschedule_type,\n\t\t\tschedule_conf,\n\t\t\tmisfire_strategy,\n            executor_route_strategy,\n\t\t\texecutor_handler,\n\t\t\texecutor_param,\n\t\t\texecutor_block_strategy,\n\t\t\texecutor_timeout,\n\t\t\texecutor_fail_retry_count,\n\t\t\tglue_type,\n\t\t\tglue_source,\n\t\t\tglue_remark,\n\t\t\tglue_updatetime,\n\t\t\tchild_jobid,\n\t\t\ttrigger_status,\n\t\t\ttrigger_last_time,\n\t\t\ttrigger_next_time\n\t\t) VALUES (\n\t\t\t#{jobGroup},\n\t\t\t#{jobDesc},\n\t\t\t#{addTime},\n\t\t\t#{updateTime},\n\t\t\t#{author},\n\t\t\t#{alarmEmail},\n\t\t\t#{scheduleType},\n\t\t\t#{scheduleConf},\n\t\t\t#{misfireStrategy},\n\t\t\t#{executorRouteStrategy},\n\t\t\t#{executorHandler},\n\t\t\t#{executorParam},\n\t\t\t#{executorBlockStrategy},\n\t\t\t#{executorTimeout},\n\t\t\t#{executorFailRetryCount},\n\t\t\t#{glueType},\n\t\t\t#{glueSource},\n\t\t\t#{glueRemark},\n\t\t\t#{glueUpdatetime},\n\t\t\t#{childJobId},\n\t\t\t#{triggerStatus},\n\t\t\t#{triggerLastTime},\n\t\t\t#{triggerNextTime}\n\t\t);\n\t\t<!--<selectKey resultType=\"java.lang.Integer\" order=\"AFTER\" keyProperty=\"id\">\n\t\t\tSELECT LAST_INSERT_ID()\n\t\t\t/*SELECT @@IDENTITY AS id*/\n\t\t</selectKey>-->\n\t</insert>\n\n\t<select id=\"loadById\" parameterType=\"java.util.HashMap\" resultMap=\"XxlJobInfo\">\n\t\tSELECT <include refid=\"Base_Column_List\" />\n\t\tFROM xxl_job_info AS t\n\t\tWHERE t.id = #{id}\n\t</select>\n\n\t<update id=\"update\" parameterType=\"com.xxl.job.admin.model.XxlJobInfo\" >\n\t\tUPDATE xxl_job_info\n\t\tSET\n\t\t\tjob_group = #{jobGroup},\n\t\t\tjob_desc = #{jobDesc},\n\t\t\tupdate_time = #{updateTime},\n\t\t\tauthor = #{author},\n\t\t\talarm_email = #{alarmEmail},\n\t\t\tschedule_type = #{scheduleType},\n\t\t\tschedule_conf = #{scheduleConf},\n\t\t\tmisfire_strategy = #{misfireStrategy},\n\t\t\texecutor_route_strategy = #{executorRouteStrategy},\n\t\t\texecutor_handler = #{executorHandler},\n\t\t\texecutor_param = #{executorParam},\n\t\t\texecutor_block_strategy = #{executorBlockStrategy},\n\t\t\texecutor_timeout = #{executorTimeout},\n\t\t\texecutor_fail_retry_count = #{executorFailRetryCount},\n\t\t\tglue_type = #{glueType},\n\t\t\tglue_source = #{glueSource},\n\t\t\tglue_remark = #{glueRemark},\n\t\t\tglue_updatetime = #{glueUpdatetime},\n\t\t\tchild_jobid = #{childJobId},\n\t\t\ttrigger_status = #{triggerStatus},\n\t\t\ttrigger_last_time = #{triggerLastTime},\n\t\t\ttrigger_next_time = #{triggerNextTime}\n\t\tWHERE id = #{id}\n\t</update>\n\n\t<delete id=\"delete\" parameterType=\"java.util.HashMap\">\n\t\tDELETE\n\t\tFROM xxl_job_info\n\t\tWHERE id = #{id}\n\t</delete>\n\n\t<select id=\"getJobsByGroup\" parameterType=\"java.util.HashMap\" resultMap=\"XxlJobInfo\">\n\t\tSELECT <include refid=\"Base_Column_List\" />\n\t\tFROM xxl_job_info AS t\n\t\tWHERE t.job_group = #{jobGroup}\n\t</select>\n\n\t<select id=\"findAllCount\" resultType=\"int\">\n\t\tSELECT count(1)\n\t\tFROM xxl_job_info\n\t</select>\n\n\n\t<select id=\"scheduleJobQuery\" parameterType=\"java.util.HashMap\" resultMap=\"XxlJobInfo\">\n\t\tSELECT <include refid=\"Base_Column_List\" />\n\t\tFROM xxl_job_info AS t\n\t\tWHERE t.trigger_status = 1\n\t\t\tand t.trigger_next_time <![CDATA[ <= ]]> #{maxNextTime}\n\t\tORDER BY id ASC\n\t\tLIMIT #{pagesize}\n\t</select>\n\n\t<update id=\"scheduleUpdate\" parameterType=\"com.xxl.job.admin.model.XxlJobInfo\"  >\n\t\tUPDATE xxl_job_info\n\t\tSET\n\t\t\ttrigger_last_time = #{triggerLastTime},\n\t\t\ttrigger_next_time = #{triggerNextTime}\n\t\t\t<if test=\"triggerStatus gte 0\">\n\t\t\t , trigger_status = #{triggerStatus}\n\t\t\t</if>\n\t\tWHERE id = #{id}\n\t\t  AND trigger_status = 1\n\t</update>\n\n\t<!--int scheduleUpdateBatch(@Param(\"list\") List<XxlJobInfo> jobs);\n\t<update id=\"scheduleUpdateBatch\" parameterType=\"java.util.List\">\n\t\tUPDATE xxl_job_info\n\t\tSET\n\t\t\ttrigger_last_time = CASE id\n\t\t\t<foreach collection=\"list\" item=\"item\">\n\t\t\t\tWHEN #{item.id} THEN #{item.triggerLastTime}\n\t\t\t</foreach>\n\t\t\tEND,\n\t\t\ttrigger_next_time = CASE id\n\t\t\t<foreach collection=\"list\" item=\"item\">\n\t\t\t\tWHEN #{item.id} THEN #{item.triggerNextTime}\n\t\t\t</foreach>\n\t\t\tEND,\n\t\t\ttrigger_status = CASE id\n\t\t\t<foreach collection=\"list\" item=\"item\">\n\t\t\t\tWHEN #{item.id} THEN\n\t\t\t\t<choose>\n\t\t\t\t\t<when test=\"item.triggerStatus >= 0\">#{item.triggerStatus}</when>\n\t\t\t\t\t<otherwise>trigger_status</otherwise> &lt;!&ndash; 保持原值 &ndash;&gt;\n\t\t\t\t</choose>\n\t\t\t</foreach>\n\t\t\tEND\n\t\tWHERE id IN\n\t\t\t<foreach collection=\"list\" item=\"item\" open=\"(\" separator=\",\" close=\")\">\n\t\t\t\t#{item.id}\n\t\t\t</foreach>\n\t\t\tAND trigger_status = 1\n\t</update>-->\n\n</mapper>\n"
  },
  {
    "path": "xxl-job-admin/src/main/resources/mapper/XxlJobLockMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \n\t\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"com.xxl.job.admin.mapper.XxlJobLockMapper\">\n\n\t<select id=\"scheduleLock\" resultType=\"java.lang.String\" >\n\t\tSELECT * FROM xxl_job_lock\n\t\tWHERE lock_name = 'schedule_lock'\n\t\tFOR UPDATE\n\t</select>\n\n\n</mapper>"
  },
  {
    "path": "xxl-job-admin/src/main/resources/mapper/XxlJobLogGlueMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \n\t\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"com.xxl.job.admin.mapper.XxlJobLogGlueMapper\">\n\t\n\t<resultMap id=\"XxlJobLogGlue\" type=\"com.xxl.job.admin.model.XxlJobLogGlue\" >\n\t\t<result column=\"id\" property=\"id\" />\n\t    <result column=\"job_id\" property=\"jobId\" />\n\t\t<result column=\"glue_type\" property=\"glueType\" />\n\t    <result column=\"glue_source\" property=\"glueSource\" />\n\t    <result column=\"glue_remark\" property=\"glueRemark\" />\n\t    <result column=\"add_time\" property=\"addTime\" />\n\t    <result column=\"update_time\" property=\"updateTime\" />\n\t</resultMap>\n\n\t<sql id=\"Base_Column_List\">\n\t\tt.id,\n\t\tt.job_id,\n\t\tt.glue_type,\n\t\tt.glue_source,\n\t\tt.glue_remark,\n\t\tt.add_time,\n\t\tt.update_time\n\t</sql>\n\t\n\t<insert id=\"save\" parameterType=\"com.xxl.job.admin.model.XxlJobLogGlue\" useGeneratedKeys=\"true\" keyProperty=\"id\" >\n\t\tINSERT INTO xxl_job_logglue (\n\t\t\t`job_id`,\n\t\t\t`glue_type`,\n\t\t\t`glue_source`,\n\t\t\t`glue_remark`,\n\t\t\t`add_time`, \n\t\t\t`update_time`\n\t\t) VALUES (\n\t\t\t#{jobId},\n\t\t\t#{glueType},\n\t\t\t#{glueSource},\n\t\t\t#{glueRemark},\n\t\t\t#{addTime},\n\t\t\t#{updateTime}\n\t\t);\n\t\t<!--<selectKey resultType=\"java.lang.Integer\" order=\"AFTER\" keyProperty=\"id\">\n\t\t\tSELECT LAST_INSERT_ID() \n\t\t</selectKey>-->\n\t</insert>\n\t\n\t<select id=\"findByJobId\" parameterType=\"java.lang.Integer\" resultMap=\"XxlJobLogGlue\">\n\t\tSELECT <include refid=\"Base_Column_List\" />\n\t\tFROM xxl_job_logglue AS t\n\t\tWHERE t.job_id = #{jobId}\n\t\tORDER BY id DESC\n\t</select>\n\t\n\t<delete id=\"removeOld\" >\n\t\tDELETE FROM xxl_job_logglue\n\t\tWHERE id NOT in(\n\t\t\tSELECT id FROM(\n\t\t\t\tSELECT id FROM xxl_job_logglue\n\t\t\t\tWHERE `job_id` = #{jobId}\n\t\t\t\tORDER BY update_time desc\n\t\t\t\tLIMIT 0, #{limit}\n\t\t\t) t1\n\t\t) AND `job_id` = #{jobId}\n\t</delete>\n\t\n\t<delete id=\"deleteByJobId\" parameterType=\"java.lang.Integer\" >\n\t\tDELETE FROM xxl_job_logglue\n\t\tWHERE `job_id` = #{jobId}\n\t</delete>\n\t\n</mapper>"
  },
  {
    "path": "xxl-job-admin/src/main/resources/mapper/XxlJobLogMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \n\t\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"com.xxl.job.admin.mapper.XxlJobLogMapper\">\n\t\n\t<resultMap id=\"XxlJobLog\" type=\"com.xxl.job.admin.model.XxlJobLog\" >\n\t\t<result column=\"id\" property=\"id\" />\n\n\t\t<result column=\"job_group\" property=\"jobGroup\" />\n\t\t<result column=\"job_id\" property=\"jobId\" />\n\n\t\t<result column=\"executor_address\" property=\"executorAddress\" />\n\t\t<result column=\"executor_handler\" property=\"executorHandler\" />\n\t    <result column=\"executor_param\" property=\"executorParam\" />\n\t\t<result column=\"executor_sharding_param\" property=\"executorShardingParam\" />\n\t\t<result column=\"executor_fail_retry_count\" property=\"executorFailRetryCount\" />\n\t    \n\t    <result column=\"trigger_time\" property=\"triggerTime\" />\n\t    <result column=\"trigger_code\" property=\"triggerCode\" />\n\t    <result column=\"trigger_msg\" property=\"triggerMsg\" />\n\t    \n\t    <result column=\"handle_time\" property=\"handleTime\" />\n\t    <result column=\"handle_code\" property=\"handleCode\" />\n\t    <result column=\"handle_msg\" property=\"handleMsg\" />\n\n\t\t<result column=\"alarm_status\" property=\"alarmStatus\" />\n\t</resultMap>\n\n\t<sql id=\"Base_Column_List\">\n\t\tt.id,\n\t\tt.job_group,\n\t\tt.job_id,\n\t\tt.executor_address,\n\t\tt.executor_handler,\n\t\tt.executor_param,\n\t\tt.executor_sharding_param,\n\t\tt.executor_fail_retry_count,\n\t\tt.trigger_time,\n\t\tt.trigger_code,\n\t\tt.trigger_msg,\n\t\tt.handle_time,\n\t\tt.handle_code,\n\t\tt.handle_msg,\n\t\tt.alarm_status\n\t</sql>\n\t\n\t<select id=\"pageList\" resultMap=\"XxlJobLog\">\n\t\tSELECT <include refid=\"Base_Column_List\" />\n\t\tFROM xxl_job_log AS t\n\t\t<trim prefix=\"WHERE\" prefixOverrides=\"AND | OR\" >\n\t\t\t<if test=\"jobId==0 and jobGroup gt 0\">\n\t\t\t\tAND t.job_group = #{jobGroup}\n\t\t\t</if>\n\t\t\t<if test=\"jobId gt 0\">\n\t\t\t\tAND t.job_id = #{jobId}\n\t\t\t</if>\n\t\t\t<if test=\"triggerTimeStart != null\">\n\t\t\t\tAND t.trigger_time <![CDATA[ >= ]]> #{triggerTimeStart}\n\t\t\t</if>\n\t\t\t<if test=\"triggerTimeEnd != null\">\n\t\t\t\tAND t.trigger_time <![CDATA[ <= ]]> #{triggerTimeEnd}\n\t\t\t</if>\n\t\t\t<if test=\"logStatus == 1\" >\n\t\t\t\tAND t.handle_code = 200\n\t\t\t</if>\n\t\t\t<if test=\"logStatus == 2\" >\n\t\t\t\tAND (\n\t\t\t\t\tt.trigger_code NOT IN (0, 200) OR\n\t\t\t\t\tt.handle_code NOT IN (0, 200)\n\t\t\t\t)\n\t\t\t</if>\n\t\t\t<if test=\"logStatus == 3\" >\n\t\t\t\tAND t.trigger_code = 200\n\t\t\t\tAND t.handle_code = 0\n\t\t\t</if>\n\t\t</trim>\n\t\tORDER BY t.id DESC\n\t\tLIMIT #{offset}, #{pagesize}\n\t</select>\n\t\n\t<select id=\"pageListCount\" resultType=\"int\">\n\t\tSELECT count(1)\n\t\tFROM xxl_job_log AS t\n\t\t<trim prefix=\"WHERE\" prefixOverrides=\"AND | OR\" >\n\t\t\t<if test=\"jobId==0 and jobGroup gt 0\">\n\t\t\t\tAND t.job_group = #{jobGroup}\n\t\t\t</if>\n\t\t\t<if test=\"jobId gt 0\">\n\t\t\t\tAND t.job_id = #{jobId}\n\t\t\t</if>\n\t\t\t<if test=\"triggerTimeStart != null\">\n\t\t\t\tAND t.trigger_time <![CDATA[ >= ]]> #{triggerTimeStart}\n\t\t\t</if>\n\t\t\t<if test=\"triggerTimeEnd != null\">\n\t\t\t\tAND t.trigger_time <![CDATA[ <= ]]> #{triggerTimeEnd}\n\t\t\t</if>\n\t\t\t<if test=\"logStatus == 1\" >\n\t\t\t\tAND t.handle_code = 200\n\t\t\t</if>\n\t\t\t<if test=\"logStatus == 2\" >\n\t\t\t\tAND (\n\t\t\t\t\tt.trigger_code NOT IN (0, 200) OR\n\t\t\t\t\tt.handle_code NOT IN (0, 200)\n\t\t\t\t)\n\t\t\t</if>\n\t\t\t<if test=\"logStatus == 3\" >\n\t\t\t\tAND t.trigger_code = 200\n\t\t\t\tAND t.handle_code = 0\n\t\t\t</if>\n\t\t</trim>\n\t</select>\n\t\n\t<select id=\"load\" parameterType=\"java.lang.Long\" resultMap=\"XxlJobLog\">\n\t\tSELECT <include refid=\"Base_Column_List\" />\n\t\tFROM xxl_job_log AS t\n\t\tWHERE t.id = #{id}\n\t</select>\n\n\t\n\t<insert id=\"save\" parameterType=\"com.xxl.job.admin.model.XxlJobLog\" useGeneratedKeys=\"true\" keyProperty=\"id\" >\n\t\tINSERT INTO xxl_job_log (\n\t\t\t`job_group`,\n\t\t\t`job_id`,\n\t\t\t`trigger_time`,\n\t\t\t`trigger_code`,\n\t\t\t`handle_code`\n\t\t) VALUES (\n\t\t\t#{jobGroup},\n\t\t\t#{jobId},\n\t\t\t#{triggerTime},\n\t\t\t#{triggerCode},\n\t\t\t#{handleCode}\n\t\t);\n\t\t<!--<selectKey resultType=\"java.lang.Integer\" order=\"AFTER\" keyProperty=\"id\">\n\t\t\tSELECT LAST_INSERT_ID() \n\t\t</selectKey>-->\n\t</insert>\n\n\t<update id=\"updateTriggerInfo\" >\n\t\tUPDATE xxl_job_log\n\t\tSET\n\t\t\t`trigger_time`= #{triggerTime},\n\t\t\t`trigger_code`= #{triggerCode},\n\t\t\t`trigger_msg`= #{triggerMsg},\n\t\t\t`executor_address`= #{executorAddress},\n\t\t\t`executor_handler`=#{executorHandler},\n\t\t\t`executor_param`= #{executorParam},\n\t\t\t`executor_sharding_param`= #{executorShardingParam},\n\t\t\t`executor_fail_retry_count`= #{executorFailRetryCount}\n\t\tWHERE `id`= #{id}\n\t</update>\n\n\t<update id=\"updateHandleInfo\">\n\t\tUPDATE xxl_job_log\n\t\tSET \n\t\t\t`handle_time`= #{handleTime}, \n\t\t\t`handle_code`= #{handleCode},\n\t\t\t`handle_msg`= #{handleMsg}\n\t\tWHERE `id`= #{id}\n\t</update>\n\t\n\t<delete id=\"delete\" >\n\t\tdelete from xxl_job_log\n\t\tWHERE job_id = #{jobId}\n\t</delete>\n\n    <!--<select id=\"triggerCountByDay\" resultType=\"java.util.Map\" >\n\t\tSELECT\n\t\t\tDATE_FORMAT(trigger_time,'%Y-%m-%d') triggerDay,\n\t\t\tCOUNT(handle_code) triggerDayCount,\n\t\t\tSUM(CASE WHEN (trigger_code in (0, 200) and handle_code = 0) then 1 else 0 end) as triggerDayCountRunning,\n\t\t\tSUM(CASE WHEN handle_code = 200 then 1 else 0 end) as triggerDayCountSuc\n\t\tFROM xxl_job_log\n\t\tWHERE trigger_time BETWEEN #{from} and #{to}\n\t\tGROUP BY triggerDay\n\t\tORDER BY triggerDay\n    </select>-->\n\n    <select id=\"findLogReport\" resultType=\"java.util.Map\" >\n\t\tSELECT\n\t\t\tIFNULL(COUNT(handle_code),0) triggerDayCount,\n\t\t\tIFNULL(SUM(CASE WHEN (trigger_code in (0, 200) and handle_code = 0) then 1 else 0 end),0) as triggerDayCountRunning,\n\t\t\tIFNULL(SUM(CASE WHEN handle_code = 200 then 1 else 0 end),0) as triggerDayCountSuc\n\t\tFROM xxl_job_log\n\t\tWHERE trigger_time BETWEEN #{from} and #{to}\n    </select>\n\n\t<select id=\"findClearLogIds\" resultType=\"long\" >\n\t\tSELECT id FROM xxl_job_log\n\t\t<trim prefix=\"WHERE\" prefixOverrides=\"AND | OR\" >\n\t\t\t<if test=\"jobGroup gt 0\">\n\t\t\t\tAND job_group = #{jobGroup}\n\t\t\t</if>\n\t\t\t<if test=\"jobId gt 0\">\n\t\t\t\tAND job_id = #{jobId}\n\t\t\t</if>\n\t\t\t<if test=\"clearBeforeTime != null\">\n\t\t\t\tAND trigger_time <![CDATA[ <= ]]> #{clearBeforeTime}\n\t\t\t</if>\n\t\t\t<if test=\"clearBeforeNum gt 0\">\n\t\t\t\tAND id NOT in(\n\t\t\t\tSELECT id FROM(\n\t\t\t\tSELECT id FROM xxl_job_log AS t\n\t\t\t\t<trim prefix=\"WHERE\" prefixOverrides=\"AND | OR\" >\n\t\t\t\t\t<if test=\"jobGroup gt 0\">\n\t\t\t\t\t\tAND t.job_group = #{jobGroup}\n\t\t\t\t\t</if>\n\t\t\t\t\t<if test=\"jobId gt 0\">\n\t\t\t\t\t\tAND t.job_id = #{jobId}\n\t\t\t\t\t</if>\n\t\t\t\t</trim>\n\t\t\t\tORDER BY t.trigger_time desc\n\t\t\t\tLIMIT 0, #{clearBeforeNum}\n\t\t\t\t) t1\n\t\t\t\t)\n\t\t\t</if>\n\t\t</trim>\n\t\torder by id asc\n\t\tLIMIT #{pagesize}\n\t</select>\n\n\t<delete id=\"clearLog\" >\n\t\tdelete from xxl_job_log\n\t\tWHERE id in\n\t\t<foreach collection=\"logIds\" item=\"item\" open=\"(\" close=\")\" separator=\",\" >\n\t\t\t#{item}\n\t\t</foreach>\n\t</delete>\n\n\t<select id=\"findFailJobLogIds\" resultType=\"long\" >\n\t\tSELECT id FROM `xxl_job_log`\n\t\tWHERE !(\n\t\t\t(trigger_code in (0, 200) and handle_code = 0)\n\t\t\tOR\n\t\t\t(handle_code = 200)\n\t\t)\n\t\tAND `alarm_status` = 0\n\t\tORDER BY id ASC\n\t\tLIMIT #{pagesize}\n\t</select>\n\n\t<update id=\"updateAlarmStatus\" >\n\t\tUPDATE xxl_job_log\n\t\tSET\n\t\t\t`alarm_status` = #{newAlarmStatus}\n\t\tWHERE `id`= #{logId} AND `alarm_status` = #{oldAlarmStatus}\n\t</update>\n\n\t<select id=\"findLostJobIds\" resultType=\"long\" >\n\t\tSELECT\n\t\t\tt.id\n\t\tFROM\n\t\t\txxl_job_log t\n\t\t\tLEFT JOIN xxl_job_registry t2 ON t.executor_address = t2.registry_value\n\t\tWHERE\n\t\t\tt.trigger_code = 200\n\t\t\t\tAND t.handle_code = 0\n\t\t\t\tAND t.trigger_time <![CDATA[ <= ]]> #{losedTime}\n\t\t\t\tAND t2.id IS NULL;\n\t</select>\n\t<!--\n\tSELECT t.id\n\tFROM xxl_job_log AS t\n\tWHERE t.trigger_code = 200\n\t\tand t.handle_code = 0\n\t\tand t.trigger_time <![CDATA[ <= ]]> #{losedTime}\n\t\tand t.executor_address not in (\n\t\t\tSELECT t2.registry_value\n\t\t\tFROM xxl_job_registry AS t2\n\t\t)\n\t-->\n\n</mapper>"
  },
  {
    "path": "xxl-job-admin/src/main/resources/mapper/XxlJobLogReportMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \n\t\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"com.xxl.job.admin.mapper.XxlJobLogReportMapper\">\n\t\n\t<resultMap id=\"XxlJobLogReport\" type=\"com.xxl.job.admin.model.XxlJobLogReport\" >\n\t\t<result column=\"id\" property=\"id\" />\n\t    <result column=\"trigger_day\" property=\"triggerDay\" />\n\t\t<result column=\"running_count\" property=\"runningCount\" />\n\t    <result column=\"suc_count\" property=\"sucCount\" />\n\t    <result column=\"fail_count\" property=\"failCount\" />\n\t</resultMap>\n\n\t<sql id=\"Base_Column_List\">\n\t\tt.id,\n\t\tt.trigger_day,\n\t\tt.running_count,\n\t\tt.suc_count,\n\t\tt.fail_count\n\t</sql>\n\t\n\t<!--<insert id=\"save\" parameterType=\"com.xxl.job.admin.model.XxlJobLogReport\" useGeneratedKeys=\"true\" keyProperty=\"id\" >\n\t\tINSERT INTO xxl_job_log_report (\n\t\t\t`trigger_day`,\n\t\t\t`running_count`,\n\t\t\t`suc_count`,\n\t\t\t`fail_count`\n\t\t) VALUES (\n\t\t\t#{triggerDay},\n\t\t\t#{runningCount},\n\t\t\t#{sucCount},\n\t\t\t#{failCount}\n\t\t);\n\t\t&lt;!&ndash;<selectKey resultType=\"java.lang.Integer\" order=\"AFTER\" keyProperty=\"id\">\n\t\t\tSELECT LAST_INSERT_ID() \n\t\t</selectKey>&ndash;&gt;\n\t</insert>\n\n\t<update id=\"update\" >\n        UPDATE xxl_job_log_report\n        SET `running_count` = #{runningCount},\n        \t`suc_count` = #{sucCount},\n        \t`fail_count` = #{failCount}\n        WHERE `trigger_day` = #{triggerDay}\n    </update>-->\n\n\t<insert id=\"saveOrUpdate\" parameterType=\"com.xxl.job.admin.model.XxlJobLogReport\" useGeneratedKeys=\"true\" keyProperty=\"id\" >\n\t\tINSERT INTO xxl_job_log_report (\n\t\t\t`trigger_day`,\n\t\t\t`running_count`,\n\t\t\t`suc_count`,\n\t\t\t`fail_count`\n\t\t) VALUES (\n\t\t\t #{triggerDay},\n\t\t\t #{runningCount},\n\t\t\t #{sucCount},\n\t\t\t #{failCount}\n\t\t )\n\t\tON DUPLICATE KEY UPDATE\n\t\t\t`running_count` = #{runningCount},\n\t\t\t`suc_count` = #{sucCount},\n\t\t\t`fail_count` = #{failCount}\n\t</insert>\n\n\t<select id=\"queryLogReport\" resultMap=\"XxlJobLogReport\">\n\t\tSELECT <include refid=\"Base_Column_List\" />\n\t\tFROM xxl_job_log_report AS t\n\t\tWHERE t.trigger_day between #{triggerDayFrom} and #{triggerDayTo}\n\t\tORDER BY t.trigger_day ASC\n\t</select>\n\n\t<select id=\"queryLogReportTotal\" resultMap=\"XxlJobLogReport\">\n\t\tSELECT\n\t\t\tSUM(running_count) running_count,\n\t\t\tSUM(suc_count) suc_count,\n\t\t\tSUM(fail_count) fail_count\n\t\tFROM xxl_job_log_report AS t\n\t</select>\n\n</mapper>"
  },
  {
    "path": "xxl-job-admin/src/main/resources/mapper/XxlJobRegistryMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \n\t\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"com.xxl.job.admin.mapper.XxlJobRegistryMapper\">\n\t\n\t<resultMap id=\"XxlJobRegistry\" type=\"com.xxl.job.admin.model.XxlJobRegistry\" >\n\t\t<result column=\"id\" property=\"id\" />\n\t    <result column=\"registry_group\" property=\"registryGroup\" />\n\t    <result column=\"registry_key\" property=\"registryKey\" />\n\t    <result column=\"registry_value\" property=\"registryValue\" />\n\t\t<result column=\"update_time\" property=\"updateTime\" />\n\t</resultMap>\n\n\t<sql id=\"Base_Column_List\">\n\t\tt.id,\n\t\tt.registry_group,\n\t\tt.registry_key,\n\t\tt.registry_value,\n\t\tt.update_time\n\t</sql>\n\n\t<select id=\"findDead\" parameterType=\"java.util.HashMap\" resultType=\"java.lang.Integer\" >\n\t\tSELECT t.id\n\t\tFROM xxl_job_registry AS t\n\t\tWHERE t.update_time <![CDATA[ < ]]> DATE_ADD(#{nowTime},INTERVAL -#{timeout} SECOND)\n\t</select>\n\t\n\t<delete id=\"removeDead\" parameterType=\"java.lang.Integer\" >\n\t\tDELETE FROM xxl_job_registry\n\t\tWHERE id in\n\t\t<foreach collection=\"ids\" item=\"item\" open=\"(\" close=\")\" separator=\",\" >\n\t\t\t#{item}\n\t\t</foreach>\n\t</delete>\n\n\t<select id=\"findAll\" parameterType=\"java.util.HashMap\" resultMap=\"XxlJobRegistry\">\n\t\tSELECT <include refid=\"Base_Column_List\" />\n\t\tFROM xxl_job_registry AS t\n\t\tWHERE t.update_time <![CDATA[ > ]]> DATE_ADD(#{nowTime},INTERVAL -#{timeout} SECOND)\n\t</select>\n\n\t<insert id=\"registrySaveOrUpdate\" >\n\t\tINSERT INTO xxl_job_registry( `registry_group` , `registry_key` , `registry_value`, `update_time`)\n\t\tVALUES( #{registryGroup}  , #{registryKey} , #{registryValue}, #{updateTime})\n\t\tON DUPLICATE KEY UPDATE\n\t\t\t`update_time` = #{updateTime}\n\t</insert>\n\n\t<!--\n    <update id=\"registryUpdate\" >\n        UPDATE xxl_job_registry\n        SET `update_time` = #{updateTime}\n        WHERE `registry_group` = #{registryGroup}\n          AND `registry_key` = #{registryKey}\n          AND `registry_value` = #{registryValue}\n    </update>\n\n    <insert id=\"registrySave\" >\n        INSERT INTO xxl_job_registry( `registry_group` , `registry_key` , `registry_value`, `update_time`)\n        VALUES( #{registryGroup}  , #{registryKey} , #{registryValue}, #{updateTime})\n    </insert>\n\t-->\n\n\t<delete id=\"registryDelete\" >\n\t\tDELETE FROM xxl_job_registry\n\t\tWHERE registry_group = #{registryGroup}\n\t\t\tAND registry_key = #{registryKey}\n\t\t\tAND registry_value = #{registryValue}\n\t</delete>\n\n    <delete id=\"removeByRegistryGroupAndKey\" >\n        DELETE FROM xxl_job_registry\n        WHERE registry_group = #{registryGroup}\n          AND registry_key = #{registryKey}\n    </delete>\n\n</mapper>"
  },
  {
    "path": "xxl-job-admin/src/main/resources/mapper/XxlJobUserMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n\t\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"com.xxl.job.admin.mapper.XxlJobUserMapper\">\n\n\t<resultMap id=\"XxlJobUser\" type=\"com.xxl.job.admin.model.XxlJobUser\" >\n\t\t<result column=\"id\" property=\"id\" />\n\t\t<result column=\"username\" property=\"username\" />\n\t    <result column=\"password\" property=\"password\" />\n\t\t<result column=\"token\" property=\"token\" />\n\t    <result column=\"role\" property=\"role\" />\n\t    <result column=\"permission\" property=\"permission\" />\n\t</resultMap>\n\n\t<sql id=\"Base_Column_List\">\n\t\tt.id,\n\t\tt.username,\n\t\tt.password,\n\t\tt.token,\n\t\tt.role,\n\t\tt.permission\n\t</sql>\n\n\t<select id=\"pageList\" parameterType=\"java.util.HashMap\" resultMap=\"XxlJobUser\">\n\t\tSELECT <include refid=\"Base_Column_List\" />\n\t\tFROM xxl_job_user AS t\n\t\t<trim prefix=\"WHERE\" prefixOverrides=\"AND | OR\" >\n\t\t\t<if test=\"username != null and username != ''\">\n\t\t\t\tAND t.username like CONCAT(CONCAT('%', #{username}), '%')\n\t\t\t</if>\n\t\t\t<if test=\"role gt -1\">\n\t\t\t\tAND t.role = #{role}\n\t\t\t</if>\n\t\t</trim>\n\t\tORDER BY username ASC\n\t\tLIMIT #{offset}, #{pagesize}\n\t</select>\n\n\t<select id=\"pageListCount\" parameterType=\"java.util.HashMap\" resultType=\"int\">\n\t\tSELECT count(1)\n\t\tFROM xxl_job_user AS t\n\t\t<trim prefix=\"WHERE\" prefixOverrides=\"AND | OR\" >\n\t\t\t<if test=\"username != null and username != ''\">\n\t\t\t\tAND t.username like CONCAT(CONCAT('%', #{username}), '%')\n\t\t\t</if>\n\t\t\t<if test=\"role gt -1\">\n\t\t\t\tAND t.role = #{role}\n\t\t\t</if>\n\t\t</trim>\n\t</select>\n\n\t<select id=\"loadByUserName\" parameterType=\"java.util.HashMap\" resultMap=\"XxlJobUser\">\n\t\tSELECT <include refid=\"Base_Column_List\" />\n\t\tFROM xxl_job_user AS t\n\t\tWHERE t.username = #{username}\n\t</select>\n\n\t<select id=\"loadById\" parameterType=\"java.util.HashMap\" resultMap=\"XxlJobUser\">\n\t\tSELECT <include refid=\"Base_Column_List\" />\n\t\tFROM xxl_job_user AS t\n\t\tWHERE t.id = #{id}\n\t</select>\n\n\t<insert id=\"save\" parameterType=\"com.xxl.job.admin.model.XxlJobUser\" useGeneratedKeys=\"true\" keyProperty=\"id\" >\n\t\tINSERT INTO xxl_job_user (\n\t\t\tusername,\n\t\t\tpassword,\n\t\t\trole,\n\t\t\tpermission\n\t\t) VALUES (\n\t\t\t#{username},\n\t\t\t#{password},\n\t\t\t#{role},\n\t\t\t#{permission}\n\t\t);\n\t</insert>\n\n\t<update id=\"update\" parameterType=\"com.xxl.job.admin.model.XxlJobUser\" >\n\t\tUPDATE xxl_job_user\n\t\tSET\n\t\t\t<if test=\"password != null and password != ''\">\n\t\t\t\tpassword = #{password},\n\t\t\t</if>\n\t\t\trole = #{role},\n\t\t\tpermission = #{permission}\n\t\tWHERE id = #{id}\n\t</update>\n\n\t<delete id=\"delete\" parameterType=\"java.util.HashMap\">\n\t\tDELETE\n\t\tFROM xxl_job_user\n\t\tWHERE id = #{id}\n\t</delete>\n\n\t<update id=\"updateToken\" parameterType=\"java.util.HashMap\" >\n\t\tUPDATE xxl_job_user\n\t\tSET token = #{token}\n\t\tWHERE id = #{id}\n\t</update>\n\n</mapper>"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/adminlte/bower_components/bootstrap-daterangepicker/daterangepicker.css",
    "content": ".daterangepicker {\n  position: absolute;\n  color: inherit;\n  background-color: #fff;\n  border-radius: 4px;\n  width: 278px;\n  padding: 4px;\n  margin-top: 1px;\n  top: 100px;\n  left: 20px;\n  /* Calendars */ }\n  .daterangepicker:before, .daterangepicker:after {\n    position: absolute;\n    display: inline-block;\n    border-bottom-color: rgba(0, 0, 0, 0.2);\n    content: ''; }\n  .daterangepicker:before {\n    top: -7px;\n    border-right: 7px solid transparent;\n    border-left: 7px solid transparent;\n    border-bottom: 7px solid #ccc; }\n  .daterangepicker:after {\n    top: -6px;\n    border-right: 6px solid transparent;\n    border-bottom: 6px solid #fff;\n    border-left: 6px solid transparent; }\n  .daterangepicker.opensleft:before {\n    right: 9px; }\n  .daterangepicker.opensleft:after {\n    right: 10px; }\n  .daterangepicker.openscenter:before {\n    left: 0;\n    right: 0;\n    width: 0;\n    margin-left: auto;\n    margin-right: auto; }\n  .daterangepicker.openscenter:after {\n    left: 0;\n    right: 0;\n    width: 0;\n    margin-left: auto;\n    margin-right: auto; }\n  .daterangepicker.opensright:before {\n    left: 9px; }\n  .daterangepicker.opensright:after {\n    left: 10px; }\n  .daterangepicker.dropup {\n    margin-top: -5px; }\n    .daterangepicker.dropup:before {\n      top: initial;\n      bottom: -7px;\n      border-bottom: initial;\n      border-top: 7px solid #ccc; }\n    .daterangepicker.dropup:after {\n      top: initial;\n      bottom: -6px;\n      border-bottom: initial;\n      border-top: 6px solid #fff; }\n  .daterangepicker.dropdown-menu {\n    max-width: none;\n    z-index: 3001; }\n  .daterangepicker.single .ranges, .daterangepicker.single .calendar {\n    float: none; }\n  .daterangepicker.show-calendar .calendar {\n    display: block; }\n  .daterangepicker .calendar {\n    display: none;\n    max-width: 270px;\n    margin: 4px; }\n    .daterangepicker .calendar.single .calendar-table {\n      border: none; }\n    .daterangepicker .calendar th, .daterangepicker .calendar td {\n      white-space: nowrap;\n      text-align: center;\n      min-width: 32px; }\n  .daterangepicker .calendar-table {\n    border: 1px solid #fff;\n    padding: 4px;\n    border-radius: 4px;\n    background-color: #fff; }\n  .daterangepicker table {\n    width: 100%;\n    margin: 0; }\n  .daterangepicker td, .daterangepicker th {\n    text-align: center;\n    width: 20px;\n    height: 20px;\n    border-radius: 4px;\n    border: 1px solid transparent;\n    white-space: nowrap;\n    cursor: pointer; }\n    .daterangepicker td.available:hover, .daterangepicker th.available:hover {\n      background-color: #eee;\n      border-color: transparent;\n      color: inherit; }\n    .daterangepicker td.week, .daterangepicker th.week {\n      font-size: 80%;\n      color: #ccc; }\n  .daterangepicker td.off, .daterangepicker td.off.in-range, .daterangepicker td.off.start-date, .daterangepicker td.off.end-date {\n    background-color: #fff;\n    border-color: transparent;\n    color: #999; }\n  .daterangepicker td.in-range {\n    background-color: #ebf4f8;\n    border-color: transparent;\n    color: #000;\n    border-radius: 0; }\n  .daterangepicker td.start-date {\n    border-radius: 4px 0 0 4px; }\n  .daterangepicker td.end-date {\n    border-radius: 0 4px 4px 0; }\n  .daterangepicker td.start-date.end-date {\n    border-radius: 4px; }\n  .daterangepicker td.active, .daterangepicker td.active:hover {\n    background-color: #357ebd;\n    border-color: transparent;\n    color: #fff; }\n  .daterangepicker th.month {\n    width: auto; }\n  .daterangepicker td.disabled, .daterangepicker option.disabled {\n    color: #999;\n    cursor: not-allowed;\n    text-decoration: line-through; }\n  .daterangepicker select.monthselect, .daterangepicker select.yearselect {\n    font-size: 12px;\n    padding: 1px;\n    height: auto;\n    margin: 0;\n    cursor: default; }\n  .daterangepicker select.monthselect {\n    margin-right: 2%;\n    width: 56%; }\n  .daterangepicker select.yearselect {\n    width: 40%; }\n  .daterangepicker select.hourselect, .daterangepicker select.minuteselect, .daterangepicker select.secondselect, .daterangepicker select.ampmselect {\n    width: 50px;\n    margin-bottom: 0; }\n  .daterangepicker .input-mini {\n    border: 1px solid #ccc;\n    border-radius: 4px;\n    color: #555;\n    height: 30px;\n    line-height: 30px;\n    display: block;\n    vertical-align: middle;\n    margin: 0 0 5px 0;\n    padding: 0 6px 0 28px;\n    width: 100%; }\n    .daterangepicker .input-mini.active {\n      border: 1px solid #08c;\n      border-radius: 4px; }\n  .daterangepicker .daterangepicker_input {\n    position: relative; }\n    .daterangepicker .daterangepicker_input i {\n      position: absolute;\n      left: 8px;\n      top: 8px; }\n  .daterangepicker.rtl .input-mini {\n    padding-right: 28px;\n    padding-left: 6px; }\n  .daterangepicker.rtl .daterangepicker_input i {\n    left: auto;\n    right: 8px; }\n  .daterangepicker .calendar-time {\n    text-align: center;\n    margin: 5px auto;\n    line-height: 30px;\n    position: relative;\n    padding-left: 28px; }\n    .daterangepicker .calendar-time select.disabled {\n      color: #ccc;\n      cursor: not-allowed; }\n\n.ranges {\n  font-size: 11px;\n  float: none;\n  margin: 4px;\n  text-align: left; }\n  .ranges ul {\n    list-style: none;\n    margin: 0 auto;\n    padding: 0;\n    width: 100%; }\n  .ranges li {\n    font-size: 13px;\n    background-color: #f5f5f5;\n    border: 1px solid #f5f5f5;\n    border-radius: 4px;\n    color: #08c;\n    padding: 3px 12px;\n    margin-bottom: 8px;\n    cursor: pointer; }\n    .ranges li:hover {\n      background-color: #08c;\n      border: 1px solid #08c;\n      color: #fff; }\n    .ranges li.active {\n      background-color: #08c;\n      border: 1px solid #08c;\n      color: #fff; }\n\n/*  Larger Screen Styling */\n@media (min-width: 564px) {\n  .daterangepicker {\n    width: auto; }\n    .daterangepicker .ranges ul {\n      width: 160px; }\n    .daterangepicker.single .ranges ul {\n      width: 100%; }\n    .daterangepicker.single .calendar.left {\n      clear: none; }\n    .daterangepicker.single.ltr .ranges, .daterangepicker.single.ltr .calendar {\n      float: left; }\n    .daterangepicker.single.rtl .ranges, .daterangepicker.single.rtl .calendar {\n      float: right; }\n    .daterangepicker.ltr {\n      direction: ltr;\n      text-align: left; }\n      .daterangepicker.ltr .calendar.left {\n        clear: left;\n        margin-right: 0; }\n        .daterangepicker.ltr .calendar.left .calendar-table {\n          border-right: none;\n          border-top-right-radius: 0;\n          border-bottom-right-radius: 0; }\n      .daterangepicker.ltr .calendar.right {\n        margin-left: 0; }\n        .daterangepicker.ltr .calendar.right .calendar-table {\n          border-left: none;\n          border-top-left-radius: 0;\n          border-bottom-left-radius: 0; }\n      .daterangepicker.ltr .left .daterangepicker_input {\n        padding-right: 12px; }\n      .daterangepicker.ltr .calendar.left .calendar-table {\n        padding-right: 12px; }\n      .daterangepicker.ltr .ranges, .daterangepicker.ltr .calendar {\n        float: left; }\n    .daterangepicker.rtl {\n      direction: rtl;\n      text-align: right; }\n      .daterangepicker.rtl .calendar.left {\n        clear: right;\n        margin-left: 0; }\n        .daterangepicker.rtl .calendar.left .calendar-table {\n          border-left: none;\n          border-top-left-radius: 0;\n          border-bottom-left-radius: 0; }\n      .daterangepicker.rtl .calendar.right {\n        margin-right: 0; }\n        .daterangepicker.rtl .calendar.right .calendar-table {\n          border-right: none;\n          border-top-right-radius: 0;\n          border-bottom-right-radius: 0; }\n      .daterangepicker.rtl .left .daterangepicker_input {\n        padding-left: 12px; }\n      .daterangepicker.rtl .calendar.left .calendar-table {\n        padding-left: 12px; }\n      .daterangepicker.rtl .ranges, .daterangepicker.rtl .calendar {\n        text-align: right;\n        float: right; } }\n@media (min-width: 730px) {\n  .daterangepicker .ranges {\n    width: auto; }\n  .daterangepicker.ltr .ranges {\n    float: left; }\n  .daterangepicker.rtl .ranges {\n    float: right; }\n  .daterangepicker .calendar.left {\n    clear: none !important; } }\n"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/adminlte/bower_components/bootstrap-daterangepicker/daterangepicker.js",
    "content": "/**\n* @version: 2.1.27\n* @author: Dan Grossman http://www.dangrossman.info/\n* @copyright: Copyright (c) 2012-2017 Dan Grossman. All rights reserved.\n* @license: Licensed under the MIT license. See http://www.opensource.org/licenses/mit-license.php\n* @website: http://www.daterangepicker.com/\n*/\n// Follow the UMD template https://github.com/umdjs/umd/blob/master/templates/returnExportsGlobal.js\n(function (root, factory) {\n    if (typeof define === 'function' && define.amd) {\n        // AMD. Make globaly available as well\n        define(['moment', 'jquery'], function (moment, jquery) {\n            if (!jquery.fn) jquery.fn = {}; // webpack server rendering\n            return factory(moment, jquery);\n        });\n    } else if (typeof module === 'object' && module.exports) {\n        // Node / Browserify\n        //isomorphic issue\n        var jQuery = (typeof window != 'undefined') ? window.jQuery : undefined;\n        if (!jQuery) {\n            jQuery = require('jquery');\n            if (!jQuery.fn) jQuery.fn = {};\n        }\n        var moment = (typeof window != 'undefined' && typeof window.moment != 'undefined') ? window.moment : require('moment');\n        module.exports = factory(moment, jQuery);\n    } else {\n        // Browser globals\n        root.daterangepicker = factory(root.moment, root.jQuery);\n    }\n}(this, function(moment, $) {\n    var DateRangePicker = function(element, options, cb) {\n\n        //default settings for options\n        this.parentEl = 'body';\n        this.element = $(element);\n        this.startDate = moment().startOf('day');\n        this.endDate = moment().endOf('day');\n        this.minDate = false;\n        this.maxDate = false;\n        this.dateLimit = false;\n        this.autoApply = false;\n        this.singleDatePicker = false;\n        this.showDropdowns = false;\n        this.showWeekNumbers = false;\n        this.showISOWeekNumbers = false;\n        this.showCustomRangeLabel = true;\n        this.timePicker = false;\n        this.timePicker24Hour = false;\n        this.timePickerIncrement = 1;\n        this.timePickerSeconds = false;\n        this.linkedCalendars = true;\n        this.autoUpdateInput = true;\n        this.alwaysShowCalendars = false;\n        this.ranges = {};\n\n        this.opens = 'right';\n        if (this.element.hasClass('pull-right'))\n            this.opens = 'left';\n\n        this.drops = 'down';\n        if (this.element.hasClass('dropup'))\n            this.drops = 'up';\n\n        this.buttonClasses = 'btn btn-sm';\n        this.applyClass = 'btn-success';\n        this.cancelClass = 'btn-default';\n\n        this.locale = {\n            direction: 'ltr',\n            format: moment.localeData().longDateFormat('L'),\n            separator: ' - ',\n            applyLabel: 'Apply',\n            cancelLabel: 'Cancel',\n            weekLabel: 'W',\n            customRangeLabel: 'Custom Range',\n            daysOfWeek: moment.weekdaysMin(),\n            monthNames: moment.monthsShort(),\n            firstDay: moment.localeData().firstDayOfWeek()\n        };\n\n        this.callback = function() { };\n\n        //some state information\n        this.isShowing = false;\n        this.leftCalendar = {};\n        this.rightCalendar = {};\n\n        //custom options from user\n        if (typeof options !== 'object' || options === null)\n            options = {};\n\n        //allow setting options with data attributes\n        //data-api options will be overwritten with custom javascript options\n        options = $.extend(this.element.data(), options);\n\n        //html template for the picker UI\n        if (typeof options.template !== 'string' && !(options.template instanceof $))\n            options.template = '<div class=\"daterangepicker dropdown-menu\">' +\n                '<div class=\"calendar left\">' +\n                    '<div class=\"daterangepicker_input\">' +\n                      '<input class=\"input-mini form-control\" type=\"text\" name=\"daterangepicker_start\" value=\"\" />' +\n                      '<i class=\"fa fa-calendar glyphicon glyphicon-calendar\"></i>' +\n                      '<div class=\"calendar-time\">' +\n                        '<div></div>' +\n                        '<i class=\"fa fa-clock-o glyphicon glyphicon-time\"></i>' +\n                      '</div>' +\n                    '</div>' +\n                    '<div class=\"calendar-table\"></div>' +\n                '</div>' +\n                '<div class=\"calendar right\">' +\n                    '<div class=\"daterangepicker_input\">' +\n                      '<input class=\"input-mini form-control\" type=\"text\" name=\"daterangepicker_end\" value=\"\" />' +\n                      '<i class=\"fa fa-calendar glyphicon glyphicon-calendar\"></i>' +\n                      '<div class=\"calendar-time\">' +\n                        '<div></div>' +\n                        '<i class=\"fa fa-clock-o glyphicon glyphicon-time\"></i>' +\n                      '</div>' +\n                    '</div>' +\n                    '<div class=\"calendar-table\"></div>' +\n                '</div>' +\n                '<div class=\"ranges\">' +\n                    '<div class=\"range_inputs\">' +\n                        '<button class=\"applyBtn\" disabled=\"disabled\" type=\"button\"></button> ' +\n                        '<button class=\"cancelBtn\" type=\"button\"></button>' +\n                    '</div>' +\n                '</div>' +\n            '</div>';\n\n        this.parentEl = (options.parentEl && $(options.parentEl).length) ? $(options.parentEl) : $(this.parentEl);\n        this.container = $(options.template).appendTo(this.parentEl);\n\n        //\n        // handle all the possible options overriding defaults\n        //\n\n        if (typeof options.locale === 'object') {\n\n            if (typeof options.locale.direction === 'string')\n                this.locale.direction = options.locale.direction;\n\n            if (typeof options.locale.format === 'string')\n                this.locale.format = options.locale.format;\n\n            if (typeof options.locale.separator === 'string')\n                this.locale.separator = options.locale.separator;\n\n            if (typeof options.locale.daysOfWeek === 'object')\n                this.locale.daysOfWeek = options.locale.daysOfWeek.slice();\n\n            if (typeof options.locale.monthNames === 'object')\n              this.locale.monthNames = options.locale.monthNames.slice();\n\n            if (typeof options.locale.firstDay === 'number')\n              this.locale.firstDay = options.locale.firstDay;\n\n            if (typeof options.locale.applyLabel === 'string')\n              this.locale.applyLabel = options.locale.applyLabel;\n\n            if (typeof options.locale.cancelLabel === 'string')\n              this.locale.cancelLabel = options.locale.cancelLabel;\n\n            if (typeof options.locale.weekLabel === 'string')\n              this.locale.weekLabel = options.locale.weekLabel;\n\n            if (typeof options.locale.customRangeLabel === 'string'){\n                //Support unicode chars in the custom range name.\n                var elem = document.createElement('textarea');\n                elem.innerHTML = options.locale.customRangeLabel;\n                var rangeHtml = elem.value;\n                this.locale.customRangeLabel = rangeHtml;\n            }\n        }\n        this.container.addClass(this.locale.direction);\n\n        if (typeof options.startDate === 'string')\n            this.startDate = moment(options.startDate, this.locale.format);\n\n        if (typeof options.endDate === 'string')\n            this.endDate = moment(options.endDate, this.locale.format);\n\n        if (typeof options.minDate === 'string')\n            this.minDate = moment(options.minDate, this.locale.format);\n\n        if (typeof options.maxDate === 'string')\n            this.maxDate = moment(options.maxDate, this.locale.format);\n\n        if (typeof options.startDate === 'object')\n            this.startDate = moment(options.startDate);\n\n        if (typeof options.endDate === 'object')\n            this.endDate = moment(options.endDate);\n\n        if (typeof options.minDate === 'object')\n            this.minDate = moment(options.minDate);\n\n        if (typeof options.maxDate === 'object')\n            this.maxDate = moment(options.maxDate);\n\n        // sanity check for bad options\n        if (this.minDate && this.startDate.isBefore(this.minDate))\n            this.startDate = this.minDate.clone();\n\n        // sanity check for bad options\n        if (this.maxDate && this.endDate.isAfter(this.maxDate))\n            this.endDate = this.maxDate.clone();\n\n        if (typeof options.applyClass === 'string')\n            this.applyClass = options.applyClass;\n\n        if (typeof options.cancelClass === 'string')\n            this.cancelClass = options.cancelClass;\n\n        if (typeof options.dateLimit === 'object')\n            this.dateLimit = options.dateLimit;\n\n        if (typeof options.opens === 'string')\n            this.opens = options.opens;\n\n        if (typeof options.drops === 'string')\n            this.drops = options.drops;\n\n        if (typeof options.showWeekNumbers === 'boolean')\n            this.showWeekNumbers = options.showWeekNumbers;\n\n        if (typeof options.showISOWeekNumbers === 'boolean')\n            this.showISOWeekNumbers = options.showISOWeekNumbers;\n\n        if (typeof options.buttonClasses === 'string')\n            this.buttonClasses = options.buttonClasses;\n\n        if (typeof options.buttonClasses === 'object')\n            this.buttonClasses = options.buttonClasses.join(' ');\n\n        if (typeof options.showDropdowns === 'boolean')\n            this.showDropdowns = options.showDropdowns;\n\n        if (typeof options.showCustomRangeLabel === 'boolean')\n            this.showCustomRangeLabel = options.showCustomRangeLabel;\n\n        if (typeof options.singleDatePicker === 'boolean') {\n            this.singleDatePicker = options.singleDatePicker;\n            if (this.singleDatePicker)\n                this.endDate = this.startDate.clone();\n        }\n\n        if (typeof options.timePicker === 'boolean')\n            this.timePicker = options.timePicker;\n\n        if (typeof options.timePickerSeconds === 'boolean')\n            this.timePickerSeconds = options.timePickerSeconds;\n\n        if (typeof options.timePickerIncrement === 'number')\n            this.timePickerIncrement = options.timePickerIncrement;\n\n        if (typeof options.timePicker24Hour === 'boolean')\n            this.timePicker24Hour = options.timePicker24Hour;\n\n        if (typeof options.autoApply === 'boolean')\n            this.autoApply = options.autoApply;\n\n        if (typeof options.autoUpdateInput === 'boolean')\n            this.autoUpdateInput = options.autoUpdateInput;\n\n        if (typeof options.linkedCalendars === 'boolean')\n            this.linkedCalendars = options.linkedCalendars;\n\n        if (typeof options.isInvalidDate === 'function')\n            this.isInvalidDate = options.isInvalidDate;\n\n        if (typeof options.isCustomDate === 'function')\n            this.isCustomDate = options.isCustomDate;\n\n        if (typeof options.alwaysShowCalendars === 'boolean')\n            this.alwaysShowCalendars = options.alwaysShowCalendars;\n\n        // update day names order to firstDay\n        if (this.locale.firstDay != 0) {\n            var iterator = this.locale.firstDay;\n            while (iterator > 0) {\n                this.locale.daysOfWeek.push(this.locale.daysOfWeek.shift());\n                iterator--;\n            }\n        }\n\n        var start, end, range;\n\n        //if no start/end dates set, check if an input element contains initial values\n        if (typeof options.startDate === 'undefined' && typeof options.endDate === 'undefined') {\n            if ($(this.element).is('input[type=text]')) {\n                var val = $(this.element).val(),\n                    split = val.split(this.locale.separator);\n\n                start = end = null;\n\n                if (split.length == 2) {\n                    start = moment(split[0], this.locale.format);\n                    end = moment(split[1], this.locale.format);\n                } else if (this.singleDatePicker && val !== \"\") {\n                    start = moment(val, this.locale.format);\n                    end = moment(val, this.locale.format);\n                }\n                if (start !== null && end !== null) {\n                    this.setStartDate(start);\n                    this.setEndDate(end);\n                }\n            }\n        }\n\n        if (typeof options.ranges === 'object') {\n            for (range in options.ranges) {\n\n                if (typeof options.ranges[range][0] === 'string')\n                    start = moment(options.ranges[range][0], this.locale.format);\n                else\n                    start = moment(options.ranges[range][0]);\n\n                if (typeof options.ranges[range][1] === 'string')\n                    end = moment(options.ranges[range][1], this.locale.format);\n                else\n                    end = moment(options.ranges[range][1]);\n\n                // If the start or end date exceed those allowed by the minDate or dateLimit\n                // options, shorten the range to the allowable period.\n                if (this.minDate && start.isBefore(this.minDate))\n                    start = this.minDate.clone();\n\n                var maxDate = this.maxDate;\n                if (this.dateLimit && maxDate && start.clone().add(this.dateLimit).isAfter(maxDate))\n                    maxDate = start.clone().add(this.dateLimit);\n                if (maxDate && end.isAfter(maxDate))\n                    end = maxDate.clone();\n\n                // If the end of the range is before the minimum or the start of the range is\n                // after the maximum, don't display this range option at all.\n                if ((this.minDate && end.isBefore(this.minDate, this.timepicker ? 'minute' : 'day')) \n                  || (maxDate && start.isAfter(maxDate, this.timepicker ? 'minute' : 'day')))\n                    continue;\n\n                //Support unicode chars in the range names.\n                var elem = document.createElement('textarea');\n                elem.innerHTML = range;\n                var rangeHtml = elem.value;\n\n                this.ranges[rangeHtml] = [start, end];\n            }\n\n            var list = '<ul>';\n            for (range in this.ranges) {\n                list += '<li data-range-key=\"' + range + '\">' + range + '</li>';\n            }\n            if (this.showCustomRangeLabel) {\n                list += '<li data-range-key=\"' + this.locale.customRangeLabel + '\">' + this.locale.customRangeLabel + '</li>';\n            }\n            list += '</ul>';\n            this.container.find('.ranges').prepend(list);\n        }\n\n        if (typeof cb === 'function') {\n            this.callback = cb;\n        }\n\n        if (!this.timePicker) {\n            this.startDate = this.startDate.startOf('day');\n            this.endDate = this.endDate.endOf('day');\n            this.container.find('.calendar-time').hide();\n        }\n\n        //can't be used together for now\n        if (this.timePicker && this.autoApply)\n            this.autoApply = false;\n\n        if (this.autoApply && typeof options.ranges !== 'object') {\n            this.container.find('.ranges').hide();\n        } else if (this.autoApply) {\n            this.container.find('.applyBtn, .cancelBtn').addClass('hide');\n        }\n\n        if (this.singleDatePicker) {\n            this.container.addClass('single');\n            this.container.find('.calendar.left').addClass('single');\n            this.container.find('.calendar.left').show();\n            this.container.find('.calendar.right').hide();\n            this.container.find('.daterangepicker_input input, .daterangepicker_input > i').hide();\n            if (this.timePicker) {\n                this.container.find('.ranges ul').hide();\n            } else {\n                this.container.find('.ranges').hide();\n            }\n        }\n\n        if ((typeof options.ranges === 'undefined' && !this.singleDatePicker) || this.alwaysShowCalendars) {\n            this.container.addClass('show-calendar');\n        }\n\n        this.container.addClass('opens' + this.opens);\n\n        //swap the position of the predefined ranges if opens right\n        if (typeof options.ranges !== 'undefined' && this.opens == 'right') {\n            this.container.find('.ranges').prependTo( this.container.find('.calendar.left').parent() );\n        }\n\n        //apply CSS classes and labels to buttons\n        this.container.find('.applyBtn, .cancelBtn').addClass(this.buttonClasses);\n        if (this.applyClass.length)\n            this.container.find('.applyBtn').addClass(this.applyClass);\n        if (this.cancelClass.length)\n            this.container.find('.cancelBtn').addClass(this.cancelClass);\n        this.container.find('.applyBtn').html(this.locale.applyLabel);\n        this.container.find('.cancelBtn').html(this.locale.cancelLabel);\n\n        //\n        // event listeners\n        //\n\n        this.container.find('.calendar')\n            .on('click.daterangepicker', '.prev', $.proxy(this.clickPrev, this))\n            .on('click.daterangepicker', '.next', $.proxy(this.clickNext, this))\n            .on('mousedown.daterangepicker', 'td.available', $.proxy(this.clickDate, this))\n            .on('mouseenter.daterangepicker', 'td.available', $.proxy(this.hoverDate, this))\n            .on('mouseleave.daterangepicker', 'td.available', $.proxy(this.updateFormInputs, this))\n            .on('change.daterangepicker', 'select.yearselect', $.proxy(this.monthOrYearChanged, this))\n            .on('change.daterangepicker', 'select.monthselect', $.proxy(this.monthOrYearChanged, this))\n            .on('change.daterangepicker', 'select.hourselect,select.minuteselect,select.secondselect,select.ampmselect', $.proxy(this.timeChanged, this))\n            .on('click.daterangepicker', '.daterangepicker_input input', $.proxy(this.showCalendars, this))\n            .on('focus.daterangepicker', '.daterangepicker_input input', $.proxy(this.formInputsFocused, this))\n            .on('blur.daterangepicker', '.daterangepicker_input input', $.proxy(this.formInputsBlurred, this))\n            .on('change.daterangepicker', '.daterangepicker_input input', $.proxy(this.formInputsChanged, this))\n            .on('keydown.daterangepicker', '.daterangepicker_input input', $.proxy(this.formInputsKeydown, this));\n\n        this.container.find('.ranges')\n            .on('click.daterangepicker', 'button.applyBtn', $.proxy(this.clickApply, this))\n            .on('click.daterangepicker', 'button.cancelBtn', $.proxy(this.clickCancel, this))\n            .on('click.daterangepicker', 'li', $.proxy(this.clickRange, this))\n            .on('mouseenter.daterangepicker', 'li', $.proxy(this.hoverRange, this))\n            .on('mouseleave.daterangepicker', 'li', $.proxy(this.updateFormInputs, this));\n\n        if (this.element.is('input') || this.element.is('button')) {\n            this.element.on({\n                'click.daterangepicker': $.proxy(this.show, this),\n                'focus.daterangepicker': $.proxy(this.show, this),\n                'keyup.daterangepicker': $.proxy(this.elementChanged, this),\n                'keydown.daterangepicker': $.proxy(this.keydown, this) //IE 11 compatibility\n            });\n        } else {\n            this.element.on('click.daterangepicker', $.proxy(this.toggle, this));\n            this.element.on('keydown.daterangepicker', $.proxy(this.toggle, this));\n        }\n\n        //\n        // if attached to a text input, set the initial value\n        //\n\n        if (this.element.is('input') && !this.singleDatePicker && this.autoUpdateInput) {\n            this.element.val(this.startDate.format(this.locale.format) + this.locale.separator + this.endDate.format(this.locale.format));\n            this.element.trigger('change');\n        } else if (this.element.is('input') && this.autoUpdateInput) {\n            this.element.val(this.startDate.format(this.locale.format));\n            this.element.trigger('change');\n        }\n\n    };\n\n    DateRangePicker.prototype = {\n\n        constructor: DateRangePicker,\n\n        setStartDate: function(startDate) {\n            if (typeof startDate === 'string')\n                this.startDate = moment(startDate, this.locale.format);\n\n            if (typeof startDate === 'object')\n                this.startDate = moment(startDate);\n\n            if (!this.timePicker)\n                this.startDate = this.startDate.startOf('day');\n\n            if (this.timePicker && this.timePickerIncrement)\n                this.startDate.minute(Math.round(this.startDate.minute() / this.timePickerIncrement) * this.timePickerIncrement);\n\n            if (this.minDate && this.startDate.isBefore(this.minDate)) {\n                this.startDate = this.minDate.clone();\n                if (this.timePicker && this.timePickerIncrement)\n                    this.startDate.minute(Math.round(this.startDate.minute() / this.timePickerIncrement) * this.timePickerIncrement);\n            }\n\n            if (this.maxDate && this.startDate.isAfter(this.maxDate)) {\n                this.startDate = this.maxDate.clone();\n                if (this.timePicker && this.timePickerIncrement)\n                    this.startDate.minute(Math.floor(this.startDate.minute() / this.timePickerIncrement) * this.timePickerIncrement);\n            }\n\n            if (!this.isShowing)\n                this.updateElement();\n\n            this.updateMonthsInView();\n        },\n\n        setEndDate: function(endDate) {\n            if (typeof endDate === 'string')\n                this.endDate = moment(endDate, this.locale.format);\n\n            if (typeof endDate === 'object')\n                this.endDate = moment(endDate);\n\n            if (!this.timePicker)\n                this.endDate = this.endDate.add(1,'d').startOf('day').subtract(1,'second');\n\n            if (this.timePicker && this.timePickerIncrement)\n                this.endDate.minute(Math.round(this.endDate.minute() / this.timePickerIncrement) * this.timePickerIncrement);\n\n            if (this.endDate.isBefore(this.startDate))\n                this.endDate = this.startDate.clone();\n\n            if (this.maxDate && this.endDate.isAfter(this.maxDate))\n                this.endDate = this.maxDate.clone();\n\n            if (this.dateLimit && this.startDate.clone().add(this.dateLimit).isBefore(this.endDate))\n                this.endDate = this.startDate.clone().add(this.dateLimit);\n\n            this.previousRightTime = this.endDate.clone();\n\n            if (!this.isShowing)\n                this.updateElement();\n\n            this.updateMonthsInView();\n        },\n\n        isInvalidDate: function() {\n            return false;\n        },\n\n        isCustomDate: function() {\n            return false;\n        },\n\n        updateView: function() {\n            if (this.timePicker) {\n                this.renderTimePicker('left');\n                this.renderTimePicker('right');\n                if (!this.endDate) {\n                    this.container.find('.right .calendar-time select').attr('disabled', 'disabled').addClass('disabled');\n                } else {\n                    this.container.find('.right .calendar-time select').removeAttr('disabled').removeClass('disabled');\n                }\n            }\n            if (this.endDate) {\n                this.container.find('input[name=\"daterangepicker_end\"]').removeClass('active');\n                this.container.find('input[name=\"daterangepicker_start\"]').addClass('active');\n            } else {\n                this.container.find('input[name=\"daterangepicker_end\"]').addClass('active');\n                this.container.find('input[name=\"daterangepicker_start\"]').removeClass('active');\n            }\n            this.updateMonthsInView();\n            this.updateCalendars();\n            this.updateFormInputs();\n        },\n\n        updateMonthsInView: function() {\n            if (this.endDate) {\n\n                //if both dates are visible already, do nothing\n                if (!this.singleDatePicker && this.leftCalendar.month && this.rightCalendar.month &&\n                    (this.startDate.format('YYYY-MM') == this.leftCalendar.month.format('YYYY-MM') || this.startDate.format('YYYY-MM') == this.rightCalendar.month.format('YYYY-MM'))\n                    &&\n                    (this.endDate.format('YYYY-MM') == this.leftCalendar.month.format('YYYY-MM') || this.endDate.format('YYYY-MM') == this.rightCalendar.month.format('YYYY-MM'))\n                    ) {\n                    return;\n                }\n\n                this.leftCalendar.month = this.startDate.clone().date(2);\n                if (!this.linkedCalendars && (this.endDate.month() != this.startDate.month() || this.endDate.year() != this.startDate.year())) {\n                    this.rightCalendar.month = this.endDate.clone().date(2);\n                } else {\n                    this.rightCalendar.month = this.startDate.clone().date(2).add(1, 'month');\n                }\n\n            } else {\n                if (this.leftCalendar.month.format('YYYY-MM') != this.startDate.format('YYYY-MM') && this.rightCalendar.month.format('YYYY-MM') != this.startDate.format('YYYY-MM')) {\n                    this.leftCalendar.month = this.startDate.clone().date(2);\n                    this.rightCalendar.month = this.startDate.clone().date(2).add(1, 'month');\n                }\n            }\n            if (this.maxDate && this.linkedCalendars && !this.singleDatePicker && this.rightCalendar.month > this.maxDate) {\n              this.rightCalendar.month = this.maxDate.clone().date(2);\n              this.leftCalendar.month = this.maxDate.clone().date(2).subtract(1, 'month');\n            }\n        },\n\n        updateCalendars: function() {\n\n            if (this.timePicker) {\n                var hour, minute, second;\n                if (this.endDate) {\n                    hour = parseInt(this.container.find('.left .hourselect').val(), 10);\n                    minute = parseInt(this.container.find('.left .minuteselect').val(), 10);\n                    second = this.timePickerSeconds ? parseInt(this.container.find('.left .secondselect').val(), 10) : 0;\n                    if (!this.timePicker24Hour) {\n                        var ampm = this.container.find('.left .ampmselect').val();\n                        if (ampm === 'PM' && hour < 12)\n                            hour += 12;\n                        if (ampm === 'AM' && hour === 12)\n                            hour = 0;\n                    }\n                } else {\n                    hour = parseInt(this.container.find('.right .hourselect').val(), 10);\n                    minute = parseInt(this.container.find('.right .minuteselect').val(), 10);\n                    second = this.timePickerSeconds ? parseInt(this.container.find('.right .secondselect').val(), 10) : 0;\n                    if (!this.timePicker24Hour) {\n                        var ampm = this.container.find('.right .ampmselect').val();\n                        if (ampm === 'PM' && hour < 12)\n                            hour += 12;\n                        if (ampm === 'AM' && hour === 12)\n                            hour = 0;\n                    }\n                }\n                this.leftCalendar.month.hour(hour).minute(minute).second(second);\n                this.rightCalendar.month.hour(hour).minute(minute).second(second);\n            }\n\n            this.renderCalendar('left');\n            this.renderCalendar('right');\n\n            //highlight any predefined range matching the current start and end dates\n            this.container.find('.ranges li').removeClass('active');\n            if (this.endDate == null) return;\n\n            this.calculateChosenLabel();\n        },\n\n        renderCalendar: function(side) {\n\n            //\n            // Build the matrix of dates that will populate the calendar\n            //\n\n            var calendar = side == 'left' ? this.leftCalendar : this.rightCalendar;\n            var month = calendar.month.month();\n            var year = calendar.month.year();\n            var hour = calendar.month.hour();\n            var minute = calendar.month.minute();\n            var second = calendar.month.second();\n            var daysInMonth = moment([year, month]).daysInMonth();\n            var firstDay = moment([year, month, 1]);\n            var lastDay = moment([year, month, daysInMonth]);\n            var lastMonth = moment(firstDay).subtract(1, 'month').month();\n            var lastYear = moment(firstDay).subtract(1, 'month').year();\n            var daysInLastMonth = moment([lastYear, lastMonth]).daysInMonth();\n            var dayOfWeek = firstDay.day();\n\n            //initialize a 6 rows x 7 columns array for the calendar\n            var calendar = [];\n            calendar.firstDay = firstDay;\n            calendar.lastDay = lastDay;\n\n            for (var i = 0; i < 6; i++) {\n                calendar[i] = [];\n            }\n\n            //populate the calendar with date objects\n            var startDay = daysInLastMonth - dayOfWeek + this.locale.firstDay + 1;\n            if (startDay > daysInLastMonth)\n                startDay -= 7;\n\n            if (dayOfWeek == this.locale.firstDay)\n                startDay = daysInLastMonth - 6;\n\n            var curDate = moment([lastYear, lastMonth, startDay, 12, minute, second]);\n\n            var col, row;\n            for (var i = 0, col = 0, row = 0; i < 42; i++, col++, curDate = moment(curDate).add(24, 'hour')) {\n                if (i > 0 && col % 7 === 0) {\n                    col = 0;\n                    row++;\n                }\n                calendar[row][col] = curDate.clone().hour(hour).minute(minute).second(second);\n                curDate.hour(12);\n\n                if (this.minDate && calendar[row][col].format('YYYY-MM-DD') == this.minDate.format('YYYY-MM-DD') && calendar[row][col].isBefore(this.minDate) && side == 'left') {\n                    calendar[row][col] = this.minDate.clone();\n                }\n\n                if (this.maxDate && calendar[row][col].format('YYYY-MM-DD') == this.maxDate.format('YYYY-MM-DD') && calendar[row][col].isAfter(this.maxDate) && side == 'right') {\n                    calendar[row][col] = this.maxDate.clone();\n                }\n\n            }\n\n            //make the calendar object available to hoverDate/clickDate\n            if (side == 'left') {\n                this.leftCalendar.calendar = calendar;\n            } else {\n                this.rightCalendar.calendar = calendar;\n            }\n\n            //\n            // Display the calendar\n            //\n\n            var minDate = side == 'left' ? this.minDate : this.startDate;\n            var maxDate = this.maxDate;\n            var selected = side == 'left' ? this.startDate : this.endDate;\n            var arrow = this.locale.direction == 'ltr' ? {left: 'chevron-left', right: 'chevron-right'} : {left: 'chevron-right', right: 'chevron-left'};\n\n            var html = '<table class=\"table-condensed\">';\n            html += '<thead>';\n            html += '<tr>';\n\n            // add empty cell for week number\n            if (this.showWeekNumbers || this.showISOWeekNumbers)\n                html += '<th></th>';\n\n            if ((!minDate || minDate.isBefore(calendar.firstDay)) && (!this.linkedCalendars || side == 'left')) {\n                html += '<th class=\"prev available\"><i class=\"fa fa-' + arrow.left + ' glyphicon glyphicon-' + arrow.left + '\"></i></th>';\n            } else {\n                html += '<th></th>';\n            }\n\n            var dateHtml = this.locale.monthNames[calendar[1][1].month()] + calendar[1][1].format(\" YYYY\");\n\n            if (this.showDropdowns) {\n                var currentMonth = calendar[1][1].month();\n                var currentYear = calendar[1][1].year();\n                var maxYear = (maxDate && maxDate.year()) || (currentYear + 5);\n                var minYear = (minDate && minDate.year()) || (currentYear - 50);\n                var inMinYear = currentYear == minYear;\n                var inMaxYear = currentYear == maxYear;\n\n                var monthHtml = '<select class=\"monthselect\">';\n                for (var m = 0; m < 12; m++) {\n                    if ((!inMinYear || m >= minDate.month()) && (!inMaxYear || m <= maxDate.month())) {\n                        monthHtml += \"<option value='\" + m + \"'\" +\n                            (m === currentMonth ? \" selected='selected'\" : \"\") +\n                            \">\" + this.locale.monthNames[m] + \"</option>\";\n                    } else {\n                        monthHtml += \"<option value='\" + m + \"'\" +\n                            (m === currentMonth ? \" selected='selected'\" : \"\") +\n                            \" disabled='disabled'>\" + this.locale.monthNames[m] + \"</option>\";\n                    }\n                }\n                monthHtml += \"</select>\";\n\n                var yearHtml = '<select class=\"yearselect\">';\n                for (var y = minYear; y <= maxYear; y++) {\n                    yearHtml += '<option value=\"' + y + '\"' +\n                        (y === currentYear ? ' selected=\"selected\"' : '') +\n                        '>' + y + '</option>';\n                }\n                yearHtml += '</select>';\n\n                dateHtml = monthHtml + yearHtml;\n            }\n\n            html += '<th colspan=\"5\" class=\"month\">' + dateHtml + '</th>';\n            if ((!maxDate || maxDate.isAfter(calendar.lastDay)) && (!this.linkedCalendars || side == 'right' || this.singleDatePicker)) {\n                html += '<th class=\"next available\"><i class=\"fa fa-' + arrow.right + ' glyphicon glyphicon-' + arrow.right + '\"></i></th>';\n            } else {\n                html += '<th></th>';\n            }\n\n            html += '</tr>';\n            html += '<tr>';\n\n            // add week number label\n            if (this.showWeekNumbers || this.showISOWeekNumbers)\n                html += '<th class=\"week\">' + this.locale.weekLabel + '</th>';\n\n            $.each(this.locale.daysOfWeek, function(index, dayOfWeek) {\n                html += '<th>' + dayOfWeek + '</th>';\n            });\n\n            html += '</tr>';\n            html += '</thead>';\n            html += '<tbody>';\n\n            //adjust maxDate to reflect the dateLimit setting in order to\n            //grey out end dates beyond the dateLimit\n            if (this.endDate == null && this.dateLimit) {\n                var maxLimit = this.startDate.clone().add(this.dateLimit).endOf('day');\n                if (!maxDate || maxLimit.isBefore(maxDate)) {\n                    maxDate = maxLimit;\n                }\n            }\n\n            for (var row = 0; row < 6; row++) {\n                html += '<tr>';\n\n                // add week number\n                if (this.showWeekNumbers)\n                    html += '<td class=\"week\">' + calendar[row][0].week() + '</td>';\n                else if (this.showISOWeekNumbers)\n                    html += '<td class=\"week\">' + calendar[row][0].isoWeek() + '</td>';\n\n                for (var col = 0; col < 7; col++) {\n\n                    var classes = [];\n\n                    //highlight today's date\n                    if (calendar[row][col].isSame(new Date(), \"day\"))\n                        classes.push('today');\n\n                    //highlight weekends\n                    if (calendar[row][col].isoWeekday() > 5)\n                        classes.push('weekend');\n\n                    //grey out the dates in other months displayed at beginning and end of this calendar\n                    if (calendar[row][col].month() != calendar[1][1].month())\n                        classes.push('off');\n\n                    //don't allow selection of dates before the minimum date\n                    if (this.minDate && calendar[row][col].isBefore(this.minDate, 'day'))\n                        classes.push('off', 'disabled');\n\n                    //don't allow selection of dates after the maximum date\n                    if (maxDate && calendar[row][col].isAfter(maxDate, 'day'))\n                        classes.push('off', 'disabled');\n\n                    //don't allow selection of date if a custom function decides it's invalid\n                    if (this.isInvalidDate(calendar[row][col]))\n                        classes.push('off', 'disabled');\n\n                    //highlight the currently selected start date\n                    if (calendar[row][col].format('YYYY-MM-DD') == this.startDate.format('YYYY-MM-DD'))\n                        classes.push('active', 'start-date');\n\n                    //highlight the currently selected end date\n                    if (this.endDate != null && calendar[row][col].format('YYYY-MM-DD') == this.endDate.format('YYYY-MM-DD'))\n                        classes.push('active', 'end-date');\n\n                    //highlight dates in-between the selected dates\n                    if (this.endDate != null && calendar[row][col] > this.startDate && calendar[row][col] < this.endDate)\n                        classes.push('in-range');\n\n                    //apply custom classes for this date\n                    var isCustom = this.isCustomDate(calendar[row][col]);\n                    if (isCustom !== false) {\n                        if (typeof isCustom === 'string')\n                            classes.push(isCustom);\n                        else\n                            Array.prototype.push.apply(classes, isCustom);\n                    }\n\n                    var cname = '', disabled = false;\n                    for (var i = 0; i < classes.length; i++) {\n                        cname += classes[i] + ' ';\n                        if (classes[i] == 'disabled')\n                            disabled = true;\n                    }\n                    if (!disabled)\n                        cname += 'available';\n\n                    html += '<td class=\"' + cname.replace(/^\\s+|\\s+$/g, '') + '\" data-title=\"' + 'r' + row + 'c' + col + '\">' + calendar[row][col].date() + '</td>';\n\n                }\n                html += '</tr>';\n            }\n\n            html += '</tbody>';\n            html += '</table>';\n\n            this.container.find('.calendar.' + side + ' .calendar-table').html(html);\n\n        },\n\n        renderTimePicker: function(side) {\n\n            // Don't bother updating the time picker if it's currently disabled\n            // because an end date hasn't been clicked yet\n            if (side == 'right' && !this.endDate) return;\n\n            var html, selected, minDate, maxDate = this.maxDate;\n\n            if (this.dateLimit && (!this.maxDate || this.startDate.clone().add(this.dateLimit).isAfter(this.maxDate)))\n                maxDate = this.startDate.clone().add(this.dateLimit);\n\n            if (side == 'left') {\n                selected = this.startDate.clone();\n                minDate = this.minDate;\n            } else if (side == 'right') {\n                selected = this.endDate.clone();\n                minDate = this.startDate;\n\n                //Preserve the time already selected\n                var timeSelector = this.container.find('.calendar.right .calendar-time div');\n                if (timeSelector.html() != '') {\n\n                    selected.hour(timeSelector.find('.hourselect option:selected').val() || selected.hour());\n                    selected.minute(timeSelector.find('.minuteselect option:selected').val() || selected.minute());\n                    selected.second(timeSelector.find('.secondselect option:selected').val() || selected.second());\n\n                    if (!this.timePicker24Hour) {\n                        var ampm = timeSelector.find('.ampmselect option:selected').val();\n                        if (ampm === 'PM' && selected.hour() < 12)\n                            selected.hour(selected.hour() + 12);\n                        if (ampm === 'AM' && selected.hour() === 12)\n                            selected.hour(0);\n                    }\n\n                }\n\n                if (selected.isBefore(this.startDate))\n                    selected = this.startDate.clone();\n\n                if (maxDate && selected.isAfter(maxDate))\n                    selected = maxDate.clone();\n\n            }\n\n            //\n            // hours\n            //\n\n            html = '<select class=\"hourselect\">';\n\n            var start = this.timePicker24Hour ? 0 : 1;\n            var end = this.timePicker24Hour ? 23 : 12;\n\n            for (var i = start; i <= end; i++) {\n                var i_in_24 = i;\n                if (!this.timePicker24Hour)\n                    i_in_24 = selected.hour() >= 12 ? (i == 12 ? 12 : i + 12) : (i == 12 ? 0 : i);\n\n                var time = selected.clone().hour(i_in_24);\n                var disabled = false;\n                if (minDate && time.minute(59).isBefore(minDate))\n                    disabled = true;\n                if (maxDate && time.minute(0).isAfter(maxDate))\n                    disabled = true;\n\n                if (i_in_24 == selected.hour() && !disabled) {\n                    html += '<option value=\"' + i + '\" selected=\"selected\">' + i + '</option>';\n                } else if (disabled) {\n                    html += '<option value=\"' + i + '\" disabled=\"disabled\" class=\"disabled\">' + i + '</option>';\n                } else {\n                    html += '<option value=\"' + i + '\">' + i + '</option>';\n                }\n            }\n\n            html += '</select> ';\n\n            //\n            // minutes\n            //\n\n            html += ': <select class=\"minuteselect\">';\n\n            for (var i = 0; i < 60; i += this.timePickerIncrement) {\n                var padded = i < 10 ? '0' + i : i;\n                var time = selected.clone().minute(i);\n\n                var disabled = false;\n                if (minDate && time.second(59).isBefore(minDate))\n                    disabled = true;\n                if (maxDate && time.second(0).isAfter(maxDate))\n                    disabled = true;\n\n                if (selected.minute() == i && !disabled) {\n                    html += '<option value=\"' + i + '\" selected=\"selected\">' + padded + '</option>';\n                } else if (disabled) {\n                    html += '<option value=\"' + i + '\" disabled=\"disabled\" class=\"disabled\">' + padded + '</option>';\n                } else {\n                    html += '<option value=\"' + i + '\">' + padded + '</option>';\n                }\n            }\n\n            html += '</select> ';\n\n            //\n            // seconds\n            //\n\n            if (this.timePickerSeconds) {\n                html += ': <select class=\"secondselect\">';\n\n                for (var i = 0; i < 60; i++) {\n                    var padded = i < 10 ? '0' + i : i;\n                    var time = selected.clone().second(i);\n\n                    var disabled = false;\n                    if (minDate && time.isBefore(minDate))\n                        disabled = true;\n                    if (maxDate && time.isAfter(maxDate))\n                        disabled = true;\n\n                    if (selected.second() == i && !disabled) {\n                        html += '<option value=\"' + i + '\" selected=\"selected\">' + padded + '</option>';\n                    } else if (disabled) {\n                        html += '<option value=\"' + i + '\" disabled=\"disabled\" class=\"disabled\">' + padded + '</option>';\n                    } else {\n                        html += '<option value=\"' + i + '\">' + padded + '</option>';\n                    }\n                }\n\n                html += '</select> ';\n            }\n\n            //\n            // AM/PM\n            //\n\n            if (!this.timePicker24Hour) {\n                html += '<select class=\"ampmselect\">';\n\n                var am_html = '';\n                var pm_html = '';\n\n                if (minDate && selected.clone().hour(12).minute(0).second(0).isBefore(minDate))\n                    am_html = ' disabled=\"disabled\" class=\"disabled\"';\n\n                if (maxDate && selected.clone().hour(0).minute(0).second(0).isAfter(maxDate))\n                    pm_html = ' disabled=\"disabled\" class=\"disabled\"';\n\n                if (selected.hour() >= 12) {\n                    html += '<option value=\"AM\"' + am_html + '>AM</option><option value=\"PM\" selected=\"selected\"' + pm_html + '>PM</option>';\n                } else {\n                    html += '<option value=\"AM\" selected=\"selected\"' + am_html + '>AM</option><option value=\"PM\"' + pm_html + '>PM</option>';\n                }\n\n                html += '</select>';\n            }\n\n            this.container.find('.calendar.' + side + ' .calendar-time div').html(html);\n\n        },\n\n        updateFormInputs: function() {\n\n            //ignore mouse movements while an above-calendar text input has focus\n            if (this.container.find('input[name=daterangepicker_start]').is(\":focus\") || this.container.find('input[name=daterangepicker_end]').is(\":focus\"))\n                return;\n\n            this.container.find('input[name=daterangepicker_start]').val(this.startDate.format(this.locale.format));\n            if (this.endDate)\n                this.container.find('input[name=daterangepicker_end]').val(this.endDate.format(this.locale.format));\n\n            if (this.singleDatePicker || (this.endDate && (this.startDate.isBefore(this.endDate) || this.startDate.isSame(this.endDate)))) {\n                this.container.find('button.applyBtn').removeAttr('disabled');\n            } else {\n                this.container.find('button.applyBtn').attr('disabled', 'disabled');\n            }\n\n        },\n\n        move: function() {\n            var parentOffset = { top: 0, left: 0 },\n                containerTop;\n            var parentRightEdge = $(window).width();\n            if (!this.parentEl.is('body')) {\n                parentOffset = {\n                    top: this.parentEl.offset().top - this.parentEl.scrollTop(),\n                    left: this.parentEl.offset().left - this.parentEl.scrollLeft()\n                };\n                parentRightEdge = this.parentEl[0].clientWidth + this.parentEl.offset().left;\n            }\n\n            if (this.drops == 'up')\n                containerTop = this.element.offset().top - this.container.outerHeight() - parentOffset.top;\n            else\n                containerTop = this.element.offset().top + this.element.outerHeight() - parentOffset.top;\n            this.container[this.drops == 'up' ? 'addClass' : 'removeClass']('dropup');\n\n            if (this.opens == 'left') {\n                this.container.css({\n                    top: containerTop,\n                    right: parentRightEdge - this.element.offset().left - this.element.outerWidth(),\n                    left: 'auto'\n                });\n                if (this.container.offset().left < 0) {\n                    this.container.css({\n                        right: 'auto',\n                        left: 9\n                    });\n                }\n            } else if (this.opens == 'center') {\n                this.container.css({\n                    top: containerTop,\n                    left: this.element.offset().left - parentOffset.left + this.element.outerWidth() / 2\n                            - this.container.outerWidth() / 2,\n                    right: 'auto'\n                });\n                if (this.container.offset().left < 0) {\n                    this.container.css({\n                        right: 'auto',\n                        left: 9\n                    });\n                }\n            } else {\n                this.container.css({\n                    top: containerTop,\n                    left: this.element.offset().left - parentOffset.left,\n                    right: 'auto'\n                });\n                if (this.container.offset().left + this.container.outerWidth() > $(window).width()) {\n                    this.container.css({\n                        left: 'auto',\n                        right: 0\n                    });\n                }\n            }\n        },\n\n        show: function(e) {\n            if (this.isShowing) return;\n\n            // Create a click proxy that is private to this instance of datepicker, for unbinding\n            this._outsideClickProxy = $.proxy(function(e) { this.outsideClick(e); }, this);\n\n            // Bind global datepicker mousedown for hiding and\n            $(document)\n              .on('mousedown.daterangepicker', this._outsideClickProxy)\n              // also support mobile devices\n              .on('touchend.daterangepicker', this._outsideClickProxy)\n              // also explicitly play nice with Bootstrap dropdowns, which stopPropagation when clicking them\n              .on('click.daterangepicker', '[data-toggle=dropdown]', this._outsideClickProxy)\n              // and also close when focus changes to outside the picker (eg. tabbing between controls)\n              .on('focusin.daterangepicker', this._outsideClickProxy);\n\n            // Reposition the picker if the window is resized while it's open\n            $(window).on('resize.daterangepicker', $.proxy(function(e) { this.move(e); }, this));\n\n            this.oldStartDate = this.startDate.clone();\n            this.oldEndDate = this.endDate.clone();\n            this.previousRightTime = this.endDate.clone();\n\n            this.updateView();\n            this.container.show();\n            this.move();\n            this.element.trigger('show.daterangepicker', this);\n            this.isShowing = true;\n        },\n\n        hide: function(e) {\n            if (!this.isShowing) return;\n\n            //incomplete date selection, revert to last values\n            if (!this.endDate) {\n                this.startDate = this.oldStartDate.clone();\n                this.endDate = this.oldEndDate.clone();\n            }\n\n            //if a new date range was selected, invoke the user callback function\n            if (!this.startDate.isSame(this.oldStartDate) || !this.endDate.isSame(this.oldEndDate))\n                this.callback(this.startDate, this.endDate, this.chosenLabel);\n\n            //if picker is attached to a text input, update it\n            this.updateElement();\n\n            $(document).off('.daterangepicker');\n            $(window).off('.daterangepicker');\n            this.container.hide();\n            this.element.trigger('hide.daterangepicker', this);\n            this.isShowing = false;\n        },\n\n        toggle: function(e) {\n            if (this.isShowing) {\n                this.hide();\n            } else {\n                this.show();\n            }\n        },\n\n        outsideClick: function(e) {\n            var target = $(e.target);\n            // if the page is clicked anywhere except within the daterangerpicker/button\n            // itself then call this.hide()\n            if (\n                // ie modal dialog fix\n                e.type == \"focusin\" ||\n                target.closest(this.element).length ||\n                target.closest(this.container).length ||\n                target.closest('.calendar-table').length\n                ) return;\n            this.hide();\n            this.element.trigger('outsideClick.daterangepicker', this);\n        },\n\n        showCalendars: function() {\n            this.container.addClass('show-calendar');\n            this.move();\n            this.element.trigger('showCalendar.daterangepicker', this);\n        },\n\n        hideCalendars: function() {\n            this.container.removeClass('show-calendar');\n            this.element.trigger('hideCalendar.daterangepicker', this);\n        },\n\n        hoverRange: function(e) {\n\n            //ignore mouse movements while an above-calendar text input has focus\n            if (this.container.find('input[name=daterangepicker_start]').is(\":focus\") || this.container.find('input[name=daterangepicker_end]').is(\":focus\"))\n                return;\n\n            var label = e.target.getAttribute('data-range-key');\n\n            if (label == this.locale.customRangeLabel) {\n                this.updateView();\n            } else {\n                var dates = this.ranges[label];\n                this.container.find('input[name=daterangepicker_start]').val(dates[0].format(this.locale.format));\n                this.container.find('input[name=daterangepicker_end]').val(dates[1].format(this.locale.format));\n            }\n\n        },\n\n        clickRange: function(e) {\n            var label = e.target.getAttribute('data-range-key');\n            this.chosenLabel = label;\n            if (label == this.locale.customRangeLabel) {\n                this.showCalendars();\n            } else {\n                var dates = this.ranges[label];\n                this.startDate = dates[0];\n                this.endDate = dates[1];\n\n                if (!this.timePicker) {\n                    this.startDate.startOf('day');\n                    this.endDate.endOf('day');\n                }\n\n                if (!this.alwaysShowCalendars)\n                    this.hideCalendars();\n                this.clickApply();\n            }\n        },\n\n        clickPrev: function(e) {\n            var cal = $(e.target).parents('.calendar');\n            if (cal.hasClass('left')) {\n                this.leftCalendar.month.subtract(1, 'month');\n                if (this.linkedCalendars)\n                    this.rightCalendar.month.subtract(1, 'month');\n            } else {\n                this.rightCalendar.month.subtract(1, 'month');\n            }\n            this.updateCalendars();\n        },\n\n        clickNext: function(e) {\n            var cal = $(e.target).parents('.calendar');\n            if (cal.hasClass('left')) {\n                this.leftCalendar.month.add(1, 'month');\n            } else {\n                this.rightCalendar.month.add(1, 'month');\n                if (this.linkedCalendars)\n                    this.leftCalendar.month.add(1, 'month');\n            }\n            this.updateCalendars();\n        },\n\n        hoverDate: function(e) {\n\n            //ignore mouse movements while an above-calendar text input has focus\n            //if (this.container.find('input[name=daterangepicker_start]').is(\":focus\") || this.container.find('input[name=daterangepicker_end]').is(\":focus\"))\n            //    return;\n\n            //ignore dates that can't be selected\n            if (!$(e.target).hasClass('available')) return;\n\n            //have the text inputs above calendars reflect the date being hovered over\n            var title = $(e.target).attr('data-title');\n            var row = title.substr(1, 1);\n            var col = title.substr(3, 1);\n            var cal = $(e.target).parents('.calendar');\n            var date = cal.hasClass('left') ? this.leftCalendar.calendar[row][col] : this.rightCalendar.calendar[row][col];\n\n            if (this.endDate && !this.container.find('input[name=daterangepicker_start]').is(\":focus\")) {\n                this.container.find('input[name=daterangepicker_start]').val(date.format(this.locale.format));\n            } else if (!this.endDate && !this.container.find('input[name=daterangepicker_end]').is(\":focus\")) {\n                this.container.find('input[name=daterangepicker_end]').val(date.format(this.locale.format));\n            }\n\n            //highlight the dates between the start date and the date being hovered as a potential end date\n            var leftCalendar = this.leftCalendar;\n            var rightCalendar = this.rightCalendar;\n            var startDate = this.startDate;\n            if (!this.endDate) {\n                this.container.find('.calendar tbody td').each(function(index, el) {\n\n                    //skip week numbers, only look at dates\n                    if ($(el).hasClass('week')) return;\n\n                    var title = $(el).attr('data-title');\n                    var row = title.substr(1, 1);\n                    var col = title.substr(3, 1);\n                    var cal = $(el).parents('.calendar');\n                    var dt = cal.hasClass('left') ? leftCalendar.calendar[row][col] : rightCalendar.calendar[row][col];\n\n                    if ((dt.isAfter(startDate) && dt.isBefore(date)) || dt.isSame(date, 'day')) {\n                        $(el).addClass('in-range');\n                    } else {\n                        $(el).removeClass('in-range');\n                    }\n\n                });\n            }\n\n        },\n\n        clickDate: function(e) {\n\n            if (!$(e.target).hasClass('available')) return;\n\n            var title = $(e.target).attr('data-title');\n            var row = title.substr(1, 1);\n            var col = title.substr(3, 1);\n            var cal = $(e.target).parents('.calendar');\n            var date = cal.hasClass('left') ? this.leftCalendar.calendar[row][col] : this.rightCalendar.calendar[row][col];\n\n            //\n            // this function needs to do a few things:\n            // * alternate between selecting a start and end date for the range,\n            // * if the time picker is enabled, apply the hour/minute/second from the select boxes to the clicked date\n            // * if autoapply is enabled, and an end date was chosen, apply the selection\n            // * if single date picker mode, and time picker isn't enabled, apply the selection immediately\n            // * if one of the inputs above the calendars was focused, cancel that manual input\n            //\n\n            if (this.endDate || date.isBefore(this.startDate, 'day')) { //picking start\n                if (this.timePicker) {\n                    var hour = parseInt(this.container.find('.left .hourselect').val(), 10);\n                    if (!this.timePicker24Hour) {\n                        var ampm = this.container.find('.left .ampmselect').val();\n                        if (ampm === 'PM' && hour < 12)\n                            hour += 12;\n                        if (ampm === 'AM' && hour === 12)\n                            hour = 0;\n                    }\n                    var minute = parseInt(this.container.find('.left .minuteselect').val(), 10);\n                    var second = this.timePickerSeconds ? parseInt(this.container.find('.left .secondselect').val(), 10) : 0;\n                    date = date.clone().hour(hour).minute(minute).second(second);\n                }\n                this.endDate = null;\n                this.setStartDate(date.clone());\n            } else if (!this.endDate && date.isBefore(this.startDate)) {\n                //special case: clicking the same date for start/end,\n                //but the time of the end date is before the start date\n                this.setEndDate(this.startDate.clone());\n            } else { // picking end\n                if (this.timePicker) {\n                    var hour = parseInt(this.container.find('.right .hourselect').val(), 10);\n                    if (!this.timePicker24Hour) {\n                        var ampm = this.container.find('.right .ampmselect').val();\n                        if (ampm === 'PM' && hour < 12)\n                            hour += 12;\n                        if (ampm === 'AM' && hour === 12)\n                            hour = 0;\n                    }\n                    var minute = parseInt(this.container.find('.right .minuteselect').val(), 10);\n                    var second = this.timePickerSeconds ? parseInt(this.container.find('.right .secondselect').val(), 10) : 0;\n                    date = date.clone().hour(hour).minute(minute).second(second);\n                }\n                this.setEndDate(date.clone());\n                if (this.autoApply) {\n                  this.calculateChosenLabel();\n                  this.clickApply();\n                }\n            }\n\n            if (this.singleDatePicker) {\n                this.setEndDate(this.startDate);\n                if (!this.timePicker)\n                    this.clickApply();\n            }\n\n            this.updateView();\n\n            //This is to cancel the blur event handler if the mouse was in one of the inputs\n            e.stopPropagation();\n\n        },\n\n        calculateChosenLabel: function () {\n            var customRange = true;\n            var i = 0;\n            for (var range in this.ranges) {\n              if (this.timePicker) {\n                    var format = this.timePickerSeconds ? \"YYYY-MM-DD hh:mm:ss\" : \"YYYY-MM-DD hh:mm\";\n                    //ignore times when comparing dates if time picker seconds is not enabled\n                    if (this.startDate.format(format) == this.ranges[range][0].format(format) && this.endDate.format(format) == this.ranges[range][1].format(format)) {\n                        customRange = false;\n                        this.chosenLabel = this.container.find('.ranges li:eq(' + i + ')').addClass('active').html();\n                        break;\n                    }\n                } else {\n                    //ignore times when comparing dates if time picker is not enabled\n                    if (this.startDate.format('YYYY-MM-DD') == this.ranges[range][0].format('YYYY-MM-DD') && this.endDate.format('YYYY-MM-DD') == this.ranges[range][1].format('YYYY-MM-DD')) {\n                        customRange = false;\n                        this.chosenLabel = this.container.find('.ranges li:eq(' + i + ')').addClass('active').html();\n                        break;\n                    }\n                }\n                i++;\n            }\n            if (customRange) {\n                if (this.showCustomRangeLabel) {\n                    this.chosenLabel = this.container.find('.ranges li:last').addClass('active').html();\n                } else {\n                    this.chosenLabel = null;\n                }\n                this.showCalendars();\n            }\n        },\n\n        clickApply: function(e) {\n            this.hide();\n            this.element.trigger('apply.daterangepicker', this);\n        },\n\n        clickCancel: function(e) {\n            this.startDate = this.oldStartDate;\n            this.endDate = this.oldEndDate;\n            this.hide();\n            this.element.trigger('cancel.daterangepicker', this);\n        },\n\n        monthOrYearChanged: function(e) {\n            var isLeft = $(e.target).closest('.calendar').hasClass('left'),\n                leftOrRight = isLeft ? 'left' : 'right',\n                cal = this.container.find('.calendar.'+leftOrRight);\n\n            // Month must be Number for new moment versions\n            var month = parseInt(cal.find('.monthselect').val(), 10);\n            var year = cal.find('.yearselect').val();\n\n            if (!isLeft) {\n                if (year < this.startDate.year() || (year == this.startDate.year() && month < this.startDate.month())) {\n                    month = this.startDate.month();\n                    year = this.startDate.year();\n                }\n            }\n\n            if (this.minDate) {\n                if (year < this.minDate.year() || (year == this.minDate.year() && month < this.minDate.month())) {\n                    month = this.minDate.month();\n                    year = this.minDate.year();\n                }\n            }\n\n            if (this.maxDate) {\n                if (year > this.maxDate.year() || (year == this.maxDate.year() && month > this.maxDate.month())) {\n                    month = this.maxDate.month();\n                    year = this.maxDate.year();\n                }\n            }\n\n            if (isLeft) {\n                this.leftCalendar.month.month(month).year(year);\n                if (this.linkedCalendars)\n                    this.rightCalendar.month = this.leftCalendar.month.clone().add(1, 'month');\n            } else {\n                this.rightCalendar.month.month(month).year(year);\n                if (this.linkedCalendars)\n                    this.leftCalendar.month = this.rightCalendar.month.clone().subtract(1, 'month');\n            }\n            this.updateCalendars();\n        },\n\n        timeChanged: function(e) {\n\n            var cal = $(e.target).closest('.calendar'),\n                isLeft = cal.hasClass('left');\n\n            var hour = parseInt(cal.find('.hourselect').val(), 10);\n            var minute = parseInt(cal.find('.minuteselect').val(), 10);\n            var second = this.timePickerSeconds ? parseInt(cal.find('.secondselect').val(), 10) : 0;\n\n            if (!this.timePicker24Hour) {\n                var ampm = cal.find('.ampmselect').val();\n                if (ampm === 'PM' && hour < 12)\n                    hour += 12;\n                if (ampm === 'AM' && hour === 12)\n                    hour = 0;\n            }\n\n            if (isLeft) {\n                var start = this.startDate.clone();\n                start.hour(hour);\n                start.minute(minute);\n                start.second(second);\n                this.setStartDate(start);\n                if (this.singleDatePicker) {\n                    this.endDate = this.startDate.clone();\n                } else if (this.endDate && this.endDate.format('YYYY-MM-DD') == start.format('YYYY-MM-DD') && this.endDate.isBefore(start)) {\n                    this.setEndDate(start.clone());\n                }\n            } else if (this.endDate) {\n                var end = this.endDate.clone();\n                end.hour(hour);\n                end.minute(minute);\n                end.second(second);\n                this.setEndDate(end);\n            }\n\n            //update the calendars so all clickable dates reflect the new time component\n            this.updateCalendars();\n\n            //update the form inputs above the calendars with the new time\n            this.updateFormInputs();\n\n            //re-render the time pickers because changing one selection can affect what's enabled in another\n            this.renderTimePicker('left');\n            this.renderTimePicker('right');\n\n        },\n\n        formInputsChanged: function(e) {\n            var isRight = $(e.target).closest('.calendar').hasClass('right');\n            var start = moment(this.container.find('input[name=\"daterangepicker_start\"]').val(), this.locale.format);\n            var end = moment(this.container.find('input[name=\"daterangepicker_end\"]').val(), this.locale.format);\n\n            if (start.isValid() && end.isValid()) {\n\n                if (isRight && end.isBefore(start))\n                    start = end.clone();\n\n                this.setStartDate(start);\n                this.setEndDate(end);\n\n                if (isRight) {\n                    this.container.find('input[name=\"daterangepicker_start\"]').val(this.startDate.format(this.locale.format));\n                } else {\n                    this.container.find('input[name=\"daterangepicker_end\"]').val(this.endDate.format(this.locale.format));\n                }\n\n            }\n\n            this.updateView();\n        },\n\n        formInputsFocused: function(e) {\n\n            // Highlight the focused input\n            this.container.find('input[name=\"daterangepicker_start\"], input[name=\"daterangepicker_end\"]').removeClass('active');\n            $(e.target).addClass('active');\n\n            // Set the state such that if the user goes back to using a mouse, \n            // the calendars are aware we're selecting the end of the range, not\n            // the start. This allows someone to edit the end of a date range without\n            // re-selecting the beginning, by clicking on the end date input then\n            // using the calendar.\n            var isRight = $(e.target).closest('.calendar').hasClass('right');\n            if (isRight) {\n                this.endDate = null;\n                this.setStartDate(this.startDate.clone());\n                this.updateView();\n            }\n\n        },\n\n        formInputsBlurred: function(e) {\n\n            // this function has one purpose right now: if you tab from the first\n            // text input to the second in the UI, the endDate is nulled so that\n            // you can click another, but if you tab out without clicking anything\n            // or changing the input value, the old endDate should be retained\n\n            if (!this.endDate) {\n                var val = this.container.find('input[name=\"daterangepicker_end\"]').val();\n                var end = moment(val, this.locale.format);\n                if (end.isValid()) {\n                    this.setEndDate(end);\n                    this.updateView();\n                }\n            }\n\n        },\n\n        formInputsKeydown: function(e) {\n            // This function ensures that if the 'enter' key was pressed in the input, then the calendars\n            // are updated with the startDate and endDate.\n            // This behaviour is automatic in Chrome/Firefox/Edge but not in IE 11 hence why this exists.\n            // Other browsers and versions of IE are untested and the behaviour is unknown.\n            if (e.keyCode === 13) {\n                // Prevent the calendar from being updated twice on Chrome/Firefox/Edge\n                e.preventDefault(); \n                this.formInputsChanged(e);\n            }\n        },\n\n\n        elementChanged: function() {\n            if (!this.element.is('input')) return;\n            if (!this.element.val().length) return;\n\n            var dateString = this.element.val().split(this.locale.separator),\n                start = null,\n                end = null;\n\n            if (dateString.length === 2) {\n                start = moment(dateString[0], this.locale.format);\n                end = moment(dateString[1], this.locale.format);\n            }\n\n            if (this.singleDatePicker || start === null || end === null) {\n                start = moment(this.element.val(), this.locale.format);\n                end = start;\n            }\n\n            if (!start.isValid() || !end.isValid()) return;\n\n            this.setStartDate(start);\n            this.setEndDate(end);\n            this.updateView();\n        },\n\n        keydown: function(e) {\n            //hide on tab or enter\n            if ((e.keyCode === 9) || (e.keyCode === 13)) {\n                this.hide();\n            }\n\n            //hide on esc and prevent propagation\n            if (e.keyCode === 27) {\n                e.preventDefault();\n                e.stopPropagation();\n\n                this.hide();\n            }\n        },\n\n        updateElement: function() {\n            if (this.element.is('input') && !this.singleDatePicker && this.autoUpdateInput) {\n                this.element.val(this.startDate.format(this.locale.format) + this.locale.separator + this.endDate.format(this.locale.format));\n                this.element.trigger('change');\n            } else if (this.element.is('input') && this.autoUpdateInput) {\n                this.element.val(this.startDate.format(this.locale.format));\n                this.element.trigger('change');\n            }\n        },\n\n        remove: function() {\n            this.container.remove();\n            this.element.off('.daterangepicker');\n            this.element.removeData();\n        }\n\n    };\n\n    $.fn.daterangepicker = function(options, callback) {\n        var implementOptions = $.extend(true, {}, $.fn.daterangepicker.defaultOptions, options);\n        this.each(function() {\n            var el = $(this);\n            if (el.data('daterangepicker'))\n                el.data('daterangepicker').remove();\n            el.data('daterangepicker', new DateRangePicker(el, implementOptions, callback));\n        });\n        return this;\n    };\n\n    return DateRangePicker;\n\n}));\n"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/adminlte/bower_components/ckeditor/ckeditor.js",
    "content": "﻿/*\nCopyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.\nFor licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n*/\n(function(){window.CKEDITOR&&window.CKEDITOR.dom||(window.CKEDITOR||(window.CKEDITOR=function(){var a=/(^|.*[\\\\\\/])ckeditor\\.js(?:\\?.*|;.*)?$/i,f={timestamp:\"J5S9\",version:\"4.12.1 (Standard)\",revision:\"64749bb245\",rnd:Math.floor(900*Math.random())+100,_:{pending:[],basePathSrcPattern:a},status:\"unloaded\",basePath:function(){var b=window.CKEDITOR_BASEPATH||\"\";if(!b)for(var c=document.getElementsByTagName(\"script\"),f=0;f<c.length;f++){var g=c[f].src.match(a);if(g){b=g[1];break}}-1==b.indexOf(\":/\")&&\n\"//\"!=b.slice(0,2)&&(b=0===b.indexOf(\"/\")?location.href.match(/^.*?:\\/\\/[^\\/]*/)[0]+b:location.href.match(/^[^\\?]*\\/(?:)/)[0]+b);if(!b)throw'The CKEditor installation path could not be automatically detected. Please set the global variable \"CKEDITOR_BASEPATH\" before creating editor instances.';return b}(),getUrl:function(a){-1==a.indexOf(\":/\")&&0!==a.indexOf(\"/\")&&(a=this.basePath+a);this.timestamp&&\"/\"!=a.charAt(a.length-1)&&!/[&?]t=/.test(a)&&(a+=(0<=a.indexOf(\"?\")?\"\\x26\":\"?\")+\"t\\x3d\"+this.timestamp);\nreturn a},domReady:function(){function a(){try{document.addEventListener?(document.removeEventListener(\"DOMContentLoaded\",a,!1),b()):document.attachEvent&&\"complete\"===document.readyState&&(document.detachEvent(\"onreadystatechange\",a),b())}catch(g){}}function b(){for(var a;a=c.shift();)a()}var c=[];return function(g){function h(){try{document.documentElement.doScroll(\"left\")}catch(e){setTimeout(h,1);return}a()}c.push(g);\"complete\"===document.readyState&&setTimeout(a,1);if(1==c.length)if(document.addEventListener)document.addEventListener(\"DOMContentLoaded\",\na,!1),window.addEventListener(\"load\",a,!1);else if(document.attachEvent){document.attachEvent(\"onreadystatechange\",a);window.attachEvent(\"onload\",a);g=!1;try{g=!window.frameElement}catch(b){}document.documentElement.doScroll&&g&&h()}}}()},b=window.CKEDITOR_GETURL;if(b){var c=f.getUrl;f.getUrl=function(a){return b.call(f,a)||c.call(f,a)}}return f}()),CKEDITOR.event||(CKEDITOR.event=function(){},CKEDITOR.event.implementOn=function(a){var f=CKEDITOR.event.prototype,b;for(b in f)null==a[b]&&(a[b]=f[b])},\nCKEDITOR.event.prototype=function(){function a(a){var d=f(this);return d[a]||(d[a]=new b(a))}var f=function(a){a=a.getPrivate&&a.getPrivate()||a._||(a._={});return a.events||(a.events={})},b=function(a){this.name=a;this.listeners=[]};b.prototype={getListenerIndex:function(a){for(var b=0,f=this.listeners;b<f.length;b++)if(f[b].fn==a)return b;return-1}};return{define:function(b,d){var f=a.call(this,b);CKEDITOR.tools.extend(f,d,!0)},on:function(b,d,f,k,g){function h(a,e,n,g){a={name:b,sender:this,editor:a,\ndata:e,listenerData:k,stop:n,cancel:g,removeListener:m};return!1===d.call(f,a)?!1:a.data}function m(){n.removeListener(b,d)}var e=a.call(this,b);if(0>e.getListenerIndex(d)){e=e.listeners;f||(f=this);isNaN(g)&&(g=10);var n=this;h.fn=d;h.priority=g;for(var q=e.length-1;0<=q;q--)if(e[q].priority<=g)return e.splice(q+1,0,h),{removeListener:m};e.unshift(h)}return{removeListener:m}},once:function(){var a=Array.prototype.slice.call(arguments),b=a[1];a[1]=function(a){a.removeListener();return b.apply(this,\narguments)};return this.on.apply(this,a)},capture:function(){CKEDITOR.event.useCapture=1;var a=this.on.apply(this,arguments);CKEDITOR.event.useCapture=0;return a},fire:function(){var a=0,b=function(){a=1},l=0,k=function(){l=1};return function(g,h,m){var e=f(this)[g];g=a;var n=l;a=l=0;if(e){var q=e.listeners;if(q.length)for(var q=q.slice(0),y,u=0;u<q.length;u++){if(e.errorProof)try{y=q[u].call(this,m,h,b,k)}catch(p){}else y=q[u].call(this,m,h,b,k);!1===y?l=1:\"undefined\"!=typeof y&&(h=y);if(a||l)break}}h=\nl?!1:\"undefined\"==typeof h?!0:h;a=g;l=n;return h}}(),fireOnce:function(a,b,l){b=this.fire(a,b,l);delete f(this)[a];return b},removeListener:function(a,b){var l=f(this)[a];if(l){var k=l.getListenerIndex(b);0<=k&&l.listeners.splice(k,1)}},removeAllListeners:function(){var a=f(this),b;for(b in a)delete a[b]},hasListeners:function(a){return(a=f(this)[a])&&0<a.listeners.length}}}()),CKEDITOR.editor||(CKEDITOR.editor=function(){CKEDITOR._.pending.push([this,arguments]);CKEDITOR.event.call(this)},CKEDITOR.editor.prototype.fire=\nfunction(a,f){a in{instanceReady:1,loaded:1}&&(this[a]=!0);return CKEDITOR.event.prototype.fire.call(this,a,f,this)},CKEDITOR.editor.prototype.fireOnce=function(a,f){a in{instanceReady:1,loaded:1}&&(this[a]=!0);return CKEDITOR.event.prototype.fireOnce.call(this,a,f,this)},CKEDITOR.event.implementOn(CKEDITOR.editor.prototype)),CKEDITOR.env||(CKEDITOR.env=function(){var a=navigator.userAgent.toLowerCase(),f=a.match(/edge[ \\/](\\d+.?\\d*)/),b=-1<a.indexOf(\"trident/\"),b=!(!f&&!b),b={ie:b,edge:!!f,webkit:!b&&\n-1<a.indexOf(\" applewebkit/\"),air:-1<a.indexOf(\" adobeair/\"),mac:-1<a.indexOf(\"macintosh\"),quirks:\"BackCompat\"==document.compatMode&&(!document.documentMode||10>document.documentMode),mobile:-1<a.indexOf(\"mobile\"),iOS:/(ipad|iphone|ipod)/.test(a),isCustomDomain:function(){if(!this.ie)return!1;var a=document.domain,b=window.location.hostname;return a!=b&&a!=\"[\"+b+\"]\"},secure:\"https:\"==location.protocol};b.gecko=\"Gecko\"==navigator.product&&!b.webkit&&!b.ie;b.webkit&&(-1<a.indexOf(\"chrome\")?b.chrome=\n!0:b.safari=!0);var c=0;b.ie&&(c=f?parseFloat(f[1]):b.quirks||!document.documentMode?parseFloat(a.match(/msie (\\d+)/)[1]):document.documentMode,b.ie9Compat=9==c,b.ie8Compat=8==c,b.ie7Compat=7==c,b.ie6Compat=7>c||b.quirks);b.gecko&&(f=a.match(/rv:([\\d\\.]+)/))&&(f=f[1].split(\".\"),c=1E4*f[0]+100*(f[1]||0)+1*(f[2]||0));b.air&&(c=parseFloat(a.match(/ adobeair\\/(\\d+)/)[1]));b.webkit&&(c=parseFloat(a.match(/ applewebkit\\/(\\d+)/)[1]));b.version=c;b.isCompatible=!(b.ie&&7>c)&&!(b.gecko&&4E4>c)&&!(b.webkit&&\n534>c);b.hidpi=2<=window.devicePixelRatio;b.needsBrFiller=b.gecko||b.webkit||b.ie&&10<c;b.needsNbspFiller=b.ie&&11>c;b.cssClass=\"cke_browser_\"+(b.ie?\"ie\":b.gecko?\"gecko\":b.webkit?\"webkit\":\"unknown\");b.quirks&&(b.cssClass+=\" cke_browser_quirks\");b.ie&&(b.cssClass+=\" cke_browser_ie\"+(b.quirks?\"6 cke_browser_iequirks\":b.version));b.air&&(b.cssClass+=\" cke_browser_air\");b.iOS&&(b.cssClass+=\" cke_browser_ios\");b.hidpi&&(b.cssClass+=\" cke_hidpi\");return b}()),\"unloaded\"==CKEDITOR.status&&function(){CKEDITOR.event.implementOn(CKEDITOR);\nCKEDITOR.loadFullCore=function(){if(\"basic_ready\"!=CKEDITOR.status)CKEDITOR.loadFullCore._load=1;else{delete CKEDITOR.loadFullCore;var a=document.createElement(\"script\");a.type=\"text/javascript\";a.src=CKEDITOR.basePath+\"ckeditor.js\";document.getElementsByTagName(\"head\")[0].appendChild(a)}};CKEDITOR.loadFullCoreTimeout=0;CKEDITOR.add=function(a){(this._.pending||(this._.pending=[])).push(a)};(function(){CKEDITOR.domReady(function(){var a=CKEDITOR.loadFullCore,f=CKEDITOR.loadFullCoreTimeout;a&&(CKEDITOR.status=\n\"basic_ready\",a&&a._load?a():f&&setTimeout(function(){CKEDITOR.loadFullCore&&CKEDITOR.loadFullCore()},1E3*f))})})();CKEDITOR.status=\"basic_loaded\"}(),\"use strict\",CKEDITOR.VERBOSITY_WARN=1,CKEDITOR.VERBOSITY_ERROR=2,CKEDITOR.verbosity=CKEDITOR.VERBOSITY_WARN|CKEDITOR.VERBOSITY_ERROR,CKEDITOR.warn=function(a,f){CKEDITOR.verbosity&CKEDITOR.VERBOSITY_WARN&&CKEDITOR.fire(\"log\",{type:\"warn\",errorCode:a,additionalData:f})},CKEDITOR.error=function(a,f){CKEDITOR.verbosity&CKEDITOR.VERBOSITY_ERROR&&CKEDITOR.fire(\"log\",\n{type:\"error\",errorCode:a,additionalData:f})},CKEDITOR.on(\"log\",function(a){if(window.console&&window.console.log){var f=console[a.data.type]?a.data.type:\"log\",b=a.data.errorCode;if(a=a.data.additionalData)console[f](\"[CKEDITOR] Error code: \"+b+\".\",a);else console[f](\"[CKEDITOR] Error code: \"+b+\".\");console[f](\"[CKEDITOR] For more information about this error go to https://ckeditor.com/docs/ckeditor4/latest/guide/dev_errors.html#\"+b)}},null,null,999),CKEDITOR.dom={},function(){function a(a,e,b){this._minInterval=\na;this._context=b;this._lastOutput=this._scheduledTimer=0;this._output=CKEDITOR.tools.bind(e,b||{});var g=this;this.input=function(){function a(){g._lastOutput=(new Date).getTime();g._scheduledTimer=0;g._call()}if(!g._scheduledTimer||!1!==g._reschedule()){var e=(new Date).getTime()-g._lastOutput;e<g._minInterval?g._scheduledTimer=setTimeout(a,g._minInterval-e):a()}}}function f(e,g,b){a.call(this,e,g,b);this._args=[];var h=this;this.input=CKEDITOR.tools.override(this.input,function(a){return function(){h._args=\nArray.prototype.slice.call(arguments);a.call(this)}})}var b=[],c=CKEDITOR.env.gecko?\"-moz-\":CKEDITOR.env.webkit?\"-webkit-\":CKEDITOR.env.ie?\"-ms-\":\"\",d=/&/g,l=/>/g,k=/</g,g=/\"/g,h=/&(lt|gt|amp|quot|nbsp|shy|#\\d{1,5});/g,m={lt:\"\\x3c\",gt:\"\\x3e\",amp:\"\\x26\",quot:'\"',nbsp:\" \",shy:\"­\"},e=function(a,e){return\"#\"==e[0]?String.fromCharCode(parseInt(e.slice(1),10)):m[e]};CKEDITOR.on(\"reset\",function(){b=[]});CKEDITOR.tools={arrayCompare:function(a,e){if(!a&&!e)return!0;if(!a||!e||a.length!=e.length)return!1;\nfor(var g=0;g<a.length;g++)if(a[g]!=e[g])return!1;return!0},getIndex:function(a,e){for(var g=0;g<a.length;++g)if(e(a[g]))return g;return-1},clone:function(a){var e;if(a&&a instanceof Array){e=[];for(var g=0;g<a.length;g++)e[g]=CKEDITOR.tools.clone(a[g]);return e}if(null===a||\"object\"!=typeof a||a instanceof String||a instanceof Number||a instanceof Boolean||a instanceof Date||a instanceof RegExp||a.nodeType||a.window===a)return a;e=new a.constructor;for(g in a)e[g]=CKEDITOR.tools.clone(a[g]);return e},\ncapitalize:function(a,e){return a.charAt(0).toUpperCase()+(e?a.slice(1):a.slice(1).toLowerCase())},extend:function(a){var e=arguments.length,g,b;\"boolean\"==typeof(g=arguments[e-1])?e--:\"boolean\"==typeof(g=arguments[e-2])&&(b=arguments[e-1],e-=2);for(var h=1;h<e;h++){var c=arguments[h]||{};CKEDITOR.tools.array.forEach(CKEDITOR.tools.object.keys(c),function(e){if(!0===g||null==a[e])if(!b||e in b)a[e]=c[e]})}return a},prototypedCopy:function(a){var e=function(){};e.prototype=a;return new e},copy:function(a){var e=\n{},g;for(g in a)e[g]=a[g];return e},isArray:function(a){return\"[object Array]\"==Object.prototype.toString.call(a)},isEmpty:function(a){for(var e in a)if(a.hasOwnProperty(e))return!1;return!0},cssVendorPrefix:function(a,e,g){if(g)return c+a+\":\"+e+\";\"+a+\":\"+e;g={};g[a]=e;g[c+a]=e;return g},cssStyleToDomStyle:function(){var a=document.createElement(\"div\").style,e=\"undefined\"!=typeof a.cssFloat?\"cssFloat\":\"undefined\"!=typeof a.styleFloat?\"styleFloat\":\"float\";return function(a){return\"float\"==a?e:a.replace(/-./g,\nfunction(a){return a.substr(1).toUpperCase()})}}(),buildStyleHtml:function(a){a=[].concat(a);for(var e,g=[],b=0;b<a.length;b++)if(e=a[b])/@import|[{}]/.test(e)?g.push(\"\\x3cstyle\\x3e\"+e+\"\\x3c/style\\x3e\"):g.push('\\x3clink type\\x3d\"text/css\" rel\\x3dstylesheet href\\x3d\"'+e+'\"\\x3e');return g.join(\"\")},htmlEncode:function(a){return void 0===a||null===a?\"\":String(a).replace(d,\"\\x26amp;\").replace(l,\"\\x26gt;\").replace(k,\"\\x26lt;\")},htmlDecode:function(a){return a.replace(h,e)},htmlEncodeAttr:function(a){return CKEDITOR.tools.htmlEncode(a).replace(g,\n\"\\x26quot;\")},htmlDecodeAttr:function(a){return CKEDITOR.tools.htmlDecode(a)},transformPlainTextToHtml:function(a,e){var g=e==CKEDITOR.ENTER_BR,b=this.htmlEncode(a.replace(/\\r\\n/g,\"\\n\")),b=b.replace(/\\t/g,\"\\x26nbsp;\\x26nbsp; \\x26nbsp;\"),h=e==CKEDITOR.ENTER_P?\"p\":\"div\";if(!g){var c=/\\n{2}/g;if(c.test(b))var d=\"\\x3c\"+h+\"\\x3e\",m=\"\\x3c/\"+h+\"\\x3e\",b=d+b.replace(c,function(){return m+d})+m}b=b.replace(/\\n/g,\"\\x3cbr\\x3e\");g||(b=b.replace(new RegExp(\"\\x3cbr\\x3e(?\\x3d\\x3c/\"+h+\"\\x3e)\"),function(a){return CKEDITOR.tools.repeat(a,\n2)}));b=b.replace(/^ | $/g,\"\\x26nbsp;\");return b=b.replace(/(>|\\s) /g,function(a,e){return e+\"\\x26nbsp;\"}).replace(/ (?=<)/g,\"\\x26nbsp;\")},getNextNumber:function(){var a=0;return function(){return++a}}(),getNextId:function(){return\"cke_\"+this.getNextNumber()},getUniqueId:function(){for(var a=\"e\",e=0;8>e;e++)a+=Math.floor(65536*(1+Math.random())).toString(16).substring(1);return a},override:function(a,e){var g=e(a);g.prototype=a.prototype;return g},setTimeout:function(a,e,g,b,h){h||(h=window);g||(g=\nh);return h.setTimeout(function(){b?a.apply(g,[].concat(b)):a.apply(g)},e||0)},throttle:function(a,e,g){return new this.buffers.throttle(a,e,g)},trim:function(){var a=/(?:^[ \\t\\n\\r]+)|(?:[ \\t\\n\\r]+$)/g;return function(e){return e.replace(a,\"\")}}(),ltrim:function(){var a=/^[ \\t\\n\\r]+/g;return function(e){return e.replace(a,\"\")}}(),rtrim:function(){var a=/[ \\t\\n\\r]+$/g;return function(e){return e.replace(a,\"\")}}(),indexOf:function(a,e){if(\"function\"==typeof e)for(var g=0,b=a.length;g<b;g++){if(e(a[g]))return g}else{if(a.indexOf)return a.indexOf(e);\ng=0;for(b=a.length;g<b;g++)if(a[g]===e)return g}return-1},search:function(a,e){var g=CKEDITOR.tools.indexOf(a,e);return 0<=g?a[g]:null},bind:function(a,e){return function(){return a.apply(e,arguments)}},createClass:function(a){var e=a.$,g=a.base,b=a.privates||a._,h=a.proto;a=a.statics;!e&&(e=function(){g&&this.base.apply(this,arguments)});if(b)var c=e,e=function(){var a=this._||(this._={}),e;for(e in b){var g=b[e];a[e]=\"function\"==typeof g?CKEDITOR.tools.bind(g,this):g}c.apply(this,arguments)};g&&\n(e.prototype=this.prototypedCopy(g.prototype),e.prototype.constructor=e,e.base=g,e.baseProto=g.prototype,e.prototype.base=function r(){this.base=g.prototype.base;g.apply(this,arguments);this.base=r});h&&this.extend(e.prototype,h,!0);a&&this.extend(e,a,!0);return e},addFunction:function(a,e){return b.push(function(){return a.apply(e||this,arguments)})-1},removeFunction:function(a){b[a]=null},callFunction:function(a){var e=b[a];return e&&e.apply(window,Array.prototype.slice.call(arguments,1))},cssLength:function(){var a=\n/^-?\\d+\\.?\\d*px$/,e;return function(g){e=CKEDITOR.tools.trim(g+\"\")+\"px\";return a.test(e)?e:g||\"\"}}(),convertToPx:function(){var a;return function(e){a||(a=CKEDITOR.dom.element.createFromHtml('\\x3cdiv style\\x3d\"position:absolute;left:-9999px;top:-9999px;margin:0px;padding:0px;border:0px;\"\\x3e\\x3c/div\\x3e',CKEDITOR.document),CKEDITOR.document.getBody().append(a));if(!/%$/.test(e)){var g=0>parseFloat(e);g&&(e=e.replace(\"-\",\"\"));a.setStyle(\"width\",e);e=a.$.clientWidth;return g?-e:e}return e}}(),repeat:function(a,\ne){return Array(e+1).join(a)},tryThese:function(){for(var a,e=0,g=arguments.length;e<g;e++){var b=arguments[e];try{a=b();break}catch(h){}}return a},genKey:function(){return Array.prototype.slice.call(arguments).join(\"-\")},defer:function(a){return function(){var e=arguments,g=this;window.setTimeout(function(){a.apply(g,e)},0)}},normalizeCssText:function(a,e){var g=[],b,h=CKEDITOR.tools.parseCssText(a,!0,e);for(b in h)g.push(b+\":\"+h[b]);g.sort();return g.length?g.join(\";\")+\";\":\"\"},convertRgbToHex:function(a){return a.replace(/(?:rgb\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*\\))/gi,\nfunction(a,e,g,b){a=[e,g,b];for(e=0;3>e;e++)a[e]=(\"0\"+parseInt(a[e],10).toString(16)).slice(-2);return\"#\"+a.join(\"\")})},normalizeHex:function(a){return a.replace(/#(([0-9a-f]{3}){1,2})($|;|\\s+)/gi,function(a,e,g,b){a=e.toLowerCase();3==a.length&&(a=a.split(\"\"),a=[a[0],a[0],a[1],a[1],a[2],a[2]].join(\"\"));return\"#\"+a+b})},parseCssText:function(a,e,g){var b={};g&&(a=(new CKEDITOR.dom.element(\"span\")).setAttribute(\"style\",a).getAttribute(\"style\")||\"\");a&&(a=CKEDITOR.tools.normalizeHex(CKEDITOR.tools.convertRgbToHex(a)));\nif(!a||\";\"==a)return b;a.replace(/&quot;/g,'\"').replace(/\\s*([^:;\\s]+)\\s*:\\s*([^;]+)\\s*(?=;|$)/g,function(a,g,h){e&&(g=g.toLowerCase(),\"font-family\"==g&&(h=h.replace(/\\s*,\\s*/g,\",\")),h=CKEDITOR.tools.trim(h));b[g]=h});return b},writeCssText:function(a,e){var g,b=[];for(g in a)b.push(g+\":\"+a[g]);e&&b.sort();return b.join(\"; \")},objectCompare:function(a,e,g){var b;if(!a&&!e)return!0;if(!a||!e)return!1;for(b in a)if(a[b]!=e[b])return!1;if(!g)for(b in e)if(a[b]!=e[b])return!1;return!0},objectKeys:function(a){return CKEDITOR.tools.object.keys(a)},\nconvertArrayToObject:function(a,e){var g={};1==arguments.length&&(e=!0);for(var b=0,h=a.length;b<h;++b)g[a[b]]=e;return g},fixDomain:function(){for(var a;;)try{a=window.parent.document.domain;break}catch(e){a=a?a.replace(/.+?(?:\\.|$)/,\"\"):document.domain;if(!a)break;document.domain=a}return!!a},eventsBuffer:function(a,e,g){return new this.buffers.event(a,e,g)},enableHtml5Elements:function(a,e){for(var g=\"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup main mark meter nav output progress section summary time video\".split(\" \"),\nb=g.length,h;b--;)h=a.createElement(g[b]),e&&a.appendChild(h)},checkIfAnyArrayItemMatches:function(a,e){for(var g=0,b=a.length;g<b;++g)if(a[g].match(e))return!0;return!1},checkIfAnyObjectPropertyMatches:function(a,e){for(var g in a)if(g.match(e))return!0;return!1},keystrokeToString:function(a,e){var g=this.keystrokeToArray(a,e);g.display=g.display.join(\"+\");g.aria=g.aria.join(\"+\");return g},keystrokeToArray:function(a,e){var g=e&16711680,b=e&65535,h=CKEDITOR.env.mac,c=[],d=[];g&CKEDITOR.CTRL&&(c.push(h?\n\"⌘\":a[17]),d.push(h?a[224]:a[17]));g&CKEDITOR.ALT&&(c.push(h?\"⌥\":a[18]),d.push(a[18]));g&CKEDITOR.SHIFT&&(c.push(h?\"⇧\":a[16]),d.push(a[16]));b&&(a[b]?(c.push(a[b]),d.push(a[b])):(c.push(String.fromCharCode(b)),d.push(String.fromCharCode(b))));return{display:c,aria:d}},transparentImageData:\"data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw\\x3d\\x3d\",getCookie:function(a){a=a.toLowerCase();for(var e=document.cookie.split(\";\"),g,b,h=0;h<e.length;h++)if(g=e[h].split(\"\\x3d\"),\nb=decodeURIComponent(CKEDITOR.tools.trim(g[0]).toLowerCase()),b===a)return decodeURIComponent(1<g.length?g[1]:\"\");return null},setCookie:function(a,e){document.cookie=encodeURIComponent(a)+\"\\x3d\"+encodeURIComponent(e)+\";path\\x3d/\"},getCsrfToken:function(){var a=CKEDITOR.tools.getCookie(\"ckCsrfToken\");if(!a||40!=a.length){var a=[],e=\"\";if(window.crypto&&window.crypto.getRandomValues)a=new Uint8Array(40),window.crypto.getRandomValues(a);else for(var g=0;40>g;g++)a.push(Math.floor(256*Math.random()));\nfor(g=0;g<a.length;g++)var b=\"abcdefghijklmnopqrstuvwxyz0123456789\".charAt(a[g]%36),e=e+(.5<Math.random()?b.toUpperCase():b);a=e;CKEDITOR.tools.setCookie(\"ckCsrfToken\",a)}return a},escapeCss:function(a){return a?window.CSS&&CSS.escape?CSS.escape(a):isNaN(parseInt(a.charAt(0),10))?a:\"\\\\3\"+a.charAt(0)+\" \"+a.substring(1,a.length):\"\"},getMouseButton:function(a){return(a=a.data?a.data.$:a)?CKEDITOR.env.ie&&(9>CKEDITOR.env.version||CKEDITOR.env.ie6Compat)?4===a.button?CKEDITOR.MOUSE_BUTTON_MIDDLE:1===a.button?\nCKEDITOR.MOUSE_BUTTON_LEFT:CKEDITOR.MOUSE_BUTTON_RIGHT:a.button:!1},convertHexStringToBytes:function(a){var e=[],g=a.length/2,b;for(b=0;b<g;b++)e.push(parseInt(a.substr(2*b,2),16));return e},convertBytesToBase64:function(a){var e=\"\",g=a.length,b;for(b=0;b<g;b+=3){var h=a.slice(b,b+3),c=h.length,d=[],m;if(3>c)for(m=c;3>m;m++)h[m]=0;d[0]=(h[0]&252)>>2;d[1]=(h[0]&3)<<4|h[1]>>4;d[2]=(h[1]&15)<<2|(h[2]&192)>>6;d[3]=h[2]&63;for(m=0;4>m;m++)e=m<=c?e+\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\".charAt(d[m]):\ne+\"\\x3d\"}return e},style:{parse:{_colors:{aliceblue:\"#F0F8FF\",antiquewhite:\"#FAEBD7\",aqua:\"#00FFFF\",aquamarine:\"#7FFFD4\",azure:\"#F0FFFF\",beige:\"#F5F5DC\",bisque:\"#FFE4C4\",black:\"#000000\",blanchedalmond:\"#FFEBCD\",blue:\"#0000FF\",blueviolet:\"#8A2BE2\",brown:\"#A52A2A\",burlywood:\"#DEB887\",cadetblue:\"#5F9EA0\",chartreuse:\"#7FFF00\",chocolate:\"#D2691E\",coral:\"#FF7F50\",cornflowerblue:\"#6495ED\",cornsilk:\"#FFF8DC\",crimson:\"#DC143C\",cyan:\"#00FFFF\",darkblue:\"#00008B\",darkcyan:\"#008B8B\",darkgoldenrod:\"#B8860B\",darkgray:\"#A9A9A9\",\ndarkgreen:\"#006400\",darkgrey:\"#A9A9A9\",darkkhaki:\"#BDB76B\",darkmagenta:\"#8B008B\",darkolivegreen:\"#556B2F\",darkorange:\"#FF8C00\",darkorchid:\"#9932CC\",darkred:\"#8B0000\",darksalmon:\"#E9967A\",darkseagreen:\"#8FBC8F\",darkslateblue:\"#483D8B\",darkslategray:\"#2F4F4F\",darkslategrey:\"#2F4F4F\",darkturquoise:\"#00CED1\",darkviolet:\"#9400D3\",deeppink:\"#FF1493\",deepskyblue:\"#00BFFF\",dimgray:\"#696969\",dimgrey:\"#696969\",dodgerblue:\"#1E90FF\",firebrick:\"#B22222\",floralwhite:\"#FFFAF0\",forestgreen:\"#228B22\",fuchsia:\"#FF00FF\",\ngainsboro:\"#DCDCDC\",ghostwhite:\"#F8F8FF\",gold:\"#FFD700\",goldenrod:\"#DAA520\",gray:\"#808080\",green:\"#008000\",greenyellow:\"#ADFF2F\",grey:\"#808080\",honeydew:\"#F0FFF0\",hotpink:\"#FF69B4\",indianred:\"#CD5C5C\",indigo:\"#4B0082\",ivory:\"#FFFFF0\",khaki:\"#F0E68C\",lavender:\"#E6E6FA\",lavenderblush:\"#FFF0F5\",lawngreen:\"#7CFC00\",lemonchiffon:\"#FFFACD\",lightblue:\"#ADD8E6\",lightcoral:\"#F08080\",lightcyan:\"#E0FFFF\",lightgoldenrodyellow:\"#FAFAD2\",lightgray:\"#D3D3D3\",lightgreen:\"#90EE90\",lightgrey:\"#D3D3D3\",lightpink:\"#FFB6C1\",\nlightsalmon:\"#FFA07A\",lightseagreen:\"#20B2AA\",lightskyblue:\"#87CEFA\",lightslategray:\"#778899\",lightslategrey:\"#778899\",lightsteelblue:\"#B0C4DE\",lightyellow:\"#FFFFE0\",lime:\"#00FF00\",limegreen:\"#32CD32\",linen:\"#FAF0E6\",magenta:\"#FF00FF\",maroon:\"#800000\",mediumaquamarine:\"#66CDAA\",mediumblue:\"#0000CD\",mediumorchid:\"#BA55D3\",mediumpurple:\"#9370DB\",mediumseagreen:\"#3CB371\",mediumslateblue:\"#7B68EE\",mediumspringgreen:\"#00FA9A\",mediumturquoise:\"#48D1CC\",mediumvioletred:\"#C71585\",midnightblue:\"#191970\",mintcream:\"#F5FFFA\",\nmistyrose:\"#FFE4E1\",moccasin:\"#FFE4B5\",navajowhite:\"#FFDEAD\",navy:\"#000080\",oldlace:\"#FDF5E6\",olive:\"#808000\",olivedrab:\"#6B8E23\",orange:\"#FFA500\",orangered:\"#FF4500\",orchid:\"#DA70D6\",palegoldenrod:\"#EEE8AA\",palegreen:\"#98FB98\",paleturquoise:\"#AFEEEE\",palevioletred:\"#DB7093\",papayawhip:\"#FFEFD5\",peachpuff:\"#FFDAB9\",peru:\"#CD853F\",pink:\"#FFC0CB\",plum:\"#DDA0DD\",powderblue:\"#B0E0E6\",purple:\"#800080\",rebeccapurple:\"#663399\",red:\"#FF0000\",rosybrown:\"#BC8F8F\",royalblue:\"#4169E1\",saddlebrown:\"#8B4513\",salmon:\"#FA8072\",\nsandybrown:\"#F4A460\",seagreen:\"#2E8B57\",seashell:\"#FFF5EE\",sienna:\"#A0522D\",silver:\"#C0C0C0\",skyblue:\"#87CEEB\",slateblue:\"#6A5ACD\",slategray:\"#708090\",slategrey:\"#708090\",snow:\"#FFFAFA\",springgreen:\"#00FF7F\",steelblue:\"#4682B4\",tan:\"#D2B48C\",teal:\"#008080\",thistle:\"#D8BFD8\",tomato:\"#FF6347\",turquoise:\"#40E0D0\",violet:\"#EE82EE\",windowtext:\"windowtext\",wheat:\"#F5DEB3\",white:\"#FFFFFF\",whitesmoke:\"#F5F5F5\",yellow:\"#FFFF00\",yellowgreen:\"#9ACD32\"},_borderStyle:\"none hidden dotted dashed solid double groove ridge inset outset\".split(\" \"),\n_widthRegExp:/^(thin|medium|thick|[\\+-]?\\d+(\\.\\d+)?[a-z%]+|[\\+-]?0+(\\.0+)?|\\.\\d+[a-z%]+)$/,_rgbaRegExp:/rgba?\\(\\s*\\d+%?\\s*,\\s*\\d+%?\\s*,\\s*\\d+%?\\s*(?:,\\s*[0-9.]+\\s*)?\\)/gi,_hslaRegExp:/hsla?\\(\\s*[0-9.]+\\s*,\\s*\\d+%\\s*,\\s*\\d+%\\s*(?:,\\s*[0-9.]+\\s*)?\\)/gi,background:function(a){var e={},g=this._findColor(a);g.length&&(e.color=g[0],CKEDITOR.tools.array.forEach(g,function(e){a=a.replace(e,\"\")}));if(a=CKEDITOR.tools.trim(a))e.unprocessed=a;return e},margin:function(a){return CKEDITOR.tools.style.parse.sideShorthand(a,\nfunction(a){return a.match(/(?:\\-?[\\.\\d]+(?:%|\\w*)|auto|inherit|initial|unset|revert)/g)||[\"0px\"]})},sideShorthand:function(a,e){function g(a){b.top=h[a[0]];b.right=h[a[1]];b.bottom=h[a[2]];b.left=h[a[3]]}var b={},h=e?e(a):a.split(/\\s+/);switch(h.length){case 1:g([0,0,0,0]);break;case 2:g([0,1,0,1]);break;case 3:g([0,1,2,1]);break;case 4:g([0,1,2,3])}return b},border:function(a){return CKEDITOR.tools.style.border.fromCssRule(a)},_findColor:function(a){var e=[],g=CKEDITOR.tools.array,e=e.concat(a.match(this._rgbaRegExp)||\n[]),e=e.concat(a.match(this._hslaRegExp)||[]);return e=e.concat(g.filter(a.split(/\\s+/),function(a){return a.match(/^\\#[a-f0-9]{3}(?:[a-f0-9]{3})?$/gi)?!0:a.toLowerCase()in CKEDITOR.tools.style.parse._colors}))}}},array:{filter:function(a,e,g){var b=[];this.forEach(a,function(h,c){e.call(g,h,c,a)&&b.push(h)});return b},find:function(a,e,g){for(var b=a.length,h=0;h<b;){if(e.call(g,a[h],h,a))return a[h];h++}},forEach:function(a,e,g){var b=a.length,h;for(h=0;h<b;h++)e.call(g,a[h],h,a)},map:function(a,\ne,g){for(var b=[],h=0;h<a.length;h++)b.push(e.call(g,a[h],h,a));return b},reduce:function(a,e,g,b){for(var h=0;h<a.length;h++)g=e.call(b,g,a[h],h,a);return g},every:function(a,e,g){if(!a.length)return!0;e=this.filter(a,e,g);return a.length===e.length}},object:{DONT_ENUMS:\"toString toLocaleString valueOf hasOwnProperty isPrototypeOf propertyIsEnumerable constructor\".split(\" \"),entries:function(a){return CKEDITOR.tools.array.map(CKEDITOR.tools.object.keys(a),function(e){return[e,a[e]]})},values:function(a){return CKEDITOR.tools.array.map(CKEDITOR.tools.object.keys(a),\nfunction(e){return a[e]})},keys:function(a){var e=Object.prototype.hasOwnProperty,g=[],b=CKEDITOR.tools.object.DONT_ENUMS,h;for(h in a)g.push(h);if(CKEDITOR.env.ie&&9>CKEDITOR.env.version)for(h=0;h<b.length;h++)e.call(a,b[h])&&g.push(b[h]);return g},findKey:function(a,e){if(\"object\"!==typeof a)return null;for(var g in a)if(a[g]===e)return g;return null},merge:function(a,e){var g=CKEDITOR.tools,b=g.clone(a),h=g.clone(e);g.array.forEach(g.object.keys(h),function(a){b[a]=\"object\"===typeof h[a]&&\"object\"===\ntypeof b[a]?g.object.merge(b[a],h[a]):h[a]});return b}},getAbsoluteRectPosition:function(a,e){function g(a){if(a){var e=a.getClientRect();b.top+=e.top;b.left+=e.left;\"x\"in b&&\"y\"in b&&(b.x+=e.x,b.y+=e.y);g(a.getWindow().getFrame())}}var b=CKEDITOR.tools.copy(e);g(a.getFrame());var h=CKEDITOR.document.getWindow().getScrollPosition();b.top+=h.y;b.left+=h.x;\"x\"in b&&\"y\"in b&&(b.y+=h.y,b.x+=h.x);b.right=b.left+b.width;b.bottom=b.top+b.height;return b}};a.prototype={reset:function(){this._lastOutput=0;\nthis._clearTimer()},_reschedule:function(){return!1},_call:function(){this._output()},_clearTimer:function(){this._scheduledTimer&&clearTimeout(this._scheduledTimer);this._scheduledTimer=0}};f.prototype=CKEDITOR.tools.prototypedCopy(a.prototype);f.prototype._reschedule=function(){this._scheduledTimer&&this._clearTimer()};f.prototype._call=function(){this._output.apply(this._context,this._args)};CKEDITOR.tools.buffers={};CKEDITOR.tools.buffers.event=a;CKEDITOR.tools.buffers.throttle=f;CKEDITOR.tools.style.border=\nCKEDITOR.tools.createClass({$:function(a){a=a||{};this.width=a.width;this.style=a.style;this.color=a.color;this._.normalize()},_:{normalizeMap:{color:[[/windowtext/g,\"black\"]]},normalize:function(){for(var a in this._.normalizeMap){var e=this[a];e&&(this[a]=CKEDITOR.tools.array.reduce(this._.normalizeMap[a],function(a,e){return a.replace(e[0],e[1])},e))}}},proto:{toString:function(){return CKEDITOR.tools.array.filter([this.width,this.style,this.color],function(a){return!!a}).join(\" \")}},statics:{fromCssRule:function(a){var e=\n{},g=a.split(/\\s+/g);a=CKEDITOR.tools.style.parse._findColor(a);a.length&&(e.color=a[0]);CKEDITOR.tools.array.forEach(g,function(a){e.style||-1===CKEDITOR.tools.indexOf(CKEDITOR.tools.style.parse._borderStyle,a)?!e.width&&CKEDITOR.tools.style.parse._widthRegExp.test(a)&&(e.width=a):e.style=a});return new CKEDITOR.tools.style.border(e)},splitCssValues:function(a,e){e=e||{};var g=CKEDITOR.tools.array.reduce([\"width\",\"style\",\"color\"],function(g,b){var h=a[\"border-\"+b]||e[b];g[b]=h?CKEDITOR.tools.style.parse.sideShorthand(h):\nnull;return g},{});return CKEDITOR.tools.array.reduce([\"top\",\"right\",\"bottom\",\"left\"],function(e,b){var h={},c;for(c in g){var d=a[\"border-\"+b+\"-\"+c];h[c]=d?d:g[c]&&g[c][b]}e[\"border-\"+b]=new CKEDITOR.tools.style.border(h);return e},{})}}});CKEDITOR.tools.array.indexOf=CKEDITOR.tools.indexOf;CKEDITOR.tools.array.isArray=CKEDITOR.tools.isArray;CKEDITOR.MOUSE_BUTTON_LEFT=0;CKEDITOR.MOUSE_BUTTON_MIDDLE=1;CKEDITOR.MOUSE_BUTTON_RIGHT=2}(),CKEDITOR.dtd=function(){var a=CKEDITOR.tools.extend,f=function(a,\ne){for(var g=CKEDITOR.tools.clone(a),b=1;b<arguments.length;b++){e=arguments[b];for(var h in e)delete g[h]}return g},b={},c={},d={address:1,article:1,aside:1,blockquote:1,details:1,div:1,dl:1,fieldset:1,figure:1,footer:1,form:1,h1:1,h2:1,h3:1,h4:1,h5:1,h6:1,header:1,hgroup:1,hr:1,main:1,menu:1,nav:1,ol:1,p:1,pre:1,section:1,table:1,ul:1},l={command:1,link:1,meta:1,noscript:1,script:1,style:1},k={},g={\"#\":1},h={center:1,dir:1,noframes:1};a(b,{a:1,abbr:1,area:1,audio:1,b:1,bdi:1,bdo:1,br:1,button:1,\ncanvas:1,cite:1,code:1,command:1,datalist:1,del:1,dfn:1,em:1,embed:1,i:1,iframe:1,img:1,input:1,ins:1,kbd:1,keygen:1,label:1,map:1,mark:1,meter:1,noscript:1,object:1,output:1,progress:1,q:1,ruby:1,s:1,samp:1,script:1,select:1,small:1,span:1,strong:1,sub:1,sup:1,textarea:1,time:1,u:1,\"var\":1,video:1,wbr:1},g,{acronym:1,applet:1,basefont:1,big:1,font:1,isindex:1,strike:1,style:1,tt:1});a(c,d,b,h);f={a:f(b,{a:1,button:1}),abbr:b,address:c,area:k,article:c,aside:c,audio:a({source:1,track:1},c),b:b,base:k,\nbdi:b,bdo:b,blockquote:c,body:c,br:k,button:f(b,{a:1,button:1}),canvas:b,caption:c,cite:b,code:b,col:k,colgroup:{col:1},command:k,datalist:a({option:1},b),dd:c,del:b,details:a({summary:1},c),dfn:b,div:c,dl:{dt:1,dd:1},dt:c,em:b,embed:k,fieldset:a({legend:1},c),figcaption:c,figure:a({figcaption:1},c),footer:c,form:c,h1:b,h2:b,h3:b,h4:b,h5:b,h6:b,head:a({title:1,base:1},l),header:c,hgroup:{h1:1,h2:1,h3:1,h4:1,h5:1,h6:1},hr:k,html:a({head:1,body:1},c,l),i:b,iframe:g,img:k,input:k,ins:b,kbd:b,keygen:k,\nlabel:b,legend:b,li:c,link:k,main:c,map:c,mark:b,menu:a({li:1},c),meta:k,meter:f(b,{meter:1}),nav:c,noscript:a({link:1,meta:1,style:1},b),object:a({param:1},b),ol:{li:1},optgroup:{option:1},option:g,output:b,p:b,param:k,pre:b,progress:f(b,{progress:1}),q:b,rp:b,rt:b,ruby:a({rp:1,rt:1},b),s:b,samp:b,script:g,section:c,select:{optgroup:1,option:1},small:b,source:k,span:b,strong:b,style:g,sub:b,summary:a({h1:1,h2:1,h3:1,h4:1,h5:1,h6:1},b),sup:b,table:{caption:1,colgroup:1,thead:1,tfoot:1,tbody:1,tr:1},\ntbody:{tr:1},td:c,textarea:g,tfoot:{tr:1},th:c,thead:{tr:1},time:f(b,{time:1}),title:g,tr:{th:1,td:1},track:k,u:b,ul:{li:1},\"var\":b,video:a({source:1,track:1},c),wbr:k,acronym:b,applet:a({param:1},c),basefont:k,big:b,center:c,dialog:k,dir:{li:1},font:b,isindex:k,noframes:c,strike:b,tt:b};a(f,{$block:a({audio:1,dd:1,dt:1,figcaption:1,li:1,video:1},d,h),$blockLimit:{article:1,aside:1,audio:1,body:1,caption:1,details:1,dir:1,div:1,dl:1,fieldset:1,figcaption:1,figure:1,footer:1,form:1,header:1,hgroup:1,\nmain:1,menu:1,nav:1,ol:1,section:1,table:1,td:1,th:1,tr:1,ul:1,video:1},$cdata:{script:1,style:1},$editable:{address:1,article:1,aside:1,blockquote:1,body:1,details:1,div:1,fieldset:1,figcaption:1,footer:1,form:1,h1:1,h2:1,h3:1,h4:1,h5:1,h6:1,header:1,hgroup:1,main:1,nav:1,p:1,pre:1,section:1},$empty:{area:1,base:1,basefont:1,br:1,col:1,command:1,dialog:1,embed:1,hr:1,img:1,input:1,isindex:1,keygen:1,link:1,meta:1,param:1,source:1,track:1,wbr:1},$inline:b,$list:{dl:1,ol:1,ul:1},$listItem:{dd:1,dt:1,\nli:1},$nonBodyContent:a({body:1,head:1,html:1},f.head),$nonEditable:{applet:1,audio:1,button:1,embed:1,iframe:1,map:1,object:1,option:1,param:1,script:1,textarea:1,video:1},$object:{applet:1,audio:1,button:1,hr:1,iframe:1,img:1,input:1,object:1,select:1,table:1,textarea:1,video:1},$removeEmpty:{abbr:1,acronym:1,b:1,bdi:1,bdo:1,big:1,cite:1,code:1,del:1,dfn:1,em:1,font:1,i:1,ins:1,label:1,kbd:1,mark:1,meter:1,output:1,q:1,ruby:1,s:1,samp:1,small:1,span:1,strike:1,strong:1,sub:1,sup:1,time:1,tt:1,u:1,\n\"var\":1},$tabIndex:{a:1,area:1,button:1,input:1,object:1,select:1,textarea:1},$tableContent:{caption:1,col:1,colgroup:1,tbody:1,td:1,tfoot:1,th:1,thead:1,tr:1},$transparent:{a:1,audio:1,canvas:1,del:1,ins:1,map:1,noscript:1,object:1,video:1},$intermediate:{caption:1,colgroup:1,dd:1,dt:1,figcaption:1,legend:1,li:1,optgroup:1,option:1,rp:1,rt:1,summary:1,tbody:1,td:1,tfoot:1,th:1,thead:1,tr:1}});return f}(),CKEDITOR.dom.event=function(a){this.$=a},CKEDITOR.dom.event.prototype={getKey:function(){return this.$.keyCode||\nthis.$.which},getKeystroke:function(){var a=this.getKey();if(this.$.ctrlKey||this.$.metaKey)a+=CKEDITOR.CTRL;this.$.shiftKey&&(a+=CKEDITOR.SHIFT);this.$.altKey&&(a+=CKEDITOR.ALT);return a},preventDefault:function(a){var f=this.$;f.preventDefault?f.preventDefault():f.returnValue=!1;a&&this.stopPropagation()},stopPropagation:function(){var a=this.$;a.stopPropagation?a.stopPropagation():a.cancelBubble=!0},getTarget:function(){var a=this.$.target||this.$.srcElement;return a?new CKEDITOR.dom.node(a):null},\ngetPhase:function(){return this.$.eventPhase||2},getPageOffset:function(){var a=this.getTarget().getDocument().$;return{x:this.$.pageX||this.$.clientX+(a.documentElement.scrollLeft||a.body.scrollLeft),y:this.$.pageY||this.$.clientY+(a.documentElement.scrollTop||a.body.scrollTop)}}},CKEDITOR.CTRL=1114112,CKEDITOR.SHIFT=2228224,CKEDITOR.ALT=4456448,CKEDITOR.EVENT_PHASE_CAPTURING=1,CKEDITOR.EVENT_PHASE_AT_TARGET=2,CKEDITOR.EVENT_PHASE_BUBBLING=3,CKEDITOR.dom.domObject=function(a){a&&(this.$=a)},CKEDITOR.dom.domObject.prototype=\nfunction(){var a=function(a,b){return function(c){\"undefined\"!=typeof CKEDITOR&&a.fire(b,new CKEDITOR.dom.event(c))}};return{getPrivate:function(){var a;(a=this.getCustomData(\"_\"))||this.setCustomData(\"_\",a={});return a},on:function(f){var b=this.getCustomData(\"_cke_nativeListeners\");b||(b={},this.setCustomData(\"_cke_nativeListeners\",b));b[f]||(b=b[f]=a(this,f),this.$.addEventListener?this.$.addEventListener(f,b,!!CKEDITOR.event.useCapture):this.$.attachEvent&&this.$.attachEvent(\"on\"+f,b));return CKEDITOR.event.prototype.on.apply(this,\narguments)},removeListener:function(a){CKEDITOR.event.prototype.removeListener.apply(this,arguments);if(!this.hasListeners(a)){var b=this.getCustomData(\"_cke_nativeListeners\"),c=b&&b[a];c&&(this.$.removeEventListener?this.$.removeEventListener(a,c,!1):this.$.detachEvent&&this.$.detachEvent(\"on\"+a,c),delete b[a])}},removeAllListeners:function(){var a=this.getCustomData(\"_cke_nativeListeners\"),b;for(b in a){var c=a[b];this.$.detachEvent?this.$.detachEvent(\"on\"+b,c):this.$.removeEventListener&&this.$.removeEventListener(b,\nc,!1);delete a[b]}CKEDITOR.event.prototype.removeAllListeners.call(this)}}}(),function(a){var f={};CKEDITOR.on(\"reset\",function(){f={}});a.equals=function(a){try{return a&&a.$===this.$}catch(c){return!1}};a.setCustomData=function(a,c){var d=this.getUniqueId();(f[d]||(f[d]={}))[a]=c;return this};a.getCustomData=function(a){var c=this.$[\"data-cke-expando\"];return(c=c&&f[c])&&a in c?c[a]:null};a.removeCustomData=function(a){var c=this.$[\"data-cke-expando\"],c=c&&f[c],d,l;c&&(d=c[a],l=a in c,delete c[a]);\nreturn l?d:null};a.clearCustomData=function(){this.removeAllListeners();var a=this.$[\"data-cke-expando\"];a&&delete f[a]};a.getUniqueId=function(){return this.$[\"data-cke-expando\"]||(this.$[\"data-cke-expando\"]=CKEDITOR.tools.getNextNumber())};CKEDITOR.event.implementOn(a)}(CKEDITOR.dom.domObject.prototype),CKEDITOR.dom.node=function(a){return a?new CKEDITOR.dom[a.nodeType==CKEDITOR.NODE_DOCUMENT?\"document\":a.nodeType==CKEDITOR.NODE_ELEMENT?\"element\":a.nodeType==CKEDITOR.NODE_TEXT?\"text\":a.nodeType==\nCKEDITOR.NODE_COMMENT?\"comment\":a.nodeType==CKEDITOR.NODE_DOCUMENT_FRAGMENT?\"documentFragment\":\"domObject\"](a):this},CKEDITOR.dom.node.prototype=new CKEDITOR.dom.domObject,CKEDITOR.NODE_ELEMENT=1,CKEDITOR.NODE_DOCUMENT=9,CKEDITOR.NODE_TEXT=3,CKEDITOR.NODE_COMMENT=8,CKEDITOR.NODE_DOCUMENT_FRAGMENT=11,CKEDITOR.POSITION_IDENTICAL=0,CKEDITOR.POSITION_DISCONNECTED=1,CKEDITOR.POSITION_FOLLOWING=2,CKEDITOR.POSITION_PRECEDING=4,CKEDITOR.POSITION_IS_CONTAINED=8,CKEDITOR.POSITION_CONTAINS=16,CKEDITOR.tools.extend(CKEDITOR.dom.node.prototype,\n{appendTo:function(a,f){a.append(this,f);return a},clone:function(a,f){function b(c){c[\"data-cke-expando\"]&&(c[\"data-cke-expando\"]=!1);if(c.nodeType==CKEDITOR.NODE_ELEMENT||c.nodeType==CKEDITOR.NODE_DOCUMENT_FRAGMENT)if(f||c.nodeType!=CKEDITOR.NODE_ELEMENT||c.removeAttribute(\"id\",!1),a){c=c.childNodes;for(var d=0;d<c.length;d++)b(c[d])}}function c(b){if(b.type==CKEDITOR.NODE_ELEMENT||b.type==CKEDITOR.NODE_DOCUMENT_FRAGMENT){if(b.type!=CKEDITOR.NODE_DOCUMENT_FRAGMENT){var d=b.getName();\":\"==d[0]&&\nb.renameNode(d.substring(1))}if(a)for(d=0;d<b.getChildCount();d++)c(b.getChild(d))}}var d=this.$.cloneNode(a);b(d);d=new CKEDITOR.dom.node(d);CKEDITOR.env.ie&&9>CKEDITOR.env.version&&(this.type==CKEDITOR.NODE_ELEMENT||this.type==CKEDITOR.NODE_DOCUMENT_FRAGMENT)&&c(d);return d},hasPrevious:function(){return!!this.$.previousSibling},hasNext:function(){return!!this.$.nextSibling},insertAfter:function(a){a.$.parentNode.insertBefore(this.$,a.$.nextSibling);return a},insertBefore:function(a){a.$.parentNode.insertBefore(this.$,\na.$);return a},insertBeforeMe:function(a){this.$.parentNode.insertBefore(a.$,this.$);return a},getAddress:function(a){for(var f=[],b=this.getDocument().$.documentElement,c=this.$;c&&c!=b;){var d=c.parentNode;d&&f.unshift(this.getIndex.call({$:c},a));c=d}return f},getDocument:function(){return new CKEDITOR.dom.document(this.$.ownerDocument||this.$.parentNode.ownerDocument)},getIndex:function(a){function f(a,g){var h=g?a.nextSibling:a.previousSibling;return h&&h.nodeType==CKEDITOR.NODE_TEXT?b(h)?f(h,\ng):h:null}function b(a){return!a.nodeValue||a.nodeValue==CKEDITOR.dom.selection.FILLING_CHAR_SEQUENCE}var c=this.$,d=-1,l;if(!this.$.parentNode||a&&c.nodeType==CKEDITOR.NODE_TEXT&&b(c)&&!f(c)&&!f(c,!0))return-1;do a&&c!=this.$&&c.nodeType==CKEDITOR.NODE_TEXT&&(l||b(c))||(d++,l=c.nodeType==CKEDITOR.NODE_TEXT);while(c=c.previousSibling);return d},getNextSourceNode:function(a,f,b){if(b&&!b.call){var c=b;b=function(a){return!a.equals(c)}}a=!a&&this.getFirst&&this.getFirst();var d;if(!a){if(this.type==\nCKEDITOR.NODE_ELEMENT&&b&&!1===b(this,!0))return null;a=this.getNext()}for(;!a&&(d=(d||this).getParent());){if(b&&!1===b(d,!0))return null;a=d.getNext()}return!a||b&&!1===b(a)?null:f&&f!=a.type?a.getNextSourceNode(!1,f,b):a},getPreviousSourceNode:function(a,f,b){if(b&&!b.call){var c=b;b=function(a){return!a.equals(c)}}a=!a&&this.getLast&&this.getLast();var d;if(!a){if(this.type==CKEDITOR.NODE_ELEMENT&&b&&!1===b(this,!0))return null;a=this.getPrevious()}for(;!a&&(d=(d||this).getParent());){if(b&&!1===\nb(d,!0))return null;a=d.getPrevious()}return!a||b&&!1===b(a)?null:f&&a.type!=f?a.getPreviousSourceNode(!1,f,b):a},getPrevious:function(a){var f=this.$,b;do b=(f=f.previousSibling)&&10!=f.nodeType&&new CKEDITOR.dom.node(f);while(b&&a&&!a(b));return b},getNext:function(a){var f=this.$,b;do b=(f=f.nextSibling)&&new CKEDITOR.dom.node(f);while(b&&a&&!a(b));return b},getParent:function(a){var f=this.$.parentNode;return f&&(f.nodeType==CKEDITOR.NODE_ELEMENT||a&&f.nodeType==CKEDITOR.NODE_DOCUMENT_FRAGMENT)?\nnew CKEDITOR.dom.node(f):null},getParents:function(a){var f=this,b=[];do b[a?\"push\":\"unshift\"](f);while(f=f.getParent());return b},getCommonAncestor:function(a){if(a.equals(this))return this;if(a.contains&&a.contains(this))return a;var f=this.contains?this:this.getParent();do if(f.contains(a))return f;while(f=f.getParent());return null},getPosition:function(a){var f=this.$,b=a.$;if(f.compareDocumentPosition)return f.compareDocumentPosition(b);if(f==b)return CKEDITOR.POSITION_IDENTICAL;if(this.type==\nCKEDITOR.NODE_ELEMENT&&a.type==CKEDITOR.NODE_ELEMENT){if(f.contains){if(f.contains(b))return CKEDITOR.POSITION_CONTAINS+CKEDITOR.POSITION_PRECEDING;if(b.contains(f))return CKEDITOR.POSITION_IS_CONTAINED+CKEDITOR.POSITION_FOLLOWING}if(\"sourceIndex\"in f)return 0>f.sourceIndex||0>b.sourceIndex?CKEDITOR.POSITION_DISCONNECTED:f.sourceIndex<b.sourceIndex?CKEDITOR.POSITION_PRECEDING:CKEDITOR.POSITION_FOLLOWING}f=this.getAddress();a=a.getAddress();for(var b=Math.min(f.length,a.length),c=0;c<b;c++)if(f[c]!=\na[c])return f[c]<a[c]?CKEDITOR.POSITION_PRECEDING:CKEDITOR.POSITION_FOLLOWING;return f.length<a.length?CKEDITOR.POSITION_CONTAINS+CKEDITOR.POSITION_PRECEDING:CKEDITOR.POSITION_IS_CONTAINED+CKEDITOR.POSITION_FOLLOWING},getAscendant:function(a,f){var b=this.$,c,d;f||(b=b.parentNode);\"function\"==typeof a?(d=!0,c=a):(d=!1,c=function(b){b=\"string\"==typeof b.nodeName?b.nodeName.toLowerCase():\"\";return\"string\"==typeof a?b==a:b in a});for(;b;){if(c(d?new CKEDITOR.dom.node(b):b))return new CKEDITOR.dom.node(b);\ntry{b=b.parentNode}catch(l){b=null}}return null},hasAscendant:function(a,f){var b=this.$;f||(b=b.parentNode);for(;b;){if(b.nodeName&&b.nodeName.toLowerCase()==a)return!0;b=b.parentNode}return!1},move:function(a,f){a.append(this.remove(),f)},remove:function(a){var f=this.$,b=f.parentNode;if(b){if(a)for(;a=f.firstChild;)b.insertBefore(f.removeChild(a),f);b.removeChild(f)}return this},replace:function(a){this.insertBefore(a);a.remove()},trim:function(){this.ltrim();this.rtrim()},ltrim:function(){for(var a;this.getFirst&&\n(a=this.getFirst());){if(a.type==CKEDITOR.NODE_TEXT){var f=CKEDITOR.tools.ltrim(a.getText()),b=a.getLength();if(f)f.length<b&&(a.split(b-f.length),this.$.removeChild(this.$.firstChild));else{a.remove();continue}}break}},rtrim:function(){for(var a;this.getLast&&(a=this.getLast());){if(a.type==CKEDITOR.NODE_TEXT){var f=CKEDITOR.tools.rtrim(a.getText()),b=a.getLength();if(f)f.length<b&&(a.split(f.length),this.$.lastChild.parentNode.removeChild(this.$.lastChild));else{a.remove();continue}}break}CKEDITOR.env.needsBrFiller&&\n(a=this.$.lastChild)&&1==a.type&&\"br\"==a.nodeName.toLowerCase()&&a.parentNode.removeChild(a)},isReadOnly:function(a){var f=this;this.type!=CKEDITOR.NODE_ELEMENT&&(f=this.getParent());CKEDITOR.env.edge&&f&&f.is(\"textarea\",\"input\")&&(a=!0);if(!a&&f&&\"undefined\"!=typeof f.$.isContentEditable)return!(f.$.isContentEditable||f.data(\"cke-editable\"));for(;f;){if(f.data(\"cke-editable\"))return!1;if(f.hasAttribute(\"contenteditable\"))return\"false\"==f.getAttribute(\"contenteditable\");f=f.getParent()}return!0}}),\nCKEDITOR.dom.window=function(a){CKEDITOR.dom.domObject.call(this,a)},CKEDITOR.dom.window.prototype=new CKEDITOR.dom.domObject,CKEDITOR.tools.extend(CKEDITOR.dom.window.prototype,{focus:function(){this.$.focus()},getViewPaneSize:function(){var a=this.$.document,f=\"CSS1Compat\"==a.compatMode;return{width:(f?a.documentElement.clientWidth:a.body.clientWidth)||0,height:(f?a.documentElement.clientHeight:a.body.clientHeight)||0}},getScrollPosition:function(){var a=this.$;if(\"pageXOffset\"in a)return{x:a.pageXOffset||\n0,y:a.pageYOffset||0};a=a.document;return{x:a.documentElement.scrollLeft||a.body.scrollLeft||0,y:a.documentElement.scrollTop||a.body.scrollTop||0}},getFrame:function(){var a=this.$.frameElement;return a?new CKEDITOR.dom.element.get(a):null}}),CKEDITOR.dom.document=function(a){CKEDITOR.dom.domObject.call(this,a)},CKEDITOR.dom.document.prototype=new CKEDITOR.dom.domObject,CKEDITOR.tools.extend(CKEDITOR.dom.document.prototype,{type:CKEDITOR.NODE_DOCUMENT,appendStyleSheet:function(a){if(this.$.createStyleSheet)this.$.createStyleSheet(a);\nelse{var f=new CKEDITOR.dom.element(\"link\");f.setAttributes({rel:\"stylesheet\",type:\"text/css\",href:a});this.getHead().append(f)}},appendStyleText:function(a){if(this.$.createStyleSheet){var f=this.$.createStyleSheet(\"\");f.cssText=a}else{var b=new CKEDITOR.dom.element(\"style\",this);b.append(new CKEDITOR.dom.text(a,this));this.getHead().append(b)}return f||b.$.sheet},createElement:function(a,f){var b=new CKEDITOR.dom.element(a,this);f&&(f.attributes&&b.setAttributes(f.attributes),f.styles&&b.setStyles(f.styles));\nreturn b},createText:function(a){return new CKEDITOR.dom.text(a,this)},focus:function(){this.getWindow().focus()},getActive:function(){var a;try{a=this.$.activeElement}catch(f){return null}return new CKEDITOR.dom.element(a)},getById:function(a){return(a=this.$.getElementById(a))?new CKEDITOR.dom.element(a):null},getByAddress:function(a,f){for(var b=this.$.documentElement,c=0;b&&c<a.length;c++){var d=a[c];if(f)for(var l=-1,k=0;k<b.childNodes.length;k++){var g=b.childNodes[k];if(!0!==f||3!=g.nodeType||\n!g.previousSibling||3!=g.previousSibling.nodeType)if(l++,l==d){b=g;break}}else b=b.childNodes[d]}return b?new CKEDITOR.dom.node(b):null},getElementsByTag:function(a,f){CKEDITOR.env.ie&&8>=document.documentMode||!f||(a=f+\":\"+a);return new CKEDITOR.dom.nodeList(this.$.getElementsByTagName(a))},getHead:function(){var a=this.$.getElementsByTagName(\"head\")[0];return a=a?new CKEDITOR.dom.element(a):this.getDocumentElement().append(new CKEDITOR.dom.element(\"head\"),!0)},getBody:function(){return new CKEDITOR.dom.element(this.$.body)},\ngetDocumentElement:function(){return new CKEDITOR.dom.element(this.$.documentElement)},getWindow:function(){return new CKEDITOR.dom.window(this.$.parentWindow||this.$.defaultView)},write:function(a){this.$.open(\"text/html\",\"replace\");CKEDITOR.env.ie&&(a=a.replace(/(?:^\\s*<!DOCTYPE[^>]*?>)|^/i,'$\\x26\\n\\x3cscript data-cke-temp\\x3d\"1\"\\x3e('+CKEDITOR.tools.fixDomain+\")();\\x3c/script\\x3e\"));this.$.write(a);this.$.close()},find:function(a){return new CKEDITOR.dom.nodeList(this.$.querySelectorAll(a))},findOne:function(a){return(a=\nthis.$.querySelector(a))?new CKEDITOR.dom.element(a):null},_getHtml5ShivFrag:function(){var a=this.getCustomData(\"html5ShivFrag\");a||(a=this.$.createDocumentFragment(),CKEDITOR.tools.enableHtml5Elements(a,!0),this.setCustomData(\"html5ShivFrag\",a));return a}}),CKEDITOR.dom.nodeList=function(a){this.$=a},CKEDITOR.dom.nodeList.prototype={count:function(){return this.$.length},getItem:function(a){return 0>a||a>=this.$.length?null:(a=this.$[a])?new CKEDITOR.dom.node(a):null},toArray:function(){return CKEDITOR.tools.array.map(this.$,\nfunction(a){return new CKEDITOR.dom.node(a)})}},CKEDITOR.dom.element=function(a,f){\"string\"==typeof a&&(a=(f?f.$:document).createElement(a));CKEDITOR.dom.domObject.call(this,a)},CKEDITOR.dom.element.get=function(a){return(a=\"string\"==typeof a?document.getElementById(a)||document.getElementsByName(a)[0]:a)&&(a.$?a:new CKEDITOR.dom.element(a))},CKEDITOR.dom.element.prototype=new CKEDITOR.dom.node,CKEDITOR.dom.element.createFromHtml=function(a,f){var b=new CKEDITOR.dom.element(\"div\",f);b.setHtml(a);\nreturn b.getFirst().remove()},CKEDITOR.dom.element.setMarker=function(a,f,b,c){var d=f.getCustomData(\"list_marker_id\")||f.setCustomData(\"list_marker_id\",CKEDITOR.tools.getNextNumber()).getCustomData(\"list_marker_id\"),l=f.getCustomData(\"list_marker_names\")||f.setCustomData(\"list_marker_names\",{}).getCustomData(\"list_marker_names\");a[d]=f;l[b]=1;return f.setCustomData(b,c)},CKEDITOR.dom.element.clearAllMarkers=function(a){for(var f in a)CKEDITOR.dom.element.clearMarkers(a,a[f],1)},CKEDITOR.dom.element.clearMarkers=\nfunction(a,f,b){var c=f.getCustomData(\"list_marker_names\"),d=f.getCustomData(\"list_marker_id\"),l;for(l in c)f.removeCustomData(l);f.removeCustomData(\"list_marker_names\");b&&(f.removeCustomData(\"list_marker_id\"),delete a[d])},function(){function a(a,b){return-1<(\" \"+a+\" \").replace(l,\" \").indexOf(\" \"+b+\" \")}function f(a){var b=!0;a.$.id||(a.$.id=\"cke_tmp_\"+CKEDITOR.tools.getNextNumber(),b=!1);return function(){b||a.removeAttribute(\"id\")}}function b(a,b){var c=CKEDITOR.tools.escapeCss(a.$.id);return\"#\"+\nc+\" \"+b.split(/,\\s*/).join(\", #\"+c+\" \")}function c(a){for(var b=0,c=0,e=k[a].length;c<e;c++)b+=parseFloat(this.getComputedStyle(k[a][c])||0,10)||0;return b}var d=document.createElement(\"_\").classList,d=\"undefined\"!==typeof d&&null!==String(d.add).match(/\\[Native code\\]/gi),l=/[\\n\\t\\r]/g;CKEDITOR.tools.extend(CKEDITOR.dom.element.prototype,{type:CKEDITOR.NODE_ELEMENT,addClass:d?function(a){this.$.classList.add(a);return this}:function(g){var b=this.$.className;b&&(a(b,g)||(b+=\" \"+g));this.$.className=\nb||g;return this},removeClass:d?function(a){var b=this.$;b.classList.remove(a);b.className||b.removeAttribute(\"class\");return this}:function(g){var b=this.getAttribute(\"class\");b&&a(b,g)&&((b=b.replace(new RegExp(\"(?:^|\\\\s+)\"+g+\"(?\\x3d\\\\s|$)\"),\"\").replace(/^\\s+/,\"\"))?this.setAttribute(\"class\",b):this.removeAttribute(\"class\"));return this},hasClass:function(b){return a(this.$.className,b)},append:function(a,b){\"string\"==typeof a&&(a=this.getDocument().createElement(a));b?this.$.insertBefore(a.$,this.$.firstChild):\nthis.$.appendChild(a.$);return a},appendHtml:function(a){if(this.$.childNodes.length){var b=new CKEDITOR.dom.element(\"div\",this.getDocument());b.setHtml(a);b.moveChildren(this)}else this.setHtml(a)},appendText:function(a){null!=this.$.text&&CKEDITOR.env.ie&&9>CKEDITOR.env.version?this.$.text+=a:this.append(new CKEDITOR.dom.text(a))},appendBogus:function(a){if(a||CKEDITOR.env.needsBrFiller){for(a=this.getLast();a&&a.type==CKEDITOR.NODE_TEXT&&!CKEDITOR.tools.rtrim(a.getText());)a=a.getPrevious();a&&\na.is&&a.is(\"br\")||(a=this.getDocument().createElement(\"br\"),CKEDITOR.env.gecko&&a.setAttribute(\"type\",\"_moz\"),this.append(a))}},breakParent:function(a,b){var c=new CKEDITOR.dom.range(this.getDocument());c.setStartAfter(this);c.setEndAfter(a);var e=c.extractContents(!1,b||!1),d;c.insertNode(this.remove());if(CKEDITOR.env.ie&&!CKEDITOR.env.edge){for(c=new CKEDITOR.dom.element(\"div\");d=e.getFirst();)d.$.style.backgroundColor&&(d.$.style.backgroundColor=d.$.style.backgroundColor),c.append(d);c.insertAfter(this);\nc.remove(!0)}else e.insertAfterNode(this)},contains:document.compareDocumentPosition?function(a){return!!(this.$.compareDocumentPosition(a.$)&16)}:function(a){var b=this.$;return a.type!=CKEDITOR.NODE_ELEMENT?b.contains(a.getParent().$):b!=a.$&&b.contains(a.$)},focus:function(){function a(){try{this.$.focus()}catch(b){}}return function(b){b?CKEDITOR.tools.setTimeout(a,100,this):a.call(this)}}(),getHtml:function(){var a=this.$.innerHTML;return CKEDITOR.env.ie?a.replace(/<\\?[^>]*>/g,\"\"):a},getOuterHtml:function(){if(this.$.outerHTML)return this.$.outerHTML.replace(/<\\?[^>]*>/,\n\"\");var a=this.$.ownerDocument.createElement(\"div\");a.appendChild(this.$.cloneNode(!0));return a.innerHTML},getClientRect:function(a){var b=CKEDITOR.tools.extend({},this.$.getBoundingClientRect());!b.width&&(b.width=b.right-b.left);!b.height&&(b.height=b.bottom-b.top);return a?CKEDITOR.tools.getAbsoluteRectPosition(this.getWindow(),b):b},setHtml:CKEDITOR.env.ie&&9>CKEDITOR.env.version?function(a){try{var b=this.$;if(this.getParent())return b.innerHTML=a;var c=this.getDocument()._getHtml5ShivFrag();\nc.appendChild(b);b.innerHTML=a;c.removeChild(b);return a}catch(e){this.$.innerHTML=\"\";b=new CKEDITOR.dom.element(\"body\",this.getDocument());b.$.innerHTML=a;for(b=b.getChildren();b.count();)this.append(b.getItem(0));return a}}:function(a){return this.$.innerHTML=a},setText:function(){var a=document.createElement(\"p\");a.innerHTML=\"x\";a=a.textContent;return function(b){this.$[a?\"textContent\":\"innerText\"]=b}}(),getAttribute:function(){var a=function(a){return this.$.getAttribute(a,2)};return CKEDITOR.env.ie&&\n(CKEDITOR.env.ie7Compat||CKEDITOR.env.quirks)?function(a){switch(a){case \"class\":a=\"className\";break;case \"http-equiv\":a=\"httpEquiv\";break;case \"name\":return this.$.name;case \"tabindex\":return a=this.$.getAttribute(a,2),0!==a&&0===this.$.tabIndex&&(a=null),a;case \"checked\":return a=this.$.attributes.getNamedItem(a),(a.specified?a.nodeValue:this.$.checked)?\"checked\":null;case \"hspace\":case \"value\":return this.$[a];case \"style\":return this.$.style.cssText;case \"contenteditable\":case \"contentEditable\":return this.$.attributes.getNamedItem(\"contentEditable\").specified?\nthis.$.getAttribute(\"contentEditable\"):null}return this.$.getAttribute(a,2)}:a}(),getAttributes:function(a){var b={},c=this.$.attributes,e;a=CKEDITOR.tools.isArray(a)?a:[];for(e=0;e<c.length;e++)-1===CKEDITOR.tools.indexOf(a,c[e].name)&&(b[c[e].name]=c[e].value);return b},getChildren:function(){return new CKEDITOR.dom.nodeList(this.$.childNodes)},getComputedStyle:document.defaultView&&document.defaultView.getComputedStyle?function(a){var b=this.getWindow().$.getComputedStyle(this.$,null);return b?\nb.getPropertyValue(a):\"\"}:function(a){return this.$.currentStyle[CKEDITOR.tools.cssStyleToDomStyle(a)]},getDtd:function(){var a=CKEDITOR.dtd[this.getName()];this.getDtd=function(){return a};return a},getElementsByTag:CKEDITOR.dom.document.prototype.getElementsByTag,getTabIndex:function(){var a=this.$.tabIndex;return 0!==a||CKEDITOR.dtd.$tabIndex[this.getName()]||0===parseInt(this.getAttribute(\"tabindex\"),10)?a:-1},getText:function(){return this.$.textContent||this.$.innerText||\"\"},getWindow:function(){return this.getDocument().getWindow()},\ngetId:function(){return this.$.id||null},getNameAtt:function(){return this.$.name||null},getName:function(){var a=this.$.nodeName.toLowerCase();if(CKEDITOR.env.ie&&8>=document.documentMode){var b=this.$.scopeName;\"HTML\"!=b&&(a=b.toLowerCase()+\":\"+a)}this.getName=function(){return a};return this.getName()},getValue:function(){return this.$.value},getFirst:function(a){var b=this.$.firstChild;(b=b&&new CKEDITOR.dom.node(b))&&a&&!a(b)&&(b=b.getNext(a));return b},getLast:function(a){var b=this.$.lastChild;\n(b=b&&new CKEDITOR.dom.node(b))&&a&&!a(b)&&(b=b.getPrevious(a));return b},getStyle:function(a){return this.$.style[CKEDITOR.tools.cssStyleToDomStyle(a)]},is:function(){var a=this.getName();if(\"object\"==typeof arguments[0])return!!arguments[0][a];for(var b=0;b<arguments.length;b++)if(arguments[b]==a)return!0;return!1},isEditable:function(a){var b=this.getName();return this.isReadOnly()||\"none\"==this.getComputedStyle(\"display\")||\"hidden\"==this.getComputedStyle(\"visibility\")||CKEDITOR.dtd.$nonEditable[b]||\nCKEDITOR.dtd.$empty[b]||this.is(\"a\")&&(this.data(\"cke-saved-name\")||this.hasAttribute(\"name\"))&&!this.getChildCount()?!1:!1!==a?(a=CKEDITOR.dtd[b]||CKEDITOR.dtd.span,!(!a||!a[\"#\"])):!0},isIdentical:function(a){var b=this.clone(0,1);a=a.clone(0,1);b.removeAttributes([\"_moz_dirty\",\"data-cke-expando\",\"data-cke-saved-href\",\"data-cke-saved-name\"]);a.removeAttributes([\"_moz_dirty\",\"data-cke-expando\",\"data-cke-saved-href\",\"data-cke-saved-name\"]);if(b.$.isEqualNode)return b.$.style.cssText=CKEDITOR.tools.normalizeCssText(b.$.style.cssText),\na.$.style.cssText=CKEDITOR.tools.normalizeCssText(a.$.style.cssText),b.$.isEqualNode(a.$);b=b.getOuterHtml();a=a.getOuterHtml();if(CKEDITOR.env.ie&&9>CKEDITOR.env.version&&this.is(\"a\")){var c=this.getParent();c.type==CKEDITOR.NODE_ELEMENT&&(c=c.clone(),c.setHtml(b),b=c.getHtml(),c.setHtml(a),a=c.getHtml())}return b==a},isVisible:function(){var a=(this.$.offsetHeight||this.$.offsetWidth)&&\"hidden\"!=this.getComputedStyle(\"visibility\"),b,c;a&&CKEDITOR.env.webkit&&(b=this.getWindow(),!b.equals(CKEDITOR.document.getWindow())&&\n(c=b.$.frameElement)&&(a=(new CKEDITOR.dom.element(c)).isVisible()));return!!a},isEmptyInlineRemoveable:function(){if(!CKEDITOR.dtd.$removeEmpty[this.getName()])return!1;for(var a=this.getChildren(),b=0,c=a.count();b<c;b++){var e=a.getItem(b);if(e.type!=CKEDITOR.NODE_ELEMENT||!e.data(\"cke-bookmark\"))if(e.type==CKEDITOR.NODE_ELEMENT&&!e.isEmptyInlineRemoveable()||e.type==CKEDITOR.NODE_TEXT&&CKEDITOR.tools.trim(e.getText()))return!1}return!0},hasAttributes:CKEDITOR.env.ie&&(CKEDITOR.env.ie7Compat||\nCKEDITOR.env.quirks)?function(){for(var a=this.$.attributes,b=0;b<a.length;b++){var c=a[b];switch(c.nodeName){case \"class\":if(this.getAttribute(\"class\"))return!0;case \"data-cke-expando\":continue;default:if(c.specified)return!0}}return!1}:function(){var a=this.$.attributes,b=a.length,c={\"data-cke-expando\":1,_moz_dirty:1};return 0<b&&(2<b||!c[a[0].nodeName]||2==b&&!c[a[1].nodeName])},hasAttribute:function(){function a(b){var g=this.$.attributes.getNamedItem(b);if(\"input\"==this.getName())switch(b){case \"class\":return 0<\nthis.$.className.length;case \"checked\":return!!this.$.checked;case \"value\":return b=this.getAttribute(\"type\"),\"checkbox\"==b||\"radio\"==b?\"on\"!=this.$.value:!!this.$.value}return g?g.specified:!1}return CKEDITOR.env.ie?8>CKEDITOR.env.version?function(b){return\"name\"==b?!!this.$.name:a.call(this,b)}:a:function(a){return!!this.$.attributes.getNamedItem(a)}}(),hide:function(){this.setStyle(\"display\",\"none\")},moveChildren:function(a,b){var c=this.$;a=a.$;if(c!=a){var e;if(b)for(;e=c.lastChild;)a.insertBefore(c.removeChild(e),\na.firstChild);else for(;e=c.firstChild;)a.appendChild(c.removeChild(e))}},mergeSiblings:function(){function a(b,g,e){if(g&&g.type==CKEDITOR.NODE_ELEMENT){for(var c=[];g.data(\"cke-bookmark\")||g.isEmptyInlineRemoveable();)if(c.push(g),g=e?g.getNext():g.getPrevious(),!g||g.type!=CKEDITOR.NODE_ELEMENT)return;if(b.isIdentical(g)){for(var d=e?b.getLast():b.getFirst();c.length;)c.shift().move(b,!e);g.moveChildren(b,!e);g.remove();d&&d.type==CKEDITOR.NODE_ELEMENT&&d.mergeSiblings()}}}return function(b){if(!1===\nb||CKEDITOR.dtd.$removeEmpty[this.getName()]||this.is(\"a\"))a(this,this.getNext(),!0),a(this,this.getPrevious())}}(),show:function(){this.setStyles({display:\"\",visibility:\"\"})},setAttribute:function(){var a=function(a,b){this.$.setAttribute(a,b);return this};return CKEDITOR.env.ie&&(CKEDITOR.env.ie7Compat||CKEDITOR.env.quirks)?function(b,c){\"class\"==b?this.$.className=c:\"style\"==b?this.$.style.cssText=c:\"tabindex\"==b?this.$.tabIndex=c:\"checked\"==b?this.$.checked=c:\"contenteditable\"==b?a.call(this,\n\"contentEditable\",c):a.apply(this,arguments);return this}:CKEDITOR.env.ie8Compat&&CKEDITOR.env.secure?function(b,c){if(\"src\"==b&&c.match(/^http:\\/\\//))try{a.apply(this,arguments)}catch(e){}else a.apply(this,arguments);return this}:a}(),setAttributes:function(a){for(var b in a)this.setAttribute(b,a[b]);return this},setValue:function(a){this.$.value=a;return this},removeAttribute:function(){var a=function(a){this.$.removeAttribute(a)};return CKEDITOR.env.ie&&(CKEDITOR.env.ie7Compat||CKEDITOR.env.quirks)?\nfunction(a){\"class\"==a?a=\"className\":\"tabindex\"==a?a=\"tabIndex\":\"contenteditable\"==a&&(a=\"contentEditable\");this.$.removeAttribute(a)}:a}(),removeAttributes:function(a){if(CKEDITOR.tools.isArray(a))for(var b=0;b<a.length;b++)this.removeAttribute(a[b]);else for(b in a=a||this.getAttributes(),a)a.hasOwnProperty(b)&&this.removeAttribute(b)},removeStyle:function(a){var b=this.$.style;if(b.removeProperty||\"border\"!=a&&\"margin\"!=a&&\"padding\"!=a)b.removeProperty?b.removeProperty(a):b.removeAttribute(CKEDITOR.tools.cssStyleToDomStyle(a)),\nthis.$.style.cssText||this.removeAttribute(\"style\");else{var c=[\"top\",\"left\",\"right\",\"bottom\"],e;\"border\"==a&&(e=[\"color\",\"style\",\"width\"]);for(var b=[],d=0;d<c.length;d++)if(e)for(var f=0;f<e.length;f++)b.push([a,c[d],e[f]].join(\"-\"));else b.push([a,c[d]].join(\"-\"));for(a=0;a<b.length;a++)this.removeStyle(b[a])}},setStyle:function(a,b){this.$.style[CKEDITOR.tools.cssStyleToDomStyle(a)]=b;return this},setStyles:function(a){for(var b in a)this.setStyle(b,a[b]);return this},setOpacity:function(a){CKEDITOR.env.ie&&\n9>CKEDITOR.env.version?(a=Math.round(100*a),this.setStyle(\"filter\",100<=a?\"\":\"progid:DXImageTransform.Microsoft.Alpha(opacity\\x3d\"+a+\")\")):this.setStyle(\"opacity\",a)},unselectable:function(){this.setStyles(CKEDITOR.tools.cssVendorPrefix(\"user-select\",\"none\"));if(CKEDITOR.env.ie){this.setAttribute(\"unselectable\",\"on\");for(var a,b=this.getElementsByTag(\"*\"),c=0,e=b.count();c<e;c++)a=b.getItem(c),a.setAttribute(\"unselectable\",\"on\")}},getPositionedAncestor:function(){for(var a=this;\"html\"!=a.getName();){if(\"static\"!=\na.getComputedStyle(\"position\"))return a;a=a.getParent()}return null},getDocumentPosition:function(a){var b=0,c=0,e=this.getDocument(),d=e.getBody(),f=\"BackCompat\"==e.$.compatMode;if(document.documentElement.getBoundingClientRect&&(CKEDITOR.env.ie?8!==CKEDITOR.env.version:1)){var l=this.$.getBoundingClientRect(),k=e.$.documentElement,p=k.clientTop||d.$.clientTop||0,v=k.clientLeft||d.$.clientLeft||0,w=!0;CKEDITOR.env.ie&&(w=e.getDocumentElement().contains(this),e=e.getBody().contains(this),w=f&&e||\n!f&&w);w&&(CKEDITOR.env.webkit||CKEDITOR.env.ie&&12<=CKEDITOR.env.version?(b=d.$.scrollLeft||k.scrollLeft,c=d.$.scrollTop||k.scrollTop):(c=f?d.$:k,b=c.scrollLeft,c=c.scrollTop),b=l.left+b-v,c=l.top+c-p)}else for(p=this,v=null;p&&\"body\"!=p.getName()&&\"html\"!=p.getName();){b+=p.$.offsetLeft-p.$.scrollLeft;c+=p.$.offsetTop-p.$.scrollTop;p.equals(this)||(b+=p.$.clientLeft||0,c+=p.$.clientTop||0);for(;v&&!v.equals(p);)b-=v.$.scrollLeft,c-=v.$.scrollTop,v=v.getParent();v=p;p=(l=p.$.offsetParent)?new CKEDITOR.dom.element(l):\nnull}a&&(l=this.getWindow(),p=a.getWindow(),!l.equals(p)&&l.$.frameElement&&(a=(new CKEDITOR.dom.element(l.$.frameElement)).getDocumentPosition(a),b+=a.x,c+=a.y));document.documentElement.getBoundingClientRect||!CKEDITOR.env.gecko||f||(b+=this.$.clientLeft?1:0,c+=this.$.clientTop?1:0);return{x:b,y:c}},scrollIntoView:function(a){var b=this.getParent();if(b){do if((b.$.clientWidth&&b.$.clientWidth<b.$.scrollWidth||b.$.clientHeight&&b.$.clientHeight<b.$.scrollHeight)&&!b.is(\"body\")&&this.scrollIntoParent(b,\na,1),b.is(\"html\")){var c=b.getWindow();try{var e=c.$.frameElement;e&&(b=new CKEDITOR.dom.element(e))}catch(d){}}while(b=b.getParent())}},scrollIntoParent:function(a,b,c){var e,d,f,l;function k(e,b){/body|html/.test(a.getName())?a.getWindow().$.scrollBy(e,b):(a.$.scrollLeft+=e,a.$.scrollTop+=b)}function p(a,e){var b={x:0,y:0};if(!a.is(w?\"body\":\"html\")){var c=a.$.getBoundingClientRect();b.x=c.left;b.y=c.top}c=a.getWindow();c.equals(e)||(c=p(CKEDITOR.dom.element.get(c.$.frameElement),e),b.x+=c.x,b.y+=\nc.y);return b}function v(a,b){return parseInt(a.getComputedStyle(\"margin-\"+b)||0,10)||0}!a&&(a=this.getWindow());f=a.getDocument();var w=\"BackCompat\"==f.$.compatMode;a instanceof CKEDITOR.dom.window&&(a=w?f.getBody():f.getDocumentElement());CKEDITOR.env.webkit&&(f=this.getEditor(!1))&&(f._.previousScrollTop=null);f=a.getWindow();d=p(this,f);var r=p(a,f),z=this.$.offsetHeight;e=this.$.offsetWidth;var t=a.$.clientHeight,x=a.$.clientWidth;f=d.x-v(this,\"left\")-r.x||0;l=d.y-v(this,\"top\")-r.y||0;e=d.x+\ne+v(this,\"right\")-(r.x+x)||0;d=d.y+z+v(this,\"bottom\")-(r.y+t)||0;(0>l||0<d)&&k(0,!0===b?l:!1===b?d:0>l?l:d);c&&(0>f||0<e)&&k(0>f?f:e,0)},setState:function(a,b,c){b=b||\"cke\";switch(a){case CKEDITOR.TRISTATE_ON:this.addClass(b+\"_on\");this.removeClass(b+\"_off\");this.removeClass(b+\"_disabled\");c&&this.setAttribute(\"aria-pressed\",!0);c&&this.removeAttribute(\"aria-disabled\");break;case CKEDITOR.TRISTATE_DISABLED:this.addClass(b+\"_disabled\");this.removeClass(b+\"_off\");this.removeClass(b+\"_on\");c&&this.setAttribute(\"aria-disabled\",\n!0);c&&this.removeAttribute(\"aria-pressed\");break;default:this.addClass(b+\"_off\"),this.removeClass(b+\"_on\"),this.removeClass(b+\"_disabled\"),c&&this.removeAttribute(\"aria-pressed\"),c&&this.removeAttribute(\"aria-disabled\")}},getFrameDocument:function(){var a=this.$;try{a.contentWindow.document}catch(b){a.src=a.src}return a&&new CKEDITOR.dom.document(a.contentWindow.document)},copyAttributes:function(a,b){var c=this.$.attributes;b=b||{};for(var e=0;e<c.length;e++){var d=c[e],f=d.nodeName.toLowerCase(),\nl;if(!(f in b))if(\"checked\"==f&&(l=this.getAttribute(f)))a.setAttribute(f,l);else if(!CKEDITOR.env.ie||this.hasAttribute(f))l=this.getAttribute(f),null===l&&(l=d.nodeValue),a.setAttribute(f,l)}\"\"!==this.$.style.cssText&&(a.$.style.cssText=this.$.style.cssText)},renameNode:function(a){if(this.getName()!=a){var b=this.getDocument();a=new CKEDITOR.dom.element(a,b);this.copyAttributes(a);this.moveChildren(a);this.getParent(!0)&&this.$.parentNode.replaceChild(a.$,this.$);a.$[\"data-cke-expando\"]=this.$[\"data-cke-expando\"];\nthis.$=a.$;delete this.getName}},getChild:function(){function a(b,c){var e=b.childNodes;if(0<=c&&c<e.length)return e[c]}return function(b){var c=this.$;if(b.slice)for(b=b.slice();0<b.length&&c;)c=a(c,b.shift());else c=a(c,b);return c?new CKEDITOR.dom.node(c):null}}(),getChildCount:function(){return this.$.childNodes.length},disableContextMenu:function(){function a(b){return b.type==CKEDITOR.NODE_ELEMENT&&b.hasClass(\"cke_enable_context_menu\")}this.on(\"contextmenu\",function(b){b.data.getTarget().getAscendant(a,\n!0)||b.data.preventDefault()})},getDirection:function(a){return a?this.getComputedStyle(\"direction\")||this.getDirection()||this.getParent()&&this.getParent().getDirection(1)||this.getDocument().$.dir||\"ltr\":this.getStyle(\"direction\")||this.getAttribute(\"dir\")},data:function(a,b){a=\"data-\"+a;if(void 0===b)return this.getAttribute(a);!1===b?this.removeAttribute(a):this.setAttribute(a,b);return null},getEditor:function(a){var b=CKEDITOR.instances,c,e,d;a=a||void 0===a;for(c in b)if(e=b[c],e.element.equals(this)&&\ne.elementMode!=CKEDITOR.ELEMENT_MODE_APPENDTO||!a&&(d=e.editable())&&(d.equals(this)||d.contains(this)))return e;return null},find:function(a){var c=f(this);a=new CKEDITOR.dom.nodeList(this.$.querySelectorAll(b(this,a)));c();return a},findOne:function(a){var c=f(this);a=this.$.querySelector(b(this,a));c();return a?new CKEDITOR.dom.element(a):null},forEach:function(a,b,c){if(!(c||b&&this.type!=b))var e=a(this);if(!1!==e){c=this.getChildren();for(var d=0;d<c.count();d++)e=c.getItem(d),e.type==CKEDITOR.NODE_ELEMENT?\ne.forEach(a,b):b&&e.type!=b||a(e)}}});var k={width:[\"border-left-width\",\"border-right-width\",\"padding-left\",\"padding-right\"],height:[\"border-top-width\",\"border-bottom-width\",\"padding-top\",\"padding-bottom\"]};CKEDITOR.dom.element.prototype.setSize=function(a,b,d){\"number\"==typeof b&&(!d||CKEDITOR.env.ie&&CKEDITOR.env.quirks||(b-=c.call(this,a)),this.setStyle(a,b+\"px\"))};CKEDITOR.dom.element.prototype.getSize=function(a,b){var d=Math.max(this.$[\"offset\"+CKEDITOR.tools.capitalize(a)],this.$[\"client\"+\nCKEDITOR.tools.capitalize(a)])||0;b&&(d-=c.call(this,a));return d}}(),CKEDITOR.dom.documentFragment=function(a){a=a||CKEDITOR.document;this.$=a.type==CKEDITOR.NODE_DOCUMENT?a.$.createDocumentFragment():a},CKEDITOR.tools.extend(CKEDITOR.dom.documentFragment.prototype,CKEDITOR.dom.element.prototype,{type:CKEDITOR.NODE_DOCUMENT_FRAGMENT,insertAfterNode:function(a){a=a.$;a.parentNode.insertBefore(this.$,a.nextSibling)},getHtml:function(){var a=new CKEDITOR.dom.element(\"div\");this.clone(1,1).appendTo(a);\nreturn a.getHtml().replace(/\\s*data-cke-expando=\".*?\"/g,\"\")}},!0,{append:1,appendBogus:1,clone:1,getFirst:1,getHtml:1,getLast:1,getParent:1,getNext:1,getPrevious:1,appendTo:1,moveChildren:1,insertBefore:1,insertAfterNode:1,replace:1,trim:1,type:1,ltrim:1,rtrim:1,getDocument:1,getChildCount:1,getChild:1,getChildren:1}),CKEDITOR.tools.extend(CKEDITOR.dom.documentFragment.prototype,CKEDITOR.dom.document.prototype,!0,{find:1,findOne:1}),function(){function a(a,b){var e=this.range;if(this._.end)return null;\nif(!this._.start){this._.start=1;if(e.collapsed)return this.end(),null;e.optimize()}var c,d=e.startContainer;c=e.endContainer;var g=e.startOffset,h=e.endOffset,n,f=this.guard,m=this.type,l=a?\"getPreviousSourceNode\":\"getNextSourceNode\";if(!a&&!this._.guardLTR){var k=c.type==CKEDITOR.NODE_ELEMENT?c:c.getParent(),C=c.type==CKEDITOR.NODE_ELEMENT?c.getChild(h):c.getNext();this._.guardLTR=function(a,b){return(!b||!k.equals(a))&&(!C||!a.equals(C))&&(a.type!=CKEDITOR.NODE_ELEMENT||!b||!a.equals(e.root))}}if(a&&\n!this._.guardRTL){var H=d.type==CKEDITOR.NODE_ELEMENT?d:d.getParent(),F=d.type==CKEDITOR.NODE_ELEMENT?g?d.getChild(g-1):null:d.getPrevious();this._.guardRTL=function(a,b){return(!b||!H.equals(a))&&(!F||!a.equals(F))&&(a.type!=CKEDITOR.NODE_ELEMENT||!b||!a.equals(e.root))}}var I=a?this._.guardRTL:this._.guardLTR;n=f?function(a,b){return!1===I(a,b)?!1:f(a,b)}:I;this.current?c=this.current[l](!1,m,n):(a?c.type==CKEDITOR.NODE_ELEMENT&&(c=0<h?c.getChild(h-1):!1===n(c,!0)?null:c.getPreviousSourceNode(!0,\nm,n)):(c=d,c.type==CKEDITOR.NODE_ELEMENT&&((c=c.getChild(g))||(c=!1===n(d,!0)?null:d.getNextSourceNode(!0,m,n)))),c&&!1===n(c)&&(c=null));for(;c&&!this._.end;){this.current=c;if(!this.evaluator||!1!==this.evaluator(c)){if(!b)return c}else if(b&&this.evaluator)return!1;c=c[l](!1,m,n)}this.end();return this.current=null}function f(b){for(var e,c=null;e=a.call(this,b);)c=e;return c}CKEDITOR.dom.walker=CKEDITOR.tools.createClass({$:function(a){this.range=a;this._={}},proto:{end:function(){this._.end=\n1},next:function(){return a.call(this)},previous:function(){return a.call(this,1)},checkForward:function(){return!1!==a.call(this,0,1)},checkBackward:function(){return!1!==a.call(this,1,1)},lastForward:function(){return f.call(this)},lastBackward:function(){return f.call(this,1)},reset:function(){delete this.current;this._={}}}});var b={block:1,\"list-item\":1,table:1,\"table-row-group\":1,\"table-header-group\":1,\"table-footer-group\":1,\"table-row\":1,\"table-column-group\":1,\"table-column\":1,\"table-cell\":1,\n\"table-caption\":1},c={absolute:1,fixed:1};CKEDITOR.dom.element.prototype.isBlockBoundary=function(a){return\"none\"!=this.getComputedStyle(\"float\")||this.getComputedStyle(\"position\")in c||!b[this.getComputedStyle(\"display\")]?!!(this.is(CKEDITOR.dtd.$block)||a&&this.is(a)):!0};CKEDITOR.dom.walker.blockBoundary=function(a){return function(b){return!(b.type==CKEDITOR.NODE_ELEMENT&&b.isBlockBoundary(a))}};CKEDITOR.dom.walker.listItemBoundary=function(){return this.blockBoundary({br:1})};CKEDITOR.dom.walker.bookmark=\nfunction(a,b){function e(a){return a&&a.getName&&\"span\"==a.getName()&&a.data(\"cke-bookmark\")}return function(c){var d,g;d=c&&c.type!=CKEDITOR.NODE_ELEMENT&&(g=c.getParent())&&e(g);d=a?d:d||e(c);return!!(b^d)}};CKEDITOR.dom.walker.whitespaces=function(a){return function(b){var e;b&&b.type==CKEDITOR.NODE_TEXT&&(e=!CKEDITOR.tools.trim(b.getText())||CKEDITOR.env.webkit&&b.getText()==CKEDITOR.dom.selection.FILLING_CHAR_SEQUENCE);return!!(a^e)}};CKEDITOR.dom.walker.invisible=function(a){var b=CKEDITOR.dom.walker.whitespaces(),\ne=CKEDITOR.env.webkit?1:0;return function(c){b(c)?c=1:(c.type==CKEDITOR.NODE_TEXT&&(c=c.getParent()),c=c.$.offsetWidth<=e);return!!(a^c)}};CKEDITOR.dom.walker.nodeType=function(a,b){return function(e){return!!(b^e.type==a)}};CKEDITOR.dom.walker.bogus=function(a){function b(a){return!l(a)&&!k(a)}return function(e){var c=CKEDITOR.env.needsBrFiller?e.is&&e.is(\"br\"):e.getText&&d.test(e.getText());c&&(c=e.getParent(),e=e.getNext(b),c=c.isBlockBoundary()&&(!e||e.type==CKEDITOR.NODE_ELEMENT&&e.isBlockBoundary()));\nreturn!!(a^c)}};CKEDITOR.dom.walker.temp=function(a){return function(b){b.type!=CKEDITOR.NODE_ELEMENT&&(b=b.getParent());b=b&&b.hasAttribute(\"data-cke-temp\");return!!(a^b)}};var d=/^[\\t\\r\\n ]*(?:&nbsp;|\\xa0)$/,l=CKEDITOR.dom.walker.whitespaces(),k=CKEDITOR.dom.walker.bookmark(),g=CKEDITOR.dom.walker.temp(),h=function(a){return k(a)||l(a)||a.type==CKEDITOR.NODE_ELEMENT&&a.is(CKEDITOR.dtd.$inline)&&!a.is(CKEDITOR.dtd.$empty)};CKEDITOR.dom.walker.ignored=function(a){return function(b){b=l(b)||k(b)||\ng(b);return!!(a^b)}};var m=CKEDITOR.dom.walker.ignored();CKEDITOR.dom.walker.empty=function(a){return function(b){for(var e=0,c=b.getChildCount();e<c;++e)if(!m(b.getChild(e)))return!!a;return!a}};var e=CKEDITOR.dom.walker.empty(),n=CKEDITOR.dom.walker.validEmptyBlockContainers=CKEDITOR.tools.extend(function(a){var b={},e;for(e in a)CKEDITOR.dtd[e][\"#\"]&&(b[e]=1);return b}(CKEDITOR.dtd.$block),{caption:1,td:1,th:1});CKEDITOR.dom.walker.editable=function(a){return function(b){b=m(b)?!1:b.type==CKEDITOR.NODE_TEXT||\nb.type==CKEDITOR.NODE_ELEMENT&&(b.is(CKEDITOR.dtd.$inline)||b.is(\"hr\")||\"false\"==b.getAttribute(\"contenteditable\")||!CKEDITOR.env.needsBrFiller&&b.is(n)&&e(b))?!0:!1;return!!(a^b)}};CKEDITOR.dom.element.prototype.getBogus=function(){var a=this;do a=a.getPreviousSourceNode();while(h(a));return a&&(CKEDITOR.env.needsBrFiller?a.is&&a.is(\"br\"):a.getText&&d.test(a.getText()))?a:!1}}(),CKEDITOR.dom.range=function(a){this.endOffset=this.endContainer=this.startOffset=this.startContainer=null;this.collapsed=\n!0;var f=a instanceof CKEDITOR.dom.document;this.document=f?a:a.getDocument();this.root=f?a.getBody():a},function(){function a(a){a.collapsed=a.startContainer&&a.endContainer&&a.startContainer.equals(a.endContainer)&&a.startOffset==a.endOffset}function f(a,b,c,d,g){function h(a,b,e,c){var d=e?a.getPrevious():a.getNext();if(c&&l)return d;t||c?b.append(a.clone(!0,g),e):(a.remove(),k&&b.append(a,e));return d}function f(){var a,b,e,c=Math.min(G.length,D.length);for(a=0;a<c;a++)if(b=G[a],e=D[a],!b.equals(e))return a;\nreturn a-1}function m(){var b=N-1,c=I&&J&&!x.equals(A);b<Q-1||b<O-1||c?(c?a.moveToPosition(A,CKEDITOR.POSITION_BEFORE_START):O==b+1&&F?a.moveToPosition(D[b],CKEDITOR.POSITION_BEFORE_END):a.moveToPosition(D[b+1],CKEDITOR.POSITION_BEFORE_START),d&&(b=G[b+1])&&b.type==CKEDITOR.NODE_ELEMENT&&(c=CKEDITOR.dom.element.createFromHtml('\\x3cspan data-cke-bookmark\\x3d\"1\" style\\x3d\"display:none\"\\x3e\\x26nbsp;\\x3c/span\\x3e',a.document),c.insertAfter(b),b.mergeSiblings(!1),a.moveToBookmark({startNode:c}))):a.collapse(!0)}\na.optimizeBookmark();var l=0===b,k=1==b,t=2==b;b=t||k;var x=a.startContainer,A=a.endContainer,B=a.startOffset,C=a.endOffset,H,F,I,J,E,L;if(t&&A.type==CKEDITOR.NODE_TEXT&&(x.equals(A)||x.type===CKEDITOR.NODE_ELEMENT&&x.getFirst().equals(A)))c.append(a.document.createText(A.substring(B,C)));else{A.type==CKEDITOR.NODE_TEXT?t?L=!0:A=A.split(C):0<A.getChildCount()?C>=A.getChildCount()?(A=A.getChild(C-1),F=!0):A=A.getChild(C):J=F=!0;x.type==CKEDITOR.NODE_TEXT?t?E=!0:x.split(B):0<x.getChildCount()?0===B?\n(x=x.getChild(B),H=!0):x=x.getChild(B-1):I=H=!0;for(var G=x.getParents(),D=A.getParents(),N=f(),Q=G.length-1,O=D.length-1,K=c,W,R,Z,ha=-1,X=N;X<=Q;X++){R=G[X];Z=R.getNext();for(X!=Q||R.equals(D[X])&&Q<O?b&&(W=K.append(R.clone(0,g))):H?h(R,K,!1,I):E&&K.append(a.document.createText(R.substring(B)));Z;){if(Z.equals(D[X])){ha=X;break}Z=h(Z,K)}K=W}K=c;for(X=N;X<=O;X++)if(c=D[X],Z=c.getPrevious(),c.equals(G[X]))b&&(K=K.getChild(0));else{X!=O||c.equals(G[X])&&O<Q?b&&(W=K.append(c.clone(0,g))):F?h(c,K,!1,\nJ):L&&K.append(a.document.createText(c.substring(0,C)));if(X>ha)for(;Z;)Z=h(Z,K,!0);K=W}t||m()}}function b(){var a=!1,b=CKEDITOR.dom.walker.whitespaces(),c=CKEDITOR.dom.walker.bookmark(!0),d=CKEDITOR.dom.walker.bogus();return function(g){return c(g)||b(g)?!0:d(g)&&!a?a=!0:g.type==CKEDITOR.NODE_TEXT&&(g.hasAscendant(\"pre\")||CKEDITOR.tools.trim(g.getText()).length)||g.type==CKEDITOR.NODE_ELEMENT&&!g.is(l)?!1:!0}}function c(a){var b=CKEDITOR.dom.walker.whitespaces(),c=CKEDITOR.dom.walker.bookmark(1);\nreturn function(d){return c(d)||b(d)?!0:!a&&k(d)||d.type==CKEDITOR.NODE_ELEMENT&&d.is(CKEDITOR.dtd.$removeEmpty)}}function d(a){return function(){var b;return this[a?\"getPreviousNode\":\"getNextNode\"](function(a){!b&&m(a)&&(b=a);return h(a)&&!(k(a)&&a.equals(b))})}}var l={abbr:1,acronym:1,b:1,bdo:1,big:1,cite:1,code:1,del:1,dfn:1,em:1,font:1,i:1,ins:1,label:1,kbd:1,q:1,samp:1,small:1,span:1,strike:1,strong:1,sub:1,sup:1,tt:1,u:1,\"var\":1},k=CKEDITOR.dom.walker.bogus(),g=/^[\\t\\r\\n ]*(?:&nbsp;|\\xa0)$/,\nh=CKEDITOR.dom.walker.editable(),m=CKEDITOR.dom.walker.ignored(!0);CKEDITOR.dom.range.prototype={clone:function(){var a=new CKEDITOR.dom.range(this.root);a._setStartContainer(this.startContainer);a.startOffset=this.startOffset;a._setEndContainer(this.endContainer);a.endOffset=this.endOffset;a.collapsed=this.collapsed;return a},collapse:function(a){a?(this._setEndContainer(this.startContainer),this.endOffset=this.startOffset):(this._setStartContainer(this.endContainer),this.startOffset=this.endOffset);\nthis.collapsed=!0},cloneContents:function(a){var b=new CKEDITOR.dom.documentFragment(this.document);this.collapsed||f(this,2,b,!1,\"undefined\"==typeof a?!0:a);return b},deleteContents:function(a){this.collapsed||f(this,0,null,a)},extractContents:function(a,b){var c=new CKEDITOR.dom.documentFragment(this.document);this.collapsed||f(this,1,c,a,\"undefined\"==typeof b?!0:b);return c},createBookmark:function(a){var b,c,d,g,h=this.collapsed;b=this.document.createElement(\"span\");b.data(\"cke-bookmark\",1);b.setStyle(\"display\",\n\"none\");b.setHtml(\"\\x26nbsp;\");a&&(d=\"cke_bm_\"+CKEDITOR.tools.getNextNumber(),b.setAttribute(\"id\",d+(h?\"C\":\"S\")));h||(c=b.clone(),c.setHtml(\"\\x26nbsp;\"),a&&c.setAttribute(\"id\",d+\"E\"),g=this.clone(),g.collapse(),g.insertNode(c));g=this.clone();g.collapse(!0);g.insertNode(b);c?(this.setStartAfter(b),this.setEndBefore(c)):this.moveToPosition(b,CKEDITOR.POSITION_AFTER_END);return{startNode:a?d+(h?\"C\":\"S\"):b,endNode:a?d+\"E\":c,serializable:a,collapsed:h}},createBookmark2:function(){function a(b){var e=\nb.container,d=b.offset,g;g=e;var h=d;g=g.type!=CKEDITOR.NODE_ELEMENT||0===h||h==g.getChildCount()?0:g.getChild(h-1).type==CKEDITOR.NODE_TEXT&&g.getChild(h).type==CKEDITOR.NODE_TEXT;g&&(e=e.getChild(d-1),d=e.getLength());if(e.type==CKEDITOR.NODE_ELEMENT&&0<d){a:{for(g=e;d--;)if(h=g.getChild(d).getIndex(!0),0<=h){d=h;break a}d=-1}d+=1}if(e.type==CKEDITOR.NODE_TEXT){g=e;for(h=0;(g=g.getPrevious())&&g.type==CKEDITOR.NODE_TEXT;)h+=g.getText().replace(CKEDITOR.dom.selection.FILLING_CHAR_SEQUENCE,\"\").length;\ng=h;e.getText()?d+=g:(h=e.getPrevious(c),g?(d=g,e=h?h.getNext():e.getParent().getFirst()):(e=e.getParent(),d=h?h.getIndex(!0)+1:0))}b.container=e;b.offset=d}function b(a,e){var c=e.getCustomData(\"cke-fillingChar\");if(c){var d=a.container;c.equals(d)&&(a.offset-=CKEDITOR.dom.selection.FILLING_CHAR_SEQUENCE.length,0>=a.offset&&(a.offset=d.getIndex(),a.container=d.getParent()))}}var c=CKEDITOR.dom.walker.nodeType(CKEDITOR.NODE_TEXT,!0);return function(c){var d=this.collapsed,g={container:this.startContainer,\noffset:this.startOffset},h={container:this.endContainer,offset:this.endOffset};c&&(a(g),b(g,this.root),d||(a(h),b(h,this.root)));return{start:g.container.getAddress(c),end:d?null:h.container.getAddress(c),startOffset:g.offset,endOffset:h.offset,normalized:c,collapsed:d,is2:!0}}}(),moveToBookmark:function(a){if(a.is2){var b=this.document.getByAddress(a.start,a.normalized),c=a.startOffset,d=a.end&&this.document.getByAddress(a.end,a.normalized);a=a.endOffset;this.setStart(b,c);d?this.setEnd(d,a):this.collapse(!0)}else b=\n(c=a.serializable)?this.document.getById(a.startNode):a.startNode,a=c?this.document.getById(a.endNode):a.endNode,this.setStartBefore(b),b.remove(),a?(this.setEndBefore(a),a.remove()):this.collapse(!0)},getBoundaryNodes:function(){var a=this.startContainer,b=this.endContainer,c=this.startOffset,d=this.endOffset,g;if(a.type==CKEDITOR.NODE_ELEMENT)if(g=a.getChildCount(),g>c)a=a.getChild(c);else if(1>g)a=a.getPreviousSourceNode();else{for(a=a.$;a.lastChild;)a=a.lastChild;a=new CKEDITOR.dom.node(a);a=\na.getNextSourceNode()||a}if(b.type==CKEDITOR.NODE_ELEMENT)if(g=b.getChildCount(),g>d)b=b.getChild(d).getPreviousSourceNode(!0);else if(1>g)b=b.getPreviousSourceNode();else{for(b=b.$;b.lastChild;)b=b.lastChild;b=new CKEDITOR.dom.node(b)}a.getPosition(b)&CKEDITOR.POSITION_FOLLOWING&&(a=b);return{startNode:a,endNode:b}},getCommonAncestor:function(a,b){var c=this.startContainer,d=this.endContainer,c=c.equals(d)?a&&c.type==CKEDITOR.NODE_ELEMENT&&this.startOffset==this.endOffset-1?c.getChild(this.startOffset):\nc:c.getCommonAncestor(d);return b&&!c.is?c.getParent():c},optimize:function(){var a=this.startContainer,b=this.startOffset;a.type!=CKEDITOR.NODE_ELEMENT&&(b?b>=a.getLength()&&this.setStartAfter(a):this.setStartBefore(a));a=this.endContainer;b=this.endOffset;a.type!=CKEDITOR.NODE_ELEMENT&&(b?b>=a.getLength()&&this.setEndAfter(a):this.setEndBefore(a))},optimizeBookmark:function(){var a=this.startContainer,b=this.endContainer;a.is&&a.is(\"span\")&&a.data(\"cke-bookmark\")&&this.setStartAt(a,CKEDITOR.POSITION_BEFORE_START);\nb&&b.is&&b.is(\"span\")&&b.data(\"cke-bookmark\")&&this.setEndAt(b,CKEDITOR.POSITION_AFTER_END)},trim:function(a,b){var c=this.startContainer,d=this.startOffset,g=this.collapsed;if((!a||g)&&c&&c.type==CKEDITOR.NODE_TEXT){if(d)if(d>=c.getLength())d=c.getIndex()+1,c=c.getParent();else{var h=c.split(d),d=c.getIndex()+1,c=c.getParent();this.startContainer.equals(this.endContainer)?this.setEnd(h,this.endOffset-this.startOffset):c.equals(this.endContainer)&&(this.endOffset+=1)}else d=c.getIndex(),c=c.getParent();\nthis.setStart(c,d);if(g){this.collapse(!0);return}}c=this.endContainer;d=this.endOffset;b||g||!c||c.type!=CKEDITOR.NODE_TEXT||(d?(d>=c.getLength()||c.split(d),d=c.getIndex()+1):d=c.getIndex(),c=c.getParent(),this.setEnd(c,d))},enlarge:function(a,b){function c(a){return a&&a.type==CKEDITOR.NODE_ELEMENT&&a.hasAttribute(\"contenteditable\")?null:a}var d=new RegExp(/[^\\s\\ufeff]/);switch(a){case CKEDITOR.ENLARGE_INLINE:var g=1;case CKEDITOR.ENLARGE_ELEMENT:var h=function(a,b){var e=new CKEDITOR.dom.range(m);\ne.setStart(a,b);e.setEndAt(m,CKEDITOR.POSITION_BEFORE_END);var e=new CKEDITOR.dom.walker(e),c;for(e.guard=function(a){return!(a.type==CKEDITOR.NODE_ELEMENT&&a.isBlockBoundary())};c=e.next();){if(c.type!=CKEDITOR.NODE_TEXT)return!1;H=c!=a?c.getText():c.substring(b);if(d.test(H))return!1}return!0};if(this.collapsed)break;var f=this.getCommonAncestor(),m=this.root,l,k,t,x,A,B=!1,C,H;C=this.startContainer;var F=this.startOffset;C.type==CKEDITOR.NODE_TEXT?(F&&(C=!CKEDITOR.tools.trim(C.substring(0,F)).length&&\nC,B=!!C),C&&((x=C.getPrevious())||(t=C.getParent()))):(F&&(x=C.getChild(F-1)||C.getLast()),x||(t=C));for(t=c(t);t||x;){if(t&&!x){!A&&t.equals(f)&&(A=!0);if(g?t.isBlockBoundary():!m.contains(t))break;B&&\"inline\"==t.getComputedStyle(\"display\")||(B=!1,A?l=t:this.setStartBefore(t));x=t.getPrevious()}for(;x;)if(C=!1,x.type==CKEDITOR.NODE_COMMENT)x=x.getPrevious();else{if(x.type==CKEDITOR.NODE_TEXT)H=x.getText(),d.test(H)&&(x=null),C=/[\\s\\ufeff]$/.test(H);else if((x.$.offsetWidth>(CKEDITOR.env.webkit?1:\n0)||b&&x.is(\"br\"))&&!x.data(\"cke-bookmark\"))if(B&&CKEDITOR.dtd.$removeEmpty[x.getName()]){H=x.getText();if(d.test(H))x=null;else for(var F=x.$.getElementsByTagName(\"*\"),I=0,J;J=F[I++];)if(!CKEDITOR.dtd.$removeEmpty[J.nodeName.toLowerCase()]){x=null;break}x&&(C=!!H.length)}else x=null;C&&(B?A?l=t:t&&this.setStartBefore(t):B=!0);if(x){C=x.getPrevious();if(!t&&!C){t=x;x=null;break}x=C}else t=null}t&&(t=c(t.getParent()))}C=this.endContainer;F=this.endOffset;t=x=null;A=B=!1;C.type==CKEDITOR.NODE_TEXT?\nCKEDITOR.tools.trim(C.substring(F)).length?B=!0:(B=!C.getLength(),F==C.getLength()?(x=C.getNext())||(t=C.getParent()):h(C,F)&&(t=C.getParent())):(x=C.getChild(F))||(t=C);for(;t||x;){if(t&&!x){!A&&t.equals(f)&&(A=!0);if(g?t.isBlockBoundary():!m.contains(t))break;B&&\"inline\"==t.getComputedStyle(\"display\")||(B=!1,A?k=t:t&&this.setEndAfter(t));x=t.getNext()}for(;x;){C=!1;if(x.type==CKEDITOR.NODE_TEXT)H=x.getText(),h(x,0)||(x=null),C=/^[\\s\\ufeff]/.test(H);else if(x.type==CKEDITOR.NODE_ELEMENT){if((0<x.$.offsetWidth||\nb&&x.is(\"br\"))&&!x.data(\"cke-bookmark\"))if(B&&CKEDITOR.dtd.$removeEmpty[x.getName()]){H=x.getText();if(d.test(H))x=null;else for(F=x.$.getElementsByTagName(\"*\"),I=0;J=F[I++];)if(!CKEDITOR.dtd.$removeEmpty[J.nodeName.toLowerCase()]){x=null;break}x&&(C=!!H.length)}else x=null}else C=1;C&&B&&(A?k=t:this.setEndAfter(t));if(x){C=x.getNext();if(!t&&!C){t=x;x=null;break}x=C}else t=null}t&&(t=c(t.getParent()))}l&&k&&(f=l.contains(k)?k:l,this.setStartBefore(f),this.setEndAfter(f));break;case CKEDITOR.ENLARGE_BLOCK_CONTENTS:case CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS:t=\nnew CKEDITOR.dom.range(this.root);m=this.root;t.setStartAt(m,CKEDITOR.POSITION_AFTER_START);t.setEnd(this.startContainer,this.startOffset);t=new CKEDITOR.dom.walker(t);var E,L,G=CKEDITOR.dom.walker.blockBoundary(a==CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS?{br:1}:null),D=null,N=function(a){if(a.type==CKEDITOR.NODE_ELEMENT&&\"false\"==a.getAttribute(\"contenteditable\"))if(D){if(D.equals(a)){D=null;return}}else D=a;else if(D)return;var b=G(a);b||(E=a);return b},g=function(a){var b=N(a);!b&&a.is&&a.is(\"br\")&&\n(L=a);return b};t.guard=N;t=t.lastBackward();E=E||m;this.setStartAt(E,!E.is(\"br\")&&(!t&&this.checkStartOfBlock()||t&&E.contains(t))?CKEDITOR.POSITION_AFTER_START:CKEDITOR.POSITION_AFTER_END);if(a==CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS){t=this.clone();t=new CKEDITOR.dom.walker(t);var Q=CKEDITOR.dom.walker.whitespaces(),O=CKEDITOR.dom.walker.bookmark();t.evaluator=function(a){return!Q(a)&&!O(a)};if((t=t.previous())&&t.type==CKEDITOR.NODE_ELEMENT&&t.is(\"br\"))break}t=this.clone();t.collapse();t.setEndAt(m,\nCKEDITOR.POSITION_BEFORE_END);t=new CKEDITOR.dom.walker(t);t.guard=a==CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS?g:N;E=D=L=null;t=t.lastForward();E=E||m;this.setEndAt(E,!t&&this.checkEndOfBlock()||t&&E.contains(t)?CKEDITOR.POSITION_BEFORE_END:CKEDITOR.POSITION_BEFORE_START);L&&this.setEndAfter(L)}},shrink:function(a,b,c){var d=\"boolean\"===typeof c?c:c&&\"boolean\"===typeof c.shrinkOnBlockBoundary?c.shrinkOnBlockBoundary:!0,g=c&&c.skipBogus;if(!this.collapsed){a=a||CKEDITOR.SHRINK_TEXT;var h=this.clone(),f=\nthis.startContainer,m=this.endContainer,l=this.startOffset,k=this.endOffset,t=c=1;f&&f.type==CKEDITOR.NODE_TEXT&&(l?l>=f.getLength()?h.setStartAfter(f):(h.setStartBefore(f),c=0):h.setStartBefore(f));m&&m.type==CKEDITOR.NODE_TEXT&&(k?k>=m.getLength()?h.setEndAfter(m):(h.setEndAfter(m),t=0):h.setEndBefore(m));var h=new CKEDITOR.dom.walker(h),x=CKEDITOR.dom.walker.bookmark(),A=CKEDITOR.dom.walker.bogus();h.evaluator=function(b){return b.type==(a==CKEDITOR.SHRINK_ELEMENT?CKEDITOR.NODE_ELEMENT:CKEDITOR.NODE_TEXT)};\nvar B;h.guard=function(b,c){if(g&&A(b)||x(b))return!0;if(a==CKEDITOR.SHRINK_ELEMENT&&b.type==CKEDITOR.NODE_TEXT||c&&b.equals(B)||!1===d&&b.type==CKEDITOR.NODE_ELEMENT&&b.isBlockBoundary()||b.type==CKEDITOR.NODE_ELEMENT&&b.hasAttribute(\"contenteditable\"))return!1;c||b.type!=CKEDITOR.NODE_ELEMENT||(B=b);return!0};c&&(f=h[a==CKEDITOR.SHRINK_ELEMENT?\"lastForward\":\"next\"]())&&this.setStartAt(f,b?CKEDITOR.POSITION_AFTER_START:CKEDITOR.POSITION_BEFORE_START);t&&(h.reset(),(h=h[a==CKEDITOR.SHRINK_ELEMENT?\n\"lastBackward\":\"previous\"]())&&this.setEndAt(h,b?CKEDITOR.POSITION_BEFORE_END:CKEDITOR.POSITION_AFTER_END));return!(!c&&!t)}},insertNode:function(a){this.optimizeBookmark();this.trim(!1,!0);var b=this.startContainer,c=b.getChild(this.startOffset);c?a.insertBefore(c):b.append(a);a.getParent()&&a.getParent().equals(this.endContainer)&&this.endOffset++;this.setStartBefore(a)},moveToPosition:function(a,b){this.setStartAt(a,b);this.collapse(!0)},moveToRange:function(a){this.setStart(a.startContainer,a.startOffset);\nthis.setEnd(a.endContainer,a.endOffset)},selectNodeContents:function(a){this.setStart(a,0);this.setEnd(a,a.type==CKEDITOR.NODE_TEXT?a.getLength():a.getChildCount())},setStart:function(b,c){b.type==CKEDITOR.NODE_ELEMENT&&CKEDITOR.dtd.$empty[b.getName()]&&(c=b.getIndex(),b=b.getParent());this._setStartContainer(b);this.startOffset=c;this.endContainer||(this._setEndContainer(b),this.endOffset=c);a(this)},setEnd:function(b,c){b.type==CKEDITOR.NODE_ELEMENT&&CKEDITOR.dtd.$empty[b.getName()]&&(c=b.getIndex()+\n1,b=b.getParent());this._setEndContainer(b);this.endOffset=c;this.startContainer||(this._setStartContainer(b),this.startOffset=c);a(this)},setStartAfter:function(a){this.setStart(a.getParent(),a.getIndex()+1)},setStartBefore:function(a){this.setStart(a.getParent(),a.getIndex())},setEndAfter:function(a){this.setEnd(a.getParent(),a.getIndex()+1)},setEndBefore:function(a){this.setEnd(a.getParent(),a.getIndex())},setStartAt:function(b,c){switch(c){case CKEDITOR.POSITION_AFTER_START:this.setStart(b,0);\nbreak;case CKEDITOR.POSITION_BEFORE_END:b.type==CKEDITOR.NODE_TEXT?this.setStart(b,b.getLength()):this.setStart(b,b.getChildCount());break;case CKEDITOR.POSITION_BEFORE_START:this.setStartBefore(b);break;case CKEDITOR.POSITION_AFTER_END:this.setStartAfter(b)}a(this)},setEndAt:function(b,c){switch(c){case CKEDITOR.POSITION_AFTER_START:this.setEnd(b,0);break;case CKEDITOR.POSITION_BEFORE_END:b.type==CKEDITOR.NODE_TEXT?this.setEnd(b,b.getLength()):this.setEnd(b,b.getChildCount());break;case CKEDITOR.POSITION_BEFORE_START:this.setEndBefore(b);\nbreak;case CKEDITOR.POSITION_AFTER_END:this.setEndAfter(b)}a(this)},fixBlock:function(a,b){var c=this.createBookmark(),d=this.document.createElement(b);this.collapse(a);this.enlarge(CKEDITOR.ENLARGE_BLOCK_CONTENTS);this.extractContents().appendTo(d);d.trim();this.insertNode(d);var g=d.getBogus();g&&g.remove();d.appendBogus();this.moveToBookmark(c);return d},splitBlock:function(a,b){var c=new CKEDITOR.dom.elementPath(this.startContainer,this.root),d=new CKEDITOR.dom.elementPath(this.endContainer,this.root),\ng=c.block,h=d.block,f=null;if(!c.blockLimit.equals(d.blockLimit))return null;\"br\"!=a&&(g||(g=this.fixBlock(!0,a),h=(new CKEDITOR.dom.elementPath(this.endContainer,this.root)).block),h||(h=this.fixBlock(!1,a)));c=g&&this.checkStartOfBlock();d=h&&this.checkEndOfBlock();this.deleteContents();g&&g.equals(h)&&(d?(f=new CKEDITOR.dom.elementPath(this.startContainer,this.root),this.moveToPosition(h,CKEDITOR.POSITION_AFTER_END),h=null):c?(f=new CKEDITOR.dom.elementPath(this.startContainer,this.root),this.moveToPosition(g,\nCKEDITOR.POSITION_BEFORE_START),g=null):(h=this.splitElement(g,b||!1),g.is(\"ul\",\"ol\")||g.appendBogus()));return{previousBlock:g,nextBlock:h,wasStartOfBlock:c,wasEndOfBlock:d,elementPath:f}},splitElement:function(a,b){if(!this.collapsed)return null;this.setEndAt(a,CKEDITOR.POSITION_BEFORE_END);var c=this.extractContents(!1,b||!1),d=a.clone(!1,b||!1);c.appendTo(d);d.insertAfter(a);this.moveToPosition(a,CKEDITOR.POSITION_AFTER_END);return d},removeEmptyBlocksAtEnd:function(){function a(e){return function(a){return b(a)||\nc(a)||a.type==CKEDITOR.NODE_ELEMENT&&a.isEmptyInlineRemoveable()||e.is(\"table\")&&a.is(\"caption\")?!1:!0}}var b=CKEDITOR.dom.walker.whitespaces(),c=CKEDITOR.dom.walker.bookmark(!1);return function(b){for(var c=this.createBookmark(),d=this[b?\"endPath\":\"startPath\"](),g=d.block||d.blockLimit,h;g&&!g.equals(d.root)&&!g.getFirst(a(g));)h=g.getParent(),this[b?\"setEndAt\":\"setStartAt\"](g,CKEDITOR.POSITION_AFTER_END),g.remove(1),g=h;this.moveToBookmark(c)}}(),startPath:function(){return new CKEDITOR.dom.elementPath(this.startContainer,\nthis.root)},endPath:function(){return new CKEDITOR.dom.elementPath(this.endContainer,this.root)},checkBoundaryOfElement:function(a,b){var d=b==CKEDITOR.START,g=this.clone();g.collapse(d);g[d?\"setStartAt\":\"setEndAt\"](a,d?CKEDITOR.POSITION_AFTER_START:CKEDITOR.POSITION_BEFORE_END);g=new CKEDITOR.dom.walker(g);g.evaluator=c(d);return g[d?\"checkBackward\":\"checkForward\"]()},checkStartOfBlock:function(){var a=this.startContainer,c=this.startOffset;CKEDITOR.env.ie&&c&&a.type==CKEDITOR.NODE_TEXT&&(a=CKEDITOR.tools.ltrim(a.substring(0,\nc)),g.test(a)&&this.trim(0,1));this.trim();a=new CKEDITOR.dom.elementPath(this.startContainer,this.root);c=this.clone();c.collapse(!0);c.setStartAt(a.block||a.blockLimit,CKEDITOR.POSITION_AFTER_START);a=new CKEDITOR.dom.walker(c);a.evaluator=b();return a.checkBackward()},checkEndOfBlock:function(){var a=this.endContainer,c=this.endOffset;CKEDITOR.env.ie&&a.type==CKEDITOR.NODE_TEXT&&(a=CKEDITOR.tools.rtrim(a.substring(c)),g.test(a)&&this.trim(1,0));this.trim();a=new CKEDITOR.dom.elementPath(this.endContainer,\nthis.root);c=this.clone();c.collapse(!1);c.setEndAt(a.block||a.blockLimit,CKEDITOR.POSITION_BEFORE_END);a=new CKEDITOR.dom.walker(c);a.evaluator=b();return a.checkForward()},getPreviousNode:function(a,b,c){var d=this.clone();d.collapse(1);d.setStartAt(c||this.root,CKEDITOR.POSITION_AFTER_START);c=new CKEDITOR.dom.walker(d);c.evaluator=a;c.guard=b;return c.previous()},getNextNode:function(a,b,c){var d=this.clone();d.collapse();d.setEndAt(c||this.root,CKEDITOR.POSITION_BEFORE_END);c=new CKEDITOR.dom.walker(d);\nc.evaluator=a;c.guard=b;return c.next()},checkReadOnly:function(){function a(b,c){for(;b;){if(b.type==CKEDITOR.NODE_ELEMENT){if(\"false\"==b.getAttribute(\"contentEditable\")&&!b.data(\"cke-editable\"))return 0;if(b.is(\"html\")||\"true\"==b.getAttribute(\"contentEditable\")&&(b.contains(c)||b.equals(c)))break}b=b.getParent()}return 1}return function(){var b=this.startContainer,c=this.endContainer;return!(a(b,c)&&a(c,b))}}(),moveToElementEditablePosition:function(a,b){if(a.type==CKEDITOR.NODE_ELEMENT&&!a.isEditable(!1))return this.moveToPosition(a,\nb?CKEDITOR.POSITION_AFTER_END:CKEDITOR.POSITION_BEFORE_START),!0;for(var c=0;a;){if(a.type==CKEDITOR.NODE_TEXT){b&&this.endContainer&&this.checkEndOfBlock()&&g.test(a.getText())?this.moveToPosition(a,CKEDITOR.POSITION_BEFORE_START):this.moveToPosition(a,b?CKEDITOR.POSITION_AFTER_END:CKEDITOR.POSITION_BEFORE_START);c=1;break}if(a.type==CKEDITOR.NODE_ELEMENT)if(a.isEditable())this.moveToPosition(a,b?CKEDITOR.POSITION_BEFORE_END:CKEDITOR.POSITION_AFTER_START),c=1;else if(b&&a.is(\"br\")&&this.endContainer&&\nthis.checkEndOfBlock())this.moveToPosition(a,CKEDITOR.POSITION_BEFORE_START);else if(\"false\"==a.getAttribute(\"contenteditable\")&&a.is(CKEDITOR.dtd.$block))return this.setStartBefore(a),this.setEndAfter(a),!0;var d=a,h=c,f=void 0;d.type==CKEDITOR.NODE_ELEMENT&&d.isEditable(!1)&&(f=d[b?\"getLast\":\"getFirst\"](m));h||f||(f=d[b?\"getPrevious\":\"getNext\"](m));a=f}return!!c},moveToClosestEditablePosition:function(a,b){var c,d=0,g,h,f=[CKEDITOR.POSITION_AFTER_END,CKEDITOR.POSITION_BEFORE_START];a?(c=new CKEDITOR.dom.range(this.root),\nc.moveToPosition(a,f[b?0:1])):c=this.clone();if(a&&!a.is(CKEDITOR.dtd.$block))d=1;else if(g=c[b?\"getNextEditableNode\":\"getPreviousEditableNode\"]())d=1,(h=g.type==CKEDITOR.NODE_ELEMENT)&&g.is(CKEDITOR.dtd.$block)&&\"false\"==g.getAttribute(\"contenteditable\")?(c.setStartAt(g,CKEDITOR.POSITION_BEFORE_START),c.setEndAt(g,CKEDITOR.POSITION_AFTER_END)):!CKEDITOR.env.needsBrFiller&&h&&g.is(CKEDITOR.dom.walker.validEmptyBlockContainers)?(c.setEnd(g,0),c.collapse()):c.moveToPosition(g,f[b?1:0]);d&&this.moveToRange(c);\nreturn!!d},moveToElementEditStart:function(a){return this.moveToElementEditablePosition(a)},moveToElementEditEnd:function(a){return this.moveToElementEditablePosition(a,!0)},getEnclosedNode:function(){var a=this.clone();a.optimize();if(a.startContainer.type!=CKEDITOR.NODE_ELEMENT||a.endContainer.type!=CKEDITOR.NODE_ELEMENT)return null;var a=new CKEDITOR.dom.walker(a),b=CKEDITOR.dom.walker.bookmark(!1,!0),c=CKEDITOR.dom.walker.whitespaces(!0);a.evaluator=function(a){return c(a)&&b(a)};var d=a.next();\na.reset();return d&&d.equals(a.previous())?d:null},getTouchedStartNode:function(){var a=this.startContainer;return this.collapsed||a.type!=CKEDITOR.NODE_ELEMENT?a:a.getChild(this.startOffset)||a},getTouchedEndNode:function(){var a=this.endContainer;return this.collapsed||a.type!=CKEDITOR.NODE_ELEMENT?a:a.getChild(this.endOffset-1)||a},getNextEditableNode:d(),getPreviousEditableNode:d(1),_getTableElement:function(a){a=a||{td:1,th:1,tr:1,tbody:1,thead:1,tfoot:1,table:1};var b=this.startContainer,c=\nthis.endContainer,d=b.getAscendant(\"table\",!0),g=c.getAscendant(\"table\",!0);return d&&!this.root.contains(d)?null:CKEDITOR.env.safari&&d&&c.equals(this.root)?b.getAscendant(a,!0):this.getEnclosedNode()?this.getEnclosedNode().getAscendant(a,!0):d&&g&&(d.equals(g)||d.contains(g)||g.contains(d))?b.getAscendant(a,!0):null},scrollIntoView:function(){var a=new CKEDITOR.dom.element.createFromHtml(\"\\x3cspan\\x3e\\x26nbsp;\\x3c/span\\x3e\",this.document),b,c,d,g=this.clone();g.optimize();(d=g.startContainer.type==\nCKEDITOR.NODE_TEXT)?(c=g.startContainer.getText(),b=g.startContainer.split(g.startOffset),a.insertAfter(g.startContainer)):g.insertNode(a);a.scrollIntoView();d&&(g.startContainer.setText(c),b.remove());a.remove()},getClientRects:function(){function a(b,c){var e=CKEDITOR.tools.array.map(b,function(a){return a}),d=new CKEDITOR.dom.range(c.root),g,h,f;c.startContainer instanceof CKEDITOR.dom.element&&(h=0===c.startOffset&&c.startContainer.hasAttribute(\"data-widget\"));c.endContainer instanceof CKEDITOR.dom.element&&\n(f=(f=c.endOffset===(c.endContainer.getChildCount?c.endContainer.getChildCount():c.endContainer.length))&&c.endContainer.hasAttribute(\"data-widget\"));h&&d.setStart(c.startContainer.getParent(),c.startContainer.getIndex());f&&d.setEnd(c.endContainer.getParent(),c.endContainer.getIndex()+1);if(h||f)c=d;d=c.cloneContents().find(\"[data-cke-widget-id]\").toArray();if(d=CKEDITOR.tools.array.map(d,function(a){var b=c.root.editor;a=a.getAttribute(\"data-cke-widget-id\");return b.widgets.instances[a].element}))return d=\nCKEDITOR.tools.array.map(d,function(a){var b;b=a.getParent().hasClass(\"cke_widget_wrapper\")?a.getParent():a;g=this.root.getDocument().$.createRange();g.setStart(b.getParent().$,b.getIndex());g.setEnd(b.getParent().$,b.getIndex()+1);b=g.getClientRects();b.widgetRect=a.getClientRect();return b},c),CKEDITOR.tools.array.forEach(d,function(a){function b(d){CKEDITOR.tools.array.forEach(e,function(b,g){var h=CKEDITOR.tools.objectCompare(a[d],b);h||(h=CKEDITOR.tools.objectCompare(a.widgetRect,b));h&&(Array.prototype.splice.call(e,\ng,a.length-d,a.widgetRect),c=!0)});c||(d<e.length-1?b(d+1):e.push(a.widgetRect))}var c;b(0)}),e}function b(a,c,e){var g;c.collapsed?e.startContainer instanceof CKEDITOR.dom.element?(a=e.checkStartOfBlock(),g=new CKEDITOR.dom.text(\"​\"),a?e.startContainer.append(g,!0):0===e.startOffset?g.insertBefore(e.startContainer.getFirst()):(e=e.startContainer.getChildren().getItem(e.startOffset-1),g.insertAfter(e)),c.setStart(g.$,0),c.setEnd(g.$,0),a=c.getClientRects(),g.remove()):e.startContainer instanceof CKEDITOR.dom.text&&\n(\"\"===e.startContainer.getText()?(e.startContainer.setText(\"​\"),a=c.getClientRects(),e.startContainer.setText(\"\")):a=[d(e.createBookmark())]):a=[d(e.createBookmark())];return a}function c(a,b,e){a=CKEDITOR.tools.extend({},a);b&&(a=CKEDITOR.tools.getAbsoluteRectPosition(e.document.getWindow(),a));!a.width&&(a.width=a.right-a.left);!a.height&&(a.height=a.bottom-a.top);return a}function d(a){var b=a.startNode;a=a.endNode;var c;b.setText(\"​\");b.removeStyle(\"display\");a?(a.setText(\"​\"),a.removeStyle(\"display\"),\nc=[b.getClientRect(),a.getClientRect()],a.remove()):c=[b.getClientRect(),b.getClientRect()];b.remove();return{right:Math.max(c[0].right,c[1].right),bottom:Math.max(c[0].bottom,c[1].bottom),left:Math.min(c[0].left,c[1].left),top:Math.min(c[0].top,c[1].top),width:Math.abs(c[0].left-c[1].left),height:Math.max(c[0].bottom,c[1].bottom)-Math.min(c[0].top,c[1].top)}}return void 0!==this.document.getSelection?function(d){var g=this.root.getDocument().$.createRange(),h;g.setStart(this.startContainer.$,this.startOffset);\ng.setEnd(this.endContainer.$,this.endOffset);h=g.getClientRects();h=a(h,this);h.length||(h=b(h,g,this));return CKEDITOR.tools.array.map(h,function(a){return c(a,d,this)},this)}:function(a){return[c(d(this.createBookmark()),a,this)]}}(),_setStartContainer:function(a){this.startContainer=a},_setEndContainer:function(a){this.endContainer=a},_find:function(a,b){var c=this.getCommonAncestor(),d=this.getBoundaryNodes(),g=[],h,f,m,l;if(c&&c.find)for(f=c.find(a),h=0;h<f.count();h++)if(c=f.getItem(h),b||!c.isReadOnly())m=\nc.getPosition(d.startNode)&CKEDITOR.POSITION_FOLLOWING||d.startNode.equals(c),l=c.getPosition(d.endNode)&CKEDITOR.POSITION_PRECEDING+CKEDITOR.POSITION_IS_CONTAINED||d.endNode.equals(c),m&&l&&g.push(c);return g}};CKEDITOR.dom.range.mergeRanges=function(a){return CKEDITOR.tools.array.reduce(a,function(a,b){var c=a[a.length-1],e=!1;b=b.clone();b.enlarge(CKEDITOR.ENLARGE_ELEMENT);if(c){var d=new CKEDITOR.dom.range(b.root),e=new CKEDITOR.dom.walker(d),g=CKEDITOR.dom.walker.whitespaces();d.setStart(c.endContainer,\nc.endOffset);d.setEnd(b.startContainer,b.startOffset);for(d=e.next();g(d)||b.endContainer.equals(d);)d=e.next();e=!d}e?c.setEnd(b.endContainer,b.endOffset):a.push(b);return a},[])}}(),CKEDITOR.POSITION_AFTER_START=1,CKEDITOR.POSITION_BEFORE_END=2,CKEDITOR.POSITION_BEFORE_START=3,CKEDITOR.POSITION_AFTER_END=4,CKEDITOR.ENLARGE_ELEMENT=1,CKEDITOR.ENLARGE_BLOCK_CONTENTS=2,CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS=3,CKEDITOR.ENLARGE_INLINE=4,CKEDITOR.START=1,CKEDITOR.END=2,CKEDITOR.SHRINK_ELEMENT=1,CKEDITOR.SHRINK_TEXT=\n2,\"use strict\",function(){function a(a){1>arguments.length||(this.range=a,this.forceBrBreak=0,this.enlargeBr=1,this.enforceRealBlocks=0,this._||(this._={}))}function f(a){var b=[];a.forEach(function(a){if(\"true\"==a.getAttribute(\"contenteditable\"))return b.push(a),!1},CKEDITOR.NODE_ELEMENT,!0);return b}function b(a,c,d,g){a:{null==g&&(g=f(d));for(var h;h=g.shift();)if(h.getDtd().p){g={element:h,remaining:g};break a}g=null}if(!g)return 0;if((h=CKEDITOR.filter.instances[g.element.data(\"cke-filter\")])&&\n!h.check(c))return b(a,c,d,g.remaining);c=new CKEDITOR.dom.range(g.element);c.selectNodeContents(g.element);c=c.createIterator();c.enlargeBr=a.enlargeBr;c.enforceRealBlocks=a.enforceRealBlocks;c.activeFilter=c.filter=h;a._.nestedEditable={element:g.element,container:d,remaining:g.remaining,iterator:c};return 1}function c(a,b,c){if(!b)return!1;a=a.clone();a.collapse(!c);return a.checkBoundaryOfElement(b,c?CKEDITOR.START:CKEDITOR.END)}var d=/^[\\r\\n\\t ]+$/,l=CKEDITOR.dom.walker.bookmark(!1,!0),k=CKEDITOR.dom.walker.whitespaces(!0),\ng=function(a){return l(a)&&k(a)},h={dd:1,dt:1,li:1};a.prototype={getNextParagraph:function(a){var e,f,k,y,u;a=a||\"p\";if(this._.nestedEditable){if(e=this._.nestedEditable.iterator.getNextParagraph(a))return this.activeFilter=this._.nestedEditable.iterator.activeFilter,e;this.activeFilter=this.filter;if(b(this,a,this._.nestedEditable.container,this._.nestedEditable.remaining))return this.activeFilter=this._.nestedEditable.iterator.activeFilter,this._.nestedEditable.iterator.getNextParagraph(a);this._.nestedEditable=\nnull}if(!this.range.root.getDtd()[a])return null;if(!this._.started){var p=this.range.clone();f=p.startPath();var v=p.endPath(),w=!p.collapsed&&c(p,f.block),r=!p.collapsed&&c(p,v.block,1);p.shrink(CKEDITOR.SHRINK_ELEMENT,!0);w&&p.setStartAt(f.block,CKEDITOR.POSITION_BEFORE_END);r&&p.setEndAt(v.block,CKEDITOR.POSITION_AFTER_START);f=p.endContainer.hasAscendant(\"pre\",!0)||p.startContainer.hasAscendant(\"pre\",!0);p.enlarge(this.forceBrBreak&&!f||!this.enlargeBr?CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS:CKEDITOR.ENLARGE_BLOCK_CONTENTS);\np.collapsed||(f=new CKEDITOR.dom.walker(p.clone()),v=CKEDITOR.dom.walker.bookmark(!0,!0),f.evaluator=v,this._.nextNode=f.next(),f=new CKEDITOR.dom.walker(p.clone()),f.evaluator=v,f=f.previous(),this._.lastNode=f.getNextSourceNode(!0,null,p.root),this._.lastNode&&this._.lastNode.type==CKEDITOR.NODE_TEXT&&!CKEDITOR.tools.trim(this._.lastNode.getText())&&this._.lastNode.getParent().isBlockBoundary()&&(v=this.range.clone(),v.moveToPosition(this._.lastNode,CKEDITOR.POSITION_AFTER_END),v.checkEndOfBlock()&&\n(v=new CKEDITOR.dom.elementPath(v.endContainer,v.root),this._.lastNode=(v.block||v.blockLimit).getNextSourceNode(!0))),this._.lastNode&&p.root.contains(this._.lastNode)||(this._.lastNode=this._.docEndMarker=p.document.createText(\"\"),this._.lastNode.insertAfter(f)),p=null);this._.started=1;f=p}v=this._.nextNode;p=this._.lastNode;for(this._.nextNode=null;v;){var w=0,r=v.hasAscendant(\"pre\"),z=v.type!=CKEDITOR.NODE_ELEMENT,t=0;if(z)v.type==CKEDITOR.NODE_TEXT&&d.test(v.getText())&&(z=0);else{var x=v.getName();\nif(CKEDITOR.dtd.$block[x]&&\"false\"==v.getAttribute(\"contenteditable\")){e=v;b(this,a,e);break}else if(v.isBlockBoundary(this.forceBrBreak&&!r&&{br:1})){if(\"br\"==x)z=1;else if(!f&&!v.getChildCount()&&\"hr\"!=x){e=v;k=v.equals(p);break}f&&(f.setEndAt(v,CKEDITOR.POSITION_BEFORE_START),\"br\"!=x&&(this._.nextNode=v));w=1}else{if(v.getFirst()){f||(f=this.range.clone(),f.setStartAt(v,CKEDITOR.POSITION_BEFORE_START));v=v.getFirst();continue}z=1}}z&&!f&&(f=this.range.clone(),f.setStartAt(v,CKEDITOR.POSITION_BEFORE_START));\nk=(!w||z)&&v.equals(p);if(f&&!w)for(;!v.getNext(g)&&!k;){x=v.getParent();if(x.isBlockBoundary(this.forceBrBreak&&!r&&{br:1})){w=1;z=0;k||x.equals(p);f.setEndAt(x,CKEDITOR.POSITION_BEFORE_END);break}v=x;z=1;k=v.equals(p);t=1}z&&f.setEndAt(v,CKEDITOR.POSITION_AFTER_END);v=this._getNextSourceNode(v,t,p);if((k=!v)||w&&f)break}if(!e){if(!f)return this._.docEndMarker&&this._.docEndMarker.remove(),this._.nextNode=null;e=new CKEDITOR.dom.elementPath(f.startContainer,f.root);v=e.blockLimit;w={div:1,th:1,td:1};\ne=e.block;!e&&v&&!this.enforceRealBlocks&&w[v.getName()]&&f.checkStartOfBlock()&&f.checkEndOfBlock()&&!v.equals(f.root)?e=v:!e||this.enforceRealBlocks&&e.is(h)?(e=this.range.document.createElement(a),f.extractContents().appendTo(e),e.trim(),f.insertNode(e),y=u=!0):\"li\"!=e.getName()?f.checkStartOfBlock()&&f.checkEndOfBlock()||(e=e.clone(!1),f.extractContents().appendTo(e),e.trim(),u=f.splitBlock(),y=!u.wasStartOfBlock,u=!u.wasEndOfBlock,f.insertNode(e)):k||(this._.nextNode=e.equals(p)?null:this._getNextSourceNode(f.getBoundaryNodes().endNode,\n1,p))}y&&(y=e.getPrevious())&&y.type==CKEDITOR.NODE_ELEMENT&&(\"br\"==y.getName()?y.remove():y.getLast()&&\"br\"==y.getLast().$.nodeName.toLowerCase()&&y.getLast().remove());u&&(y=e.getLast())&&y.type==CKEDITOR.NODE_ELEMENT&&\"br\"==y.getName()&&(!CKEDITOR.env.needsBrFiller||y.getPrevious(l)||y.getNext(l))&&y.remove();this._.nextNode||(this._.nextNode=k||e.equals(p)||!p?null:this._getNextSourceNode(e,1,p));return e},_getNextSourceNode:function(a,b,c){function d(a){return!(a.equals(c)||a.equals(g))}var g=\nthis.range.root;for(a=a.getNextSourceNode(b,null,d);!l(a);)a=a.getNextSourceNode(b,null,d);return a}};CKEDITOR.dom.range.prototype.createIterator=function(){return new a(this)}}(),CKEDITOR.command=function(a,f){this.uiItems=[];this.exec=function(b){if(this.state==CKEDITOR.TRISTATE_DISABLED||!this.checkAllowed())return!1;this.editorFocus&&a.focus();return!1===this.fire(\"exec\")?!0:!1!==f.exec.call(this,a,b)};this.refresh=function(a,b){if(!this.readOnly&&a.readOnly)return!0;if(this.context&&!b.isContextFor(this.context)||\n!this.checkAllowed(!0))return this.disable(),!0;this.startDisabled||this.enable();this.modes&&!this.modes[a.mode]&&this.disable();return!1===this.fire(\"refresh\",{editor:a,path:b})?!0:f.refresh&&!1!==f.refresh.apply(this,arguments)};var b;this.checkAllowed=function(c){return c||\"boolean\"!=typeof b?b=a.activeFilter.checkFeature(this):b};CKEDITOR.tools.extend(this,f,{modes:{wysiwyg:1},editorFocus:1,contextSensitive:!!f.context,state:CKEDITOR.TRISTATE_DISABLED});CKEDITOR.event.call(this)},CKEDITOR.command.prototype=\n{enable:function(){this.state==CKEDITOR.TRISTATE_DISABLED&&this.checkAllowed()&&this.setState(this.preserveState&&\"undefined\"!=typeof this.previousState?this.previousState:CKEDITOR.TRISTATE_OFF)},disable:function(){this.setState(CKEDITOR.TRISTATE_DISABLED)},setState:function(a){if(this.state==a||a!=CKEDITOR.TRISTATE_DISABLED&&!this.checkAllowed())return!1;this.previousState=this.state;this.state=a;this.fire(\"state\");return!0},toggleState:function(){this.state==CKEDITOR.TRISTATE_OFF?this.setState(CKEDITOR.TRISTATE_ON):\nthis.state==CKEDITOR.TRISTATE_ON&&this.setState(CKEDITOR.TRISTATE_OFF)}},CKEDITOR.event.implementOn(CKEDITOR.command.prototype),CKEDITOR.ENTER_P=1,CKEDITOR.ENTER_BR=2,CKEDITOR.ENTER_DIV=3,CKEDITOR.config={customConfig:\"config.js\",autoUpdateElement:!0,language:\"\",defaultLanguage:\"en\",contentsLangDirection:\"\",enterMode:CKEDITOR.ENTER_P,forceEnterMode:!1,shiftEnterMode:CKEDITOR.ENTER_BR,docType:\"\\x3c!DOCTYPE html\\x3e\",bodyId:\"\",bodyClass:\"\",fullPage:!1,height:200,contentsCss:CKEDITOR.getUrl(\"contents.css\"),\nextraPlugins:\"\",removePlugins:\"\",protectedSource:[],tabIndex:0,width:\"\",baseFloatZIndex:1E4,blockedKeystrokes:[CKEDITOR.CTRL+66,CKEDITOR.CTRL+73,CKEDITOR.CTRL+85]},function(){function a(a,b,c,e,d){var g,h;a=[];for(g in b){h=b[g];h=\"boolean\"==typeof h?{}:\"function\"==typeof h?{match:h}:I(h);\"$\"!=g.charAt(0)&&(h.elements=g);c&&(h.featureName=c.toLowerCase());var f=h;f.elements=k(f.elements,/\\s+/)||null;f.propertiesOnly=f.propertiesOnly||!0===f.elements;var m=/\\s*,\\s*/,l=void 0;for(l in L){f[l]=k(f[l],\nm)||null;var n=f,v=G[l],D=k(f[G[l]],m),x=f[l],A=[],B=!0,r=void 0;D?B=!1:D={};for(r in x)\"!\"==r.charAt(0)&&(r=r.slice(1),A.push(r),D[r]=!0,B=!1);for(;r=A.pop();)x[r]=x[\"!\"+r],delete x[\"!\"+r];n[v]=(B?!1:D)||null}f.match=f.match||null;e.push(h);a.push(h)}b=d.elements;d=d.generic;var F;c=0;for(e=a.length;c<e;++c){g=I(a[c]);h=!0===g.classes||!0===g.styles||!0===g.attributes;f=g;l=v=m=void 0;for(m in L)f[m]=w(f[m]);n=!0;for(l in G){m=G[l];v=f[m];D=[];x=void 0;for(x in v)-1<x.indexOf(\"*\")?D.push(new RegExp(\"^\"+\nx.replace(/\\*/g,\".*\")+\"$\")):D.push(x);v=D;v.length&&(f[m]=v,n=!1)}f.nothingRequired=n;f.noProperties=!(f.attributes||f.classes||f.styles);if(!0===g.elements||null===g.elements)d[h?\"unshift\":\"push\"](g);else for(F in f=g.elements,delete g.elements,f)if(b[F])b[F][h?\"unshift\":\"push\"](g);else b[F]=[g]}}function f(a,c,e,d){if(!a.match||a.match(c))if(d||g(a,c))if(a.propertiesOnly||(e.valid=!0),e.allAttributes||(e.allAttributes=b(a.attributes,c.attributes,e.validAttributes)),e.allStyles||(e.allStyles=b(a.styles,\nc.styles,e.validStyles)),!e.allClasses){a=a.classes;c=c.classes;d=e.validClasses;if(a)if(!0===a)a=!0;else{for(var h=0,f=c.length,m;h<f;++h)m=c[h],d[m]||(d[m]=a(m));a=!1}else a=!1;e.allClasses=a}}function b(a,b,c){if(!a)return!1;if(!0===a)return!0;for(var e in b)c[e]||(c[e]=a(e));return!1}function c(a,b,c){if(!a.match||a.match(b)){if(a.noProperties)return!1;c.hadInvalidAttribute=d(a.attributes,b.attributes)||c.hadInvalidAttribute;c.hadInvalidStyle=d(a.styles,b.styles)||c.hadInvalidStyle;a=a.classes;\nb=b.classes;if(a){for(var e=!1,g=!0===a,h=b.length;h--;)if(g||a(b[h]))b.splice(h,1),e=!0;a=e}else a=!1;c.hadInvalidClass=a||c.hadInvalidClass}}function d(a,b){if(!a)return!1;var c=!1,e=!0===a,d;for(d in b)if(e||a(d))delete b[d],c=!0;return c}function l(a,b,c){if(a.disabled||a.customConfig&&!c||!b)return!1;a._.cachedChecks={};return!0}function k(a,b){if(!a)return!1;if(!0===a)return a;if(\"string\"==typeof a)return a=J(a),\"*\"==a?!0:CKEDITOR.tools.convertArrayToObject(a.split(b));if(CKEDITOR.tools.isArray(a))return a.length?\nCKEDITOR.tools.convertArrayToObject(a):!1;var c={},e=0,d;for(d in a)c[d]=a[d],e++;return e?c:!1}function g(a,b){if(a.nothingRequired)return!0;var c,e,d,g;if(d=a.requiredClasses)for(g=b.classes,c=0;c<d.length;++c)if(e=d[c],\"string\"==typeof e){if(-1==CKEDITOR.tools.indexOf(g,e))return!1}else if(!CKEDITOR.tools.checkIfAnyArrayItemMatches(g,e))return!1;return h(b.styles,a.requiredStyles)&&h(b.attributes,a.requiredAttributes)}function h(a,b){if(!b)return!0;for(var c=0,e;c<b.length;++c)if(e=b[c],\"string\"==\ntypeof e){if(!(e in a))return!1}else if(!CKEDITOR.tools.checkIfAnyObjectPropertyMatches(a,e))return!1;return!0}function m(a){if(!a)return{};a=a.split(/\\s*,\\s*/).sort();for(var b={};a.length;)b[a.shift()]=\"cke-test\";return b}function e(a){var b,c,e,d,g={},h=1;for(a=J(a);b=a.match(D);)(c=b[2])?(e=n(c,\"styles\"),d=n(c,\"attrs\"),c=n(c,\"classes\")):e=d=c=null,g[\"$\"+h++]={elements:b[1],classes:c,styles:e,attributes:d},a=a.slice(b[0].length);return g}function n(a,b){var c=a.match(N[b]);return c?J(c[1]):null}\nfunction q(a){var b=a.styleBackup=a.attributes.style,c=a.classBackup=a.attributes[\"class\"];a.styles||(a.styles=CKEDITOR.tools.parseCssText(b||\"\",1));a.classes||(a.classes=c?c.split(/\\s+/):[])}function y(a,b,e,d){var g=0,h;d.toHtml&&(b.name=b.name.replace(Q,\"$1\"));if(d.doCallbacks&&a.elementCallbacks){a:{h=a.elementCallbacks;for(var m=0,l=h.length,k;m<l;++m)if(k=h[m](b)){h=k;break a}h=void 0}if(h)return h}if(d.doTransform&&(h=a._.transformations[b.name])){q(b);for(m=0;m<h.length;++m)x(a,b,h[m]);p(b)}if(d.doFilter){a:{m=\nb.name;l=a._;a=l.allowedRules.elements[m];h=l.allowedRules.generic;m=l.disallowedRules.elements[m];l=l.disallowedRules.generic;k=d.skipRequired;var n={valid:!1,validAttributes:{},validClasses:{},validStyles:{},allAttributes:!1,allClasses:!1,allStyles:!1,hadInvalidAttribute:!1,hadInvalidClass:!1,hadInvalidStyle:!1},D,A;if(a||h){q(b);if(m)for(D=0,A=m.length;D<A;++D)if(!1===c(m[D],b,n)){a=null;break a}if(l)for(D=0,A=l.length;D<A;++D)c(l[D],b,n);if(a)for(D=0,A=a.length;D<A;++D)f(a[D],b,n,k);if(h)for(D=\n0,A=h.length;D<A;++D)f(h[D],b,n,k);a=n}else a=null}if(!a||!a.valid)return e.push(b),1;A=a.validAttributes;var r=a.validStyles;h=a.validClasses;var m=b.attributes,B=b.styles,l=b.classes;k=b.classBackup;var F=b.styleBackup,w,G,J=[],n=[],C=/^data-cke-/;D=!1;delete m.style;delete m[\"class\"];delete b.classBackup;delete b.styleBackup;if(!a.allAttributes)for(w in m)A[w]||(C.test(w)?w==(G=w.replace(/^data-cke-saved-/,\"\"))||A[G]||(delete m[w],D=!0):(delete m[w],D=!0));if(!a.allStyles||a.hadInvalidStyle){for(w in B)a.allStyles||\nr[w]?J.push(w+\":\"+B[w]):D=!0;J.length&&(m.style=J.sort().join(\"; \"))}else F&&(m.style=F);if(!a.allClasses||a.hadInvalidClass){for(w=0;w<l.length;++w)(a.allClasses||h[l[w]])&&n.push(l[w]);n.length&&(m[\"class\"]=n.sort().join(\" \"));k&&n.length<k.split(/\\s+/).length&&(D=!0)}else k&&(m[\"class\"]=k);D&&(g=1);if(!d.skipFinalValidation&&!v(b))return e.push(b),1}d.toHtml&&(b.name=b.name.replace(O,\"cke:$1\"));return g}function u(a){var b=[],c;for(c in a)-1<c.indexOf(\"*\")&&b.push(c.replace(/\\*/g,\".*\"));return b.length?\nnew RegExp(\"^(?:\"+b.join(\"|\")+\")$\"):null}function p(a){var b=a.attributes,c;delete b.style;delete b[\"class\"];if(c=CKEDITOR.tools.writeCssText(a.styles,!0))b.style=c;a.classes.length&&(b[\"class\"]=a.classes.sort().join(\" \"))}function v(a){switch(a.name){case \"a\":if(!(a.children.length||a.attributes.name||a.attributes.id))return!1;break;case \"img\":if(!a.attributes.src)return!1}return!0}function w(a){if(!a)return!1;if(!0===a)return!0;var b=u(a);return function(c){return c in a||b&&c.match(b)}}function r(){return new CKEDITOR.htmlParser.element(\"br\")}\nfunction z(a){return a.type==CKEDITOR.NODE_ELEMENT&&(\"br\"==a.name||F.$block[a.name])}function t(a,b,c){var e=a.name;if(F.$empty[e]||!a.children.length)\"hr\"==e&&\"br\"==b?a.replaceWith(r()):(a.parent&&c.push({check:\"it\",el:a.parent}),a.remove());else if(F.$block[e]||\"tr\"==e)if(\"br\"==b)a.previous&&!z(a.previous)&&(b=r(),b.insertBefore(a)),a.next&&!z(a.next)&&(b=r(),b.insertAfter(a)),a.replaceWithChildren();else{var e=a.children,d;b:{d=F[b];for(var g=0,h=e.length,f;g<h;++g)if(f=e[g],f.type==CKEDITOR.NODE_ELEMENT&&\n!d[f.name]){d=!1;break b}d=!0}if(d)a.name=b,a.attributes={},c.push({check:\"parent-down\",el:a});else{d=a.parent;for(var g=d.type==CKEDITOR.NODE_DOCUMENT_FRAGMENT||\"body\"==d.name,m,l,h=e.length;0<h;)f=e[--h],g&&(f.type==CKEDITOR.NODE_TEXT||f.type==CKEDITOR.NODE_ELEMENT&&F.$inline[f.name])?(m||(m=new CKEDITOR.htmlParser.element(b),m.insertAfter(a),c.push({check:\"parent-down\",el:m})),m.add(f,0)):(m=null,l=F[d.name]||F.span,f.insertAfter(a),d.type==CKEDITOR.NODE_DOCUMENT_FRAGMENT||f.type!=CKEDITOR.NODE_ELEMENT||\nl[f.name]||c.push({check:\"el-up\",el:f}));a.remove()}}else e in{style:1,script:1}?a.remove():(a.parent&&c.push({check:\"it\",el:a.parent}),a.replaceWithChildren())}function x(a,b,c){var e,d;for(e=0;e<c.length;++e)if(d=c[e],!(d.check&&!a.check(d.check,!1)||d.left&&!d.left(b))){d.right(b,K);break}}function A(a,b){var c=b.getDefinition(),e=c.attributes,d=c.styles,g,h,f,m;if(a.name!=c.element)return!1;for(g in e)if(\"class\"==g)for(c=e[g].split(/\\s+/),f=a.classes.join(\"|\");m=c.pop();){if(-1==f.indexOf(m))return!1}else if(a.attributes[g]!=\ne[g])return!1;for(h in d)if(a.styles[h]!=d[h])return!1;return!0}function B(a,b){var c,e;\"string\"==typeof a?c=a:a instanceof CKEDITOR.style?e=a:(c=a[0],e=a[1]);return[{element:c,left:e,right:function(a,c){c.transform(a,b)}}]}function C(a){return function(b){return A(b,a)}}function H(a){return function(b,c){c[a](b)}}var F=CKEDITOR.dtd,I=CKEDITOR.tools.copy,J=CKEDITOR.tools.trim,E=[\"\",\"p\",\"br\",\"div\"];CKEDITOR.FILTER_SKIP_TREE=2;CKEDITOR.filter=function(a,b){this.allowedContent=[];this.disallowedContent=\n[];this.elementCallbacks=null;this.disabled=!1;this.editor=null;this.id=CKEDITOR.tools.getNextNumber();this._={allowedRules:{elements:{},generic:[]},disallowedRules:{elements:{},generic:[]},transformations:{},cachedTests:{},cachedChecks:{}};CKEDITOR.filter.instances[this.id]=this;var c=this.editor=a instanceof CKEDITOR.editor?a:null;if(c&&!b){this.customConfig=!0;var e=c.config.allowedContent;!0===e?this.disabled=!0:(e||(this.customConfig=!1),this.allow(e,\"config\",1),this.allow(c.config.extraAllowedContent,\n\"extra\",1),this.allow(E[c.enterMode]+\" \"+E[c.shiftEnterMode],\"default\",1),this.disallow(c.config.disallowedContent))}else this.customConfig=!1,this.allow(b||a,\"default\",1)};CKEDITOR.filter.instances={};CKEDITOR.filter.prototype={allow:function(b,c,d){if(!l(this,b,d))return!1;var g,h;if(\"string\"==typeof b)b=e(b);else if(b instanceof CKEDITOR.style){if(b.toAllowedContentRules)return this.allow(b.toAllowedContentRules(this.editor),c,d);g=b.getDefinition();b={};d=g.attributes;b[g.element]=g={styles:g.styles,\nrequiredStyles:g.styles&&CKEDITOR.tools.object.keys(g.styles)};d&&(d=I(d),g.classes=d[\"class\"]?d[\"class\"].split(/\\s+/):null,g.requiredClasses=g.classes,delete d[\"class\"],g.attributes=d,g.requiredAttributes=d&&CKEDITOR.tools.object.keys(d))}else if(CKEDITOR.tools.isArray(b)){for(g=0;g<b.length;++g)h=this.allow(b[g],c,d);return h}a(this,b,c,this.allowedContent,this._.allowedRules);return!0},applyTo:function(a,b,c,e){if(this.disabled)return!1;var d=this,g=[],h=this.editor&&this.editor.config.protectedSource,\nf,m=!1,l={doFilter:!c,doTransform:!0,doCallbacks:!0,toHtml:b};a.forEach(function(a){if(a.type==CKEDITOR.NODE_ELEMENT){if(\"off\"==a.attributes[\"data-cke-filter\"])return!1;if(!b||\"span\"!=a.name||!~CKEDITOR.tools.object.keys(a.attributes).join(\"|\").indexOf(\"data-cke-\"))if(f=y(d,a,g,l),f&1)m=!0;else if(f&2)return!1}else if(a.type==CKEDITOR.NODE_COMMENT&&a.value.match(/^\\{cke_protected\\}(?!\\{C\\})/)){var c;a:{var e=decodeURIComponent(a.value.replace(/^\\{cke_protected\\}/,\"\"));c=[];var k,n,v;if(h)for(n=0;n<\nh.length;++n)if((v=e.match(h[n]))&&v[0].length==e.length){c=!0;break a}e=CKEDITOR.htmlParser.fragment.fromHtml(e);1==e.children.length&&(k=e.children[0]).type==CKEDITOR.NODE_ELEMENT&&y(d,k,c,l);c=!c.length}c||g.push(a)}},null,!0);g.length&&(m=!0);var k;a=[];e=E[e||(this.editor?this.editor.enterMode:CKEDITOR.ENTER_P)];for(var n;c=g.pop();)c.type==CKEDITOR.NODE_ELEMENT?t(c,e,a):c.remove();for(;k=a.pop();)if(c=k.el,c.parent)switch(n=F[c.parent.name]||F.span,k.check){case \"it\":F.$removeEmpty[c.name]&&\n!c.children.length?t(c,e,a):v(c)||t(c,e,a);break;case \"el-up\":c.parent.type==CKEDITOR.NODE_DOCUMENT_FRAGMENT||n[c.name]||t(c,e,a);break;case \"parent-down\":c.parent.type==CKEDITOR.NODE_DOCUMENT_FRAGMENT||n[c.name]||t(c.parent,e,a)}return m},checkFeature:function(a){if(this.disabled||!a)return!0;a.toFeature&&(a=a.toFeature(this.editor));return!a.requiredContent||this.check(a.requiredContent)},disable:function(){this.disabled=!0},disallow:function(b){if(!l(this,b,!0))return!1;\"string\"==typeof b&&(b=\ne(b));a(this,b,null,this.disallowedContent,this._.disallowedRules);return!0},addContentForms:function(a){if(!this.disabled&&a){var b,c,e=[],d;for(b=0;b<a.length&&!d;++b)c=a[b],(\"string\"==typeof c||c instanceof CKEDITOR.style)&&this.check(c)&&(d=c);if(d){for(b=0;b<a.length;++b)e.push(B(a[b],d));this.addTransformations(e)}}},addElementCallback:function(a){this.elementCallbacks||(this.elementCallbacks=[]);this.elementCallbacks.push(a)},addFeature:function(a){if(this.disabled||!a)return!0;a.toFeature&&\n(a=a.toFeature(this.editor));this.allow(a.allowedContent,a.name);this.addTransformations(a.contentTransformations);this.addContentForms(a.contentForms);return a.requiredContent&&(this.customConfig||this.disallowedContent.length)?this.check(a.requiredContent):!0},addTransformations:function(a){var b,c;if(!this.disabled&&a){var e=this._.transformations,d;for(d=0;d<a.length;++d){b=a[d];var g=void 0,h=void 0,f=void 0,m=void 0,l=void 0,k=void 0;c=[];for(h=0;h<b.length;++h)f=b[h],\"string\"==typeof f?(f=\nf.split(/\\s*:\\s*/),m=f[0],l=null,k=f[1]):(m=f.check,l=f.left,k=f.right),g||(g=f,g=g.element?g.element:m?m.match(/^([a-z0-9]+)/i)[0]:g.left.getDefinition().element),l instanceof CKEDITOR.style&&(l=C(l)),c.push({check:m==g?null:m,left:l,right:\"string\"==typeof k?H(k):k});b=g;e[b]||(e[b]=[]);e[b].push(c)}}},check:function(a,b,c){if(this.disabled)return!0;if(CKEDITOR.tools.isArray(a)){for(var d=a.length;d--;)if(this.check(a[d],b,c))return!0;return!1}var g,h;if(\"string\"==typeof a){h=a+\"\\x3c\"+(!1===b?\"0\":\n\"1\")+(c?\"1\":\"0\")+\"\\x3e\";if(h in this._.cachedChecks)return this._.cachedChecks[h];g=e(a).$1;var f=g.styles,d=g.classes;g.name=g.elements;g.classes=d=d?d.split(/\\s*,\\s*/):[];g.styles=m(f);g.attributes=m(g.attributes);g.children=[];d.length&&(g.attributes[\"class\"]=d.join(\" \"));f&&(g.attributes.style=CKEDITOR.tools.writeCssText(g.styles))}else g=a.getDefinition(),f=g.styles,d=g.attributes||{},f&&!CKEDITOR.tools.isEmpty(f)?(f=I(f),d.style=CKEDITOR.tools.writeCssText(f,!0)):f={},g={name:g.element,attributes:d,\nclasses:d[\"class\"]?d[\"class\"].split(/\\s+/):[],styles:f,children:[]};var f=CKEDITOR.tools.clone(g),l=[],k;if(!1!==b&&(k=this._.transformations[g.name])){for(d=0;d<k.length;++d)x(this,g,k[d]);p(g)}y(this,f,l,{doFilter:!0,doTransform:!1!==b,skipRequired:!c,skipFinalValidation:!c});0<l.length?c=!1:((b=g.attributes[\"class\"])&&(g.attributes[\"class\"]=g.attributes[\"class\"].split(\" \").sort().join(\" \")),c=CKEDITOR.tools.objectCompare(g.attributes,f.attributes,!0),b&&(g.attributes[\"class\"]=b));\"string\"==typeof a&&\n(this._.cachedChecks[h]=c);return c},getAllowedEnterMode:function(){var a=[\"p\",\"div\",\"br\"],b={p:CKEDITOR.ENTER_P,div:CKEDITOR.ENTER_DIV,br:CKEDITOR.ENTER_BR};return function(c,e){var d=a.slice(),g;if(this.check(E[c]))return c;for(e||(d=d.reverse());g=d.pop();)if(this.check(g))return b[g];return CKEDITOR.ENTER_BR}}(),clone:function(){var a=new CKEDITOR.filter,b=CKEDITOR.tools.clone;a.allowedContent=b(this.allowedContent);a._.allowedRules=b(this._.allowedRules);a.disallowedContent=b(this.disallowedContent);\na._.disallowedRules=b(this._.disallowedRules);a._.transformations=b(this._.transformations);a.disabled=this.disabled;a.editor=this.editor;return a},destroy:function(){delete CKEDITOR.filter.instances[this.id];delete this._;delete this.allowedContent;delete this.disallowedContent}};var L={styles:1,attributes:1,classes:1},G={styles:\"requiredStyles\",attributes:\"requiredAttributes\",classes:\"requiredClasses\"},D=/^([a-z0-9\\-*\\s]+)((?:\\s*\\{[!\\w\\-,\\s\\*]+\\}\\s*|\\s*\\[[!\\w\\-,\\s\\*]+\\]\\s*|\\s*\\([!\\w\\-,\\s\\*]+\\)\\s*){0,3})(?:;\\s*|$)/i,\nN={styles:/{([^}]+)}/,attrs:/\\[([^\\]]+)\\]/,classes:/\\(([^\\)]+)\\)/},Q=/^cke:(object|embed|param)$/,O=/^(object|embed|param)$/,K;K=CKEDITOR.filter.transformationsTools={sizeToStyle:function(a){this.lengthToStyle(a,\"width\");this.lengthToStyle(a,\"height\")},sizeToAttribute:function(a){this.lengthToAttribute(a,\"width\");this.lengthToAttribute(a,\"height\")},lengthToStyle:function(a,b,c){c=c||b;if(!(c in a.styles)){var e=a.attributes[b];e&&(/^\\d+$/.test(e)&&(e+=\"px\"),a.styles[c]=e)}delete a.attributes[b]},\nlengthToAttribute:function(a,b,c){c=c||b;if(!(c in a.attributes)){var e=a.styles[b],d=e&&e.match(/^(\\d+)(?:\\.\\d*)?px$/);d?a.attributes[c]=d[1]:\"cke-test\"==e&&(a.attributes[c]=\"cke-test\")}delete a.styles[b]},alignmentToStyle:function(a){if(!(\"float\"in a.styles)){var b=a.attributes.align;if(\"left\"==b||\"right\"==b)a.styles[\"float\"]=b}delete a.attributes.align},alignmentToAttribute:function(a){if(!(\"align\"in a.attributes)){var b=a.styles[\"float\"];if(\"left\"==b||\"right\"==b)a.attributes.align=b}delete a.styles[\"float\"]},\nsplitBorderShorthand:function(a){if(a.styles.border){var b=CKEDITOR.tools.style.parse.border(a.styles.border);b.color&&(a.styles[\"border-color\"]=b.color);b.style&&(a.styles[\"border-style\"]=b.style);b.width&&(a.styles[\"border-width\"]=b.width);delete a.styles.border}},listTypeToStyle:function(a){if(a.attributes.type)switch(a.attributes.type){case \"a\":a.styles[\"list-style-type\"]=\"lower-alpha\";break;case \"A\":a.styles[\"list-style-type\"]=\"upper-alpha\";break;case \"i\":a.styles[\"list-style-type\"]=\"lower-roman\";\nbreak;case \"I\":a.styles[\"list-style-type\"]=\"upper-roman\";break;case \"1\":a.styles[\"list-style-type\"]=\"decimal\";break;default:a.styles[\"list-style-type\"]=a.attributes.type}},splitMarginShorthand:function(a){function b(e){a.styles[\"margin-top\"]=c[e[0]];a.styles[\"margin-right\"]=c[e[1]];a.styles[\"margin-bottom\"]=c[e[2]];a.styles[\"margin-left\"]=c[e[3]]}if(a.styles.margin){var c=a.styles.margin.match(/(\\-?[\\.\\d]+\\w+)/g)||[\"0px\"];switch(c.length){case 1:b([0,0,0,0]);break;case 2:b([0,1,0,1]);break;case 3:b([0,\n1,2,1]);break;case 4:b([0,1,2,3])}delete a.styles.margin}},matchesStyle:A,transform:function(a,b){if(\"string\"==typeof b)a.name=b;else{var c=b.getDefinition(),e=c.styles,d=c.attributes,g,h,f,m;a.name=c.element;for(g in d)if(\"class\"==g)for(c=a.classes.join(\"|\"),f=d[g].split(/\\s+/);m=f.pop();)-1==c.indexOf(m)&&a.classes.push(m);else a.attributes[g]=d[g];for(h in e)a.styles[h]=e[h]}}}}(),function(){CKEDITOR.focusManager=function(a){if(a.focusManager)return a.focusManager;this.hasFocus=!1;this.currentActive=\nnull;this._={editor:a};return this};CKEDITOR.focusManager._={blurDelay:200};CKEDITOR.focusManager.prototype={focus:function(a){this._.timer&&clearTimeout(this._.timer);a&&(this.currentActive=a);this.hasFocus||this._.locked||((a=CKEDITOR.currentInstance)&&a.focusManager.blur(1),this.hasFocus=!0,(a=this._.editor.container)&&a.addClass(\"cke_focus\"),this._.editor.fire(\"focus\"))},lock:function(){this._.locked=1},unlock:function(){delete this._.locked},blur:function(a){function f(){if(this.hasFocus){this.hasFocus=\n!1;var a=this._.editor.container;a&&a.removeClass(\"cke_focus\");this._.editor.fire(\"blur\")}}if(!this._.locked){this._.timer&&clearTimeout(this._.timer);var b=CKEDITOR.focusManager._.blurDelay;a||!b?f.call(this):this._.timer=CKEDITOR.tools.setTimeout(function(){delete this._.timer;f.call(this)},b,this)}},add:function(a,f){var b=a.getCustomData(\"focusmanager\");if(!b||b!=this){b&&b.remove(a);var b=\"focus\",c=\"blur\";f&&(CKEDITOR.env.ie?(b=\"focusin\",c=\"focusout\"):CKEDITOR.event.useCapture=1);var d={blur:function(){a.equals(this.currentActive)&&\nthis.blur()},focus:function(){this.focus(a)}};a.on(b,d.focus,this);a.on(c,d.blur,this);f&&(CKEDITOR.event.useCapture=0);a.setCustomData(\"focusmanager\",this);a.setCustomData(\"focusmanager_handlers\",d)}},remove:function(a){a.removeCustomData(\"focusmanager\");var f=a.removeCustomData(\"focusmanager_handlers\");a.removeListener(\"blur\",f.blur);a.removeListener(\"focus\",f.focus)}}}(),CKEDITOR.keystrokeHandler=function(a){if(a.keystrokeHandler)return a.keystrokeHandler;this.keystrokes={};this.blockedKeystrokes=\n{};this._={editor:a};return this},function(){var a,f=function(b){b=b.data;var d=b.getKeystroke(),f=this.keystrokes[d],k=this._.editor;a=!1===k.fire(\"key\",{keyCode:d,domEvent:b});a||(f&&(a=!1!==k.execCommand(f,{from:\"keystrokeHandler\"})),a||(a=!!this.blockedKeystrokes[d]));a&&b.preventDefault(!0);return!a},b=function(b){a&&(a=!1,b.data.preventDefault(!0))};CKEDITOR.keystrokeHandler.prototype={attach:function(a){a.on(\"keydown\",f,this);if(CKEDITOR.env.gecko&&CKEDITOR.env.mac)a.on(\"keypress\",b,this)}}}(),\nfunction(){CKEDITOR.lang={languages:{af:1,ar:1,az:1,bg:1,bn:1,bs:1,ca:1,cs:1,cy:1,da:1,de:1,\"de-ch\":1,el:1,\"en-au\":1,\"en-ca\":1,\"en-gb\":1,en:1,eo:1,es:1,\"es-mx\":1,et:1,eu:1,fa:1,fi:1,fo:1,\"fr-ca\":1,fr:1,gl:1,gu:1,he:1,hi:1,hr:1,hu:1,id:1,is:1,it:1,ja:1,ka:1,km:1,ko:1,ku:1,lt:1,lv:1,mk:1,mn:1,ms:1,nb:1,nl:1,no:1,oc:1,pl:1,\"pt-br\":1,pt:1,ro:1,ru:1,si:1,sk:1,sl:1,sq:1,\"sr-latn\":1,sr:1,sv:1,th:1,tr:1,tt:1,ug:1,uk:1,vi:1,\"zh-cn\":1,zh:1},rtl:{ar:1,fa:1,he:1,ku:1,ug:1},load:function(a,f,b){a&&CKEDITOR.lang.languages[a]||\n(a=this.detect(f,a));var c=this;f=function(){c[a].dir=c.rtl[a]?\"rtl\":\"ltr\";b(a,c[a])};this[a]?f():CKEDITOR.scriptLoader.load(CKEDITOR.getUrl(\"lang/\"+a+\".js\"),f,this)},detect:function(a,f){var b=this.languages;f=f||navigator.userLanguage||navigator.language||a;var c=f.toLowerCase().match(/([a-z]+)(?:-([a-z]+))?/),d=c[1],c=c[2];b[d+\"-\"+c]?d=d+\"-\"+c:b[d]||(d=null);CKEDITOR.lang.detect=d?function(){return d}:function(a){return a};return d||a}}}(),CKEDITOR.scriptLoader=function(){var a={},f={};return{load:function(b,\nc,d,l){var k=\"string\"==typeof b;k&&(b=[b]);d||(d=CKEDITOR);var g=b.length,h=[],m=[],e=function(a){c&&(k?c.call(d,a):c.call(d,h,m))};if(0===g)e(!0);else{var n=function(a,b){(b?h:m).push(a);0>=--g&&(l&&CKEDITOR.document.getDocumentElement().removeStyle(\"cursor\"),e(b))},q=function(b,c){a[b]=1;var e=f[b];delete f[b];for(var d=0;d<e.length;d++)e[d](b,c)},y=function(b){if(a[b])n(b,!0);else{var e=f[b]||(f[b]=[]);e.push(n);if(!(1<e.length)){var d=new CKEDITOR.dom.element(\"script\");d.setAttributes({type:\"text/javascript\",\nsrc:b});c&&(CKEDITOR.env.ie&&(8>=CKEDITOR.env.version||CKEDITOR.env.ie9Compat)?d.$.onreadystatechange=function(){if(\"loaded\"==d.$.readyState||\"complete\"==d.$.readyState)d.$.onreadystatechange=null,q(b,!0)}:(d.$.onload=function(){setTimeout(function(){d.$.onload=null;d.$.onerror=null;q(b,!0)},0)},d.$.onerror=function(){d.$.onload=null;d.$.onerror=null;q(b,!1)}));d.appendTo(CKEDITOR.document.getHead())}}};l&&CKEDITOR.document.getDocumentElement().setStyle(\"cursor\",\"wait\");for(var u=0;u<g;u++)y(b[u])}},\nqueue:function(){function a(){var b;(b=c[0])&&this.load(b.scriptUrl,b.callback,CKEDITOR,0)}var c=[];return function(d,f){var k=this;c.push({scriptUrl:d,callback:function(){f&&f.apply(this,arguments);c.shift();a.call(k)}});1==c.length&&a.call(this)}}()}}(),CKEDITOR.resourceManager=function(a,f){this.basePath=a;this.fileName=f;this.registered={};this.loaded={};this.externals={};this._={waitingList:{}}},CKEDITOR.resourceManager.prototype={add:function(a,f){if(this.registered[a])throw Error('[CKEDITOR.resourceManager.add] The resource name \"'+\na+'\" is already registered.');var b=this.registered[a]=f||{};b.name=a;b.path=this.getPath(a);CKEDITOR.fire(a+CKEDITOR.tools.capitalize(this.fileName)+\"Ready\",b);return this.get(a)},get:function(a){return this.registered[a]||null},getPath:function(a){var f=this.externals[a];return CKEDITOR.getUrl(f&&f.dir||this.basePath+a+\"/\")},getFilePath:function(a){var f=this.externals[a];return CKEDITOR.getUrl(this.getPath(a)+(f?f.file:this.fileName+\".js\"))},addExternal:function(a,f,b){a=a.split(\",\");for(var c=\n0;c<a.length;c++){var d=a[c];b||(f=f.replace(/[^\\/]+$/,function(a){b=a;return\"\"}));this.externals[d]={dir:f,file:b||this.fileName+\".js\"}}},load:function(a,f,b){CKEDITOR.tools.isArray(a)||(a=a?[a]:[]);for(var c=this.loaded,d=this.registered,l=[],k={},g={},h=0;h<a.length;h++){var m=a[h];if(m)if(c[m]||d[m])g[m]=this.get(m);else{var e=this.getFilePath(m);l.push(e);e in k||(k[e]=[]);k[e].push(m)}}CKEDITOR.scriptLoader.load(l,function(a,e){if(e.length)throw Error('[CKEDITOR.resourceManager.load] Resource name \"'+\nk[e[0]].join(\",\")+'\" was not found at \"'+e[0]+'\".');for(var d=0;d<a.length;d++)for(var h=k[a[d]],m=0;m<h.length;m++){var l=h[m];g[l]=this.get(l);c[l]=1}f.call(b,g)},this)}},CKEDITOR.plugins=new CKEDITOR.resourceManager(\"plugins/\",\"plugin\"),CKEDITOR.plugins.load=CKEDITOR.tools.override(CKEDITOR.plugins.load,function(a){var f={};return function(b,c,d){var l={},k=function(b){a.call(this,b,function(a){CKEDITOR.tools.extend(l,a);var b=[],e;for(e in a){var g=a[e],q=g&&g.requires;if(!f[e]){if(g.icons)for(var y=\ng.icons.split(\",\"),u=y.length;u--;)CKEDITOR.skin.addIcon(y[u],g.path+\"icons/\"+(CKEDITOR.env.hidpi&&g.hidpi?\"hidpi/\":\"\")+y[u]+\".png\");g.isSupportedEnvironment=g.isSupportedEnvironment||function(){return!0};f[e]=1}if(q)for(q.split&&(q=q.split(\",\")),g=0;g<q.length;g++)l[q[g]]||b.push(q[g])}if(b.length)k.call(this,b);else{for(e in l)g=l[e],g.onLoad&&!g.onLoad._called&&(!1===g.onLoad()&&delete l[e],g.onLoad._called=1);c&&c.call(d||window,l)}},this)};k.call(this,b)}}),CKEDITOR.plugins.setLang=function(a,\nf,b){var c=this.get(a);a=c.langEntries||(c.langEntries={});c=c.lang||(c.lang=[]);c.split&&(c=c.split(\",\"));-1==CKEDITOR.tools.indexOf(c,f)&&c.push(f);a[f]=b},CKEDITOR.ui=function(a){if(a.ui)return a.ui;this.items={};this.instances={};this.editor=a;this._={handlers:{}};return this},CKEDITOR.ui.prototype={add:function(a,f,b){b.name=a.toLowerCase();var c=this.items[a]={type:f,command:b.command||null,args:Array.prototype.slice.call(arguments,2)};CKEDITOR.tools.extend(c,b)},get:function(a){return this.instances[a]},\ncreate:function(a){var f=this.items[a],b=f&&this._.handlers[f.type],c=f&&f.command&&this.editor.getCommand(f.command),b=b&&b.create.apply(this,f.args);this.instances[a]=b;c&&c.uiItems.push(b);b&&!b.type&&(b.type=f.type);return b},addHandler:function(a,f){this._.handlers[a]=f},space:function(a){return CKEDITOR.document.getById(this.spaceId(a))},spaceId:function(a){return this.editor.id+\"_\"+a}},CKEDITOR.event.implementOn(CKEDITOR.ui),function(){function a(a,e,d){CKEDITOR.event.call(this);a=a&&CKEDITOR.tools.clone(a);\nif(void 0!==e){if(!(e instanceof CKEDITOR.dom.element))throw Error(\"Expect element of type CKEDITOR.dom.element.\");if(!d)throw Error(\"One of the element modes must be specified.\");if(CKEDITOR.env.ie&&CKEDITOR.env.quirks&&d==CKEDITOR.ELEMENT_MODE_INLINE)throw Error(\"Inline element mode is not supported on IE quirks.\");if(!b(e,d))throw Error('The specified element mode is not supported on element: \"'+e.getName()+'\".');this.element=e;this.elementMode=d;this.name=this.elementMode!=CKEDITOR.ELEMENT_MODE_APPENDTO&&\n(e.getId()||e.getNameAtt())}else this.elementMode=CKEDITOR.ELEMENT_MODE_NONE;this._={};this.commands={};this.templates={};this.name=this.name||f();this.id=CKEDITOR.tools.getNextId();this.status=\"unloaded\";this.config=CKEDITOR.tools.prototypedCopy(CKEDITOR.config);this.ui=new CKEDITOR.ui(this);this.focusManager=new CKEDITOR.focusManager(this);this.keystrokeHandler=new CKEDITOR.keystrokeHandler(this);this.on(\"readOnly\",c);this.on(\"selectionChange\",function(a){l(this,a.data.path)});this.on(\"activeFilterChange\",\nfunction(){l(this,this.elementPath(),!0)});this.on(\"mode\",c);this.on(\"instanceReady\",function(){if(this.config.startupFocus){if(\"end\"===this.config.startupFocus){var a=this.createRange();a.selectNodeContents(this.editable());a.shrink(CKEDITOR.SHRINK_ELEMENT,!0);a.collapse();this.getSelection().selectRanges([a])}this.focus()}});CKEDITOR.fire(\"instanceCreated\",null,this);CKEDITOR.add(this);CKEDITOR.tools.setTimeout(function(){\"destroyed\"!==this.status?g(this,a):CKEDITOR.warn(\"editor-incorrect-destroy\")},\n0,this)}function f(){do var a=\"editor\"+ ++u;while(CKEDITOR.instances[a]);return a}function b(a,b){return b==CKEDITOR.ELEMENT_MODE_INLINE?a.is(CKEDITOR.dtd.$editable)||a.is(\"textarea\"):b==CKEDITOR.ELEMENT_MODE_REPLACE?!a.is(CKEDITOR.dtd.$nonBodyContent):1}function c(){var a=this.commands,b;for(b in a)d(this,a[b])}function d(a,b){b[b.startDisabled?\"disable\":a.readOnly&&!b.readOnly?\"disable\":b.modes[a.mode]?\"enable\":\"disable\"]()}function l(a,b,c){if(b){var e,d,g=a.commands;for(d in g)e=g[d],(c||e.contextSensitive)&&\ne.refresh(a,b)}}function k(a){var b=a.config.customConfig;if(!b)return!1;var b=CKEDITOR.getUrl(b),c=p[b]||(p[b]={});c.fn?(c.fn.call(a,a.config),CKEDITOR.getUrl(a.config.customConfig)!=b&&k(a)||a.fireOnce(\"customConfigLoaded\")):CKEDITOR.scriptLoader.queue(b,function(){c.fn=CKEDITOR.editorConfig?CKEDITOR.editorConfig:function(){};k(a)});return!0}function g(a,b){a.on(\"customConfigLoaded\",function(){if(b){if(b.on)for(var c in b.on)a.on(c,b.on[c]);CKEDITOR.tools.extend(a.config,b,!0);delete a.config.on}c=\na.config;a.readOnly=c.readOnly?!0:a.elementMode==CKEDITOR.ELEMENT_MODE_INLINE?a.element.is(\"textarea\")?a.element.hasAttribute(\"disabled\")||a.element.hasAttribute(\"readonly\"):a.element.isReadOnly():a.elementMode==CKEDITOR.ELEMENT_MODE_REPLACE?a.element.hasAttribute(\"disabled\")||a.element.hasAttribute(\"readonly\"):!1;a.blockless=a.elementMode==CKEDITOR.ELEMENT_MODE_INLINE?!(a.element.is(\"textarea\")||CKEDITOR.dtd[a.element.getName()].p):!1;a.tabIndex=c.tabIndex||a.element&&a.element.getAttribute(\"tabindex\")||\n0;a.activeEnterMode=a.enterMode=a.blockless?CKEDITOR.ENTER_BR:c.enterMode;a.activeShiftEnterMode=a.shiftEnterMode=a.blockless?CKEDITOR.ENTER_BR:c.shiftEnterMode;c.skin&&(CKEDITOR.skinName=c.skin);a.fireOnce(\"configLoaded\");a.dataProcessor=new CKEDITOR.htmlDataProcessor(a);a.filter=a.activeFilter=new CKEDITOR.filter(a);h(a)});b&&null!=b.customConfig&&(a.config.customConfig=b.customConfig);k(a)||a.fireOnce(\"customConfigLoaded\")}function h(a){CKEDITOR.skin.loadPart(\"editor\",function(){m(a)})}function m(a){CKEDITOR.lang.load(a.config.language,\na.config.defaultLanguage,function(b,c){var d=a.config.title;a.langCode=b;a.lang=CKEDITOR.tools.prototypedCopy(c);a.title=\"string\"==typeof d||!1===d?d:[a.lang.editor,a.name].join(\", \");a.config.contentsLangDirection||(a.config.contentsLangDirection=a.elementMode==CKEDITOR.ELEMENT_MODE_INLINE?a.element.getDirection(1):a.lang.dir);a.fire(\"langLoaded\");e(a)})}function e(a){a.getStylesSet(function(b){a.once(\"loaded\",function(){a.fire(\"stylesSet\",{styles:b})},null,null,1);n(a)})}function n(a){function b(a){if(!a)return\"\";\nCKEDITOR.tools.isArray(a)&&(a=a.join(\",\"));return a.replace(/\\s/g,\"\")}var c=a.config,e=b(c.plugins),d=b(c.extraPlugins),g=b(c.removePlugins);if(d)var h=new RegExp(\"(?:^|,)(?:\"+d.replace(/,/g,\"|\")+\")(?\\x3d,|$)\",\"g\"),e=e.replace(h,\"\"),e=e+(\",\"+d);if(g)var f=new RegExp(\"(?:^|,)(?:\"+g.replace(/,/g,\"|\")+\")(?\\x3d,|$)\",\"g\"),e=e.replace(f,\"\");CKEDITOR.env.air&&(e+=\",adobeair\");CKEDITOR.plugins.load(e.split(\",\"),function(b){var e=[],d=[],g=[];a.plugins=CKEDITOR.tools.extend({},a.plugins,b);for(var h in b){var m=\nb[h],l=m.lang,k=null,n=m.requires,x;CKEDITOR.tools.isArray(n)&&(n=n.join(\",\"));if(n&&(x=n.match(f)))for(;n=x.pop();)CKEDITOR.error(\"editor-plugin-required\",{plugin:n.replace(\",\",\"\"),requiredBy:h});l&&!a.lang[h]&&(l.split&&(l=l.split(\",\")),0<=CKEDITOR.tools.indexOf(l,a.langCode)?k=a.langCode:(k=a.langCode.replace(/-.*/,\"\"),k=k!=a.langCode&&0<=CKEDITOR.tools.indexOf(l,k)?k:0<=CKEDITOR.tools.indexOf(l,\"en\")?\"en\":l[0]),m.langEntries&&m.langEntries[k]?(a.lang[h]=m.langEntries[k],k=null):g.push(CKEDITOR.getUrl(m.path+\n\"lang/\"+k+\".js\")));d.push(k);e.push(m)}CKEDITOR.scriptLoader.load(g,function(){for(var b=[\"beforeInit\",\"init\",\"afterInit\"],g=0;g<b.length;g++)for(var h=0;h<e.length;h++){var f=e[h];0===g&&d[h]&&f.lang&&f.langEntries&&(a.lang[f.name]=f.langEntries[d[h]]);if(f[b[g]])f[b[g]](a)}a.fireOnce(\"pluginsLoaded\");c.keystrokes&&a.setKeystroke(a.config.keystrokes);for(h=0;h<a.config.blockedKeystrokes.length;h++)a.keystrokeHandler.blockedKeystrokes[a.config.blockedKeystrokes[h]]=1;a.status=\"loaded\";a.fireOnce(\"loaded\");\nCKEDITOR.fire(\"instanceLoaded\",null,a)})})}function q(){var a=this.element;if(a&&this.elementMode!=CKEDITOR.ELEMENT_MODE_APPENDTO){var b=this.getData();this.config.htmlEncodeOutput&&(b=CKEDITOR.tools.htmlEncode(b));a.is(\"textarea\")?a.setValue(b):a.setHtml(b);return!0}return!1}function y(a,b){function c(a){var b=a.startContainer,e=a.endContainer;return b.is&&(b.is(\"tr\")||b.is(\"td\")&&b.equals(e)&&a.endOffset===b.getChildCount())?!0:!1}function e(a){var b=a.startContainer;return b.is(\"tr\")?a.cloneContents():\nb.clone(!0)}for(var d=new CKEDITOR.dom.documentFragment,g,h,f,m=0;m<a.length;m++){var l=a[m],k=l.startContainer.getAscendant(\"tr\",!0);c(l)?(g||(g=k.getAscendant(\"table\").clone(),g.append(k.getAscendant({thead:1,tbody:1,tfoot:1}).clone()),d.append(g),g=g.findOne(\"thead, tbody, tfoot\")),h&&h.equals(k)||(h=k,f=k.clone(),g.append(f)),f.append(e(l))):d.append(l.cloneContents())}return g?d:b.getHtmlFromRange(a[0])}a.prototype=CKEDITOR.editor.prototype;CKEDITOR.editor=a;var u=0,p={};CKEDITOR.tools.extend(CKEDITOR.editor.prototype,\n{plugins:{detectConflict:function(a,b){for(var c=0;c<b.length;c++){var e=b[c];if(this[e])return CKEDITOR.warn(\"editor-plugin-conflict\",{plugin:a,replacedWith:e}),!0}return!1}},addCommand:function(a,b){b.name=a.toLowerCase();var c=b instanceof CKEDITOR.command?b:new CKEDITOR.command(this,b);this.mode&&d(this,c);return this.commands[a]=c},_attachToForm:function(){function a(b){c.updateElement();c._.required&&!e.getValue()&&!1===c.fire(\"required\")&&b.data.preventDefault()}function b(a){return!!(a&&a.call&&\na.apply)}var c=this,e=c.element,d=new CKEDITOR.dom.element(e.$.form);e.is(\"textarea\")&&d&&(d.on(\"submit\",a),b(d.$.submit)&&(d.$.submit=CKEDITOR.tools.override(d.$.submit,function(b){return function(){a();b.apply?b.apply(this):b()}})),c.on(\"destroy\",function(){d.removeListener(\"submit\",a)}))},destroy:function(a){var b=CKEDITOR.filter.instances,c=this;this.fire(\"beforeDestroy\");!a&&q.call(this);this.editable(null);this.filter&&delete this.filter;CKEDITOR.tools.array.forEach(CKEDITOR.tools.object.keys(b),\nfunction(a){a=b[a];c===a.editor&&a.destroy()});delete this.activeFilter;this.status=\"destroyed\";this.fire(\"destroy\");this.removeAllListeners();CKEDITOR.remove(this);CKEDITOR.fire(\"instanceDestroyed\",null,this)},elementPath:function(a){if(!a){a=this.getSelection();if(!a)return null;a=a.getStartElement()}return a?new CKEDITOR.dom.elementPath(a,this.editable()):null},createRange:function(){var a=this.editable();return a?new CKEDITOR.dom.range(a):null},execCommand:function(a,b){var c=this.getCommand(a),\ne={name:a,commandData:b||{},command:c};return c&&c.state!=CKEDITOR.TRISTATE_DISABLED&&!1!==this.fire(\"beforeCommandExec\",e)&&(e.returnValue=c.exec(e.commandData),!c.async&&!1!==this.fire(\"afterCommandExec\",e))?e.returnValue:!1},getCommand:function(a){return this.commands[a]},getData:function(a){!a&&this.fire(\"beforeGetData\");var b=this._.data;\"string\"!=typeof b&&(b=(b=this.element)&&this.elementMode==CKEDITOR.ELEMENT_MODE_REPLACE?b.is(\"textarea\")?b.getValue():b.getHtml():\"\");b={dataValue:b};!a&&this.fire(\"getData\",\nb);return b.dataValue},getSnapshot:function(){var a=this.fire(\"getSnapshot\");\"string\"!=typeof a&&(a=(a=this.element)&&this.elementMode==CKEDITOR.ELEMENT_MODE_REPLACE?a.is(\"textarea\")?a.getValue():a.getHtml():\"\");return a},loadSnapshot:function(a){this.fire(\"loadSnapshot\",a)},setData:function(a,b,c){var e=!0,d=b;b&&\"object\"==typeof b&&(c=b.internal,d=b.callback,e=!b.noSnapshot);!c&&e&&this.fire(\"saveSnapshot\");if(d||!c)this.once(\"dataReady\",function(a){!c&&e&&this.fire(\"saveSnapshot\");d&&d.call(a.editor)});\na={dataValue:a};!c&&this.fire(\"setData\",a);this._.data=a.dataValue;!c&&this.fire(\"afterSetData\",a)},setReadOnly:function(a){a=null==a||a;this.readOnly!=a&&(this.readOnly=a,this.keystrokeHandler.blockedKeystrokes[8]=+a,this.editable().setReadOnly(a),this.fire(\"readOnly\"))},insertHtml:function(a,b,c){this.fire(\"insertHtml\",{dataValue:a,mode:b,range:c})},insertText:function(a){this.fire(\"insertText\",a)},insertElement:function(a){this.fire(\"insertElement\",a)},getSelectedHtml:function(a){var b=this.editable(),\nc=this.getSelection(),c=c&&c.getRanges();if(!b||!c||0===c.length)return null;b=y(c,b);return a?b.getHtml():b},extractSelectedHtml:function(a,b){var c=this.editable(),e=this.getSelection().getRanges(),d=new CKEDITOR.dom.documentFragment,g;if(!c||0===e.length)return null;for(g=0;g<e.length;g++)d.append(c.extractHtmlFromRange(e[g],b));b||this.getSelection().selectRanges([e[0]]);return a?d.getHtml():d},focus:function(){this.fire(\"beforeFocus\")},checkDirty:function(){return\"ready\"==this.status&&this._.previousValue!==\nthis.getSnapshot()},resetDirty:function(){this._.previousValue=this.getSnapshot()},updateElement:function(){return q.call(this)},setKeystroke:function(){for(var a=this.keystrokeHandler.keystrokes,b=CKEDITOR.tools.isArray(arguments[0])?arguments[0]:[[].slice.call(arguments,0)],c,e,d=b.length;d--;)c=b[d],e=0,CKEDITOR.tools.isArray(c)&&(e=c[1],c=c[0]),e?a[c]=e:delete a[c]},getCommandKeystroke:function(a,b){var c=\"string\"===typeof a?this.getCommand(a):a,e=[];if(c){var d=CKEDITOR.tools.object.findKey(this.commands,\nc),g=this.keystrokeHandler.keystrokes;if(c.fakeKeystroke)e.push(c.fakeKeystroke);else for(var h in g)g[h]===d&&e.push(h)}return b?e:e[0]||null},addFeature:function(a){return this.filter.addFeature(a)},setActiveFilter:function(a){a||(a=this.filter);this.activeFilter!==a&&(this.activeFilter=a,this.fire(\"activeFilterChange\"),a===this.filter?this.setActiveEnterMode(null,null):this.setActiveEnterMode(a.getAllowedEnterMode(this.enterMode),a.getAllowedEnterMode(this.shiftEnterMode,!0)))},setActiveEnterMode:function(a,\nb){a=a?this.blockless?CKEDITOR.ENTER_BR:a:this.enterMode;b=b?this.blockless?CKEDITOR.ENTER_BR:b:this.shiftEnterMode;if(this.activeEnterMode!=a||this.activeShiftEnterMode!=b)this.activeEnterMode=a,this.activeShiftEnterMode=b,this.fire(\"activeEnterModeChange\")},showNotification:function(a){alert(a)}});CKEDITOR.editor._getEditorElement=function(a){if(!CKEDITOR.env.isCompatible)return null;var b=CKEDITOR.dom.element.get(a);return b?b.getEditor()?(CKEDITOR.error(\"editor-element-conflict\",{editorName:b.getEditor().name}),\nnull):b:(CKEDITOR.error(\"editor-incorrect-element\",{element:a}),null)}}(),CKEDITOR.ELEMENT_MODE_NONE=0,CKEDITOR.ELEMENT_MODE_REPLACE=1,CKEDITOR.ELEMENT_MODE_APPENDTO=2,CKEDITOR.ELEMENT_MODE_INLINE=3,CKEDITOR.htmlParser=function(){this._={htmlPartsRegex:/<(?:(?:\\/([^>]+)>)|(?:!--([\\S|\\s]*?)--\\x3e)|(?:([^\\/\\s>]+)((?:\\s+[\\w\\-:.]+(?:\\s*=\\s*?(?:(?:\"[^\"]*\")|(?:'[^']*')|[^\\s\"'\\/>]+))?)*)[\\S\\s]*?(\\/?)>))/g}},function(){var a=/([\\w\\-:.]+)(?:(?:\\s*=\\s*(?:(?:\"([^\"]*)\")|(?:'([^']*)')|([^\\s>]+)))|(?=\\s|$))/g,\nf={checked:1,compact:1,declare:1,defer:1,disabled:1,ismap:1,multiple:1,nohref:1,noresize:1,noshade:1,nowrap:1,readonly:1,selected:1};CKEDITOR.htmlParser.prototype={onTagOpen:function(){},onTagClose:function(){},onText:function(){},onCDATA:function(){},onComment:function(){},parse:function(b){for(var c,d,l=0,k;c=this._.htmlPartsRegex.exec(b);){d=c.index;if(d>l)if(l=b.substring(l,d),k)k.push(l);else this.onText(l);l=this._.htmlPartsRegex.lastIndex;if(d=c[1])if(d=d.toLowerCase(),k&&CKEDITOR.dtd.$cdata[d]&&\n(this.onCDATA(k.join(\"\")),k=null),!k){this.onTagClose(d);continue}if(k)k.push(c[0]);else if(d=c[3]){if(d=d.toLowerCase(),!/=\"/.test(d)){var g={},h,m=c[4];c=!!c[5];if(m)for(;h=a.exec(m);){var e=h[1].toLowerCase();h=h[2]||h[3]||h[4]||\"\";g[e]=!h&&f[e]?e:CKEDITOR.tools.htmlDecodeAttr(h)}this.onTagOpen(d,g,c);!k&&CKEDITOR.dtd.$cdata[d]&&(k=[])}}else if(d=c[2])this.onComment(d)}if(b.length>l)this.onText(b.substring(l,b.length))}}}(),CKEDITOR.htmlParser.basicWriter=CKEDITOR.tools.createClass({$:function(){this._=\n{output:[]}},proto:{openTag:function(a){this._.output.push(\"\\x3c\",a)},openTagClose:function(a,f){f?this._.output.push(\" /\\x3e\"):this._.output.push(\"\\x3e\")},attribute:function(a,f){\"string\"==typeof f&&(f=CKEDITOR.tools.htmlEncodeAttr(f));this._.output.push(\" \",a,'\\x3d\"',f,'\"')},closeTag:function(a){this._.output.push(\"\\x3c/\",a,\"\\x3e\")},text:function(a){this._.output.push(a)},comment:function(a){this._.output.push(\"\\x3c!--\",a,\"--\\x3e\")},write:function(a){this._.output.push(a)},reset:function(){this._.output=\n[];this._.indent=!1},getHtml:function(a){var f=this._.output.join(\"\");a&&this.reset();return f}}}),\"use strict\",function(){CKEDITOR.htmlParser.node=function(){};CKEDITOR.htmlParser.node.prototype={remove:function(){var a=this.parent.children,f=CKEDITOR.tools.indexOf(a,this),b=this.previous,c=this.next;b&&(b.next=c);c&&(c.previous=b);a.splice(f,1);this.parent=null},replaceWith:function(a){var f=this.parent.children,b=CKEDITOR.tools.indexOf(f,this),c=a.previous=this.previous,d=a.next=this.next;c&&(c.next=\na);d&&(d.previous=a);f[b]=a;a.parent=this.parent;this.parent=null},insertAfter:function(a){var f=a.parent.children,b=CKEDITOR.tools.indexOf(f,a),c=a.next;f.splice(b+1,0,this);this.next=a.next;this.previous=a;a.next=this;c&&(c.previous=this);this.parent=a.parent},insertBefore:function(a){var f=a.parent.children,b=CKEDITOR.tools.indexOf(f,a);f.splice(b,0,this);this.next=a;(this.previous=a.previous)&&(a.previous.next=this);a.previous=this;this.parent=a.parent},getAscendant:function(a){var f=\"function\"==\ntypeof a?a:\"string\"==typeof a?function(b){return b.name==a}:function(b){return b.name in a},b=this.parent;for(;b&&b.type==CKEDITOR.NODE_ELEMENT;){if(f(b))return b;b=b.parent}return null},wrapWith:function(a){this.replaceWith(a);a.add(this);return a},getIndex:function(){return CKEDITOR.tools.indexOf(this.parent.children,this)},getFilterContext:function(a){return a||{}}}}(),\"use strict\",CKEDITOR.htmlParser.comment=function(a){this.value=a;this._={isBlockLike:!1}},CKEDITOR.htmlParser.comment.prototype=\nCKEDITOR.tools.extend(new CKEDITOR.htmlParser.node,{type:CKEDITOR.NODE_COMMENT,filter:function(a,f){var b=this.value;if(!(b=a.onComment(f,b,this)))return this.remove(),!1;if(\"string\"!=typeof b)return this.replaceWith(b),!1;this.value=b;return!0},writeHtml:function(a,f){f&&this.filter(f);a.comment(this.value)}}),\"use strict\",function(){CKEDITOR.htmlParser.text=function(a){this.value=a;this._={isBlockLike:!1}};CKEDITOR.htmlParser.text.prototype=CKEDITOR.tools.extend(new CKEDITOR.htmlParser.node,{type:CKEDITOR.NODE_TEXT,\nfilter:function(a,f){if(!(this.value=a.onText(f,this.value,this)))return this.remove(),!1},writeHtml:function(a,f){f&&this.filter(f);a.text(this.value)}})}(),\"use strict\",function(){CKEDITOR.htmlParser.cdata=function(a){this.value=a};CKEDITOR.htmlParser.cdata.prototype=CKEDITOR.tools.extend(new CKEDITOR.htmlParser.node,{type:CKEDITOR.NODE_TEXT,filter:function(){},writeHtml:function(a){a.write(this.value)}})}(),\"use strict\",CKEDITOR.htmlParser.fragment=function(){this.children=[];this.parent=null;\nthis._={isBlockLike:!0,hasInlineStarted:!1}},function(){function a(a){return a.attributes[\"data-cke-survive\"]?!1:\"a\"==a.name&&a.attributes.href||CKEDITOR.dtd.$removeEmpty[a.name]}var f=CKEDITOR.tools.extend({table:1,ul:1,ol:1,dl:1},CKEDITOR.dtd.table,CKEDITOR.dtd.ul,CKEDITOR.dtd.ol,CKEDITOR.dtd.dl),b={ol:1,ul:1},c=CKEDITOR.tools.extend({},{html:1},CKEDITOR.dtd.html,CKEDITOR.dtd.body,CKEDITOR.dtd.head,{style:1,script:1}),d={ul:\"li\",ol:\"li\",dl:\"dd\",table:\"tbody\",tbody:\"tr\",thead:\"tr\",tfoot:\"tr\",tr:\"td\"};\nCKEDITOR.htmlParser.fragment.fromHtml=function(l,k,g){function h(a){var b;if(0<v.length)for(var c=0;c<v.length;c++){var e=v[c],d=e.name,g=CKEDITOR.dtd[d],h=r.name&&CKEDITOR.dtd[r.name];h&&!h[d]||a&&g&&!g[a]&&CKEDITOR.dtd[a]?d==r.name&&(n(r,r.parent,1),c--):(b||(m(),b=1),e=e.clone(),e.parent=r,r=e,v.splice(c,1),c--)}}function m(){for(;w.length;)n(w.shift(),r)}function e(a){if(a._.isBlockLike&&\"pre\"!=a.name&&\"textarea\"!=a.name){var b=a.children.length,c=a.children[b-1],e;c&&c.type==CKEDITOR.NODE_TEXT&&\n((e=CKEDITOR.tools.rtrim(c.value))?c.value=e:a.children.length=b-1)}}function n(b,c,d){c=c||r||p;var h=r;void 0===b.previous&&(q(c,b)&&(r=c,u.onTagOpen(g,{}),b.returnPoint=c=r),e(b),a(b)&&!b.children.length||c.add(b),\"pre\"==b.name&&(t=!1),\"textarea\"==b.name&&(z=!1));b.returnPoint?(r=b.returnPoint,delete b.returnPoint):r=d?c:h}function q(a,b){if((a==p||\"body\"==a.name)&&g&&(!a.name||CKEDITOR.dtd[a.name][g])){var c,e;return(c=b.attributes&&(e=b.attributes[\"data-cke-real-element-type\"])?e:b.name)&&c in\nCKEDITOR.dtd.$inline&&!(c in CKEDITOR.dtd.head)&&!b.isOrphan||b.type==CKEDITOR.NODE_TEXT}}function y(a,b){return a in CKEDITOR.dtd.$listItem||a in CKEDITOR.dtd.$tableContent?a==b||\"dt\"==a&&\"dd\"==b||\"dd\"==a&&\"dt\"==b:!1}var u=new CKEDITOR.htmlParser,p=k instanceof CKEDITOR.htmlParser.element?k:\"string\"==typeof k?new CKEDITOR.htmlParser.element(k):new CKEDITOR.htmlParser.fragment,v=[],w=[],r=p,z=\"textarea\"==p.name,t=\"pre\"==p.name;u.onTagOpen=function(e,d,g,l){d=new CKEDITOR.htmlParser.element(e,d);d.isUnknown&&\ng&&(d.isEmpty=!0);d.isOptionalClose=l;if(a(d))v.push(d);else{if(\"pre\"==e)t=!0;else{if(\"br\"==e&&t){r.add(new CKEDITOR.htmlParser.text(\"\\n\"));return}\"textarea\"==e&&(z=!0)}if(\"br\"==e)w.push(d);else{for(;!(l=(g=r.name)?CKEDITOR.dtd[g]||(r._.isBlockLike?CKEDITOR.dtd.div:CKEDITOR.dtd.span):c,d.isUnknown||r.isUnknown||l[e]);)if(r.isOptionalClose)u.onTagClose(g);else if(e in b&&g in b)g=r.children,(g=g[g.length-1])&&\"li\"==g.name||n(g=new CKEDITOR.htmlParser.element(\"li\"),r),!d.returnPoint&&(d.returnPoint=\nr),r=g;else if(e in CKEDITOR.dtd.$listItem&&!y(e,g))u.onTagOpen(\"li\"==e?\"ul\":\"dl\",{},0,1);else if(g in f&&!y(e,g))!d.returnPoint&&(d.returnPoint=r),r=r.parent;else if(g in CKEDITOR.dtd.$inline&&v.unshift(r),r.parent)n(r,r.parent,1);else{d.isOrphan=1;break}h(e);m();d.parent=r;d.isEmpty?n(d):r=d}}};u.onTagClose=function(a){for(var b=v.length-1;0<=b;b--)if(a==v[b].name){v.splice(b,1);return}for(var c=[],e=[],d=r;d!=p&&d.name!=a;)d._.isBlockLike||e.unshift(d),c.push(d),d=d.returnPoint||d.parent;if(d!=\np){for(b=0;b<c.length;b++){var h=c[b];n(h,h.parent)}r=d;d._.isBlockLike&&m();n(d,d.parent);d==r&&(r=r.parent);v=v.concat(e)}\"body\"==a&&(g=!1)};u.onText=function(a){if(!(r._.hasInlineStarted&&!w.length||t||z)&&(a=CKEDITOR.tools.ltrim(a),0===a.length))return;var b=r.name,e=b?CKEDITOR.dtd[b]||(r._.isBlockLike?CKEDITOR.dtd.div:CKEDITOR.dtd.span):c;if(!z&&!e[\"#\"]&&b in f)u.onTagOpen(d[b]||\"\"),u.onText(a);else{m();h();t||z||(a=a.replace(/[\\t\\r\\n ]{2,}|[\\t\\r\\n]/g,\" \"));a=new CKEDITOR.htmlParser.text(a);\nif(q(r,a))this.onTagOpen(g,{},0,1);r.add(a)}};u.onCDATA=function(a){r.add(new CKEDITOR.htmlParser.cdata(a))};u.onComment=function(a){m();h();r.add(new CKEDITOR.htmlParser.comment(a))};u.parse(l);for(m();r!=p;)n(r,r.parent,1);e(p);return p};CKEDITOR.htmlParser.fragment.prototype={type:CKEDITOR.NODE_DOCUMENT_FRAGMENT,add:function(a,b){isNaN(b)&&(b=this.children.length);var c=0<b?this.children[b-1]:null;if(c){if(a._.isBlockLike&&c.type==CKEDITOR.NODE_TEXT&&(c.value=CKEDITOR.tools.rtrim(c.value),0===\nc.value.length)){this.children.pop();this.add(a);return}c.next=a}a.previous=c;a.parent=this;this.children.splice(b,0,a);this._.hasInlineStarted||(this._.hasInlineStarted=a.type==CKEDITOR.NODE_TEXT||a.type==CKEDITOR.NODE_ELEMENT&&!a._.isBlockLike)},filter:function(a,b){b=this.getFilterContext(b);a.onRoot(b,this);this.filterChildren(a,!1,b)},filterChildren:function(a,b,c){if(this.childrenFilteredBy!=a.id){c=this.getFilterContext(c);if(b&&!this.parent)a.onRoot(c,this);this.childrenFilteredBy=a.id;for(b=\n0;b<this.children.length;b++)!1===this.children[b].filter(a,c)&&b--}},writeHtml:function(a,b){b&&this.filter(b);this.writeChildrenHtml(a)},writeChildrenHtml:function(a,b,c){var d=this.getFilterContext();if(c&&!this.parent&&b)b.onRoot(d,this);b&&this.filterChildren(b,!1,d);b=0;c=this.children;for(d=c.length;b<d;b++)c[b].writeHtml(a)},forEach:function(a,b,c){if(!(c||b&&this.type!=b))var d=a(this);if(!1!==d){c=this.children;for(var f=0;f<c.length;f++)d=c[f],d.type==CKEDITOR.NODE_ELEMENT?d.forEach(a,\nb):b&&d.type!=b||a(d)}},getFilterContext:function(a){return a||{}}}}(),\"use strict\",function(){function a(){this.rules=[]}function f(b,c,d,f){var k,g;for(k in c)(g=b[k])||(g=b[k]=new a),g.add(c[k],d,f)}CKEDITOR.htmlParser.filter=CKEDITOR.tools.createClass({$:function(b){this.id=CKEDITOR.tools.getNextNumber();this.elementNameRules=new a;this.attributeNameRules=new a;this.elementsRules={};this.attributesRules={};this.textRules=new a;this.commentRules=new a;this.rootRules=new a;b&&this.addRules(b,10)},\nproto:{addRules:function(a,c){var d;\"number\"==typeof c?d=c:c&&\"priority\"in c&&(d=c.priority);\"number\"!=typeof d&&(d=10);\"object\"!=typeof c&&(c={});a.elementNames&&this.elementNameRules.addMany(a.elementNames,d,c);a.attributeNames&&this.attributeNameRules.addMany(a.attributeNames,d,c);a.elements&&f(this.elementsRules,a.elements,d,c);a.attributes&&f(this.attributesRules,a.attributes,d,c);a.text&&this.textRules.add(a.text,d,c);a.comment&&this.commentRules.add(a.comment,d,c);a.root&&this.rootRules.add(a.root,\nd,c)},applyTo:function(a){a.filter(this)},onElementName:function(a,c){return this.elementNameRules.execOnName(a,c)},onAttributeName:function(a,c){return this.attributeNameRules.execOnName(a,c)},onText:function(a,c,d){return this.textRules.exec(a,c,d)},onComment:function(a,c,d){return this.commentRules.exec(a,c,d)},onRoot:function(a,c){return this.rootRules.exec(a,c)},onElement:function(a,c){for(var d=[this.elementsRules[\"^\"],this.elementsRules[c.name],this.elementsRules.$],f,k=0;3>k;k++)if(f=d[k]){f=\nf.exec(a,c,this);if(!1===f)return null;if(f&&f!=c)return this.onNode(a,f);if(c.parent&&!c.name)break}return c},onNode:function(a,c){var d=c.type;return d==CKEDITOR.NODE_ELEMENT?this.onElement(a,c):d==CKEDITOR.NODE_TEXT?new CKEDITOR.htmlParser.text(this.onText(a,c.value)):d==CKEDITOR.NODE_COMMENT?new CKEDITOR.htmlParser.comment(this.onComment(a,c.value)):null},onAttribute:function(a,c,d,f){return(d=this.attributesRules[d])?d.exec(a,f,c,this):f}}});CKEDITOR.htmlParser.filterRulesGroup=a;a.prototype=\n{add:function(a,c,d){this.rules.splice(this.findIndex(c),0,{value:a,priority:c,options:d})},addMany:function(a,c,d){for(var f=[this.findIndex(c),0],k=0,g=a.length;k<g;k++)f.push({value:a[k],priority:c,options:d});this.rules.splice.apply(this.rules,f)},findIndex:function(a){for(var c=this.rules,d=c.length-1;0<=d&&a<c[d].priority;)d--;return d+1},exec:function(a,c){var d=c instanceof CKEDITOR.htmlParser.node||c instanceof CKEDITOR.htmlParser.fragment,f=Array.prototype.slice.call(arguments,1),k=this.rules,\ng=k.length,h,m,e,n;for(n=0;n<g;n++)if(d&&(h=c.type,m=c.name),e=k[n],!(a.nonEditable&&!e.options.applyToAll||a.nestedEditable&&e.options.excludeNestedEditable)){e=e.value.apply(null,f);if(!1===e||d&&e&&(e.name!=m||e.type!=h))return e;null!=e&&(f[0]=c=e)}return c},execOnName:function(a,c){for(var d=0,f=this.rules,k=f.length,g;c&&d<k;d++)g=f[d],a.nonEditable&&!g.options.applyToAll||a.nestedEditable&&g.options.excludeNestedEditable||(c=c.replace(g.value[0],g.value[1]));return c}}}(),function(){function a(a,\ne){function g(a){return a||CKEDITOR.env.needsNbspFiller?new CKEDITOR.htmlParser.text(\" \"):new CKEDITOR.htmlParser.element(\"br\",{\"data-cke-bogus\":1})}function h(a,e){return function(d){if(d.type!=CKEDITOR.NODE_DOCUMENT_FRAGMENT){var h=[],m=b(d),k,D;if(m)for(f(m,1)&&h.push(m);m;)l(m)&&(k=c(m))&&f(k)&&((D=c(k))&&!l(D)?h.push(k):(g(n).insertAfter(k),k.remove())),m=m.previous;for(m=0;m<h.length;m++)h[m].remove();if(h=!a||!1!==(\"function\"==typeof e?e(d):e))n||CKEDITOR.env.needsBrFiller||d.type!=CKEDITOR.NODE_DOCUMENT_FRAGMENT?\nn||CKEDITOR.env.needsBrFiller||!(7<document.documentMode||d.name in CKEDITOR.dtd.tr||d.name in CKEDITOR.dtd.$listItem)?(h=b(d),h=!h||\"form\"==d.name&&\"input\"==h.name):h=!1:h=!1;h&&d.add(g(a))}}}function f(a,b){if((!n||CKEDITOR.env.needsBrFiller)&&a.type==CKEDITOR.NODE_ELEMENT&&\"br\"==a.name&&!a.attributes[\"data-cke-eol\"])return!0;var c;return a.type==CKEDITOR.NODE_TEXT&&(c=a.value.match(r))&&(c.index&&((new CKEDITOR.htmlParser.text(a.value.substring(0,c.index))).insertBefore(a),a.value=c[0]),!CKEDITOR.env.needsBrFiller&&\nn&&(!b||a.parent.name in D)||!n&&((c=a.previous)&&\"br\"==c.name||!c||l(c)))?!0:!1}var m={elements:{}},n=\"html\"==e,D=CKEDITOR.tools.extend({},A),x;for(x in D)\"#\"in t[x]||delete D[x];for(x in D)m.elements[x]=h(n,a.config.fillEmptyBlocks);m.root=h(n,!1);m.elements.br=function(a){return function(b){if(b.parent.type!=CKEDITOR.NODE_DOCUMENT_FRAGMENT){var e=b.attributes;if(\"data-cke-bogus\"in e||\"data-cke-eol\"in e)delete e[\"data-cke-bogus\"];else{for(e=b.next;e&&d(e);)e=e.next;var h=c(b);!e&&l(b.parent)?k(b.parent,\ng(a)):l(e)&&h&&!l(h)&&g(a).insertBefore(e)}}}}(n);return m}function f(a,b){return a!=CKEDITOR.ENTER_BR&&!1!==b?a==CKEDITOR.ENTER_DIV?\"div\":\"p\":!1}function b(a){for(a=a.children[a.children.length-1];a&&d(a);)a=a.previous;return a}function c(a){for(a=a.previous;a&&d(a);)a=a.previous;return a}function d(a){return a.type==CKEDITOR.NODE_TEXT&&!CKEDITOR.tools.trim(a.value)||a.type==CKEDITOR.NODE_ELEMENT&&a.attributes[\"data-cke-bookmark\"]}function l(a){return a&&(a.type==CKEDITOR.NODE_ELEMENT&&a.name in\nA||a.type==CKEDITOR.NODE_DOCUMENT_FRAGMENT)}function k(a,b){var c=a.children[a.children.length-1];a.children.push(b);b.parent=a;c&&(c.next=b,b.previous=c)}function g(a){a=a.attributes;\"false\"!=a.contenteditable&&(a[\"data-cke-editable\"]=a.contenteditable?\"true\":1);a.contenteditable=\"false\"}function h(a){a=a.attributes;switch(a[\"data-cke-editable\"]){case \"true\":a.contenteditable=\"true\";break;case \"1\":delete a.contenteditable}}function m(a){return a.replace(I,function(a,b,c){return\"\\x3c\"+b+c.replace(J,\nfunction(a,b){return E.test(b)&&-1==c.indexOf(\"data-cke-saved-\"+b)?\" data-cke-saved-\"+a+\" data-cke-\"+CKEDITOR.rnd+\"-\"+a:a})+\"\\x3e\"})}function e(a,b){return a.replace(b,function(a,b,c){0===a.indexOf(\"\\x3ctextarea\")&&(a=b+p(c).replace(/</g,\"\\x26lt;\").replace(/>/g,\"\\x26gt;\")+\"\\x3c/textarea\\x3e\");return\"\\x3ccke:encoded\\x3e\"+encodeURIComponent(a)+\"\\x3c/cke:encoded\\x3e\"})}function n(a){return a.replace(D,function(a,b){return decodeURIComponent(b)})}function q(a){return a.replace(/\\x3c!--(?!{cke_protected})[\\s\\S]+?--\\x3e/g,\nfunction(a){return\"\\x3c!--\"+z+\"{C}\"+encodeURIComponent(a).replace(/--/g,\"%2D%2D\")+\"--\\x3e\"})}function y(a){return CKEDITOR.tools.array.reduce(a.split(\"\"),function(a,b){var c=b.toLowerCase(),e=b.toUpperCase(),d=u(c);c!==e&&(d+=\"|\"+u(e));return a+(\"(\"+d+\")\")},\"\")}function u(a){var b;b=a.charCodeAt(0);var c=b.toString(16);b={htmlCode:\"\\x26#\"+b+\";?\",hex:\"\\x26#x0*\"+c+\";?\",entity:{\"\\x3c\":\"\\x26lt;\",\"\\x3e\":\"\\x26gt;\",\":\":\"\\x26colon;\"}[a]};for(var e in b)b[e]&&(a+=\"|\"+b[e]);return a}function p(a){return a.replace(/\\x3c!--\\{cke_protected\\}\\{C\\}([\\s\\S]+?)--\\x3e/g,\nfunction(a,b){return decodeURIComponent(b)})}function v(a,b){var c=b._.dataStore;return a.replace(/\\x3c!--\\{cke_protected\\}([\\s\\S]+?)--\\x3e/g,function(a,b){return decodeURIComponent(b)}).replace(/\\{cke_protected_(\\d+)\\}/g,function(a,b){return c&&c[b]||\"\"})}function w(a,b){var c=[],e=b.config.protectedSource,d=b._.dataStore||(b._.dataStore={id:1}),g=/<\\!--\\{cke_temp(comment)?\\}(\\d*?)--\\x3e/g,e=[/<script[\\s\\S]*?(<\\/script>|$)/gi,/<noscript[\\s\\S]*?<\\/noscript>/gi,/<meta[\\s\\S]*?\\/?>/gi].concat(e);a=a.replace(/\\x3c!--[\\s\\S]*?--\\x3e/g,\nfunction(a){return\"\\x3c!--{cke_tempcomment}\"+(c.push(a)-1)+\"--\\x3e\"});for(var h=0;h<e.length;h++)a=a.replace(e[h],function(a){a=a.replace(g,function(a,b,e){return c[e]});return/cke_temp(comment)?/.test(a)?a:\"\\x3c!--{cke_temp}\"+(c.push(a)-1)+\"--\\x3e\"});a=a.replace(g,function(a,b,e){return\"\\x3c!--\"+z+(b?\"{C}\":\"\")+encodeURIComponent(c[e]).replace(/--/g,\"%2D%2D\")+\"--\\x3e\"});a=a.replace(/<\\w+(?:\\s+(?:(?:[^\\s=>]+\\s*=\\s*(?:[^'\"\\s>]+|'[^']*'|\"[^\"]*\"))|[^\\s=\\/>]+))+\\s*\\/?>/g,function(a){return a.replace(/\\x3c!--\\{cke_protected\\}([^>]*)--\\x3e/g,\nfunction(a,b){d[d.id]=decodeURIComponent(b);return\"{cke_protected_\"+d.id++ +\"}\"})});return a=a.replace(/<(title|iframe|textarea)([^>]*)>([\\s\\S]*?)<\\/\\1>/g,function(a,c,e,d){return\"\\x3c\"+c+e+\"\\x3e\"+v(p(d),b)+\"\\x3c/\"+c+\"\\x3e\"})}CKEDITOR.htmlDataProcessor=function(b){var c,d,g=this;this.editor=b;this.dataFilter=c=new CKEDITOR.htmlParser.filter;this.htmlFilter=d=new CKEDITOR.htmlParser.filter;this.writer=new CKEDITOR.htmlParser.basicWriter;c.addRules(B);c.addRules(C,{applyToAll:!0});c.addRules(a(b,\"data\"),\n{applyToAll:!0});d.addRules(H);d.addRules(F,{applyToAll:!0});d.addRules(a(b,\"html\"),{applyToAll:!0});b.on(\"toHtml\",function(a){a=a.data;var c=a.dataValue,d,c=c.replace(N,\"\"),c=w(c,b),c=e(c,G),c=m(c),c=e(c,L),c=c.replace(Q,\"$1cke:$2\"),c=c.replace(K,\"\\x3ccke:$1$2\\x3e\\x3c/cke:$1\\x3e\"),c=c.replace(/(<pre\\b[^>]*>)(\\r\\n|\\n)/g,\"$1$2$2\"),c=c.replace(/([^a-z0-9<\\-])(on\\w{3,})(?!>)/gi,\"$1data-cke-\"+CKEDITOR.rnd+\"-$2\");d=a.context||b.editable().getName();var g;CKEDITOR.env.ie&&9>CKEDITOR.env.version&&\"pre\"==\nd&&(d=\"div\",c=\"\\x3cpre\\x3e\"+c+\"\\x3c/pre\\x3e\",g=1);d=b.document.createElement(d);d.setHtml(\"a\"+c);c=d.getHtml().substr(1);c=c.replace(new RegExp(\"data-cke-\"+CKEDITOR.rnd+\"-\",\"ig\"),\"\");g&&(c=c.replace(/^<pre>|<\\/pre>$/gi,\"\"));c=c.replace(O,\"$1$2\");c=n(c);c=p(c);d=!1===a.fixForBody?!1:f(a.enterMode,b.config.autoParagraph);c=CKEDITOR.htmlParser.fragment.fromHtml(c,a.context,d);d&&(g=c,!g.children.length&&CKEDITOR.dtd[g.name][d]&&(d=new CKEDITOR.htmlParser.element(d),g.add(d)));a.dataValue=c},null,null,\n5);b.on(\"toHtml\",function(a){a.data.filter.applyTo(a.data.dataValue,!0,a.data.dontFilter,a.data.enterMode)&&b.fire(\"dataFiltered\")},null,null,6);b.on(\"toHtml\",function(a){a.data.dataValue.filterChildren(g.dataFilter,!0)},null,null,10);b.on(\"toHtml\",function(a){a=a.data;var b=a.dataValue,c=new CKEDITOR.htmlParser.basicWriter;b.writeChildrenHtml(c);b=c.getHtml(!0);a.dataValue=q(b)},null,null,15);b.on(\"toDataFormat\",function(a){var c=a.data.dataValue;a.data.enterMode!=CKEDITOR.ENTER_BR&&(c=c.replace(/^<br *\\/?>/i,\n\"\"));a.data.dataValue=CKEDITOR.htmlParser.fragment.fromHtml(c,a.data.context,f(a.data.enterMode,b.config.autoParagraph))},null,null,5);b.on(\"toDataFormat\",function(a){a.data.dataValue.filterChildren(g.htmlFilter,!0)},null,null,10);b.on(\"toDataFormat\",function(a){a.data.filter.applyTo(a.data.dataValue,!1,!0)},null,null,11);b.on(\"toDataFormat\",function(a){var c=a.data.dataValue,e=g.writer;e.reset();c.writeChildrenHtml(e);c=e.getHtml(!0);c=p(c);c=v(c,b);a.data.dataValue=c},null,null,15)};CKEDITOR.htmlDataProcessor.prototype=\n{toHtml:function(a,b,c,e){var d=this.editor,g,h,f,m;b&&\"object\"==typeof b?(g=b.context,c=b.fixForBody,e=b.dontFilter,h=b.filter,f=b.enterMode,m=b.protectedWhitespaces):g=b;g||null===g||(g=d.editable().getName());return d.fire(\"toHtml\",{dataValue:a,context:g,fixForBody:c,dontFilter:e,filter:h||d.filter,enterMode:f||d.enterMode,protectedWhitespaces:m}).dataValue},toDataFormat:function(a,b){var c,e,d;b&&(c=b.context,e=b.filter,d=b.enterMode);c||null===c||(c=this.editor.editable().getName());return this.editor.fire(\"toDataFormat\",\n{dataValue:a,filter:e||this.editor.filter,context:c,enterMode:d||this.editor.enterMode}).dataValue}};var r=/(?:&nbsp;|\\xa0)$/,z=\"{cke_protected}\",t=CKEDITOR.dtd,x=\"caption colgroup col thead tfoot tbody\".split(\" \"),A=CKEDITOR.tools.extend({},t.$blockLimit,t.$block),B={elements:{input:g,textarea:g}},C={attributeNames:[[/^on/,\"data-cke-pa-on\"],[/^srcdoc/,\"data-cke-pa-srcdoc\"],[/^data-cke-expando$/,\"\"]],elements:{iframe:function(a){if(a.attributes&&a.attributes.src){var b=a.attributes.src.toLowerCase().replace(/[^a-z]/gi,\n\"\");if(0===b.indexOf(\"javascript\")||0===b.indexOf(\"data\"))a.attributes[\"data-cke-pa-src\"]=a.attributes.src,delete a.attributes.src}}}},H={elements:{embed:function(a){var b=a.parent;if(b&&\"object\"==b.name){var c=b.attributes.width,b=b.attributes.height;c&&(a.attributes.width=c);b&&(a.attributes.height=b)}},a:function(a){var b=a.attributes;if(!(a.children.length||b.name||b.id||a.attributes[\"data-cke-saved-name\"]))return!1}}},F={elementNames:[[/^cke:/,\"\"],[/^\\?xml:namespace$/,\"\"]],attributeNames:[[/^data-cke-(saved|pa)-/,\n\"\"],[/^data-cke-.*/,\"\"],[\"hidefocus\",\"\"]],elements:{$:function(a){var b=a.attributes;if(b){if(b[\"data-cke-temp\"])return!1;for(var c=[\"name\",\"href\",\"src\"],e,d=0;d<c.length;d++)e=\"data-cke-saved-\"+c[d],e in b&&delete b[c[d]]}return a},table:function(a){a.children.slice(0).sort(function(a,b){var c,e;a.type==CKEDITOR.NODE_ELEMENT&&b.type==a.type&&(c=CKEDITOR.tools.indexOf(x,a.name),e=CKEDITOR.tools.indexOf(x,b.name));-1<c&&-1<e&&c!=e||(c=a.parent?a.getIndex():-1,e=b.parent?b.getIndex():-1);return c>e?\n1:-1})},param:function(a){a.children=[];a.isEmpty=!0;return a},span:function(a){\"Apple-style-span\"==a.attributes[\"class\"]&&delete a.name},html:function(a){delete a.attributes.contenteditable;delete a.attributes[\"class\"]},body:function(a){delete a.attributes.spellcheck;delete a.attributes.contenteditable},style:function(a){var b=a.children[0];b&&b.value&&(b.value=CKEDITOR.tools.trim(b.value));a.attributes.type||(a.attributes.type=\"text/css\")},title:function(a){var b=a.children[0];!b&&k(a,b=new CKEDITOR.htmlParser.text);\nb.value=a.attributes[\"data-cke-title\"]||\"\"},input:h,textarea:h},attributes:{\"class\":function(a){return CKEDITOR.tools.ltrim(a.replace(/(?:^|\\s+)cke_[^\\s]*/g,\"\"))||!1}}};CKEDITOR.env.ie&&(F.attributes.style=function(a){return a.replace(/(^|;)([^\\:]+)/g,function(a){return a.toLowerCase()})});var I=/<(a|area|img|input|source)\\b([^>]*)>/gi,J=/([\\w-:]+)\\s*=\\s*(?:(?:\"[^\"]*\")|(?:'[^']*')|(?:[^ \"'>]+))/gi,E=/^(href|src|name)$/i,L=/(?:<style(?=[ >])[^>]*>[\\s\\S]*?<\\/style>)|(?:<(:?link|meta|base)[^>]*>)/gi,\nG=/(<textarea(?=[ >])[^>]*>)([\\s\\S]*?)(?:<\\/textarea>)/gi,D=/<cke:encoded>([^<]*)<\\/cke:encoded>/gi,N=new RegExp(\"(\"+y(\"\\x3ccke:encoded\\x3e\")+\"(.*?)\"+y(\"\\x3c/cke:encoded\\x3e\")+\")|(\"+y(\"\\x3c\")+y(\"/\")+\"?\"+y(\"cke:encoded\\x3e\")+\")\",\"gi\"),Q=/(<\\/?)((?:object|embed|param|html|body|head|title)([\\s][^>]*)?>)/gi,O=/(<\\/?)cke:((?:html|body|head|title)[^>]*>)/gi,K=/<cke:(param|embed)([^>]*?)\\/?>(?!\\s*<\\/cke:\\1)/gi}(),\"use strict\",CKEDITOR.htmlParser.element=function(a,f){this.name=a;this.attributes=f||{};this.children=\n[];var b=a||\"\",c=b.match(/^cke:(.*)/);c&&(b=c[1]);b=!!(CKEDITOR.dtd.$nonBodyContent[b]||CKEDITOR.dtd.$block[b]||CKEDITOR.dtd.$listItem[b]||CKEDITOR.dtd.$tableContent[b]||CKEDITOR.dtd.$nonEditable[b]||\"br\"==b);this.isEmpty=!!CKEDITOR.dtd.$empty[a];this.isUnknown=!CKEDITOR.dtd[a];this._={isBlockLike:b,hasInlineStarted:this.isEmpty||!b}},CKEDITOR.htmlParser.cssStyle=function(a){var f={};((a instanceof CKEDITOR.htmlParser.element?a.attributes.style:a)||\"\").replace(/&quot;/g,'\"').replace(/\\s*([^ :;]+)\\s*:\\s*([^;]+)\\s*(?=;|$)/g,\nfunction(a,c,d){\"font-family\"==c&&(d=d.replace(/[\"']/g,\"\"));f[c.toLowerCase()]=d});return{rules:f,populate:function(a){var c=this.toString();c&&(a instanceof CKEDITOR.dom.element?a.setAttribute(\"style\",c):a instanceof CKEDITOR.htmlParser.element?a.attributes.style=c:a.style=c)},toString:function(){var a=[],c;for(c in f)f[c]&&a.push(c,\":\",f[c],\";\");return a.join(\"\")}}},function(){function a(a){return function(b){return b.type==CKEDITOR.NODE_ELEMENT&&(\"string\"==typeof a?b.name==a:b.name in a)}}var f=\nfunction(a,b){a=a[0];b=b[0];return a<b?-1:a>b?1:0},b=CKEDITOR.htmlParser.fragment.prototype;CKEDITOR.htmlParser.element.prototype=CKEDITOR.tools.extend(new CKEDITOR.htmlParser.node,{type:CKEDITOR.NODE_ELEMENT,add:b.add,clone:function(){return new CKEDITOR.htmlParser.element(this.name,this.attributes)},filter:function(a,b){var f=this,k,g;b=f.getFilterContext(b);if(!f.parent)a.onRoot(b,f);for(;;){k=f.name;if(!(g=a.onElementName(b,k)))return this.remove(),!1;f.name=g;if(!(f=a.onElement(b,f)))return this.remove(),\n!1;if(f!==this)return this.replaceWith(f),!1;if(f.name==k)break;if(f.type!=CKEDITOR.NODE_ELEMENT)return this.replaceWith(f),!1;if(!f.name)return this.replaceWithChildren(),!1}k=f.attributes;var h,m;for(h in k){for(g=k[h];;)if(m=a.onAttributeName(b,h))if(m!=h)delete k[h],h=m;else break;else{delete k[h];break}m&&(!1===(g=a.onAttribute(b,f,m,g))?delete k[m]:k[m]=g)}f.isEmpty||this.filterChildren(a,!1,b);return!0},filterChildren:b.filterChildren,writeHtml:function(a,b){b&&this.filter(b);var l=this.name,\nk=[],g=this.attributes,h,m;a.openTag(l,g);for(h in g)k.push([h,g[h]]);a.sortAttributes&&k.sort(f);h=0;for(m=k.length;h<m;h++)g=k[h],a.attribute(g[0],g[1]);a.openTagClose(l,this.isEmpty);this.writeChildrenHtml(a);this.isEmpty||a.closeTag(l)},writeChildrenHtml:b.writeChildrenHtml,replaceWithChildren:function(){for(var a=this.children,b=a.length;b;)a[--b].insertAfter(this);this.remove()},forEach:b.forEach,getFirst:function(b){if(!b)return this.children.length?this.children[0]:null;\"function\"!=typeof b&&\n(b=a(b));for(var d=0,f=this.children.length;d<f;++d)if(b(this.children[d]))return this.children[d];return null},getHtml:function(){var a=new CKEDITOR.htmlParser.basicWriter;this.writeChildrenHtml(a);return a.getHtml()},setHtml:function(a){a=this.children=CKEDITOR.htmlParser.fragment.fromHtml(a).children;for(var b=0,f=a.length;b<f;++b)a[b].parent=this},getOuterHtml:function(){var a=new CKEDITOR.htmlParser.basicWriter;this.writeHtml(a);return a.getHtml()},split:function(a){for(var b=this.children.splice(a,\nthis.children.length-a),f=this.clone(),k=0;k<b.length;++k)b[k].parent=f;f.children=b;b[0]&&(b[0].previous=null);0<a&&(this.children[a-1].next=null);this.parent.add(f,this.getIndex()+1);return f},find:function(a,b){void 0===b&&(b=!1);var f=[],k;for(k=0;k<this.children.length;k++){var g=this.children[k];\"function\"==typeof a&&a(g)?f.push(g):\"string\"==typeof a&&g.name===a&&f.push(g);b&&g.find&&(f=f.concat(g.find(a,b)))}return f},findOne:function(a,b){var f=null,k=CKEDITOR.tools.array.find(this.children,\nfunction(g){var h=\"function\"===typeof a?a(g):g.name===a;if(h||!b)return h;g.children&&g.findOne&&(f=g.findOne(a,!0));return!!f});return f||k||null},addClass:function(a){if(!this.hasClass(a)){var b=this.attributes[\"class\"]||\"\";this.attributes[\"class\"]=b+(b?\" \":\"\")+a}},removeClass:function(a){var b=this.attributes[\"class\"];b&&((b=CKEDITOR.tools.trim(b.replace(new RegExp(\"(?:\\\\s+|^)\"+a+\"(?:\\\\s+|$)\"),\" \")))?this.attributes[\"class\"]=b:delete this.attributes[\"class\"])},hasClass:function(a){var b=this.attributes[\"class\"];\nreturn b?(new RegExp(\"(?:^|\\\\s)\"+a+\"(?\\x3d\\\\s|$)\")).test(b):!1},getFilterContext:function(a){var b=[];a||(a={nonEditable:!1,nestedEditable:!1});a.nonEditable||\"false\"!=this.attributes.contenteditable?a.nonEditable&&!a.nestedEditable&&\"true\"==this.attributes.contenteditable&&b.push(\"nestedEditable\",!0):b.push(\"nonEditable\",!0);if(b.length){a=CKEDITOR.tools.copy(a);for(var f=0;f<b.length;f+=2)a[b[f]]=b[f+1]}return a}},!0)}(),function(){var a=/{([^}]+)}/g;CKEDITOR.template=function(a){this.source=\"function\"===\ntypeof a?a:String(a)};CKEDITOR.template.prototype.output=function(f,b){var c=(\"function\"===typeof this.source?this.source(f):this.source).replace(a,function(a,b){return void 0!==f[b]?f[b]:a});return b?b.push(c):c}}(),delete CKEDITOR.loadFullCore,CKEDITOR.instances={},CKEDITOR.document=new CKEDITOR.dom.document(document),CKEDITOR.add=function(a){function f(){CKEDITOR.currentInstance==a&&(CKEDITOR.currentInstance=null,CKEDITOR.fire(\"currentInstance\"))}CKEDITOR.instances[a.name]=a;a.on(\"focus\",function(){CKEDITOR.currentInstance!=\na&&(CKEDITOR.currentInstance=a,CKEDITOR.fire(\"currentInstance\"))});a.on(\"blur\",f);a.on(\"destroy\",f);CKEDITOR.fire(\"instance\",null,a)},CKEDITOR.remove=function(a){delete CKEDITOR.instances[a.name]},function(){var a={};CKEDITOR.addTemplate=function(f,b){var c=a[f];if(c)return c;c={name:f,source:b};CKEDITOR.fire(\"template\",c);return a[f]=new CKEDITOR.template(c.source)};CKEDITOR.getTemplate=function(f){return a[f]}}(),function(){var a=[];CKEDITOR.addCss=function(f){a.push(f)};CKEDITOR.getCss=function(){return a.join(\"\\n\")}}(),\nCKEDITOR.on(\"instanceDestroyed\",function(){CKEDITOR.tools.isEmpty(this.instances)&&CKEDITOR.fire(\"reset\")}),CKEDITOR.TRISTATE_ON=1,CKEDITOR.TRISTATE_OFF=2,CKEDITOR.TRISTATE_DISABLED=0,function(){CKEDITOR.inline=function(a,f){a=CKEDITOR.editor._getEditorElement(a);if(!a)return null;var b=new CKEDITOR.editor(f,a,CKEDITOR.ELEMENT_MODE_INLINE),c=a.is(\"textarea\")?a:null;c?(b.setData(c.getValue(),null,!0),a=CKEDITOR.dom.element.createFromHtml('\\x3cdiv contenteditable\\x3d\"'+!!b.readOnly+'\" class\\x3d\"cke_textarea_inline\"\\x3e'+\nc.getValue()+\"\\x3c/div\\x3e\",CKEDITOR.document),a.insertAfter(c),c.hide(),c.$.form&&b._attachToForm()):b.setData(a.getHtml(),null,!0);b.on(\"loaded\",function(){b.fire(\"uiReady\");b.editable(a);b.container=a;b.ui.contentsElement=a;b.setData(b.getData(1));b.resetDirty();b.fire(\"contentDom\");b.mode=\"wysiwyg\";b.fire(\"mode\");b.status=\"ready\";b.fireOnce(\"instanceReady\");CKEDITOR.fire(\"instanceReady\",null,b)},null,null,1E4);b.on(\"destroy\",function(){c&&(b.container.clearCustomData(),b.container.remove(),c.show());\nb.element.clearCustomData();delete b.element});return b};CKEDITOR.inlineAll=function(){var a,f,b;for(b in CKEDITOR.dtd.$editable)for(var c=CKEDITOR.document.getElementsByTag(b),d=0,l=c.count();d<l;d++)a=c.getItem(d),\"true\"==a.getAttribute(\"contenteditable\")&&(f={element:a,config:{}},!1!==CKEDITOR.fire(\"inline\",f)&&CKEDITOR.inline(a,f.config))};CKEDITOR.domReady(function(){!CKEDITOR.disableAutoInline&&CKEDITOR.inlineAll()})}(),CKEDITOR.replaceClass=\"ckeditor\",function(){function a(a,d,l,k){a=CKEDITOR.editor._getEditorElement(a);\nif(!a)return null;var g=new CKEDITOR.editor(d,a,k);k==CKEDITOR.ELEMENT_MODE_REPLACE&&(a.setStyle(\"visibility\",\"hidden\"),g._.required=a.hasAttribute(\"required\"),a.removeAttribute(\"required\"));l&&g.setData(l,null,!0);g.on(\"loaded\",function(){b(g);k==CKEDITOR.ELEMENT_MODE_REPLACE&&g.config.autoUpdateElement&&a.$.form&&g._attachToForm();g.setMode(g.config.startupMode,function(){g.resetDirty();g.status=\"ready\";g.fireOnce(\"instanceReady\");CKEDITOR.fire(\"instanceReady\",null,g)})});g.on(\"destroy\",f);return g}\nfunction f(){var a=this.container,b=this.element;a&&(a.clearCustomData(),a.remove());b&&(b.clearCustomData(),this.elementMode==CKEDITOR.ELEMENT_MODE_REPLACE&&(b.show(),this._.required&&b.setAttribute(\"required\",\"required\")),delete this.element)}function b(a){var b=a.name,f=a.element,k=a.elementMode,g=a.fire(\"uiSpace\",{space:\"top\",html:\"\"}).html,h=a.fire(\"uiSpace\",{space:\"bottom\",html:\"\"}).html,m=new CKEDITOR.template('\\x3c{outerEl} id\\x3d\"cke_{name}\" class\\x3d\"{id} cke cke_reset cke_chrome cke_editor_{name} cke_{langDir} '+\nCKEDITOR.env.cssClass+'\"  dir\\x3d\"{langDir}\" lang\\x3d\"{langCode}\" role\\x3d\"application\"'+(a.title?' aria-labelledby\\x3d\"cke_{name}_arialbl\"':\"\")+\"\\x3e\"+(a.title?'\\x3cspan id\\x3d\"cke_{name}_arialbl\" class\\x3d\"cke_voice_label\"\\x3e{voiceLabel}\\x3c/span\\x3e':\"\")+'\\x3c{outerEl} class\\x3d\"cke_inner cke_reset\" role\\x3d\"presentation\"\\x3e{topHtml}\\x3c{outerEl} id\\x3d\"{contentId}\" class\\x3d\"cke_contents cke_reset\" role\\x3d\"presentation\"\\x3e\\x3c/{outerEl}\\x3e{bottomHtml}\\x3c/{outerEl}\\x3e\\x3c/{outerEl}\\x3e'),\nb=CKEDITOR.dom.element.createFromHtml(m.output({id:a.id,name:b,langDir:a.lang.dir,langCode:a.langCode,voiceLabel:a.title,topHtml:g?'\\x3cspan id\\x3d\"'+a.ui.spaceId(\"top\")+'\" class\\x3d\"cke_top cke_reset_all\" role\\x3d\"presentation\" style\\x3d\"height:auto\"\\x3e'+g+\"\\x3c/span\\x3e\":\"\",contentId:a.ui.spaceId(\"contents\"),bottomHtml:h?'\\x3cspan id\\x3d\"'+a.ui.spaceId(\"bottom\")+'\" class\\x3d\"cke_bottom cke_reset_all\" role\\x3d\"presentation\"\\x3e'+h+\"\\x3c/span\\x3e\":\"\",outerEl:CKEDITOR.env.ie?\"span\":\"div\"}));k==CKEDITOR.ELEMENT_MODE_REPLACE?\n(f.hide(),b.insertAfter(f)):f.append(b);a.container=b;a.ui.contentsElement=a.ui.space(\"contents\");g&&a.ui.space(\"top\").unselectable();h&&a.ui.space(\"bottom\").unselectable();f=a.config.width;k=a.config.height;f&&b.setStyle(\"width\",CKEDITOR.tools.cssLength(f));k&&a.ui.space(\"contents\").setStyle(\"height\",CKEDITOR.tools.cssLength(k));b.disableContextMenu();CKEDITOR.env.webkit&&b.on(\"focus\",function(){a.focus()});a.fireOnce(\"uiReady\")}CKEDITOR.replace=function(b,d){return a(b,d,null,CKEDITOR.ELEMENT_MODE_REPLACE)};\nCKEDITOR.appendTo=function(b,d,f){return a(b,d,f,CKEDITOR.ELEMENT_MODE_APPENDTO)};CKEDITOR.replaceAll=function(){for(var a=document.getElementsByTagName(\"textarea\"),b=0;b<a.length;b++){var f=null,k=a[b];if(k.name||k.id){if(\"string\"==typeof arguments[0]){if(!(new RegExp(\"(?:^|\\\\s)\"+arguments[0]+\"(?:$|\\\\s)\")).test(k.className))continue}else if(\"function\"==typeof arguments[0]&&(f={},!1===arguments[0](k,f)))continue;this.replace(k,f)}}};CKEDITOR.editor.prototype.addMode=function(a,b){(this._.modes||(this._.modes=\n{}))[a]=b};CKEDITOR.editor.prototype.setMode=function(a,b){var f=this,k=this._.modes;if(a!=f.mode&&k&&k[a]){f.fire(\"beforeSetMode\",a);if(f.mode){var g=f.checkDirty(),k=f._.previousModeData,h,m=0;f.fire(\"beforeModeUnload\");f.editable(0);f._.previousMode=f.mode;f._.previousModeData=h=f.getData(1);\"source\"==f.mode&&k==h&&(f.fire(\"lockSnapshot\",{forceUpdate:!0}),m=1);f.ui.space(\"contents\").setHtml(\"\");f.mode=\"\"}else f._.previousModeData=f.getData(1);this._.modes[a](function(){f.mode=a;void 0!==g&&!g&&\nf.resetDirty();m?f.fire(\"unlockSnapshot\"):\"wysiwyg\"==a&&f.fire(\"saveSnapshot\");setTimeout(function(){f.fire(\"mode\");b&&b.call(f)},0)})}};CKEDITOR.editor.prototype.resize=function(a,b,f,k){var g=this.container,h=this.ui.space(\"contents\"),m=CKEDITOR.env.webkit&&this.document&&this.document.getWindow().$.frameElement;k=k?this.container.getFirst(function(a){return a.type==CKEDITOR.NODE_ELEMENT&&a.hasClass(\"cke_inner\")}):g;k.setSize(\"width\",a,!0);m&&(m.style.width=\"1%\");var e=(k.$.offsetHeight||0)-(h.$.clientHeight||\n0),g=Math.max(b-(f?0:e),0);b=f?b+e:b;h.setStyle(\"height\",g+\"px\");m&&(m.style.width=\"100%\");this.fire(\"resize\",{outerHeight:b,contentsHeight:g,outerWidth:a||k.getSize(\"width\")})};CKEDITOR.editor.prototype.getResizable=function(a){return a?this.ui.space(\"contents\"):this.container};CKEDITOR.domReady(function(){CKEDITOR.replaceClass&&CKEDITOR.replaceAll(CKEDITOR.replaceClass)})}(),CKEDITOR.config.startupMode=\"wysiwyg\",function(){function a(a){var b=a.editor,e=a.data.path,d=e.blockLimit,g=a.data.selection,\nh=g.getRanges()[0],m;if(CKEDITOR.env.gecko||CKEDITOR.env.ie&&CKEDITOR.env.needsBrFiller)if(g=f(g,e))g.appendBogus(),m=CKEDITOR.env.ie;k(b,e.block,d)&&h.collapsed&&!h.getCommonAncestor().isReadOnly()&&(e=h.clone(),e.enlarge(CKEDITOR.ENLARGE_BLOCK_CONTENTS),d=new CKEDITOR.dom.walker(e),d.guard=function(a){return!c(a)||a.type==CKEDITOR.NODE_COMMENT||a.isReadOnly()},!d.checkForward()||e.checkStartOfBlock()&&e.checkEndOfBlock())&&(b=h.fixBlock(!0,b.activeEnterMode==CKEDITOR.ENTER_DIV?\"div\":\"p\"),CKEDITOR.env.needsBrFiller||\n(b=b.getFirst(c))&&b.type==CKEDITOR.NODE_TEXT&&CKEDITOR.tools.trim(b.getText()).match(/^(?:&nbsp;|\\xa0)$/)&&b.remove(),m=1,a.cancel());m&&h.select()}function f(a,b){if(a.isFake)return 0;var e=b.block||b.blockLimit,d=e&&e.getLast(c);if(!(!e||!e.isBlockBoundary()||d&&d.type==CKEDITOR.NODE_ELEMENT&&d.isBlockBoundary()||e.is(\"pre\")||e.getBogus()))return e}function b(a){var b=a.data.getTarget();b.is(\"input\")&&(b=b.getAttribute(\"type\"),\"submit\"!=b&&\"reset\"!=b||a.data.preventDefault())}function c(a){return n(a)&&\nq(a)}function d(a,b){return function(c){var e=c.data.$.toElement||c.data.$.fromElement||c.data.$.relatedTarget;(e=e&&e.nodeType==CKEDITOR.NODE_ELEMENT?new CKEDITOR.dom.element(e):null)&&(b.equals(e)||b.contains(e))||a.call(this,c)}}function l(a){function b(a){return function(b,d){d&&b.type==CKEDITOR.NODE_ELEMENT&&b.is(g)&&(e=b);if(!(d||!c(b)||a&&u(b)))return!1}}var e,d=a.getRanges()[0];a=a.root;var g={table:1,ul:1,ol:1,dl:1};if(d.startPath().contains(g)){var f=d.clone();f.collapse(1);f.setStartAt(a,\nCKEDITOR.POSITION_AFTER_START);a=new CKEDITOR.dom.walker(f);a.guard=b();a.checkBackward();if(e)return f=d.clone(),f.collapse(),f.setEndAt(e,CKEDITOR.POSITION_AFTER_END),a=new CKEDITOR.dom.walker(f),a.guard=b(!0),e=!1,a.checkForward(),e}return null}function k(a,b,c){return!1!==a.config.autoParagraph&&a.activeEnterMode!=CKEDITOR.ENTER_BR&&(a.editable().equals(c)&&!b||b&&\"true\"==b.getAttribute(\"contenteditable\"))}function g(a){return a.activeEnterMode!=CKEDITOR.ENTER_BR&&!1!==a.config.autoParagraph?\na.activeEnterMode==CKEDITOR.ENTER_DIV?\"div\":\"p\":!1}function h(a){a&&a.isEmptyInlineRemoveable()&&a.remove()}function m(a){var b=a.editor;b.getSelection().scrollIntoView();setTimeout(function(){b.fire(\"saveSnapshot\")},0)}function e(a,b,c){var e=a.getCommonAncestor(b);for(b=a=c?b:a;(a=a.getParent())&&!e.equals(a)&&1==a.getChildCount();)b=a;b.remove()}var n,q,y,u,p,v,w,r,z,t;CKEDITOR.editable=CKEDITOR.tools.createClass({base:CKEDITOR.dom.element,$:function(a,b){this.base(b.$||b);this.editor=a;this.status=\n\"unloaded\";this.hasFocus=!1;this.setup()},proto:{focus:function(){var a;if(CKEDITOR.env.webkit&&!this.hasFocus&&(a=this.editor._.previousActive||this.getDocument().getActive(),this.contains(a))){a.focus();return}CKEDITOR.env.edge&&14<CKEDITOR.env.version&&!this.hasFocus&&this.getDocument().equals(CKEDITOR.document)&&(this.editor._.previousScrollTop=this.$.scrollTop);try{if(!CKEDITOR.env.ie||CKEDITOR.env.edge&&14<CKEDITOR.env.version||!this.getDocument().equals(CKEDITOR.document))if(CKEDITOR.env.chrome){var b=\nthis.$.scrollTop;this.$.focus();this.$.scrollTop=b}else this.$.focus();else this.$.setActive()}catch(c){if(!CKEDITOR.env.ie)throw c;}CKEDITOR.env.safari&&!this.isInline()&&(a=CKEDITOR.document.getActive(),a.equals(this.getWindow().getFrame())||this.getWindow().focus())},on:function(a,b){var c=Array.prototype.slice.call(arguments,0);CKEDITOR.env.ie&&/^focus|blur$/.exec(a)&&(a=\"focus\"==a?\"focusin\":\"focusout\",b=d(b,this),c[0]=a,c[1]=b);return CKEDITOR.dom.element.prototype.on.apply(this,c)},attachListener:function(a){!this._.listeners&&\n(this._.listeners=[]);var b=Array.prototype.slice.call(arguments,1),b=a.on.apply(a,b);this._.listeners.push(b);return b},clearListeners:function(){var a=this._.listeners;try{for(;a.length;)a.pop().removeListener()}catch(b){}},restoreAttrs:function(){var a=this._.attrChanges,b,c;for(c in a)a.hasOwnProperty(c)&&(b=a[c],null!==b?this.setAttribute(c,b):this.removeAttribute(c))},attachClass:function(a){var b=this.getCustomData(\"classes\");this.hasClass(a)||(!b&&(b=[]),b.push(a),this.setCustomData(\"classes\",\nb),this.addClass(a))},changeAttr:function(a,b){var c=this.getAttribute(a);b!==c&&(!this._.attrChanges&&(this._.attrChanges={}),a in this._.attrChanges||(this._.attrChanges[a]=c),this.setAttribute(a,b))},insertText:function(a){this.editor.focus();this.insertHtml(this.transformPlainTextToHtml(a),\"text\")},transformPlainTextToHtml:function(a){var b=this.editor.getSelection().getStartElement().hasAscendant(\"pre\",!0)?CKEDITOR.ENTER_BR:this.editor.activeEnterMode;return CKEDITOR.tools.transformPlainTextToHtml(a,\nb)},insertHtml:function(a,b,c){var e=this.editor;e.focus();e.fire(\"saveSnapshot\");c||(c=e.getSelection().getRanges()[0]);v(this,b||\"html\",a,c);c.select();m(this);this.editor.fire(\"afterInsertHtml\",{})},insertHtmlIntoRange:function(a,b,c){v(this,c||\"html\",a,b);this.editor.fire(\"afterInsertHtml\",{intoRange:b})},insertElement:function(a,b){var e=this.editor;e.focus();e.fire(\"saveSnapshot\");var d=e.activeEnterMode,e=e.getSelection(),g=a.getName(),g=CKEDITOR.dtd.$block[g];b||(b=e.getRanges()[0]);this.insertElementIntoRange(a,\nb)&&(b.moveToPosition(a,CKEDITOR.POSITION_AFTER_END),g&&((g=a.getNext(function(a){return c(a)&&!u(a)}))&&g.type==CKEDITOR.NODE_ELEMENT&&g.is(CKEDITOR.dtd.$block)?g.getDtd()[\"#\"]?b.moveToElementEditStart(g):b.moveToElementEditEnd(a):g||d==CKEDITOR.ENTER_BR||(g=b.fixBlock(!0,d==CKEDITOR.ENTER_DIV?\"div\":\"p\"),b.moveToElementEditStart(g))));e.selectRanges([b]);m(this)},insertElementIntoSelection:function(a){this.insertElement(a)},insertElementIntoRange:function(a,b){var c=this.editor,e=c.config.enterMode,\nd=a.getName(),g=CKEDITOR.dtd.$block[d];if(b.checkReadOnly())return!1;b.deleteContents(1);b.startContainer.type==CKEDITOR.NODE_ELEMENT&&(b.startContainer.is({tr:1,table:1,tbody:1,thead:1,tfoot:1})?w(b):b.startContainer.is(CKEDITOR.dtd.$list)&&r(b));var f,m;if(g)for(;(f=b.getCommonAncestor(0,1))&&(m=CKEDITOR.dtd[f.getName()])&&(!m||!m[d]);)if(f.getName()in CKEDITOR.dtd.span){var g=b.splitElement(f),k=b.createBookmark();h(f);h(g);b.moveToBookmark(k)}else b.checkStartOfBlock()&&b.checkEndOfBlock()?(b.setStartBefore(f),\nb.collapse(!0),f.remove()):b.splitBlock(e==CKEDITOR.ENTER_DIV?\"div\":\"p\",c.editable());b.insertNode(a);return!0},setData:function(a,b){b||(a=this.editor.dataProcessor.toHtml(a));this.setHtml(a);this.fixInitialSelection();\"unloaded\"==this.status&&(this.status=\"ready\");this.editor.fire(\"dataReady\")},getData:function(a){var b=this.getHtml();a||(b=this.editor.dataProcessor.toDataFormat(b));return b},setReadOnly:function(a){this.setAttribute(\"contenteditable\",!a)},detach:function(){this.removeClass(\"cke_editable\");\nthis.status=\"detached\";var a=this.editor;this._.detach();delete a.document;delete a.window},isInline:function(){return this.getDocument().equals(CKEDITOR.document)},fixInitialSelection:function(){function a(){var b=c.getDocument().$,e=b.getSelection(),d;a:if(e.anchorNode&&e.anchorNode==c.$)d=!0;else{if(CKEDITOR.env.webkit&&(d=c.getDocument().getActive())&&d.equals(c)&&!e.anchorNode){d=!0;break a}d=void 0}d&&(d=new CKEDITOR.dom.range(c),d.moveToElementEditStart(c),b=b.createRange(),b.setStart(d.startContainer.$,\nd.startOffset),b.collapse(!0),e.removeAllRanges(),e.addRange(b))}function b(){var a=c.getDocument().$,e=a.selection,d=c.getDocument().getActive();\"None\"==e.type&&d.equals(c)&&(e=new CKEDITOR.dom.range(c),a=a.body.createTextRange(),e.moveToElementEditStart(c),e=e.startContainer,e.type!=CKEDITOR.NODE_ELEMENT&&(e=e.getParent()),a.moveToElementText(e.$),a.collapse(!0),a.select())}var c=this;if(CKEDITOR.env.ie&&(9>CKEDITOR.env.version||CKEDITOR.env.quirks))this.hasFocus&&(this.focus(),b());else if(this.hasFocus)this.focus(),\na();else this.once(\"focus\",function(){a()},null,null,-999)},getHtmlFromRange:function(a){if(a.collapsed)return new CKEDITOR.dom.documentFragment(a.document);a={doc:this.getDocument(),range:a.clone()};z.eol.detect(a,this);z.bogus.exclude(a);z.cell.shrink(a);a.fragment=a.range.cloneContents();z.tree.rebuild(a,this);z.eol.fix(a,this);return new CKEDITOR.dom.documentFragment(a.fragment.$)},extractHtmlFromRange:function(a,b){var c=t,e={range:a,doc:a.document},d=this.getHtmlFromRange(a);if(a.collapsed)return a.optimize(),\nd;a.enlarge(CKEDITOR.ENLARGE_INLINE,1);c.table.detectPurge(e);e.bookmark=a.createBookmark();delete e.range;var g=this.editor.createRange();g.moveToPosition(e.bookmark.startNode,CKEDITOR.POSITION_BEFORE_START);e.targetBookmark=g.createBookmark();c.list.detectMerge(e,this);c.table.detectRanges(e,this);c.block.detectMerge(e,this);e.tableContentsRanges?(c.table.deleteRanges(e),a.moveToBookmark(e.bookmark),e.range=a):(a.moveToBookmark(e.bookmark),e.range=a,a.extractContents(c.detectExtractMerge(e)));a.moveToBookmark(e.targetBookmark);\na.optimize();c.fixUneditableRangePosition(a);c.list.merge(e,this);c.table.purge(e,this);c.block.merge(e,this);if(b){c=a.startPath();if(e=a.checkStartOfBlock()&&a.checkEndOfBlock()&&c.block&&!a.root.equals(c.block)){a:{var e=c.block.getElementsByTag(\"span\"),g=0,f;if(e)for(;f=e.getItem(g++);)if(!q(f)){e=!0;break a}e=!1}e=!e}e&&(a.moveToPosition(c.block,CKEDITOR.POSITION_BEFORE_START),c.block.remove())}else c.autoParagraph(this.editor,a),y(a.startContainer)&&a.startContainer.appendBogus();a.startContainer.mergeSiblings();\nreturn d},setup:function(){var a=this.editor;this.attachListener(a,\"beforeGetData\",function(){var b=this.getData();this.is(\"textarea\")||!1!==a.config.ignoreEmptyParagraph&&(b=b.replace(p,function(a,b){return b}));a.setData(b,null,1)},this);this.attachListener(a,\"getSnapshot\",function(a){a.data=this.getData(1)},this);this.attachListener(a,\"afterSetData\",function(){this.setData(a.getData(1))},this);this.attachListener(a,\"loadSnapshot\",function(a){this.setData(a.data,1)},this);this.attachListener(a,\n\"beforeFocus\",function(){var b=a.getSelection();(b=b&&b.getNative())&&\"Control\"==b.type||this.focus()},this);this.attachListener(a,\"insertHtml\",function(a){this.insertHtml(a.data.dataValue,a.data.mode,a.data.range)},this);this.attachListener(a,\"insertElement\",function(a){this.insertElement(a.data)},this);this.attachListener(a,\"insertText\",function(a){this.insertText(a.data)},this);this.setReadOnly(a.readOnly);this.attachClass(\"cke_editable\");a.elementMode==CKEDITOR.ELEMENT_MODE_INLINE?this.attachClass(\"cke_editable_inline\"):\na.elementMode!=CKEDITOR.ELEMENT_MODE_REPLACE&&a.elementMode!=CKEDITOR.ELEMENT_MODE_APPENDTO||this.attachClass(\"cke_editable_themed\");this.attachClass(\"cke_contents_\"+a.config.contentsLangDirection);a.keystrokeHandler.blockedKeystrokes[8]=+a.readOnly;a.keystrokeHandler.attach(this);this.on(\"blur\",function(){this.hasFocus=!1},null,null,-1);this.on(\"focus\",function(){this.hasFocus=!0},null,null,-1);if(CKEDITOR.env.webkit)this.on(\"scroll\",function(){a._.previousScrollTop=a.editable().$.scrollTop},null,\nnull,-1);if(CKEDITOR.env.edge&&14<CKEDITOR.env.version){var d=function(){var b=a.editable();null!=a._.previousScrollTop&&b.getDocument().equals(CKEDITOR.document)&&(b.$.scrollTop=a._.previousScrollTop,a._.previousScrollTop=null,this.removeListener(\"scroll\",d))};this.on(\"scroll\",d)}a.focusManager.add(this);this.equals(CKEDITOR.document.getActive())&&(this.hasFocus=!0,a.once(\"contentDom\",function(){a.focusManager.focus(this)},this));this.isInline()&&this.changeAttr(\"tabindex\",a.tabIndex);if(!this.is(\"textarea\")){a.document=\nthis.getDocument();a.window=this.getWindow();var g=a.document;this.changeAttr(\"spellcheck\",!a.config.disableNativeSpellChecker);var f=a.config.contentsLangDirection;this.getDirection(1)!=f&&this.changeAttr(\"dir\",f);var h=CKEDITOR.getCss();if(h){var f=g.getHead(),m=f.getCustomData(\"stylesheet\");m?h!=m.getText()&&(CKEDITOR.env.ie&&9>CKEDITOR.env.version?m.$.styleSheet.cssText=h:m.setText(h)):(h=g.appendStyleText(h),h=new CKEDITOR.dom.element(h.ownerNode||h.owningElement),f.setCustomData(\"stylesheet\",\nh),h.data(\"cke-temp\",1))}f=g.getCustomData(\"stylesheet_ref\")||0;g.setCustomData(\"stylesheet_ref\",f+1);this.setCustomData(\"cke_includeReadonly\",!a.config.disableReadonlyStyling);this.attachListener(this,\"click\",function(a){a=a.data;var b=(new CKEDITOR.dom.elementPath(a.getTarget(),this)).contains(\"a\");b&&2!=a.$.button&&b.isReadOnly()&&a.preventDefault()});var k={8:1,46:1};this.attachListener(a,\"key\",function(b){if(a.readOnly)return!0;var c=b.data.domEvent.getKey(),e;b=a.getSelection();if(0!==b.getRanges().length){if(c in\nk){var d,g=b.getRanges()[0],f=g.startPath(),h,m,q,c=8==c;CKEDITOR.env.ie&&11>CKEDITOR.env.version&&(d=b.getSelectedElement())||(d=l(b))?(a.fire(\"saveSnapshot\"),g.moveToPosition(d,CKEDITOR.POSITION_BEFORE_START),d.remove(),g.select(),a.fire(\"saveSnapshot\"),e=1):g.collapsed&&((h=f.block)&&(q=h[c?\"getPrevious\":\"getNext\"](n))&&q.type==CKEDITOR.NODE_ELEMENT&&q.is(\"table\")&&g[c?\"checkStartOfBlock\":\"checkEndOfBlock\"]()?(a.fire(\"saveSnapshot\"),g[c?\"checkEndOfBlock\":\"checkStartOfBlock\"]()&&h.remove(),g[\"moveToElementEdit\"+\n(c?\"End\":\"Start\")](q),g.select(),a.fire(\"saveSnapshot\"),e=1):f.blockLimit&&f.blockLimit.is(\"td\")&&(m=f.blockLimit.getAscendant(\"table\"))&&g.checkBoundaryOfElement(m,c?CKEDITOR.START:CKEDITOR.END)&&(q=m[c?\"getPrevious\":\"getNext\"](n))?(a.fire(\"saveSnapshot\"),g[\"moveToElementEdit\"+(c?\"End\":\"Start\")](q),g.checkStartOfBlock()&&g.checkEndOfBlock()?q.remove():g.select(),a.fire(\"saveSnapshot\"),e=1):(m=f.contains([\"td\",\"th\",\"caption\"]))&&g.checkBoundaryOfElement(m,c?CKEDITOR.START:CKEDITOR.END)&&(e=1))}return!e}});\na.blockless&&CKEDITOR.env.ie&&CKEDITOR.env.needsBrFiller&&this.attachListener(this,\"keyup\",function(b){b.data.getKeystroke()in k&&!this.getFirst(c)&&(this.appendBogus(),b=a.createRange(),b.moveToPosition(this,CKEDITOR.POSITION_AFTER_START),b.select())});this.attachListener(this,\"dblclick\",function(b){if(a.readOnly)return!1;b={element:b.data.getTarget()};a.fire(\"doubleclick\",b)});CKEDITOR.env.ie&&this.attachListener(this,\"click\",b);CKEDITOR.env.ie&&!CKEDITOR.env.edge||this.attachListener(this,\"mousedown\",\nfunction(b){var c=b.data.getTarget();c.is(\"img\",\"hr\",\"input\",\"textarea\",\"select\")&&!c.isReadOnly()&&(a.getSelection().selectElement(c),c.is(\"input\",\"textarea\",\"select\")&&b.data.preventDefault())});CKEDITOR.env.edge&&this.attachListener(this,\"mouseup\",function(b){(b=b.data.getTarget())&&b.is(\"img\")&&!b.isReadOnly()&&a.getSelection().selectElement(b)});CKEDITOR.env.gecko&&this.attachListener(this,\"mouseup\",function(b){if(2==b.data.$.button&&(b=b.data.getTarget(),!b.getAscendant(\"table\")&&!b.getOuterHtml().replace(p,\n\"\"))){var c=a.createRange();c.moveToElementEditStart(b);c.select(!0)}});CKEDITOR.env.webkit&&(this.attachListener(this,\"click\",function(a){a.data.getTarget().is(\"input\",\"select\")&&a.data.preventDefault()}),this.attachListener(this,\"mouseup\",function(a){a.data.getTarget().is(\"input\",\"textarea\")&&a.data.preventDefault()}));CKEDITOR.env.webkit&&this.attachListener(a,\"key\",function(b){if(a.readOnly)return!0;var c=b.data.domEvent.getKey();if(c in k&&(b=a.getSelection(),0!==b.getRanges().length)){var c=\n8==c,d=b.getRanges()[0];b=d.startPath();if(d.collapsed)a:{var g=b.block;if(g&&d[c?\"checkStartOfBlock\":\"checkEndOfBlock\"]()&&d.moveToClosestEditablePosition(g,!c)&&d.collapsed){if(d.startContainer.type==CKEDITOR.NODE_ELEMENT){var f=d.startContainer.getChild(d.startOffset-(c?1:0));if(f&&f.type==CKEDITOR.NODE_ELEMENT&&f.is(\"hr\")){a.fire(\"saveSnapshot\");f.remove();b=!0;break a}}d=d.startPath().block;if(!d||d&&d.contains(g))b=void 0;else{a.fire(\"saveSnapshot\");var h;(h=(c?d:g).getBogus())&&h.remove();\nh=a.getSelection();f=h.createBookmarks();(c?g:d).moveChildren(c?d:g,!1);b.lastElement.mergeSiblings();e(g,d,!c);h.selectBookmarks(f);b=!0}}else b=!1}else c=d,h=b.block,d=c.endPath().block,h&&d&&!h.equals(d)?(a.fire(\"saveSnapshot\"),(g=h.getBogus())&&g.remove(),c.enlarge(CKEDITOR.ENLARGE_INLINE),c.deleteContents(),d.getParent()&&(d.moveChildren(h,!1),b.lastElement.mergeSiblings(),e(h,d,!0)),c=a.getSelection().getRanges()[0],c.collapse(1),c.optimize(),\"\"===c.startContainer.getHtml()&&c.startContainer.appendBogus(),\nc.select(),b=!0):b=!1;if(!b)return;a.getSelection().scrollIntoView();a.fire(\"saveSnapshot\");return!1}},this,null,100)}}},_:{detach:function(){this.editor.setData(this.editor.getData(),0,1);this.clearListeners();this.restoreAttrs();var a;if(a=this.removeCustomData(\"classes\"))for(;a.length;)this.removeClass(a.pop());if(!this.is(\"textarea\")){a=this.getDocument();var b=a.getHead();if(b.getCustomData(\"stylesheet\")){var c=a.getCustomData(\"stylesheet_ref\");--c?a.setCustomData(\"stylesheet_ref\",c):(a.removeCustomData(\"stylesheet_ref\"),\nb.removeCustomData(\"stylesheet\").remove())}}this.editor.fire(\"contentDomUnload\");delete this.editor}}});CKEDITOR.editor.prototype.editable=function(a){var b=this._.editable;if(b&&a)return 0;arguments.length&&(b=this._.editable=a?a instanceof CKEDITOR.editable?a:new CKEDITOR.editable(this,a):(b&&b.detach(),null));return b};CKEDITOR.on(\"instanceLoaded\",function(b){var c=b.editor;c.on(\"insertElement\",function(a){a=a.data;a.type==CKEDITOR.NODE_ELEMENT&&(a.is(\"input\")||a.is(\"textarea\"))&&(\"false\"!=a.getAttribute(\"contentEditable\")&&\na.data(\"cke-editable\",a.hasAttribute(\"contenteditable\")?\"true\":\"1\"),a.setAttribute(\"contentEditable\",!1))});c.on(\"selectionChange\",function(b){if(!c.readOnly){var e=c.getSelection();e&&!e.isLocked&&(e=c.checkDirty(),c.fire(\"lockSnapshot\"),a(b),c.fire(\"unlockSnapshot\"),!e&&c.resetDirty())}})});CKEDITOR.on(\"instanceCreated\",function(a){var b=a.editor;b.on(\"mode\",function(){var a=b.editable();if(a&&a.isInline()){var c=b.title;a.changeAttr(\"role\",\"textbox\");a.changeAttr(\"aria-multiline\",\"true\");a.changeAttr(\"aria-label\",\nc);c&&a.changeAttr(\"title\",c);var e=b.fire(\"ariaEditorHelpLabel\",{}).label;if(e&&(c=this.ui.space(this.elementMode==CKEDITOR.ELEMENT_MODE_INLINE?\"top\":\"contents\"))){var d=CKEDITOR.tools.getNextId(),e=CKEDITOR.dom.element.createFromHtml('\\x3cspan id\\x3d\"'+d+'\" class\\x3d\"cke_voice_label\"\\x3e'+e+\"\\x3c/span\\x3e\");c.append(e);a.changeAttr(\"aria-describedby\",d)}}})});CKEDITOR.addCss(\".cke_editable{cursor:text}.cke_editable img,.cke_editable input,.cke_editable textarea{cursor:default}\");n=CKEDITOR.dom.walker.whitespaces(!0);\nq=CKEDITOR.dom.walker.bookmark(!1,!0);y=CKEDITOR.dom.walker.empty();u=CKEDITOR.dom.walker.bogus();p=/(^|<body\\b[^>]*>)\\s*<(p|div|address|h\\d|center|pre)[^>]*>\\s*(?:<br[^>]*>|&nbsp;|\\u00A0|&#160;)?\\s*(:?<\\/\\2>)?\\s*(?=$|<\\/body>)/gi;v=function(){function a(b){return b.type==CKEDITOR.NODE_ELEMENT}function b(c,e){var d,g,f,h,m=[],k=e.range.startContainer;d=e.range.startPath();for(var k=n[k.getName()],l=0,q=c.getChildren(),G=q.count(),v=-1,r=-1,F=0,t=d.contains(n.$list);l<G;++l)d=q.getItem(l),a(d)?(f=\nd.getName(),t&&f in CKEDITOR.dtd.$list?m=m.concat(b(d,e)):(h=!!k[f],\"br\"!=f||!d.data(\"cke-eol\")||l&&l!=G-1||(F=(g=l?m[l-1].node:q.getItem(l+1))&&(!a(g)||!g.is(\"br\")),g=g&&a(g)&&n.$block[g.getName()]),-1!=v||h||(v=l),h||(r=l),m.push({isElement:1,isLineBreak:F,isBlock:d.isBlockBoundary(),hasBlockSibling:g,node:d,name:f,allowed:h}),g=F=0)):m.push({isElement:0,node:d,allowed:1});-1<v&&(m[v].firstNotAllowed=1);-1<r&&(m[r].lastNotAllowed=1);return m}function e(b,c){var d=[],g=b.getChildren(),f=g.count(),\nh,m=0,k=n[c],l=!b.is(n.$inline)||b.is(\"br\");for(l&&d.push(\" \");m<f;m++)h=g.getItem(m),a(h)&&!h.is(k)?d=d.concat(e(h,c)):d.push(h);l&&d.push(\" \");return d}function d(b){return a(b.startContainer)&&b.startContainer.getChild(b.startOffset-1)}function f(b){return b&&a(b)&&(b.is(n.$removeEmpty)||b.is(\"a\")&&!b.isBlockBoundary())}function m(b,c,e,d){var g=b.clone(),f,h;g.setEndAt(c,CKEDITOR.POSITION_BEFORE_END);(f=(new CKEDITOR.dom.walker(g)).next())&&a(f)&&q[f.getName()]&&(h=f.getPrevious())&&a(h)&&!h.getParent().equals(b.startContainer)&&\ne.contains(h)&&d.contains(f)&&f.isIdentical(h)&&(f.moveChildren(h),f.remove(),m(b,c,e,d))}function l(b,c){function e(b,c){if(c.isBlock&&c.isElement&&!c.node.is(\"br\")&&a(b)&&b.is(\"br\"))return b.remove(),1}var d=c.endContainer.getChild(c.endOffset),g=c.endContainer.getChild(c.endOffset-1);d&&e(d,b[b.length-1]);g&&e(g,b[0])&&(c.setEnd(c.endContainer,c.endOffset-1),c.collapse())}var n=CKEDITOR.dtd,q={p:1,div:1,h1:1,h2:1,h3:1,h4:1,h5:1,h6:1,ul:1,ol:1,li:1,pre:1,dl:1,blockquote:1},v={p:1,div:1,h1:1,h2:1,\nh3:1,h4:1,h5:1,h6:1},G=CKEDITOR.tools.extend({},n.$inline);delete G.br;return function(D,q,r,t){var w=D.editor,z=!1;\"unfiltered_html\"==q&&(q=\"html\",z=!0);if(!t.checkReadOnly()){var y=(new CKEDITOR.dom.elementPath(t.startContainer,t.root)).blockLimit||t.root;q={type:q,dontFilter:z,editable:D,editor:w,range:t,blockLimit:y,mergeCandidates:[],zombies:[]};var z=q.range,y=q.mergeCandidates,u=\"html\"===q.type,p,E,U,ba,ca,V;\"text\"==q.type&&z.shrink(CKEDITOR.SHRINK_ELEMENT,!0,!1)&&(E=CKEDITOR.dom.element.createFromHtml(\"\\x3cspan\\x3e\\x26nbsp;\\x3c/span\\x3e\",\nz.document),z.insertNode(E),z.setStartAfter(E));U=new CKEDITOR.dom.elementPath(z.startContainer);q.endPath=ba=new CKEDITOR.dom.elementPath(z.endContainer);if(!z.collapsed){p=ba.block||ba.blockLimit;var M=z.getCommonAncestor();p&&!p.equals(M)&&!p.contains(M)&&z.checkEndOfBlock()&&q.zombies.push(p);z.deleteContents()}for(;(ca=d(z))&&a(ca)&&ca.isBlockBoundary()&&U.contains(ca);)z.moveToPosition(ca,CKEDITOR.POSITION_BEFORE_END);m(z,q.blockLimit,U,ba);E&&(z.setEndBefore(E),z.collapse(),E.remove());E=z.startPath();\nif(p=E.contains(f,!1,1))V=z.splitElement(p),q.inlineStylesRoot=p,q.inlineStylesPeak=E.lastElement;E=z.createBookmark();u&&(h(p),h(V));(p=E.startNode.getPrevious(c))&&a(p)&&f(p)&&y.push(p);(p=E.startNode.getNext(c))&&a(p)&&f(p)&&y.push(p);for(p=E.startNode;(p=p.getParent())&&f(p);)y.push(p);z.moveToBookmark(E);\"\"===w.getData()&&w.enterMode===CKEDITOR.ENTER_DIV&&((w=D.getFirst())&&w.remove(),t.setStartAt(D,CKEDITOR.POSITION_AFTER_START),t.collapse(!0));if(D=r){D=q.range;if(\"text\"==q.type&&q.inlineStylesRoot){t=\nq.inlineStylesPeak;w=t.getDocument().createText(\"{cke-peak}\");for(V=q.inlineStylesRoot.getParent();!t.equals(V);)w=w.appendTo(t.clone()),t=t.getParent();r=w.getOuterHtml().split(\"{cke-peak}\").join(r)}t=q.blockLimit.getName();if(/^\\s+|\\s+$/.test(r)&&\"span\"in CKEDITOR.dtd[t]){var aa='\\x3cspan data-cke-marker\\x3d\"1\"\\x3e\\x26nbsp;\\x3c/span\\x3e';r=aa+r+aa}r=q.editor.dataProcessor.toHtml(r,{context:null,fixForBody:!1,protectedWhitespaces:!!aa,dontFilter:q.dontFilter,filter:q.editor.activeFilter,enterMode:q.editor.activeEnterMode});\nt=D.document.createElement(\"body\");t.setHtml(r);aa&&(t.getFirst().remove(),t.getLast().remove());if((aa=D.startPath().block)&&(1!=aa.getChildCount()||!aa.getBogus()))a:{var P;if(1==t.getChildCount()&&a(P=t.getFirst())&&P.is(v)&&!P.hasAttribute(\"contenteditable\")){aa=P.getElementsByTag(\"*\");D=0;for(V=aa.count();D<V;D++)if(w=aa.getItem(D),!w.is(G))break a;P.moveChildren(P.getParent(1));P.remove()}}q.dataWrapper=t;D=r}if(D){P=q.range;D=P.document;t=q.blockLimit;V=0;var S,aa=[],T,Y;r=E=0;var da,w=P.startContainer;\nca=q.endPath.elements[0];var ga,z=ca.getPosition(w),y=!!ca.getCommonAncestor(w)&&z!=CKEDITOR.POSITION_IDENTICAL&&!(z&CKEDITOR.POSITION_CONTAINS+CKEDITOR.POSITION_IS_CONTAINED),w=b(q.dataWrapper,q);for(l(w,P);V<w.length;V++){z=w[V];if(u=z.isLineBreak)u=P,p=t,ba=U=void 0,z.hasBlockSibling?u=1:(U=u.startContainer.getAscendant(n.$block,1))&&U.is({div:1,p:1})?(ba=U.getPosition(p),ba==CKEDITOR.POSITION_IDENTICAL||ba==CKEDITOR.POSITION_CONTAINS?u=0:(p=u.splitElement(U),u.moveToPosition(p,CKEDITOR.POSITION_AFTER_START),\nu=1)):u=0;if(u)r=0<V;else{u=P.startPath();!z.isBlock&&k(q.editor,u.block,u.blockLimit)&&(Y=g(q.editor))&&(Y=D.createElement(Y),Y.appendBogus(),P.insertNode(Y),CKEDITOR.env.needsBrFiller&&(S=Y.getBogus())&&S.remove(),P.moveToPosition(Y,CKEDITOR.POSITION_BEFORE_END));if((u=P.startPath().block)&&!u.equals(T)){if(S=u.getBogus())S.remove(),aa.push(u);T=u}z.firstNotAllowed&&(E=1);if(E&&z.isElement){u=P.startContainer;for(p=null;u&&!n[u.getName()][z.name];){if(u.equals(t)){u=null;break}p=u;u=u.getParent()}if(u)p&&\n(da=P.splitElement(p),q.zombies.push(da),q.zombies.push(p));else{p=t.getName();ga=!V;u=V==w.length-1;p=e(z.node,p);U=[];ba=p.length;for(var M=0,ia=void 0,ea=0,ja=-1;M<ba;M++)ia=p[M],\" \"==ia?(ea||ga&&!M||(U.push(new CKEDITOR.dom.text(\" \")),ja=U.length),ea=1):(U.push(ia),ea=0);u&&ja==U.length&&U.pop();ga=U}}if(ga){for(;u=ga.pop();)P.insertNode(u);ga=0}else P.insertNode(z.node);z.lastNotAllowed&&V<w.length-1&&((da=y?ca:da)&&P.setEndAt(da,CKEDITOR.POSITION_AFTER_START),E=0);P.collapse()}}1!=w.length?\nS=!1:(S=w[0],S=S.isElement&&\"false\"==S.node.getAttribute(\"contenteditable\"));S&&(r=!0,u=w[0].node,P.setStartAt(u,CKEDITOR.POSITION_BEFORE_START),P.setEndAt(u,CKEDITOR.POSITION_AFTER_END));q.dontMoveCaret=r;q.bogusNeededBlocks=aa}S=q.range;var fa;da=q.bogusNeededBlocks;for(ga=S.createBookmark();T=q.zombies.pop();)T.getParent()&&(Y=S.clone(),Y.moveToElementEditStart(T),Y.removeEmptyBlocksAtEnd());if(da)for(;T=da.pop();)CKEDITOR.env.needsBrFiller?T.appendBogus():T.append(S.document.createText(\" \"));\nfor(;T=q.mergeCandidates.pop();)T.mergeSiblings();S.moveToBookmark(ga);if(!q.dontMoveCaret){for(T=d(S);T&&a(T)&&!T.is(n.$empty);){if(T.isBlockBoundary())S.moveToPosition(T,CKEDITOR.POSITION_BEFORE_END);else{if(f(T)&&T.getHtml().match(/(\\s|&nbsp;)$/g)){fa=null;break}fa=S.clone();fa.moveToPosition(T,CKEDITOR.POSITION_BEFORE_END)}T=T.getLast(c)}fa&&S.moveToRange(fa)}}}}();w=function(){function a(b){b=new CKEDITOR.dom.walker(b);b.guard=function(a,b){if(b)return!1;if(a.type==CKEDITOR.NODE_ELEMENT)return a.is(CKEDITOR.dtd.$tableContent)};\nb.evaluator=function(a){return a.type==CKEDITOR.NODE_ELEMENT};return b}function b(a,c,e){c=a.getDocument().createElement(c);a.append(c,e);return c}function c(a){var b=a.count(),e;for(b;0<b--;)e=a.getItem(b),CKEDITOR.tools.trim(e.getHtml())||(e.appendBogus(),CKEDITOR.env.ie&&9>CKEDITOR.env.version&&e.getChildCount()&&e.getFirst().remove())}return function(e){var d=e.startContainer,g=d.getAscendant(\"table\",1),f=!1;c(g.getElementsByTag(\"td\"));c(g.getElementsByTag(\"th\"));g=e.clone();g.setStart(d,0);g=\na(g).lastBackward();g||(g=e.clone(),g.setEndAt(d,CKEDITOR.POSITION_BEFORE_END),g=a(g).lastForward(),f=!0);g||(g=d);g.is(\"table\")?(e.setStartAt(g,CKEDITOR.POSITION_BEFORE_START),e.collapse(!0),g.remove()):(g.is({tbody:1,thead:1,tfoot:1})&&(g=b(g,\"tr\",f)),g.is(\"tr\")&&(g=b(g,g.getParent().is(\"thead\")?\"th\":\"td\",f)),(d=g.getBogus())&&d.remove(),e.moveToPosition(g,f?CKEDITOR.POSITION_AFTER_START:CKEDITOR.POSITION_BEFORE_END))}}();r=function(){function a(b){b=new CKEDITOR.dom.walker(b);b.guard=function(a,\nb){if(b)return!1;if(a.type==CKEDITOR.NODE_ELEMENT)return a.is(CKEDITOR.dtd.$list)||a.is(CKEDITOR.dtd.$listItem)};b.evaluator=function(a){return a.type==CKEDITOR.NODE_ELEMENT&&a.is(CKEDITOR.dtd.$listItem)};return b}return function(b){var c=b.startContainer,e=!1,d;d=b.clone();d.setStart(c,0);d=a(d).lastBackward();d||(d=b.clone(),d.setEndAt(c,CKEDITOR.POSITION_BEFORE_END),d=a(d).lastForward(),e=!0);d||(d=c);d.is(CKEDITOR.dtd.$list)?(b.setStartAt(d,CKEDITOR.POSITION_BEFORE_START),b.collapse(!0),d.remove()):\n((c=d.getBogus())&&c.remove(),b.moveToPosition(d,e?CKEDITOR.POSITION_AFTER_START:CKEDITOR.POSITION_BEFORE_END),b.select())}}();z={eol:{detect:function(a,b){var c=a.range,e=c.clone(),d=c.clone(),g=new CKEDITOR.dom.elementPath(c.startContainer,b),f=new CKEDITOR.dom.elementPath(c.endContainer,b);e.collapse(1);d.collapse();g.block&&e.checkBoundaryOfElement(g.block,CKEDITOR.END)&&(c.setStartAfter(g.block),a.prependEolBr=1);f.block&&d.checkBoundaryOfElement(f.block,CKEDITOR.START)&&(c.setEndBefore(f.block),\na.appendEolBr=1)},fix:function(a,b){var c=b.getDocument(),e;a.appendEolBr&&(e=this.createEolBr(c),a.fragment.append(e));!a.prependEolBr||e&&!e.getPrevious()||a.fragment.append(this.createEolBr(c),1)},createEolBr:function(a){return a.createElement(\"br\",{attributes:{\"data-cke-eol\":1}})}},bogus:{exclude:function(a){var b=a.range.getBoundaryNodes(),c=b.startNode,b=b.endNode;!b||!u(b)||c&&c.equals(b)||a.range.setEndBefore(b)}},tree:{rebuild:function(a,b){var c=a.range,e=c.getCommonAncestor(),d=new CKEDITOR.dom.elementPath(e,\nb),g=new CKEDITOR.dom.elementPath(c.startContainer,b),c=new CKEDITOR.dom.elementPath(c.endContainer,b),f;e.type==CKEDITOR.NODE_TEXT&&(e=e.getParent());if(d.blockLimit.is({tr:1,table:1})){var h=d.contains(\"table\").getParent();f=function(a){return!a.equals(h)}}else if(d.block&&d.block.is(CKEDITOR.dtd.$listItem)&&(g=g.contains(CKEDITOR.dtd.$list),c=c.contains(CKEDITOR.dtd.$list),!g.equals(c))){var m=d.contains(CKEDITOR.dtd.$list).getParent();f=function(a){return!a.equals(m)}}f||(f=function(a){return!a.equals(d.block)&&\n!a.equals(d.blockLimit)});this.rebuildFragment(a,b,e,f)},rebuildFragment:function(a,b,c,e){for(var d;c&&!c.equals(b)&&e(c);)d=c.clone(0,1),a.fragment.appendTo(d),a.fragment=d,c=c.getParent()}},cell:{shrink:function(a){a=a.range;var b=a.startContainer,c=a.endContainer,e=a.startOffset,d=a.endOffset;b.type==CKEDITOR.NODE_ELEMENT&&b.equals(c)&&b.is(\"tr\")&&++e==d&&a.shrink(CKEDITOR.SHRINK_TEXT)}}};t=function(){function a(b,c){var e=b.getParent();if(e.is(CKEDITOR.dtd.$inline))b[c?\"insertBefore\":\"insertAfter\"](e)}\nfunction b(c,e,d){a(e);a(d,1);for(var g;g=d.getNext();)g.insertAfter(e),e=g;y(c)&&c.remove()}function c(a,b){var e=new CKEDITOR.dom.range(a);e.setStartAfter(b.startNode);e.setEndBefore(b.endNode);return e}return{list:{detectMerge:function(a,b){var e=c(b,a.bookmark),d=e.startPath(),g=e.endPath(),f=d.contains(CKEDITOR.dtd.$list),h=g.contains(CKEDITOR.dtd.$list);a.mergeList=f&&h&&f.getParent().equals(h.getParent())&&!f.equals(h);a.mergeListItems=d.block&&g.block&&d.block.is(CKEDITOR.dtd.$listItem)&&\ng.block.is(CKEDITOR.dtd.$listItem);if(a.mergeList||a.mergeListItems)e=e.clone(),e.setStartBefore(a.bookmark.startNode),e.setEndAfter(a.bookmark.endNode),a.mergeListBookmark=e.createBookmark()},merge:function(a,c){if(a.mergeListBookmark){var e=a.mergeListBookmark.startNode,d=a.mergeListBookmark.endNode,g=new CKEDITOR.dom.elementPath(e,c),f=new CKEDITOR.dom.elementPath(d,c);if(a.mergeList){var h=g.contains(CKEDITOR.dtd.$list),m=f.contains(CKEDITOR.dtd.$list);h.equals(m)||(m.moveChildren(h),m.remove())}a.mergeListItems&&\n(g=g.contains(CKEDITOR.dtd.$listItem),f=f.contains(CKEDITOR.dtd.$listItem),g.equals(f)||b(f,e,d));e.remove();d.remove()}}},block:{detectMerge:function(a,b){if(!a.tableContentsRanges&&!a.mergeListBookmark){var c=new CKEDITOR.dom.range(b);c.setStartBefore(a.bookmark.startNode);c.setEndAfter(a.bookmark.endNode);a.mergeBlockBookmark=c.createBookmark()}},merge:function(a,c){if(a.mergeBlockBookmark&&!a.purgeTableBookmark){var e=a.mergeBlockBookmark.startNode,d=a.mergeBlockBookmark.endNode,g=new CKEDITOR.dom.elementPath(e,\nc),f=new CKEDITOR.dom.elementPath(d,c),g=g.block,f=f.block;g&&f&&!g.equals(f)&&b(f,e,d);e.remove();d.remove()}}},table:function(){function a(c){var d=[],g,f=new CKEDITOR.dom.walker(c),h=c.startPath().contains(e),m=c.endPath().contains(e),k={};f.guard=function(a,f){if(a.type==CKEDITOR.NODE_ELEMENT){var l=\"visited_\"+(f?\"out\":\"in\");if(a.getCustomData(l))return;CKEDITOR.dom.element.setMarker(k,a,l,1)}if(f&&h&&a.equals(h))g=c.clone(),g.setEndAt(h,CKEDITOR.POSITION_BEFORE_END),d.push(g);else if(!f&&m&&\na.equals(m))g=c.clone(),g.setStartAt(m,CKEDITOR.POSITION_AFTER_START),d.push(g);else{if(l=!f)l=a.type==CKEDITOR.NODE_ELEMENT&&a.is(e)&&(!h||b(a,h))&&(!m||b(a,m));if(!l&&(l=f))if(a.is(e))var l=h&&h.getAscendant(\"table\",!0),n=m&&m.getAscendant(\"table\",!0),q=a.getAscendant(\"table\",!0),l=l&&l.contains(q)||n&&n.contains(q);else l=void 0;l&&(g=c.clone(),g.selectNodeContents(a),d.push(g))}};f.lastForward();CKEDITOR.dom.element.clearAllMarkers(k);return d}function b(a,c){var e=CKEDITOR.POSITION_CONTAINS+\nCKEDITOR.POSITION_IS_CONTAINED,d=a.getPosition(c);return d===CKEDITOR.POSITION_IDENTICAL?!1:0===(d&e)}var e={td:1,th:1,caption:1};return{detectPurge:function(a){var b=a.range,c=b.clone();c.enlarge(CKEDITOR.ENLARGE_ELEMENT);var c=new CKEDITOR.dom.walker(c),d=0;c.evaluator=function(a){a.type==CKEDITOR.NODE_ELEMENT&&a.is(e)&&++d};c.checkForward();if(1<d){var c=b.startPath().contains(\"table\"),g=b.endPath().contains(\"table\");c&&g&&b.checkBoundaryOfElement(c,CKEDITOR.START)&&b.checkBoundaryOfElement(g,\nCKEDITOR.END)&&(b=a.range.clone(),b.setStartBefore(c),b.setEndAfter(g),a.purgeTableBookmark=b.createBookmark())}},detectRanges:function(d,g){var f=c(g,d.bookmark),h=f.clone(),m,k,l=f.getCommonAncestor();l.is(CKEDITOR.dtd.$tableContent)&&!l.is(e)&&(l=l.getAscendant(\"table\",!0));k=l;l=new CKEDITOR.dom.elementPath(f.startContainer,k);k=new CKEDITOR.dom.elementPath(f.endContainer,k);l=l.contains(\"table\");k=k.contains(\"table\");if(l||k)l&&k&&b(l,k)?(d.tableSurroundingRange=h,h.setStartAt(l,CKEDITOR.POSITION_AFTER_END),\nh.setEndAt(k,CKEDITOR.POSITION_BEFORE_START),h=f.clone(),h.setEndAt(l,CKEDITOR.POSITION_AFTER_END),m=f.clone(),m.setStartAt(k,CKEDITOR.POSITION_BEFORE_START),m=a(h).concat(a(m))):l?k||(d.tableSurroundingRange=h,h.setStartAt(l,CKEDITOR.POSITION_AFTER_END),f.setEndAt(l,CKEDITOR.POSITION_AFTER_END)):(d.tableSurroundingRange=h,h.setEndAt(k,CKEDITOR.POSITION_BEFORE_START),f.setStartAt(k,CKEDITOR.POSITION_AFTER_START)),d.tableContentsRanges=m?m:a(f)},deleteRanges:function(a){for(var b;b=a.tableContentsRanges.pop();)b.extractContents(),\ny(b.startContainer)&&b.startContainer.appendBogus();a.tableSurroundingRange&&a.tableSurroundingRange.extractContents()},purge:function(a){if(a.purgeTableBookmark){var b=a.doc,c=a.range.clone(),b=b.createElement(\"p\");b.insertBefore(a.purgeTableBookmark.startNode);c.moveToBookmark(a.purgeTableBookmark);c.deleteContents();a.range.moveToPosition(b,CKEDITOR.POSITION_AFTER_START)}}}}(),detectExtractMerge:function(a){return!(a.range.startPath().contains(CKEDITOR.dtd.$listItem)&&a.range.endPath().contains(CKEDITOR.dtd.$listItem))},\nfixUneditableRangePosition:function(a){a.startContainer.getDtd()[\"#\"]||a.moveToClosestEditablePosition(null,!0)},autoParagraph:function(a,b){var c=b.startPath(),e;k(a,c.block,c.blockLimit)&&(e=g(a))&&(e=b.document.createElement(e),e.appendBogus(),b.insertNode(e),b.moveToPosition(e,CKEDITOR.POSITION_AFTER_START))}}}()}(),function(){function a(a){return CKEDITOR.plugins.widget&&CKEDITOR.plugins.widget.isDomWidget(a)}function f(b,c){if(0===b.length||a(b[0].getEnclosedNode()))return!1;var e,d;if((e=!c&&\n1===b.length)&&!(e=b[0].collapsed)){var g=b[0];e=g.startContainer.getAscendant({td:1,th:1},!0);var f=g.endContainer.getAscendant({td:1,th:1},!0);d=CKEDITOR.tools.trim;e&&e.equals(f)&&!e.findOne(\"td, th, tr, tbody, table\")?(g=g.cloneContents(),e=g.getFirst()?d(g.getFirst().getText())!==d(e.getText()):!0):e=!1}if(e)return!1;for(d=0;d<b.length;d++)if(e=b[d]._getTableElement(),!e)return!1;return!0}function b(a){function b(a){a=a.find(\"td, th\");var c=[],e;for(e=0;e<a.count();e++)c.push(a.getItem(e));return c}\nvar c=[],e,d;for(d=0;d<a.length;d++)e=a[d]._getTableElement(),e.is&&e.is({td:1,th:1})?c.push(e):c=c.concat(b(e));return c}function c(a){a=b(a);var c=\"\",e=[],d,g;for(g=0;g<a.length;g++)d&&!d.equals(a[g].getAscendant(\"tr\"))?(c+=e.join(\"\\t\")+\"\\n\",d=a[g].getAscendant(\"tr\"),e=[]):0===g&&(d=a[g].getAscendant(\"tr\")),e.push(a[g].getText());return c+=e.join(\"\\t\")}function d(a){var b=this.root.editor,e=b.getSelection(1);this.reset();t=!0;e.root.once(\"selectionchange\",function(a){a.cancel()},null,null,0);e.selectRanges([a[0]]);\ne=this._.cache;e.ranges=new CKEDITOR.dom.rangeList(a);e.type=CKEDITOR.SELECTION_TEXT;e.selectedElement=a[0]._getTableElement();e.selectedText=c(a);e.nativeSel=null;this.isFake=1;this.rev=w++;b._.fakeSelection=this;t=!1;this.root.fire(\"selectionchange\")}function l(){var b=this._.fakeSelection,c;if(b){c=this.getSelection(1);var e;if(!(e=!c)&&(e=!c.isHidden())){e=b;var d=c.getRanges(),g=e.getRanges(),h=d.length&&d[0]._getTableElement()&&d[0]._getTableElement().getAscendant(\"table\",!0),m=g.length&&g[0]._getTableElement()&&\ng[0]._getTableElement().getAscendant(\"table\",!0),k=1===d.length&&d[0]._getTableElement()&&d[0]._getTableElement().is(\"table\"),l=1===g.length&&g[0]._getTableElement()&&g[0]._getTableElement().is(\"table\");if(a(e.getSelectedElement()))e=!1;else{var n=1===d.length&&d[0].collapsed,g=f(d,!!CKEDITOR.env.webkit)&&f(g);h=h&&m?h.equals(m)||m.contains(h):!1;h&&(n||g)?(k&&!l&&e.selectRanges(d),e=!0):e=!1}e=!e}e&&(b.reset(),b=0)}if(!b&&(b=c||this.getSelection(1),!b||b.getType()==CKEDITOR.SELECTION_NONE))return;\nthis.fire(\"selectionCheck\",b);c=this.elementPath();c.compare(this._.selectionPreviousPath)||(e=this._.selectionPreviousPath&&this._.selectionPreviousPath.blockLimit.equals(c.blockLimit),!CKEDITOR.env.webkit&&!CKEDITOR.env.gecko||e||(this._.previousActive=this.document.getActive()),this._.selectionPreviousPath=c,this.fire(\"selectionChange\",{selection:b,path:c}))}function k(){A=!0;x||(g.call(this),x=CKEDITOR.tools.setTimeout(g,200,this))}function g(){x=null;A&&(CKEDITOR.tools.setTimeout(l,0,this),A=\n!1)}function h(a){return B(a)||a.type==CKEDITOR.NODE_ELEMENT&&!a.is(CKEDITOR.dtd.$empty)?!0:!1}function m(a){function b(c,e){return c&&c.type!=CKEDITOR.NODE_TEXT?a.clone()[\"moveToElementEdit\"+(e?\"End\":\"Start\")](c):!1}if(!(a.root instanceof CKEDITOR.editable))return!1;var c=a.startContainer,e=a.getPreviousNode(h,null,c),d=a.getNextNode(h,null,c);return b(e)||b(d,1)||!(e||d||c.type==CKEDITOR.NODE_ELEMENT&&c.isBlockBoundary()&&c.getBogus())?!0:!1}function e(a){n(a,!1);var b=a.getDocument().createText(r);\na.setCustomData(\"cke-fillingChar\",b);return b}function n(a,b){var c=a&&a.removeCustomData(\"cke-fillingChar\");if(c){if(!1!==b){var e=a.getDocument().getSelection().getNative(),d=e&&\"None\"!=e.type&&e.getRangeAt(0),g=r.length;if(c.getLength()>g&&d&&d.intersectsNode(c.$)){var f=[{node:e.anchorNode,offset:e.anchorOffset},{node:e.focusNode,offset:e.focusOffset}];e.anchorNode==c.$&&e.anchorOffset>g&&(f[0].offset-=g);e.focusNode==c.$&&e.focusOffset>g&&(f[1].offset-=g)}}c.setText(q(c.getText(),1));f&&(c=a.getDocument().$,\ne=c.getSelection(),c=c.createRange(),c.setStart(f[0].node,f[0].offset),c.collapse(!0),e.removeAllRanges(),e.addRange(c),e.extend(f[1].node,f[1].offset))}}function q(a,b){return b?a.replace(z,function(a,b){return b?\" \":\"\"}):a.replace(r,\"\")}function y(a,b){var c=b&&CKEDITOR.tools.htmlEncode(b)||\"\\x26nbsp;\",c=CKEDITOR.dom.element.createFromHtml('\\x3cdiv data-cke-hidden-sel\\x3d\"1\" data-cke-temp\\x3d\"1\" style\\x3d\"'+(CKEDITOR.env.ie&&14>CKEDITOR.env.version?\"display:none\":\"position:fixed;top:0;left:-1000px;width:0;height:0;overflow:hidden;\")+\n'\"\\x3e'+c+\"\\x3c/div\\x3e\",a.document);a.fire(\"lockSnapshot\");a.editable().append(c);var e=a.getSelection(1),d=a.createRange(),g=e.root.on(\"selectionchange\",function(a){a.cancel()},null,null,0);d.setStartAt(c,CKEDITOR.POSITION_AFTER_START);d.setEndAt(c,CKEDITOR.POSITION_BEFORE_END);e.selectRanges([d]);g.removeListener();a.fire(\"unlockSnapshot\");a._.hiddenSelectionContainer=c}function u(a){var b={37:1,39:1,8:1,46:1};return function(c){var e=c.data.getKeystroke();if(b[e]){var d=a.getSelection().getRanges(),\ng=d[0];1==d.length&&g.collapsed&&(e=g[38>e?\"getPreviousEditableNode\":\"getNextEditableNode\"]())&&e.type==CKEDITOR.NODE_ELEMENT&&\"false\"==e.getAttribute(\"contenteditable\")&&(a.getSelection().fake(e),c.data.preventDefault(),c.cancel())}}}function p(a){for(var b=0;b<a.length;b++){var c=a[b];c.getCommonAncestor().isReadOnly()&&a.splice(b,1);if(!c.collapsed){if(c.startContainer.isReadOnly())for(var e=c.startContainer,d;e&&!((d=e.type==CKEDITOR.NODE_ELEMENT)&&e.is(\"body\")||!e.isReadOnly());)d&&\"false\"==\ne.getAttribute(\"contentEditable\")&&c.setStartAfter(e),e=e.getParent();e=c.startContainer;d=c.endContainer;var g=c.startOffset,f=c.endOffset,h=c.clone();e&&e.type==CKEDITOR.NODE_TEXT&&(g>=e.getLength()?h.setStartAfter(e):h.setStartBefore(e));d&&d.type==CKEDITOR.NODE_TEXT&&(f?h.setEndAfter(d):h.setEndBefore(d));e=new CKEDITOR.dom.walker(h);e.evaluator=function(e){if(e.type==CKEDITOR.NODE_ELEMENT&&e.isReadOnly()){var d=c.clone();c.setEndBefore(e);c.collapsed&&a.splice(b--,1);e.getPosition(h.endContainer)&\nCKEDITOR.POSITION_CONTAINS||(d.setStartAfter(e),d.collapsed||a.splice(b+1,0,d));return!0}return!1};e.next()}}return a}var v=\"function\"!=typeof window.getSelection,w=1,r=CKEDITOR.tools.repeat(\"​\",7),z=new RegExp(r+\"( )?\",\"g\"),t,x,A,B=CKEDITOR.dom.walker.invisible(1),C=function(){function a(b){return function(a){var c=a.editor.createRange();c.moveToClosestEditablePosition(a.selected,b)&&a.editor.getSelection().selectRanges([c]);return!1}}function b(a){return function(b){var c=b.editor,e=c.createRange(),\nd;if(!c.readOnly)return(d=e.moveToClosestEditablePosition(b.selected,a))||(d=e.moveToClosestEditablePosition(b.selected,!a)),d&&c.getSelection().selectRanges([e]),c.fire(\"saveSnapshot\"),b.selected.remove(),d||(e.moveToElementEditablePosition(c.editable()),c.getSelection().selectRanges([e])),c.fire(\"saveSnapshot\"),!1}}var c=a(),e=a(1);return{37:c,38:c,39:e,40:e,8:b(),46:b(1)}}();CKEDITOR.on(\"instanceCreated\",function(a){function b(){var a=c.getSelection();a&&a.removeAllRanges()}var c=a.editor;c.on(\"contentDom\",\nfunction(){function a(){t=new CKEDITOR.dom.selection(c.getSelection());t.lock()}function b(){g.removeListener(\"mouseup\",b);m.removeListener(\"mouseup\",b);var a=CKEDITOR.document.$.selection,c=a.createRange();\"None\"!=a.type&&c.parentElement()&&c.parentElement().ownerDocument==d.$&&c.select()}function e(a){a=a.getRanges()[0];return a?(a=a.startContainer.getAscendant(function(a){return a.type==CKEDITOR.NODE_ELEMENT&&a.hasAttribute(\"contenteditable\")},!0))&&\"false\"===a.getAttribute(\"contenteditable\")?\na:null:null}var d=c.document,g=CKEDITOR.document,f=c.editable(),h=d.getBody(),m=d.getDocumentElement(),q=f.isInline(),r,t;CKEDITOR.env.gecko&&f.attachListener(f,\"focus\",function(a){a.removeListener();0!==r&&(a=c.getSelection().getNative())&&a.isCollapsed&&a.anchorNode==f.$&&(a=c.createRange(),a.moveToElementEditStart(f),a.select())},null,null,-2);f.attachListener(f,CKEDITOR.env.webkit||CKEDITOR.env.gecko?\"focusin\":\"focus\",function(){if(r&&(CKEDITOR.env.webkit||CKEDITOR.env.gecko)){r=c._.previousActive&&\nc._.previousActive.equals(d.getActive());var a=null!=c._.previousScrollTop&&c._.previousScrollTop!=f.$.scrollTop;CKEDITOR.env.webkit&&r&&a&&(f.$.scrollTop=c._.previousScrollTop)}c.unlockSelection(r);r=0},null,null,-1);f.attachListener(f,\"mousedown\",function(){r=0});if(CKEDITOR.env.ie||q)v?f.attachListener(f,\"beforedeactivate\",a,null,null,-1):f.attachListener(c,\"selectionCheck\",a,null,null,-1),f.attachListener(f,CKEDITOR.env.webkit||CKEDITOR.env.gecko?\"focusout\":\"blur\",function(){c.lockSelection(t);\nr=1},null,null,-1),f.attachListener(f,\"mousedown\",function(){r=0});if(CKEDITOR.env.ie&&!q){var w;f.attachListener(f,\"mousedown\",function(a){2==a.data.$.button&&((a=c.document.getSelection())&&a.getType()!=CKEDITOR.SELECTION_NONE||(w=c.window.getScrollPosition()))});f.attachListener(f,\"mouseup\",function(a){2==a.data.$.button&&w&&(c.document.$.documentElement.scrollLeft=w.x,c.document.$.documentElement.scrollTop=w.y);w=null});if(\"BackCompat\"!=d.$.compatMode){if(CKEDITOR.env.ie7Compat||CKEDITOR.env.ie6Compat){var z,\ny;m.on(\"mousedown\",function(a){function b(a){a=a.data.$;if(z){var c=h.$.createTextRange();try{c.moveToPoint(a.clientX,a.clientY)}catch(e){}z.setEndPoint(0>y.compareEndPoints(\"StartToStart\",c)?\"EndToEnd\":\"StartToStart\",c);z.select()}}function c(){m.removeListener(\"mousemove\",b);g.removeListener(\"mouseup\",c);m.removeListener(\"mouseup\",c);z.select()}a=a.data;if(a.getTarget().is(\"html\")&&a.$.y<m.$.clientHeight&&a.$.x<m.$.clientWidth){z=h.$.createTextRange();try{z.moveToPoint(a.$.clientX,a.$.clientY)}catch(e){}y=\nz.duplicate();m.on(\"mousemove\",b);g.on(\"mouseup\",c);m.on(\"mouseup\",c)}})}if(7<CKEDITOR.env.version&&11>CKEDITOR.env.version)m.on(\"mousedown\",function(a){a.data.getTarget().is(\"html\")&&(g.on(\"mouseup\",b),m.on(\"mouseup\",b))})}}f.attachListener(f,\"selectionchange\",l,c);f.attachListener(f,\"keyup\",k,c);f.attachListener(f,\"touchstart\",k,c);f.attachListener(f,\"touchend\",k,c);CKEDITOR.env.ie&&f.attachListener(f,\"keydown\",function(a){var b=this.getSelection(1),c=e(b);c&&!c.equals(f)&&(b.selectElement(c),a.data.preventDefault())},\nc);f.attachListener(f,CKEDITOR.env.webkit||CKEDITOR.env.gecko?\"focusin\":\"focus\",function(){c.forceNextSelectionCheck();c.selectionChange(1)});if(q&&(CKEDITOR.env.webkit||CKEDITOR.env.gecko)){var p;f.attachListener(f,\"mousedown\",function(){p=1});f.attachListener(d.getDocumentElement(),\"mouseup\",function(){p&&k.call(c);p=0})}else f.attachListener(CKEDITOR.env.ie?f:d.getDocumentElement(),\"mouseup\",k,c);CKEDITOR.env.webkit&&f.attachListener(d,\"keydown\",function(a){switch(a.data.getKey()){case 13:case 33:case 34:case 35:case 36:case 37:case 39:case 8:case 45:case 46:f.hasFocus&&\nn(f)}},null,null,-1);f.attachListener(f,\"keydown\",u(c),null,null,-1)});c.on(\"setData\",function(){c.unlockSelection();CKEDITOR.env.webkit&&b()});c.on(\"contentDomUnload\",function(){c.unlockSelection()});if(CKEDITOR.env.ie9Compat)c.on(\"beforeDestroy\",b,null,null,9);c.on(\"dataReady\",function(){delete c._.fakeSelection;delete c._.hiddenSelectionContainer;c.selectionChange(1)});c.on(\"loadSnapshot\",function(){var a=CKEDITOR.dom.walker.nodeType(CKEDITOR.NODE_ELEMENT),b=c.editable().getLast(a);b&&b.hasAttribute(\"data-cke-hidden-sel\")&&\n(b.remove(),CKEDITOR.env.gecko&&(a=c.editable().getFirst(a))&&a.is(\"br\")&&a.getAttribute(\"_moz_editor_bogus_node\")&&a.remove())},null,null,100);c.on(\"key\",function(a){if(\"wysiwyg\"==c.mode){var b=c.getSelection();if(b.isFake){var e=C[a.data.keyCode];if(e)return e({editor:c,selected:b.getSelectedElement(),selection:b,keyEvent:a})}}})});if(CKEDITOR.env.webkit)CKEDITOR.on(\"instanceReady\",function(a){var b=a.editor;b.on(\"selectionChange\",function(){var a=b.editable(),c=a.getCustomData(\"cke-fillingChar\");\nc&&(c.getCustomData(\"ready\")?(n(a),a.editor.fire(\"selectionCheck\")):c.setCustomData(\"ready\",1))},null,null,-1);b.on(\"beforeSetMode\",function(){n(b.editable())},null,null,-1);b.on(\"getSnapshot\",function(a){a.data&&(a.data=q(a.data))},b,null,20);b.on(\"toDataFormat\",function(a){a.data.dataValue=q(a.data.dataValue)},null,null,0)});CKEDITOR.editor.prototype.selectionChange=function(a){(a?l:k).call(this)};CKEDITOR.editor.prototype.getSelection=function(a){return!this._.savedSelection&&!this._.fakeSelection||\na?(a=this.editable())&&\"wysiwyg\"==this.mode?new CKEDITOR.dom.selection(a):null:this._.savedSelection||this._.fakeSelection};CKEDITOR.editor.prototype.lockSelection=function(a){a=a||this.getSelection(1);return a.getType()!=CKEDITOR.SELECTION_NONE?(!a.isLocked&&a.lock(),this._.savedSelection=a,!0):!1};CKEDITOR.editor.prototype.unlockSelection=function(a){var b=this._.savedSelection;return b?(b.unlock(a),delete this._.savedSelection,!0):!1};CKEDITOR.editor.prototype.forceNextSelectionCheck=function(){delete this._.selectionPreviousPath};\nCKEDITOR.dom.document.prototype.getSelection=function(){return new CKEDITOR.dom.selection(this)};CKEDITOR.dom.range.prototype.select=function(){var a=this.root instanceof CKEDITOR.editable?this.root.editor.getSelection():new CKEDITOR.dom.selection(this.root);a.selectRanges([this]);return a};CKEDITOR.SELECTION_NONE=1;CKEDITOR.SELECTION_TEXT=2;CKEDITOR.SELECTION_ELEMENT=3;CKEDITOR.dom.selection=function(a){if(a instanceof CKEDITOR.dom.selection){var b=a;a=a.root}var c=a instanceof CKEDITOR.dom.element;\nthis.rev=b?b.rev:w++;this.document=a instanceof CKEDITOR.dom.document?a:a.getDocument();this.root=c?a:this.document.getBody();this.isLocked=0;this._={cache:{}};if(b)return CKEDITOR.tools.extend(this._.cache,b._.cache),this.isFake=b.isFake,this.isLocked=b.isLocked,this;a=this.getNative();var e,d;if(a)if(a.getRangeAt)e=(d=a.rangeCount&&a.getRangeAt(0))&&new CKEDITOR.dom.node(d.commonAncestorContainer);else{try{d=a.createRange()}catch(g){}e=d&&CKEDITOR.dom.element.get(d.item&&d.item(0)||d.parentElement())}if(!e||\ne.type!=CKEDITOR.NODE_ELEMENT&&e.type!=CKEDITOR.NODE_TEXT||!this.root.equals(e)&&!this.root.contains(e))this._.cache.type=CKEDITOR.SELECTION_NONE,this._.cache.startElement=null,this._.cache.selectedElement=null,this._.cache.selectedText=\"\",this._.cache.ranges=new CKEDITOR.dom.rangeList;return this};var H={img:1,hr:1,li:1,table:1,tr:1,td:1,th:1,embed:1,object:1,ol:1,ul:1,a:1,input:1,form:1,select:1,textarea:1,button:1,fieldset:1,thead:1,tfoot:1};CKEDITOR.tools.extend(CKEDITOR.dom.selection,{_removeFillingCharSequenceString:q,\n_createFillingCharSequenceNode:e,FILLING_CHAR_SEQUENCE:r});CKEDITOR.dom.selection.prototype={getNative:function(){return void 0!==this._.cache.nativeSel?this._.cache.nativeSel:this._.cache.nativeSel=v?this.document.$.selection:this.document.getWindow().$.getSelection()},getType:v?function(){var a=this._.cache;if(a.type)return a.type;var b=CKEDITOR.SELECTION_NONE;try{var c=this.getNative(),e=c.type;\"Text\"==e&&(b=CKEDITOR.SELECTION_TEXT);\"Control\"==e&&(b=CKEDITOR.SELECTION_ELEMENT);c.createRange().parentElement()&&\n(b=CKEDITOR.SELECTION_TEXT)}catch(d){}return a.type=b}:function(){var a=this._.cache;if(a.type)return a.type;var b=CKEDITOR.SELECTION_TEXT,c=this.getNative();if(!c||!c.rangeCount)b=CKEDITOR.SELECTION_NONE;else if(1==c.rangeCount){var c=c.getRangeAt(0),e=c.startContainer;e==c.endContainer&&1==e.nodeType&&1==c.endOffset-c.startOffset&&H[e.childNodes[c.startOffset].nodeName.toLowerCase()]&&(b=CKEDITOR.SELECTION_ELEMENT)}return a.type=b},getRanges:function(){var a=v?function(){function a(b){return(new CKEDITOR.dom.node(b)).getIndex()}\nvar b=function(b,c){b=b.duplicate();b.collapse(c);var e=b.parentElement();if(!e.hasChildNodes())return{container:e,offset:0};for(var d=e.children,g,f,h=b.duplicate(),m=0,k=d.length-1,l=-1,n,q;m<=k;)if(l=Math.floor((m+k)/2),g=d[l],h.moveToElementText(g),n=h.compareEndPoints(\"StartToStart\",b),0<n)k=l-1;else if(0>n)m=l+1;else return{container:e,offset:a(g)};if(-1==l||l==d.length-1&&0>n){h.moveToElementText(e);h.setEndPoint(\"StartToStart\",b);h=h.text.replace(/(\\r\\n|\\r)/g,\"\\n\").length;d=e.childNodes;if(!h)return g=\nd[d.length-1],g.nodeType!=CKEDITOR.NODE_TEXT?{container:e,offset:d.length}:{container:g,offset:g.nodeValue.length};for(e=d.length;0<h&&0<e;)f=d[--e],f.nodeType==CKEDITOR.NODE_TEXT&&(q=f,h-=f.nodeValue.length);return{container:q,offset:-h}}h.collapse(0<n?!0:!1);h.setEndPoint(0<n?\"StartToStart\":\"EndToStart\",b);h=h.text.replace(/(\\r\\n|\\r)/g,\"\\n\").length;if(!h)return{container:e,offset:a(g)+(0<n?0:1)};for(;0<h;)try{f=g[0<n?\"previousSibling\":\"nextSibling\"],f.nodeType==CKEDITOR.NODE_TEXT&&(h-=f.nodeValue.length,\nq=f),g=f}catch(r){return{container:e,offset:a(g)}}return{container:q,offset:0<n?-h:q.nodeValue.length+h}};return function(){var a=this.getNative(),c=a&&a.createRange(),e=this.getType();if(!a)return[];if(e==CKEDITOR.SELECTION_TEXT)return a=new CKEDITOR.dom.range(this.root),e=b(c,!0),a.setStart(new CKEDITOR.dom.node(e.container),e.offset),e=b(c),a.setEnd(new CKEDITOR.dom.node(e.container),e.offset),a.endContainer.getPosition(a.startContainer)&CKEDITOR.POSITION_PRECEDING&&a.endOffset<=a.startContainer.getIndex()&&\na.collapse(),[a];if(e==CKEDITOR.SELECTION_ELEMENT){for(var e=[],d=0;d<c.length;d++){for(var g=c.item(d),f=g.parentNode,h=0,a=new CKEDITOR.dom.range(this.root);h<f.childNodes.length&&f.childNodes[h]!=g;h++);a.setStart(new CKEDITOR.dom.node(f),h);a.setEnd(new CKEDITOR.dom.node(f),h+1);e.push(a)}return e}return[]}}():function(){var a=[],b,c=this.getNative();if(!c)return a;for(var e=0;e<c.rangeCount;e++){var d=c.getRangeAt(e);b=new CKEDITOR.dom.range(this.root);b.setStart(new CKEDITOR.dom.node(d.startContainer),\nd.startOffset);b.setEnd(new CKEDITOR.dom.node(d.endContainer),d.endOffset);a.push(b)}return a};return function(b){var c=this._.cache,e=c.ranges;e||(c.ranges=e=new CKEDITOR.dom.rangeList(a.call(this)));return b?p(new CKEDITOR.dom.rangeList(e.slice())):e}}(),getStartElement:function(){var a=this._.cache;if(void 0!==a.startElement)return a.startElement;var b;switch(this.getType()){case CKEDITOR.SELECTION_ELEMENT:return this.getSelectedElement();case CKEDITOR.SELECTION_TEXT:var c=this.getRanges()[0];\nif(c){if(c.collapsed)b=c.startContainer,b.type!=CKEDITOR.NODE_ELEMENT&&(b=b.getParent());else{for(c.optimize();b=c.startContainer,c.startOffset==(b.getChildCount?b.getChildCount():b.getLength())&&!b.isBlockBoundary();)c.setStartAfter(b);b=c.startContainer;if(b.type!=CKEDITOR.NODE_ELEMENT)return b.getParent();if((b=b.getChild(c.startOffset))&&b.type==CKEDITOR.NODE_ELEMENT)for(c=b.getFirst();c&&c.type==CKEDITOR.NODE_ELEMENT;)b=c,c=c.getFirst();else b=c.startContainer}b=b.$}}return a.startElement=b?\nnew CKEDITOR.dom.element(b):null},getSelectedElement:function(){var a=this._.cache;if(void 0!==a.selectedElement)return a.selectedElement;var b=this,c=CKEDITOR.tools.tryThese(function(){return b.getNative().createRange().item(0)},function(){for(var a=b.getRanges()[0].clone(),c,e,d=2;d&&!((c=a.getEnclosedNode())&&c.type==CKEDITOR.NODE_ELEMENT&&H[c.getName()]&&(e=c));d--)a.shrink(CKEDITOR.SHRINK_ELEMENT);return e&&e.$});return a.selectedElement=c?new CKEDITOR.dom.element(c):null},getSelectedText:function(){var a=\nthis._.cache;if(void 0!==a.selectedText)return a.selectedText;var b=this.getNative(),b=v?\"Control\"==b.type?\"\":b.createRange().text:b.toString();return a.selectedText=b},lock:function(){this.getRanges();this.getStartElement();this.getSelectedElement();this.getSelectedText();this._.cache.nativeSel=null;this.isLocked=1},unlock:function(a){if(this.isLocked){if(a)var b=this.getSelectedElement(),c=this.getRanges(),e=this.isFake;this.isLocked=0;this.reset();a&&(a=b||c[0]&&c[0].getCommonAncestor())&&a.getAscendant(\"body\",\n1)&&(f(c)?d.call(this,c):e?this.fake(b):b?this.selectElement(b):this.selectRanges(c))}},reset:function(){this._.cache={};this.isFake=0;var a=this.root.editor;if(a&&a._.fakeSelection)if(this.rev==a._.fakeSelection.rev){delete a._.fakeSelection;var b=a._.hiddenSelectionContainer;if(b){var c=a.checkDirty();a.fire(\"lockSnapshot\");b.remove();a.fire(\"unlockSnapshot\");!c&&a.resetDirty()}delete a._.hiddenSelectionContainer}else CKEDITOR.warn(\"selection-fake-reset\");this.rev=w++},selectElement:function(a){var b=\nnew CKEDITOR.dom.range(this.root);b.setStartBefore(a);b.setEndAfter(a);this.selectRanges([b])},selectRanges:function(a){var b=this.root.editor,c=b&&b._.hiddenSelectionContainer;this.reset();if(c)for(var c=this.root,g,h=0;h<a.length;++h)g=a[h],g.endContainer.equals(c)&&(g.endOffset=Math.min(g.endOffset,c.getChildCount()));if(a.length)if(this.isLocked){var k=CKEDITOR.document.getActive();this.unlock();this.selectRanges(a);this.lock();k&&!k.equals(this.root)&&k.focus()}else{var l;a:{var q,r;if(1==a.length&&\n!(r=a[0]).collapsed&&(l=r.getEnclosedNode())&&l.type==CKEDITOR.NODE_ELEMENT&&(r=r.clone(),r.shrink(CKEDITOR.SHRINK_ELEMENT,!0),(q=r.getEnclosedNode())&&q.type==CKEDITOR.NODE_ELEMENT&&(l=q),\"false\"==l.getAttribute(\"contenteditable\")))break a;l=void 0}if(l)this.fake(l);else if(b&&b.plugins.tableselection&&b.plugins.tableselection.isSupportedEnvironment()&&f(a)&&!t&&!a[0]._getTableElement({table:1}).hasAttribute(\"data-cke-tableselection-ignored\"))d.call(this,a);else{if(v){q=CKEDITOR.dom.walker.whitespaces(!0);\nl=/\\ufeff|\\u00a0/;r={table:1,tbody:1,tr:1};1<a.length&&(b=a[a.length-1],a[0].setEnd(b.endContainer,b.endOffset));b=a[0];a=b.collapsed;var w,z,u;if((c=b.getEnclosedNode())&&c.type==CKEDITOR.NODE_ELEMENT&&c.getName()in H&&(!c.is(\"a\")||!c.getText()))try{u=c.$.createControlRange();u.addElement(c.$);u.select();return}catch(y){}if(b.startContainer.type==CKEDITOR.NODE_ELEMENT&&b.startContainer.getName()in r||b.endContainer.type==CKEDITOR.NODE_ELEMENT&&b.endContainer.getName()in r)b.shrink(CKEDITOR.NODE_ELEMENT,\n!0),a=b.collapsed;u=b.createBookmark();r=u.startNode;a||(k=u.endNode);u=b.document.$.body.createTextRange();u.moveToElementText(r.$);u.moveStart(\"character\",1);k?(l=b.document.$.body.createTextRange(),l.moveToElementText(k.$),u.setEndPoint(\"EndToEnd\",l),u.moveEnd(\"character\",-1)):(w=r.getNext(q),z=r.hasAscendant(\"pre\"),w=!(w&&w.getText&&w.getText().match(l))&&(z||!r.hasPrevious()||r.getPrevious().is&&r.getPrevious().is(\"br\")),z=b.document.createElement(\"span\"),z.setHtml(\"\\x26#65279;\"),z.insertBefore(r),\nw&&b.document.createText(\"﻿\").insertBefore(r));b.setStartBefore(r);r.remove();a?(w?(u.moveStart(\"character\",-1),u.select(),b.document.$.selection.clear()):u.select(),b.moveToPosition(z,CKEDITOR.POSITION_BEFORE_START),z.remove()):(b.setEndBefore(k),k.remove(),u.select())}else{k=this.getNative();if(!k)return;this.removeAllRanges();for(u=0;u<a.length;u++){if(u<a.length-1&&(w=a[u],z=a[u+1],l=w.clone(),l.setStart(w.endContainer,w.endOffset),l.setEnd(z.startContainer,z.startOffset),!l.collapsed&&(l.shrink(CKEDITOR.NODE_ELEMENT,\n!0),b=l.getCommonAncestor(),l=l.getEnclosedNode(),b.isReadOnly()||l&&l.isReadOnly()))){z.setStart(w.startContainer,w.startOffset);a.splice(u--,1);continue}b=a[u];z=this.document.$.createRange();b.collapsed&&CKEDITOR.env.webkit&&m(b)&&(l=e(this.root),b.insertNode(l),(w=l.getNext())&&!l.getPrevious()&&w.type==CKEDITOR.NODE_ELEMENT&&\"br\"==w.getName()?(n(this.root),b.moveToPosition(w,CKEDITOR.POSITION_BEFORE_START)):b.moveToPosition(l,CKEDITOR.POSITION_AFTER_END));z.setStart(b.startContainer.$,b.startOffset);\ntry{z.setEnd(b.endContainer.$,b.endOffset)}catch(p){if(0<=p.toString().indexOf(\"NS_ERROR_ILLEGAL_VALUE\"))b.collapse(1),z.setEnd(b.endContainer.$,b.endOffset);else throw p;}k.addRange(z)}}this.reset();this.root.fire(\"selectionchange\")}}},fake:function(a,b){var c=this.root.editor;void 0===b&&a.hasAttribute(\"aria-label\")&&(b=a.getAttribute(\"aria-label\"));this.reset();y(c,b);var e=this._.cache,d=new CKEDITOR.dom.range(this.root);d.setStartBefore(a);d.setEndAfter(a);e.ranges=new CKEDITOR.dom.rangeList(d);\ne.selectedElement=e.startElement=a;e.type=CKEDITOR.SELECTION_ELEMENT;e.selectedText=e.nativeSel=null;this.isFake=1;this.rev=w++;c._.fakeSelection=this;this.root.fire(\"selectionchange\")},isHidden:function(){var a=this.getCommonAncestor();a&&a.type==CKEDITOR.NODE_TEXT&&(a=a.getParent());return!(!a||!a.data(\"cke-hidden-sel\"))},isInTable:function(a){return f(this.getRanges(),a)},isCollapsed:function(){var a=this.getRanges();return 1===a.length&&a[0].collapsed},createBookmarks:function(a){a=this.getRanges().createBookmarks(a);\nthis.isFake&&(a.isFake=1);return a},createBookmarks2:function(a){a=this.getRanges().createBookmarks2(a);this.isFake&&(a.isFake=1);return a},selectBookmarks:function(a){for(var b=[],c,e=0;e<a.length;e++){var d=new CKEDITOR.dom.range(this.root);d.moveToBookmark(a[e]);b.push(d)}a.isFake&&(c=f(b)?b[0]._getTableElement():b[0].getEnclosedNode(),c&&c.type==CKEDITOR.NODE_ELEMENT||(CKEDITOR.warn(\"selection-not-fake\"),a.isFake=0));a.isFake&&!f(b)?this.fake(c):this.selectRanges(b);return this},getCommonAncestor:function(){var a=\nthis.getRanges();return a.length?a[0].startContainer.getCommonAncestor(a[a.length-1].endContainer):null},scrollIntoView:function(){this.type!=CKEDITOR.SELECTION_NONE&&this.getRanges()[0].scrollIntoView()},removeAllRanges:function(){if(this.getType()!=CKEDITOR.SELECTION_NONE){var a=this.getNative();try{a&&a[v?\"empty\":\"removeAllRanges\"]()}catch(b){}this.reset()}}}}(),\"use strict\",CKEDITOR.STYLE_BLOCK=1,CKEDITOR.STYLE_INLINE=2,CKEDITOR.STYLE_OBJECT=3,function(){function a(a,b){for(var c,e;(a=a.getParent())&&\n!a.equals(b);)if(a.getAttribute(\"data-nostyle\"))c=a;else if(!e){var d=a.getAttribute(\"contentEditable\");\"false\"==d?c=a:\"true\"==d&&(e=1)}return c}function f(a,b,c,e){return(a.getPosition(b)|e)==e&&(!c.childRule||c.childRule(a))}function b(c){var e=c.document;if(c.collapsed)e=w(this,e),c.insertNode(e),c.moveToPosition(e,CKEDITOR.POSITION_BEFORE_END);else{var g=this.element,h=this._.definition,m,k=h.ignoreReadonly,l=k||h.includeReadonly;null==l&&(l=c.root.getCustomData(\"cke_includeReadonly\"));var n=\nCKEDITOR.dtd[g];n||(m=!0,n=CKEDITOR.dtd.span);c.enlarge(CKEDITOR.ENLARGE_INLINE,1);c.trim();var q=c.createBookmark(),r=q.startNode,v=q.endNode,t=r,z;if(!k){var y=c.getCommonAncestor(),k=a(r,y),y=a(v,y);k&&(t=k.getNextSourceNode(!0));y&&(v=y)}for(t.getPosition(v)==CKEDITOR.POSITION_FOLLOWING&&(t=0);t;){k=!1;if(t.equals(v))t=null,k=!0;else{var p=t.type==CKEDITOR.NODE_ELEMENT?t.getName():null,y=p&&\"false\"==t.getAttribute(\"contentEditable\"),A=p&&t.getAttribute(\"data-nostyle\");if(p&&t.data(\"cke-bookmark\")||\nt.type===CKEDITOR.NODE_COMMENT){t=t.getNextSourceNode(!0);continue}if(y&&l&&CKEDITOR.dtd.$block[p])for(var B=t,x=d(B),C=void 0,H=x.length,da=0,B=H&&new CKEDITOR.dom.range(B.getDocument());da<H;++da){var C=x[da],I=CKEDITOR.filter.instances[C.data(\"cke-filter\")];if(I?I.check(this):1)B.selectNodeContents(C),b.call(this,B)}x=p?!n[p]||A?0:y&&!l?0:f(t,v,h,L):1;if(x)if(C=t.getParent(),x=h,H=g,da=m,!C||!(C.getDtd()||CKEDITOR.dtd.span)[H]&&!da||x.parentRule&&!x.parentRule(C))k=!0;else{if(z||p&&CKEDITOR.dtd.$removeEmpty[p]&&\n(t.getPosition(v)|L)!=L||(z=c.clone(),z.setStartBefore(t)),p=t.type,p==CKEDITOR.NODE_TEXT||y||p==CKEDITOR.NODE_ELEMENT&&!t.getChildCount()){for(var p=t,F;(k=!p.getNext(J))&&(F=p.getParent(),n[F.getName()])&&f(F,r,h,G);)p=F;z.setEndAfter(p)}}else k=!0;t=t.getNextSourceNode(A||y)}if(k&&z&&!z.collapsed){for(var k=w(this,e),y=k.hasAttributes(),A=z.getCommonAncestor(),p={},x={},C={},H={},ea,E,fa;k&&A;){if(A.getName()==g){for(ea in h.attributes)!H[ea]&&(fa=A.getAttribute(E))&&(k.getAttribute(ea)==fa?x[ea]=\n1:H[ea]=1);for(E in h.styles)!C[E]&&(fa=A.getStyle(E))&&(k.getStyle(E)==fa?p[E]=1:C[E]=1)}A=A.getParent()}for(ea in x)k.removeAttribute(ea);for(E in p)k.removeStyle(E);y&&!k.hasAttributes()&&(k=null);k?(z.extractContents().appendTo(k),z.insertNode(k),u.call(this,k),k.mergeSiblings(),CKEDITOR.env.ie||k.$.normalize()):(k=new CKEDITOR.dom.element(\"span\"),z.extractContents().appendTo(k),z.insertNode(k),u.call(this,k),k.remove(!0));z=null}}c.moveToBookmark(q);c.shrink(CKEDITOR.SHRINK_TEXT);c.shrink(CKEDITOR.NODE_ELEMENT,\n!0)}}function c(a){function b(){for(var a=new CKEDITOR.dom.elementPath(e.getParent()),c=new CKEDITOR.dom.elementPath(l.getParent()),d=null,g=null,f=0;f<a.elements.length;f++){var h=a.elements[f];if(h==a.block||h==a.blockLimit)break;n.checkElementRemovable(h,!0)&&(d=h)}for(f=0;f<c.elements.length;f++){h=c.elements[f];if(h==c.block||h==c.blockLimit)break;n.checkElementRemovable(h,!0)&&(g=h)}g&&l.breakParent(g);d&&e.breakParent(d)}a.enlarge(CKEDITOR.ENLARGE_INLINE,1);var c=a.createBookmark(),e=c.startNode,\nd=this._.definition.alwaysRemoveElement;if(a.collapsed){for(var g=new CKEDITOR.dom.elementPath(e.getParent(),a.root),f,h=0,m;h<g.elements.length&&(m=g.elements[h])&&m!=g.block&&m!=g.blockLimit;h++)if(this.checkElementRemovable(m)){var k;!d&&a.collapsed&&(a.checkBoundaryOfElement(m,CKEDITOR.END)||(k=a.checkBoundaryOfElement(m,CKEDITOR.START)))?(f=m,f.match=k?\"start\":\"end\"):(m.mergeSiblings(),m.is(this.element)?y.call(this,m):p(m,t(this)[m.getName()]))}if(f){d=e;for(h=0;;h++){m=g.elements[h];if(m.equals(f))break;\nelse if(m.match)continue;else m=m.clone();m.append(d);d=m}d[\"start\"==f.match?\"insertBefore\":\"insertAfter\"](f)}}else{var l=c.endNode,n=this;b();for(g=e;!g.equals(l);)f=g.getNextSourceNode(),g.type==CKEDITOR.NODE_ELEMENT&&this.checkElementRemovable(g)&&(g.getName()==this.element?y.call(this,g):p(g,t(this)[g.getName()]),f.type==CKEDITOR.NODE_ELEMENT&&f.contains(e)&&(b(),f=e.getNext())),g=f}a.moveToBookmark(c);a.shrink(CKEDITOR.NODE_ELEMENT,!0)}function d(a){var b=[];a.forEach(function(a){if(\"true\"==\na.getAttribute(\"contenteditable\"))return b.push(a),!1},CKEDITOR.NODE_ELEMENT,!0);return b}function l(a){var b=a.getEnclosedNode()||a.getCommonAncestor(!1,!0);(a=(new CKEDITOR.dom.elementPath(b,a.root)).contains(this.element,1))&&!a.isReadOnly()&&r(a,this)}function k(a){var b=a.getCommonAncestor(!0,!0);if(a=(new CKEDITOR.dom.elementPath(b,a.root)).contains(this.element,1)){var b=this._.definition,c=b.attributes;if(c)for(var e in c)a.removeAttribute(e,c[e]);if(b.styles)for(var d in b.styles)b.styles.hasOwnProperty(d)&&\na.removeStyle(d)}}function g(a){var b=a.createBookmark(!0),c=a.createIterator();c.enforceRealBlocks=!0;this._.enterMode&&(c.enlargeBr=this._.enterMode!=CKEDITOR.ENTER_BR);for(var e,d=a.document,g;e=c.getNextParagraph();)!e.isReadOnly()&&(c.activeFilter?c.activeFilter.check(this):1)&&(g=w(this,d,e),m(e,g));a.moveToBookmark(b)}function h(a){var b=a.createBookmark(1),c=a.createIterator();c.enforceRealBlocks=!0;c.enlargeBr=this._.enterMode!=CKEDITOR.ENTER_BR;for(var e,d;e=c.getNextParagraph();)this.checkElementRemovable(e)&&\n(e.is(\"pre\")?((d=this._.enterMode==CKEDITOR.ENTER_BR?null:a.document.createElement(this._.enterMode==CKEDITOR.ENTER_P?\"p\":\"div\"))&&e.copyAttributes(d),m(e,d)):y.call(this,e));a.moveToBookmark(b)}function m(a,b){var c=!b;c&&(b=a.getDocument().createElement(\"div\"),a.copyAttributes(b));var d=b&&b.is(\"pre\"),g=a.is(\"pre\"),f=!d&&g;if(d&&!g){g=b;(f=a.getBogus())&&f.remove();f=a.getHtml();f=n(f,/(?:^[ \\t\\n\\r]+)|(?:[ \\t\\n\\r]+$)/g,\"\");f=f.replace(/[ \\t\\r\\n]*(<br[^>]*>)[ \\t\\r\\n]*/gi,\"$1\");f=f.replace(/([ \\t\\n\\r]+|&nbsp;)/g,\n\" \");f=f.replace(/<br\\b[^>]*>/gi,\"\\n\");if(CKEDITOR.env.ie){var h=a.getDocument().createElement(\"div\");h.append(g);g.$.outerHTML=\"\\x3cpre\\x3e\"+f+\"\\x3c/pre\\x3e\";g.copyAttributes(h.getFirst());g=h.getFirst().remove()}else g.setHtml(f);b=g}else f?b=q(c?[a.getHtml()]:e(a),b):a.moveChildren(b);b.replace(a);if(d){var c=b,m;(m=c.getPrevious(E))&&m.type==CKEDITOR.NODE_ELEMENT&&m.is(\"pre\")&&(d=n(m.getHtml(),/\\n$/,\"\")+\"\\n\\n\"+n(c.getHtml(),/^\\n/,\"\"),CKEDITOR.env.ie?c.$.outerHTML=\"\\x3cpre\\x3e\"+d+\"\\x3c/pre\\x3e\":\nc.setHtml(d),m.remove())}else c&&v(b)}function e(a){var b=[];n(a.getOuterHtml(),/(\\S\\s*)\\n(?:\\s|(<span[^>]+data-cke-bookmark.*?\\/span>))*\\n(?!$)/gi,function(a,b,c){return b+\"\\x3c/pre\\x3e\"+c+\"\\x3cpre\\x3e\"}).replace(/<pre\\b.*?>([\\s\\S]*?)<\\/pre>/gi,function(a,c){b.push(c)});return b}function n(a,b,c){var e=\"\",d=\"\";a=a.replace(/(^<span[^>]+data-cke-bookmark.*?\\/span>)|(<span[^>]+data-cke-bookmark.*?\\/span>$)/gi,function(a,b,c){b&&(e=b);c&&(d=c);return\"\"});return e+a.replace(b,c)+d}function q(a,b){var c;\n1<a.length&&(c=new CKEDITOR.dom.documentFragment(b.getDocument()));for(var e=0;e<a.length;e++){var d=a[e],d=d.replace(/(\\r\\n|\\r)/g,\"\\n\"),d=n(d,/^[ \\t]*\\n/,\"\"),d=n(d,/\\n$/,\"\"),d=n(d,/^[ \\t]+|[ \\t]+$/g,function(a,b){return 1==a.length?\"\\x26nbsp;\":b?\" \"+CKEDITOR.tools.repeat(\"\\x26nbsp;\",a.length-1):CKEDITOR.tools.repeat(\"\\x26nbsp;\",a.length-1)+\" \"}),d=d.replace(/\\n/g,\"\\x3cbr\\x3e\"),d=d.replace(/[ \\t]{2,}/g,function(a){return CKEDITOR.tools.repeat(\"\\x26nbsp;\",a.length-1)+\" \"});if(c){var g=b.clone();g.setHtml(d);\nc.append(g)}else b.setHtml(d)}return c||b}function y(a,b){var c=this._.definition,e=c.attributes,c=c.styles,d=t(this)[a.getName()],g=CKEDITOR.tools.isEmpty(e)&&CKEDITOR.tools.isEmpty(c),f;for(f in e)if(\"class\"!=f&&!this._.definition.fullMatch||a.getAttribute(f)==x(f,e[f]))b&&\"data-\"==f.slice(0,5)||(g=a.hasAttribute(f),a.removeAttribute(f));for(var h in c)this._.definition.fullMatch&&a.getStyle(h)!=x(h,c[h],!0)||(g=g||!!a.getStyle(h),a.removeStyle(h));p(a,d,C[a.getName()]);g&&(this._.definition.alwaysRemoveElement?\nv(a,1):!CKEDITOR.dtd.$block[a.getName()]||this._.enterMode==CKEDITOR.ENTER_BR&&!a.hasAttributes()?v(a):a.renameNode(this._.enterMode==CKEDITOR.ENTER_P?\"p\":\"div\"))}function u(a){for(var b=t(this),c=a.getElementsByTag(this.element),e,d=c.count();0<=--d;)e=c.getItem(d),e.isReadOnly()||y.call(this,e,!0);for(var g in b)if(g!=this.element)for(c=a.getElementsByTag(g),d=c.count()-1;0<=d;d--)e=c.getItem(d),e.isReadOnly()||p(e,b[g])}function p(a,b,c){if(b=b&&b.attributes)for(var e=0;e<b.length;e++){var d=b[e][0],\ng;if(g=a.getAttribute(d)){var f=b[e][1];(null===f||f.test&&f.test(g)||\"string\"==typeof f&&g==f)&&a.removeAttribute(d)}}c||v(a)}function v(a,b){if(!a.hasAttributes()||b)if(CKEDITOR.dtd.$block[a.getName()]){var c=a.getPrevious(E),e=a.getNext(E);!c||c.type!=CKEDITOR.NODE_TEXT&&c.isBlockBoundary({br:1})||a.append(\"br\",1);!e||e.type!=CKEDITOR.NODE_TEXT&&e.isBlockBoundary({br:1})||a.append(\"br\");a.remove(!0)}else c=a.getFirst(),e=a.getLast(),a.remove(!0),c&&(c.type==CKEDITOR.NODE_ELEMENT&&c.mergeSiblings(),\ne&&!c.equals(e)&&e.type==CKEDITOR.NODE_ELEMENT&&e.mergeSiblings())}function w(a,b,c){var e;e=a.element;\"*\"==e&&(e=\"span\");e=new CKEDITOR.dom.element(e,b);c&&c.copyAttributes(e);e=r(e,a);b.getCustomData(\"doc_processing_style\")&&e.hasAttribute(\"id\")?e.removeAttribute(\"id\"):b.setCustomData(\"doc_processing_style\",1);return e}function r(a,b){var c=b._.definition,e=c.attributes,c=CKEDITOR.style.getStyleText(c);if(e)for(var d in e)a.setAttribute(d,e[d]);c&&a.setAttribute(\"style\",c);a.getDocument().removeCustomData(\"doc_processing_style\");\nreturn a}function z(a,b){for(var c in a)a[c]=a[c].replace(I,function(a,c){return b[c]})}function t(a){if(a._.overrides)return a._.overrides;var b=a._.overrides={},c=a._.definition.overrides;if(c){CKEDITOR.tools.isArray(c)||(c=[c]);for(var e=0;e<c.length;e++){var d=c[e],g,f;\"string\"==typeof d?g=d.toLowerCase():(g=d.element?d.element.toLowerCase():a.element,f=d.attributes);d=b[g]||(b[g]={});if(f){var d=d.attributes=d.attributes||[],h;for(h in f)d.push([h.toLowerCase(),f[h]])}}}return b}function x(a,\nb,c){var e=new CKEDITOR.dom.element(\"span\");e[c?\"setStyle\":\"setAttribute\"](a,b);return e[c?\"getStyle\":\"getAttribute\"](a)}function A(a,b){function c(a,b){return\"font-family\"==b.toLowerCase()?a.replace(/[\"']/g,\"\"):a}\"string\"==typeof a&&(a=CKEDITOR.tools.parseCssText(a));\"string\"==typeof b&&(b=CKEDITOR.tools.parseCssText(b,!0));for(var e in a)if(!(e in b)||c(b[e],e)!=c(a[e],e)&&\"inherit\"!=a[e]&&\"inherit\"!=b[e])return!1;return!0}function B(a,b,c){var e=a.getRanges();b=b?this.removeFromRange:this.applyToRange;\nvar d,g;if(a.isFake&&a.isInTable())for(d=[],g=0;g<e.length;g++)d.push(e[g].clone());for(var f=e.createIterator();g=f.getNextRange();)b.call(this,g,c);a.selectRanges(d||e)}var C={address:1,div:1,h1:1,h2:1,h3:1,h4:1,h5:1,h6:1,p:1,pre:1,section:1,header:1,footer:1,nav:1,article:1,aside:1,figure:1,dialog:1,hgroup:1,time:1,meter:1,menu:1,command:1,keygen:1,output:1,progress:1,details:1,datagrid:1,datalist:1},H={a:1,blockquote:1,embed:1,hr:1,img:1,li:1,object:1,ol:1,table:1,td:1,tr:1,th:1,ul:1,dl:1,dt:1,\ndd:1,form:1,audio:1,video:1},F=/\\s*(?:;\\s*|$)/,I=/#\\((.+?)\\)/g,J=CKEDITOR.dom.walker.bookmark(0,1),E=CKEDITOR.dom.walker.whitespaces(1);CKEDITOR.style=function(a,b){if(\"string\"==typeof a.type)return new CKEDITOR.style.customHandlers[a.type](a);var c=a.attributes;c&&c.style&&(a.styles=CKEDITOR.tools.extend({},a.styles,CKEDITOR.tools.parseCssText(c.style)),delete c.style);b&&(a=CKEDITOR.tools.clone(a),z(a.attributes,b),z(a.styles,b));c=this.element=a.element?\"string\"==typeof a.element?a.element.toLowerCase():\na.element:\"*\";this.type=a.type||(C[c]?CKEDITOR.STYLE_BLOCK:H[c]?CKEDITOR.STYLE_OBJECT:CKEDITOR.STYLE_INLINE);\"object\"==typeof this.element&&(this.type=CKEDITOR.STYLE_OBJECT);this._={definition:a}};CKEDITOR.style.prototype={apply:function(a){if(a instanceof CKEDITOR.dom.document)return B.call(this,a.getSelection());if(this.checkApplicable(a.elementPath(),a)){var b=this._.enterMode;b||(this._.enterMode=a.activeEnterMode);B.call(this,a.getSelection(),0,a);this._.enterMode=b}},remove:function(a){if(a instanceof\nCKEDITOR.dom.document)return B.call(this,a.getSelection(),1);if(this.checkApplicable(a.elementPath(),a)){var b=this._.enterMode;b||(this._.enterMode=a.activeEnterMode);B.call(this,a.getSelection(),1,a);this._.enterMode=b}},applyToRange:function(a){this.applyToRange=this.type==CKEDITOR.STYLE_INLINE?b:this.type==CKEDITOR.STYLE_BLOCK?g:this.type==CKEDITOR.STYLE_OBJECT?l:null;return this.applyToRange(a)},removeFromRange:function(a){this.removeFromRange=this.type==CKEDITOR.STYLE_INLINE?c:this.type==CKEDITOR.STYLE_BLOCK?\nh:this.type==CKEDITOR.STYLE_OBJECT?k:null;return this.removeFromRange(a)},applyToObject:function(a){r(a,this)},checkActive:function(a,b){switch(this.type){case CKEDITOR.STYLE_BLOCK:return this.checkElementRemovable(a.block||a.blockLimit,!0,b);case CKEDITOR.STYLE_OBJECT:case CKEDITOR.STYLE_INLINE:for(var c=a.elements,e=0,d;e<c.length;e++)if(d=c[e],this.type!=CKEDITOR.STYLE_INLINE||d!=a.block&&d!=a.blockLimit){if(this.type==CKEDITOR.STYLE_OBJECT){var g=d.getName();if(!(\"string\"==typeof this.element?\ng==this.element:g in this.element))continue}if(this.checkElementRemovable(d,!0,b))return!0}}return!1},checkApplicable:function(a,b,c){b&&b instanceof CKEDITOR.filter&&(c=b);if(c&&!c.check(this))return!1;switch(this.type){case CKEDITOR.STYLE_OBJECT:return!!a.contains(this.element);case CKEDITOR.STYLE_BLOCK:return!!a.blockLimit.getDtd()[this.element]}return!0},checkElementMatch:function(a,b){var c=this._.definition;if(!a||!c.ignoreReadonly&&a.isReadOnly())return!1;var e=a.getName();if(\"string\"==typeof this.element?\ne==this.element:e in this.element){if(!b&&!a.hasAttributes())return!0;if(e=c._AC)c=e;else{var e={},d=0,g=c.attributes;if(g)for(var f in g)d++,e[f]=g[f];if(f=CKEDITOR.style.getStyleText(c))e.style||d++,e.style=f;e._length=d;c=c._AC=e}if(c._length){for(var h in c)if(\"_length\"!=h)if(e=a.getAttribute(h)||\"\",\"style\"==h?A(c[h],e):c[h]==e){if(!b)return!0}else if(b)return!1;if(b)return!0}else return!0}return!1},checkElementRemovable:function(a,b,c){if(this.checkElementMatch(a,b,c))return!0;if(b=t(this)[a.getName()]){var e;\nif(!(b=b.attributes))return!0;for(c=0;c<b.length;c++)if(e=b[c][0],e=a.getAttribute(e)){var d=b[c][1];if(null===d)return!0;if(\"string\"==typeof d){if(e==d)return!0}else if(d.test(e))return!0}}return!1},buildPreview:function(a){var b=this._.definition,c=[],e=b.element;\"bdo\"==e&&(e=\"span\");var c=[\"\\x3c\",e],d=b.attributes;if(d)for(var g in d)c.push(\" \",g,'\\x3d\"',d[g],'\"');(d=CKEDITOR.style.getStyleText(b))&&c.push(' style\\x3d\"',d,'\"');c.push(\"\\x3e\",a||b.name,\"\\x3c/\",e,\"\\x3e\");return c.join(\"\")},getDefinition:function(){return this._.definition}};\nCKEDITOR.style.getStyleText=function(a){var b=a._ST;if(b)return b;var b=a.styles,c=a.attributes&&a.attributes.style||\"\",e=\"\";c.length&&(c=c.replace(F,\";\"));for(var d in b){var g=b[d],f=(d+\":\"+g).replace(F,\";\");\"inherit\"==g?e+=f:c+=f}c.length&&(c=CKEDITOR.tools.normalizeCssText(c,!0));return a._ST=c+e};CKEDITOR.style.customHandlers={};CKEDITOR.style.addCustomHandler=function(a){var b=function(a){this._={definition:a};this.setup&&this.setup(a)};b.prototype=CKEDITOR.tools.extend(CKEDITOR.tools.prototypedCopy(CKEDITOR.style.prototype),\n{assignedTo:CKEDITOR.STYLE_OBJECT},a,!0);return this.customHandlers[a.type]=b};var L=CKEDITOR.POSITION_PRECEDING|CKEDITOR.POSITION_IDENTICAL|CKEDITOR.POSITION_IS_CONTAINED,G=CKEDITOR.POSITION_FOLLOWING|CKEDITOR.POSITION_IDENTICAL|CKEDITOR.POSITION_IS_CONTAINED}(),CKEDITOR.styleCommand=function(a,f){this.requiredContent=this.allowedContent=this.style=a;CKEDITOR.tools.extend(this,f,!0)},CKEDITOR.styleCommand.prototype.exec=function(a){a.focus();this.state==CKEDITOR.TRISTATE_OFF?a.applyStyle(this.style):\nthis.state==CKEDITOR.TRISTATE_ON&&a.removeStyle(this.style)},CKEDITOR.stylesSet=new CKEDITOR.resourceManager(\"\",\"stylesSet\"),CKEDITOR.addStylesSet=CKEDITOR.tools.bind(CKEDITOR.stylesSet.add,CKEDITOR.stylesSet),CKEDITOR.loadStylesSet=function(a,f,b){CKEDITOR.stylesSet.addExternal(a,f,\"\");CKEDITOR.stylesSet.load(a,b)},CKEDITOR.tools.extend(CKEDITOR.editor.prototype,{attachStyleStateChange:function(a,f){var b=this._.styleStateChangeCallbacks;b||(b=this._.styleStateChangeCallbacks=[],this.on(\"selectionChange\",\nfunction(a){for(var d=0;d<b.length;d++){var f=b[d],k=f.style.checkActive(a.data.path,this)?CKEDITOR.TRISTATE_ON:CKEDITOR.TRISTATE_OFF;f.fn.call(this,k)}}));b.push({style:a,fn:f})},applyStyle:function(a){a.apply(this)},removeStyle:function(a){a.remove(this)},getStylesSet:function(a){if(this._.stylesDefinitions)a(this._.stylesDefinitions);else{var f=this,b=f.config.stylesCombo_stylesSet||f.config.stylesSet;if(!1===b)a(null);else if(b instanceof Array)f._.stylesDefinitions=b,a(b);else{b||(b=\"default\");\nvar b=b.split(\":\"),c=b[0];CKEDITOR.stylesSet.addExternal(c,b[1]?b.slice(1).join(\":\"):CKEDITOR.getUrl(\"styles.js\"),\"\");CKEDITOR.stylesSet.load(c,function(b){f._.stylesDefinitions=b[c];a(f._.stylesDefinitions)})}}}}),function(){if(window.Promise)CKEDITOR.tools.promise=Promise;else{var a=CKEDITOR.getUrl(\"vendor/promise.js\");CKEDITOR.scriptLoader.load(a,function(f){f?CKEDITOR.tools.promise=ES6Promise:CKEDITOR.error(\"no-vendor-lib\",{path:a})})}}(),CKEDITOR.dom.comment=function(a,f){\"string\"==typeof a&&\n(a=(f?f.$:document).createComment(a));CKEDITOR.dom.domObject.call(this,a)},CKEDITOR.dom.comment.prototype=new CKEDITOR.dom.node,CKEDITOR.tools.extend(CKEDITOR.dom.comment.prototype,{type:CKEDITOR.NODE_COMMENT,getOuterHtml:function(){return\"\\x3c!--\"+this.$.nodeValue+\"--\\x3e\"}}),\"use strict\",function(){var a={},f={},b;for(b in CKEDITOR.dtd.$blockLimit)b in CKEDITOR.dtd.$list||(a[b]=1);for(b in CKEDITOR.dtd.$block)b in CKEDITOR.dtd.$blockLimit||b in CKEDITOR.dtd.$empty||(f[b]=1);CKEDITOR.dom.elementPath=\nfunction(b,d){var l=null,k=null,g=[],h=b,m;d=d||b.getDocument().getBody();h||(h=d);do if(h.type==CKEDITOR.NODE_ELEMENT){g.push(h);if(!this.lastElement&&(this.lastElement=h,h.is(CKEDITOR.dtd.$object)||\"false\"==h.getAttribute(\"contenteditable\")))continue;if(h.equals(d))break;if(!k&&(m=h.getName(),\"true\"==h.getAttribute(\"contenteditable\")?k=h:!l&&f[m]&&(l=h),a[m])){if(m=!l&&\"div\"==m){a:{m=h.getChildren();for(var e=0,n=m.count();e<n;e++){var q=m.getItem(e);if(q.type==CKEDITOR.NODE_ELEMENT&&CKEDITOR.dtd.$block[q.getName()]){m=\n!0;break a}}m=!1}m=!m}m?l=h:k=h}}while(h=h.getParent());k||(k=d);this.block=l;this.blockLimit=k;this.root=d;this.elements=g}}(),CKEDITOR.dom.elementPath.prototype={compare:function(a){var f=this.elements;a=a&&a.elements;if(!a||f.length!=a.length)return!1;for(var b=0;b<f.length;b++)if(!f[b].equals(a[b]))return!1;return!0},contains:function(a,f,b){var c=0,d;\"string\"==typeof a&&(d=function(b){return b.getName()==a});a instanceof CKEDITOR.dom.element?d=function(b){return b.equals(a)}:CKEDITOR.tools.isArray(a)?\nd=function(b){return-1<CKEDITOR.tools.indexOf(a,b.getName())}:\"function\"==typeof a?d=a:\"object\"==typeof a&&(d=function(b){return b.getName()in a});var l=this.elements,k=l.length;f&&(b?c+=1:--k);b&&(l=Array.prototype.slice.call(l,0),l.reverse());for(;c<k;c++)if(d(l[c]))return l[c];return null},isContextFor:function(a){var f;return a in CKEDITOR.dtd.$block?(f=this.contains(CKEDITOR.dtd.$intermediate)||this.root.equals(this.block)&&this.block||this.blockLimit,!!f.getDtd()[a]):!0},direction:function(){return(this.block||\nthis.blockLimit||this.root).getDirection(1)}},CKEDITOR.dom.text=function(a,f){\"string\"==typeof a&&(a=(f?f.$:document).createTextNode(a));this.$=a},CKEDITOR.dom.text.prototype=new CKEDITOR.dom.node,CKEDITOR.tools.extend(CKEDITOR.dom.text.prototype,{type:CKEDITOR.NODE_TEXT,getLength:function(){return this.$.nodeValue.length},getText:function(){return this.$.nodeValue},setText:function(a){this.$.nodeValue=a},split:function(a){var f=this.$.parentNode,b=f.childNodes.length,c=this.getLength(),d=this.getDocument(),\nl=new CKEDITOR.dom.text(this.$.splitText(a),d);f.childNodes.length==b&&(a>=c?(l=d.createText(\"\"),l.insertAfter(this)):(a=d.createText(\"\"),a.insertAfter(l),a.remove()));return l},substring:function(a,f){return\"number\"!=typeof f?this.$.nodeValue.substr(a):this.$.nodeValue.substring(a,f)}}),function(){function a(a,c,d){var f=a.serializable,k=c[d?\"endContainer\":\"startContainer\"],g=d?\"endOffset\":\"startOffset\",h=f?c.document.getById(a.startNode):a.startNode;a=f?c.document.getById(a.endNode):a.endNode;k.equals(h.getPrevious())?\n(c.startOffset=c.startOffset-k.getLength()-a.getPrevious().getLength(),k=a.getNext()):k.equals(a.getPrevious())&&(c.startOffset-=k.getLength(),k=a.getNext());k.equals(h.getParent())&&c[g]++;k.equals(a.getParent())&&c[g]++;c[d?\"endContainer\":\"startContainer\"]=k;return c}CKEDITOR.dom.rangeList=function(a){if(a instanceof CKEDITOR.dom.rangeList)return a;a?a instanceof CKEDITOR.dom.range&&(a=[a]):a=[];return CKEDITOR.tools.extend(a,f)};var f={createIterator:function(){var a=this,c=CKEDITOR.dom.walker.bookmark(),\nd=[],f;return{getNextRange:function(k){f=void 0===f?0:f+1;var g=a[f];if(g&&1<a.length){if(!f)for(var h=a.length-1;0<=h;h--)d.unshift(a[h].createBookmark(!0));if(k)for(var m=0;a[f+m+1];){var e=g.document;k=0;h=e.getById(d[m].endNode);for(e=e.getById(d[m+1].startNode);;){h=h.getNextSourceNode(!1);if(e.equals(h))k=1;else if(c(h)||h.type==CKEDITOR.NODE_ELEMENT&&h.isBlockBoundary())continue;break}if(!k)break;m++}for(g.moveToBookmark(d.shift());m--;)h=a[++f],h.moveToBookmark(d.shift()),g.setEnd(h.endContainer,\nh.endOffset)}return g}}},createBookmarks:function(b){for(var c=[],d,f=0;f<this.length;f++){c.push(d=this[f].createBookmark(b,!0));for(var k=f+1;k<this.length;k++)this[k]=a(d,this[k]),this[k]=a(d,this[k],!0)}return c},createBookmarks2:function(a){for(var c=[],d=0;d<this.length;d++)c.push(this[d].createBookmark2(a));return c},moveToBookmarks:function(a){for(var c=0;c<this.length;c++)this[c].moveToBookmark(a[c])}}}(),function(){function a(){return CKEDITOR.getUrl(CKEDITOR.skinName.split(\",\")[1]||\"skins/\"+\nCKEDITOR.skinName.split(\",\")[0]+\"/\")}function f(b){var c=CKEDITOR.skin[\"ua_\"+b],d=CKEDITOR.env;if(c)for(var c=c.split(\",\").sort(function(a,b){return a>b?-1:1}),g=0,f;g<c.length;g++)if(f=c[g],d.ie&&(f.replace(/^ie/,\"\")==d.version||d.quirks&&\"iequirks\"==f)&&(f=\"ie\"),d[f]){b+=\"_\"+c[g];break}return CKEDITOR.getUrl(a()+b+\".css\")}function b(a,b){l[a]||(CKEDITOR.document.appendStyleSheet(f(a)),l[a]=1);b&&b()}function c(a){var b=a.getById(k);b||(b=a.getHead().append(\"style\"),b.setAttribute(\"id\",k),b.setAttribute(\"type\",\n\"text/css\"));return b}function d(a,b,c){var d,g,f;if(CKEDITOR.env.webkit)for(b=b.split(\"}\").slice(0,-1),g=0;g<b.length;g++)b[g]=b[g].split(\"{\");for(var h=0;h<a.length;h++)if(CKEDITOR.env.webkit)for(g=0;g<b.length;g++){f=b[g][1];for(d=0;d<c.length;d++)f=f.replace(c[d][0],c[d][1]);a[h].$.sheet.addRule(b[g][0],f)}else{f=b;for(d=0;d<c.length;d++)f=f.replace(c[d][0],c[d][1]);CKEDITOR.env.ie&&11>CKEDITOR.env.version?a[h].$.styleSheet.cssText+=f:a[h].$.innerHTML+=f}}var l={};CKEDITOR.skin={path:a,loadPart:function(c,\ne){CKEDITOR.skin.name!=CKEDITOR.skinName.split(\",\")[0]?CKEDITOR.scriptLoader.load(CKEDITOR.getUrl(a()+\"skin.js\"),function(){b(c,e)}):b(c,e)},getPath:function(a){return CKEDITOR.getUrl(f(a))},icons:{},addIcon:function(a,b,c,d){a=a.toLowerCase();this.icons[a]||(this.icons[a]={path:b,offset:c||0,bgsize:d||\"16px\"})},getIconStyle:function(a,b,c,d,g){var f;a&&(a=a.toLowerCase(),b&&(f=this.icons[a+\"-rtl\"]),f||(f=this.icons[a]));a=c||f&&f.path||\"\";d=d||f&&f.offset;g=g||f&&f.bgsize||\"16px\";a&&(a=a.replace(/'/g,\n\"\\\\'\"));return a&&\"background-image:url('\"+CKEDITOR.getUrl(a)+\"');background-position:0 \"+d+\"px;background-size:\"+g+\";\"}};CKEDITOR.tools.extend(CKEDITOR.editor.prototype,{getUiColor:function(){return this.uiColor},setUiColor:function(a){var b=c(CKEDITOR.document);return(this.setUiColor=function(a){this.uiColor=a;var c=CKEDITOR.skin.chameleon,f=\"\",m=\"\";\"function\"==typeof c&&(f=c(this,\"editor\"),m=c(this,\"panel\"));a=[[h,a]];d([b],f,a);d(g,m,a)}).call(this,a)}});var k=\"cke_ui_color\",g=[],h=/\\$color/g;\nCKEDITOR.on(\"instanceLoaded\",function(a){if(!CKEDITOR.env.ie||!CKEDITOR.env.quirks){var b=a.editor;a=function(a){a=(a.data[0]||a.data).element.getElementsByTag(\"iframe\").getItem(0).getFrameDocument();if(!a.getById(\"cke_ui_color\")){var f=c(a);g.push(f);b.on(\"destroy\",function(){g=CKEDITOR.tools.array.filter(g,function(a){return f!==a})});(a=b.getUiColor())&&d([f],CKEDITOR.skin.chameleon(b,\"panel\"),[[h,a]])}};b.on(\"panelShow\",a);b.on(\"menuShow\",a);b.config.uiColor&&b.setUiColor(b.config.uiColor)}})}(),\nfunction(){if(CKEDITOR.env.webkit)CKEDITOR.env.hc=!1;else{var a=CKEDITOR.dom.element.createFromHtml('\\x3cdiv style\\x3d\"width:0;height:0;position:absolute;left:-10000px;border:1px solid;border-color:red blue\"\\x3e\\x3c/div\\x3e',CKEDITOR.document);a.appendTo(CKEDITOR.document.getHead());try{var f=a.getComputedStyle(\"border-top-color\"),b=a.getComputedStyle(\"border-right-color\");CKEDITOR.env.hc=!(!f||f!=b)}catch(c){CKEDITOR.env.hc=!1}a.remove()}CKEDITOR.env.hc&&(CKEDITOR.env.cssClass+=\" cke_hc\");CKEDITOR.document.appendStyleText(\".cke{visibility:hidden;}\");\nCKEDITOR.status=\"loaded\";CKEDITOR.fireOnce(\"loaded\");if(a=CKEDITOR._.pending)for(delete CKEDITOR._.pending,f=0;f<a.length;f++)CKEDITOR.editor.prototype.constructor.apply(a[f][0],a[f][1]),CKEDITOR.add(a[f][0])}(),CKEDITOR.skin.name=\"moono-lisa\",CKEDITOR.skin.ua_editor=\"ie,iequirks,ie8,gecko\",CKEDITOR.skin.ua_dialog=\"ie,iequirks,ie8\",CKEDITOR.skin.chameleon=function(){var a=function(){return function(a,c){for(var d=a.match(/[^#]./g),f=0;3>f;f++){var k=f,g;g=parseInt(d[f],16);g=(\"0\"+(0>c?0|g*(1+c):0|\ng+(255-g)*c).toString(16)).slice(-2);d[k]=g}return\"#\"+d.join(\"\")}}(),f={editor:new CKEDITOR.template(\"{id}.cke_chrome [border-color:{defaultBorder};] {id} .cke_top [ background-color:{defaultBackground};border-bottom-color:{defaultBorder};] {id} .cke_bottom [background-color:{defaultBackground};border-top-color:{defaultBorder};] {id} .cke_resizer [border-right-color:{ckeResizer}] {id} .cke_dialog_title [background-color:{defaultBackground};border-bottom-color:{defaultBorder};] {id} .cke_dialog_footer [background-color:{defaultBackground};outline-color:{defaultBorder};] {id} .cke_dialog_tab [background-color:{dialogTab};border-color:{defaultBorder};] {id} .cke_dialog_tab:hover [background-color:{lightBackground};] {id} .cke_dialog_contents [border-top-color:{defaultBorder};] {id} .cke_dialog_tab_selected, {id} .cke_dialog_tab_selected:hover [background:{dialogTabSelected};border-bottom-color:{dialogTabSelectedBorder};] {id} .cke_dialog_body [background:{dialogBody};border-color:{defaultBorder};] {id} a.cke_button_off:hover,{id} a.cke_button_off:focus,{id} a.cke_button_off:active [background-color:{darkBackground};border-color:{toolbarElementsBorder};] {id} .cke_button_on [background-color:{ckeButtonOn};border-color:{toolbarElementsBorder};] {id} .cke_toolbar_separator,{id} .cke_toolgroup a.cke_button:last-child:after,{id} .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after [background-color: {toolbarElementsBorder};border-color: {toolbarElementsBorder};] {id} a.cke_combo_button:hover,{id} a.cke_combo_button:focus,{id} .cke_combo_on a.cke_combo_button [border-color:{toolbarElementsBorder};background-color:{darkBackground};] {id} .cke_combo:after [border-color:{toolbarElementsBorder};] {id} .cke_path_item [color:{elementsPathColor};] {id} a.cke_path_item:hover,{id} a.cke_path_item:focus,{id} a.cke_path_item:active [background-color:{darkBackground};] {id}.cke_panel [border-color:{defaultBorder};] \"),\npanel:new CKEDITOR.template(\".cke_panel_grouptitle [background-color:{lightBackground};border-color:{defaultBorder};] .cke_menubutton_icon [background-color:{menubuttonIcon};] .cke_menubutton:hover,.cke_menubutton:focus,.cke_menubutton:active [background-color:{menubuttonHover};] .cke_menubutton:hover .cke_menubutton_icon, .cke_menubutton:focus .cke_menubutton_icon, .cke_menubutton:active .cke_menubutton_icon [background-color:{menubuttonIconHover};] .cke_menubutton_disabled:hover .cke_menubutton_icon,.cke_menubutton_disabled:focus .cke_menubutton_icon,.cke_menubutton_disabled:active .cke_menubutton_icon [background-color:{menubuttonIcon};] .cke_menuseparator [background-color:{menubuttonIcon};] a:hover.cke_colorbox, a:active.cke_colorbox [border-color:{defaultBorder};] a:hover.cke_colorauto, a:hover.cke_colormore, a:active.cke_colorauto, a:active.cke_colormore [background-color:{ckeColorauto};border-color:{defaultBorder};] \")};\nreturn function(b,c){var d=a(b.uiColor,.4),d={id:\".\"+b.id,defaultBorder:a(d,-.2),toolbarElementsBorder:a(d,-.25),defaultBackground:d,lightBackground:a(d,.8),darkBackground:a(d,-.15),ckeButtonOn:a(d,.4),ckeResizer:a(d,-.4),ckeColorauto:a(d,.8),dialogBody:a(d,.7),dialogTab:a(d,.65),dialogTabSelected:\"#FFF\",dialogTabSelectedBorder:\"#FFF\",elementsPathColor:a(d,-.6),menubuttonHover:a(d,.1),menubuttonIcon:a(d,.5),menubuttonIconHover:a(d,.3)};return f[c].output(d).replace(/\\[/g,\"{\").replace(/\\]/g,\"}\")}}(),\nCKEDITOR.plugins.add(\"dialogui\",{onLoad:function(){var a=function(a){this._||(this._={});this._[\"default\"]=this._.initValue=a[\"default\"]||\"\";this._.required=a.required||!1;for(var b=[this._],c=1;c<arguments.length;c++)b.push(arguments[c]);b.push(!0);CKEDITOR.tools.extend.apply(CKEDITOR.tools,b);return this._},f={build:function(a,b,c){return new CKEDITOR.ui.dialog.textInput(a,b,c)}},b={build:function(a,b,c){return new CKEDITOR.ui.dialog[b.type](a,b,c)}},c={isChanged:function(){return this.getValue()!=\nthis.getInitValue()},reset:function(a){this.setValue(this.getInitValue(),a)},setInitValue:function(){this._.initValue=this.getValue()},resetInitValue:function(){this._.initValue=this._[\"default\"]},getInitValue:function(){return this._.initValue}},d=CKEDITOR.tools.extend({},CKEDITOR.ui.dialog.uiElement.prototype.eventProcessors,{onChange:function(a,b){this._.domOnChangeRegistered||(a.on(\"load\",function(){this.getInputElement().on(\"change\",function(){a.parts.dialog.isVisible()&&this.fire(\"change\",{value:this.getValue()})},\nthis)},this),this._.domOnChangeRegistered=!0);this.on(\"change\",b)}},!0),l=/^on([A-Z]\\w+)/,k=function(a){for(var b in a)(l.test(b)||\"title\"==b||\"type\"==b)&&delete a[b];return a},g=function(a){a=a.data.getKeystroke();a==CKEDITOR.SHIFT+CKEDITOR.ALT+36?this.setDirectionMarker(\"ltr\"):a==CKEDITOR.SHIFT+CKEDITOR.ALT+35&&this.setDirectionMarker(\"rtl\")};CKEDITOR.tools.extend(CKEDITOR.ui.dialog,{labeledElement:function(b,c,e,d){if(!(4>arguments.length)){var g=a.call(this,c);g.labelId=CKEDITOR.tools.getNextId()+\n\"_label\";this._.children=[];var f={role:c.role||\"presentation\"};c.includeLabel&&(f[\"aria-labelledby\"]=g.labelId);CKEDITOR.ui.dialog.uiElement.call(this,b,c,e,\"div\",null,f,function(){var a=[],e=c.required?\" cke_required\":\"\";\"horizontal\"!=c.labelLayout?a.push('\\x3clabel class\\x3d\"cke_dialog_ui_labeled_label'+e+'\" ',' id\\x3d\"'+g.labelId+'\"',g.inputId?' for\\x3d\"'+g.inputId+'\"':\"\",(c.labelStyle?' style\\x3d\"'+c.labelStyle+'\"':\"\")+\"\\x3e\",c.label,\"\\x3c/label\\x3e\",'\\x3cdiv class\\x3d\"cke_dialog_ui_labeled_content\"',\nc.controlStyle?' style\\x3d\"'+c.controlStyle+'\"':\"\",' role\\x3d\"presentation\"\\x3e',d.call(this,b,c),\"\\x3c/div\\x3e\"):(e={type:\"hbox\",widths:c.widths,padding:0,children:[{type:\"html\",html:'\\x3clabel class\\x3d\"cke_dialog_ui_labeled_label'+e+'\" id\\x3d\"'+g.labelId+'\" for\\x3d\"'+g.inputId+'\"'+(c.labelStyle?' style\\x3d\"'+c.labelStyle+'\"':\"\")+\"\\x3e\"+CKEDITOR.tools.htmlEncode(c.label)+\"\\x3c/label\\x3e\"},{type:\"html\",html:'\\x3cspan class\\x3d\"cke_dialog_ui_labeled_content\"'+(c.controlStyle?' style\\x3d\"'+c.controlStyle+\n'\"':\"\")+\"\\x3e\"+d.call(this,b,c)+\"\\x3c/span\\x3e\"}]},CKEDITOR.dialog._.uiElementBuilders.hbox.build(b,e,a));return a.join(\"\")})}},textInput:function(b,c,e){if(!(3>arguments.length)){a.call(this,c);var d=this._.inputId=CKEDITOR.tools.getNextId()+\"_textInput\",f={\"class\":\"cke_dialog_ui_input_\"+c.type,id:d,type:c.type};c.validate&&(this.validate=c.validate);c.maxLength&&(f.maxlength=c.maxLength);c.size&&(f.size=c.size);c.inputStyle&&(f.style=c.inputStyle);var k=this,l=!1;b.on(\"load\",function(){k.getInputElement().on(\"keydown\",\nfunction(a){13==a.data.getKeystroke()&&(l=!0)});k.getInputElement().on(\"keyup\",function(a){13==a.data.getKeystroke()&&l&&(b.getButton(\"ok\")&&setTimeout(function(){b.getButton(\"ok\").click()},0),l=!1);k.bidi&&g.call(k,a)},null,null,1E3)});CKEDITOR.ui.dialog.labeledElement.call(this,b,c,e,function(){var a=['\\x3cdiv class\\x3d\"cke_dialog_ui_input_',c.type,'\" role\\x3d\"presentation\"'];c.width&&a.push('style\\x3d\"width:'+c.width+'\" ');a.push(\"\\x3e\\x3cinput \");f[\"aria-labelledby\"]=this._.labelId;this._.required&&\n(f[\"aria-required\"]=this._.required);for(var b in f)a.push(b+'\\x3d\"'+f[b]+'\" ');a.push(\" /\\x3e\\x3c/div\\x3e\");return a.join(\"\")})}},textarea:function(b,c,e){if(!(3>arguments.length)){a.call(this,c);var d=this,f=this._.inputId=CKEDITOR.tools.getNextId()+\"_textarea\",k={};c.validate&&(this.validate=c.validate);k.rows=c.rows||5;k.cols=c.cols||20;k[\"class\"]=\"cke_dialog_ui_input_textarea \"+(c[\"class\"]||\"\");\"undefined\"!=typeof c.inputStyle&&(k.style=c.inputStyle);c.dir&&(k.dir=c.dir);if(d.bidi)b.on(\"load\",\nfunction(){d.getInputElement().on(\"keyup\",g)},d);CKEDITOR.ui.dialog.labeledElement.call(this,b,c,e,function(){k[\"aria-labelledby\"]=this._.labelId;this._.required&&(k[\"aria-required\"]=this._.required);var a=['\\x3cdiv class\\x3d\"cke_dialog_ui_input_textarea\" role\\x3d\"presentation\"\\x3e\\x3ctextarea id\\x3d\"',f,'\" '],b;for(b in k)a.push(b+'\\x3d\"'+CKEDITOR.tools.htmlEncode(k[b])+'\" ');a.push(\"\\x3e\",CKEDITOR.tools.htmlEncode(d._[\"default\"]),\"\\x3c/textarea\\x3e\\x3c/div\\x3e\");return a.join(\"\")})}},checkbox:function(b,\nc,e){if(!(3>arguments.length)){var d=a.call(this,c,{\"default\":!!c[\"default\"]});c.validate&&(this.validate=c.validate);CKEDITOR.ui.dialog.uiElement.call(this,b,c,e,\"span\",null,null,function(){var a=CKEDITOR.tools.extend({},c,{id:c.id?c.id+\"_checkbox\":CKEDITOR.tools.getNextId()+\"_checkbox\"},!0),e=[],g=CKEDITOR.tools.getNextId()+\"_label\",f={\"class\":\"cke_dialog_ui_checkbox_input\",type:\"checkbox\",\"aria-labelledby\":g};k(a);c[\"default\"]&&(f.checked=\"checked\");\"undefined\"!=typeof a.inputStyle&&(a.style=a.inputStyle);\nd.checkbox=new CKEDITOR.ui.dialog.uiElement(b,a,e,\"input\",null,f);e.push(' \\x3clabel id\\x3d\"',g,'\" for\\x3d\"',f.id,'\"'+(c.labelStyle?' style\\x3d\"'+c.labelStyle+'\"':\"\")+\"\\x3e\",CKEDITOR.tools.htmlEncode(c.label),\"\\x3c/label\\x3e\");return e.join(\"\")})}},radio:function(b,c,e){if(!(3>arguments.length)){a.call(this,c);this._[\"default\"]||(this._[\"default\"]=this._.initValue=c.items[0][1]);c.validate&&(this.validate=c.validate);var d=[],g=this;c.role=\"radiogroup\";c.includeLabel=!0;CKEDITOR.ui.dialog.labeledElement.call(this,\nb,c,e,function(){for(var a=[],e=[],f=(c.id?c.id:CKEDITOR.tools.getNextId())+\"_radio\",l=0;l<c.items.length;l++){var w=c.items[l],r=void 0!==w[2]?w[2]:w[0],z=void 0!==w[1]?w[1]:w[0],t=CKEDITOR.tools.getNextId()+\"_radio_input\",x=t+\"_label\",t=CKEDITOR.tools.extend({},c,{id:t,title:null,type:null},!0),r=CKEDITOR.tools.extend({},t,{title:r},!0),A={type:\"radio\",\"class\":\"cke_dialog_ui_radio_input\",name:f,value:z,\"aria-labelledby\":x},B=[];g._[\"default\"]==z&&(A.checked=\"checked\");k(t);k(r);\"undefined\"!=typeof t.inputStyle&&\n(t.style=t.inputStyle);t.keyboardFocusable=!0;d.push(new CKEDITOR.ui.dialog.uiElement(b,t,B,\"input\",null,A));B.push(\" \");new CKEDITOR.ui.dialog.uiElement(b,r,B,\"label\",null,{id:x,\"for\":A.id},w[0]);a.push(B.join(\"\"))}new CKEDITOR.ui.dialog.hbox(b,d,a,e);return e.join(\"\")});this._.children=d}},button:function(b,c,e){if(arguments.length){\"function\"==typeof c&&(c=c(b.getParentEditor()));a.call(this,c,{disabled:c.disabled||!1});CKEDITOR.event.implementOn(this);var d=this;b.on(\"load\",function(){var a=this.getElement();\n(function(){a.on(\"click\",function(a){d.click();a.data.preventDefault()});a.on(\"keydown\",function(a){a.data.getKeystroke()in{32:1}&&(d.click(),a.data.preventDefault())})})();a.unselectable()},this);var g=CKEDITOR.tools.extend({},c);delete g.style;var f=CKEDITOR.tools.getNextId()+\"_label\";CKEDITOR.ui.dialog.uiElement.call(this,b,g,e,\"a\",null,{style:c.style,href:\"javascript:void(0)\",title:c.label,hidefocus:\"true\",\"class\":c[\"class\"],role:\"button\",\"aria-labelledby\":f},'\\x3cspan id\\x3d\"'+f+'\" class\\x3d\"cke_dialog_ui_button\"\\x3e'+\nCKEDITOR.tools.htmlEncode(c.label)+\"\\x3c/span\\x3e\")}},select:function(b,c,e){if(!(3>arguments.length)){var d=a.call(this,c);c.validate&&(this.validate=c.validate);d.inputId=CKEDITOR.tools.getNextId()+\"_select\";CKEDITOR.ui.dialog.labeledElement.call(this,b,c,e,function(){var a=CKEDITOR.tools.extend({},c,{id:c.id?c.id+\"_select\":CKEDITOR.tools.getNextId()+\"_select\"},!0),e=[],g=[],f={id:d.inputId,\"class\":\"cke_dialog_ui_input_select\",\"aria-labelledby\":this._.labelId};e.push('\\x3cdiv class\\x3d\"cke_dialog_ui_input_',\nc.type,'\" role\\x3d\"presentation\"');c.width&&e.push('style\\x3d\"width:'+c.width+'\" ');e.push(\"\\x3e\");void 0!==c.size&&(f.size=c.size);void 0!==c.multiple&&(f.multiple=c.multiple);k(a);for(var l=0,w;l<c.items.length&&(w=c.items[l]);l++)g.push('\\x3coption value\\x3d\"',CKEDITOR.tools.htmlEncode(void 0!==w[1]?w[1]:w[0]).replace(/\"/g,\"\\x26quot;\"),'\" /\\x3e ',CKEDITOR.tools.htmlEncode(w[0]));\"undefined\"!=typeof a.inputStyle&&(a.style=a.inputStyle);d.select=new CKEDITOR.ui.dialog.uiElement(b,a,e,\"select\",null,\nf,g.join(\"\"));e.push(\"\\x3c/div\\x3e\");return e.join(\"\")})}},file:function(b,c,e){if(!(3>arguments.length)){void 0===c[\"default\"]&&(c[\"default\"]=\"\");var d=CKEDITOR.tools.extend(a.call(this,c),{definition:c,buttons:[]});c.validate&&(this.validate=c.validate);b.on(\"load\",function(){CKEDITOR.document.getById(d.frameId).getParent().addClass(\"cke_dialog_ui_input_file\")});CKEDITOR.ui.dialog.labeledElement.call(this,b,c,e,function(){d.frameId=CKEDITOR.tools.getNextId()+\"_fileInput\";var a=['\\x3ciframe frameborder\\x3d\"0\" allowtransparency\\x3d\"0\" class\\x3d\"cke_dialog_ui_input_file\" role\\x3d\"presentation\" id\\x3d\"',\nd.frameId,'\" title\\x3d\"',c.label,'\" src\\x3d\"javascript:void('];a.push(CKEDITOR.env.ie?\"(function(){\"+encodeURIComponent(\"document.open();(\"+CKEDITOR.tools.fixDomain+\")();document.close();\")+\"})()\":\"0\");a.push(')\"\\x3e\\x3c/iframe\\x3e');return a.join(\"\")})}},fileButton:function(b,c,e){var d=this;if(!(3>arguments.length)){a.call(this,c);c.validate&&(this.validate=c.validate);var g=CKEDITOR.tools.extend({},c),f=g.onClick;g.className=(g.className?g.className+\" \":\"\")+\"cke_dialog_ui_button\";g.onClick=function(a){var e=\nc[\"for\"];a=f?f.call(this,a):!1;!1!==a&&(\"xhr\"!==a&&b.getContentElement(e[0],e[1]).submit(),this.disable())};b.on(\"load\",function(){b.getContentElement(c[\"for\"][0],c[\"for\"][1])._.buttons.push(d)});CKEDITOR.ui.dialog.button.call(this,b,g,e)}},html:function(){var a=/^\\s*<[\\w:]+\\s+([^>]*)?>/,b=/^(\\s*<[\\w:]+(?:\\s+[^>]*)?)((?:.|\\r|\\n)+)$/,c=/\\/$/;return function(d,g,f){if(!(3>arguments.length)){var k=[],l=g.html;\"\\x3c\"!=l.charAt(0)&&(l=\"\\x3cspan\\x3e\"+l+\"\\x3c/span\\x3e\");var v=g.focus;if(v){var w=this.focus;\nthis.focus=function(){(\"function\"==typeof v?v:w).call(this);this.fire(\"focus\")};g.isFocusable&&(this.isFocusable=this.isFocusable);this.keyboardFocusable=!0}CKEDITOR.ui.dialog.uiElement.call(this,d,g,k,\"span\",null,null,\"\");k=k.join(\"\").match(a);l=l.match(b)||[\"\",\"\",\"\"];c.test(l[1])&&(l[1]=l[1].slice(0,-1),l[2]=\"/\"+l[2]);f.push([l[1],\" \",k[1]||\"\",l[2]].join(\"\"))}}}(),fieldset:function(a,b,c,d,g){var f=g.label;this._={children:b};CKEDITOR.ui.dialog.uiElement.call(this,a,g,d,\"fieldset\",null,null,function(){var a=\n[];f&&a.push(\"\\x3clegend\"+(g.labelStyle?' style\\x3d\"'+g.labelStyle+'\"':\"\")+\"\\x3e\"+f+\"\\x3c/legend\\x3e\");for(var b=0;b<c.length;b++)a.push(c[b]);return a.join(\"\")})}},!0);CKEDITOR.ui.dialog.html.prototype=new CKEDITOR.ui.dialog.uiElement;CKEDITOR.ui.dialog.labeledElement.prototype=CKEDITOR.tools.extend(new CKEDITOR.ui.dialog.uiElement,{setLabel:function(a){var b=CKEDITOR.document.getById(this._.labelId);1>b.getChildCount()?(new CKEDITOR.dom.text(a,CKEDITOR.document)).appendTo(b):b.getChild(0).$.nodeValue=\na;return this},getLabel:function(){var a=CKEDITOR.document.getById(this._.labelId);return!a||1>a.getChildCount()?\"\":a.getChild(0).getText()},eventProcessors:d},!0);CKEDITOR.ui.dialog.button.prototype=CKEDITOR.tools.extend(new CKEDITOR.ui.dialog.uiElement,{click:function(){return this._.disabled?!1:this.fire(\"click\",{dialog:this._.dialog})},enable:function(){this._.disabled=!1;var a=this.getElement();a&&a.removeClass(\"cke_disabled\")},disable:function(){this._.disabled=!0;this.getElement().addClass(\"cke_disabled\")},\nisVisible:function(){return this.getElement().getFirst().isVisible()},isEnabled:function(){return!this._.disabled},eventProcessors:CKEDITOR.tools.extend({},CKEDITOR.ui.dialog.uiElement.prototype.eventProcessors,{onClick:function(a,b){this.on(\"click\",function(){b.apply(this,arguments)})}},!0),accessKeyUp:function(){this.click()},accessKeyDown:function(){this.focus()},keyboardFocusable:!0},!0);CKEDITOR.ui.dialog.textInput.prototype=CKEDITOR.tools.extend(new CKEDITOR.ui.dialog.labeledElement,{getInputElement:function(){return CKEDITOR.document.getById(this._.inputId)},\nfocus:function(){var a=this.selectParentTab();setTimeout(function(){var b=a.getInputElement();b&&b.$.focus()},0)},select:function(){var a=this.selectParentTab();setTimeout(function(){var b=a.getInputElement();b&&(b.$.focus(),b.$.select())},0)},accessKeyUp:function(){this.select()},setValue:function(a){if(this.bidi){var b=a&&a.charAt(0);(b=\"‪\"==b?\"ltr\":\"‫\"==b?\"rtl\":null)&&(a=a.slice(1));this.setDirectionMarker(b)}a||(a=\"\");return CKEDITOR.ui.dialog.uiElement.prototype.setValue.apply(this,arguments)},\ngetValue:function(){var a=CKEDITOR.ui.dialog.uiElement.prototype.getValue.call(this);if(this.bidi&&a){var b=this.getDirectionMarker();b&&(a=(\"ltr\"==b?\"‪\":\"‫\")+a)}return a},setDirectionMarker:function(a){var b=this.getInputElement();a?b.setAttributes({dir:a,\"data-cke-dir-marker\":a}):this.getDirectionMarker()&&b.removeAttributes([\"dir\",\"data-cke-dir-marker\"])},getDirectionMarker:function(){return this.getInputElement().data(\"cke-dir-marker\")},keyboardFocusable:!0},c,!0);CKEDITOR.ui.dialog.textarea.prototype=\nnew CKEDITOR.ui.dialog.textInput;CKEDITOR.ui.dialog.select.prototype=CKEDITOR.tools.extend(new CKEDITOR.ui.dialog.labeledElement,{getInputElement:function(){return this._.select.getElement()},add:function(a,b,c){var d=new CKEDITOR.dom.element(\"option\",this.getDialog().getParentEditor().document),g=this.getInputElement().$;d.$.text=a;d.$.value=void 0===b||null===b?a:b;void 0===c||null===c?CKEDITOR.env.ie?g.add(d.$):g.add(d.$,null):g.add(d.$,c);return this},remove:function(a){this.getInputElement().$.remove(a);\nreturn this},clear:function(){for(var a=this.getInputElement().$;0<a.length;)a.remove(0);return this},keyboardFocusable:!0},c,!0);CKEDITOR.ui.dialog.checkbox.prototype=CKEDITOR.tools.extend(new CKEDITOR.ui.dialog.uiElement,{getInputElement:function(){return this._.checkbox.getElement()},setValue:function(a,b){this.getInputElement().$.checked=a;!b&&this.fire(\"change\",{value:a})},getValue:function(){return this.getInputElement().$.checked},accessKeyUp:function(){this.setValue(!this.getValue())},eventProcessors:{onChange:function(a,\nb){if(!CKEDITOR.env.ie||8<CKEDITOR.env.version)return d.onChange.apply(this,arguments);a.on(\"load\",function(){var a=this._.checkbox.getElement();a.on(\"propertychange\",function(b){b=b.data.$;\"checked\"==b.propertyName&&this.fire(\"change\",{value:a.$.checked})},this)},this);this.on(\"change\",b);return null}},keyboardFocusable:!0},c,!0);CKEDITOR.ui.dialog.radio.prototype=CKEDITOR.tools.extend(new CKEDITOR.ui.dialog.uiElement,{setValue:function(a,b){for(var c=this._.children,d,g=0;g<c.length&&(d=c[g]);g++)d.getElement().$.checked=\nd.getValue()==a;!b&&this.fire(\"change\",{value:a})},getValue:function(){for(var a=this._.children,b=0;b<a.length;b++)if(a[b].getElement().$.checked)return a[b].getValue();return null},accessKeyUp:function(){var a=this._.children,b;for(b=0;b<a.length;b++)if(a[b].getElement().$.checked){a[b].getElement().focus();return}a[0].getElement().focus()},eventProcessors:{onChange:function(a,b){if(!CKEDITOR.env.ie||8<CKEDITOR.env.version)return d.onChange.apply(this,arguments);a.on(\"load\",function(){for(var a=\nthis._.children,b=this,c=0;c<a.length;c++)a[c].getElement().on(\"propertychange\",function(a){a=a.data.$;\"checked\"==a.propertyName&&this.$.checked&&b.fire(\"change\",{value:this.getAttribute(\"value\")})})},this);this.on(\"change\",b);return null}}},c,!0);CKEDITOR.ui.dialog.file.prototype=CKEDITOR.tools.extend(new CKEDITOR.ui.dialog.labeledElement,c,{getInputElement:function(){var a=CKEDITOR.document.getById(this._.frameId).getFrameDocument();return 0<a.$.forms.length?new CKEDITOR.dom.element(a.$.forms[0].elements[0]):\nthis.getElement()},submit:function(){this.getInputElement().getParent().$.submit();return this},getAction:function(){return this.getInputElement().getParent().$.action},registerEvents:function(a){var b=/^on([A-Z]\\w+)/,c,d=function(a,b,c,e){a.on(\"formLoaded\",function(){a.getInputElement().on(c,e,a)})},g;for(g in a)if(c=g.match(b))this.eventProcessors[g]?this.eventProcessors[g].call(this,this._.dialog,a[g]):d(this,this._.dialog,c[1].toLowerCase(),a[g]);return this},reset:function(){function a(){c.$.open();\nvar h=\"\";d.size&&(h=d.size-(CKEDITOR.env.ie?7:0));var r=b.frameId+\"_input\";c.$.write(['\\x3chtml dir\\x3d\"'+l+'\" lang\\x3d\"'+v+'\"\\x3e\\x3chead\\x3e\\x3ctitle\\x3e\\x3c/title\\x3e\\x3c/head\\x3e\\x3cbody style\\x3d\"margin: 0; overflow: hidden; background: transparent;\"\\x3e','\\x3cform enctype\\x3d\"multipart/form-data\" method\\x3d\"POST\" dir\\x3d\"'+l+'\" lang\\x3d\"'+v+'\" action\\x3d\"',CKEDITOR.tools.htmlEncode(d.action),'\"\\x3e\\x3clabel id\\x3d\"',b.labelId,'\" for\\x3d\"',r,'\" style\\x3d\"display:none\"\\x3e',CKEDITOR.tools.htmlEncode(d.label),\n'\\x3c/label\\x3e\\x3cinput style\\x3d\"width:100%\" id\\x3d\"',r,'\" aria-labelledby\\x3d\"',b.labelId,'\" type\\x3d\"file\" name\\x3d\"',CKEDITOR.tools.htmlEncode(d.id||\"cke_upload\"),'\" size\\x3d\"',CKEDITOR.tools.htmlEncode(0<h?h:\"\"),'\" /\\x3e\\x3c/form\\x3e\\x3c/body\\x3e\\x3c/html\\x3e\\x3cscript\\x3e',CKEDITOR.env.ie?\"(\"+CKEDITOR.tools.fixDomain+\")();\":\"\",\"window.parent.CKEDITOR.tools.callFunction(\"+f+\");\",\"window.onbeforeunload \\x3d function() {window.parent.CKEDITOR.tools.callFunction(\"+k+\")}\",\"\\x3c/script\\x3e\"].join(\"\"));\nc.$.close();for(h=0;h<g.length;h++)g[h].enable()}var b=this._,c=CKEDITOR.document.getById(b.frameId).getFrameDocument(),d=b.definition,g=b.buttons,f=this.formLoadedNumber,k=this.formUnloadNumber,l=b.dialog._.editor.lang.dir,v=b.dialog._.editor.langCode;f||(f=this.formLoadedNumber=CKEDITOR.tools.addFunction(function(){this.fire(\"formLoaded\")},this),k=this.formUnloadNumber=CKEDITOR.tools.addFunction(function(){this.getInputElement().clearCustomData()},this),this.getDialog()._.editor.on(\"destroy\",function(){CKEDITOR.tools.removeFunction(f);\nCKEDITOR.tools.removeFunction(k)}));CKEDITOR.env.gecko?setTimeout(a,500):a()},getValue:function(){return this.getInputElement().$.value||\"\"},setInitValue:function(){this._.initValue=\"\"},eventProcessors:{onChange:function(a,b){this._.domOnChangeRegistered||(this.on(\"formLoaded\",function(){this.getInputElement().on(\"change\",function(){this.fire(\"change\",{value:this.getValue()})},this)},this),this._.domOnChangeRegistered=!0);this.on(\"change\",b)}},keyboardFocusable:!0},!0);CKEDITOR.ui.dialog.fileButton.prototype=\nnew CKEDITOR.ui.dialog.button;CKEDITOR.ui.dialog.fieldset.prototype=CKEDITOR.tools.clone(CKEDITOR.ui.dialog.hbox.prototype);CKEDITOR.dialog.addUIElement(\"text\",f);CKEDITOR.dialog.addUIElement(\"password\",f);CKEDITOR.dialog.addUIElement(\"tel\",f);CKEDITOR.dialog.addUIElement(\"textarea\",b);CKEDITOR.dialog.addUIElement(\"checkbox\",b);CKEDITOR.dialog.addUIElement(\"radio\",b);CKEDITOR.dialog.addUIElement(\"button\",b);CKEDITOR.dialog.addUIElement(\"select\",b);CKEDITOR.dialog.addUIElement(\"file\",b);CKEDITOR.dialog.addUIElement(\"fileButton\",\nb);CKEDITOR.dialog.addUIElement(\"html\",b);CKEDITOR.dialog.addUIElement(\"fieldset\",{build:function(a,b,c){for(var d=b.children,g,f=[],k=[],l=0;l<d.length&&(g=d[l]);l++){var v=[];f.push(v);k.push(CKEDITOR.dialog._.uiElementBuilders[g.type].build(a,g,v))}return new CKEDITOR.ui.dialog[b.type](a,k,f,c,b)}})}}),CKEDITOR.DIALOG_RESIZE_NONE=0,CKEDITOR.DIALOG_RESIZE_WIDTH=1,CKEDITOR.DIALOG_RESIZE_HEIGHT=2,CKEDITOR.DIALOG_RESIZE_BOTH=3,CKEDITOR.DIALOG_STATE_IDLE=1,CKEDITOR.DIALOG_STATE_BUSY=2,function(){function a(){for(var a=\nthis._.tabIdList.length,b=CKEDITOR.tools.indexOf(this._.tabIdList,this._.currentTabId)+a,c=b-1;c>b-a;c--)if(this._.tabs[this._.tabIdList[c%a]][0].$.offsetHeight)return this._.tabIdList[c%a];return null}function f(){for(var a=this._.tabIdList.length,b=CKEDITOR.tools.indexOf(this._.tabIdList,this._.currentTabId),c=b+1;c<b+a;c++)if(this._.tabs[this._.tabIdList[c%a]][0].$.offsetHeight)return this._.tabIdList[c%a];return null}function b(a,b){for(var c=a.$.getElementsByTagName(\"input\"),e=0,d=c.length;e<\nd;e++){var g=new CKEDITOR.dom.element(c[e]);\"text\"==g.getAttribute(\"type\").toLowerCase()&&(b?(g.setAttribute(\"value\",g.getCustomData(\"fake_value\")||\"\"),g.removeCustomData(\"fake_value\")):(g.setCustomData(\"fake_value\",g.getAttribute(\"value\")),g.setAttribute(\"value\",\"\")))}}function c(a,b){var c=this.getInputElement();c&&(a?c.removeAttribute(\"aria-invalid\"):c.setAttribute(\"aria-invalid\",!0));a||(this.select?this.select():this.focus());b&&alert(b);this.fire(\"validated\",{valid:a,msg:b})}function d(){var a=\nthis.getInputElement();a&&a.removeAttribute(\"aria-invalid\")}function l(a){var b=CKEDITOR.dom.element.createFromHtml(CKEDITOR.addTemplate(\"dialog\",p).output({id:CKEDITOR.tools.getNextNumber(),editorId:a.id,langDir:a.lang.dir,langCode:a.langCode,editorDialogClass:\"cke_editor_\"+a.name.replace(/\\./g,\"\\\\.\")+\"_dialog\",closeTitle:a.lang.common.close,hidpi:CKEDITOR.env.hidpi?\"cke_hidpi\":\"\"})),c=b.getChild([0,0,0,0,0]),e=c.getChild(0),d=c.getChild(1);a.plugins.clipboard&&CKEDITOR.plugins.clipboard.preventDefaultDropOnElement(c);\n!CKEDITOR.env.ie||CKEDITOR.env.quirks||CKEDITOR.env.edge||(a=\"javascript:void(function(){\"+encodeURIComponent(\"document.open();(\"+CKEDITOR.tools.fixDomain+\")();document.close();\")+\"}())\",CKEDITOR.dom.element.createFromHtml('\\x3ciframe frameBorder\\x3d\"0\" class\\x3d\"cke_iframe_shim\" src\\x3d\"'+a+'\" tabIndex\\x3d\"-1\"\\x3e\\x3c/iframe\\x3e').appendTo(c.getParent()));e.unselectable();d.unselectable();return{element:b,parts:{dialog:b.getChild(0),title:e,close:d,tabs:c.getChild(2),contents:c.getChild([3,0,0,0]),\nfooter:c.getChild([3,0,1,0])}}}function k(a,b,c){this.element=b;this.focusIndex=c;this.tabIndex=0;this.isFocusable=function(){return!b.getAttribute(\"disabled\")&&b.isVisible()};this.focus=function(){a._.currentFocusIndex=this.focusIndex;this.element.focus()};b.on(\"keydown\",function(a){a.data.getKeystroke()in{32:1,13:1}&&this.fire(\"click\")});b.on(\"focus\",function(){this.fire(\"mouseover\")});b.on(\"blur\",function(){this.fire(\"mouseout\")})}function g(a){function b(){a.layout()}var c=CKEDITOR.document.getWindow();\nc.on(\"resize\",b);a.on(\"hide\",function(){c.removeListener(\"resize\",b)})}function h(a,b){this._={dialog:a};CKEDITOR.tools.extend(this,b)}function m(a){function b(c){var k=a.getSize(),l=CKEDITOR.document.getWindow().getViewPaneSize(),m=c.data.$.screenX,n=c.data.$.screenY,r=m-e.x,t=n-e.y;e={x:m,y:n};d.x+=r;d.y+=t;a.move(d.x+h[3]<f?-h[3]:d.x-h[1]>l.width-k.width-f?l.width-k.width+(\"rtl\"==g.lang.dir?0:h[1]):d.x,d.y+h[0]<f?-h[0]:d.y-h[2]>l.height-k.height-f?l.height-k.height+h[2]:d.y,1);c.data.preventDefault()}\nfunction c(){CKEDITOR.document.removeListener(\"mousemove\",b);CKEDITOR.document.removeListener(\"mouseup\",c);if(CKEDITOR.env.ie6Compat){var a=B.getChild(0).getFrameDocument();a.removeListener(\"mousemove\",b);a.removeListener(\"mouseup\",c)}}var e=null,d=null,g=a.getParentEditor(),f=g.config.dialog_magnetDistance,h=CKEDITOR.skin.margins||[0,0,0,0];\"undefined\"==typeof f&&(f=20);a.parts.title.on(\"mousedown\",function(g){e={x:g.data.$.screenX,y:g.data.$.screenY};CKEDITOR.document.on(\"mousemove\",b);CKEDITOR.document.on(\"mouseup\",\nc);d=a.getPosition();if(CKEDITOR.env.ie6Compat){var f=B.getChild(0).getFrameDocument();f.on(\"mousemove\",b);f.on(\"mouseup\",c)}g.data.preventDefault()},a)}function e(a){function b(c){var n=\"rtl\"==g.lang.dir,r=m.width,t=m.height,v=r+(c.data.$.screenX-l.x)*(n?-1:1)*(a._.moved?1:2),q=t+(c.data.$.screenY-l.y)*(a._.moved?1:2),w=a._.element.getFirst(),w=n&&w.getComputedStyle(\"right\"),z=a.getPosition();z.y+q>k.height&&(q=k.height-z.y);(n?w:z.x)+v>k.width&&(v=k.width-(n?w:z.x));if(d==CKEDITOR.DIALOG_RESIZE_WIDTH||\nd==CKEDITOR.DIALOG_RESIZE_BOTH)r=Math.max(e.minWidth||0,v-f);if(d==CKEDITOR.DIALOG_RESIZE_HEIGHT||d==CKEDITOR.DIALOG_RESIZE_BOTH)t=Math.max(e.minHeight||0,q-h);a.resize(r,t);a._.moved||a.layout();c.data.preventDefault()}function c(){CKEDITOR.document.removeListener(\"mouseup\",c);CKEDITOR.document.removeListener(\"mousemove\",b);n&&(n.remove(),n=null);if(CKEDITOR.env.ie6Compat){var a=B.getChild(0).getFrameDocument();a.removeListener(\"mouseup\",c);a.removeListener(\"mousemove\",b)}}var e=a.definition,d=e.resizable;\nif(d!=CKEDITOR.DIALOG_RESIZE_NONE){var g=a.getParentEditor(),f,h,k,l,m,n,r=CKEDITOR.tools.addFunction(function(e){m=a.getSize();var d=a.parts.contents;d.$.getElementsByTagName(\"iframe\").length&&(n=CKEDITOR.dom.element.createFromHtml('\\x3cdiv class\\x3d\"cke_dialog_resize_cover\" style\\x3d\"height: 100%; position: absolute; width: 100%;\"\\x3e\\x3c/div\\x3e'),d.append(n));h=m.height-a.parts.contents.getSize(\"height\",!(CKEDITOR.env.gecko||CKEDITOR.env.ie&&CKEDITOR.env.quirks));f=m.width-a.parts.contents.getSize(\"width\",\n1);l={x:e.screenX,y:e.screenY};k=CKEDITOR.document.getWindow().getViewPaneSize();CKEDITOR.document.on(\"mousemove\",b);CKEDITOR.document.on(\"mouseup\",c);CKEDITOR.env.ie6Compat&&(d=B.getChild(0).getFrameDocument(),d.on(\"mousemove\",b),d.on(\"mouseup\",c));e.preventDefault&&e.preventDefault()});a.on(\"load\",function(){var b=\"\";d==CKEDITOR.DIALOG_RESIZE_WIDTH?b=\" cke_resizer_horizontal\":d==CKEDITOR.DIALOG_RESIZE_HEIGHT&&(b=\" cke_resizer_vertical\");b=CKEDITOR.dom.element.createFromHtml('\\x3cdiv class\\x3d\"cke_resizer'+\nb+\" cke_resizer_\"+g.lang.dir+'\" title\\x3d\"'+CKEDITOR.tools.htmlEncode(g.lang.common.resize)+'\" onmousedown\\x3d\"CKEDITOR.tools.callFunction('+r+', event )\"\\x3e'+(\"ltr\"==g.lang.dir?\"◢\":\"◣\")+\"\\x3c/div\\x3e\");a.parts.footer.append(b,1)});g.on(\"destroy\",function(){CKEDITOR.tools.removeFunction(r)})}}function n(a){a.data.preventDefault(1)}function q(a){var b=CKEDITOR.document.getWindow(),c=a.config,e=CKEDITOR.skinName||a.config.skin,d=c.dialog_backgroundCoverColor||(\"moono-lisa\"==e?\"black\":\"white\"),e=c.dialog_backgroundCoverOpacity,\ng=c.baseFloatZIndex,c=CKEDITOR.tools.genKey(d,e,g),f=A[c];f?f.show():(g=['\\x3cdiv tabIndex\\x3d\"-1\" style\\x3d\"position: ',CKEDITOR.env.ie6Compat?\"absolute\":\"fixed\",\"; z-index: \",g,\"; top: 0px; left: 0px; \",CKEDITOR.env.ie6Compat?\"\":\"background-color: \"+d,'\" class\\x3d\"cke_dialog_background_cover\"\\x3e'],CKEDITOR.env.ie6Compat&&(d=\"\\x3chtml\\x3e\\x3cbody style\\x3d\\\\'background-color:\"+d+\";\\\\'\\x3e\\x3c/body\\x3e\\x3c/html\\x3e\",g.push('\\x3ciframe hidefocus\\x3d\"true\" frameborder\\x3d\"0\" id\\x3d\"cke_dialog_background_iframe\" src\\x3d\"javascript:'),\ng.push(\"void((function(){\"+encodeURIComponent(\"document.open();(\"+CKEDITOR.tools.fixDomain+\")();document.write( '\"+d+\"' );document.close();\")+\"})())\"),g.push('\" style\\x3d\"position:absolute;left:0;top:0;width:100%;height: 100%;filter: progid:DXImageTransform.Microsoft.Alpha(opacity\\x3d0)\"\\x3e\\x3c/iframe\\x3e')),g.push(\"\\x3c/div\\x3e\"),f=CKEDITOR.dom.element.createFromHtml(g.join(\"\")),f.setOpacity(void 0!==e?e:.5),f.on(\"keydown\",n),f.on(\"keypress\",n),f.on(\"keyup\",n),f.appendTo(CKEDITOR.document.getBody()),\nA[c]=f);a.focusManager.add(f);B=f;a=function(){var a=b.getViewPaneSize();f.setStyles({width:a.width+\"px\",height:a.height+\"px\"})};var h=function(){var a=b.getScrollPosition(),c=CKEDITOR.dialog._.currentTop;f.setStyles({left:a.x+\"px\",top:a.y+\"px\"});if(c){do a=c.getPosition(),c.move(a.x,a.y);while(c=c._.parentDialog)}};x=a;b.on(\"resize\",a);a();CKEDITOR.env.mac&&CKEDITOR.env.webkit||f.focus();if(CKEDITOR.env.ie6Compat){var k=function(){h();k.prevScrollHandler.apply(this,arguments)};b.$.setTimeout(function(){k.prevScrollHandler=\nwindow.onscroll||function(){};window.onscroll=k},0);h()}}function y(a){B&&(a.focusManager.remove(B),a=CKEDITOR.document.getWindow(),B.hide(),B=null,a.removeListener(\"resize\",x),CKEDITOR.env.ie6Compat&&a.$.setTimeout(function(){window.onscroll=window.onscroll&&window.onscroll.prevScrollHandler||null},0),x=null)}var u=CKEDITOR.tools.cssLength,p='\\x3cdiv class\\x3d\"cke_reset_all {editorId} {editorDialogClass} {hidpi}\" dir\\x3d\"{langDir}\" lang\\x3d\"{langCode}\" role\\x3d\"dialog\" aria-labelledby\\x3d\"cke_dialog_title_{id}\"\\x3e\\x3ctable class\\x3d\"cke_dialog '+\nCKEDITOR.env.cssClass+' cke_{langDir}\" style\\x3d\"position:absolute\" role\\x3d\"presentation\"\\x3e\\x3ctr\\x3e\\x3ctd role\\x3d\"presentation\"\\x3e\\x3cdiv class\\x3d\"cke_dialog_body\" role\\x3d\"presentation\"\\x3e\\x3cdiv id\\x3d\"cke_dialog_title_{id}\" class\\x3d\"cke_dialog_title\" role\\x3d\"presentation\"\\x3e\\x3c/div\\x3e\\x3ca id\\x3d\"cke_dialog_close_button_{id}\" class\\x3d\"cke_dialog_close_button\" href\\x3d\"javascript:void(0)\" title\\x3d\"{closeTitle}\" role\\x3d\"button\"\\x3e\\x3cspan class\\x3d\"cke_label\"\\x3eX\\x3c/span\\x3e\\x3c/a\\x3e\\x3cdiv id\\x3d\"cke_dialog_tabs_{id}\" class\\x3d\"cke_dialog_tabs\" role\\x3d\"tablist\"\\x3e\\x3c/div\\x3e\\x3ctable class\\x3d\"cke_dialog_contents\" role\\x3d\"presentation\"\\x3e\\x3ctr\\x3e\\x3ctd id\\x3d\"cke_dialog_contents_{id}\" class\\x3d\"cke_dialog_contents_body\" role\\x3d\"presentation\"\\x3e\\x3c/td\\x3e\\x3c/tr\\x3e\\x3ctr\\x3e\\x3ctd id\\x3d\"cke_dialog_footer_{id}\" class\\x3d\"cke_dialog_footer\" role\\x3d\"presentation\"\\x3e\\x3c/td\\x3e\\x3c/tr\\x3e\\x3c/table\\x3e\\x3c/div\\x3e\\x3c/td\\x3e\\x3c/tr\\x3e\\x3c/table\\x3e\\x3c/div\\x3e';\nCKEDITOR.dialog=function(b,g){function h(){var a=x._.focusList;a.sort(function(a,b){return a.tabIndex!=b.tabIndex?b.tabIndex-a.tabIndex:a.focusIndex-b.focusIndex});for(var b=a.length,c=0;c<b;c++)a[c].focusIndex=c}function k(a){var b=x._.focusList;a=a||0;if(!(1>b.length)){var c=x._.currentFocusIndex;x._.tabBarMode&&0>a&&(c=0);try{b[c].getInputElement().$.blur()}catch(e){}var d=c,g=1<x._.pageCount;do{d+=a;if(g&&!x._.tabBarMode&&(d==b.length||-1==d)){x._.tabBarMode=!0;x._.tabs[x._.currentTabId][0].focus();\nx._.currentFocusIndex=-1;return}d=(d+b.length)%b.length;if(d==c)break}while(a&&!b[d].isFocusable());b[d].focus();\"text\"==b[d].type&&b[d].select()}}function n(c){if(x==CKEDITOR.dialog._.currentTop){var e=c.data.getKeystroke(),d=\"rtl\"==b.lang.dir,g=[37,38,39,40];u=p=0;if(9==e||e==CKEDITOR.SHIFT+9)k(e==CKEDITOR.SHIFT+9?-1:1),u=1;else if(e==CKEDITOR.ALT+121&&!x._.tabBarMode&&1<x.getPageCount())x._.tabBarMode=!0,x._.tabs[x._.currentTabId][0].focus(),x._.currentFocusIndex=-1,u=1;else if(-1!=CKEDITOR.tools.indexOf(g,\ne)&&x._.tabBarMode)e=-1!=CKEDITOR.tools.indexOf([d?39:37,38],e)?a.call(x):f.call(x),x.selectPage(e),x._.tabs[e][0].focus(),u=1;else if(13!=e&&32!=e||!x._.tabBarMode)if(13==e)e=c.data.getTarget(),e.is(\"a\",\"button\",\"select\",\"textarea\")||e.is(\"input\")&&\"button\"==e.$.type||((e=this.getButton(\"ok\"))&&CKEDITOR.tools.setTimeout(e.click,0,e),u=1),p=1;else if(27==e)(e=this.getButton(\"cancel\"))?CKEDITOR.tools.setTimeout(e.click,0,e):!1!==this.fire(\"cancel\",{hide:!0}).hide&&this.hide(),p=1;else return;else this.selectPage(this._.currentTabId),\nthis._.tabBarMode=!1,this._.currentFocusIndex=-1,k(1),u=1;r(c)}}function r(a){u?a.data.preventDefault(1):p&&a.data.stopPropagation()}var q=CKEDITOR.dialog._.dialogDefinitions[g],w=CKEDITOR.tools.clone(v),z=b.config.dialog_buttonsOrder||\"OS\",A=b.lang.dir,B={},u,p;(\"OS\"==z&&CKEDITOR.env.mac||\"rtl\"==z&&\"ltr\"==A||\"ltr\"==z&&\"rtl\"==A)&&w.buttons.reverse();q=CKEDITOR.tools.extend(q(b),w);q=CKEDITOR.tools.clone(q);q=new t(this,q);w=l(b);this._={editor:b,element:w.element,name:g,contentSize:{width:0,height:0},\nsize:{width:0,height:0},contents:{},buttons:{},accessKeyMap:{},tabs:{},tabIdList:[],currentTabId:null,currentTabIndex:null,pageCount:0,lastTab:null,tabBarMode:!1,focusList:[],currentFocusIndex:0,hasFocus:!1};this.parts=w.parts;CKEDITOR.tools.setTimeout(function(){b.fire(\"ariaWidget\",this.parts.contents)},0,this);w={position:CKEDITOR.env.ie6Compat?\"absolute\":\"fixed\",top:0,visibility:\"hidden\"};w[\"rtl\"==A?\"right\":\"left\"]=0;this.parts.dialog.setStyles(w);CKEDITOR.event.call(this);this.definition=q=CKEDITOR.fire(\"dialogDefinition\",\n{name:g,definition:q},b).definition;if(!(\"removeDialogTabs\"in b._)&&b.config.removeDialogTabs){w=b.config.removeDialogTabs.split(\";\");for(A=0;A<w.length;A++)if(z=w[A].split(\":\"),2==z.length){var y=z[0];B[y]||(B[y]=[]);B[y].push(z[1])}b._.removeDialogTabs=B}if(b._.removeDialogTabs&&(B=b._.removeDialogTabs[g]))for(A=0;A<B.length;A++)q.removeContents(B[A]);if(q.onLoad)this.on(\"load\",q.onLoad);if(q.onShow)this.on(\"show\",q.onShow);if(q.onHide)this.on(\"hide\",q.onHide);if(q.onOk)this.on(\"ok\",function(a){b.fire(\"saveSnapshot\");\nsetTimeout(function(){b.fire(\"saveSnapshot\")},0);!1===q.onOk.call(this,a)&&(a.data.hide=!1)});this.state=CKEDITOR.DIALOG_STATE_IDLE;if(q.onCancel)this.on(\"cancel\",function(a){!1===q.onCancel.call(this,a)&&(a.data.hide=!1)});var x=this,M=function(a){var b=x._.contents,c=!1,e;for(e in b)for(var d in b[e])if(c=a.call(this,b[e][d]))return};this.on(\"ok\",function(a){M(function(b){if(b.validate){var e=b.validate(this),d=\"string\"==typeof e||!1===e;d&&(a.data.hide=!1,a.stop());c.call(b,!d,\"string\"==typeof e?\ne:void 0);return d}})},this,null,0);this.on(\"cancel\",function(a){M(function(c){if(c.isChanged())return b.config.dialog_noConfirmCancel||confirm(b.lang.common.confirmCancel)||(a.data.hide=!1),!0})},this,null,0);this.parts.close.on(\"click\",function(a){!1!==this.fire(\"cancel\",{hide:!0}).hide&&this.hide();a.data.preventDefault()},this);this.changeFocus=k;var C=this._.element;b.focusManager.add(C,1);this.on(\"show\",function(){C.on(\"keydown\",n,this);if(CKEDITOR.env.gecko)C.on(\"keypress\",r,this)});this.on(\"hide\",\nfunction(){C.removeListener(\"keydown\",n);CKEDITOR.env.gecko&&C.removeListener(\"keypress\",r);M(function(a){d.apply(a)})});this.on(\"iframeAdded\",function(a){(new CKEDITOR.dom.document(a.data.iframe.$.contentWindow.document)).on(\"keydown\",n,this,null,0)});this.on(\"show\",function(){h();var a=1<x._.pageCount;b.config.dialog_startupFocusTab&&a?(x._.tabBarMode=!0,x._.tabs[x._.currentTabId][0].focus(),x._.currentFocusIndex=-1):this._.hasFocus||(this._.currentFocusIndex=a?-1:this._.focusList.length-1,q.onFocus?\n(a=q.onFocus.call(this))&&a.focus():k(1))},this,null,4294967295);if(CKEDITOR.env.ie6Compat)this.on(\"load\",function(){var a=this.getElement(),b=a.getFirst();b.remove();b.appendTo(a)},this);m(this);e(this);(new CKEDITOR.dom.text(q.title,CKEDITOR.document)).appendTo(this.parts.title);for(A=0;A<q.contents.length;A++)(B=q.contents[A])&&this.addPage(B);this.parts.tabs.on(\"click\",function(a){var b=a.data.getTarget();b.hasClass(\"cke_dialog_tab\")&&(b=b.$.id,this.selectPage(b.substring(4,b.lastIndexOf(\"_\"))),\nthis._.tabBarMode&&(this._.tabBarMode=!1,this._.currentFocusIndex=-1,k(1)),a.data.preventDefault())},this);A=[];B=CKEDITOR.dialog._.uiElementBuilders.hbox.build(this,{type:\"hbox\",className:\"cke_dialog_footer_buttons\",widths:[],children:q.buttons},A).getChild();this.parts.footer.setHtml(A.join(\"\"));for(A=0;A<B.length;A++)this._.buttons[B[A].id]=B[A]};CKEDITOR.dialog.prototype={destroy:function(){this.hide();this._.element.remove()},resize:function(){return function(a,b){this._.contentSize&&this._.contentSize.width==\na&&this._.contentSize.height==b||(CKEDITOR.dialog.fire(\"resize\",{dialog:this,width:a,height:b},this._.editor),this.fire(\"resize\",{width:a,height:b},this._.editor),this.parts.contents.setStyles({width:a+\"px\",height:b+\"px\"}),\"rtl\"==this._.editor.lang.dir&&this._.position&&(this._.position.x=CKEDITOR.document.getWindow().getViewPaneSize().width-this._.contentSize.width-parseInt(this._.element.getFirst().getStyle(\"right\"),10)),this._.contentSize={width:a,height:b})}}(),getSize:function(){var a=this._.element.getFirst();\nreturn{width:a.$.offsetWidth||0,height:a.$.offsetHeight||0}},move:function(a,b,c){var e=this._.element.getFirst(),d=\"rtl\"==this._.editor.lang.dir,g=\"fixed\"==e.getComputedStyle(\"position\");CKEDITOR.env.ie&&e.setStyle(\"zoom\",\"100%\");g&&this._.position&&this._.position.x==a&&this._.position.y==b||(this._.position={x:a,y:b},g||(g=CKEDITOR.document.getWindow().getScrollPosition(),a+=g.x,b+=g.y),d&&(g=this.getSize(),a=CKEDITOR.document.getWindow().getViewPaneSize().width-g.width-a),b={top:(0<b?b:0)+\"px\"},\nb[d?\"right\":\"left\"]=(0<a?a:0)+\"px\",e.setStyles(b),c&&(this._.moved=1))},getPosition:function(){return CKEDITOR.tools.extend({},this._.position)},show:function(){var a=this._.element,b=this.definition;a.getParent()&&a.getParent().equals(CKEDITOR.document.getBody())?a.setStyle(\"display\",\"block\"):a.appendTo(CKEDITOR.document.getBody());this.resize(this._.contentSize&&this._.contentSize.width||b.width||b.minWidth,this._.contentSize&&this._.contentSize.height||b.height||b.minHeight);this.reset();null===\nthis._.currentTabId&&this.selectPage(this.definition.contents[0].id);null===CKEDITOR.dialog._.currentZIndex&&(CKEDITOR.dialog._.currentZIndex=this._.editor.config.baseFloatZIndex);this._.element.getFirst().setStyle(\"z-index\",CKEDITOR.dialog._.currentZIndex+=10);null===CKEDITOR.dialog._.currentTop?(CKEDITOR.dialog._.currentTop=this,this._.parentDialog=null,q(this._.editor)):(this._.parentDialog=CKEDITOR.dialog._.currentTop,this._.parentDialog.getElement().getFirst().$.style.zIndex-=Math.floor(this._.editor.config.baseFloatZIndex/\n2),CKEDITOR.dialog._.currentTop=this);a.on(\"keydown\",H);a.on(\"keyup\",F);this._.hasFocus=!1;for(var c in b.contents)if(b.contents[c]){var a=b.contents[c],e=this._.tabs[a.id],d=a.requiredContent,f=0;if(e){for(var h in this._.contents[a.id]){var k=this._.contents[a.id][h];\"hbox\"!=k.type&&\"vbox\"!=k.type&&k.getInputElement()&&(k.requiredContent&&!this._.editor.activeFilter.check(k.requiredContent)?k.disable():(k.enable(),f++))}!f||d&&!this._.editor.activeFilter.check(d)?e[0].addClass(\"cke_dialog_tab_disabled\"):\ne[0].removeClass(\"cke_dialog_tab_disabled\")}}CKEDITOR.tools.setTimeout(function(){this.layout();g(this);this.parts.dialog.setStyle(\"visibility\",\"\");this.fireOnce(\"load\",{});CKEDITOR.ui.fire(\"ready\",this);this.fire(\"show\",{});this._.editor.fire(\"dialogShow\",this);this._.parentDialog||this._.editor.focusManager.lock();this.foreach(function(a){a.setInitValue&&a.setInitValue()})},100,this)},layout:function(){var a=this.parts.dialog,b=this.getSize(),c=CKEDITOR.document.getWindow().getViewPaneSize(),e=\n(c.width-b.width)/2,d=(c.height-b.height)/2;CKEDITOR.env.ie6Compat||(b.height+(0<d?d:0)>c.height||b.width+(0<e?e:0)>c.width?a.setStyle(\"position\",\"absolute\"):a.setStyle(\"position\",\"fixed\"));this.move(this._.moved?this._.position.x:e,this._.moved?this._.position.y:d)},foreach:function(a){for(var b in this._.contents)for(var c in this._.contents[b])a.call(this,this._.contents[b][c]);return this},reset:function(){var a=function(a){a.reset&&a.reset(1)};return function(){this.foreach(a);return this}}(),\nsetupContent:function(){var a=arguments;this.foreach(function(b){b.setup&&b.setup.apply(b,a)})},commitContent:function(){var a=arguments;this.foreach(function(b){CKEDITOR.env.ie&&this._.currentFocusIndex==b.focusIndex&&b.getInputElement().$.blur();b.commit&&b.commit.apply(b,a)})},hide:function(){if(this.parts.dialog.isVisible()){this.fire(\"hide\",{});this._.editor.fire(\"dialogHide\",this);this.selectPage(this._.tabIdList[0]);var a=this._.element;a.setStyle(\"display\",\"none\");this.parts.dialog.setStyle(\"visibility\",\n\"hidden\");for(J(this);CKEDITOR.dialog._.currentTop!=this;)CKEDITOR.dialog._.currentTop.hide();if(this._.parentDialog){var b=this._.parentDialog.getElement().getFirst();b.setStyle(\"z-index\",parseInt(b.$.style.zIndex,10)+Math.floor(this._.editor.config.baseFloatZIndex/2))}else y(this._.editor);if(CKEDITOR.dialog._.currentTop=this._.parentDialog)CKEDITOR.dialog._.currentZIndex-=10;else{CKEDITOR.dialog._.currentZIndex=null;a.removeListener(\"keydown\",H);a.removeListener(\"keyup\",F);var c=this._.editor;\nc.focus();setTimeout(function(){c.focusManager.unlock();CKEDITOR.env.iOS&&c.window.focus()},0)}delete this._.parentDialog;this.foreach(function(a){a.resetInitValue&&a.resetInitValue()});this.setState(CKEDITOR.DIALOG_STATE_IDLE)}},addPage:function(a){if(!a.requiredContent||this._.editor.filter.check(a.requiredContent)){for(var b=[],c=a.label?' title\\x3d\"'+CKEDITOR.tools.htmlEncode(a.label)+'\"':\"\",e=CKEDITOR.dialog._.uiElementBuilders.vbox.build(this,{type:\"vbox\",className:\"cke_dialog_page_contents\",\nchildren:a.elements,expand:!!a.expand,padding:a.padding,style:a.style||\"width: 100%;\"},b),d=this._.contents[a.id]={},g=e.getChild(),f=0;e=g.shift();)e.notAllowed||\"hbox\"==e.type||\"vbox\"==e.type||f++,d[e.id]=e,\"function\"==typeof e.getChild&&g.push.apply(g,e.getChild());f||(a.hidden=!0);b=CKEDITOR.dom.element.createFromHtml(b.join(\"\"));b.setAttribute(\"role\",\"tabpanel\");e=CKEDITOR.env;d=\"cke_\"+a.id+\"_\"+CKEDITOR.tools.getNextNumber();c=CKEDITOR.dom.element.createFromHtml(['\\x3ca class\\x3d\"cke_dialog_tab\"',\n0<this._.pageCount?\" cke_last\":\"cke_first\",c,a.hidden?' style\\x3d\"display:none\"':\"\",' id\\x3d\"',d,'\"',e.gecko&&!e.hc?\"\":' href\\x3d\"javascript:void(0)\"',' tabIndex\\x3d\"-1\" hidefocus\\x3d\"true\" role\\x3d\"tab\"\\x3e',a.label,\"\\x3c/a\\x3e\"].join(\"\"));b.setAttribute(\"aria-labelledby\",d);this._.tabs[a.id]=[c,b];this._.tabIdList.push(a.id);!a.hidden&&this._.pageCount++;this._.lastTab=c;this.updateStyle();b.setAttribute(\"name\",a.id);b.appendTo(this.parts.contents);c.unselectable();this.parts.tabs.append(c);a.accessKey&&\n(I(this,this,\"CTRL+\"+a.accessKey,L,E),this._.accessKeyMap[\"CTRL+\"+a.accessKey]=a.id)}},selectPage:function(a){if(this._.currentTabId!=a&&!this._.tabs[a][0].hasClass(\"cke_dialog_tab_disabled\")&&!1!==this.fire(\"selectPage\",{page:a,currentPage:this._.currentTabId})){for(var c in this._.tabs){var e=this._.tabs[c][0],d=this._.tabs[c][1];c!=a&&(e.removeClass(\"cke_dialog_tab_selected\"),d.hide());d.setAttribute(\"aria-hidden\",c!=a)}var g=this._.tabs[a];g[0].addClass(\"cke_dialog_tab_selected\");CKEDITOR.env.ie6Compat||\nCKEDITOR.env.ie7Compat?(b(g[1]),g[1].show(),setTimeout(function(){b(g[1],1)},0)):g[1].show();this._.currentTabId=a;this._.currentTabIndex=CKEDITOR.tools.indexOf(this._.tabIdList,a)}},updateStyle:function(){this.parts.dialog[(1===this._.pageCount?\"add\":\"remove\")+\"Class\"](\"cke_single_page\")},hidePage:function(b){var c=this._.tabs[b]&&this._.tabs[b][0];c&&1!=this._.pageCount&&c.isVisible()&&(b==this._.currentTabId&&this.selectPage(a.call(this)),c.hide(),this._.pageCount--,this.updateStyle())},showPage:function(a){if(a=\nthis._.tabs[a]&&this._.tabs[a][0])a.show(),this._.pageCount++,this.updateStyle()},getElement:function(){return this._.element},getName:function(){return this._.name},getContentElement:function(a,b){var c=this._.contents[a];return c&&c[b]},getValueOf:function(a,b){return this.getContentElement(a,b).getValue()},setValueOf:function(a,b,c){return this.getContentElement(a,b).setValue(c)},getButton:function(a){return this._.buttons[a]},click:function(a){return this._.buttons[a].click()},disableButton:function(a){return this._.buttons[a].disable()},\nenableButton:function(a){return this._.buttons[a].enable()},getPageCount:function(){return this._.pageCount},getParentEditor:function(){return this._.editor},getSelectedElement:function(){return this.getParentEditor().getSelection().getSelectedElement()},addFocusable:function(a,b){if(\"undefined\"==typeof b)b=this._.focusList.length,this._.focusList.push(new k(this,a,b));else{this._.focusList.splice(b,0,new k(this,a,b));for(var c=b+1;c<this._.focusList.length;c++)this._.focusList[c].focusIndex++}},\nsetState:function(a){if(this.state!=a){this.state=a;if(a==CKEDITOR.DIALOG_STATE_BUSY){if(!this.parts.spinner){var b=this.getParentEditor().lang.dir,c={attributes:{\"class\":\"cke_dialog_spinner\"},styles:{\"float\":\"rtl\"==b?\"right\":\"left\"}};c.styles[\"margin-\"+(\"rtl\"==b?\"left\":\"right\")]=\"8px\";this.parts.spinner=CKEDITOR.document.createElement(\"div\",c);this.parts.spinner.setHtml(\"\\x26#8987;\");this.parts.spinner.appendTo(this.parts.title,1)}this.parts.spinner.show();this.getButton(\"ok\").disable()}else a==\nCKEDITOR.DIALOG_STATE_IDLE&&(this.parts.spinner&&this.parts.spinner.hide(),this.getButton(\"ok\").enable());this.fire(\"state\",a)}}};CKEDITOR.tools.extend(CKEDITOR.dialog,{add:function(a,b){this._.dialogDefinitions[a]&&\"function\"!=typeof b||(this._.dialogDefinitions[a]=b)},exists:function(a){return!!this._.dialogDefinitions[a]},getCurrent:function(){return CKEDITOR.dialog._.currentTop},isTabEnabled:function(a,b,c){a=a.config.removeDialogTabs;return!(a&&a.match(new RegExp(\"(?:^|;)\"+b+\":\"+c+\"(?:$|;)\",\n\"i\")))},okButton:function(){var a=function(a,b){b=b||{};return CKEDITOR.tools.extend({id:\"ok\",type:\"button\",label:a.lang.common.ok,\"class\":\"cke_dialog_ui_button_ok\",onClick:function(a){a=a.data.dialog;!1!==a.fire(\"ok\",{hide:!0}).hide&&a.hide()}},b,!0)};a.type=\"button\";a.override=function(b){return CKEDITOR.tools.extend(function(c){return a(c,b)},{type:\"button\"},!0)};return a}(),cancelButton:function(){var a=function(a,b){b=b||{};return CKEDITOR.tools.extend({id:\"cancel\",type:\"button\",label:a.lang.common.cancel,\n\"class\":\"cke_dialog_ui_button_cancel\",onClick:function(a){a=a.data.dialog;!1!==a.fire(\"cancel\",{hide:!0}).hide&&a.hide()}},b,!0)};a.type=\"button\";a.override=function(b){return CKEDITOR.tools.extend(function(c){return a(c,b)},{type:\"button\"},!0)};return a}(),addUIElement:function(a,b){this._.uiElementBuilders[a]=b}});CKEDITOR.dialog._={uiElementBuilders:{},dialogDefinitions:{},currentTop:null,currentZIndex:null};CKEDITOR.event.implementOn(CKEDITOR.dialog);CKEDITOR.event.implementOn(CKEDITOR.dialog.prototype);\nvar v={resizable:CKEDITOR.DIALOG_RESIZE_BOTH,minWidth:600,minHeight:400,buttons:[CKEDITOR.dialog.okButton,CKEDITOR.dialog.cancelButton]},w=function(a,b,c){for(var e=0,d;d=a[e];e++)if(d.id==b||c&&d[c]&&(d=w(d[c],b,c)))return d;return null},r=function(a,b,c,e,d){if(c){for(var g=0,f;f=a[g];g++){if(f.id==c)return a.splice(g,0,b),b;if(e&&f[e]&&(f=r(f[e],b,c,e,!0)))return f}if(d)return null}a.push(b);return b},z=function(a,b,c){for(var e=0,d;d=a[e];e++){if(d.id==b)return a.splice(e,1);if(c&&d[c]&&(d=z(d[c],\nb,c)))return d}return null},t=function(a,b){this.dialog=a;for(var c=b.contents,e=0,d;d=c[e];e++)c[e]=d&&new h(a,d);CKEDITOR.tools.extend(this,b)};t.prototype={getContents:function(a){return w(this.contents,a)},getButton:function(a){return w(this.buttons,a)},addContents:function(a,b){return r(this.contents,a,b)},addButton:function(a,b){return r(this.buttons,a,b)},removeContents:function(a){z(this.contents,a)},removeButton:function(a){z(this.buttons,a)}};h.prototype={get:function(a){return w(this.elements,\na,\"children\")},add:function(a,b){return r(this.elements,a,b,\"children\")},remove:function(a){z(this.elements,a,\"children\")}};var x,A={},B,C={},H=function(a){var b=a.data.$.ctrlKey||a.data.$.metaKey,c=a.data.$.altKey,e=a.data.$.shiftKey,d=String.fromCharCode(a.data.$.keyCode);(b=C[(b?\"CTRL+\":\"\")+(c?\"ALT+\":\"\")+(e?\"SHIFT+\":\"\")+d])&&b.length&&(b=b[b.length-1],b.keydown&&b.keydown.call(b.uiElement,b.dialog,b.key),a.data.preventDefault())},F=function(a){var b=a.data.$.ctrlKey||a.data.$.metaKey,c=a.data.$.altKey,\ne=a.data.$.shiftKey,d=String.fromCharCode(a.data.$.keyCode);(b=C[(b?\"CTRL+\":\"\")+(c?\"ALT+\":\"\")+(e?\"SHIFT+\":\"\")+d])&&b.length&&(b=b[b.length-1],b.keyup&&(b.keyup.call(b.uiElement,b.dialog,b.key),a.data.preventDefault()))},I=function(a,b,c,e,d){(C[c]||(C[c]=[])).push({uiElement:a,dialog:b,key:c,keyup:d||a.accessKeyUp,keydown:e||a.accessKeyDown})},J=function(a){for(var b in C){for(var c=C[b],e=c.length-1;0<=e;e--)c[e].dialog!=a&&c[e].uiElement!=a||c.splice(e,1);0===c.length&&delete C[b]}},E=function(a,\nb){a._.accessKeyMap[b]&&a.selectPage(a._.accessKeyMap[b])},L=function(){};(function(){CKEDITOR.ui.dialog={uiElement:function(a,b,c,e,d,g,f){if(!(4>arguments.length)){var h=(e.call?e(b):e)||\"div\",k=[\"\\x3c\",h,\" \"],l=(d&&d.call?d(b):d)||{},m=(g&&g.call?g(b):g)||{},n=(f&&f.call?f.call(this,a,b):f)||\"\",r=this.domId=m.id||CKEDITOR.tools.getNextId()+\"_uiElement\";b.requiredContent&&!a.getParentEditor().filter.check(b.requiredContent)&&(l.display=\"none\",this.notAllowed=!0);m.id=r;var q={};b.type&&(q[\"cke_dialog_ui_\"+\nb.type]=1);b.className&&(q[b.className]=1);b.disabled&&(q.cke_disabled=1);for(var t=m[\"class\"]&&m[\"class\"].split?m[\"class\"].split(\" \"):[],r=0;r<t.length;r++)t[r]&&(q[t[r]]=1);t=[];for(r in q)t.push(r);m[\"class\"]=t.join(\" \");b.title&&(m.title=b.title);q=(b.style||\"\").split(\";\");b.align&&(t=b.align,l[\"margin-left\"]=\"left\"==t?0:\"auto\",l[\"margin-right\"]=\"right\"==t?0:\"auto\");for(r in l)q.push(r+\":\"+l[r]);b.hidden&&q.push(\"display:none\");for(r=q.length-1;0<=r;r--)\"\"===q[r]&&q.splice(r,1);0<q.length&&(m.style=\n(m.style?m.style+\"; \":\"\")+q.join(\"; \"));for(r in m)k.push(r+'\\x3d\"'+CKEDITOR.tools.htmlEncode(m[r])+'\" ');k.push(\"\\x3e\",n,\"\\x3c/\",h,\"\\x3e\");c.push(k.join(\"\"));(this._||(this._={})).dialog=a;\"boolean\"==typeof b.isChanged&&(this.isChanged=function(){return b.isChanged});\"function\"==typeof b.isChanged&&(this.isChanged=b.isChanged);\"function\"==typeof b.setValue&&(this.setValue=CKEDITOR.tools.override(this.setValue,function(a){return function(c){a.call(this,b.setValue.call(this,c))}}));\"function\"==typeof b.getValue&&\n(this.getValue=CKEDITOR.tools.override(this.getValue,function(a){return function(){return b.getValue.call(this,a.call(this))}}));CKEDITOR.event.implementOn(this);this.registerEvents(b);this.accessKeyUp&&this.accessKeyDown&&b.accessKey&&I(this,a,\"CTRL+\"+b.accessKey);var v=this;a.on(\"load\",function(){var b=v.getInputElement();if(b){var c=v.type in{checkbox:1,ratio:1}&&CKEDITOR.env.ie&&8>CKEDITOR.env.version?\"cke_dialog_ui_focused\":\"\";b.on(\"focus\",function(){a._.tabBarMode=!1;a._.hasFocus=!0;v.fire(\"focus\");\nc&&this.addClass(c)});b.on(\"blur\",function(){v.fire(\"blur\");c&&this.removeClass(c)})}});CKEDITOR.tools.extend(this,b);this.keyboardFocusable&&(this.tabIndex=b.tabIndex||0,this.focusIndex=a._.focusList.push(this)-1,this.on(\"focus\",function(){a._.currentFocusIndex=v.focusIndex}))}},hbox:function(a,b,c,e,d){if(!(4>arguments.length)){this._||(this._={});var g=this._.children=b,f=d&&d.widths||null,h=d&&d.height||null,k,l={role:\"presentation\"};d&&d.align&&(l.align=d.align);CKEDITOR.ui.dialog.uiElement.call(this,\na,d||{type:\"hbox\"},e,\"table\",{},l,function(){var a=['\\x3ctbody\\x3e\\x3ctr class\\x3d\"cke_dialog_ui_hbox\"\\x3e'];for(k=0;k<c.length;k++){var b=\"cke_dialog_ui_hbox_child\",e=[];0===k&&(b=\"cke_dialog_ui_hbox_first\");k==c.length-1&&(b=\"cke_dialog_ui_hbox_last\");a.push('\\x3ctd class\\x3d\"',b,'\" role\\x3d\"presentation\" ');f?f[k]&&e.push(\"width:\"+u(f[k])):e.push(\"width:\"+Math.floor(100/c.length)+\"%\");h&&e.push(\"height:\"+u(h));d&&void 0!==d.padding&&e.push(\"padding:\"+u(d.padding));CKEDITOR.env.ie&&CKEDITOR.env.quirks&&\ng[k].align&&e.push(\"text-align:\"+g[k].align);0<e.length&&a.push('style\\x3d\"'+e.join(\"; \")+'\" ');a.push(\"\\x3e\",c[k],\"\\x3c/td\\x3e\")}a.push(\"\\x3c/tr\\x3e\\x3c/tbody\\x3e\");return a.join(\"\")})}},vbox:function(a,b,c,e,d){if(!(3>arguments.length)){this._||(this._={});var g=this._.children=b,f=d&&d.width||null,h=d&&d.heights||null;CKEDITOR.ui.dialog.uiElement.call(this,a,d||{type:\"vbox\"},e,\"div\",null,{role:\"presentation\"},function(){var b=['\\x3ctable role\\x3d\"presentation\" cellspacing\\x3d\"0\" border\\x3d\"0\" '];\nb.push('style\\x3d\"');d&&d.expand&&b.push(\"height:100%;\");b.push(\"width:\"+u(f||\"100%\"),\";\");CKEDITOR.env.webkit&&b.push(\"float:none;\");b.push('\"');b.push('align\\x3d\"',CKEDITOR.tools.htmlEncode(d&&d.align||(\"ltr\"==a.getParentEditor().lang.dir?\"left\":\"right\")),'\" ');b.push(\"\\x3e\\x3ctbody\\x3e\");for(var e=0;e<c.length;e++){var k=[];b.push('\\x3ctr\\x3e\\x3ctd role\\x3d\"presentation\" ');f&&k.push(\"width:\"+u(f||\"100%\"));h?k.push(\"height:\"+u(h[e])):d&&d.expand&&k.push(\"height:\"+Math.floor(100/c.length)+\"%\");\nd&&void 0!==d.padding&&k.push(\"padding:\"+u(d.padding));CKEDITOR.env.ie&&CKEDITOR.env.quirks&&g[e].align&&k.push(\"text-align:\"+g[e].align);0<k.length&&b.push('style\\x3d\"',k.join(\"; \"),'\" ');b.push(' class\\x3d\"cke_dialog_ui_vbox_child\"\\x3e',c[e],\"\\x3c/td\\x3e\\x3c/tr\\x3e\")}b.push(\"\\x3c/tbody\\x3e\\x3c/table\\x3e\");return b.join(\"\")})}}}})();CKEDITOR.ui.dialog.uiElement.prototype={getElement:function(){return CKEDITOR.document.getById(this.domId)},getInputElement:function(){return this.getElement()},getDialog:function(){return this._.dialog},\nsetValue:function(a,b){this.getInputElement().setValue(a);!b&&this.fire(\"change\",{value:a});return this},getValue:function(){return this.getInputElement().getValue()},isChanged:function(){return!1},selectParentTab:function(){for(var a=this.getInputElement();(a=a.getParent())&&-1==a.$.className.search(\"cke_dialog_page_contents\"););if(!a)return this;a=a.getAttribute(\"name\");this._.dialog._.currentTabId!=a&&this._.dialog.selectPage(a);return this},focus:function(){this.selectParentTab().getInputElement().focus();\nreturn this},registerEvents:function(a){var b=/^on([A-Z]\\w+)/,c,e=function(a,b,c,e){b.on(\"load\",function(){a.getInputElement().on(c,e,a)})},d;for(d in a)if(c=d.match(b))this.eventProcessors[d]?this.eventProcessors[d].call(this,this._.dialog,a[d]):e(this,this._.dialog,c[1].toLowerCase(),a[d]);return this},eventProcessors:{onLoad:function(a,b){a.on(\"load\",b,this)},onShow:function(a,b){a.on(\"show\",b,this)},onHide:function(a,b){a.on(\"hide\",b,this)}},accessKeyDown:function(){this.focus()},accessKeyUp:function(){},\ndisable:function(){var a=this.getElement();this.getInputElement().setAttribute(\"disabled\",\"true\");a.addClass(\"cke_disabled\")},enable:function(){var a=this.getElement();this.getInputElement().removeAttribute(\"disabled\");a.removeClass(\"cke_disabled\")},isEnabled:function(){return!this.getElement().hasClass(\"cke_disabled\")},isVisible:function(){return this.getInputElement().isVisible()},isFocusable:function(){return this.isEnabled()&&this.isVisible()?!0:!1}};CKEDITOR.ui.dialog.hbox.prototype=CKEDITOR.tools.extend(new CKEDITOR.ui.dialog.uiElement,\n{getChild:function(a){if(1>arguments.length)return this._.children.concat();a.splice||(a=[a]);return 2>a.length?this._.children[a[0]]:this._.children[a[0]]&&this._.children[a[0]].getChild?this._.children[a[0]].getChild(a.slice(1,a.length)):null}},!0);CKEDITOR.ui.dialog.vbox.prototype=new CKEDITOR.ui.dialog.hbox;(function(){var a={build:function(a,b,c){for(var e=b.children,d,g=[],f=[],h=0;h<e.length&&(d=e[h]);h++){var k=[];g.push(k);f.push(CKEDITOR.dialog._.uiElementBuilders[d.type].build(a,d,k))}return new CKEDITOR.ui.dialog[b.type](a,\nf,g,c,b)}};CKEDITOR.dialog.addUIElement(\"hbox\",a);CKEDITOR.dialog.addUIElement(\"vbox\",a)})();CKEDITOR.dialogCommand=function(a,b){this.dialogName=a;CKEDITOR.tools.extend(this,b,!0)};CKEDITOR.dialogCommand.prototype={exec:function(a){var b=this.tabId;a.openDialog(this.dialogName,function(a){b&&a.selectPage(b)})},canUndo:!1,editorFocus:1};(function(){var a=/^([a]|[^a])+$/,b=/^\\d*$/,c=/^\\d*(?:\\.\\d+)?$/,e=/^(((\\d*(\\.\\d+))|(\\d*))(px|\\%)?)?$/,d=/^(((\\d*(\\.\\d+))|(\\d*))(px|em|ex|in|cm|mm|pt|pc|\\%)?)?$/i,\ng=/^(\\s*[\\w-]+\\s*:\\s*[^:;]+(?:;|$))*$/;CKEDITOR.VALIDATE_OR=1;CKEDITOR.VALIDATE_AND=2;CKEDITOR.dialog.validate={functions:function(){var a=arguments;return function(){var b=this&&this.getValue?this.getValue():a[0],c,e=CKEDITOR.VALIDATE_AND,d=[],g;for(g=0;g<a.length;g++)if(\"function\"==typeof a[g])d.push(a[g]);else break;g<a.length&&\"string\"==typeof a[g]&&(c=a[g],g++);g<a.length&&\"number\"==typeof a[g]&&(e=a[g]);var f=e==CKEDITOR.VALIDATE_AND?!0:!1;for(g=0;g<d.length;g++)f=e==CKEDITOR.VALIDATE_AND?f&&\nd[g](b):f||d[g](b);return f?!0:c}},regex:function(a,b){return function(c){c=this&&this.getValue?this.getValue():c;return a.test(c)?!0:b}},notEmpty:function(b){return this.regex(a,b)},integer:function(a){return this.regex(b,a)},number:function(a){return this.regex(c,a)},cssLength:function(a){return this.functions(function(a){return d.test(CKEDITOR.tools.trim(a))},a)},htmlLength:function(a){return this.functions(function(a){return e.test(CKEDITOR.tools.trim(a))},a)},inlineStyle:function(a){return this.functions(function(a){return g.test(CKEDITOR.tools.trim(a))},\na)},equals:function(a,b){return this.functions(function(b){return b==a},b)},notEqual:function(a,b){return this.functions(function(b){return b!=a},b)}};CKEDITOR.on(\"instanceDestroyed\",function(a){if(CKEDITOR.tools.isEmpty(CKEDITOR.instances)){for(var b;b=CKEDITOR.dialog._.currentTop;)b.hide();for(var c in A)A[c].remove();A={}}a=a.editor._.storedDialogs;for(var e in a)a[e].destroy()})})();CKEDITOR.tools.extend(CKEDITOR.editor.prototype,{openDialog:function(a,b){var c=null,e=CKEDITOR.dialog._.dialogDefinitions[a];\nnull===CKEDITOR.dialog._.currentTop&&q(this);if(\"function\"==typeof e)c=this._.storedDialogs||(this._.storedDialogs={}),c=c[a]||(c[a]=new CKEDITOR.dialog(this,a)),b&&b.call(c,c),c.show();else{if(\"failed\"==e)throw y(this),Error('[CKEDITOR.dialog.openDialog] Dialog \"'+a+'\" failed when loading definition.');\"string\"==typeof e&&CKEDITOR.scriptLoader.load(CKEDITOR.getUrl(e),function(){\"function\"!=typeof CKEDITOR.dialog._.dialogDefinitions[a]&&(CKEDITOR.dialog._.dialogDefinitions[a]=\"failed\");this.openDialog(a,\nb)},this,0,1)}CKEDITOR.skin.loadPart(\"dialog\");return c}})}(),CKEDITOR.plugins.add(\"dialog\",{requires:\"dialogui\",init:function(a){a.on(\"doubleclick\",function(f){f.data.dialog&&a.openDialog(f.data.dialog)},null,null,999)}}),function(){CKEDITOR.plugins.add(\"a11yhelp\",{requires:\"dialog\",availableLangs:{af:1,ar:1,az:1,bg:1,ca:1,cs:1,cy:1,da:1,de:1,\"de-ch\":1,el:1,en:1,\"en-au\":1,\"en-gb\":1,eo:1,es:1,\"es-mx\":1,et:1,eu:1,fa:1,fi:1,fo:1,fr:1,\"fr-ca\":1,gl:1,gu:1,he:1,hi:1,hr:1,hu:1,id:1,it:1,ja:1,km:1,ko:1,\nku:1,lt:1,lv:1,mk:1,mn:1,nb:1,nl:1,no:1,oc:1,pl:1,pt:1,\"pt-br\":1,ro:1,ru:1,si:1,sk:1,sl:1,sq:1,sr:1,\"sr-latn\":1,sv:1,th:1,tr:1,tt:1,ug:1,uk:1,vi:1,zh:1,\"zh-cn\":1},init:function(a){var f=this;a.addCommand(\"a11yHelp\",{exec:function(){var b=a.langCode,b=f.availableLangs[b]?b:f.availableLangs[b.replace(/-.*/,\"\")]?b.replace(/-.*/,\"\"):\"en\";CKEDITOR.scriptLoader.load(CKEDITOR.getUrl(f.path+\"dialogs/lang/\"+b+\".js\"),function(){a.lang.a11yhelp=f.langEntries[b];a.openDialog(\"a11yHelp\")})},modes:{wysiwyg:1,source:1},\nreadOnly:1,canUndo:!1});a.setKeystroke(CKEDITOR.ALT+48,\"a11yHelp\");CKEDITOR.dialog.add(\"a11yHelp\",this.path+\"dialogs/a11yhelp.js\");a.on(\"ariaEditorHelpLabel\",function(b){b.data.label=a.lang.common.editorHelp})}})}(),CKEDITOR.plugins.add(\"about\",{requires:\"dialog\",init:function(a){var f=a.addCommand(\"about\",new CKEDITOR.dialogCommand(\"about\"));f.modes={wysiwyg:1,source:1};f.canUndo=!1;f.readOnly=1;a.ui.addButton&&a.ui.addButton(\"About\",{label:a.lang.about.dlgTitle,command:\"about\",toolbar:\"about\"});\nCKEDITOR.dialog.add(\"about\",this.path+\"dialogs/about.js\")}}),CKEDITOR.plugins.add(\"basicstyles\",{init:function(a){var f=0,b=function(b,d,h,l){if(l){l=new CKEDITOR.style(l);var e=c[h];e.unshift(l);a.attachStyleStateChange(l,function(b){!a.readOnly&&a.getCommand(h).setState(b)});a.addCommand(h,new CKEDITOR.styleCommand(l,{contentForms:e}));a.ui.addButton&&a.ui.addButton(b,{label:d,command:h,toolbar:\"basicstyles,\"+(f+=10)})}},c={bold:[\"strong\",\"b\",[\"span\",function(a){a=a.styles[\"font-weight\"];return\"bold\"==\na||700<=+a}]],italic:[\"em\",\"i\",[\"span\",function(a){return\"italic\"==a.styles[\"font-style\"]}]],underline:[\"u\",[\"span\",function(a){return\"underline\"==a.styles[\"text-decoration\"]}]],strike:[\"s\",\"strike\",[\"span\",function(a){return\"line-through\"==a.styles[\"text-decoration\"]}]],subscript:[\"sub\"],superscript:[\"sup\"]},d=a.config,l=a.lang.basicstyles;b(\"Bold\",l.bold,\"bold\",d.coreStyles_bold);b(\"Italic\",l.italic,\"italic\",d.coreStyles_italic);b(\"Underline\",l.underline,\"underline\",d.coreStyles_underline);b(\"Strike\",\nl.strike,\"strike\",d.coreStyles_strike);b(\"Subscript\",l.subscript,\"subscript\",d.coreStyles_subscript);b(\"Superscript\",l.superscript,\"superscript\",d.coreStyles_superscript);a.setKeystroke([[CKEDITOR.CTRL+66,\"bold\"],[CKEDITOR.CTRL+73,\"italic\"],[CKEDITOR.CTRL+85,\"underline\"]])}}),CKEDITOR.config.coreStyles_bold={element:\"strong\",overrides:\"b\"},CKEDITOR.config.coreStyles_italic={element:\"em\",overrides:\"i\"},CKEDITOR.config.coreStyles_underline={element:\"u\"},CKEDITOR.config.coreStyles_strike={element:\"s\",\noverrides:\"strike\"},CKEDITOR.config.coreStyles_subscript={element:\"sub\"},CKEDITOR.config.coreStyles_superscript={element:\"sup\"},function(){var a={exec:function(a){var b=a.getCommand(\"blockquote\").state,c=a.getSelection(),d=c&&c.getRanges()[0];if(d){var l=c.createBookmarks();if(CKEDITOR.env.ie){var k=l[0].startNode,g=l[0].endNode,h;if(k&&\"blockquote\"==k.getParent().getName())for(h=k;h=h.getNext();)if(h.type==CKEDITOR.NODE_ELEMENT&&h.isBlockBoundary()){k.move(h,!0);break}if(g&&\"blockquote\"==g.getParent().getName())for(h=\ng;h=h.getPrevious();)if(h.type==CKEDITOR.NODE_ELEMENT&&h.isBlockBoundary()){g.move(h);break}}var m=d.createIterator();m.enlargeBr=a.config.enterMode!=CKEDITOR.ENTER_BR;if(b==CKEDITOR.TRISTATE_OFF){for(k=[];b=m.getNextParagraph();)k.push(b);1>k.length&&(b=a.document.createElement(a.config.enterMode==CKEDITOR.ENTER_P?\"p\":\"div\"),g=l.shift(),d.insertNode(b),b.append(new CKEDITOR.dom.text(\"﻿\",a.document)),d.moveToBookmark(g),d.selectNodeContents(b),d.collapse(!0),g=d.createBookmark(),k.push(b),l.unshift(g));\nh=k[0].getParent();d=[];for(g=0;g<k.length;g++)b=k[g],h=h.getCommonAncestor(b.getParent());for(b={table:1,tbody:1,tr:1,ol:1,ul:1};b[h.getName()];)h=h.getParent();for(g=null;0<k.length;){for(b=k.shift();!b.getParent().equals(h);)b=b.getParent();b.equals(g)||d.push(b);g=b}for(;0<d.length;)if(b=d.shift(),\"blockquote\"==b.getName()){for(g=new CKEDITOR.dom.documentFragment(a.document);b.getFirst();)g.append(b.getFirst().remove()),k.push(g.getLast());g.replace(b)}else k.push(b);d=a.document.createElement(\"blockquote\");\nfor(d.insertBefore(k[0]);0<k.length;)b=k.shift(),d.append(b)}else if(b==CKEDITOR.TRISTATE_ON){g=[];for(h={};b=m.getNextParagraph();){for(k=d=null;b.getParent();){if(\"blockquote\"==b.getParent().getName()){d=b.getParent();k=b;break}b=b.getParent()}d&&k&&!k.getCustomData(\"blockquote_moveout\")&&(g.push(k),CKEDITOR.dom.element.setMarker(h,k,\"blockquote_moveout\",!0))}CKEDITOR.dom.element.clearAllMarkers(h);b=[];k=[];for(h={};0<g.length;)m=g.shift(),d=m.getParent(),m.getPrevious()?m.getNext()?(m.breakParent(m.getParent()),\nk.push(m.getNext())):m.remove().insertAfter(d):m.remove().insertBefore(d),d.getCustomData(\"blockquote_processed\")||(k.push(d),CKEDITOR.dom.element.setMarker(h,d,\"blockquote_processed\",!0)),b.push(m);CKEDITOR.dom.element.clearAllMarkers(h);for(g=k.length-1;0<=g;g--){d=k[g];a:{h=d;for(var m=0,e=h.getChildCount(),n=void 0;m<e&&(n=h.getChild(m));m++)if(n.type==CKEDITOR.NODE_ELEMENT&&n.isBlockBoundary()){h=!1;break a}h=!0}h&&d.remove()}if(a.config.enterMode==CKEDITOR.ENTER_BR)for(d=!0;b.length;)if(m=b.shift(),\n\"div\"==m.getName()){g=new CKEDITOR.dom.documentFragment(a.document);!d||!m.getPrevious()||m.getPrevious().type==CKEDITOR.NODE_ELEMENT&&m.getPrevious().isBlockBoundary()||g.append(a.document.createElement(\"br\"));for(d=m.getNext()&&!(m.getNext().type==CKEDITOR.NODE_ELEMENT&&m.getNext().isBlockBoundary());m.getFirst();)m.getFirst().remove().appendTo(g);d&&g.append(a.document.createElement(\"br\"));g.replace(m);d=!1}}c.selectBookmarks(l);a.focus()}},refresh:function(a,b){this.setState(a.elementPath(b.block||\nb.blockLimit).contains(\"blockquote\",1)?CKEDITOR.TRISTATE_ON:CKEDITOR.TRISTATE_OFF)},context:\"blockquote\",allowedContent:\"blockquote\",requiredContent:\"blockquote\"};CKEDITOR.plugins.add(\"blockquote\",{init:function(f){f.blockless||(f.addCommand(\"blockquote\",a),f.ui.addButton&&f.ui.addButton(\"Blockquote\",{label:f.lang.blockquote.toolbar,command:\"blockquote\",toolbar:\"blocks,10\"}))}})}(),\"use strict\",function(){function a(a,c){CKEDITOR.tools.extend(this,c,{editor:a,id:\"cke-\"+CKEDITOR.tools.getUniqueId(),\narea:a._.notificationArea});c.type||(this.type=\"info\");this.element=this._createElement();a.plugins.clipboard&&CKEDITOR.plugins.clipboard.preventDefaultDropOnElement(this.element)}function f(a){var c=this;this.editor=a;this.notifications=[];this.element=this._createElement();this._uiBuffer=CKEDITOR.tools.eventsBuffer(10,this._layout,this);this._changeBuffer=CKEDITOR.tools.eventsBuffer(500,this._layout,this);a.on(\"destroy\",function(){c._removeListeners();c.element.remove()})}CKEDITOR.plugins.add(\"notification\",\n{init:function(a){function c(a){var b=new CKEDITOR.dom.element(\"div\");b.setStyles({position:\"fixed\",\"margin-left\":\"-9999px\"});b.setAttributes({\"aria-live\":\"assertive\",\"aria-atomic\":\"true\"});b.setText(a);CKEDITOR.document.getBody().append(b);setTimeout(function(){b.remove()},100)}a._.notificationArea=new f(a);a.showNotification=function(c,f,k){var g,h;\"progress\"==f?g=k:h=k;c=new CKEDITOR.plugins.notification(a,{message:c,type:f,progress:g,duration:h});c.show();return c};a.on(\"key\",function(d){if(27==\nd.data.keyCode){var f=a._.notificationArea.notifications;f.length&&(c(a.lang.notification.closed),f[f.length-1].hide(),d.cancel())}})}});a.prototype={show:function(){!1!==this.editor.fire(\"notificationShow\",{notification:this})&&(this.area.add(this),this._hideAfterTimeout())},update:function(a){var c=!0;!1===this.editor.fire(\"notificationUpdate\",{notification:this,options:a})&&(c=!1);var d=this.element,f=d.findOne(\".cke_notification_message\"),k=d.findOne(\".cke_notification_progress\"),g=a.type;d.removeAttribute(\"role\");\na.progress&&\"progress\"!=this.type&&(g=\"progress\");g&&(d.removeClass(this._getClass()),d.removeAttribute(\"aria-label\"),this.type=g,d.addClass(this._getClass()),d.setAttribute(\"aria-label\",this.type),\"progress\"!=this.type||k?\"progress\"!=this.type&&k&&k.remove():(k=this._createProgressElement(),k.insertBefore(f)));void 0!==a.message&&(this.message=a.message,f.setHtml(this.message));void 0!==a.progress&&(this.progress=a.progress,k&&k.setStyle(\"width\",this._getPercentageProgress()));c&&a.important&&(d.setAttribute(\"role\",\n\"alert\"),this.isVisible()||this.area.add(this));this.duration=a.duration;this._hideAfterTimeout()},hide:function(){!1!==this.editor.fire(\"notificationHide\",{notification:this})&&this.area.remove(this)},isVisible:function(){return 0<=CKEDITOR.tools.indexOf(this.area.notifications,this)},_createElement:function(){var a=this,c,d,f=this.editor.lang.common.close;c=new CKEDITOR.dom.element(\"div\");c.addClass(\"cke_notification\");c.addClass(this._getClass());c.setAttributes({id:this.id,role:\"alert\",\"aria-label\":this.type});\n\"progress\"==this.type&&c.append(this._createProgressElement());d=new CKEDITOR.dom.element(\"p\");d.addClass(\"cke_notification_message\");d.setHtml(this.message);c.append(d);d=CKEDITOR.dom.element.createFromHtml('\\x3ca class\\x3d\"cke_notification_close\" href\\x3d\"javascript:void(0)\" title\\x3d\"'+f+'\" role\\x3d\"button\" tabindex\\x3d\"-1\"\\x3e\\x3cspan class\\x3d\"cke_label\"\\x3eX\\x3c/span\\x3e\\x3c/a\\x3e');c.append(d);d.on(\"click\",function(){a.editor.focus();a.hide()});return c},_getClass:function(){return\"progress\"==\nthis.type?\"cke_notification_info\":\"cke_notification_\"+this.type},_createProgressElement:function(){var a=new CKEDITOR.dom.element(\"span\");a.addClass(\"cke_notification_progress\");a.setStyle(\"width\",this._getPercentageProgress());return a},_getPercentageProgress:function(){return Math.round(100*(this.progress||0))+\"%\"},_hideAfterTimeout:function(){var a=this,c;this._hideTimeoutId&&clearTimeout(this._hideTimeoutId);if(\"number\"==typeof this.duration)c=this.duration;else if(\"info\"==this.type||\"success\"==\nthis.type)c=\"number\"==typeof this.editor.config.notification_duration?this.editor.config.notification_duration:5E3;c&&(a._hideTimeoutId=setTimeout(function(){a.hide()},c))}};f.prototype={add:function(a){this.notifications.push(a);this.element.append(a.element);1==this.element.getChildCount()&&(CKEDITOR.document.getBody().append(this.element),this._attachListeners());this._layout()},remove:function(a){var c=CKEDITOR.tools.indexOf(this.notifications,a);0>c||(this.notifications.splice(c,1),a.element.remove(),\nthis.element.getChildCount()||(this._removeListeners(),this.element.remove()))},_createElement:function(){var a=this.editor,c=a.config,d=new CKEDITOR.dom.element(\"div\");d.addClass(\"cke_notifications_area\");d.setAttribute(\"id\",\"cke_notifications_area_\"+a.name);d.setStyle(\"z-index\",c.baseFloatZIndex-2);return d},_attachListeners:function(){var a=CKEDITOR.document.getWindow(),c=this.editor;a.on(\"scroll\",this._uiBuffer.input);a.on(\"resize\",this._uiBuffer.input);c.on(\"change\",this._changeBuffer.input);\nc.on(\"floatingSpaceLayout\",this._layout,this,null,20);c.on(\"blur\",this._layout,this,null,20)},_removeListeners:function(){var a=CKEDITOR.document.getWindow(),c=this.editor;a.removeListener(\"scroll\",this._uiBuffer.input);a.removeListener(\"resize\",this._uiBuffer.input);c.removeListener(\"change\",this._changeBuffer.input);c.removeListener(\"floatingSpaceLayout\",this._layout);c.removeListener(\"blur\",this._layout)},_layout:function(){function a(){c.setStyle(\"left\",w(r+f.width-n-q))}var c=this.element,d=\nthis.editor,f=d.ui.contentsElement.getClientRect(),k=d.ui.contentsElement.getDocumentPosition(),g,h,m=c.getClientRect(),e,n=this._notificationWidth,q=this._notificationMargin;e=CKEDITOR.document.getWindow();var y=e.getScrollPosition(),u=e.getViewPaneSize(),p=CKEDITOR.document.getBody(),v=p.getDocumentPosition(),w=CKEDITOR.tools.cssLength;n&&q||(e=this.element.getChild(0),n=this._notificationWidth=e.getClientRect().width,q=this._notificationMargin=parseInt(e.getComputedStyle(\"margin-left\"),10)+parseInt(e.getComputedStyle(\"margin-right\"),\n10));d.toolbar&&(g=d.ui.space(\"top\"),h=g.getClientRect());g&&g.isVisible()&&h.bottom>f.top&&h.bottom<f.bottom-m.height?c.setStyles({position:\"fixed\",top:w(h.bottom)}):0<f.top?c.setStyles({position:\"absolute\",top:w(k.y)}):k.y+f.height-m.height>y.y?c.setStyles({position:\"fixed\",top:0}):c.setStyles({position:\"absolute\",top:w(k.y+f.height-m.height)});var r=\"fixed\"==c.getStyle(\"position\")?f.left:\"static\"!=p.getComputedStyle(\"position\")?k.x-v.x:k.x;f.width<n+q?k.x+n+q>y.x+u.width?a():c.setStyle(\"left\",\nw(r)):k.x+n+q>y.x+u.width?c.setStyle(\"left\",w(r)):k.x+f.width/2+n/2+q>y.x+u.width?c.setStyle(\"left\",w(r-k.x+y.x+u.width-n-q)):0>f.left+f.width-n-q?a():0>f.left+f.width/2-n/2?c.setStyle(\"left\",w(r-k.x+y.x)):c.setStyle(\"left\",w(r+f.width/2-n/2-q/2))}};CKEDITOR.plugins.notification=a}(),function(){var a='\\x3ca id\\x3d\"{id}\" class\\x3d\"cke_button cke_button__{name} cke_button_{state} {cls}\"'+(CKEDITOR.env.gecko&&!CKEDITOR.env.hc?\"\":\" href\\x3d\\\"javascript:void('{titleJs}')\\\"\")+' title\\x3d\"{title}\" tabindex\\x3d\"-1\" hidefocus\\x3d\"true\" role\\x3d\"button\" aria-labelledby\\x3d\"{id}_label\" aria-describedby\\x3d\"{id}_description\" aria-haspopup\\x3d\"{hasArrow}\" aria-disabled\\x3d\"{ariaDisabled}\"';\nCKEDITOR.env.gecko&&CKEDITOR.env.mac&&(a+=' onkeypress\\x3d\"return false;\"');CKEDITOR.env.gecko&&(a+=' onblur\\x3d\"this.style.cssText \\x3d this.style.cssText;\"');var f=\"\";CKEDITOR.env.ie&&(f='return false;\" onmouseup\\x3d\"CKEDITOR.tools.getMouseButton(event)\\x3d\\x3dCKEDITOR.MOUSE_BUTTON_LEFT\\x26\\x26');var a=a+(' onkeydown\\x3d\"return CKEDITOR.tools.callFunction({keydownFn},event);\" onfocus\\x3d\"return CKEDITOR.tools.callFunction({focusFn},event);\" onclick\\x3d\"'+f+'CKEDITOR.tools.callFunction({clickFn},this);return false;\"\\x3e\\x3cspan class\\x3d\"cke_button_icon cke_button__{iconName}_icon\" style\\x3d\"{style}\"')+\n'\\x3e\\x26nbsp;\\x3c/span\\x3e\\x3cspan id\\x3d\"{id}_label\" class\\x3d\"cke_button_label cke_button__{name}_label\" aria-hidden\\x3d\"false\"\\x3e{label}\\x3c/span\\x3e\\x3cspan id\\x3d\"{id}_description\" class\\x3d\"cke_button_label\" aria-hidden\\x3d\"false\"\\x3e{ariaShortcut}\\x3c/span\\x3e{arrowHtml}\\x3c/a\\x3e',b=CKEDITOR.addTemplate(\"buttonArrow\",'\\x3cspan class\\x3d\"cke_button_arrow\"\\x3e'+(CKEDITOR.env.hc?\"\\x26#9660;\":\"\")+\"\\x3c/span\\x3e\"),c=CKEDITOR.addTemplate(\"button\",a);CKEDITOR.plugins.add(\"button\",{beforeInit:function(a){a.ui.addHandler(CKEDITOR.UI_BUTTON,\nCKEDITOR.ui.button.handler)}});CKEDITOR.UI_BUTTON=\"button\";CKEDITOR.ui.button=function(a){CKEDITOR.tools.extend(this,a,{title:a.label,click:a.click||function(b){b.execCommand(a.command)}});this._={}};CKEDITOR.ui.button.handler={create:function(a){return new CKEDITOR.ui.button(a)}};CKEDITOR.ui.button.prototype={render:function(a,f){function k(){var b=a.mode;b&&(b=this.modes[b]?void 0!==g[b]?g[b]:CKEDITOR.TRISTATE_OFF:CKEDITOR.TRISTATE_DISABLED,b=a.readOnly&&!this.readOnly?CKEDITOR.TRISTATE_DISABLED:\nb,this.setState(b),this.refresh&&this.refresh())}var g=null,h=CKEDITOR.env,m=this._.id=CKEDITOR.tools.getNextId(),e=\"\",n=this.command,q,y,u;this._.editor=a;var p={id:m,button:this,editor:a,focus:function(){CKEDITOR.document.getById(m).focus()},execute:function(){this.button.click(a)},attach:function(a){this.button.attach(a)}},v=CKEDITOR.tools.addFunction(function(a){if(p.onkey)return a=new CKEDITOR.dom.event(a),!1!==p.onkey(p,a.getKeystroke())}),w=CKEDITOR.tools.addFunction(function(a){var b;p.onfocus&&\n(b=!1!==p.onfocus(p,new CKEDITOR.dom.event(a)));return b}),r=0;p.clickFn=q=CKEDITOR.tools.addFunction(function(){r&&(a.unlockSelection(1),r=0);p.execute();h.iOS&&a.focus()});this.modes?(g={},a.on(\"beforeModeUnload\",function(){a.mode&&this._.state!=CKEDITOR.TRISTATE_DISABLED&&(g[a.mode]=this._.state)},this),a.on(\"activeFilterChange\",k,this),a.on(\"mode\",k,this),!this.readOnly&&a.on(\"readOnly\",k,this)):n&&(n=a.getCommand(n))&&(n.on(\"state\",function(){this.setState(n.state)},this),e+=n.state==CKEDITOR.TRISTATE_ON?\n\"on\":n.state==CKEDITOR.TRISTATE_DISABLED?\"disabled\":\"off\");var z;if(this.directional)a.on(\"contentDirChanged\",function(b){var c=CKEDITOR.document.getById(this._.id),e=c.getFirst();b=b.data;b!=a.lang.dir?c.addClass(\"cke_\"+b):c.removeClass(\"cke_ltr\").removeClass(\"cke_rtl\");e.setAttribute(\"style\",CKEDITOR.skin.getIconStyle(z,\"rtl\"==b,this.icon,this.iconOffset))},this);n?(y=a.getCommandKeystroke(n))&&(u=CKEDITOR.tools.keystrokeToString(a.lang.common.keyboard,y)):e+=\"off\";y=this.name||this.command;var t=\nnull,x=this.icon;z=y;this.icon&&!/\\./.test(this.icon)?(z=this.icon,x=null):(this.icon&&(t=this.icon),CKEDITOR.env.hidpi&&this.iconHiDpi&&(t=this.iconHiDpi));t?(CKEDITOR.skin.addIcon(t,t),x=null):t=z;e={id:m,name:y,iconName:z,label:this.label,cls:(this.hasArrow?\"cke_button_expandable \":\"\")+(this.className||\"\"),state:e,ariaDisabled:\"disabled\"==e?\"true\":\"false\",title:this.title+(u?\" (\"+u.display+\")\":\"\"),ariaShortcut:u?a.lang.common.keyboardShortcut+\" \"+u.aria:\"\",titleJs:h.gecko&&!h.hc?\"\":(this.title||\n\"\").replace(\"'\",\"\"),hasArrow:\"string\"===typeof this.hasArrow&&this.hasArrow||(this.hasArrow?\"true\":\"false\"),keydownFn:v,focusFn:w,clickFn:q,style:CKEDITOR.skin.getIconStyle(t,\"rtl\"==a.lang.dir,x,this.iconOffset),arrowHtml:this.hasArrow?b.output():\"\"};c.output(e,f);if(this.onRender)this.onRender();return p},setState:function(a){if(this._.state==a)return!1;this._.state=a;var b=CKEDITOR.document.getById(this._.id);return b?(b.setState(a,\"cke_button\"),b.setAttribute(\"aria-disabled\",a==CKEDITOR.TRISTATE_DISABLED),\nthis.hasArrow?b.setAttribute(\"aria-expanded\",a==CKEDITOR.TRISTATE_ON):a===CKEDITOR.TRISTATE_ON?b.setAttribute(\"aria-pressed\",!0):b.removeAttribute(\"aria-pressed\"),!0):!1},getState:function(){return this._.state},toFeature:function(a){if(this._.feature)return this._.feature;var b=this;this.allowedContent||this.requiredContent||!this.command||(b=a.getCommand(this.command)||b);return this._.feature=b}};CKEDITOR.ui.prototype.addButton=function(a,b){this.add(a,CKEDITOR.UI_BUTTON,b)}}(),function(){function a(a){function b(){for(var e=\nc(),h=CKEDITOR.tools.clone(a.config.toolbarGroups)||f(a),m=0;m<h.length;m++){var l=h[m];if(\"/\"!=l){\"string\"==typeof l&&(l=h[m]={name:l});var p,v=l.groups;if(v)for(var w=0;w<v.length;w++)p=v[w],(p=e[p])&&g(l,p);(p=e[l.name])&&g(l,p)}}return h}function c(){var b={},e,g,f;for(e in a.ui.items)g=a.ui.items[e],f=g.toolbar||\"others\",f=f.split(\",\"),g=f[0],f=parseInt(f[1]||-1,10),b[g]||(b[g]=[]),b[g].push({name:e,order:f});for(g in b)b[g]=b[g].sort(function(a,b){return a.order==b.order?0:0>b.order?-1:0>a.order?\n1:a.order<b.order?-1:1});return b}function g(b,c){if(c.length){b.items?b.items.push(a.ui.create(\"-\")):b.items=[];for(var e;e=c.shift();)e=\"string\"==typeof e?e:e.name,m&&-1!=CKEDITOR.tools.indexOf(m,e)||(e=a.ui.create(e))&&a.addFeature(e)&&b.items.push(e)}}function h(a){var b=[],c,e,d;for(c=0;c<a.length;++c)e=a[c],d={},\"/\"==e?b.push(e):CKEDITOR.tools.isArray(e)?(g(d,CKEDITOR.tools.clone(e)),b.push(d)):e.items&&(g(d,CKEDITOR.tools.clone(e.items)),d.name=e.name,b.push(d));return b}var m=a.config.removeButtons,\nm=m&&m.split(\",\"),e=a.config.toolbar;\"string\"==typeof e&&(e=a.config[\"toolbar_\"+e]);return a.toolbar=e?h(e):b()}function f(a){return a._.toolbarGroups||(a._.toolbarGroups=[{name:\"document\",groups:[\"mode\",\"document\",\"doctools\"]},{name:\"clipboard\",groups:[\"clipboard\",\"undo\"]},{name:\"editing\",groups:[\"find\",\"selection\",\"spellchecker\"]},{name:\"forms\"},\"/\",{name:\"basicstyles\",groups:[\"basicstyles\",\"cleanup\"]},{name:\"paragraph\",groups:[\"list\",\"indent\",\"blocks\",\"align\",\"bidi\"]},{name:\"links\"},{name:\"insert\"},\n\"/\",{name:\"styles\"},{name:\"colors\"},{name:\"tools\"},{name:\"others\"},{name:\"about\"}])}var b=function(){this.toolbars=[];this.focusCommandExecuted=!1};b.prototype.focus=function(){for(var a=0,b;b=this.toolbars[a++];)for(var c=0,g;g=b.items[c++];)if(g.focus){g.focus();return}};var c={modes:{wysiwyg:1,source:1},readOnly:1,exec:function(a){a.toolbox&&(a.toolbox.focusCommandExecuted=!0,CKEDITOR.env.ie||CKEDITOR.env.air?setTimeout(function(){a.toolbox.focus()},100):a.toolbox.focus())}};CKEDITOR.plugins.add(\"toolbar\",\n{requires:\"button\",init:function(d){var f,k=function(a,b){var c,e=\"rtl\"==d.lang.dir,n=d.config.toolbarGroupCycling,q=e?37:39,e=e?39:37,n=void 0===n||n;switch(b){case 9:case CKEDITOR.SHIFT+9:for(;!c||!c.items.length;)if(c=9==b?(c?c.next:a.toolbar.next)||d.toolbox.toolbars[0]:(c?c.previous:a.toolbar.previous)||d.toolbox.toolbars[d.toolbox.toolbars.length-1],c.items.length)for(a=c.items[f?c.items.length-1:0];a&&!a.focus;)(a=f?a.previous:a.next)||(c=0);a&&a.focus();return!1;case q:c=a;do c=c.next,!c&&\nn&&(c=a.toolbar.items[0]);while(c&&!c.focus);c?c.focus():k(a,9);return!1;case 40:return a.button&&a.button.hasArrow?a.execute():k(a,40==b?q:e),!1;case e:case 38:c=a;do c=c.previous,!c&&n&&(c=a.toolbar.items[a.toolbar.items.length-1]);while(c&&!c.focus);c?c.focus():(f=1,k(a,CKEDITOR.SHIFT+9),f=0);return!1;case 27:return d.focus(),!1;case 13:case 32:return a.execute(),!1}return!0};d.on(\"uiSpace\",function(c){if(c.data.space==d.config.toolbarLocation){c.removeListener();d.toolbox=new b;var f=CKEDITOR.tools.getNextId(),\nl=['\\x3cspan id\\x3d\"',f,'\" class\\x3d\"cke_voice_label\"\\x3e',d.lang.toolbar.toolbars,\"\\x3c/span\\x3e\",'\\x3cspan id\\x3d\"'+d.ui.spaceId(\"toolbox\")+'\" class\\x3d\"cke_toolbox\" role\\x3d\"group\" aria-labelledby\\x3d\"',f,'\" onmousedown\\x3d\"return false;\"\\x3e'],f=!1!==d.config.toolbarStartupExpanded,e,n;d.config.toolbarCanCollapse&&d.elementMode!=CKEDITOR.ELEMENT_MODE_INLINE&&l.push('\\x3cspan class\\x3d\"cke_toolbox_main\"'+(f?\"\\x3e\":' style\\x3d\"display:none\"\\x3e'));for(var q=d.toolbox.toolbars,y=a(d),u=y.length,\np=0;p<u;p++){var v,w=0,r,z=y[p],t=\"/\"!==z&&(\"/\"===y[p+1]||p==u-1),x;if(z)if(e&&(l.push(\"\\x3c/span\\x3e\"),n=e=0),\"/\"===z)l.push('\\x3cspan class\\x3d\"cke_toolbar_break\"\\x3e\\x3c/span\\x3e');else{x=z.items||z;for(var A=0;A<x.length;A++){var B=x[A],C;if(B){var H=function(a){a=a.render(d,l);F=w.items.push(a)-1;0<F&&(a.previous=w.items[F-1],a.previous.next=a);a.toolbar=w;a.onkey=k;a.onfocus=function(){d.toolbox.focusCommandExecuted||d.focus()}};if(B.type==CKEDITOR.UI_SEPARATOR)n=e&&B;else{C=!1!==B.canGroup;\nif(!w){v=CKEDITOR.tools.getNextId();w={id:v,items:[]};r=z.name&&(d.lang.toolbar.toolbarGroups[z.name]||z.name);l.push('\\x3cspan id\\x3d\"',v,'\" class\\x3d\"cke_toolbar'+(t?' cke_toolbar_last\"':'\"'),r?' aria-labelledby\\x3d\"'+v+'_label\"':\"\",' role\\x3d\"toolbar\"\\x3e');r&&l.push('\\x3cspan id\\x3d\"',v,'_label\" class\\x3d\"cke_voice_label\"\\x3e',r,\"\\x3c/span\\x3e\");l.push('\\x3cspan class\\x3d\"cke_toolbar_start\"\\x3e\\x3c/span\\x3e');var F=q.push(w)-1;0<F&&(w.previous=q[F-1],w.previous.next=w)}C?e||(l.push('\\x3cspan class\\x3d\"cke_toolgroup\" role\\x3d\"presentation\"\\x3e'),\ne=1):e&&(l.push(\"\\x3c/span\\x3e\"),e=0);n&&(H(n),n=0);H(B)}}}e&&(l.push(\"\\x3c/span\\x3e\"),n=e=0);w&&l.push('\\x3cspan class\\x3d\"cke_toolbar_end\"\\x3e\\x3c/span\\x3e\\x3c/span\\x3e')}}d.config.toolbarCanCollapse&&l.push(\"\\x3c/span\\x3e\");if(d.config.toolbarCanCollapse&&d.elementMode!=CKEDITOR.ELEMENT_MODE_INLINE){var I=CKEDITOR.tools.addFunction(function(){d.execCommand(\"toolbarCollapse\")});d.on(\"destroy\",function(){CKEDITOR.tools.removeFunction(I)});d.addCommand(\"toolbarCollapse\",{readOnly:1,exec:function(a){var b=\na.ui.space(\"toolbar_collapser\"),c=b.getPrevious(),e=a.ui.space(\"contents\"),d=c.getParent(),g=parseInt(e.$.style.height,10),f=d.$.offsetHeight,h=b.hasClass(\"cke_toolbox_collapser_min\");h?(c.show(),b.removeClass(\"cke_toolbox_collapser_min\"),b.setAttribute(\"title\",a.lang.toolbar.toolbarCollapse)):(c.hide(),b.addClass(\"cke_toolbox_collapser_min\"),b.setAttribute(\"title\",a.lang.toolbar.toolbarExpand));b.getFirst().setText(h?\"▲\":\"◀\");e.setStyle(\"height\",g-(d.$.offsetHeight-f)+\"px\");a.fire(\"resize\",{outerHeight:a.container.$.offsetHeight,\ncontentsHeight:e.$.offsetHeight,outerWidth:a.container.$.offsetWidth})},modes:{wysiwyg:1,source:1}});d.setKeystroke(CKEDITOR.ALT+(CKEDITOR.env.ie||CKEDITOR.env.webkit?189:109),\"toolbarCollapse\");l.push('\\x3ca title\\x3d\"'+(f?d.lang.toolbar.toolbarCollapse:d.lang.toolbar.toolbarExpand)+'\" id\\x3d\"'+d.ui.spaceId(\"toolbar_collapser\")+'\" tabIndex\\x3d\"-1\" class\\x3d\"cke_toolbox_collapser');f||l.push(\" cke_toolbox_collapser_min\");l.push('\" onclick\\x3d\"CKEDITOR.tools.callFunction('+I+')\"\\x3e','\\x3cspan class\\x3d\"cke_arrow\"\\x3e\\x26#9650;\\x3c/span\\x3e',\n\"\\x3c/a\\x3e\")}l.push(\"\\x3c/span\\x3e\");c.data.html+=l.join(\"\")}});d.on(\"destroy\",function(){if(this.toolbox){var a,b=0,c,e,d;for(a=this.toolbox.toolbars;b<a.length;b++)for(e=a[b].items,c=0;c<e.length;c++)d=e[c],d.clickFn&&CKEDITOR.tools.removeFunction(d.clickFn),d.keyDownFn&&CKEDITOR.tools.removeFunction(d.keyDownFn)}});d.on(\"uiReady\",function(){var a=d.ui.space(\"toolbox\");a&&d.focusManager.add(a,1)});d.addCommand(\"toolbarFocus\",c);d.setKeystroke(CKEDITOR.ALT+121,\"toolbarFocus\");d.ui.add(\"-\",CKEDITOR.UI_SEPARATOR,\n{});d.ui.addHandler(CKEDITOR.UI_SEPARATOR,{create:function(){return{render:function(a,b){b.push('\\x3cspan class\\x3d\"cke_toolbar_separator\" role\\x3d\"separator\"\\x3e\\x3c/span\\x3e');return{}}}}})}});CKEDITOR.ui.prototype.addToolbarGroup=function(a,b,c){var g=f(this.editor),h=0===b,m={name:a};if(c){if(c=CKEDITOR.tools.search(g,function(a){return a.name==c})){!c.groups&&(c.groups=[]);if(b&&(b=CKEDITOR.tools.indexOf(c.groups,b),0<=b)){c.groups.splice(b+1,0,a);return}h?c.groups.splice(0,0,a):c.groups.push(a);\nreturn}b=null}b&&(b=CKEDITOR.tools.indexOf(g,function(a){return a.name==b}));h?g.splice(0,0,a):\"number\"==typeof b?g.splice(b+1,0,m):g.push(a)}}(),CKEDITOR.UI_SEPARATOR=\"separator\",CKEDITOR.config.toolbarLocation=\"top\",\"use strict\",function(){function a(a,b,c){b.type||(b.type=\"auto\");if(c&&!1===a.fire(\"beforePaste\",b)||!b.dataValue&&b.dataTransfer.isEmpty())return!1;b.dataValue||(b.dataValue=\"\");if(CKEDITOR.env.gecko&&\"drop\"==b.method&&a.toolbox)a.once(\"afterPaste\",function(){a.toolbox.focus()});return a.fire(\"paste\",\nb)}function f(b){function c(){var a=b.editable();if(CKEDITOR.plugins.clipboard.isCustomCopyCutSupported){var d=function(a){b.getSelection().isCollapsed()||(b.readOnly&&\"cut\"==a.name||C.initPasteDataTransfer(a,b),a.data.preventDefault())};a.on(\"copy\",d);a.on(\"cut\",d);a.on(\"cut\",function(){b.readOnly||b.extractSelectedHtml()},null,null,999)}a.on(C.mainPasteEvent,function(a){\"beforepaste\"==C.mainPasteEvent&&H||x(a)});\"beforepaste\"==C.mainPasteEvent&&(a.on(\"paste\",function(a){F||(f(),a.data.preventDefault(),\nx(a),k(\"paste\"))}),a.on(\"contextmenu\",h,null,null,0),a.on(\"beforepaste\",function(a){!a.data||a.data.$.ctrlKey||a.data.$.shiftKey||h()},null,null,0));a.on(\"beforecut\",function(){!H&&l(b)});var g;a.attachListener(CKEDITOR.env.ie?a:b.document.getDocumentElement(),\"mouseup\",function(){g=setTimeout(A,0)});b.on(\"destroy\",function(){clearTimeout(g)});a.on(\"keyup\",A)}function d(a){return{type:a,canUndo:\"cut\"==a,startDisabled:!0,fakeKeystroke:\"cut\"==a?CKEDITOR.CTRL+88:CKEDITOR.CTRL+67,exec:function(){\"cut\"==\nthis.type&&l();var a;var c=this.type;if(CKEDITOR.env.ie)a=k(c);else try{a=b.document.$.execCommand(c,!1,null)}catch(d){a=!1}a||b.showNotification(b.lang.clipboard[this.type+\"Error\"]);return a}}}function g(){return{canUndo:!1,async:!0,fakeKeystroke:CKEDITOR.CTRL+86,exec:function(b,c){function e(c,f){f=\"undefined\"!==typeof f?f:!0;c?(c.method=\"paste\",c.dataTransfer||(c.dataTransfer=C.initPasteDataTransfer()),a(b,c,f)):g&&!b._.forcePasteDialog&&b.showNotification(k,\"info\",b.config.clipboard_notificationDuration);\nb._.forcePasteDialog=!1;b.fire(\"afterCommandExec\",{name:\"paste\",command:d,returnValue:!!c})}c=\"undefined\"!==typeof c&&null!==c?c:{};var d=this,g=\"undefined\"!==typeof c.notification?c.notification:!0,f=c.type,h=CKEDITOR.tools.keystrokeToString(b.lang.common.keyboard,b.getCommandKeystroke(this)),k=\"string\"===typeof g?g:b.lang.clipboard.pasteNotification.replace(/%1/,'\\x3ckbd aria-label\\x3d\"'+h.aria+'\"\\x3e'+h.display+\"\\x3c/kbd\\x3e\"),h=\"string\"===typeof c?c:c.dataValue;f&&!0!==b.config.forcePasteAsPlainText&&\n\"allow-word\"!==b.config.forcePasteAsPlainText?b._.nextPasteType=f:delete b._.nextPasteType;\"string\"===typeof h?e({dataValue:h}):b.getClipboardData(e)}}}function f(){F=1;setTimeout(function(){F=0},100)}function h(){H=1;setTimeout(function(){H=0},10)}function k(a){var c=b.document,d=c.getBody(),g=!1,f=function(){g=!0};d.on(a,f);7<CKEDITOR.env.version?c.$.execCommand(a):c.$.selection.createRange().execCommand(a);d.removeListener(a,f);return g}function l(){if(CKEDITOR.env.ie&&!CKEDITOR.env.quirks){var a=\nb.getSelection(),c,d,g;a.getType()==CKEDITOR.SELECTION_ELEMENT&&(c=a.getSelectedElement())&&(d=a.getRanges()[0],g=b.document.createText(\"\"),g.insertBefore(c),d.setStartBefore(g),d.setEndAfter(c),a.selectRanges([d]),setTimeout(function(){c.getParent()&&(g.remove(),a.selectElement(c))},0))}}function m(a,c){var d=b.document,g=b.editable(),f=function(a){a.cancel()},h;if(!d.getById(\"cke_pastebin\")){var k=b.getSelection(),l=k.createBookmarks();CKEDITOR.env.ie&&k.root.fire(\"selectionchange\");var n=new CKEDITOR.dom.element(!CKEDITOR.env.webkit&&\n!g.is(\"body\")||CKEDITOR.env.ie?\"div\":\"body\",d);n.setAttributes({id:\"cke_pastebin\",\"data-cke-temp\":\"1\"});var r=0,d=d.getWindow();CKEDITOR.env.webkit?(g.append(n),n.addClass(\"cke_editable\"),g.is(\"body\")||(r=\"static\"!=g.getComputedStyle(\"position\")?g:CKEDITOR.dom.element.get(g.$.offsetParent),r=r.getDocumentPosition().y)):g.getAscendant(CKEDITOR.env.ie?\"body\":\"html\",1).append(n);n.setStyles({position:\"absolute\",top:d.getScrollPosition().y-r+10+\"px\",width:\"1px\",height:Math.max(1,d.getViewPaneSize().height-\n20)+\"px\",overflow:\"hidden\",margin:0,padding:0});CKEDITOR.env.safari&&n.setStyles(CKEDITOR.tools.cssVendorPrefix(\"user-select\",\"text\"));(r=n.getParent().isReadOnly())?(n.setOpacity(0),n.setAttribute(\"contenteditable\",!0)):n.setStyle(\"ltr\"==b.config.contentsLangDirection?\"left\":\"right\",\"-10000px\");b.on(\"selectionChange\",f,null,null,0);if(CKEDITOR.env.webkit||CKEDITOR.env.gecko)h=g.once(\"blur\",f,null,null,-100);r&&n.focus();r=new CKEDITOR.dom.range(n);r.selectNodeContents(n);var t=r.select();CKEDITOR.env.ie&&\n(h=g.once(\"blur\",function(){b.lockSelection(t)}));var q=CKEDITOR.document.getWindow().getScrollPosition().y;setTimeout(function(){CKEDITOR.env.webkit&&(CKEDITOR.document.getBody().$.scrollTop=q);h&&h.removeListener();CKEDITOR.env.ie&&g.focus();k.selectBookmarks(l);n.remove();var a;CKEDITOR.env.webkit&&(a=n.getFirst())&&a.is&&a.hasClass(\"Apple-style-span\")&&(n=a);b.removeListener(\"selectionChange\",f);c(n.getHtml())},0)}}function z(){if(\"paste\"==C.mainPasteEvent)return b.fire(\"beforePaste\",{type:\"auto\",\nmethod:\"paste\"}),!1;b.focus();f();var a=b.focusManager;a.lock();if(b.editable().fire(C.mainPasteEvent)&&!k(\"paste\"))return a.unlock(),!1;a.unlock();return!0}function t(a){if(\"wysiwyg\"==b.mode)switch(a.data.keyCode){case CKEDITOR.CTRL+86:case CKEDITOR.SHIFT+45:a=b.editable();f();\"paste\"==C.mainPasteEvent&&a.fire(\"beforepaste\");break;case CKEDITOR.CTRL+88:case CKEDITOR.SHIFT+46:b.fire(\"saveSnapshot\"),setTimeout(function(){b.fire(\"saveSnapshot\")},50)}}function x(c){var d={type:\"auto\",method:\"paste\",\ndataTransfer:C.initPasteDataTransfer(c)};d.dataTransfer.cacheData();var g=!1!==b.fire(\"beforePaste\",d);g&&C.canClipboardApiBeTrusted(d.dataTransfer,b)?(c.data.preventDefault(),setTimeout(function(){a(b,d)},0)):m(c,function(c){d.dataValue=c.replace(/<span[^>]+data-cke-bookmark[^<]*?<\\/span>/ig,\"\");g&&a(b,d)})}function A(){if(\"wysiwyg\"==b.mode){var a=B(\"paste\");b.getCommand(\"cut\").setState(B(\"cut\"));b.getCommand(\"copy\").setState(B(\"copy\"));b.getCommand(\"paste\").setState(a);b.fire(\"pasteState\",a)}}function B(a){var c=\nb.getSelection(),c=c&&c.getRanges()[0];if((b.readOnly||c&&c.checkReadOnly())&&a in{paste:1,cut:1})return CKEDITOR.TRISTATE_DISABLED;if(\"paste\"==a)return CKEDITOR.TRISTATE_OFF;a=b.getSelection();c=a.getRanges();return a.getType()==CKEDITOR.SELECTION_NONE||1==c.length&&c[0].collapsed?CKEDITOR.TRISTATE_DISABLED:CKEDITOR.TRISTATE_OFF}var C=CKEDITOR.plugins.clipboard,H=0,F=0;(function(){b.on(\"key\",t);b.on(\"contentDom\",c);b.on(\"selectionChange\",A);if(b.contextMenu){b.contextMenu.addListener(function(){return{cut:B(\"cut\"),\ncopy:B(\"copy\"),paste:B(\"paste\")}});var a=null;b.on(\"menuShow\",function(){a&&(a.removeListener(),a=null);var c=b.contextMenu.findItemByCommandName(\"paste\");c&&c.element&&(a=c.element.on(\"touchend\",function(){b._.forcePasteDialog=!0}))})}if(b.ui.addButton)b.once(\"instanceReady\",function(){b._.pasteButtons&&CKEDITOR.tools.array.forEach(b._.pasteButtons,function(a){if(a=b.ui.get(a))if(a=CKEDITOR.document.getById(a._.id))a.on(\"touchend\",function(){b._.forcePasteDialog=!0})})})})();(function(){function a(c,\nd,g,f,h){var k=b.lang.clipboard[d];b.addCommand(d,g);b.ui.addButton&&b.ui.addButton(c,{label:k,command:d,toolbar:\"clipboard,\"+f});b.addMenuItems&&b.addMenuItem(d,{label:k,command:d,group:\"clipboard\",order:h})}a(\"Cut\",\"cut\",d(\"cut\"),10,1);a(\"Copy\",\"copy\",d(\"copy\"),20,4);a(\"Paste\",\"paste\",g(),30,8);b._.pasteButtons||(b._.pasteButtons=[]);b._.pasteButtons.push(\"Paste\")})();b.getClipboardData=function(a,c){function d(a){a.removeListener();a.cancel();c(a.data)}function g(a){a.removeListener();a.cancel();\nc({type:h,dataValue:a.data.dataValue,dataTransfer:a.data.dataTransfer,method:\"paste\"})}var f=!1,h=\"auto\";c||(c=a,a=null);b.on(\"beforePaste\",function(a){a.removeListener();f=!0;h=a.data.type},null,null,1E3);b.on(\"paste\",d,null,null,0);!1===z()&&(b.removeListener(\"paste\",d),b._.forcePasteDialog&&f&&b.fire(\"pasteDialog\")?(b.on(\"pasteDialogCommit\",g),b.on(\"dialogHide\",function(a){a.removeListener();a.data.removeListener(\"pasteDialogCommit\",g);a.data._.committed||c(null)})):c(null))}}function b(a){if(CKEDITOR.env.webkit){if(!a.match(/^[^<]*$/g)&&\n!a.match(/^(<div><br( ?\\/)?><\\/div>|<div>[^<]*<\\/div>)*$/gi))return\"html\"}else if(CKEDITOR.env.ie){if(!a.match(/^([^<]|<br( ?\\/)?>)*$/gi)&&!a.match(/^(<p>([^<]|<br( ?\\/)?>)*<\\/p>|(\\r\\n))*$/gi))return\"html\"}else if(CKEDITOR.env.gecko){if(!a.match(/^([^<]|<br( ?\\/)?>)*$/gi))return\"html\"}else return\"html\";return\"htmlifiedtext\"}function c(a,b){function c(a){return CKEDITOR.tools.repeat(\"\\x3c/p\\x3e\\x3cp\\x3e\",~~(a/2))+(1==a%2?\"\\x3cbr\\x3e\":\"\")}b=b.replace(/(?!\\u3000)\\s+/g,\" \").replace(/> +</g,\"\\x3e\\x3c\").replace(/<br ?\\/>/gi,\n\"\\x3cbr\\x3e\");b=b.replace(/<\\/?[A-Z]+>/g,function(a){return a.toLowerCase()});if(b.match(/^[^<]$/))return b;CKEDITOR.env.webkit&&-1<b.indexOf(\"\\x3cdiv\\x3e\")&&(b=b.replace(/^(<div>(<br>|)<\\/div>)(?!$|(<div>(<br>|)<\\/div>))/g,\"\\x3cbr\\x3e\").replace(/^(<div>(<br>|)<\\/div>){2}(?!$)/g,\"\\x3cdiv\\x3e\\x3c/div\\x3e\"),b.match(/<div>(<br>|)<\\/div>/)&&(b=\"\\x3cp\\x3e\"+b.replace(/(<div>(<br>|)<\\/div>)+/g,function(a){return c(a.split(\"\\x3c/div\\x3e\\x3cdiv\\x3e\").length+1)})+\"\\x3c/p\\x3e\"),b=b.replace(/<\\/div><div>/g,\"\\x3cbr\\x3e\"),\nb=b.replace(/<\\/?div>/g,\"\"));CKEDITOR.env.gecko&&a.enterMode!=CKEDITOR.ENTER_BR&&(CKEDITOR.env.gecko&&(b=b.replace(/^<br><br>$/,\"\\x3cbr\\x3e\")),-1<b.indexOf(\"\\x3cbr\\x3e\\x3cbr\\x3e\")&&(b=\"\\x3cp\\x3e\"+b.replace(/(<br>){2,}/g,function(a){return c(a.length/4)})+\"\\x3c/p\\x3e\"));return k(a,b)}function d(a){function b(){var a={},c;for(c in CKEDITOR.dtd)\"$\"!=c.charAt(0)&&\"div\"!=c&&\"span\"!=c&&(a[c]=1);return a}var c={};return{get:function(d){return\"plain-text\"==d?c.plainText||(c.plainText=new CKEDITOR.filter(a,\n\"br\")):\"semantic-content\"==d?((d=c.semanticContent)||(d=new CKEDITOR.filter(a,{}),d.allow({$1:{elements:b(),attributes:!0,styles:!1,classes:!1}}),d=c.semanticContent=d),d):d?new CKEDITOR.filter(a,d):null}}}function l(a,b,c){b=CKEDITOR.htmlParser.fragment.fromHtml(b);var d=new CKEDITOR.htmlParser.basicWriter;c.applyTo(b,!0,!1,a.activeEnterMode);b.writeHtml(d);return d.getHtml()}function k(a,b){a.enterMode==CKEDITOR.ENTER_BR?b=b.replace(/(<\\/p><p>)+/g,function(a){return CKEDITOR.tools.repeat(\"\\x3cbr\\x3e\",\na.length/7*2)}).replace(/<\\/?p>/g,\"\"):a.enterMode==CKEDITOR.ENTER_DIV&&(b=b.replace(/<(\\/)?p>/g,\"\\x3c$1div\\x3e\"));return b}function g(a){a.data.preventDefault();a.data.$.dataTransfer.dropEffect=\"none\"}function h(b){var c=CKEDITOR.plugins.clipboard;b.on(\"contentDom\",function(){function d(c,g,f){g.select();a(b,{dataTransfer:f,method:\"drop\"},1);f.sourceEditor.fire(\"saveSnapshot\");f.sourceEditor.editable().extractHtmlFromRange(c);f.sourceEditor.getSelection().selectRanges([c]);f.sourceEditor.fire(\"saveSnapshot\")}\nfunction g(d,f){d.select();a(b,{dataTransfer:f,method:\"drop\"},1);c.resetDragDataTransfer()}function f(a,c,d){var g={$:a.data.$,target:a.data.getTarget()};c&&(g.dragRange=c);d&&(g.dropRange=d);!1===b.fire(a.name,g)&&a.data.preventDefault()}function h(a){a.type!=CKEDITOR.NODE_ELEMENT&&(a=a.getParent());return a.getChildCount()}var k=b.editable(),l=CKEDITOR.plugins.clipboard.getDropTarget(b),m=b.ui.space(\"top\"),z=b.ui.space(\"bottom\");c.preventDefaultDropOnElement(m);c.preventDefaultDropOnElement(z);\nk.attachListener(l,\"dragstart\",f);k.attachListener(b,\"dragstart\",c.resetDragDataTransfer,c,null,1);k.attachListener(b,\"dragstart\",function(a){c.initDragDataTransfer(a,b)},null,null,2);k.attachListener(b,\"dragstart\",function(){var a=c.dragRange=b.getSelection().getRanges()[0];CKEDITOR.env.ie&&10>CKEDITOR.env.version&&(c.dragStartContainerChildCount=a?h(a.startContainer):null,c.dragEndContainerChildCount=a?h(a.endContainer):null)},null,null,100);k.attachListener(l,\"dragend\",f);k.attachListener(b,\"dragend\",\nc.initDragDataTransfer,c,null,1);k.attachListener(b,\"dragend\",c.resetDragDataTransfer,c,null,100);k.attachListener(l,\"dragover\",function(a){if(CKEDITOR.env.edge)a.data.preventDefault();else{var b=a.data.getTarget();b&&b.is&&b.is(\"html\")?a.data.preventDefault():CKEDITOR.env.ie&&CKEDITOR.plugins.clipboard.isFileApiSupported&&a.data.$.dataTransfer.types.contains(\"Files\")&&a.data.preventDefault()}});k.attachListener(l,\"drop\",function(a){if(!a.data.$.defaultPrevented){a.data.preventDefault();var d=a.data.getTarget();\nif(!d.isReadOnly()||d.type==CKEDITOR.NODE_ELEMENT&&d.is(\"html\")){var d=c.getRangeAtDropPosition(a,b),g=c.dragRange;d&&f(a,g,d)}}},null,null,9999);k.attachListener(b,\"drop\",c.initDragDataTransfer,c,null,1);k.attachListener(b,\"drop\",function(a){if(a=a.data){var f=a.dropRange,h=a.dragRange,k=a.dataTransfer;k.getTransferType(b)==CKEDITOR.DATA_TRANSFER_INTERNAL?setTimeout(function(){c.internalDrop(h,f,k,b)},0):k.getTransferType(b)==CKEDITOR.DATA_TRANSFER_CROSS_EDITORS?d(h,f,k):g(f,k)}},null,null,9999)})}\nvar m;CKEDITOR.plugins.add(\"clipboard\",{requires:\"dialog,notification,toolbar\",init:function(a){var g,k=d(a);a.config.forcePasteAsPlainText?g=\"plain-text\":a.config.pasteFilter?g=a.config.pasteFilter:!CKEDITOR.env.webkit||\"pasteFilter\"in a.config||(g=\"semantic-content\");a.pasteFilter=k.get(g);f(a);h(a);CKEDITOR.dialog.add(\"paste\",CKEDITOR.getUrl(this.path+\"dialogs/paste.js\"));if(CKEDITOR.env.gecko){var m=[\"image/png\",\"image/jpeg\",\"image/gif\"],u;a.on(\"paste\",function(b){var c=b.data,d=c.dataTransfer;\nif(!c.dataValue&&\"paste\"==c.method&&d&&1==d.getFilesCount()&&u!=d.id&&(d=d.getFile(0),-1!=CKEDITOR.tools.indexOf(m,d.type))){var g=new FileReader;g.addEventListener(\"load\",function(){b.data.dataValue='\\x3cimg src\\x3d\"'+g.result+'\" /\\x3e';a.fire(\"paste\",b.data)},!1);g.addEventListener(\"abort\",function(){a.fire(\"paste\",b.data)},!1);g.addEventListener(\"error\",function(){a.fire(\"paste\",b.data)},!1);g.readAsDataURL(d);u=c.dataTransfer.id;b.stop()}},null,null,1)}a.on(\"paste\",function(b){b.data.dataTransfer||\n(b.data.dataTransfer=new CKEDITOR.plugins.clipboard.dataTransfer);if(!b.data.dataValue){var c=b.data.dataTransfer,d=c.getData(\"text/html\");if(d)b.data.dataValue=d,b.data.type=\"html\";else if(d=c.getData(\"text/plain\"))b.data.dataValue=a.editable().transformPlainTextToHtml(d),b.data.type=\"text\"}},null,null,1);a.on(\"paste\",function(a){var b=a.data.dataValue,c=CKEDITOR.dtd.$block;-1<b.indexOf(\"Apple-\")&&(b=b.replace(/<span class=\"Apple-converted-space\">&nbsp;<\\/span>/gi,\" \"),\"html\"!=a.data.type&&(b=b.replace(/<span class=\"Apple-tab-span\"[^>]*>([^<]*)<\\/span>/gi,\nfunction(a,b){return b.replace(/\\t/g,\"\\x26nbsp;\\x26nbsp; \\x26nbsp;\")})),-1<b.indexOf('\\x3cbr class\\x3d\"Apple-interchange-newline\"\\x3e')&&(a.data.startsWithEOL=1,a.data.preSniffing=\"html\",b=b.replace(/<br class=\"Apple-interchange-newline\">/,\"\")),b=b.replace(/(<[^>]+) class=\"Apple-[^\"]*\"/gi,\"$1\"));if(b.match(/^<[^<]+cke_(editable|contents)/i)){var d,e,g=new CKEDITOR.dom.element(\"div\");for(g.setHtml(b);1==g.getChildCount()&&(d=g.getFirst())&&d.type==CKEDITOR.NODE_ELEMENT&&(d.hasClass(\"cke_editable\")||\nd.hasClass(\"cke_contents\"));)g=e=d;e&&(b=e.getHtml().replace(/<br>$/i,\"\"))}CKEDITOR.env.ie?b=b.replace(/^&nbsp;(?: |\\r\\n)?<(\\w+)/g,function(b,d){return d.toLowerCase()in c?(a.data.preSniffing=\"html\",\"\\x3c\"+d):b}):CKEDITOR.env.webkit?b=b.replace(/<\\/(\\w+)><div><br><\\/div>$/,function(b,d){return d in c?(a.data.endsWithEOL=1,\"\\x3c/\"+d+\"\\x3e\"):b}):CKEDITOR.env.gecko&&(b=b.replace(/(\\s)<br>$/,\"$1\"));a.data.dataValue=b},null,null,3);a.on(\"paste\",function(d){d=d.data;var g=a._.nextPasteType||d.type,f=d.dataValue,\nh,m=a.config.clipboard_defaultContentType||\"html\",n=d.dataTransfer.getTransferType(a)==CKEDITOR.DATA_TRANSFER_EXTERNAL,u=!0===a.config.forcePasteAsPlainText;h=\"html\"==g||\"html\"==d.preSniffing?\"html\":b(f);delete a._.nextPasteType;\"htmlifiedtext\"==h&&(f=c(a.config,f));if(\"text\"==g&&\"html\"==h)f=l(a,f,k.get(\"plain-text\"));else if(n&&a.pasteFilter&&!d.dontFilter||u)f=l(a,f,a.pasteFilter);d.startsWithEOL&&(f='\\x3cbr data-cke-eol\\x3d\"1\"\\x3e'+f);d.endsWithEOL&&(f+='\\x3cbr data-cke-eol\\x3d\"1\"\\x3e');\"auto\"==\ng&&(g=\"html\"==h||\"html\"==m?\"html\":\"text\");d.type=g;d.dataValue=f;delete d.preSniffing;delete d.startsWithEOL;delete d.endsWithEOL},null,null,6);a.on(\"paste\",function(b){b=b.data;b.dataValue&&(a.insertHtml(b.dataValue,b.type,b.range),setTimeout(function(){a.fire(\"afterPaste\")},0))},null,null,1E3);a.on(\"pasteDialog\",function(b){setTimeout(function(){a.openDialog(\"paste\",b.data)},0)})}});CKEDITOR.plugins.clipboard={isCustomCopyCutSupported:(!CKEDITOR.env.ie||16<=CKEDITOR.env.version)&&!CKEDITOR.env.iOS,\nisCustomDataTypesSupported:!CKEDITOR.env.ie||16<=CKEDITOR.env.version,isFileApiSupported:!CKEDITOR.env.ie||9<CKEDITOR.env.version,mainPasteEvent:CKEDITOR.env.ie&&!CKEDITOR.env.edge?\"beforepaste\":\"paste\",addPasteButton:function(a,b,c){a.ui.addButton&&(a.ui.addButton(b,c),a._.pasteButtons||(a._.pasteButtons=[]),a._.pasteButtons.push(b))},canClipboardApiBeTrusted:function(a,b){return a.getTransferType(b)!=CKEDITOR.DATA_TRANSFER_EXTERNAL||CKEDITOR.env.chrome&&!a.isEmpty()||CKEDITOR.env.gecko&&(a.getData(\"text/html\")||\na.getFilesCount())||CKEDITOR.env.safari&&603<=CKEDITOR.env.version&&!CKEDITOR.env.iOS||CKEDITOR.env.edge&&16<=CKEDITOR.env.version?!0:!1},getDropTarget:function(a){var b=a.editable();return CKEDITOR.env.ie&&9>CKEDITOR.env.version||b.isInline()?b:a.document},fixSplitNodesAfterDrop:function(a,b,c,d){function g(a,c,d){var e=a;e.type==CKEDITOR.NODE_TEXT&&(e=a.getParent());if(e.equals(c)&&d!=c.getChildCount())return a=b.startContainer.getChild(b.startOffset-1),c=b.startContainer.getChild(b.startOffset),\na&&a.type==CKEDITOR.NODE_TEXT&&c&&c.type==CKEDITOR.NODE_TEXT&&(d=a.getLength(),a.setText(a.getText()+c.getText()),c.remove(),b.setStart(a,d),b.collapse(!0)),!0}var f=b.startContainer;\"number\"==typeof d&&\"number\"==typeof c&&f.type==CKEDITOR.NODE_ELEMENT&&(g(a.startContainer,f,c)||g(a.endContainer,f,d))},isDropRangeAffectedByDragRange:function(a,b){var c=b.startContainer,d=b.endOffset;return a.endContainer.equals(c)&&a.endOffset<=d||a.startContainer.getParent().equals(c)&&a.startContainer.getIndex()<\nd||a.endContainer.getParent().equals(c)&&a.endContainer.getIndex()<d?!0:!1},internalDrop:function(b,c,d,g){var f=CKEDITOR.plugins.clipboard,h=g.editable(),k,l;g.fire(\"saveSnapshot\");g.fire(\"lockSnapshot\",{dontUpdate:1});CKEDITOR.env.ie&&10>CKEDITOR.env.version&&this.fixSplitNodesAfterDrop(b,c,f.dragStartContainerChildCount,f.dragEndContainerChildCount);(l=this.isDropRangeAffectedByDragRange(b,c))||(k=b.createBookmark(!1));f=c.clone().createBookmark(!1);l&&(k=b.createBookmark(!1));b=k.startNode;c=\nk.endNode;l=f.startNode;c&&b.getPosition(l)&CKEDITOR.POSITION_PRECEDING&&c.getPosition(l)&CKEDITOR.POSITION_FOLLOWING&&l.insertBefore(b);b=g.createRange();b.moveToBookmark(k);h.extractHtmlFromRange(b,1);c=g.createRange();f.startNode.getCommonAncestor(h)||(f=g.getSelection().createBookmarks()[0]);c.moveToBookmark(f);a(g,{dataTransfer:d,method:\"drop\",range:c},1);g.fire(\"unlockSnapshot\")},getRangeAtDropPosition:function(a,b){var c=a.data.$,d=c.clientX,g=c.clientY,f=b.getSelection(!0).getRanges()[0],\nh=b.createRange();if(a.data.testRange)return a.data.testRange;if(document.caretRangeFromPoint&&b.document.$.caretRangeFromPoint(d,g))c=b.document.$.caretRangeFromPoint(d,g),h.setStart(CKEDITOR.dom.node(c.startContainer),c.startOffset),h.collapse(!0);else if(c.rangeParent)h.setStart(CKEDITOR.dom.node(c.rangeParent),c.rangeOffset),h.collapse(!0);else{if(CKEDITOR.env.ie&&8<CKEDITOR.env.version&&f&&b.editable().hasFocus)return f;if(document.body.createTextRange){b.focus();c=b.document.getBody().$.createTextRange();\ntry{for(var k=!1,l=0;20>l&&!k;l++){if(!k)try{c.moveToPoint(d,g-l),k=!0}catch(m){}if(!k)try{c.moveToPoint(d,g+l),k=!0}catch(t){}}if(k){var x=\"cke-temp-\"+(new Date).getTime();c.pasteHTML('\\x3cspan id\\x3d\"'+x+'\"\\x3e​\\x3c/span\\x3e');var A=b.document.getById(x);h.moveToPosition(A,CKEDITOR.POSITION_BEFORE_START);A.remove()}else{var B=b.document.$.elementFromPoint(d,g),C=new CKEDITOR.dom.element(B),H;if(C.equals(b.editable())||\"html\"==C.getName())return f&&f.startContainer&&!f.startContainer.equals(b.editable())?\nf:null;H=C.getClientRect();d<H.left?h.setStartAt(C,CKEDITOR.POSITION_AFTER_START):h.setStartAt(C,CKEDITOR.POSITION_BEFORE_END);h.collapse(!0)}}catch(F){return null}}else return null}return h},initDragDataTransfer:function(a,b){var c=a.data.$?a.data.$.dataTransfer:null,d=new this.dataTransfer(c,b);\"dragstart\"===a.name&&d.storeId();c?this.dragData&&d.id==this.dragData.id?d=this.dragData:this.dragData=d:this.dragData?d=this.dragData:this.dragData=d;a.data.dataTransfer=d},resetDragDataTransfer:function(){this.dragData=\nnull},initPasteDataTransfer:function(a,b){if(this.isCustomCopyCutSupported){if(a&&a.data&&a.data.$){var c=a.data.$.clipboardData,d=new this.dataTransfer(c,b);\"copy\"!==a.name&&\"cut\"!==a.name||d.storeId();this.copyCutData&&d.id==this.copyCutData.id?(d=this.copyCutData,d.$=c):this.copyCutData=d;return d}return new this.dataTransfer(null,b)}return new this.dataTransfer(CKEDITOR.env.edge&&a&&a.data.$&&a.data.$.clipboardData||null,b)},preventDefaultDropOnElement:function(a){a&&a.on(\"dragover\",g)}};m=CKEDITOR.plugins.clipboard.isCustomDataTypesSupported?\n\"cke/id\":\"Text\";CKEDITOR.plugins.clipboard.dataTransfer=function(a,b){a&&(this.$=a);this._={metaRegExp:/^<meta.*?>/i,bodyRegExp:/<body(?:[\\s\\S]*?)>([\\s\\S]*)<\\/body>/i,fragmentRegExp:/\\x3c!--(?:Start|End)Fragment--\\x3e/g,data:{},files:[],nativeHtmlCache:\"\",normalizeType:function(a){a=a.toLowerCase();return\"text\"==a||\"text/plain\"==a?\"Text\":\"url\"==a?\"URL\":a}};this._.fallbackDataTransfer=new CKEDITOR.plugins.clipboard.fallbackDataTransfer(this);this.id=this.getData(m);this.id||(this.id=\"Text\"==m?\"\":\"cke-\"+\nCKEDITOR.tools.getUniqueId());b&&(this.sourceEditor=b,this.setData(\"text/html\",b.getSelectedHtml(1)),\"Text\"==m||this.getData(\"text/plain\")||this.setData(\"text/plain\",b.getSelection().getSelectedText()))};CKEDITOR.DATA_TRANSFER_INTERNAL=1;CKEDITOR.DATA_TRANSFER_CROSS_EDITORS=2;CKEDITOR.DATA_TRANSFER_EXTERNAL=3;CKEDITOR.plugins.clipboard.dataTransfer.prototype={getData:function(a,b){a=this._.normalizeType(a);var c=\"text/html\"==a&&b?this._.nativeHtmlCache:this._.data[a];if(void 0===c||null===c||\"\"===\nc){if(this._.fallbackDataTransfer.isRequired())c=this._.fallbackDataTransfer.getData(a,b);else try{c=this.$.getData(a)||\"\"}catch(d){c=\"\"}\"text/html\"!=a||b||(c=this._stripHtml(c))}\"Text\"==a&&CKEDITOR.env.gecko&&this.getFilesCount()&&\"file://\"==c.substring(0,7)&&(c=\"\");if(\"string\"===typeof c)var g=c.indexOf(\"\\x3c/html\\x3e\"),c=-1!==g?c.substring(0,g+7):c;return c},setData:function(a,b){a=this._.normalizeType(a);\"text/html\"==a?(this._.data[a]=this._stripHtml(b),this._.nativeHtmlCache=b):this._.data[a]=\nb;if(CKEDITOR.plugins.clipboard.isCustomDataTypesSupported||\"URL\"==a||\"Text\"==a)if(\"Text\"==m&&\"Text\"==a&&(this.id=b),this._.fallbackDataTransfer.isRequired())this._.fallbackDataTransfer.setData(a,b);else try{this.$.setData(a,b)}catch(c){}},storeId:function(){\"Text\"!==m&&this.setData(m,this.id)},getTransferType:function(a){return this.sourceEditor?this.sourceEditor==a?CKEDITOR.DATA_TRANSFER_INTERNAL:CKEDITOR.DATA_TRANSFER_CROSS_EDITORS:CKEDITOR.DATA_TRANSFER_EXTERNAL},cacheData:function(){function a(c){c=\nb._.normalizeType(c);var d=b.getData(c);\"text/html\"==c&&(b._.nativeHtmlCache=b.getData(c,!0),d=b._stripHtml(d));d&&(b._.data[c]=d)}if(this.$){var b=this,c,d;if(CKEDITOR.plugins.clipboard.isCustomDataTypesSupported){if(this.$.types)for(c=0;c<this.$.types.length;c++)a(this.$.types[c])}else a(\"Text\"),a(\"URL\");d=this._getImageFromClipboard();if(this.$&&this.$.files||d){this._.files=[];if(this.$.files&&this.$.files.length)for(c=0;c<this.$.files.length;c++)this._.files.push(this.$.files[c]);0===this._.files.length&&\nd&&this._.files.push(d)}}},getFilesCount:function(){return this._.files.length?this._.files.length:this.$&&this.$.files&&this.$.files.length?this.$.files.length:this._getImageFromClipboard()?1:0},getFile:function(a){return this._.files.length?this._.files[a]:this.$&&this.$.files&&this.$.files.length?this.$.files[a]:0===a?this._getImageFromClipboard():void 0},isEmpty:function(){var a={},b;if(this.getFilesCount())return!1;CKEDITOR.tools.array.forEach(CKEDITOR.tools.object.keys(this._.data),function(b){a[b]=\n1});if(this.$)if(CKEDITOR.plugins.clipboard.isCustomDataTypesSupported){if(this.$.types)for(var c=0;c<this.$.types.length;c++)a[this.$.types[c]]=1}else a.Text=1,a.URL=1;\"Text\"!=m&&(a[m]=0);for(b in a)if(a[b]&&\"\"!==this.getData(b))return!1;return!0},_getImageFromClipboard:function(){var a;try{if(this.$&&this.$.items&&this.$.items[0]&&(a=this.$.items[0].getAsFile())&&a.type)return a}catch(b){}},_stripHtml:function(a){if(a&&a.length){a=a.replace(this._.metaRegExp,\"\");var b=this._.bodyRegExp.exec(a);\nb&&b.length&&(a=b[1],a=a.replace(this._.fragmentRegExp,\"\"))}return a}};CKEDITOR.plugins.clipboard.fallbackDataTransfer=function(a){this._dataTransfer=a;this._customDataFallbackType=\"text/html\"};CKEDITOR.plugins.clipboard.fallbackDataTransfer._isCustomMimeTypeSupported=null;CKEDITOR.plugins.clipboard.fallbackDataTransfer._customTypes=[];CKEDITOR.plugins.clipboard.fallbackDataTransfer.prototype={isRequired:function(){var a=CKEDITOR.plugins.clipboard.fallbackDataTransfer,b=this._dataTransfer.$;if(null===\na._isCustomMimeTypeSupported)if(b){a._isCustomMimeTypeSupported=!1;if(CKEDITOR.env.edge&&17<=CKEDITOR.env.version)return!0;try{b.setData(\"cke/mimetypetest\",\"cke test value\"),a._isCustomMimeTypeSupported=\"cke test value\"===b.getData(\"cke/mimetypetest\"),b.clearData(\"cke/mimetypetest\")}catch(c){}}else return!1;return!a._isCustomMimeTypeSupported},getData:function(a,b){var c=this._getData(this._customDataFallbackType,!0);if(b)return c;var c=this._extractDataComment(c),d=null,d=a===this._customDataFallbackType?\nc.content:c.data&&c.data[a]?c.data[a]:this._getData(a,!0);return null!==d?d:\"\"},setData:function(a,b){var c=a===this._customDataFallbackType;c&&(b=this._applyDataComment(b,this._getFallbackTypeData()));var d=b,g=this._dataTransfer.$;try{g.setData(a,d),c&&(this._dataTransfer._.nativeHtmlCache=d)}catch(f){if(this._isUnsupportedMimeTypeError(f)){c=CKEDITOR.plugins.clipboard.fallbackDataTransfer;-1===CKEDITOR.tools.indexOf(c._customTypes,a)&&c._customTypes.push(a);var c=this._getFallbackTypeContent(),\nh=this._getFallbackTypeData();h[a]=d;try{d=this._applyDataComment(c,h),g.setData(this._customDataFallbackType,d),this._dataTransfer._.nativeHtmlCache=d}catch(k){d=\"\"}}}return d},_getData:function(a,b){var c=this._dataTransfer._.data;if(!b&&c[a])return c[a];try{return this._dataTransfer.$.getData(a)}catch(d){return null}},_getFallbackTypeContent:function(){var a=this._dataTransfer._.data[this._customDataFallbackType];a||(a=this._extractDataComment(this._getData(this._customDataFallbackType,!0)).content);\nreturn a},_getFallbackTypeData:function(){var a=CKEDITOR.plugins.clipboard.fallbackDataTransfer._customTypes,b=this._extractDataComment(this._getData(this._customDataFallbackType,!0)).data||{},c=this._dataTransfer._.data;CKEDITOR.tools.array.forEach(a,function(a){void 0!==c[a]?b[a]=c[a]:void 0!==b[a]&&(b[a]=b[a])},this);return b},_isUnsupportedMimeTypeError:function(a){return a.message&&-1!==a.message.search(/element not found/gi)},_extractDataComment:function(a){var b={data:null,content:a||\"\"};if(a&&\n16<a.length){var c;(c=/\\x3c!--cke-data:(.*?)--\\x3e/g.exec(a))&&c[1]&&(b.data=JSON.parse(decodeURIComponent(c[1])),b.content=a.replace(c[0],\"\"))}return b},_applyDataComment:function(a,b){var c=\"\";b&&CKEDITOR.tools.object.keys(b).length&&(c=\"\\x3c!--cke-data:\"+encodeURIComponent(JSON.stringify(b))+\"--\\x3e\");return c+(a&&a.length?a:\"\")}}}(),CKEDITOR.config.clipboard_notificationDuration=1E4,function(){CKEDITOR.plugins.add(\"panel\",{beforeInit:function(a){a.ui.addHandler(CKEDITOR.UI_PANEL,CKEDITOR.ui.panel.handler)}});\nCKEDITOR.UI_PANEL=\"panel\";CKEDITOR.ui.panel=function(a,b){b&&CKEDITOR.tools.extend(this,b);CKEDITOR.tools.extend(this,{className:\"\",css:[]});this.id=CKEDITOR.tools.getNextId();this.document=a;this.isFramed=this.forceIFrame||this.css.length;this._={blocks:{}}};CKEDITOR.ui.panel.handler={create:function(a){return new CKEDITOR.ui.panel(a)}};var a=CKEDITOR.addTemplate(\"panel\",'\\x3cdiv lang\\x3d\"{langCode}\" id\\x3d\"{id}\" dir\\x3d{dir} class\\x3d\"cke cke_reset_all {editorId} cke_panel cke_panel {cls} cke_{dir}\" style\\x3d\"z-index:{z-index}\" role\\x3d\"presentation\"\\x3e{frame}\\x3c/div\\x3e'),\nf=CKEDITOR.addTemplate(\"panel-frame\",'\\x3ciframe id\\x3d\"{id}\" class\\x3d\"cke_panel_frame\" role\\x3d\"presentation\" frameborder\\x3d\"0\" src\\x3d\"{src}\"\\x3e\\x3c/iframe\\x3e'),b=CKEDITOR.addTemplate(\"panel-frame-inner\",'\\x3c!DOCTYPE html\\x3e\\x3chtml class\\x3d\"cke_panel_container {env}\" dir\\x3d\"{dir}\" lang\\x3d\"{langCode}\"\\x3e\\x3chead\\x3e{css}\\x3c/head\\x3e\\x3cbody class\\x3d\"cke_{dir}\" style\\x3d\"margin:0;padding:0\" onload\\x3d\"{onload}\"\\x3e\\x3c/body\\x3e\\x3c/html\\x3e');CKEDITOR.ui.panel.prototype={render:function(c,\nd){var l={editorId:c.id,id:this.id,langCode:c.langCode,dir:c.lang.dir,cls:this.className,frame:\"\",env:CKEDITOR.env.cssClass,\"z-index\":c.config.baseFloatZIndex+1};this.getHolderElement=function(){var a=this._.holder;if(!a){if(this.isFramed){var a=this.document.getById(this.id+\"_frame\"),c=a.getParent(),a=a.getFrameDocument();CKEDITOR.env.iOS&&c.setStyles({overflow:\"scroll\",\"-webkit-overflow-scrolling\":\"touch\"});c=CKEDITOR.tools.addFunction(CKEDITOR.tools.bind(function(){this.isLoaded=!0;if(this.onLoad)this.onLoad()},\nthis));a.write(b.output(CKEDITOR.tools.extend({css:CKEDITOR.tools.buildStyleHtml(this.css),onload:\"window.parent.CKEDITOR.tools.callFunction(\"+c+\");\"},l)));a.getWindow().$.CKEDITOR=CKEDITOR;a.on(\"keydown\",function(a){var b=a.data.getKeystroke(),c=this.document.getById(this.id).getAttribute(\"dir\");if(\"input\"!==a.data.getTarget().getName()||37!==b&&39!==b)this._.onKeyDown&&!1===this._.onKeyDown(b)?\"input\"===a.data.getTarget().getName()&&32===b||a.data.preventDefault():(27==b||b==(\"rtl\"==c?39:37))&&\nthis.onEscape&&!1===this.onEscape(b)&&a.data.preventDefault()},this);a=a.getBody();a.unselectable();CKEDITOR.env.air&&CKEDITOR.tools.callFunction(c)}else a=this.document.getById(this.id);this._.holder=a}return a};if(this.isFramed){var k=CKEDITOR.env.air?\"javascript:void(0)\":CKEDITOR.env.ie&&!CKEDITOR.env.edge?\"javascript:void(function(){\"+encodeURIComponent(\"document.open();(\"+CKEDITOR.tools.fixDomain+\")();document.close();\")+\"}())\":\"\";l.frame=f.output({id:this.id+\"_frame\",src:k})}k=a.output(l);d&&\nd.push(k);return k},addBlock:function(a,b){b=this._.blocks[a]=b instanceof CKEDITOR.ui.panel.block?b:new CKEDITOR.ui.panel.block(this.getHolderElement(),b);this._.currentBlock||this.showBlock(a);return b},getBlock:function(a){return this._.blocks[a]},showBlock:function(a){a=this._.blocks[a];var b=this._.currentBlock,f=!this.forceIFrame||CKEDITOR.env.ie?this._.holder:this.document.getById(this.id+\"_frame\");b&&b.hide();this._.currentBlock=a;CKEDITOR.fire(\"ariaWidget\",f);a._.focusIndex=-1;this._.onKeyDown=\na.onKeyDown&&CKEDITOR.tools.bind(a.onKeyDown,a);a.show();return a},destroy:function(){this.element&&this.element.remove()}};CKEDITOR.ui.panel.block=CKEDITOR.tools.createClass({$:function(a,b){this.element=a.append(a.getDocument().createElement(\"div\",{attributes:{tabindex:-1,\"class\":\"cke_panel_block\"},styles:{display:\"none\"}}));b&&CKEDITOR.tools.extend(this,b);this.element.setAttributes({role:this.attributes.role||\"presentation\",\"aria-label\":this.attributes[\"aria-label\"],title:this.attributes.title||\nthis.attributes[\"aria-label\"]});this.keys={};this._.focusIndex=-1;this.element.disableContextMenu()},_:{markItem:function(a){-1!=a&&(a=this._.getItems().getItem(this._.focusIndex=a),CKEDITOR.env.webkit&&a.getDocument().getWindow().focus(),a.focus(),this.onMark&&this.onMark(a))},markFirstDisplayed:function(a){for(var b=function(a){return a.type==CKEDITOR.NODE_ELEMENT&&\"none\"==a.getStyle(\"display\")},f=this._.getItems(),k,g,h=f.count()-1;0<=h;h--)if(k=f.getItem(h),k.getAscendant(b)||(g=k,this._.focusIndex=\nh),\"true\"==k.getAttribute(\"aria-selected\")){g=k;this._.focusIndex=h;break}g&&(a&&a(),CKEDITOR.env.webkit&&g.getDocument().getWindow().focus(),g.focus(),this.onMark&&this.onMark(g))},getItems:function(){return this.element.find(\"a,input\")}},proto:{show:function(){this.element.setStyle(\"display\",\"\")},hide:function(){this.onHide&&!0===this.onHide.call(this)||this.element.setStyle(\"display\",\"none\")},onKeyDown:function(a,b){var f=this.keys[a];switch(f){case \"next\":for(var k=this._.focusIndex,f=this._.getItems(),\ng;g=f.getItem(++k);)if(g.getAttribute(\"_cke_focus\")&&g.$.offsetWidth){this._.focusIndex=k;g.focus(!0);break}return g||b?!1:(this._.focusIndex=-1,this.onKeyDown(a,1));case \"prev\":k=this._.focusIndex;for(f=this._.getItems();0<k&&(g=f.getItem(--k));){if(g.getAttribute(\"_cke_focus\")&&g.$.offsetWidth){this._.focusIndex=k;g.focus(!0);break}g=null}return g||b?!1:(this._.focusIndex=f.count(),this.onKeyDown(a,1));case \"click\":case \"mouseup\":return k=this._.focusIndex,(g=0<=k&&this._.getItems().getItem(k))&&\n(g.$[f]?g.$[f]():g.$[\"on\"+f]()),!1}return!0}}})}(),CKEDITOR.plugins.add(\"floatpanel\",{requires:\"panel\"}),function(){function a(a,c,d,l,k){k=CKEDITOR.tools.genKey(c.getUniqueId(),d.getUniqueId(),a.lang.dir,a.uiColor||\"\",l.css||\"\",k||\"\");var g=f[k];g||(g=f[k]=new CKEDITOR.ui.panel(c,l),g.element=d.append(CKEDITOR.dom.element.createFromHtml(g.render(a),c)),g.element.setStyles({display:\"none\",position:\"absolute\"}));return g}var f={};CKEDITOR.ui.floatPanel=CKEDITOR.tools.createClass({$:function(b,c,d,\nf){function k(){e.hide()}d.forceIFrame=1;d.toolbarRelated&&b.elementMode==CKEDITOR.ELEMENT_MODE_INLINE&&(c=CKEDITOR.document.getById(\"cke_\"+b.name));var g=c.getDocument();f=a(b,g,c,d,f||0);var h=f.element,m=h.getFirst(),e=this;h.disableContextMenu();this.element=h;this._={editor:b,panel:f,parentElement:c,definition:d,document:g,iframe:m,children:[],dir:b.lang.dir,showBlockParams:null,markFirst:void 0!==d.markFirst?d.markFirst:!0};b.on(\"mode\",k);b.on(\"resize\",k);g.getWindow().on(\"resize\",function(){this.reposition()},\nthis)},proto:{addBlock:function(a,c){return this._.panel.addBlock(a,c)},addListBlock:function(a,c){return this._.panel.addListBlock(a,c)},getBlock:function(a){return this._.panel.getBlock(a)},showBlock:function(a,c,d,f,k,g){var h=this._.panel,m=h.showBlock(a);this._.showBlockParams=[].slice.call(arguments);this.allowBlur(!1);var e=this._.editor.editable();this._.returnFocus=e.hasFocus?e:new CKEDITOR.dom.element(CKEDITOR.document.$.activeElement);this._.hideTimeout=0;var n=this.element,e=this._.iframe,\ne=CKEDITOR.env.ie&&!CKEDITOR.env.edge?e:new CKEDITOR.dom.window(e.$.contentWindow),q=n.getDocument(),y=this._.parentElement.getPositionedAncestor(),u=c.getDocumentPosition(q),q=y?y.getDocumentPosition(q):{x:0,y:0},p=\"rtl\"==this._.dir,v=u.x+(f||0)-q.x,w=u.y+(k||0)-q.y;!p||1!=d&&4!=d?p||2!=d&&3!=d||(v+=c.$.offsetWidth-1):v+=c.$.offsetWidth;if(3==d||4==d)w+=c.$.offsetHeight-1;this._.panel._.offsetParentId=c.getId();n.setStyles({top:w+\"px\",left:0,display:\"\"});n.setOpacity(0);n.getFirst().removeStyle(\"width\");\nthis._.editor.focusManager.add(e);this._.blurSet||(CKEDITOR.event.useCapture=!0,e.on(\"blur\",function(a){function b(){delete this._.returnFocus;this.hide()}this.allowBlur()&&a.data.getPhase()==CKEDITOR.EVENT_PHASE_AT_TARGET&&this.visible&&!this._.activeChild&&(CKEDITOR.env.iOS?this._.hideTimeout||(this._.hideTimeout=CKEDITOR.tools.setTimeout(b,0,this)):b.call(this))},this),e.on(\"focus\",function(){this._.focused=!0;this.hideChild();this.allowBlur(!0)},this),CKEDITOR.env.iOS&&(e.on(\"touchstart\",function(){clearTimeout(this._.hideTimeout)},\nthis),e.on(\"touchend\",function(){this._.hideTimeout=0;this.focus()},this)),CKEDITOR.event.useCapture=!1,this._.blurSet=1);h.onEscape=CKEDITOR.tools.bind(function(a){if(this.onEscape&&!1===this.onEscape(a))return!1},this);CKEDITOR.tools.setTimeout(function(){var a=CKEDITOR.tools.bind(function(){var a=n;a.removeStyle(\"width\");if(m.autoSize){var b=m.element.getDocument(),b=(CKEDITOR.env.webkit||CKEDITOR.env.edge?m.element:b.getBody()).$.scrollWidth;CKEDITOR.env.ie&&CKEDITOR.env.quirks&&0<b&&(b+=(a.$.offsetWidth||\n0)-(a.$.clientWidth||0)+3);a.setStyle(\"width\",b+10+\"px\");b=m.element.$.scrollHeight;CKEDITOR.env.ie&&CKEDITOR.env.quirks&&0<b&&(b+=(a.$.offsetHeight||0)-(a.$.clientHeight||0)+3);a.setStyle(\"height\",b+\"px\");h._.currentBlock.element.setStyle(\"display\",\"none\").removeStyle(\"display\")}else a.removeStyle(\"height\");p&&(v-=n.$.offsetWidth);n.setStyle(\"left\",v+\"px\");var b=h.element.getWindow(),a=n.$.getBoundingClientRect(),b=b.getViewPaneSize(),c=a.width||a.right-a.left,d=a.height||a.bottom-a.top,e=p?a.right:\nb.width-a.left,f=p?b.width-a.right:a.left;p?e<c&&(v=f>c?v+c:b.width>c?v-a.left:v-a.right+b.width):e<c&&(v=f>c?v-c:b.width>c?v-a.right+b.width:v-a.left);c=a.top;b.height-a.top<d&&(w=c>d?w-d:b.height>d?w-a.bottom+b.height:w-a.top);CKEDITOR.env.ie&&!CKEDITOR.env.edge&&(b=a=new CKEDITOR.dom.element(n.$.offsetParent),\"html\"==b.getName()&&(b=b.getDocument().getBody()),\"rtl\"==b.getComputedStyle(\"direction\")&&(v=CKEDITOR.env.ie8Compat?v-2*n.getDocument().getDocumentElement().$.scrollLeft:v-(a.$.scrollWidth-\na.$.clientWidth)));var a=n.getFirst(),k;(k=a.getCustomData(\"activePanel\"))&&k.onHide&&k.onHide.call(this,1);a.setCustomData(\"activePanel\",this);n.setStyles({top:w+\"px\",left:v+\"px\"});n.setOpacity(1);g&&g()},this);h.isLoaded?a():h.onLoad=a;CKEDITOR.tools.setTimeout(function(){var a=CKEDITOR.env.webkit&&CKEDITOR.document.getWindow().getScrollPosition().y;this.focus();m.element.focus();CKEDITOR.env.webkit&&(CKEDITOR.document.getBody().$.scrollTop=a);this.allowBlur(!0);this._.markFirst&&(CKEDITOR.env.ie?\nCKEDITOR.tools.setTimeout(function(){m.markFirstDisplayed?m.markFirstDisplayed():m._.markFirstDisplayed()},0):m.markFirstDisplayed?m.markFirstDisplayed():m._.markFirstDisplayed());this._.editor.fire(\"panelShow\",this)},0,this)},CKEDITOR.env.air?200:0,this);this.visible=1;this.onShow&&this.onShow.call(this)},reposition:function(){var a=this._.showBlockParams;this.visible&&this._.showBlockParams&&(this.hide(),this.showBlock.apply(this,a))},focus:function(){if(CKEDITOR.env.webkit){var a=CKEDITOR.document.getActive();\na&&!a.equals(this._.iframe)&&a.$.blur()}(this._.lastFocused||this._.iframe.getFrameDocument().getWindow()).focus()},blur:function(){var a=this._.iframe.getFrameDocument().getActive();a&&a.is(\"a\")&&(this._.lastFocused=a)},hide:function(a){if(this.visible&&(!this.onHide||!0!==this.onHide.call(this))){this.hideChild();CKEDITOR.env.gecko&&this._.iframe.getFrameDocument().$.activeElement.blur();this.element.setStyle(\"display\",\"none\");this.visible=0;this.element.getFirst().removeCustomData(\"activePanel\");\nif(a=a&&this._.returnFocus)CKEDITOR.env.webkit&&a.type&&a.getWindow().$.focus(),a.focus();delete this._.lastFocused;this._.showBlockParams=null;this._.editor.fire(\"panelHide\",this)}},allowBlur:function(a){var c=this._.panel;void 0!==a&&(c.allowBlur=a);return c.allowBlur},showAsChild:function(a,c,d,f,k,g){if(this._.activeChild!=a||a._.panel._.offsetParentId!=d.getId())this.hideChild(),a.onHide=CKEDITOR.tools.bind(function(){CKEDITOR.tools.setTimeout(function(){this._.focused||this.hide()},0,this)},\nthis),this._.activeChild=a,this._.focused=!1,a.showBlock(c,d,f,k,g),this.blur(),(CKEDITOR.env.ie7Compat||CKEDITOR.env.ie6Compat)&&setTimeout(function(){a.element.getChild(0).$.style.cssText+=\"\"},100)},hideChild:function(a){var c=this._.activeChild;c&&(delete c.onHide,delete this._.activeChild,c.hide(),a&&this.focus())}}});CKEDITOR.on(\"instanceDestroyed\",function(){var a=CKEDITOR.tools.isEmpty(CKEDITOR.instances),c;for(c in f){var d=f[c];a?d.destroy():d.element.hide()}a&&(f={})})}(),CKEDITOR.plugins.add(\"menu\",\n{requires:\"floatpanel\",beforeInit:function(a){for(var f=a.config.menu_groups.split(\",\"),b=a._.menuGroups={},c=a._.menuItems={},d=0;d<f.length;d++)b[f[d]]=d+1;a.addMenuGroup=function(a,c){b[a]=c||100};a.addMenuItem=function(a,d){b[d.group]&&(c[a]=new CKEDITOR.menuItem(this,a,d))};a.addMenuItems=function(a){for(var b in a)this.addMenuItem(b,a[b])};a.getMenuItem=function(a){return c[a]};a.removeMenuItem=function(a){delete c[a]}}}),function(){function a(a){a.sort(function(a,b){return a.group<b.group?\n-1:a.group>b.group?1:a.order<b.order?-1:a.order>b.order?1:0})}var f='\\x3cspan class\\x3d\"cke_menuitem\"\\x3e\\x3ca id\\x3d\"{id}\" class\\x3d\"cke_menubutton cke_menubutton__{name} cke_menubutton_{state} {cls}\" href\\x3d\"{href}\" title\\x3d\"{title}\" tabindex\\x3d\"-1\" _cke_focus\\x3d1 hidefocus\\x3d\"true\" role\\x3d\"{role}\" aria-label\\x3d\"{label}\" aria-describedby\\x3d\"{id}_description\" aria-haspopup\\x3d\"{hasPopup}\" aria-disabled\\x3d\"{disabled}\" {ariaChecked} draggable\\x3d\"false\"';CKEDITOR.env.gecko&&CKEDITOR.env.mac&&\n(f+=' onkeypress\\x3d\"return false;\"');CKEDITOR.env.gecko&&(f+=' onblur\\x3d\"this.style.cssText \\x3d this.style.cssText;\" ondragstart\\x3d\"return false;\"');var f=f+(' onmouseover\\x3d\"CKEDITOR.tools.callFunction({hoverFn},{index});\" onmouseout\\x3d\"CKEDITOR.tools.callFunction({moveOutFn},{index});\" '+(CKEDITOR.env.ie?'onclick\\x3d\"return false;\" onmouseup':\"onclick\")+'\\x3d\"CKEDITOR.tools.callFunction({clickFn},{index}); return false;\"\\x3e'),b=CKEDITOR.addTemplate(\"menuItem\",f+'\\x3cspan class\\x3d\"cke_menubutton_inner\"\\x3e\\x3cspan class\\x3d\"cke_menubutton_icon\"\\x3e\\x3cspan class\\x3d\"cke_button_icon cke_button__{iconName}_icon\" style\\x3d\"{iconStyle}\"\\x3e\\x3c/span\\x3e\\x3c/span\\x3e\\x3cspan class\\x3d\"cke_menubutton_label\"\\x3e{label}\\x3c/span\\x3e{shortcutHtml}{arrowHtml}\\x3c/span\\x3e\\x3c/a\\x3e\\x3cspan id\\x3d\"{id}_description\" class\\x3d\"cke_voice_label\" aria-hidden\\x3d\"false\"\\x3e{ariaShortcut}\\x3c/span\\x3e\\x3c/span\\x3e'),\nc=CKEDITOR.addTemplate(\"menuArrow\",'\\x3cspan class\\x3d\"cke_menuarrow\"\\x3e\\x3cspan\\x3e{label}\\x3c/span\\x3e\\x3c/span\\x3e'),d=CKEDITOR.addTemplate(\"menuShortcut\",'\\x3cspan class\\x3d\"cke_menubutton_label cke_menubutton_shortcut\"\\x3e{shortcut}\\x3c/span\\x3e');CKEDITOR.menu=CKEDITOR.tools.createClass({$:function(a,b){b=this._.definition=b||{};this.id=CKEDITOR.tools.getNextId();this.editor=a;this.items=[];this._.listeners=[];this._.level=b.level||1;var c=CKEDITOR.tools.extend({},b.panel,{css:[CKEDITOR.skin.getPath(\"editor\")],\nlevel:this._.level-1,block:{}}),d=c.block.attributes=c.attributes||{};!d.role&&(d.role=\"menu\");this._.panelDefinition=c},_:{onShow:function(){var a=this.editor.getSelection(),b=a&&a.getStartElement(),c=this.editor.elementPath(),d=this._.listeners;this.removeAll();for(var f=0;f<d.length;f++){var e=d[f](b,a,c);if(e)for(var n in e){var q=this.editor.getMenuItem(n);!q||q.command&&!this.editor.getCommand(q.command).state||(q.state=e[n],this.add(q))}}},onClick:function(a){this.hide();if(a.onClick)a.onClick();\nelse a.command&&this.editor.execCommand(a.command)},onEscape:function(a){var b=this.parent;b?b._.panel.hideChild(1):27==a&&this.hide(1);return!1},onHide:function(){this.onHide&&this.onHide()},showSubMenu:function(a){var b=this._.subMenu,c=this.items[a];if(c=c.getItems&&c.getItems()){b?b.removeAll():(b=this._.subMenu=new CKEDITOR.menu(this.editor,CKEDITOR.tools.extend({},this._.definition,{level:this._.level+1},!0)),b.parent=this,b._.onClick=CKEDITOR.tools.bind(this._.onClick,this));for(var d in c){var f=\nthis.editor.getMenuItem(d);f&&(f.state=c[d],b.add(f))}var e=this._.panel.getBlock(this.id).element.getDocument().getById(this.id+String(a));setTimeout(function(){b.show(e,2)},0)}else this._.panel.hideChild(1)}},proto:{add:function(a){a.order||(a.order=this.items.length);this.items.push(a)},removeAll:function(){this.items=[]},show:function(b,c,d,f){if(!this.parent&&(this._.onShow(),!this.items.length))return;c=c||(\"rtl\"==this.editor.lang.dir?2:1);var m=this.items,e=this.editor,n=this._.panel,q=this._.element;\nif(!n){n=this._.panel=new CKEDITOR.ui.floatPanel(this.editor,CKEDITOR.document.getBody(),this._.panelDefinition,this._.level);n.onEscape=CKEDITOR.tools.bind(function(a){if(!1===this._.onEscape(a))return!1},this);n.onShow=function(){n._.panel.getHolderElement().getParent().addClass(\"cke\").addClass(\"cke_reset_all\")};n.onHide=CKEDITOR.tools.bind(function(){this._.onHide&&this._.onHide()},this);q=n.addBlock(this.id,this._.panelDefinition.block);q.autoSize=!0;var y=q.keys;y[40]=\"next\";y[9]=\"next\";y[38]=\n\"prev\";y[CKEDITOR.SHIFT+9]=\"prev\";y[\"rtl\"==e.lang.dir?37:39]=CKEDITOR.env.ie?\"mouseup\":\"click\";y[32]=CKEDITOR.env.ie?\"mouseup\":\"click\";CKEDITOR.env.ie&&(y[13]=\"mouseup\");q=this._.element=q.element;y=q.getDocument();y.getBody().setStyle(\"overflow\",\"hidden\");y.getElementsByTag(\"html\").getItem(0).setStyle(\"overflow\",\"hidden\");this._.itemOverFn=CKEDITOR.tools.addFunction(function(a){clearTimeout(this._.showSubTimeout);this._.showSubTimeout=CKEDITOR.tools.setTimeout(this._.showSubMenu,e.config.menu_subMenuDelay||\n400,this,[a])},this);this._.itemOutFn=CKEDITOR.tools.addFunction(function(){clearTimeout(this._.showSubTimeout)},this);this._.itemClickFn=CKEDITOR.tools.addFunction(function(a){var b=this.items[a];if(b.state==CKEDITOR.TRISTATE_DISABLED)this.hide(1);else if(b.getItems)this._.showSubMenu(a);else this._.onClick(b)},this)}a(m);for(var y=e.elementPath(),y=['\\x3cdiv class\\x3d\"cke_menu'+(y&&y.direction()!=e.lang.dir?\" cke_mixed_dir_content\":\"\")+'\" role\\x3d\"presentation\"\\x3e'],u=m.length,p=u&&m[0].group,\nv=0;v<u;v++){var w=m[v];p!=w.group&&(y.push('\\x3cdiv class\\x3d\"cke_menuseparator\" role\\x3d\"separator\"\\x3e\\x3c/div\\x3e'),p=w.group);w.render(this,v,y)}y.push(\"\\x3c/div\\x3e\");q.setHtml(y.join(\"\"));CKEDITOR.ui.fire(\"ready\",this);this.parent?this.parent._.panel.showAsChild(n,this.id,b,c,d,f):n.showBlock(this.id,b,c,d,f);e.fire(\"menuShow\",[n])},addListener:function(a){this._.listeners.push(a)},hide:function(a){this._.onHide&&this._.onHide();this._.panel&&this._.panel.hide(a)},findItemByCommandName:function(a){var b=\nCKEDITOR.tools.array.filter(this.items,function(b){return a===b.command});return b.length?(b=b[0],{item:b,element:this._.element.findOne(\".\"+b.className)}):null}}});CKEDITOR.menuItem=CKEDITOR.tools.createClass({$:function(a,b,c){CKEDITOR.tools.extend(this,c,{order:0,className:\"cke_menubutton__\"+b});this.group=a._.menuGroups[this.group];this.editor=a;this.name=b},proto:{render:function(a,f,g){var h=a.id+String(f),m=\"undefined\"==typeof this.state?CKEDITOR.TRISTATE_OFF:this.state,e=\"\",n=this.editor,\nq,y,u=m==CKEDITOR.TRISTATE_ON?\"on\":m==CKEDITOR.TRISTATE_DISABLED?\"disabled\":\"off\";this.role in{menuitemcheckbox:1,menuitemradio:1}&&(e=' aria-checked\\x3d\"'+(m==CKEDITOR.TRISTATE_ON?\"true\":\"false\")+'\"');var p=this.getItems,v=\"\\x26#\"+(\"rtl\"==this.editor.lang.dir?\"9668\":\"9658\")+\";\",w=this.name;this.icon&&!/\\./.test(this.icon)&&(w=this.icon);this.command&&(q=n.getCommand(this.command),(q=n.getCommandKeystroke(q))&&(y=CKEDITOR.tools.keystrokeToString(n.lang.common.keyboard,q)));a={id:h,name:this.name,\niconName:w,label:this.label,cls:this.className||\"\",state:u,hasPopup:p?\"true\":\"false\",disabled:m==CKEDITOR.TRISTATE_DISABLED,title:this.label+(y?\" (\"+y.display+\")\":\"\"),ariaShortcut:y?n.lang.common.keyboardShortcut+\" \"+y.aria:\"\",href:\"javascript:void('\"+(this.label||\"\").replace(\"'\")+\"')\",hoverFn:a._.itemOverFn,moveOutFn:a._.itemOutFn,clickFn:a._.itemClickFn,index:f,iconStyle:CKEDITOR.skin.getIconStyle(w,\"rtl\"==this.editor.lang.dir,w==this.icon?null:this.icon,this.iconOffset),shortcutHtml:y?d.output({shortcut:y.display}):\n\"\",arrowHtml:p?c.output({label:v}):\"\",role:this.role?this.role:\"menuitem\",ariaChecked:e};b.output(a,g)}}})}(),CKEDITOR.config.menu_groups=\"clipboard,form,tablecell,tablecellproperties,tablerow,tablecolumn,table,anchor,link,image,flash,checkbox,radio,textfield,hiddenfield,imagebutton,button,select,textarea,div\",CKEDITOR.plugins.add(\"contextmenu\",{requires:\"menu\",onLoad:function(){CKEDITOR.plugins.contextMenu=CKEDITOR.tools.createClass({base:CKEDITOR.menu,$:function(a){this.base.call(this,a,{panel:{css:a.config.contextmenu_contentsCss,\nclassName:\"cke_menu_panel\",attributes:{\"aria-label\":a.lang.contextmenu.options}}})},proto:{addTarget:function(a,f){function b(){d=!1}var c,d;a.on(\"contextmenu\",function(a){a=a.data;var b=CKEDITOR.env.webkit?c:CKEDITOR.env.mac?a.$.metaKey:a.$.ctrlKey;if(!f||!b)if(a.preventDefault(),!d){if(CKEDITOR.env.mac&&CKEDITOR.env.webkit){var b=this.editor,h=(new CKEDITOR.dom.elementPath(a.getTarget(),b.editable())).contains(function(a){return a.hasAttribute(\"contenteditable\")},!0);h&&\"false\"==h.getAttribute(\"contenteditable\")&&\nb.getSelection().fake(h)}var h=a.getTarget().getDocument(),m=a.getTarget().getDocument().getDocumentElement(),b=!h.equals(CKEDITOR.document),h=h.getWindow().getScrollPosition(),e=b?a.$.clientX:a.$.pageX||h.x+a.$.clientX,l=b?a.$.clientY:a.$.pageY||h.y+a.$.clientY;CKEDITOR.tools.setTimeout(function(){this.open(m,null,e,l)},CKEDITOR.env.ie?200:0,this)}},this);if(CKEDITOR.env.webkit){var l=function(){c=0};a.on(\"keydown\",function(a){c=CKEDITOR.env.mac?a.data.$.metaKey:a.data.$.ctrlKey});a.on(\"keyup\",l);\na.on(\"contextmenu\",l)}CKEDITOR.env.gecko&&!CKEDITOR.env.mac&&(a.on(\"keydown\",function(a){a.data.$.shiftKey&&121===a.data.$.keyCode&&(d=!0)},null,null,0),a.on(\"keyup\",b),a.on(\"contextmenu\",b))},open:function(a,f,b,c){!1!==this.editor.config.enableContextMenu&&this.editor.getSelection().getType()!==CKEDITOR.SELECTION_NONE&&(this.editor.focus(),a=a||CKEDITOR.document.getDocumentElement(),this.editor.selectionChange(1),this.show(a,f,b,c))}}})},beforeInit:function(a){var f=a.contextMenu=new CKEDITOR.plugins.contextMenu(a);\na.on(\"contentDom\",function(){f.addTarget(a.editable(),!1!==a.config.browserContextMenuOnCtrl)});a.addCommand(\"contextMenu\",{exec:function(a){var c=0,d=0,f=a.getSelection().getRanges(),f=f[f.length-1].getClientRects(a.editable().isInline());if(f=f[f.length-1])c=f[\"rtl\"===a.lang.dir?\"left\":\"right\"],d=f.bottom;a.contextMenu.open(a.document.getBody().getParent(),null,c,d)}});a.setKeystroke(CKEDITOR.SHIFT+121,\"contextMenu\");a.setKeystroke(CKEDITOR.CTRL+CKEDITOR.SHIFT+121,\"contextMenu\")}}),function(){function a(a,\nb){function k(b){b=e.list[b];var c;b.equals(a.editable())||\"true\"==b.getAttribute(\"contenteditable\")?(c=a.createRange(),c.selectNodeContents(b),c=c.select()):(c=a.getSelection(),c.selectElement(b));CKEDITOR.env.ie&&a.fire(\"selectionChange\",{selection:c,path:new CKEDITOR.dom.elementPath(b)});a.focus()}function g(){m&&m.setHtml('\\x3cspan class\\x3d\"cke_path_empty\"\\x3e\\x26nbsp;\\x3c/span\\x3e');delete e.list}var h=a.ui.spaceId(\"path\"),m,e=a._.elementsPath,n=e.idBase;b.html+='\\x3cspan id\\x3d\"'+h+'_label\" class\\x3d\"cke_voice_label\"\\x3e'+\na.lang.elementspath.eleLabel+'\\x3c/span\\x3e\\x3cspan id\\x3d\"'+h+'\" class\\x3d\"cke_path\" role\\x3d\"group\" aria-labelledby\\x3d\"'+h+'_label\"\\x3e\\x3cspan class\\x3d\"cke_path_empty\"\\x3e\\x26nbsp;\\x3c/span\\x3e\\x3c/span\\x3e';a.on(\"uiReady\",function(){var b=a.ui.space(\"path\");b&&a.focusManager.add(b,1)});e.onClick=k;var q=CKEDITOR.tools.addFunction(k),y=CKEDITOR.tools.addFunction(function(b,c){var g=e.idBase,f;c=new CKEDITOR.dom.event(c);f=\"rtl\"==a.lang.dir;switch(c.getKeystroke()){case f?39:37:case 9:return(f=\nCKEDITOR.document.getById(g+(b+1)))||(f=CKEDITOR.document.getById(g+\"0\")),f.focus(),!1;case f?37:39:case CKEDITOR.SHIFT+9:return(f=CKEDITOR.document.getById(g+(b-1)))||(f=CKEDITOR.document.getById(g+(e.list.length-1))),f.focus(),!1;case 27:return a.focus(),!1;case 13:case 32:return k(b),!1}return!0});a.on(\"selectionChange\",function(b){for(var g=[],f=e.list=[],k=[],l=e.filters,z=!0,t=b.data.path.elements,x=t.length;x--;){var A=t[x],B=0;b=A.data(\"cke-display-name\")?A.data(\"cke-display-name\"):A.data(\"cke-real-element-type\")?\nA.data(\"cke-real-element-type\"):A.getName();(z=A.hasAttribute(\"contenteditable\")?\"true\"==A.getAttribute(\"contenteditable\"):z)||A.hasAttribute(\"contenteditable\")||(B=1);for(var C=0;C<l.length;C++){var H=l[C](A,b);if(!1===H){B=1;break}b=H||b}B||(f.unshift(A),k.unshift(b))}f=f.length;for(l=0;l<f;l++)b=k[l],z=a.lang.elementspath.eleTitle.replace(/%1/,b),b=c.output({id:n+l,label:z,text:b,jsTitle:\"javascript:void('\"+b+\"')\",index:l,keyDownFn:y,clickFn:q}),g.unshift(b);m||(m=CKEDITOR.document.getById(h));\nk=m;k.setHtml(g.join(\"\")+'\\x3cspan class\\x3d\"cke_path_empty\"\\x3e\\x26nbsp;\\x3c/span\\x3e');a.fire(\"elementsPathUpdate\",{space:k})});a.on(\"readOnly\",g);a.on(\"contentDomUnload\",g);a.addCommand(\"elementsPathFocus\",f.toolbarFocus);a.setKeystroke(CKEDITOR.ALT+122,\"elementsPathFocus\")}var f={toolbarFocus:{editorFocus:!1,readOnly:1,exec:function(a){(a=CKEDITOR.document.getById(a._.elementsPath.idBase+\"0\"))&&a.focus(CKEDITOR.env.ie||CKEDITOR.env.air)}}},b=\"\";CKEDITOR.env.gecko&&CKEDITOR.env.mac&&(b+=' onkeypress\\x3d\"return false;\"');\nCKEDITOR.env.gecko&&(b+=' onblur\\x3d\"this.style.cssText \\x3d this.style.cssText;\"');var c=CKEDITOR.addTemplate(\"pathItem\",'\\x3ca id\\x3d\"{id}\" href\\x3d\"{jsTitle}\" tabindex\\x3d\"-1\" class\\x3d\"cke_path_item\" title\\x3d\"{label}\"'+b+' hidefocus\\x3d\"true\"  draggable\\x3d\"false\"  ondragstart\\x3d\"return false;\" onkeydown\\x3d\"return CKEDITOR.tools.callFunction({keyDownFn},{index}, event );\" onclick\\x3d\"CKEDITOR.tools.callFunction({clickFn},{index}); return false;\" role\\x3d\"button\" aria-label\\x3d\"{label}\"\\x3e{text}\\x3c/a\\x3e');\nCKEDITOR.plugins.add(\"elementspath\",{init:function(b){b._.elementsPath={idBase:\"cke_elementspath_\"+CKEDITOR.tools.getNextNumber()+\"_\",filters:[]};b.on(\"uiSpace\",function(c){\"bottom\"==c.data.space&&a(b,c.data)})}})}(),function(){function a(a,d){var l,k;d.on(\"refresh\",function(a){var c=[f],d;for(d in a.data.states)c.push(a.data.states[d]);this.setState(CKEDITOR.tools.search(c,b)?b:f)},d,null,100);d.on(\"exec\",function(b){l=a.getSelection();k=l.createBookmarks(1);b.data||(b.data={});b.data.done=!1},d,\nnull,0);d.on(\"exec\",function(){a.forceNextSelectionCheck();l.selectBookmarks(k)},d,null,100)}var f=CKEDITOR.TRISTATE_DISABLED,b=CKEDITOR.TRISTATE_OFF;CKEDITOR.plugins.add(\"indent\",{init:function(b){var d=CKEDITOR.plugins.indent.genericDefinition;a(b,b.addCommand(\"indent\",new d(!0)));a(b,b.addCommand(\"outdent\",new d));b.ui.addButton&&(b.ui.addButton(\"Indent\",{label:b.lang.indent.indent,command:\"indent\",directional:!0,toolbar:\"indent,20\"}),b.ui.addButton(\"Outdent\",{label:b.lang.indent.outdent,command:\"outdent\",\ndirectional:!0,toolbar:\"indent,10\"}));b.on(\"dirChanged\",function(a){var d=b.createRange(),g=a.data.node;d.setStartBefore(g);d.setEndAfter(g);for(var f=new CKEDITOR.dom.walker(d),m;m=f.next();)if(m.type==CKEDITOR.NODE_ELEMENT)if(!m.equals(g)&&m.getDirection())d.setStartAfter(m),f=new CKEDITOR.dom.walker(d);else{var e=b.config.indentClasses;if(e)for(var n=\"ltr\"==a.data.dir?[\"_rtl\",\"\"]:[\"\",\"_rtl\"],q=0;q<e.length;q++)m.hasClass(e[q]+n[0])&&(m.removeClass(e[q]+n[0]),m.addClass(e[q]+n[1]));e=m.getStyle(\"margin-right\");\nn=m.getStyle(\"margin-left\");e?m.setStyle(\"margin-left\",e):m.removeStyle(\"margin-left\");n?m.setStyle(\"margin-right\",n):m.removeStyle(\"margin-right\")}})}});CKEDITOR.plugins.indent={genericDefinition:function(a){this.isIndent=!!a;this.startDisabled=!this.isIndent},specificDefinition:function(a,b,f){this.name=b;this.editor=a;this.jobs={};this.enterBr=a.config.enterMode==CKEDITOR.ENTER_BR;this.isIndent=!!f;this.relatedGlobal=f?\"indent\":\"outdent\";this.indentKey=f?9:CKEDITOR.SHIFT+9;this.database={}},registerCommands:function(a,\nb){a.on(\"pluginsLoaded\",function(){for(var a in b)(function(a,b){var c=a.getCommand(b.relatedGlobal),d;for(d in b.jobs)c.on(\"exec\",function(c){c.data.done||(a.fire(\"lockSnapshot\"),b.execJob(a,d)&&(c.data.done=!0),a.fire(\"unlockSnapshot\"),CKEDITOR.dom.element.clearAllMarkers(b.database))},this,null,d),c.on(\"refresh\",function(c){c.data.states||(c.data.states={});c.data.states[b.name+\"@\"+d]=b.refreshJob(a,d,c.data.path)},this,null,d);a.addFeature(b)})(this,b[a])})}};CKEDITOR.plugins.indent.genericDefinition.prototype=\n{context:\"p\",exec:function(){}};CKEDITOR.plugins.indent.specificDefinition.prototype={execJob:function(a,b){var l=this.jobs[b];if(l.state!=f)return l.exec.call(this,a)},refreshJob:function(a,b,l){b=this.jobs[b];a.activeFilter.checkFeature(this)?b.state=b.refresh.call(this,a,l):b.state=f;return b.state},getContext:function(a){return a.contains(this.context)}}}(),function(){function a(a){function c(f){for(var h=l.startContainer,r=l.endContainer;h&&!h.getParent().equals(f);)h=h.getParent();for(;r&&!r.getParent().equals(f);)r=\nr.getParent();if(!h||!r)return!1;for(var z=[],t=!1;!t;)h.equals(r)&&(t=!0),z.push(h),h=h.getNext();if(1>z.length)return!1;h=f.getParents(!0);for(r=0;r<h.length;r++)if(h[r].getName&&k[h[r].getName()]){f=h[r];break}for(var h=d.isIndent?1:-1,r=z[0],z=z[z.length-1],t=CKEDITOR.plugins.list.listToArray(f,e),x=t[z.getCustomData(\"listarray_index\")].indent,r=r.getCustomData(\"listarray_index\");r<=z.getCustomData(\"listarray_index\");r++)if(t[r].indent+=h,0<h){for(var A=t[r].parent,B=r-1;0<=B;B--)if(t[B].indent===\nh){A=t[B].parent;break}t[r].parent=new CKEDITOR.dom.element(A.getName(),A.getDocument())}for(r=z.getCustomData(\"listarray_index\")+1;r<t.length&&t[r].indent>x;r++)t[r].indent+=h;h=CKEDITOR.plugins.list.arrayToList(t,e,null,a.config.enterMode,f.getDirection());if(!d.isIndent){var C;if((C=f.getParent())&&C.is(\"li\"))for(var z=h.listNode.getChildren(),u=[],p,r=z.count()-1;0<=r;r--)(p=z.getItem(r))&&p.is&&p.is(\"li\")&&u.push(p)}h&&h.listNode.replace(f);if(u&&u.length)for(r=0;r<u.length;r++){for(p=f=u[r];(p=\np.getNext())&&p.is&&p.getName()in k;)CKEDITOR.env.needsNbspFiller&&!f.getFirst(b)&&f.append(l.document.createText(\" \")),f.append(p);f.insertAfter(C)}h&&a.fire(\"contentDomInvalidated\");return!0}for(var d=this,e=this.database,k=this.context,l,y=a.getSelection(),y=(y&&y.getRanges()).createIterator();l=y.getNextRange();){for(var u=l.getCommonAncestor();u&&(u.type!=CKEDITOR.NODE_ELEMENT||!k[u.getName()]);){if(a.editable().equals(u)){u=!1;break}u=u.getParent()}u||(u=l.startPath().contains(k))&&l.setEndAt(u,\nCKEDITOR.POSITION_BEFORE_END);if(!u){var p=l.getEnclosedNode();p&&p.type==CKEDITOR.NODE_ELEMENT&&p.getName()in k&&(l.setStartAt(p,CKEDITOR.POSITION_AFTER_START),l.setEndAt(p,CKEDITOR.POSITION_BEFORE_END),u=p)}u&&l.startContainer.type==CKEDITOR.NODE_ELEMENT&&l.startContainer.getName()in k&&(p=new CKEDITOR.dom.walker(l),p.evaluator=f,l.startContainer=p.next());u&&l.endContainer.type==CKEDITOR.NODE_ELEMENT&&l.endContainer.getName()in k&&(p=new CKEDITOR.dom.walker(l),p.evaluator=f,l.endContainer=p.previous());\nif(u)return c(u)}return 0}function f(a){return a.type==CKEDITOR.NODE_ELEMENT&&a.is(\"li\")}function b(a){return c(a)&&d(a)}var c=CKEDITOR.dom.walker.whitespaces(!0),d=CKEDITOR.dom.walker.bookmark(!1,!0),l=CKEDITOR.TRISTATE_DISABLED,k=CKEDITOR.TRISTATE_OFF;CKEDITOR.plugins.add(\"indentlist\",{requires:\"indent\",init:function(b){function c(b){d.specificDefinition.apply(this,arguments);this.requiredContent=[\"ul\",\"ol\"];b.on(\"key\",function(a){var c=b.elementPath();if(\"wysiwyg\"==b.mode&&a.data.keyCode==this.indentKey&&\nc){var d=this.getContext(c);!d||this.isIndent&&CKEDITOR.plugins.indentList.firstItemInPath(this.context,c,d)||(b.execCommand(this.relatedGlobal),a.cancel())}},this);this.jobs[this.isIndent?10:30]={refresh:this.isIndent?function(a,b){var c=this.getContext(b),d=CKEDITOR.plugins.indentList.firstItemInPath(this.context,b,c);return c&&this.isIndent&&!d?k:l}:function(a,b){return!this.getContext(b)||this.isIndent?l:k},exec:CKEDITOR.tools.bind(a,this)}}var d=CKEDITOR.plugins.indent;d.registerCommands(b,{indentlist:new c(b,\n\"indentlist\",!0),outdentlist:new c(b,\"outdentlist\")});CKEDITOR.tools.extend(c.prototype,d.specificDefinition.prototype,{context:{ol:1,ul:1}})}});CKEDITOR.plugins.indentList={};CKEDITOR.plugins.indentList.firstItemInPath=function(a,b,c){var d=b.contains(f);c||(c=b.contains(a));return c&&d&&d.equals(c.getFirst(f))}}(),function(){function a(a,b,c,d){for(var e=CKEDITOR.plugins.list.listToArray(b.root,c),g=[],f=0;f<b.contents.length;f++){var h=b.contents[f];(h=h.getAscendant(\"li\",!0))&&!h.getCustomData(\"list_item_processed\")&&\n(g.push(h),CKEDITOR.dom.element.setMarker(c,h,\"list_item_processed\",!0))}for(var h=b.root.getDocument(),k,l,f=0;f<g.length;f++){var m=g[f].getCustomData(\"listarray_index\");k=e[m].parent;k.is(this.type)||(l=h.createElement(this.type),k.copyAttributes(l,{start:1,type:1}),l.removeStyle(\"list-style-type\"),e[m].parent=l)}c=CKEDITOR.plugins.list.arrayToList(e,c,null,a.config.enterMode);for(var n,e=c.listNode.getChildCount(),f=0;f<e&&(n=c.listNode.getChild(f));f++)n.getName()==this.type&&d.push(n);c.listNode.replace(b.root);\na.fire(\"contentDomInvalidated\")}function f(a,b,c){var d=b.contents,e=b.root.getDocument(),g=[];if(1==d.length&&d[0].equals(b.root)){var f=e.createElement(\"div\");d[0].moveChildren&&d[0].moveChildren(f);d[0].append(f);d[0]=f}b=b.contents[0].getParent();for(f=0;f<d.length;f++)b=b.getCommonAncestor(d[f].getParent());a=a.config.useComputedState;var h,k;a=void 0===a||a;for(f=0;f<d.length;f++)for(var l=d[f],m;m=l.getParent();){if(m.equals(b)){g.push(l);!k&&l.getDirection()&&(k=1);l=l.getDirection(a);null!==\nh&&(h=h&&h!=l?null:l);break}l=m}if(!(1>g.length)){d=g[g.length-1].getNext();f=e.createElement(this.type);for(c.push(f);g.length;)c=g.shift(),a=e.createElement(\"li\"),l=c,l.is(\"pre\")||u.test(l.getName())||\"false\"==l.getAttribute(\"contenteditable\")?c.appendTo(a):(c.copyAttributes(a),h&&c.getDirection()&&(a.removeStyle(\"direction\"),a.removeAttribute(\"dir\")),c.moveChildren(a),c.remove()),a.appendTo(f);h&&k&&f.setAttribute(\"dir\",h);d?f.insertBefore(d):f.appendTo(b)}}function b(a,b,c){function d(c){if(!(!(l=\nk[c?\"getFirst\":\"getLast\"]())||l.is&&l.isBlockBoundary()||!(m=b.root[c?\"getPrevious\":\"getNext\"](CKEDITOR.dom.walker.invisible(!0)))||m.is&&m.isBlockBoundary({br:1})))a.document.createElement(\"br\")[c?\"insertBefore\":\"insertAfter\"](l)}for(var e=CKEDITOR.plugins.list.listToArray(b.root,c),g=[],f=0;f<b.contents.length;f++){var h=b.contents[f];(h=h.getAscendant(\"li\",!0))&&!h.getCustomData(\"list_item_processed\")&&(g.push(h),CKEDITOR.dom.element.setMarker(c,h,\"list_item_processed\",!0))}h=null;for(f=0;f<g.length;f++)h=\ng[f].getCustomData(\"listarray_index\"),e[h].indent=-1;for(f=h+1;f<e.length;f++)if(e[f].indent>e[f-1].indent+1){g=e[f-1].indent+1-e[f].indent;for(h=e[f].indent;e[f]&&e[f].indent>=h;)e[f].indent+=g,f++;f--}var k=CKEDITOR.plugins.list.arrayToList(e,c,null,a.config.enterMode,b.root.getAttribute(\"dir\")).listNode,l,m;d(!0);d();k.replace(b.root);a.fire(\"contentDomInvalidated\")}function c(a,b){this.name=a;this.context=this.type=b;this.allowedContent=b+\" li\";this.requiredContent=b}function d(a,b,c,d){for(var e,\ng;e=a[d?\"getLast\":\"getFirst\"](p);)(g=e.getDirection(1))!==b.getDirection(1)&&e.setAttribute(\"dir\",g),e.remove(),c?e[d?\"insertBefore\":\"insertAfter\"](c):b.append(e,d),c=e}function l(a){function b(c){var e=a[c?\"getPrevious\":\"getNext\"](q);e&&e.type==CKEDITOR.NODE_ELEMENT&&e.is(a.getName())&&(d(a,e,null,!c),a.remove(),a=e)}b();b(1)}function k(a){return a.type==CKEDITOR.NODE_ELEMENT&&(a.getName()in CKEDITOR.dtd.$block||a.getName()in CKEDITOR.dtd.$listItem)&&CKEDITOR.dtd[a.getName()][\"#\"]}function g(a,b,\nc){a.fire(\"saveSnapshot\");c.enlarge(CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS);var e=c.extractContents();b.trim(!1,!0);var g=b.createBookmark(),f=new CKEDITOR.dom.elementPath(b.startContainer),k=f.block,f=f.lastElement.getAscendant(\"li\",1)||k,m=new CKEDITOR.dom.elementPath(c.startContainer),n=m.contains(CKEDITOR.dtd.$listItem),m=m.contains(CKEDITOR.dtd.$list);k?(k=k.getBogus())&&k.remove():m&&(k=m.getPrevious(q))&&y(k)&&k.remove();(k=e.getLast())&&k.type==CKEDITOR.NODE_ELEMENT&&k.is(\"br\")&&k.remove();(k=\nb.startContainer.getChild(b.startOffset))?e.insertBefore(k):b.startContainer.append(e);n&&(e=h(n))&&(f.contains(n)?(d(e,n.getParent(),n),e.remove()):f.append(e));for(;c.checkStartOfBlock()&&c.checkEndOfBlock();){m=c.startPath();e=m.block;if(!e)break;e.is(\"li\")&&(f=e.getParent(),e.equals(f.getLast(q))&&e.equals(f.getFirst(q))&&(e=f));c.moveToPosition(e,CKEDITOR.POSITION_BEFORE_START);e.remove()}c=c.clone();e=a.editable();c.setEndAt(e,CKEDITOR.POSITION_BEFORE_END);c=new CKEDITOR.dom.walker(c);c.evaluator=\nfunction(a){return q(a)&&!y(a)};(c=c.next())&&c.type==CKEDITOR.NODE_ELEMENT&&c.getName()in CKEDITOR.dtd.$list&&l(c);b.moveToBookmark(g);b.select();a.fire(\"saveSnapshot\")}function h(a){return(a=a.getLast(q))&&a.type==CKEDITOR.NODE_ELEMENT&&a.getName()in m?a:null}var m={ol:1,ul:1},e=CKEDITOR.dom.walker.whitespaces(),n=CKEDITOR.dom.walker.bookmark(),q=function(a){return!(e(a)||n(a))},y=CKEDITOR.dom.walker.bogus();CKEDITOR.plugins.list={listToArray:function(a,b,c,d,e){if(!m[a.getName()])return[];d||(d=\n0);c||(c=[]);for(var g=0,f=a.getChildCount();g<f;g++){var h=a.getChild(g);h.type==CKEDITOR.NODE_ELEMENT&&h.getName()in CKEDITOR.dtd.$list&&CKEDITOR.plugins.list.listToArray(h,b,c,d+1);if(\"li\"==h.$.nodeName.toLowerCase()){var k={parent:a,indent:d,element:h,contents:[]};e?k.grandparent=e:(k.grandparent=a.getParent(),k.grandparent&&\"li\"==k.grandparent.$.nodeName.toLowerCase()&&(k.grandparent=k.grandparent.getParent()));b&&CKEDITOR.dom.element.setMarker(b,h,\"listarray_index\",c.length);c.push(k);for(var l=\n0,n=h.getChildCount(),q;l<n;l++)q=h.getChild(l),q.type==CKEDITOR.NODE_ELEMENT&&m[q.getName()]?CKEDITOR.plugins.list.listToArray(q,b,c,d+1,k.grandparent):k.contents.push(q)}}return c},arrayToList:function(a,b,c,d,e){c||(c=0);if(!a||a.length<c+1)return null;for(var g,f=a[c].parent.getDocument(),h=new CKEDITOR.dom.documentFragment(f),k=null,l=c,u=Math.max(a[c].indent,0),p=null,y,E,L=d==CKEDITOR.ENTER_P?\"p\":\"div\";;){var G=a[l];g=G.grandparent;y=G.element.getDirection(1);if(G.indent==u){k&&a[l].parent.getName()==\nk.getName()||(k=a[l].parent.clone(!1,1),e&&k.setAttribute(\"dir\",e),h.append(k));p=k.append(G.element.clone(0,1));y!=k.getDirection(1)&&p.setAttribute(\"dir\",y);for(g=0;g<G.contents.length;g++)p.append(G.contents[g].clone(1,1));l++}else if(G.indent==Math.max(u,0)+1)G=a[l-1].element.getDirection(1),l=CKEDITOR.plugins.list.arrayToList(a,null,l,d,G!=y?y:null),!p.getChildCount()&&CKEDITOR.env.needsNbspFiller&&7>=f.$.documentMode&&p.append(f.createText(\" \")),p.append(l.listNode),l=l.nextIndex;else if(-1==\nG.indent&&!c&&g){m[g.getName()]?(p=G.element.clone(!1,!0),y!=g.getDirection(1)&&p.setAttribute(\"dir\",y)):p=new CKEDITOR.dom.documentFragment(f);var k=g.getDirection(1)!=y,D=G.element,N=D.getAttribute(\"class\"),Q=D.getAttribute(\"style\"),O=p.type==CKEDITOR.NODE_DOCUMENT_FRAGMENT&&(d!=CKEDITOR.ENTER_BR||k||Q||N),K,W=G.contents.length,R;for(g=0;g<W;g++)if(K=G.contents[g],n(K)&&1<W)O?R=K.clone(1,1):p.append(K.clone(1,1));else if(K.type==CKEDITOR.NODE_ELEMENT&&K.isBlockBoundary()){k&&!K.getDirection()&&\nK.setAttribute(\"dir\",y);E=K;var Z=D.getAttribute(\"style\");Z&&E.setAttribute(\"style\",Z.replace(/([^;])$/,\"$1;\")+(E.getAttribute(\"style\")||\"\"));N&&K.addClass(N);E=null;R&&(p.append(R),R=null);p.append(K.clone(1,1))}else O?(E||(E=f.createElement(L),p.append(E),k&&E.setAttribute(\"dir\",y)),Q&&E.setAttribute(\"style\",Q),N&&E.setAttribute(\"class\",N),R&&(E.append(R),R=null),E.append(K.clone(1,1))):p.append(K.clone(1,1));R&&((E||p).append(R),R=null);p.type==CKEDITOR.NODE_DOCUMENT_FRAGMENT&&l!=a.length-1&&(CKEDITOR.env.needsBrFiller&&\n(y=p.getLast())&&y.type==CKEDITOR.NODE_ELEMENT&&y.is(\"br\")&&y.remove(),(y=p.getLast(q))&&y.type==CKEDITOR.NODE_ELEMENT&&y.is(CKEDITOR.dtd.$block)||p.append(f.createElement(\"br\")));y=p.$.nodeName.toLowerCase();\"div\"!=y&&\"p\"!=y||p.appendBogus();h.append(p);k=null;l++}else return null;E=null;if(a.length<=l||Math.max(a[l].indent,0)<u)break}if(b)for(a=h.getFirst();a;){if(a.type==CKEDITOR.NODE_ELEMENT&&(CKEDITOR.dom.element.clearMarkers(b,a),a.getName()in CKEDITOR.dtd.$listItem&&(c=a,f=e=d=void 0,d=c.getDirection()))){for(e=\nc.getParent();e&&!(f=e.getDirection());)e=e.getParent();d==f&&c.removeAttribute(\"dir\")}a=a.getNextSourceNode()}return{listNode:h,nextIndex:l}}};var u=/^h[1-6]$/,p=CKEDITOR.dom.walker.nodeType(CKEDITOR.NODE_ELEMENT);c.prototype={exec:function(c){function d(a){return m[a.root.getName()]&&!e(a.root,[CKEDITOR.NODE_COMMENT])}function e(a,b){return CKEDITOR.tools.array.filter(a.getChildren().toArray(),function(a){return-1===CKEDITOR.tools.array.indexOf(b,a.type)}).length}function g(a){var b=!0;if(0===a.getChildCount())return!1;\na.forEach(function(a){if(a.type!==CKEDITOR.NODE_COMMENT)return b=!1},null,!0);return b}this.refresh(c,c.elementPath());var h=c.config,k=c.getSelection(),n=k&&k.getRanges();if(this.state==CKEDITOR.TRISTATE_OFF){var B=c.editable();if(B.getFirst(q)){var p=1==n.length&&n[0];(h=p&&p.getEnclosedNode())&&h.is&&this.type==h.getName()&&this.setState(CKEDITOR.TRISTATE_ON)}else h.enterMode==CKEDITOR.ENTER_BR?B.appendBogus():n[0].fixBlock(1,h.enterMode==CKEDITOR.ENTER_P?\"p\":\"div\"),k.selectRanges(n)}for(var h=\nk.createBookmarks(!0),B=[],u={},n=n.createIterator(),y=0;(p=n.getNextRange())&&++y;){var I=p.getBoundaryNodes(),J=I.startNode,E=I.endNode;J.type==CKEDITOR.NODE_ELEMENT&&\"td\"==J.getName()&&p.setStartAt(I.startNode,CKEDITOR.POSITION_AFTER_START);E.type==CKEDITOR.NODE_ELEMENT&&\"td\"==E.getName()&&p.setEndAt(I.endNode,CKEDITOR.POSITION_BEFORE_END);p=p.createIterator();for(p.forceBrBreak=this.state==CKEDITOR.TRISTATE_OFF;I=p.getNextParagraph();)if(!I.getCustomData(\"list_block\")&&!g(I)){CKEDITOR.dom.element.setMarker(u,\nI,\"list_block\",1);for(var L=c.elementPath(I),J=L.elements,E=0,L=L.blockLimit,G,D=J.length-1;0<=D&&(G=J[D]);D--)if(m[G.getName()]&&L.contains(G)){L.removeCustomData(\"list_group_object_\"+y);(J=G.getCustomData(\"list_group_object\"))?J.contents.push(I):(J={root:G,contents:[I]},B.push(J),CKEDITOR.dom.element.setMarker(u,G,\"list_group_object\",J));E=1;break}E||(E=L,E.getCustomData(\"list_group_object_\"+y)?E.getCustomData(\"list_group_object_\"+y).contents.push(I):(J={root:E,contents:[I]},CKEDITOR.dom.element.setMarker(u,\nE,\"list_group_object_\"+y,J),B.push(J)))}}for(G=[];0<B.length;)J=B.shift(),this.state==CKEDITOR.TRISTATE_OFF?d(J)||(m[J.root.getName()]?a.call(this,c,J,u,G):f.call(this,c,J,G)):this.state==CKEDITOR.TRISTATE_ON&&m[J.root.getName()]&&!d(J)&&b.call(this,c,J,u);for(D=0;D<G.length;D++)l(G[D]);CKEDITOR.dom.element.clearAllMarkers(u);k.selectBookmarks(h);c.focus()},refresh:function(a,b){var c=b.contains(m,1),d=b.blockLimit||b.root;c&&d.contains(c)?this.setState(c.is(this.type)?CKEDITOR.TRISTATE_ON:CKEDITOR.TRISTATE_OFF):\nthis.setState(CKEDITOR.TRISTATE_OFF)}};CKEDITOR.plugins.add(\"list\",{requires:\"indentlist\",init:function(a){a.blockless||(a.addCommand(\"numberedlist\",new c(\"numberedlist\",\"ol\")),a.addCommand(\"bulletedlist\",new c(\"bulletedlist\",\"ul\")),a.ui.addButton&&(a.ui.addButton(\"NumberedList\",{label:a.lang.list.numberedlist,command:\"numberedlist\",directional:!0,toolbar:\"list,10\"}),a.ui.addButton(\"BulletedList\",{label:a.lang.list.bulletedlist,command:\"bulletedlist\",directional:!0,toolbar:\"list,20\"})),a.on(\"key\",\nfunction(b){var c=b.data.domEvent.getKey(),d;if(\"wysiwyg\"==a.mode&&c in{8:1,46:1}){var e=a.getSelection().getRanges()[0],f=e&&e.startPath();if(e&&e.collapsed){var l=8==c,n=a.editable(),p=new CKEDITOR.dom.walker(e.clone());p.evaluator=function(a){return q(a)&&!y(a)};p.guard=function(a,b){return!(b&&a.type==CKEDITOR.NODE_ELEMENT&&a.is(\"table\"))};c=e.clone();if(l){var u;(u=f.contains(m))&&e.checkBoundaryOfElement(u,CKEDITOR.START)&&(u=u.getParent())&&u.is(\"li\")&&(u=h(u))?(d=u,u=u.getPrevious(q),c.moveToPosition(u&&\ny(u)?u:d,CKEDITOR.POSITION_BEFORE_START)):(p.range.setStartAt(n,CKEDITOR.POSITION_AFTER_START),p.range.setEnd(e.startContainer,e.startOffset),(u=p.previous())&&u.type==CKEDITOR.NODE_ELEMENT&&(u.getName()in m||u.is(\"li\"))&&(u.is(\"li\")||(p.range.selectNodeContents(u),p.reset(),p.evaluator=k,u=p.previous()),d=u,c.moveToElementEditEnd(d),c.moveToPosition(c.endPath().block,CKEDITOR.POSITION_BEFORE_END)));if(d)g(a,c,e),b.cancel();else{var F=f.contains(m);F&&e.checkBoundaryOfElement(F,CKEDITOR.START)&&(d=\nF.getFirst(q),e.checkBoundaryOfElement(d,CKEDITOR.START)&&(u=F.getPrevious(q),h(d)?u&&(e.moveToElementEditEnd(u),e.select()):a.execCommand(\"outdent\"),b.cancel()))}}else if(d=f.contains(\"li\")){if(p.range.setEndAt(n,CKEDITOR.POSITION_BEFORE_END),l=(n=d.getLast(q))&&k(n)?n:d,f=0,(u=p.next())&&u.type==CKEDITOR.NODE_ELEMENT&&u.getName()in m&&u.equals(n)?(f=1,u=p.next()):e.checkBoundaryOfElement(l,CKEDITOR.END)&&(f=2),f&&u){e=e.clone();e.moveToElementEditStart(u);if(1==f&&(c.optimize(),!c.startContainer.equals(d))){for(d=\nc.startContainer;d.is(CKEDITOR.dtd.$inline);)F=d,d=d.getParent();F&&c.moveToPosition(F,CKEDITOR.POSITION_AFTER_END)}2==f&&(c.moveToPosition(c.endPath().block,CKEDITOR.POSITION_BEFORE_END),e.endPath().block&&e.moveToPosition(e.endPath().block,CKEDITOR.POSITION_AFTER_START));g(a,c,e);b.cancel()}}else p.range.setEndAt(n,CKEDITOR.POSITION_BEFORE_END),(u=p.next())&&u.type==CKEDITOR.NODE_ELEMENT&&u.is(m)&&(u=u.getFirst(q),f.block&&e.checkStartOfBlock()&&e.checkEndOfBlock()?(f.block.remove(),e.moveToElementEditStart(u),\ne.select()):h(u)?(e.moveToElementEditStart(u),e.select()):(e=e.clone(),e.moveToElementEditStart(u),g(a,c,e)),b.cancel());setTimeout(function(){a.selectionChange(1)})}}}))}})}(),function(){function a(a,b,c){c=a.config.forceEnterMode||c;if(\"wysiwyg\"==a.mode){b||(b=a.activeEnterMode);var d=a.elementPath();d&&!d.isContextFor(\"p\")&&(b=CKEDITOR.ENTER_BR,c=1);a.fire(\"saveSnapshot\");b==CKEDITOR.ENTER_BR?k(a,b,null,c):g(a,b,null,c);a.fire(\"saveSnapshot\")}}function f(a){a=a.getSelection().getRanges(!0);for(var b=\na.length-1;0<b;b--)a[b].deleteContents();return a[0]}function b(a){var b=a.startContainer.getAscendant(function(a){return a.type==CKEDITOR.NODE_ELEMENT&&\"true\"==a.getAttribute(\"contenteditable\")},!0);if(a.root.equals(b))return a;b=new CKEDITOR.dom.range(b);b.moveToRange(a);return b}CKEDITOR.plugins.add(\"enterkey\",{init:function(b){b.addCommand(\"enter\",{modes:{wysiwyg:1},editorFocus:!1,exec:function(b){a(b)}});b.addCommand(\"shiftEnter\",{modes:{wysiwyg:1},editorFocus:!1,exec:function(b){a(b,b.activeShiftEnterMode,\n1)}});b.setKeystroke([[13,\"enter\"],[CKEDITOR.SHIFT+13,\"shiftEnter\"]])}});var c=CKEDITOR.dom.walker.whitespaces(),d=CKEDITOR.dom.walker.bookmark(),l,k,g,h;CKEDITOR.plugins.enterkey={enterBlock:function(a,e,g,l){function y(a){var b;if(a===CKEDITOR.ENTER_BR||-1===CKEDITOR.tools.indexOf([\"td\",\"th\"],w.lastElement.getName())||1!==w.lastElement.getChildCount())return!1;a=w.lastElement.getChild(0).clone(!0);(b=a.getBogus())&&b.remove();return a.getText().length?!1:!0}if(g=g||f(a)){g=b(g);var u=g.document,\np=g.checkStartOfBlock(),v=g.checkEndOfBlock(),w=a.elementPath(g.startContainer),r=w.block,z=e==CKEDITOR.ENTER_DIV?\"div\":\"p\",t;if(r&&p&&v){p=r.getParent();if(p.is(\"li\")&&1<p.getChildCount()){u=new CKEDITOR.dom.element(\"li\");t=a.createRange();u.insertAfter(p);r.remove();t.setStart(u,0);a.getSelection().selectRanges([t]);return}if(r.is(\"li\")||r.getParent().is(\"li\")){r.is(\"li\")||(r=r.getParent(),p=r.getParent());t=p.getParent();g=!r.hasPrevious();var x=!r.hasNext();l=a.getSelection();var z=l.createBookmarks(),\nA=r.getDirection(1),v=r.getAttribute(\"class\"),B=r.getAttribute(\"style\"),C=t.getDirection(1)!=A;a=a.enterMode!=CKEDITOR.ENTER_BR||C||B||v;if(t.is(\"li\"))g||x?(g&&x&&p.remove(),r[x?\"insertAfter\":\"insertBefore\"](t)):r.breakParent(t);else{if(a)if(w.block.is(\"li\")?(t=u.createElement(e==CKEDITOR.ENTER_P?\"p\":\"div\"),C&&t.setAttribute(\"dir\",A),B&&t.setAttribute(\"style\",B),v&&t.setAttribute(\"class\",v),r.moveChildren(t)):t=w.block,g||x)t[g?\"insertBefore\":\"insertAfter\"](p);else r.breakParent(p),t.insertAfter(p);\nelse if(r.appendBogus(!0),g||x)for(;u=r[g?\"getFirst\":\"getLast\"]();)u[g?\"insertBefore\":\"insertAfter\"](p);else for(r.breakParent(p);u=r.getLast();)u.insertAfter(p);r.remove()}l.selectBookmarks(z);return}if(r&&r.getParent().is(\"blockquote\")){r.breakParent(r.getParent());r.getPrevious().getFirst(CKEDITOR.dom.walker.invisible(1))||r.getPrevious().remove();r.getNext().getFirst(CKEDITOR.dom.walker.invisible(1))||r.getNext().remove();g.moveToElementEditStart(r);g.select();return}}else if(r&&r.is(\"pre\")&&\n!v){k(a,e,g,l);return}if(B=g.splitBlock(z)){a=B.previousBlock;r=B.nextBlock;p=B.wasStartOfBlock;v=B.wasEndOfBlock;r?(x=r.getParent(),x.is(\"li\")&&(r.breakParent(x),r.move(r.getNext(),1))):a&&(x=a.getParent())&&x.is(\"li\")&&(a.breakParent(x),x=a.getNext(),g.moveToElementEditStart(x),a.move(a.getPrevious()));if(p||v)if(y(e))g.moveToElementEditStart(g.getTouchedStartNode());else{if(a){if(a.is(\"li\")||!h.test(a.getName())&&!a.is(\"pre\"))t=a.clone()}else r&&(t=r.clone());t?l&&!t.is(\"li\")&&t.renameNode(z):\nx&&x.is(\"li\")?t=x:(t=u.createElement(z),a&&(A=a.getDirection())&&t.setAttribute(\"dir\",A));if(u=B.elementPath)for(e=0,l=u.elements.length;e<l;e++){z=u.elements[e];if(z.equals(u.block)||z.equals(u.blockLimit))break;CKEDITOR.dtd.$removeEmpty[z.getName()]&&(z=z.clone(),t.moveChildren(z),t.append(z))}t.appendBogus();t.getParent()||g.insertNode(t);t.is(\"li\")&&t.removeAttribute(\"value\");!CKEDITOR.env.ie||!p||v&&a.getChildCount()||(g.moveToElementEditStart(v?a:t),g.select());g.moveToElementEditStart(p&&!v?\nr:t)}else r.is(\"li\")&&(t=g.clone(),t.selectNodeContents(r),t=new CKEDITOR.dom.walker(t),t.evaluator=function(a){return!(d(a)||c(a)||a.type==CKEDITOR.NODE_ELEMENT&&a.getName()in CKEDITOR.dtd.$inline&&!(a.getName()in CKEDITOR.dtd.$empty))},(x=t.next())&&x.type==CKEDITOR.NODE_ELEMENT&&x.is(\"ul\",\"ol\")&&(CKEDITOR.env.needsBrFiller?u.createElement(\"br\"):u.createText(\" \")).insertBefore(x)),r&&g.moveToElementEditStart(r);g.select();g.scrollIntoView()}}},enterBr:function(a,b,c,d){if(c=c||f(a)){var k=c.document,\nl=c.checkEndOfBlock(),p=new CKEDITOR.dom.elementPath(a.getSelection().getStartElement()),v=p.block,w=v&&p.block.getName();d||\"li\"!=w?(!d&&l&&h.test(w)?(l=v.getDirection())?(k=k.createElement(\"div\"),k.setAttribute(\"dir\",l),k.insertAfter(v),c.setStart(k,0)):(k.createElement(\"br\").insertAfter(v),CKEDITOR.env.gecko&&k.createText(\"\").insertAfter(v),c.setStartAt(v.getNext(),CKEDITOR.env.ie?CKEDITOR.POSITION_BEFORE_START:CKEDITOR.POSITION_AFTER_START)):(a=\"pre\"==w&&CKEDITOR.env.ie&&8>CKEDITOR.env.version?\nk.createText(\"\\r\"):k.createElement(\"br\"),c.deleteContents(),c.insertNode(a),CKEDITOR.env.needsBrFiller?(k.createText(\"﻿\").insertAfter(a),l&&(v||p.blockLimit).appendBogus(),a.getNext().$.nodeValue=\"\",c.setStartAt(a.getNext(),CKEDITOR.POSITION_AFTER_START)):c.setStartAt(a,CKEDITOR.POSITION_AFTER_END)),c.collapse(!0),c.select(),c.scrollIntoView()):g(a,b,c,d)}}};l=CKEDITOR.plugins.enterkey;k=l.enterBr;g=l.enterBlock;h=/^h[1-6]$/}(),function(){function a(a,b){var c={},d=[],l={nbsp:\" \",shy:\"­\",gt:\"\\x3e\",\nlt:\"\\x3c\",amp:\"\\x26\",apos:\"'\",quot:'\"'};a=a.replace(/\\b(nbsp|shy|gt|lt|amp|apos|quot)(?:,|$)/g,function(a,e){var g=b?\"\\x26\"+e+\";\":l[e];c[g]=b?l[e]:\"\\x26\"+e+\";\";d.push(g);return\"\"});a=a.replace(/,$/,\"\");if(!b&&a){a=a.split(\",\");var k=document.createElement(\"div\"),g;k.innerHTML=\"\\x26\"+a.join(\";\\x26\")+\";\";g=k.innerHTML;k=null;for(k=0;k<g.length;k++){var h=g.charAt(k);c[h]=\"\\x26\"+a[k]+\";\";d.push(h)}}c.regex=d.join(b?\"|\":\"\");return c}CKEDITOR.plugins.add(\"entities\",{afterInit:function(f){function b(a){return h[a]}\nfunction c(a){return\"force\"!=d.entities_processNumerical&&k[a]?k[a]:\"\\x26#\"+a.charCodeAt(0)+\";\"}var d=f.config;if(f=(f=f.dataProcessor)&&f.htmlFilter){var l=[];!1!==d.basicEntities&&l.push(\"nbsp,gt,lt,amp\");d.entities&&(l.length&&l.push(\"quot,iexcl,cent,pound,curren,yen,brvbar,sect,uml,copy,ordf,laquo,not,shy,reg,macr,deg,plusmn,sup2,sup3,acute,micro,para,middot,cedil,sup1,ordm,raquo,frac14,frac12,frac34,iquest,times,divide,fnof,bull,hellip,prime,Prime,oline,frasl,weierp,image,real,trade,alefsym,larr,uarr,rarr,darr,harr,crarr,lArr,uArr,rArr,dArr,hArr,forall,part,exist,empty,nabla,isin,notin,ni,prod,sum,minus,lowast,radic,prop,infin,ang,and,or,cap,cup,int,there4,sim,cong,asymp,ne,equiv,le,ge,sub,sup,nsub,sube,supe,oplus,otimes,perp,sdot,lceil,rceil,lfloor,rfloor,lang,rang,loz,spades,clubs,hearts,diams,circ,tilde,ensp,emsp,thinsp,zwnj,zwj,lrm,rlm,ndash,mdash,lsquo,rsquo,sbquo,ldquo,rdquo,bdquo,dagger,Dagger,permil,lsaquo,rsaquo,euro\"),\nd.entities_latin&&l.push(\"Agrave,Aacute,Acirc,Atilde,Auml,Aring,AElig,Ccedil,Egrave,Eacute,Ecirc,Euml,Igrave,Iacute,Icirc,Iuml,ETH,Ntilde,Ograve,Oacute,Ocirc,Otilde,Ouml,Oslash,Ugrave,Uacute,Ucirc,Uuml,Yacute,THORN,szlig,agrave,aacute,acirc,atilde,auml,aring,aelig,ccedil,egrave,eacute,ecirc,euml,igrave,iacute,icirc,iuml,eth,ntilde,ograve,oacute,ocirc,otilde,ouml,oslash,ugrave,uacute,ucirc,uuml,yacute,thorn,yuml,OElig,oelig,Scaron,scaron,Yuml\"),d.entities_greek&&l.push(\"Alpha,Beta,Gamma,Delta,Epsilon,Zeta,Eta,Theta,Iota,Kappa,Lambda,Mu,Nu,Xi,Omicron,Pi,Rho,Sigma,Tau,Upsilon,Phi,Chi,Psi,Omega,alpha,beta,gamma,delta,epsilon,zeta,eta,theta,iota,kappa,lambda,mu,nu,xi,omicron,pi,rho,sigmaf,sigma,tau,upsilon,phi,chi,psi,omega,thetasym,upsih,piv\"),\nd.entities_additional&&l.push(d.entities_additional));var k=a(l.join(\",\")),g=k.regex?\"[\"+k.regex+\"]\":\"a^\";delete k.regex;d.entities&&d.entities_processNumerical&&(g=\"[^ -~]|\"+g);var g=new RegExp(g,\"g\"),h=a(\"nbsp,gt,lt,amp,shy\",!0),m=new RegExp(h.regex,\"g\");f.addRules({text:function(a){return a.replace(m,b).replace(g,c)}},{applyToAll:!0,excludeNestedEditable:!0})}}})}(),CKEDITOR.config.basicEntities=!0,CKEDITOR.config.entities=!0,CKEDITOR.config.entities_latin=!0,CKEDITOR.config.entities_greek=!0,\nCKEDITOR.config.entities_additional=\"#39\",CKEDITOR.plugins.add(\"popup\"),CKEDITOR.tools.extend(CKEDITOR.editor.prototype,{popup:function(a,f,b,c){f=f||\"80%\";b=b||\"70%\";\"string\"==typeof f&&1<f.length&&\"%\"==f.substr(f.length-1,1)&&(f=parseInt(window.screen.width*parseInt(f,10)/100,10));\"string\"==typeof b&&1<b.length&&\"%\"==b.substr(b.length-1,1)&&(b=parseInt(window.screen.height*parseInt(b,10)/100,10));640>f&&(f=640);420>b&&(b=420);var d=parseInt((window.screen.height-b)/2,10),l=parseInt((window.screen.width-\nf)/2,10);c=(c||\"location\\x3dno,menubar\\x3dno,toolbar\\x3dno,dependent\\x3dyes,minimizable\\x3dno,modal\\x3dyes,alwaysRaised\\x3dyes,resizable\\x3dyes,scrollbars\\x3dyes\")+\",width\\x3d\"+f+\",height\\x3d\"+b+\",top\\x3d\"+d+\",left\\x3d\"+l;var k=window.open(\"\",null,c,!0);if(!k)return!1;try{-1==navigator.userAgent.toLowerCase().indexOf(\" chrome/\")&&(k.moveTo(l,d),k.resizeTo(f,b)),k.focus(),k.location.href=a}catch(g){window.open(a,null,c,!0)}return!0}}),\"use strict\",function(){function a(a){this.editor=a;this.loaders=\n[]}function f(a,c,f){var g=a.config.fileTools_defaultFileName;this.editor=a;this.lang=a.lang;\"string\"===typeof c?(this.data=c,this.file=b(this.data),this.loaded=this.total=this.file.size):(this.data=null,this.file=c,this.total=this.file.size,this.loaded=0);f?this.fileName=f:this.file.name?this.fileName=this.file.name:(a=this.file.type.split(\"/\"),g&&(a[0]=g),this.fileName=a.join(\".\"));this.uploaded=0;this.responseData=this.uploadTotal=null;this.status=\"created\";this.abort=function(){this.changeStatus(\"abort\")}}\nfunction b(a){var b=a.match(c)[1];a=a.replace(c,\"\");a=atob(a);var f=[],g,h,m,e;for(g=0;g<a.length;g+=512){h=a.slice(g,g+512);m=Array(h.length);for(e=0;e<h.length;e++)m[e]=h.charCodeAt(e);h=new Uint8Array(m);f.push(h)}return new Blob(f,{type:b})}CKEDITOR.plugins.add(\"filetools\",{beforeInit:function(b){b.uploadRepository=new a(b);b.on(\"fileUploadRequest\",function(a){var b=a.data.fileLoader;b.xhr.open(\"POST\",b.uploadUrl,!0);a.data.requestData.upload={file:b.file,name:b.fileName}},null,null,5);b.on(\"fileUploadRequest\",\nfunction(a){var c=a.data.fileLoader,g=new FormData;a=a.data.requestData;var f=b.config.fileTools_requestHeaders,m,e;for(e in a){var n=a[e];\"object\"===typeof n&&n.file?g.append(e,n.file,n.name):g.append(e,n)}g.append(\"ckCsrfToken\",CKEDITOR.tools.getCsrfToken());if(f)for(m in f)c.xhr.setRequestHeader(m,f[m]);c.xhr.send(g)},null,null,999);b.on(\"fileUploadResponse\",function(a){var b=a.data.fileLoader,c=b.xhr,d=a.data;try{var f=JSON.parse(c.responseText);f.error&&f.error.message&&(d.message=f.error.message);\nif(f.uploaded)for(var e in f)d[e]=f[e];else a.cancel()}catch(n){d.message=b.lang.filetools.responseError,CKEDITOR.warn(\"filetools-response-error\",{responseText:c.responseText}),a.cancel()}},null,null,999)}});a.prototype={create:function(a,b,c){c=c||f;var g=this.loaders.length;a=new c(this.editor,a,b);a.id=g;this.loaders[g]=a;this.fire(\"instanceCreated\",a);return a},isFinished:function(){for(var a=0;a<this.loaders.length;++a)if(!this.loaders[a].isFinished())return!1;return!0}};f.prototype={loadAndUpload:function(a,\nb){var c=this;this.once(\"loaded\",function(g){g.cancel();c.once(\"update\",function(a){a.cancel()},null,null,0);c.upload(a,b)},null,null,0);this.load()},load:function(){var a=this,b=this.reader=new FileReader;a.changeStatus(\"loading\");this.abort=function(){a.reader.abort()};b.onabort=function(){a.changeStatus(\"abort\")};b.onerror=function(){a.message=a.lang.filetools.loadError;a.changeStatus(\"error\")};b.onprogress=function(b){a.loaded=b.loaded;a.update()};b.onload=function(){a.loaded=a.total;a.data=b.result;\na.changeStatus(\"loaded\")};b.readAsDataURL(this.file)},upload:function(a,b){var c=b||{};a?(this.uploadUrl=a,this.xhr=new XMLHttpRequest,this.attachRequestListeners(),this.editor.fire(\"fileUploadRequest\",{fileLoader:this,requestData:c})&&this.changeStatus(\"uploading\")):(this.message=this.lang.filetools.noUrlError,this.changeStatus(\"error\"))},attachRequestListeners:function(){function a(){\"error\"!=c.status&&(c.message=c.lang.filetools.networkError,c.changeStatus(\"error\"))}function b(){\"abort\"!=c.status&&\nc.changeStatus(\"abort\")}var c=this,g=this.xhr;c.abort=function(){g.abort();b()};g.onerror=a;g.onabort=b;g.upload?(g.upload.onprogress=function(a){a.lengthComputable&&(c.uploadTotal||(c.uploadTotal=a.total),c.uploaded=a.loaded,c.update())},g.upload.onerror=a,g.upload.onabort=b):(c.uploadTotal=c.total,c.update());g.onload=function(){c.update();if(\"abort\"!=c.status)if(c.uploaded=c.uploadTotal,200>g.status||299<g.status)c.message=c.lang.filetools[\"httpError\"+g.status],c.message||(c.message=c.lang.filetools.httpError.replace(\"%1\",\ng.status)),c.changeStatus(\"error\");else{for(var a={fileLoader:c},b=[\"message\",\"fileName\",\"url\"],d=c.editor.fire(\"fileUploadResponse\",a),f=0;f<b.length;f++){var l=b[f];\"string\"===typeof a[l]&&(c[l]=a[l])}c.responseData=a;delete c.responseData.fileLoader;!1===d?c.changeStatus(\"error\"):c.changeStatus(\"uploaded\")}}},changeStatus:function(a){this.status=a;if(\"error\"==a||\"abort\"==a||\"loaded\"==a||\"uploaded\"==a)this.abort=function(){};this.fire(a);this.update()},update:function(){this.fire(\"update\")},isFinished:function(){return!!this.status.match(/^(?:loaded|uploaded|error|abort)$/)}};\nCKEDITOR.event.implementOn(a.prototype);CKEDITOR.event.implementOn(f.prototype);var c=/^data:(\\S*?);base64,/;CKEDITOR.fileTools||(CKEDITOR.fileTools={});CKEDITOR.tools.extend(CKEDITOR.fileTools,{uploadRepository:a,fileLoader:f,getUploadUrl:function(a,b){var c=CKEDITOR.tools.capitalize;return b&&a[b+\"UploadUrl\"]?a[b+\"UploadUrl\"]:a.uploadUrl?a.uploadUrl:b&&a[\"filebrowser\"+c(b,1)+\"UploadUrl\"]?a[\"filebrowser\"+c(b,1)+\"UploadUrl\"]+\"\\x26responseType\\x3djson\":a.filebrowserUploadUrl?a.filebrowserUploadUrl+\n\"\\x26responseType\\x3djson\":null},isTypeSupported:function(a,b){return!!a.type.match(b)},isFileUploadSupported:\"function\"===typeof FileReader&&\"function\"===typeof(new FileReader).readAsDataURL&&\"function\"===typeof FormData&&\"function\"===typeof(new FormData).append&&\"function\"===typeof XMLHttpRequest&&\"function\"===typeof Blob})}(),function(){function a(a,b){var c=[];if(b)for(var d in b)c.push(d+\"\\x3d\"+encodeURIComponent(b[d]));else return a;return a+(-1!=a.indexOf(\"?\")?\"\\x26\":\"?\")+c.join(\"\\x26\")}function f(b){return!b.match(/command=QuickUpload/)||\nb.match(/(\\?|&)responseType=json/)?b:a(b,{responseType:\"json\"})}function b(a){a+=\"\";return a.charAt(0).toUpperCase()+a.substr(1)}function c(){var c=this.getDialog(),d=c.getParentEditor();d._.filebrowserSe=this;var e=d.config[\"filebrowser\"+b(c.getName())+\"WindowWidth\"]||d.config.filebrowserWindowWidth||\"80%\",c=d.config[\"filebrowser\"+b(c.getName())+\"WindowHeight\"]||d.config.filebrowserWindowHeight||\"70%\",g=this.filebrowser.params||{};g.CKEditor=d.name;g.CKEditorFuncNum=d._.filebrowserFn;g.langCode||\n(g.langCode=d.langCode);g=a(this.filebrowser.url,g);d.popup(g,e,c,d.config.filebrowserWindowFeatures||d.config.fileBrowserWindowFeatures)}function d(a){var b=new CKEDITOR.dom.element(a.$.form);b&&((a=b.$.elements.ckCsrfToken)?a=new CKEDITOR.dom.element(a):(a=new CKEDITOR.dom.element(\"input\"),a.setAttributes({name:\"ckCsrfToken\",type:\"hidden\"}),b.append(a)),a.setAttribute(\"value\",CKEDITOR.tools.getCsrfToken()))}function l(){var a=this.getDialog();a.getParentEditor()._.filebrowserSe=this;return a.getContentElement(this[\"for\"][0],\nthis[\"for\"][1]).getInputElement().$.value&&a.getContentElement(this[\"for\"][0],this[\"for\"][1]).getAction()?!0:!1}function k(b,c,d){var e=d.params||{};e.CKEditor=b.name;e.CKEditorFuncNum=b._.filebrowserFn;e.langCode||(e.langCode=b.langCode);c.action=a(d.url,e);c.filebrowser=d}function g(a,m,y,u){if(u&&u.length)for(var p,v=u.length;v--;)if(p=u[v],\"hbox\"!=p.type&&\"vbox\"!=p.type&&\"fieldset\"!=p.type||g(a,m,y,p.children),p.filebrowser)if(\"string\"==typeof p.filebrowser&&(p.filebrowser={action:\"fileButton\"==\np.type?\"QuickUpload\":\"Browse\",target:p.filebrowser}),\"Browse\"==p.filebrowser.action){var w=p.filebrowser.url;void 0===w&&(w=a.config[\"filebrowser\"+b(m)+\"BrowseUrl\"],void 0===w&&(w=a.config.filebrowserBrowseUrl));w&&(p.onClick=c,p.filebrowser.url=w,p.hidden=!1)}else if(\"QuickUpload\"==p.filebrowser.action&&p[\"for\"]&&(w=p.filebrowser.url,void 0===w&&(w=a.config[\"filebrowser\"+b(m)+\"UploadUrl\"],void 0===w&&(w=a.config.filebrowserUploadUrl)),w)){var r=p.onClick;p.onClick=function(b){var c=b.sender,g=c.getDialog().getContentElement(this[\"for\"][0],\nthis[\"for\"][1]).getInputElement(),k=CKEDITOR.fileTools&&CKEDITOR.fileTools.isFileUploadSupported;if(r&&!1===r.call(c,b))return!1;if(l.call(c,b)){if(\"form\"!==a.config.filebrowserUploadMethod&&k)return b=a.uploadRepository.create(g.$.files[0]),b.on(\"uploaded\",function(a){var b=a.sender.responseData;e.call(a.sender.editor,b.url,b.message)}),b.on(\"error\",h.bind(this)),b.on(\"abort\",h.bind(this)),b.loadAndUpload(f(w)),\"xhr\";d(g);return!0}return!1};p.filebrowser.url=w;p.hidden=!1;k(a,y.getContents(p[\"for\"][0]).get(p[\"for\"][1]),\np.filebrowser)}}function h(a){var b={};try{b=JSON.parse(a.sender.xhr.response)||{}}catch(c){}this.enable();alert(b.error?b.error.message:a.sender.message)}function m(a,b,c){if(-1!==c.indexOf(\";\")){c=c.split(\";\");for(var d=0;d<c.length;d++)if(m(a,b,c[d]))return!0;return!1}return(a=a.getContents(b).get(c).filebrowser)&&a.url}function e(a,b){var c=this._.filebrowserSe.getDialog(),d=this._.filebrowserSe[\"for\"],e=this._.filebrowserSe.filebrowser.onSelect;d&&c.getContentElement(d[0],d[1]).reset();if(\"function\"!=\ntypeof b||!1!==b.call(this._.filebrowserSe))if(!e||!1!==e.call(this._.filebrowserSe,a,b))if(\"string\"==typeof b&&b&&alert(b),a&&(d=this._.filebrowserSe,c=d.getDialog(),d=d.filebrowser.target||null))if(d=d.split(\":\"),e=c.getContentElement(d[0],d[1]))e.setValue(a),c.selectPage(d[0])}CKEDITOR.plugins.add(\"filebrowser\",{requires:\"popup,filetools\",init:function(a){a._.filebrowserFn=CKEDITOR.tools.addFunction(e,a);a.on(\"destroy\",function(){CKEDITOR.tools.removeFunction(this._.filebrowserFn)})}});CKEDITOR.on(\"dialogDefinition\",\nfunction(a){if(a.editor.plugins.filebrowser)for(var b=a.data.definition,c,d=0;d<b.contents.length;++d)if(c=b.contents[d])g(a.editor,a.data.name,b,c.elements),c.hidden&&c.filebrowser&&(c.hidden=!m(b,c.id,c.filebrowser))})}(),function(){function a(a){var d=a.config,l=a.fire(\"uiSpace\",{space:\"top\",html:\"\"}).html,k=function(){function e(a,c,d){h.setStyle(c,b(d));h.setStyle(\"position\",a)}function g(a){var b=m.getDocumentPosition();switch(a){case \"top\":e(\"absolute\",\"top\",b.y-r-x);break;case \"pin\":e(\"fixed\",\n\"top\",B);break;case \"bottom\":e(\"absolute\",\"top\",b.y+(v.height||v.bottom-v.top)+x)}l=a}var l,m,p,v,w,r,z,t=d.floatSpaceDockedOffsetX||0,x=d.floatSpaceDockedOffsetY||0,A=d.floatSpacePinnedOffsetX||0,B=d.floatSpacePinnedOffsetY||0;return function(e){if(m=a.editable()){var n=e&&\"focus\"==e.name;n&&h.show();a.fire(\"floatingSpaceLayout\",{show:n});h.removeStyle(\"left\");h.removeStyle(\"right\");p=h.getClientRect();v=m.getClientRect();w=f.getViewPaneSize();r=p.height;z=\"pageXOffset\"in f.$?f.$.pageXOffset:CKEDITOR.document.$.documentElement.scrollLeft;\nl?(r+x<=v.top?g(\"top\"):r+x>w.height-v.bottom?g(\"pin\"):g(\"bottom\"),e=w.width/2,e=d.floatSpacePreferRight?\"right\":0<v.left&&v.right<w.width&&v.width>p.width?\"rtl\"==d.contentsLangDirection?\"right\":\"left\":e-v.left>v.right-e?\"left\":\"right\",p.width>w.width?(e=\"left\",n=0):(n=\"left\"==e?0<v.left?v.left:0:v.right<w.width?w.width-v.right:0,n+p.width>w.width&&(e=\"left\"==e?\"right\":\"left\",n=0)),h.setStyle(e,b((\"pin\"==l?A:t)+n+(\"pin\"==l?0:\"left\"==e?z:-z)))):(l=\"pin\",g(\"pin\"),k(e))}}}();if(l){var g=new CKEDITOR.template('\\x3cdiv id\\x3d\"cke_{name}\" class\\x3d\"cke {id} cke_reset_all cke_chrome cke_editor_{name} cke_float cke_{langDir} '+\nCKEDITOR.env.cssClass+'\" dir\\x3d\"{langDir}\" title\\x3d\"'+(CKEDITOR.env.gecko?\" \":\"\")+'\" lang\\x3d\"{langCode}\" role\\x3d\"application\" style\\x3d\"{style}\"'+(a.title?' aria-labelledby\\x3d\"cke_{name}_arialbl\"':\" \")+\"\\x3e\"+(a.title?'\\x3cspan id\\x3d\"cke_{name}_arialbl\" class\\x3d\"cke_voice_label\"\\x3e{voiceLabel}\\x3c/span\\x3e':\" \")+'\\x3cdiv class\\x3d\"cke_inner\"\\x3e\\x3cdiv id\\x3d\"{topId}\" class\\x3d\"cke_top\" role\\x3d\"presentation\"\\x3e{content}\\x3c/div\\x3e\\x3c/div\\x3e\\x3c/div\\x3e'),h=CKEDITOR.document.getBody().append(CKEDITOR.dom.element.createFromHtml(g.output({content:l,\nid:a.id,langDir:a.lang.dir,langCode:a.langCode,name:a.name,style:\"display:none;z-index:\"+(d.baseFloatZIndex-1),topId:a.ui.spaceId(\"top\"),voiceLabel:a.title}))),m=CKEDITOR.tools.eventsBuffer(500,k),e=CKEDITOR.tools.eventsBuffer(100,k);h.unselectable();h.on(\"mousedown\",function(a){a=a.data;a.getTarget().hasAscendant(\"a\",1)||a.preventDefault()});a.on(\"focus\",function(b){k(b);a.on(\"change\",m.input);f.on(\"scroll\",e.input);f.on(\"resize\",e.input)});a.on(\"blur\",function(){h.hide();a.removeListener(\"change\",\nm.input);f.removeListener(\"scroll\",e.input);f.removeListener(\"resize\",e.input)});a.on(\"destroy\",function(){f.removeListener(\"scroll\",e.input);f.removeListener(\"resize\",e.input);h.clearCustomData();h.remove()});a.focusManager.hasFocus&&h.show();a.focusManager.add(h,1)}}var f=CKEDITOR.document.getWindow(),b=CKEDITOR.tools.cssLength;CKEDITOR.plugins.add(\"floatingspace\",{init:function(b){b.on(\"loaded\",function(){a(this)},null,null,20)}})}(),CKEDITOR.plugins.add(\"listblock\",{requires:\"panel\",onLoad:function(){var a=\nCKEDITOR.addTemplate(\"panel-list\",'\\x3cul role\\x3d\"presentation\" class\\x3d\"cke_panel_list\"\\x3e{items}\\x3c/ul\\x3e'),f=CKEDITOR.addTemplate(\"panel-list-item\",'\\x3cli id\\x3d\"{id}\" class\\x3d\"cke_panel_listItem\" role\\x3dpresentation\\x3e\\x3ca id\\x3d\"{id}_option\" _cke_focus\\x3d1 hidefocus\\x3dtrue title\\x3d\"{title}\" draggable\\x3d\"false\" ondragstart\\x3d\"return false;\" href\\x3d\"javascript:void(\\'{val}\\')\"  {onclick}\\x3d\"CKEDITOR.tools.callFunction({clickFn},\\'{val}\\'); return false;\" role\\x3d\"option\"\\x3e{text}\\x3c/a\\x3e\\x3c/li\\x3e'),\nb=CKEDITOR.addTemplate(\"panel-list-group\",'\\x3ch1 id\\x3d\"{id}\" draggable\\x3d\"false\" ondragstart\\x3d\"return false;\" class\\x3d\"cke_panel_grouptitle\" role\\x3d\"presentation\" \\x3e{label}\\x3c/h1\\x3e'),c=/\\'/g;CKEDITOR.ui.panel.prototype.addListBlock=function(a,b){return this.addBlock(a,new CKEDITOR.ui.listBlock(this.getHolderElement(),b))};CKEDITOR.ui.listBlock=CKEDITOR.tools.createClass({base:CKEDITOR.ui.panel.block,$:function(a,b){b=b||{};var c=b.attributes||(b.attributes={});(this.multiSelect=!!b.multiSelect)&&\n(c[\"aria-multiselectable\"]=!0);!c.role&&(c.role=\"listbox\");this.base.apply(this,arguments);this.element.setAttribute(\"role\",c.role);c=this.keys;c[40]=\"next\";c[9]=\"next\";c[38]=\"prev\";c[CKEDITOR.SHIFT+9]=\"prev\";c[32]=CKEDITOR.env.ie?\"mouseup\":\"click\";CKEDITOR.env.ie&&(c[13]=\"mouseup\");this._.pendingHtml=[];this._.pendingList=[];this._.items={};this._.groups={}},_:{close:function(){if(this._.started){var b=a.output({items:this._.pendingList.join(\"\")});this._.pendingList=[];this._.pendingHtml.push(b);\ndelete this._.started}},getClick:function(){this._.click||(this._.click=CKEDITOR.tools.addFunction(function(a){var b=this.toggle(a);if(this.onClick)this.onClick(a,b)},this));return this._.click}},proto:{add:function(a,b,k){var g=CKEDITOR.tools.getNextId();this._.started||(this._.started=1,this._.size=this._.size||0);this._.items[a]=g;var h;h=CKEDITOR.tools.htmlEncodeAttr(a).replace(c,\"\\\\'\");a={id:g,val:h,onclick:CKEDITOR.env.ie?'onclick\\x3d\"return false;\" onmouseup':\"onclick\",clickFn:this._.getClick(),\ntitle:CKEDITOR.tools.htmlEncodeAttr(k||a),text:b||a};this._.pendingList.push(f.output(a))},startGroup:function(a){this._.close();var c=CKEDITOR.tools.getNextId();this._.groups[a]=c;this._.pendingHtml.push(b.output({id:c,label:a}))},commit:function(){this._.close();this.element.appendHtml(this._.pendingHtml.join(\"\"));delete this._.size;this._.pendingHtml=[]},toggle:function(a){var b=this.isMarked(a);b?this.unmark(a):this.mark(a);return!b},hideGroup:function(a){var b=(a=this.element.getDocument().getById(this._.groups[a]))&&\na.getNext();a&&(a.setStyle(\"display\",\"none\"),b&&\"ul\"==b.getName()&&b.setStyle(\"display\",\"none\"))},hideItem:function(a){this.element.getDocument().getById(this._.items[a]).setStyle(\"display\",\"none\")},showAll:function(){var a=this._.items,b=this._.groups,c=this.element.getDocument(),g;for(g in a)c.getById(a[g]).setStyle(\"display\",\"\");for(var f in b)a=c.getById(b[f]),g=a.getNext(),a.setStyle(\"display\",\"\"),g&&\"ul\"==g.getName()&&g.setStyle(\"display\",\"\")},mark:function(a){this.multiSelect||this.unmarkAll();\na=this._.items[a];var b=this.element.getDocument().getById(a);b.addClass(\"cke_selected\");this.element.getDocument().getById(a+\"_option\").setAttribute(\"aria-selected\",!0);this.onMark&&this.onMark(b)},markFirstDisplayed:function(){var a=this;this._.markFirstDisplayed(function(){a.multiSelect||a.unmarkAll()})},unmark:function(a){var b=this.element.getDocument();a=this._.items[a];var c=b.getById(a);c.removeClass(\"cke_selected\");b.getById(a+\"_option\").removeAttribute(\"aria-selected\");this.onUnmark&&this.onUnmark(c)},\nunmarkAll:function(){var a=this._.items,b=this.element.getDocument(),c;for(c in a){var g=a[c];b.getById(g).removeClass(\"cke_selected\");b.getById(g+\"_option\").removeAttribute(\"aria-selected\")}this.onUnmark&&this.onUnmark()},isMarked:function(a){return this.element.getDocument().getById(this._.items[a]).hasClass(\"cke_selected\")},focus:function(a){this._.focusIndex=-1;var b=this.element.getElementsByTag(\"a\"),c,g=-1;if(a)for(c=this.element.getDocument().getById(this._.items[a]).getFirst();a=b.getItem(++g);){if(a.equals(c)){this._.focusIndex=\ng;break}}else this.element.focus();c&&setTimeout(function(){c.focus()},0)}}})}}),CKEDITOR.plugins.add(\"richcombo\",{requires:\"floatpanel,listblock,button\",beforeInit:function(a){a.ui.addHandler(CKEDITOR.UI_RICHCOMBO,CKEDITOR.ui.richCombo.handler)}}),function(){var a='\\x3cspan id\\x3d\"{id}\" class\\x3d\"cke_combo cke_combo__{name} {cls}\" role\\x3d\"presentation\"\\x3e\\x3cspan id\\x3d\"{id}_label\" class\\x3d\"cke_combo_label\"\\x3e{label}\\x3c/span\\x3e\\x3ca class\\x3d\"cke_combo_button\" title\\x3d\"{title}\" tabindex\\x3d\"-1\"'+\n(CKEDITOR.env.gecko&&!CKEDITOR.env.hc?\"\":\" href\\x3d\\\"javascript:void('{titleJs}')\\\"\")+' hidefocus\\x3d\"true\" role\\x3d\"button\" aria-labelledby\\x3d\"{id}_label\" aria-haspopup\\x3d\"listbox\"';CKEDITOR.env.gecko&&CKEDITOR.env.mac&&(a+=' onkeypress\\x3d\"return false;\"');CKEDITOR.env.gecko&&(a+=' onblur\\x3d\"this.style.cssText \\x3d this.style.cssText;\"');var a=a+(' onkeydown\\x3d\"return CKEDITOR.tools.callFunction({keydownFn},event,this);\" onfocus\\x3d\"return CKEDITOR.tools.callFunction({focusFn},event);\" '+(CKEDITOR.env.ie?\n'onclick\\x3d\"return false;\" onmouseup':\"onclick\")+'\\x3d\"CKEDITOR.tools.callFunction({clickFn},this);return false;\"\\x3e\\x3cspan id\\x3d\"{id}_text\" class\\x3d\"cke_combo_text cke_combo_inlinelabel\"\\x3e{label}\\x3c/span\\x3e\\x3cspan class\\x3d\"cke_combo_open\"\\x3e\\x3cspan class\\x3d\"cke_combo_arrow\"\\x3e'+(CKEDITOR.env.hc?\"\\x26#9660;\":CKEDITOR.env.air?\"\\x26nbsp;\":\"\")+\"\\x3c/span\\x3e\\x3c/span\\x3e\\x3c/a\\x3e\\x3c/span\\x3e\"),f=CKEDITOR.addTemplate(\"combo\",a);CKEDITOR.UI_RICHCOMBO=\"richcombo\";CKEDITOR.ui.richCombo=\nCKEDITOR.tools.createClass({$:function(a){CKEDITOR.tools.extend(this,a,{canGroup:!1,title:a.label,modes:{wysiwyg:1},editorFocus:1});a=this.panel||{};delete this.panel;this.id=CKEDITOR.tools.getNextNumber();this.document=a.parent&&a.parent.getDocument()||CKEDITOR.document;a.className=\"cke_combopanel\";a.block={multiSelect:a.multiSelect,attributes:a.attributes};a.toolbarRelated=!0;this._={panelDefinition:a,items:{},listeners:[]}},proto:{renderHtml:function(a){var c=[];this.render(a,c);return c.join(\"\")},\nrender:function(a,c){function d(){if(this.getState()!=CKEDITOR.TRISTATE_ON){var c=this.modes[a.mode]?CKEDITOR.TRISTATE_OFF:CKEDITOR.TRISTATE_DISABLED;a.readOnly&&!this.readOnly&&(c=CKEDITOR.TRISTATE_DISABLED);this.setState(c);this.setValue(\"\");c!=CKEDITOR.TRISTATE_DISABLED&&this.refresh&&this.refresh()}}var l=CKEDITOR.env,k=\"cke_\"+this.id,g=CKEDITOR.tools.addFunction(function(c){q&&(a.unlockSelection(1),q=0);m.execute(c)},this),h=this,m={id:k,combo:this,focus:function(){CKEDITOR.document.getById(k).getChild(1).focus()},\nexecute:function(c){var d=h._;if(d.state!=CKEDITOR.TRISTATE_DISABLED)if(h.createPanel(a),d.on)d.panel.hide();else{h.commit();var e=h.getValue();e?d.list.mark(e):d.list.unmarkAll();d.panel.showBlock(h.id,new CKEDITOR.dom.element(c),4)}},clickFn:g};this._.listeners.push(a.on(\"activeFilterChange\",d,this));this._.listeners.push(a.on(\"mode\",d,this));this._.listeners.push(a.on(\"selectionChange\",d,this));!this.readOnly&&this._.listeners.push(a.on(\"readOnly\",d,this));var e=CKEDITOR.tools.addFunction(function(a,\nb){a=new CKEDITOR.dom.event(a);var c=a.getKeystroke();switch(c){case 13:case 32:case 40:CKEDITOR.tools.callFunction(g,b);break;default:m.onkey(m,c)}a.preventDefault()}),n=CKEDITOR.tools.addFunction(function(){m.onfocus&&m.onfocus()}),q=0;m.keyDownFn=e;l={id:k,name:this.name||this.command,label:this.label,title:this.title,cls:this.className||\"\",titleJs:l.gecko&&!l.hc?\"\":(this.title||\"\").replace(\"'\",\"\"),keydownFn:e,focusFn:n,clickFn:g};f.output(l,c);if(this.onRender)this.onRender();return m},createPanel:function(a){if(!this._.panel){var c=\nthis._.panelDefinition,d=this._.panelDefinition.block,f=c.parent||CKEDITOR.document.getBody(),k=\"cke_combopanel__\"+this.name,g=new CKEDITOR.ui.floatPanel(a,f,c),c=g.addListBlock(this.id,d),h=this;g.onShow=function(){this.element.addClass(k);h.setState(CKEDITOR.TRISTATE_ON);h._.on=1;h.editorFocus&&!a.focusManager.hasFocus&&a.focus();if(h.onOpen)h.onOpen()};g.onHide=function(c){this.element.removeClass(k);h.setState(h.modes&&h.modes[a.mode]?CKEDITOR.TRISTATE_OFF:CKEDITOR.TRISTATE_DISABLED);h._.on=0;\nif(!c&&h.onClose)h.onClose()};g.onEscape=function(){g.hide(1)};c.onClick=function(a,b){h.onClick&&h.onClick.call(h,a,b);g.hide()};this._.panel=g;this._.list=c;g.getBlock(this.id).onHide=function(){h._.on=0;h.setState(CKEDITOR.TRISTATE_OFF)};this.init&&this.init()}},setValue:function(a,c){this._.value=a;var d=this.document.getById(\"cke_\"+this.id+\"_text\");d&&(a||c?d.removeClass(\"cke_combo_inlinelabel\"):(c=this.label,d.addClass(\"cke_combo_inlinelabel\")),d.setText(\"undefined\"!=typeof c?c:a))},getValue:function(){return this._.value||\n\"\"},unmarkAll:function(){this._.list.unmarkAll()},mark:function(a){this._.list.mark(a)},hideItem:function(a){this._.list.hideItem(a)},hideGroup:function(a){this._.list.hideGroup(a)},showAll:function(){this._.list.showAll()},add:function(a,c,d){this._.items[a]=d||a;this._.list.add(a,c,d)},startGroup:function(a){this._.list.startGroup(a)},commit:function(){this._.committed||(this._.list.commit(),this._.committed=1,CKEDITOR.ui.fire(\"ready\",this));this._.committed=1},setState:function(a){if(this._.state!=\na){var c=this.document.getById(\"cke_\"+this.id);c.setState(a,\"cke_combo\");a==CKEDITOR.TRISTATE_DISABLED?c.setAttribute(\"aria-disabled\",!0):c.removeAttribute(\"aria-disabled\");this._.state=a}},getState:function(){return this._.state},enable:function(){this._.state==CKEDITOR.TRISTATE_DISABLED&&this.setState(this._.lastState)},disable:function(){this._.state!=CKEDITOR.TRISTATE_DISABLED&&(this._.lastState=this._.state,this.setState(CKEDITOR.TRISTATE_DISABLED))},destroy:function(){CKEDITOR.tools.array.forEach(this._.listeners,\nfunction(a){a.removeListener()});this._.listeners=[]}},statics:{handler:{create:function(a){return new CKEDITOR.ui.richCombo(a)}}}});CKEDITOR.ui.prototype.addRichCombo=function(a,c){this.add(a,CKEDITOR.UI_RICHCOMBO,c)}}(),CKEDITOR.plugins.add(\"format\",{requires:\"richcombo\",init:function(a){if(!a.blockless){for(var f=a.config,b=a.lang.format,c=f.format_tags.split(\";\"),d={},l=0,k=[],g=0;g<c.length;g++){var h=c[g],m=new CKEDITOR.style(f[\"format_\"+h]);if(!a.filter.customConfig||a.filter.check(m))l++,\nd[h]=m,d[h]._.enterMode=a.config.enterMode,k.push(m)}0!==l&&a.ui.addRichCombo(\"Format\",{label:b.label,title:b.panelTitle,toolbar:\"styles,20\",allowedContent:k,panel:{css:[CKEDITOR.skin.getPath(\"editor\")].concat(f.contentsCss),multiSelect:!1,attributes:{\"aria-label\":b.panelTitle}},init:function(){this.startGroup(b.panelTitle);for(var a in d){var c=b[\"tag_\"+a];this.add(a,d[a].buildPreview(c),c)}},onClick:function(b){a.focus();a.fire(\"saveSnapshot\");b=d[b];var c=a.elementPath();b.checkActive(c,a)||a.applyStyle(b);\nsetTimeout(function(){a.fire(\"saveSnapshot\")},0)},onRender:function(){a.on(\"selectionChange\",function(b){var c=this.getValue();b=b.data.path;this.refresh();for(var g in d)if(d[g].checkActive(b,a)){g!=c&&this.setValue(g,a.lang.format[\"tag_\"+g]);return}this.setValue(\"\")},this)},onOpen:function(){this.showAll();for(var b in d)a.activeFilter.check(d[b])||this.hideItem(b)},refresh:function(){var b=a.elementPath();if(b){if(b.isContextFor(\"p\"))for(var c in d)if(a.activeFilter.check(d[c]))return;this.setState(CKEDITOR.TRISTATE_DISABLED)}}})}}}),\nCKEDITOR.config.format_tags=\"p;h1;h2;h3;h4;h5;h6;pre;address;div\",CKEDITOR.config.format_p={element:\"p\"},CKEDITOR.config.format_div={element:\"div\"},CKEDITOR.config.format_pre={element:\"pre\"},CKEDITOR.config.format_address={element:\"address\"},CKEDITOR.config.format_h1={element:\"h1\"},CKEDITOR.config.format_h2={element:\"h2\"},CKEDITOR.config.format_h3={element:\"h3\"},CKEDITOR.config.format_h4={element:\"h4\"},CKEDITOR.config.format_h5={element:\"h5\"},CKEDITOR.config.format_h6={element:\"h6\"},function(){var a=\n{canUndo:!1,exec:function(a){var b=a.document.createElement(\"hr\");a.insertElement(b)},allowedContent:\"hr\",requiredContent:\"hr\"};CKEDITOR.plugins.add(\"horizontalrule\",{init:function(f){f.blockless||(f.addCommand(\"horizontalrule\",a),f.ui.addButton&&f.ui.addButton(\"HorizontalRule\",{label:f.lang.horizontalrule.toolbar,command:\"horizontalrule\",toolbar:\"insert,40\"}))}})}(),CKEDITOR.plugins.add(\"htmlwriter\",{init:function(a){var f=new CKEDITOR.htmlWriter;f.forceSimpleAmpersand=a.config.forceSimpleAmpersand;\nf.indentationChars=a.config.dataIndentationChars||\"\\t\";a.dataProcessor.writer=f}}),CKEDITOR.htmlWriter=CKEDITOR.tools.createClass({base:CKEDITOR.htmlParser.basicWriter,$:function(){this.base();this.indentationChars=\"\\t\";this.selfClosingEnd=\" /\\x3e\";this.lineBreakChars=\"\\n\";this.sortAttributes=1;this._.indent=0;this._.indentation=\"\";this._.inPre=0;this._.rules={};var a=CKEDITOR.dtd,f;for(f in CKEDITOR.tools.extend({},a.$nonBodyContent,a.$block,a.$listItem,a.$tableContent))this.setRules(f,{indent:!a[f][\"#\"],\nbreakBeforeOpen:1,breakBeforeClose:!a[f][\"#\"],breakAfterClose:1,needsSpace:f in a.$block&&!(f in{li:1,dt:1,dd:1})});this.setRules(\"br\",{breakAfterOpen:1});this.setRules(\"title\",{indent:0,breakAfterOpen:0});this.setRules(\"style\",{indent:0,breakBeforeClose:1});this.setRules(\"pre\",{breakAfterOpen:1,indent:0})},proto:{openTag:function(a){var f=this._.rules[a];this._.afterCloser&&f&&f.needsSpace&&this._.needsSpace&&this._.output.push(\"\\n\");this._.indent?this.indentation():f&&f.breakBeforeOpen&&(this.lineBreak(),\nthis.indentation());this._.output.push(\"\\x3c\",a);this._.afterCloser=0},openTagClose:function(a,f){var b=this._.rules[a];f?(this._.output.push(this.selfClosingEnd),b&&b.breakAfterClose&&(this._.needsSpace=b.needsSpace)):(this._.output.push(\"\\x3e\"),b&&b.indent&&(this._.indentation+=this.indentationChars));b&&b.breakAfterOpen&&this.lineBreak();\"pre\"==a&&(this._.inPre=1)},attribute:function(a,f){\"string\"==typeof f&&(f=CKEDITOR.tools.htmlEncodeAttr(f),this.forceSimpleAmpersand&&(f=f.replace(/&amp;/g,\"\\x26\")));\nthis._.output.push(\" \",a,'\\x3d\"',f,'\"')},closeTag:function(a){var f=this._.rules[a];f&&f.indent&&(this._.indentation=this._.indentation.substr(this.indentationChars.length));this._.indent?this.indentation():f&&f.breakBeforeClose&&(this.lineBreak(),this.indentation());this._.output.push(\"\\x3c/\",a,\"\\x3e\");\"pre\"==a&&(this._.inPre=0);f&&f.breakAfterClose&&(this.lineBreak(),this._.needsSpace=f.needsSpace);this._.afterCloser=1},text:function(a){this._.indent&&(this.indentation(),!this._.inPre&&(a=CKEDITOR.tools.ltrim(a)));\nthis._.output.push(a)},comment:function(a){this._.indent&&this.indentation();this._.output.push(\"\\x3c!--\",a,\"--\\x3e\")},lineBreak:function(){!this._.inPre&&0<this._.output.length&&this._.output.push(this.lineBreakChars);this._.indent=1},indentation:function(){!this._.inPre&&this._.indentation&&this._.output.push(this._.indentation);this._.indent=0},reset:function(){this._.output=[];this._.indent=0;this._.indentation=\"\";this._.afterCloser=0;this._.inPre=0;this._.needsSpace=0},setRules:function(a,f){var b=\nthis._.rules[a];b?CKEDITOR.tools.extend(b,f,!0):this._.rules[a]=f}}}),function(){function a(a,c){c||(c=a.getSelection().getSelectedElement());if(c&&c.is(\"img\")&&!c.data(\"cke-realelement\")&&!c.isReadOnly())return c}function f(a){var c=a.getStyle(\"float\");if(\"inherit\"==c||\"none\"==c)c=0;c||(c=a.getAttribute(\"align\"));return c}CKEDITOR.plugins.add(\"image\",{requires:\"dialog\",init:function(b){if(!b.plugins.detectConflict(\"image\",[\"easyimage\",\"image2\"])){CKEDITOR.dialog.add(\"image\",this.path+\"dialogs/image.js\");\nvar c=\"img[alt,!src]{border-style,border-width,float,height,margin,margin-bottom,margin-left,margin-right,margin-top,width}\";CKEDITOR.dialog.isTabEnabled(b,\"image\",\"advanced\")&&(c=\"img[alt,dir,id,lang,longdesc,!src,title]{*}(*)\");b.addCommand(\"image\",new CKEDITOR.dialogCommand(\"image\",{allowedContent:c,requiredContent:\"img[alt,src]\",contentTransformations:[[\"img{width}: sizeToStyle\",\"img[width]: sizeToAttribute\"],[\"img{float}: alignmentToStyle\",\"img[align]: alignmentToAttribute\"]]}));b.ui.addButton&&\nb.ui.addButton(\"Image\",{label:b.lang.common.image,command:\"image\",toolbar:\"insert,10\"});b.on(\"doubleclick\",function(a){var b=a.data.element;!b.is(\"img\")||b.data(\"cke-realelement\")||b.isReadOnly()||(a.data.dialog=\"image\")});b.addMenuItems&&b.addMenuItems({image:{label:b.lang.image.menu,command:\"image\",group:\"image\"}});b.contextMenu&&b.contextMenu.addListener(function(c){if(a(b,c))return{image:CKEDITOR.TRISTATE_OFF}})}},afterInit:function(b){function c(c){var l=b.getCommand(\"justify\"+c);if(l){if(\"left\"==\nc||\"right\"==c)l.on(\"exec\",function(k){var g=a(b),h;g&&(h=f(g),h==c?(g.removeStyle(\"float\"),c==f(g)&&g.removeAttribute(\"align\")):g.setStyle(\"float\",c),k.cancel())});l.on(\"refresh\",function(k){var g=a(b);g&&(g=f(g),this.setState(g==c?CKEDITOR.TRISTATE_ON:\"right\"==c||\"left\"==c?CKEDITOR.TRISTATE_OFF:CKEDITOR.TRISTATE_DISABLED),k.cancel())})}}b.plugins.image2||(c(\"left\"),c(\"right\"),c(\"center\"),c(\"block\"))}})}(),CKEDITOR.config.image_removeLinkByEmptyURL=!0,function(){function a(a,b){var d=c.exec(a),f=\nc.exec(b);if(d){if(!d[2]&&\"px\"==f[2])return f[1];if(\"px\"==d[2]&&!f[2])return f[1]+\"px\"}return b}var f=CKEDITOR.htmlParser.cssStyle,b=CKEDITOR.tools.cssLength,c=/^((?:\\d*(?:\\.\\d+))|(?:\\d+))(.*)?$/i,d={elements:{$:function(b){var c=b.attributes;if((c=(c=(c=c&&c[\"data-cke-realelement\"])&&new CKEDITOR.htmlParser.fragment.fromHtml(decodeURIComponent(c)))&&c.children[0])&&b.attributes[\"data-cke-resizable\"]){var d=(new f(b)).rules;b=c.attributes;var h=d.width,d=d.height;h&&(b.width=a(b.width,h));d&&(b.height=\na(b.height,d))}return c}}};CKEDITOR.plugins.add(\"fakeobjects\",{init:function(a){a.filter.allow(\"img[!data-cke-realelement,src,alt,title](*){*}\",\"fakeobjects\")},afterInit:function(a){(a=(a=a.dataProcessor)&&a.htmlFilter)&&a.addRules(d,{applyToAll:!0})}});CKEDITOR.editor.prototype.createFakeElement=function(a,c,d,h){var m=this.lang.fakeobjects,m=m[d]||m.unknown;c={\"class\":c,\"data-cke-realelement\":encodeURIComponent(a.getOuterHtml()),\"data-cke-real-node-type\":a.type,alt:m,title:m,align:a.getAttribute(\"align\")||\n\"\"};CKEDITOR.env.hc||(c.src=CKEDITOR.tools.transparentImageData);d&&(c[\"data-cke-real-element-type\"]=d);h&&(c[\"data-cke-resizable\"]=h,d=new f,h=a.getAttribute(\"width\"),a=a.getAttribute(\"height\"),h&&(d.rules.width=b(h)),a&&(d.rules.height=b(a)),d.populate(c));return this.document.createElement(\"img\",{attributes:c})};CKEDITOR.editor.prototype.createFakeParserElement=function(a,c,d,h){var m=this.lang.fakeobjects,m=m[d]||m.unknown,e;e=new CKEDITOR.htmlParser.basicWriter;a.writeHtml(e);e=e.getHtml();c=\n{\"class\":c,\"data-cke-realelement\":encodeURIComponent(e),\"data-cke-real-node-type\":a.type,alt:m,title:m,align:a.attributes.align||\"\"};CKEDITOR.env.hc||(c.src=CKEDITOR.tools.transparentImageData);d&&(c[\"data-cke-real-element-type\"]=d);h&&(c[\"data-cke-resizable\"]=h,h=a.attributes,a=new f,d=h.width,h=h.height,void 0!==d&&(a.rules.width=b(d)),void 0!==h&&(a.rules.height=b(h)),a.populate(c));return new CKEDITOR.htmlParser.element(\"img\",c)};CKEDITOR.editor.prototype.restoreRealElement=function(b){if(b.data(\"cke-real-node-type\")!=\nCKEDITOR.NODE_ELEMENT)return null;var c=CKEDITOR.dom.element.createFromHtml(decodeURIComponent(b.data(\"cke-realelement\")),this.document);if(b.data(\"cke-resizable\")){var d=b.getStyle(\"width\");b=b.getStyle(\"height\");d&&c.setAttribute(\"width\",a(c.getAttribute(\"width\"),d));b&&c.setAttribute(\"height\",a(c.getAttribute(\"height\"),b))}return c}}(),\"use strict\",function(){function a(a){return a.replace(/'/g,\"\\\\$\\x26\")}function f(a){for(var b,c=a.length,d=[],e=0;e<c;e++)b=a.charCodeAt(e),d.push(b);return\"String.fromCharCode(\"+\nd.join(\",\")+\")\"}function b(b,c){var d=b.plugins.link,e=d.compiledProtectionFunction.params,g,f;f=[d.compiledProtectionFunction.name,\"(\"];for(var h=0;h<e.length;h++)d=e[h].toLowerCase(),g=c[d],0<h&&f.push(\",\"),f.push(\"'\",g?a(encodeURIComponent(c[d])):\"\",\"'\");f.push(\")\");return f.join(\"\")}function c(a){a=a.config.emailProtection||\"\";var b;a&&\"encode\"!=a&&(b={},a.replace(/^([^(]+)\\(([^)]+)\\)$/,function(a,c,d){b.name=c;b.params=[];d.replace(/[^,\\s]+/g,function(a){b.params.push(a)})}));return b}CKEDITOR.plugins.add(\"link\",\n{requires:\"dialog,fakeobjects\",onLoad:function(){function a(b){return c.replace(/%1/g,\"rtl\"==b?\"right\":\"left\").replace(/%2/g,\"cke_contents_\"+b)}var b=\"background:url(\"+CKEDITOR.getUrl(this.path+\"images\"+(CKEDITOR.env.hidpi?\"/hidpi\":\"\")+\"/anchor.png\")+\") no-repeat %1 center;border:1px dotted #00f;background-size:16px;\",c=\".%2 a.cke_anchor,.%2 a.cke_anchor_empty,.cke_editable.%2 a[name],.cke_editable.%2 a[data-cke-saved-name]{\"+b+\"padding-%1:18px;cursor:auto;}.%2 img.cke_anchor{\"+b+\"width:16px;min-height:15px;height:1.15em;vertical-align:text-bottom;}\";\nCKEDITOR.addCss(a(\"ltr\")+a(\"rtl\"))},init:function(a){var b=\"a[!href]\";CKEDITOR.dialog.isTabEnabled(a,\"link\",\"advanced\")&&(b=b.replace(\"]\",\",accesskey,charset,dir,id,lang,name,rel,tabindex,title,type,download]{*}(*)\"));CKEDITOR.dialog.isTabEnabled(a,\"link\",\"target\")&&(b=b.replace(\"]\",\",target,onclick]\"));a.addCommand(\"link\",new CKEDITOR.dialogCommand(\"link\",{allowedContent:b,requiredContent:\"a[href]\"}));a.addCommand(\"anchor\",new CKEDITOR.dialogCommand(\"anchor\",{allowedContent:\"a[!name,id]\",requiredContent:\"a[name]\"}));\na.addCommand(\"unlink\",new CKEDITOR.unlinkCommand);a.addCommand(\"removeAnchor\",new CKEDITOR.removeAnchorCommand);a.setKeystroke(CKEDITOR.CTRL+76,\"link\");a.setKeystroke(CKEDITOR.CTRL+75,\"link\");a.ui.addButton&&(a.ui.addButton(\"Link\",{label:a.lang.link.toolbar,command:\"link\",toolbar:\"links,10\"}),a.ui.addButton(\"Unlink\",{label:a.lang.link.unlink,command:\"unlink\",toolbar:\"links,20\"}),a.ui.addButton(\"Anchor\",{label:a.lang.link.anchor.toolbar,command:\"anchor\",toolbar:\"links,30\"}));CKEDITOR.dialog.add(\"link\",\nthis.path+\"dialogs/link.js\");CKEDITOR.dialog.add(\"anchor\",this.path+\"dialogs/anchor.js\");a.on(\"doubleclick\",function(b){var c=b.data.element.getAscendant({a:1,img:1},!0);c&&!c.isReadOnly()&&(c.is(\"a\")?(b.data.dialog=!c.getAttribute(\"name\")||c.getAttribute(\"href\")&&c.getChildCount()?\"link\":\"anchor\",b.data.link=c):CKEDITOR.plugins.link.tryRestoreFakeAnchor(a,c)&&(b.data.dialog=\"anchor\"))},null,null,0);a.on(\"doubleclick\",function(b){b.data.dialog in{link:1,anchor:1}&&b.data.link&&a.getSelection().selectElement(b.data.link)},\nnull,null,20);a.addMenuItems&&a.addMenuItems({anchor:{label:a.lang.link.anchor.menu,command:\"anchor\",group:\"anchor\",order:1},removeAnchor:{label:a.lang.link.anchor.remove,command:\"removeAnchor\",group:\"anchor\",order:5},link:{label:a.lang.link.menu,command:\"link\",group:\"link\",order:1},unlink:{label:a.lang.link.unlink,command:\"unlink\",group:\"link\",order:5}});a.contextMenu&&a.contextMenu.addListener(function(b){if(!b||b.isReadOnly())return null;b=CKEDITOR.plugins.link.tryRestoreFakeAnchor(a,b);if(!b&&\n!(b=CKEDITOR.plugins.link.getSelectedLink(a)))return null;var c={};b.getAttribute(\"href\")&&b.getChildCount()&&(c={link:CKEDITOR.TRISTATE_OFF,unlink:CKEDITOR.TRISTATE_OFF});b&&b.hasAttribute(\"name\")&&(c.anchor=c.removeAnchor=CKEDITOR.TRISTATE_OFF);return c});this.compiledProtectionFunction=c(a)},afterInit:function(a){a.dataProcessor.dataFilter.addRules({elements:{a:function(b){return b.attributes.name?b.children.length?null:a.createFakeParserElement(b,\"cke_anchor\",\"anchor\"):null}}});var b=a._.elementsPath&&\na._.elementsPath.filters;b&&b.push(function(b,c){if(\"a\"==c&&(CKEDITOR.plugins.link.tryRestoreFakeAnchor(a,b)||b.getAttribute(\"name\")&&(!b.getAttribute(\"href\")||!b.getChildCount())))return\"anchor\"})}});var d=/^javascript:/,l=/^mailto:([^?]+)(?:\\?(.+))?$/,k=/subject=([^;?:@&=$,\\/]*)/i,g=/body=([^;?:@&=$,\\/]*)/i,h=/^#(.*)$/,m=/^((?:http|https|ftp|news):\\/\\/)?(.*)$/,e=/^(_(?:self|top|parent|blank))$/,n=/^javascript:void\\(location\\.href='mailto:'\\+String\\.fromCharCode\\(([^)]+)\\)(?:\\+'(.*)')?\\)$/,q=/^javascript:([^(]+)\\(([^)]+)\\)$/,\ny=/\\s*window.open\\(\\s*this\\.href\\s*,\\s*(?:'([^']*)'|null)\\s*,\\s*'([^']*)'\\s*\\)\\s*;\\s*return\\s*false;*\\s*/,u=/(?:^|,)([^=]+)=(\\d+|yes|no)/gi,p=/^tel:(.*)$/,v={id:\"advId\",dir:\"advLangDir\",accessKey:\"advAccessKey\",name:\"advName\",lang:\"advLangCode\",tabindex:\"advTabIndex\",title:\"advTitle\",type:\"advContentType\",\"class\":\"advCSSClasses\",charset:\"advCharset\",style:\"advStyles\",rel:\"advRel\"};CKEDITOR.plugins.link={getSelectedLink:function(a,b){var c=a.getSelection(),d=c.getSelectedElement(),e=c.getRanges(),\ng=[],f;if(!b&&d&&d.is(\"a\"))return d;for(d=0;d<e.length;d++)if(f=c.getRanges()[d],f.shrink(CKEDITOR.SHRINK_ELEMENT,!0,{skipBogus:!0}),(f=a.elementPath(f.getCommonAncestor()).contains(\"a\",1))&&b)g.push(f);else if(f)return f;return b?g:null},getEditorAnchors:function(a){for(var b=a.editable(),c=b.isInline()&&!a.plugins.divarea?a.document:b,b=c.getElementsByTag(\"a\"),c=c.getElementsByTag(\"img\"),d=[],e=0,g;g=b.getItem(e++);)(g.data(\"cke-saved-name\")||g.hasAttribute(\"name\"))&&d.push({name:g.data(\"cke-saved-name\")||\ng.getAttribute(\"name\"),id:g.getAttribute(\"id\")});for(e=0;g=c.getItem(e++);)(g=this.tryRestoreFakeAnchor(a,g))&&d.push({name:g.getAttribute(\"name\"),id:g.getAttribute(\"id\")});return d},fakeAnchor:!0,tryRestoreFakeAnchor:function(a,b){if(b&&b.data(\"cke-real-element-type\")&&\"anchor\"==b.data(\"cke-real-element-type\")){var c=a.restoreRealElement(b);if(c.data(\"cke-saved-name\"))return c}},parseLinkAttributes:function(a,b){var c=b&&(b.data(\"cke-saved-href\")||b.getAttribute(\"href\"))||\"\",f=a.plugins.link.compiledProtectionFunction,\nx=a.config.emailProtection,A,B={};c.match(d)&&(\"encode\"==x?c=c.replace(n,function(a,b,c){c=c||\"\";return\"mailto:\"+String.fromCharCode.apply(String,b.split(\",\"))+c.replace(/\\\\'/g,\"'\")}):x&&c.replace(q,function(a,b,c){if(b==f.name){B.type=\"email\";a=B.email={};b=/(^')|('$)/g;c=c.match(/[^,\\s]+/g);for(var d=c.length,e,g,h=0;h<d;h++)e=decodeURIComponent,g=c[h].replace(b,\"\").replace(/\\\\'/g,\"'\"),g=e(g),e=f.params[h].toLowerCase(),a[e]=g;a.address=[a.name,a.domain].join(\"@\")}}));if(!B.type)if(x=c.match(h))B.type=\n\"anchor\",B.anchor={},B.anchor.name=B.anchor.id=x[1];else if(x=c.match(p))B.type=\"tel\",B.tel=x[1];else if(x=c.match(l)){A=c.match(k);c=c.match(g);B.type=\"email\";var C=B.email={};C.address=x[1];A&&(C.subject=decodeURIComponent(A[1]));c&&(C.body=decodeURIComponent(c[1]))}else c&&(A=c.match(m))&&(B.type=\"url\",B.url={},B.url.protocol=A[1],B.url.url=A[2]);if(b){if(c=b.getAttribute(\"target\"))B.target={type:c.match(e)?c:\"frame\",name:c};else if(c=(c=b.data(\"cke-pa-onclick\")||b.getAttribute(\"onclick\"))&&c.match(y))for(B.target=\n{type:\"popup\",name:c[1]};x=u.exec(c[2]);)\"yes\"!=x[2]&&\"1\"!=x[2]||x[1]in{height:1,width:1,top:1,left:1}?isFinite(x[2])&&(B.target[x[1]]=x[2]):B.target[x[1]]=!0;null!==b.getAttribute(\"download\")&&(B.download=!0);var c={},H;for(H in v)(x=b.getAttribute(H))&&(c[v[H]]=x);if(H=b.data(\"cke-saved-name\")||c.advName)c.advName=H;CKEDITOR.tools.isEmpty(c)||(B.advanced=c)}return B},getLinkAttributes:function(c,d){var e=c.config.emailProtection||\"\",g={};switch(d.type){case \"url\":var e=d.url&&void 0!==d.url.protocol?\nd.url.protocol:\"http://\",h=d.url&&CKEDITOR.tools.trim(d.url.url)||\"\";g[\"data-cke-saved-href\"]=0===h.indexOf(\"/\")?h:e+h;break;case \"anchor\":e=d.anchor&&d.anchor.id;g[\"data-cke-saved-href\"]=\"#\"+(d.anchor&&d.anchor.name||e||\"\");break;case \"email\":var k=d.email,h=k.address;switch(e){case \"\":case \"encode\":var l=encodeURIComponent(k.subject||\"\"),m=encodeURIComponent(k.body||\"\"),k=[];l&&k.push(\"subject\\x3d\"+l);m&&k.push(\"body\\x3d\"+m);k=k.length?\"?\"+k.join(\"\\x26\"):\"\";\"encode\"==e?(e=[\"javascript:void(location.href\\x3d'mailto:'+\",\nf(h)],k&&e.push(\"+'\",a(k),\"'\"),e.push(\")\")):e=[\"mailto:\",h,k];break;default:e=h.split(\"@\",2),k.name=e[0],k.domain=e[1],e=[\"javascript:\",b(c,k)]}g[\"data-cke-saved-href\"]=e.join(\"\");break;case \"tel\":g[\"data-cke-saved-href\"]=\"tel:\"+d.tel}if(d.target)if(\"popup\"==d.target.type){for(var e=[\"window.open(this.href, '\",d.target.name||\"\",\"', '\"],n=\"resizable status location toolbar menubar fullscreen scrollbars dependent\".split(\" \"),h=n.length,l=function(a){d.target[a]&&n.push(a+\"\\x3d\"+d.target[a])},k=0;k<\nh;k++)n[k]+=d.target[n[k]]?\"\\x3dyes\":\"\\x3dno\";l(\"width\");l(\"left\");l(\"height\");l(\"top\");e.push(n.join(\",\"),\"'); return false;\");g[\"data-cke-pa-onclick\"]=e.join(\"\")}else\"notSet\"!=d.target.type&&d.target.name&&(g.target=d.target.name);d.download&&(g.download=\"\");if(d.advanced){for(var q in v)(e=d.advanced[v[q]])&&(g[q]=e);g.name&&(g[\"data-cke-saved-name\"]=g.name)}g[\"data-cke-saved-href\"]&&(g.href=g[\"data-cke-saved-href\"]);q={target:1,onclick:1,\"data-cke-pa-onclick\":1,\"data-cke-saved-name\":1,download:1};\nd.advanced&&CKEDITOR.tools.extend(q,v);for(var p in g)delete q[p];return{set:g,removed:CKEDITOR.tools.object.keys(q)}},showDisplayTextForElement:function(a,b){var c={img:1,table:1,tbody:1,thead:1,tfoot:1,input:1,select:1,textarea:1},d=b.getSelection();return b.widgets&&b.widgets.focused||d&&1<d.getRanges().length?!1:!a||!a.getName||!a.is(c)}};CKEDITOR.unlinkCommand=function(){};CKEDITOR.unlinkCommand.prototype={exec:function(a){if(CKEDITOR.env.ie){var b=a.getSelection().getRanges()[0],c=b.getPreviousEditableNode()&&\nb.getPreviousEditableNode().getAscendant(\"a\",!0)||b.getNextEditableNode()&&b.getNextEditableNode().getAscendant(\"a\",!0),d;b.collapsed&&c&&(d=b.createBookmark(),b.selectNodeContents(c),b.select())}c=new CKEDITOR.style({element:\"a\",type:CKEDITOR.STYLE_INLINE,alwaysRemoveElement:1});a.removeStyle(c);d&&(b.moveToBookmark(d),b.select())},refresh:function(a,b){var c=b.lastElement&&b.lastElement.getAscendant(\"a\",!0);c&&\"a\"==c.getName()&&c.getAttribute(\"href\")&&c.getChildCount()?this.setState(CKEDITOR.TRISTATE_OFF):\nthis.setState(CKEDITOR.TRISTATE_DISABLED)},contextSensitive:1,startDisabled:1,requiredContent:\"a[href]\",editorFocus:1};CKEDITOR.removeAnchorCommand=function(){};CKEDITOR.removeAnchorCommand.prototype={exec:function(a){var b=a.getSelection(),c=b.createBookmarks(),d;if(b&&(d=b.getSelectedElement())&&(d.getChildCount()?d.is(\"a\"):CKEDITOR.plugins.link.tryRestoreFakeAnchor(a,d)))d.remove(1);else if(d=CKEDITOR.plugins.link.getSelectedLink(a))d.hasAttribute(\"href\")?(d.removeAttributes({name:1,\"data-cke-saved-name\":1}),\nd.removeClass(\"cke_anchor\")):d.remove(1);b.selectBookmarks(c)},requiredContent:\"a[name]\"};CKEDITOR.tools.extend(CKEDITOR.config,{linkShowAdvancedTab:!0,linkShowTargetTab:!0})}(),\"use strict\",function(){function a(a,b,c){return n(b)&&n(c)&&c.equals(b.getNext(function(a){return!(P(a)||S(a)||q(a))}))}function f(a){this.upper=a[0];this.lower=a[1];this.set.apply(this,a.slice(2))}function b(a){var b=a.element;if(b&&n(b)&&(b=b.getAscendant(a.triggers,!0))&&a.editable.contains(b)){var c=k(b);if(\"true\"==c.getAttribute(\"contenteditable\"))return b;\nif(c.is(a.triggers))return c}return null}function c(a,b,c){t(a,b);t(a,c);a=b.size.bottom;c=c.size.top;return a&&c?0|(a+c)/2:a||c}function d(a,b,c){return b=b[c?\"getPrevious\":\"getNext\"](function(b){return b&&b.type==CKEDITOR.NODE_TEXT&&!P(b)||n(b)&&!q(b)&&!e(a,b)})}function l(a,b,c){return a>b&&a<c}function k(a,b){if(a.data(\"cke-editable\"))return null;for(b||(a=a.getParent());a&&!a.data(\"cke-editable\");){if(a.hasAttribute(\"contenteditable\"))return a;a=a.getParent()}return null}function g(a){var b=\na.doc,c=F('\\x3cspan contenteditable\\x3d\"false\" data-cke-magic-line\\x3d\"1\" style\\x3d\"'+ca+\"position:absolute;border-top:1px dashed \"+a.boxColor+'\"\\x3e\\x3c/span\\x3e',b),d=CKEDITOR.getUrl(this.path+\"images/\"+(I.hidpi?\"hidpi/\":\"\")+\"icon\"+(a.rtl?\"-rtl\":\"\")+\".png\");C(c,{attach:function(){this.wrap.getParent()||this.wrap.appendTo(a.editable,!0);return this},lineChildren:[C(F('\\x3cspan title\\x3d\"'+a.editor.lang.magicline.title+'\" contenteditable\\x3d\"false\"\\x3e\\x26#8629;\\x3c/span\\x3e',b),{base:ca+\"height:17px;width:17px;\"+\n(a.rtl?\"left\":\"right\")+\":17px;background:url(\"+d+\") center no-repeat \"+a.boxColor+\";cursor:pointer;\"+(I.hc?\"font-size: 15px;line-height:14px;border:1px solid #fff;text-align:center;\":\"\")+(I.hidpi?\"background-size: 9px 10px;\":\"\"),looks:[\"top:-8px; border-radius: 2px;\",\"top:-17px; border-radius: 2px 2px 0px 0px;\",\"top:-1px; border-radius: 0px 0px 2px 2px;\"]}),C(F(M,b),{base:V+\"left:0px;border-left-color:\"+a.boxColor+\";\",looks:[\"border-width:8px 0 8px 8px;top:-8px\",\"border-width:8px 0 0 8px;top:-8px\",\n\"border-width:0 0 8px 8px;top:0px\"]}),C(F(M,b),{base:V+\"right:0px;border-right-color:\"+a.boxColor+\";\",looks:[\"border-width:8px 8px 8px 0;top:-8px\",\"border-width:8px 8px 0 0;top:-8px\",\"border-width:0 8px 8px 0;top:0px\"]})],detach:function(){this.wrap.getParent()&&this.wrap.remove();return this},mouseNear:function(){t(a,this);var b=a.holdDistance,c=this.size;return c&&l(a.mouse.y,c.top-b,c.bottom+b)&&l(a.mouse.x,c.left-b,c.right+b)?!0:!1},place:function(){var b=a.view,c=a.editable,d=a.trigger,e=d.upper,\ng=d.lower,f=e||g,h=f.getParent(),k={};this.trigger=d;e&&t(a,e,!0);g&&t(a,g,!0);t(a,h,!0);a.inInlineMode&&x(a,!0);h.equals(c)?(k.left=b.scroll.x,k.right=-b.scroll.x,k.width=\"\"):(k.left=f.size.left-f.size.margin.left+b.scroll.x-(a.inInlineMode?b.editable.left+b.editable.border.left:0),k.width=f.size.outerWidth+f.size.margin.left+f.size.margin.right+b.scroll.x,k.right=\"\");e&&g?k.top=e.size.margin.bottom===g.size.margin.top?0|e.size.bottom+e.size.margin.bottom/2:e.size.margin.bottom<g.size.margin.top?\ne.size.bottom+e.size.margin.bottom:e.size.bottom+e.size.margin.bottom-g.size.margin.top:e?g||(k.top=e.size.bottom+e.size.margin.bottom):k.top=g.size.top-g.size.margin.top;d.is(O)||l(k.top,b.scroll.y-15,b.scroll.y+5)?(k.top=a.inInlineMode?0:b.scroll.y,this.look(O)):d.is(K)||l(k.top,b.pane.bottom-5,b.pane.bottom+15)?(k.top=a.inInlineMode?b.editable.height+b.editable.padding.top+b.editable.padding.bottom:b.pane.bottom-1,this.look(K)):(a.inInlineMode&&(k.top-=b.editable.top+b.editable.border.top),this.look(W));\na.inInlineMode&&(k.top--,k.top+=b.editable.scroll.top,k.left+=b.editable.scroll.left);for(var m in k)k[m]=CKEDITOR.tools.cssLength(k[m]);this.setStyles(k)},look:function(a){if(this.oldLook!=a){for(var b=this.lineChildren.length,c;b--;)(c=this.lineChildren[b]).setAttribute(\"style\",c.base+c.looks[0|a/2]);this.oldLook=a}},wrap:new H(\"span\",a.doc)});for(b=c.lineChildren.length;b--;)c.lineChildren[b].appendTo(c);c.look(W);c.appendTo(c.wrap);c.unselectable();c.lineChildren[0].on(\"mouseup\",function(b){c.detach();\nh(a,function(b){var c=a.line.trigger;b[c.is(G)?\"insertBefore\":\"insertAfter\"](c.is(G)?c.lower:c.upper)},!0);a.editor.focus();I.ie||a.enterMode==CKEDITOR.ENTER_BR||a.hotNode.scrollIntoView();b.data.preventDefault(!0)});c.on(\"mousedown\",function(a){a.data.preventDefault(!0)});a.line=c}function h(a,b,c){var d=new CKEDITOR.dom.range(a.doc),e=a.editor,g;I.ie&&a.enterMode==CKEDITOR.ENTER_BR?g=a.doc.createText(R):(g=(g=k(a.element,!0))&&g.data(\"cke-enter-mode\")||a.enterMode,g=new H(L[g],a.doc),g.is(\"br\")||\na.doc.createText(R).appendTo(g));c&&e.fire(\"saveSnapshot\");b(g);d.moveToPosition(g,CKEDITOR.POSITION_AFTER_START);e.getSelection().selectRanges([d]);a.hotNode=g;c&&e.fire(\"saveSnapshot\")}function m(a,c){return{canUndo:!0,modes:{wysiwyg:1},exec:function(){function e(b){var d=I.ie&&9>I.version?\" \":R,g=a.hotNode&&a.hotNode.getText()==d&&a.element.equals(a.hotNode)&&a.lastCmdDirection===!!c;h(a,function(d){g&&a.hotNode&&a.hotNode.remove();d[c?\"insertAfter\":\"insertBefore\"](b);d.setAttributes({\"data-cke-magicline-hot\":1,\n\"data-cke-magicline-dir\":!!c});a.lastCmdDirection=!!c});I.ie||a.enterMode==CKEDITOR.ENTER_BR||a.hotNode.scrollIntoView();a.line.detach()}return function(g){g=g.getSelection().getStartElement();var f;g=g.getAscendant(U,1);if(!p(a,g)&&g&&!g.equals(a.editable)&&!g.contains(a.editable)){(f=k(g))&&\"false\"==f.getAttribute(\"contenteditable\")&&(g=f);a.element=g;f=d(a,g,!c);var h;n(f)&&f.is(a.triggers)&&f.is(X)&&(!d(a,f,!c)||(h=d(a,f,!c))&&n(h)&&h.is(a.triggers))?e(f):(h=b(a,g),n(h)&&(d(a,h,!c)?(g=d(a,h,!c))&&\nn(g)&&g.is(a.triggers)&&e(h):e(h)))}}}()}}function e(a,b){if(!b||b.type!=CKEDITOR.NODE_ELEMENT||!b.$)return!1;var c=a.line;return c.wrap.equals(b)||c.wrap.contains(b)}function n(a){return a&&a.type==CKEDITOR.NODE_ELEMENT&&a.$}function q(a){if(!n(a))return!1;var b;(b=y(a))||(n(a)?(b={left:1,right:1,center:1},b=!(!b[a.getComputedStyle(\"float\")]&&!b[a.getAttribute(\"align\")])):b=!1);return b}function y(a){return!!{absolute:1,fixed:1}[a.getComputedStyle(\"position\")]}function u(a,b){return n(b)?b.is(a.triggers):\nnull}function p(a,b){if(!b)return!1;for(var c=b.getParents(1),d=c.length;d--;)for(var e=a.tabuList.length;e--;)if(c[d].hasAttribute(a.tabuList[e]))return!0;return!1}function v(a,b,c){b=b[c?\"getLast\":\"getFirst\"](function(b){return a.isRelevant(b)&&!b.is(ha)});if(!b)return!1;t(a,b);return c?b.size.top>a.mouse.y:b.size.bottom<a.mouse.y}function w(a){var b=a.editable,c=a.mouse,d=a.view,g=a.triggerOffset;x(a);var h=c.y>(a.inInlineMode?d.editable.top+d.editable.height/2:Math.min(d.editable.height,d.pane.height)/\n2),b=b[h?\"getLast\":\"getFirst\"](function(a){return!(P(a)||S(a))});if(!b)return null;e(a,b)&&(b=a.line.wrap[h?\"getPrevious\":\"getNext\"](function(a){return!(P(a)||S(a))}));if(!n(b)||q(b)||!u(a,b))return null;t(a,b);return!h&&0<=b.size.top&&l(c.y,0,b.size.top+g)?(a=a.inInlineMode||0===d.scroll.y?O:W,new f([null,b,G,Q,a])):h&&b.size.bottom<=d.pane.height&&l(c.y,b.size.bottom-g,d.pane.height)?(a=a.inInlineMode||l(b.size.bottom,d.pane.height-g,d.pane.height)?K:W,new f([b,null,D,Q,a])):null}function r(a){var c=\na.mouse,e=a.view,g=a.triggerOffset,h=b(a);if(!h)return null;t(a,h);var g=Math.min(g,0|h.size.outerHeight/2),k=[],m,r;if(l(c.y,h.size.top-1,h.size.top+g))r=!1;else if(l(c.y,h.size.bottom-g,h.size.bottom+1))r=!0;else return null;if(q(h)||v(a,h,r)||h.getParent().is(Z))return null;var M=d(a,h,!r);if(M){if(M&&M.type==CKEDITOR.NODE_TEXT)return null;if(n(M)){if(q(M)||!u(a,M)||M.getParent().is(Z))return null;k=[M,h][r?\"reverse\":\"concat\"]().concat([N,Q])}}else h.equals(a.editable[r?\"getLast\":\"getFirst\"](a.isRelevant))?\n(x(a),r&&l(c.y,h.size.bottom-g,e.pane.height)&&l(h.size.bottom,e.pane.height-g,e.pane.height)?m=K:l(c.y,0,h.size.top+g)&&(m=O)):m=W,k=[null,h][r?\"reverse\":\"concat\"]().concat([r?D:G,Q,m,h.equals(a.editable[r?\"getLast\":\"getFirst\"](a.isRelevant))?r?K:O:W]);return 0 in k?new f(k):null}function z(a,b,c,d){for(var e=b.getDocumentPosition(),g={},f={},h={},k={},l=Y.length;l--;)g[Y[l]]=parseInt(b.getComputedStyle.call(b,\"border-\"+Y[l]+\"-width\"),10)||0,h[Y[l]]=parseInt(b.getComputedStyle.call(b,\"padding-\"+\nY[l]),10)||0,f[Y[l]]=parseInt(b.getComputedStyle.call(b,\"margin-\"+Y[l]),10)||0;c&&!d||A(a,d);k.top=e.y-(c?0:a.view.scroll.y);k.left=e.x-(c?0:a.view.scroll.x);k.outerWidth=b.$.offsetWidth;k.outerHeight=b.$.offsetHeight;k.height=k.outerHeight-(h.top+h.bottom+g.top+g.bottom);k.width=k.outerWidth-(h.left+h.right+g.left+g.right);k.bottom=k.top+k.outerHeight;k.right=k.left+k.outerWidth;a.inInlineMode&&(k.scroll={top:b.$.scrollTop,left:b.$.scrollLeft});return C({border:g,padding:h,margin:f,ignoreScroll:c},\nk,!0)}function t(a,b,c){if(!n(b))return b.size=null;if(!b.size)b.size={};else if(b.size.ignoreScroll==c&&b.size.date>new Date-ba)return null;return C(b.size,z(a,b,c),{date:+new Date},!0)}function x(a,b){a.view.editable=z(a,a.editable,b,!0)}function A(a,b){a.view||(a.view={});var c=a.view;if(!(!b&&c&&c.date>new Date-ba)){var d=a.win,c=d.getScrollPosition(),d=d.getViewPaneSize();C(a.view,{scroll:{x:c.x,y:c.y,width:a.doc.$.documentElement.scrollWidth-d.width,height:a.doc.$.documentElement.scrollHeight-\nd.height},pane:{width:d.width,height:d.height,bottom:d.height+c.y},date:+new Date},!0)}}function B(a,b,c,d){for(var e=d,g=d,h=0,k=!1,l=!1,m=a.view.pane.height,n=a.mouse;n.y+h<m&&0<n.y-h;){k||(k=b(e,d));l||(l=b(g,d));!k&&0<n.y-h&&(e=c(a,{x:n.x,y:n.y-h}));!l&&n.y+h<m&&(g=c(a,{x:n.x,y:n.y+h}));if(k&&l)break;h+=2}return new f([e,g,null,null])}CKEDITOR.plugins.add(\"magicline\",{init:function(a){var c=a.config,k=c.magicline_triggerOffset||30,l={editor:a,enterMode:c.enterMode,triggerOffset:k,holdDistance:0|\nk*(c.magicline_holdDistance||.5),boxColor:c.magicline_color||\"#ff0000\",rtl:\"rtl\"==c.contentsLangDirection,tabuList:[\"data-cke-hidden-sel\"].concat(c.magicline_tabuList||[]),triggers:c.magicline_everywhere?U:{table:1,hr:1,div:1,ul:1,ol:1,dl:1,form:1,blockquote:1}},M,v,t;l.isRelevant=function(a){return n(a)&&!e(l,a)&&!q(a)};a.on(\"contentDom\",function(){var k=a.editable(),n=a.document,q=a.window;C(l,{editable:k,inInlineMode:k.isInline(),doc:n,win:q,hotNode:null},!0);l.boundary=l.inInlineMode?l.editable:\nl.doc.getDocumentElement();k.is(E.$inline)||(l.inInlineMode&&!y(k)&&k.setStyles({position:\"relative\",top:null,left:null}),g.call(this,l),A(l),k.attachListener(a,\"beforeUndoImage\",function(){l.line.detach()}),k.attachListener(a,\"beforeGetData\",function(){l.line.wrap.getParent()&&(l.line.detach(),a.once(\"getData\",function(){l.line.attach()},null,null,1E3))},null,null,0),k.attachListener(l.inInlineMode?n:n.getWindow().getFrame(),\"mouseout\",function(b){if(\"wysiwyg\"==a.mode)if(l.inInlineMode){var c=b.data.$.clientX;\nb=b.data.$.clientY;A(l);x(l,!0);var d=l.view.editable,e=l.view.scroll;c>d.left-e.x&&c<d.right-e.x&&b>d.top-e.y&&b<d.bottom-e.y||(clearTimeout(t),t=null,l.line.detach())}else clearTimeout(t),t=null,l.line.detach()}),k.attachListener(k,\"keyup\",function(){l.hiddenMode=0}),k.attachListener(k,\"keydown\",function(b){if(\"wysiwyg\"==a.mode)switch(b.data.getKeystroke()){case 2228240:case 16:l.hiddenMode=1,l.line.detach()}}),k.attachListener(l.inInlineMode?k:n,\"mousemove\",function(b){v=!0;if(\"wysiwyg\"==a.mode&&\n!a.readOnly&&!t){var c={x:b.data.$.clientX,y:b.data.$.clientY};t=setTimeout(function(){l.mouse=c;t=l.trigger=null;A(l);v&&!l.hiddenMode&&a.focusManager.hasFocus&&!l.line.mouseNear()&&(l.element=aa(l,!0))&&((l.trigger=w(l)||r(l)||T(l))&&!p(l,l.trigger.upper||l.trigger.lower)?l.line.attach().place():(l.trigger=null,l.line.detach()),v=!1)},30)}}),k.attachListener(q,\"scroll\",function(){\"wysiwyg\"==a.mode&&(l.line.detach(),I.webkit&&(l.hiddenMode=1,clearTimeout(M),M=setTimeout(function(){l.mouseDown||(l.hiddenMode=\n0)},50)))}),k.attachListener(J?n:q,\"mousedown\",function(){\"wysiwyg\"==a.mode&&(l.line.detach(),l.hiddenMode=1,l.mouseDown=1)}),k.attachListener(J?n:q,\"mouseup\",function(){l.hiddenMode=0;l.mouseDown=0}),a.addCommand(\"accessPreviousSpace\",m(l)),a.addCommand(\"accessNextSpace\",m(l,!0)),a.setKeystroke([[c.magicline_keystrokePrevious,\"accessPreviousSpace\"],[c.magicline_keystrokeNext,\"accessNextSpace\"]]),a.on(\"loadSnapshot\",function(){var b,c,d,e;for(e in{p:1,br:1,div:1})for(b=a.document.getElementsByTag(e),\nd=b.count();d--;)if((c=b.getItem(d)).data(\"cke-magicline-hot\")){l.hotNode=c;l.lastCmdDirection=\"true\"===c.data(\"cke-magicline-dir\")?!0:!1;return}}),a._.magiclineBackdoor={accessFocusSpace:h,boxTrigger:f,isLine:e,getAscendantTrigger:b,getNonEmptyNeighbour:d,getSize:z,that:l,triggerEdge:r,triggerEditable:w,triggerExpand:T})},this)}});var C=CKEDITOR.tools.extend,H=CKEDITOR.dom.element,F=H.createFromHtml,I=CKEDITOR.env,J=CKEDITOR.env.ie&&9>CKEDITOR.env.version,E=CKEDITOR.dtd,L={},G=128,D=64,N=32,Q=16,\nO=4,K=2,W=1,R=\" \",Z=E.$listItem,ha=E.$tableContent,X=C({},E.$nonEditable,E.$empty),U=E.$block,ba=100,ca=\"width:0px;height:0px;padding:0px;margin:0px;display:block;z-index:9999;color:#fff;position:absolute;font-size: 0px;line-height:0px;\",V=ca+\"border-color:transparent;display:block;border-style:solid;\",M=\"\\x3cspan\\x3e\"+R+\"\\x3c/span\\x3e\";L[CKEDITOR.ENTER_BR]=\"br\";L[CKEDITOR.ENTER_P]=\"p\";L[CKEDITOR.ENTER_DIV]=\"div\";f.prototype={set:function(a,b,c){this.properties=a+b+(c||W);return this},is:function(a){return(this.properties&\na)==a}};var aa=function(){function a(b,c){var d=b.$.elementFromPoint(c.x,c.y);return d&&d.nodeType?new CKEDITOR.dom.element(d):null}return function(b,c,d){if(!b.mouse)return null;var g=b.doc,f=b.line.wrap;d=d||b.mouse;var h=a(g,d);c&&e(b,h)&&(f.hide(),h=a(g,d),f.show());return!h||h.type!=CKEDITOR.NODE_ELEMENT||!h.$||I.ie&&9>I.version&&!b.boundary.equals(h)&&!b.boundary.contains(h)?null:h}}(),P=CKEDITOR.dom.walker.whitespaces(),S=CKEDITOR.dom.walker.nodeType(CKEDITOR.NODE_COMMENT),T=function(){function b(e){var g=\ne.element,f,h,k;if(!n(g)||g.contains(e.editable)||g.isReadOnly())return null;k=B(e,function(a,b){return!b.equals(a)},function(a,b){return aa(a,!0,b)},g);f=k.upper;h=k.lower;if(a(e,f,h))return k.set(N,8);if(f&&g.contains(f))for(;!f.getParent().equals(g);)f=f.getParent();else f=g.getFirst(function(a){return d(e,a)});if(h&&g.contains(h))for(;!h.getParent().equals(g);)h=h.getParent();else h=g.getLast(function(a){return d(e,a)});if(!f||!h)return null;t(e,f);t(e,h);if(!l(e.mouse.y,f.size.top,h.size.bottom))return null;\nfor(var g=Number.MAX_VALUE,m,r,M,q;h&&!h.equals(f)&&(r=f.getNext(e.isRelevant));)m=Math.abs(c(e,f,r)-e.mouse.y),m<g&&(g=m,M=f,q=r),f=r,t(e,f);if(!M||!q||!l(e.mouse.y,M.size.top,q.size.bottom))return null;k.upper=M;k.lower=q;return k.set(N,8)}function d(a,b){return!(b&&b.type==CKEDITOR.NODE_TEXT||S(b)||q(b)||e(a,b)||b.type==CKEDITOR.NODE_ELEMENT&&b.$&&b.is(\"br\"))}return function(c){var d=b(c),e;if(e=d){e=d.upper;var g=d.lower;e=!e||!g||q(g)||q(e)||g.equals(e)||e.equals(g)||g.contains(e)||e.contains(g)?\n!1:u(c,e)&&u(c,g)&&a(c,e,g)?!0:!1}return e?d:null}}(),Y=[\"top\",\"left\",\"right\",\"bottom\"]}(),CKEDITOR.config.magicline_keystrokePrevious=CKEDITOR.CTRL+CKEDITOR.SHIFT+51,CKEDITOR.config.magicline_keystrokeNext=CKEDITOR.CTRL+CKEDITOR.SHIFT+52,function(){function a(a){if(!a||a.type!=CKEDITOR.NODE_ELEMENT||\"form\"!=a.getName())return[];for(var b=[],c=[\"style\",\"className\"],d=0;d<c.length;d++){var f=a.$.elements.namedItem(c[d]);f&&(f=new CKEDITOR.dom.element(f),b.push([f,f.nextSibling]),f.remove())}return b}\nfunction f(a,b){if(a&&a.type==CKEDITOR.NODE_ELEMENT&&\"form\"==a.getName()&&0<b.length)for(var c=b.length-1;0<=c;c--){var d=b[c][0],f=b[c][1];f?d.insertBefore(f):d.appendTo(a)}}function b(b,c){var d=a(b),h={},m=b.$;c||(h[\"class\"]=m.className||\"\",m.className=\"\");h.inline=m.style.cssText||\"\";c||(m.style.cssText=\"position: static; overflow: visible\");f(d);return h}function c(b,c){var d=a(b),h=b.$;\"class\"in c&&(h.className=c[\"class\"]);\"inline\"in c&&(h.style.cssText=c.inline);f(d)}function d(a){if(!a.editable().isInline()){var b=\nCKEDITOR.instances,c;for(c in b){var d=b[c];\"wysiwyg\"!=d.mode||d.readOnly||(d=d.document.getBody(),d.setAttribute(\"contentEditable\",!1),d.setAttribute(\"contentEditable\",!0))}a.editable().hasFocus&&(a.toolbox.focus(),a.focus())}}CKEDITOR.plugins.add(\"maximize\",{init:function(a){function f(){var b=m.getViewPaneSize();a.resize(b.width,b.height,null,!0)}if(a.elementMode!=CKEDITOR.ELEMENT_MODE_INLINE){var g=a.lang,h=CKEDITOR.document,m=h.getWindow(),e,n,q,y=CKEDITOR.TRISTATE_OFF;a.addCommand(\"maximize\",\n{modes:{wysiwyg:!CKEDITOR.env.iOS,source:!CKEDITOR.env.iOS},readOnly:1,editorFocus:!1,exec:function(){var u=a.container.getFirst(function(a){return a.type==CKEDITOR.NODE_ELEMENT&&a.hasClass(\"cke_inner\")}),p=a.ui.space(\"contents\");if(\"wysiwyg\"==a.mode){var v=a.getSelection();e=v&&v.getRanges();n=m.getScrollPosition()}else{var w=a.editable().$;e=!CKEDITOR.env.ie&&[w.selectionStart,w.selectionEnd];n=[w.scrollLeft,w.scrollTop]}if(this.state==CKEDITOR.TRISTATE_OFF){m.on(\"resize\",f);q=m.getScrollPosition();\nfor(v=a.container;v=v.getParent();)v.setCustomData(\"maximize_saved_styles\",b(v)),v.setStyle(\"z-index\",a.config.baseFloatZIndex-5);p.setCustomData(\"maximize_saved_styles\",b(p,!0));u.setCustomData(\"maximize_saved_styles\",b(u,!0));p={overflow:CKEDITOR.env.webkit?\"\":\"hidden\",width:0,height:0};h.getDocumentElement().setStyles(p);!CKEDITOR.env.gecko&&h.getDocumentElement().setStyle(\"position\",\"fixed\");CKEDITOR.env.gecko&&CKEDITOR.env.quirks||h.getBody().setStyles(p);CKEDITOR.env.ie?setTimeout(function(){m.$.scrollTo(0,\n0)},0):m.$.scrollTo(0,0);u.setStyle(\"position\",CKEDITOR.env.gecko&&CKEDITOR.env.quirks?\"fixed\":\"absolute\");u.$.offsetLeft;u.setStyles({\"z-index\":a.config.baseFloatZIndex-5,left:\"0px\",top:\"0px\"});u.addClass(\"cke_maximized\");f();p=u.getDocumentPosition();u.setStyles({left:-1*p.x+\"px\",top:-1*p.y+\"px\"});CKEDITOR.env.gecko&&d(a)}else if(this.state==CKEDITOR.TRISTATE_ON){m.removeListener(\"resize\",f);for(var v=[p,u],r=0;r<v.length;r++)c(v[r],v[r].getCustomData(\"maximize_saved_styles\")),v[r].removeCustomData(\"maximize_saved_styles\");\nfor(v=a.container;v=v.getParent();)c(v,v.getCustomData(\"maximize_saved_styles\")),v.removeCustomData(\"maximize_saved_styles\");CKEDITOR.env.ie?setTimeout(function(){m.$.scrollTo(q.x,q.y)},0):m.$.scrollTo(q.x,q.y);u.removeClass(\"cke_maximized\");CKEDITOR.env.webkit&&(u.setStyle(\"display\",\"inline\"),setTimeout(function(){u.setStyle(\"display\",\"block\")},0));a.fire(\"resize\",{outerHeight:a.container.$.offsetHeight,contentsHeight:p.$.offsetHeight,outerWidth:a.container.$.offsetWidth})}this.toggleState();if(v=\nthis.uiItems[0])p=this.state==CKEDITOR.TRISTATE_OFF?g.maximize.maximize:g.maximize.minimize,v=CKEDITOR.document.getById(v._.id),v.getChild(1).setHtml(p),v.setAttribute(\"title\",p),v.setAttribute(\"href\",'javascript:void(\"'+p+'\");');\"wysiwyg\"==a.mode?e?(CKEDITOR.env.gecko&&d(a),a.getSelection().selectRanges(e),(w=a.getSelection().getStartElement())&&w.scrollIntoView(!0)):m.$.scrollTo(n.x,n.y):(e&&(w.selectionStart=e[0],w.selectionEnd=e[1]),w.scrollLeft=n[0],w.scrollTop=n[1]);e=n=null;y=this.state;a.fire(\"maximize\",\nthis.state)},canUndo:!1});a.ui.addButton&&a.ui.addButton(\"Maximize\",{label:g.maximize.maximize,command:\"maximize\",toolbar:\"tools,10\"});a.on(\"mode\",function(){var b=a.getCommand(\"maximize\");b.setState(b.state==CKEDITOR.TRISTATE_DISABLED?CKEDITOR.TRISTATE_DISABLED:y)},null,null,100)}}})}(),function(){function a(a,b,c){var d=CKEDITOR.cleanWord;d?c():(a=CKEDITOR.getUrl(a.config.pasteFromWordCleanupFile||b+\"filter/default.js\"),CKEDITOR.scriptLoader.load(a,c,null,!0));return!d}CKEDITOR.plugins.add(\"pastefromword\",\n{requires:\"clipboard\",init:function(f){function b(a){var b=CKEDITOR.plugins.pastefromword&&CKEDITOR.plugins.pastefromword.images,c,d=[];if(b&&a.editor.filter.check(\"img[src]\")&&(c=b.extractTagsFromHtml(a.data.dataValue),0!==c.length&&(b=b.extractFromRtf(a.data.dataTransfer[\"text/rtf\"]),0!==b.length&&(CKEDITOR.tools.array.forEach(b,function(a){d.push(a.type?\"data:\"+a.type+\";base64,\"+CKEDITOR.tools.convertBytesToBase64(CKEDITOR.tools.convertHexStringToBytes(a.hex)):null)},this),c.length===d.length))))for(b=\n0;b<c.length;b++)0===c[b].indexOf(\"file://\")&&d[b]&&(a.data.dataValue=a.data.dataValue.replace(c[b],d[b]))}var c=0,d=this.path,l=void 0===f.config.pasteFromWord_inlineImages?!0:f.config.pasteFromWord_inlineImages;f.addCommand(\"pastefromword\",{canUndo:!1,async:!0,exec:function(a,b){c=1;a.execCommand(\"paste\",{type:\"html\",notification:b&&\"undefined\"!==typeof b.notification?b.notification:!0})}});CKEDITOR.plugins.clipboard.addPasteButton(f,\"PasteFromWord\",{label:f.lang.pastefromword.toolbar,command:\"pastefromword\",\ntoolbar:\"clipboard,50\"});f.on(\"paste\",function(b){var g=b.data,h=CKEDITOR.plugins.clipboard.isCustomDataTypesSupported?g.dataTransfer.getData(\"text/html\",!0):null,l=CKEDITOR.plugins.clipboard.isCustomDataTypesSupported?g.dataTransfer.getData(\"text/rtf\"):null,h=h||g.dataValue,e={dataValue:h,dataTransfer:{\"text/rtf\":l}},l=/(class=\\\"?Mso|style=(?:\\\"|\\')[^\\\"]*?\\bmso\\-|w:WordDocument|<o:\\w+>|<\\/font>)/,l=/<meta\\s*name=(?:\\\"|\\')?generator(?:\\\"|\\')?\\s*content=(?:\\\"|\\')?microsoft/gi.test(h)||l.test(h);if(h&&\n(c||l)&&(!1!==f.fire(\"pasteFromWord\",e)||c)){g.dontFilter=!0;var n=a(f,d,function(){if(n)f.fire(\"paste\",g);else if(!f.config.pasteFromWordPromptCleanup||c||confirm(f.lang.pastefromword.confirmCleanup))e.dataValue=CKEDITOR.cleanWord(e.dataValue,f),f.fire(\"afterPasteFromWord\",e),g.dataValue=e.dataValue,!0===f.config.forcePasteAsPlainText?g.type=\"text\":CKEDITOR.plugins.clipboard.isCustomCopyCutSupported||\"allow-word\"!==f.config.forcePasteAsPlainText||(g.type=\"html\");c=0});n&&b.cancel()}},null,null,3);\nif(CKEDITOR.plugins.clipboard.isCustomDataTypesSupported&&l)f.on(\"afterPasteFromWord\",b)}})}(),function(){var a={canUndo:!1,async:!0,exec:function(a,b){var c=a.lang,d=CKEDITOR.tools.keystrokeToString(c.common.keyboard,a.getCommandKeystroke(CKEDITOR.env.ie?a.commands.paste:this)),l=b&&\"undefined\"!==typeof b.notification?b.notification:!b||!b.from||\"keystrokeHandler\"===b.from&&CKEDITOR.env.ie,c=l&&\"string\"===typeof l?l:c.pastetext.pasteNotification.replace(/%1/,'\\x3ckbd aria-label\\x3d\"'+d.aria+'\"\\x3e'+\nd.display+\"\\x3c/kbd\\x3e\");a.execCommand(\"paste\",{type:\"text\",notification:l?c:!1})}};CKEDITOR.plugins.add(\"pastetext\",{requires:\"clipboard\",init:function(f){var b=CKEDITOR.env.safari?CKEDITOR.CTRL+CKEDITOR.ALT+CKEDITOR.SHIFT+86:CKEDITOR.CTRL+CKEDITOR.SHIFT+86;f.addCommand(\"pastetext\",a);f.setKeystroke(b,\"pastetext\");CKEDITOR.plugins.clipboard.addPasteButton(f,\"PasteText\",{label:f.lang.pastetext.button,command:\"pastetext\",toolbar:\"clipboard,40\"});if(f.config.forcePasteAsPlainText)f.on(\"beforePaste\",\nfunction(a){\"html\"!=a.data.type&&(a.data.type=\"text\")});f.on(\"pasteState\",function(a){f.getCommand(\"pastetext\").setState(a.data)})}})}(),CKEDITOR.plugins.add(\"removeformat\",{init:function(a){a.addCommand(\"removeFormat\",CKEDITOR.plugins.removeformat.commands.removeformat);a.ui.addButton&&a.ui.addButton(\"RemoveFormat\",{label:a.lang.removeformat.toolbar,command:\"removeFormat\",toolbar:\"cleanup,10\"})}}),CKEDITOR.plugins.removeformat={commands:{removeformat:{exec:function(a){for(var f=a._.removeFormatRegex||\n(a._.removeFormatRegex=new RegExp(\"^(?:\"+a.config.removeFormatTags.replace(/,/g,\"|\")+\")$\",\"i\")),b=a._.removeAttributes||(a._.removeAttributes=a.config.removeFormatAttributes.split(\",\")),c=CKEDITOR.plugins.removeformat.filter,d=a.getSelection().getRanges().createIterator(),l=function(a){return a.type==CKEDITOR.NODE_ELEMENT},k=[],g;g=d.getNextRange();){var h=g.createBookmark();g=a.createRange();g.setStartBefore(h.startNode);h.endNode&&g.setEndAfter(h.endNode);g.collapsed||g.enlarge(CKEDITOR.ENLARGE_ELEMENT);\nvar m=g.createBookmark(),e=m.startNode,n=m.endNode,q=function(b){for(var d=a.elementPath(b),e=d.elements,g=1,h;(h=e[g])&&!h.equals(d.block)&&!h.equals(d.blockLimit);g++)f.test(h.getName())&&c(a,h)&&b.breakParent(h)};q(e);if(n)for(q(n),e=e.getNextSourceNode(!0,CKEDITOR.NODE_ELEMENT);e&&!e.equals(n);)if(e.isReadOnly()){if(e.getPosition(n)&CKEDITOR.POSITION_CONTAINS)break;e=e.getNext(l)}else q=e.getNextSourceNode(!1,CKEDITOR.NODE_ELEMENT),\"img\"==e.getName()&&e.data(\"cke-realelement\")||e.hasAttribute(\"data-cke-bookmark\")||\n!c(a,e)||(f.test(e.getName())?e.remove(1):(e.removeAttributes(b),a.fire(\"removeFormatCleanup\",e))),e=q;m.startNode.remove();m.endNode&&m.endNode.remove();g.moveToBookmark(h);k.push(g)}a.forceNextSelectionCheck();a.getSelection().selectRanges(k)}}},filter:function(a,f){for(var b=a._.removeFormatFilters||[],c=0;c<b.length;c++)if(!1===b[c](f))return!1;return!0}},CKEDITOR.editor.prototype.addRemoveFormatFilter=function(a){this._.removeFormatFilters||(this._.removeFormatFilters=[]);this._.removeFormatFilters.push(a)},\nCKEDITOR.config.removeFormatTags=\"b,big,cite,code,del,dfn,em,font,i,ins,kbd,q,s,samp,small,span,strike,strong,sub,sup,tt,u,var\",CKEDITOR.config.removeFormatAttributes=\"class,style,lang,width,height,align,hspace,valign\",CKEDITOR.plugins.add(\"resize\",{init:function(a){function f(b){var d=h.width,f=h.height,k=d+(b.data.$.screenX-g.x)*(\"rtl\"==l?-1:1);b=f+(b.data.$.screenY-g.y);m&&(d=Math.max(c.resize_minWidth,Math.min(k,c.resize_maxWidth)));e&&(f=Math.max(c.resize_minHeight,Math.min(b,c.resize_maxHeight)));\na.resize(m?d:null,f)}function b(){CKEDITOR.document.removeListener(\"mousemove\",f);CKEDITOR.document.removeListener(\"mouseup\",b);a.document&&(a.document.removeListener(\"mousemove\",f),a.document.removeListener(\"mouseup\",b))}var c=a.config,d=a.ui.spaceId(\"resizer\"),l=a.element?a.element.getDirection(1):\"ltr\";!c.resize_dir&&(c.resize_dir=\"vertical\");void 0===c.resize_maxWidth&&(c.resize_maxWidth=3E3);void 0===c.resize_maxHeight&&(c.resize_maxHeight=3E3);void 0===c.resize_minWidth&&(c.resize_minWidth=\n750);void 0===c.resize_minHeight&&(c.resize_minHeight=250);if(!1!==c.resize_enabled){var k=null,g,h,m=(\"both\"==c.resize_dir||\"horizontal\"==c.resize_dir)&&c.resize_minWidth!=c.resize_maxWidth,e=(\"both\"==c.resize_dir||\"vertical\"==c.resize_dir)&&c.resize_minHeight!=c.resize_maxHeight,n=CKEDITOR.tools.addFunction(function(d){k||(k=a.getResizable());h={width:k.$.offsetWidth||0,height:k.$.offsetHeight||0};g={x:d.screenX,y:d.screenY};c.resize_minWidth>h.width&&(c.resize_minWidth=h.width);c.resize_minHeight>\nh.height&&(c.resize_minHeight=h.height);CKEDITOR.document.on(\"mousemove\",f);CKEDITOR.document.on(\"mouseup\",b);a.document&&(a.document.on(\"mousemove\",f),a.document.on(\"mouseup\",b));d.preventDefault&&d.preventDefault()});a.on(\"destroy\",function(){CKEDITOR.tools.removeFunction(n)});a.on(\"uiSpace\",function(b){if(\"bottom\"==b.data.space){var c=\"\";m&&!e&&(c=\" cke_resizer_horizontal\");!m&&e&&(c=\" cke_resizer_vertical\");var g='\\x3cspan id\\x3d\"'+d+'\" class\\x3d\"cke_resizer'+c+\" cke_resizer_\"+l+'\" title\\x3d\"'+\nCKEDITOR.tools.htmlEncode(a.lang.common.resize)+'\" onmousedown\\x3d\"CKEDITOR.tools.callFunction('+n+', event)\"\\x3e'+(\"ltr\"==l?\"◢\":\"◣\")+\"\\x3c/span\\x3e\";\"ltr\"==l&&\"ltr\"==c?b.data.html+=g:b.data.html=g+b.data.html}},a,null,100);a.on(\"maximize\",function(b){a.ui.space(\"resizer\")[b.data==CKEDITOR.TRISTATE_ON?\"hide\":\"show\"]()})}}}),CKEDITOR.plugins.add(\"menubutton\",{requires:\"button,menu\",onLoad:function(){var a=function(a){var b=this._,c=b.menu;b.state!==CKEDITOR.TRISTATE_DISABLED&&(b.on&&c?c.hide():(b.previousState=\nb.state,c||(c=b.menu=new CKEDITOR.menu(a,{panel:{className:\"cke_menu_panel\",attributes:{\"aria-label\":a.lang.common.options}}}),c.onHide=CKEDITOR.tools.bind(function(){var c=this.command?a.getCommand(this.command).modes:this.modes;this.setState(!c||c[a.mode]?b.previousState:CKEDITOR.TRISTATE_DISABLED);b.on=0},this),this.onMenu&&c.addListener(this.onMenu)),this.setState(CKEDITOR.TRISTATE_ON),b.on=1,setTimeout(function(){c.show(CKEDITOR.document.getById(b.id),4)},0)))};CKEDITOR.ui.menuButton=CKEDITOR.tools.createClass({base:CKEDITOR.ui.button,\n$:function(f){delete f.panel;this.base(f);this.hasArrow=\"menu\";this.click=a},statics:{handler:{create:function(a){return new CKEDITOR.ui.menuButton(a)}}}})},beforeInit:function(a){a.ui.addHandler(CKEDITOR.UI_MENUBUTTON,CKEDITOR.ui.menuButton.handler)}}),CKEDITOR.UI_MENUBUTTON=\"menubutton\",\"use strict\",CKEDITOR.plugins.add(\"scayt\",{requires:\"menubutton,dialog\",tabToOpen:null,dialogName:\"scaytDialog\",onLoad:function(a){\"moono-lisa\"==(CKEDITOR.skinName||a.config.skin)&&CKEDITOR.document.appendStyleSheet(CKEDITOR.getUrl(this.path+\n\"skins/\"+CKEDITOR.skin.name+\"/scayt.css\"));CKEDITOR.document.appendStyleSheet(CKEDITOR.getUrl(this.path+\"dialogs/dialog.css\"))},init:function(a){var f=this,b=CKEDITOR.plugins.scayt;this.bindEvents(a);this.parseConfig(a);this.addRule(a);CKEDITOR.dialog.add(this.dialogName,CKEDITOR.getUrl(this.path+\"dialogs/options.js\"));this.addMenuItems(a);var c=a.lang.scayt,d=CKEDITOR.env;a.ui.add(\"Scayt\",CKEDITOR.UI_MENUBUTTON,{label:c.text_title,title:a.plugins.wsc?a.lang.wsc.title:c.text_title,modes:{wysiwyg:!(d.ie&&\n(8>d.version||d.quirks))},toolbar:\"spellchecker,20\",refresh:function(){var c=a.ui.instances.Scayt.getState();a.scayt&&(c=b.state.scayt[a.name]?CKEDITOR.TRISTATE_ON:CKEDITOR.TRISTATE_OFF);a.fire(\"scaytButtonState\",c)},onRender:function(){var b=this;a.on(\"scaytButtonState\",function(a){void 0!==typeof a.data&&b.setState(a.data)})},onMenu:function(){var c=a.scayt;a.getMenuItem(\"scaytToggle\").label=a.lang.scayt[c&&b.state.scayt[a.name]?\"btn_disable\":\"btn_enable\"];var d={scaytToggle:CKEDITOR.TRISTATE_OFF,\nscaytOptions:c?CKEDITOR.TRISTATE_OFF:CKEDITOR.TRISTATE_DISABLED,scaytLangs:c?CKEDITOR.TRISTATE_OFF:CKEDITOR.TRISTATE_DISABLED,scaytDict:c?CKEDITOR.TRISTATE_OFF:CKEDITOR.TRISTATE_DISABLED,scaytAbout:c?CKEDITOR.TRISTATE_OFF:CKEDITOR.TRISTATE_DISABLED,WSC:a.plugins.wsc?CKEDITOR.TRISTATE_OFF:CKEDITOR.TRISTATE_DISABLED};a.config.scayt_uiTabs[0]||delete d.scaytOptions;a.config.scayt_uiTabs[1]||delete d.scaytLangs;a.config.scayt_uiTabs[2]||delete d.scaytDict;c&&!CKEDITOR.plugins.scayt.isNewUdSupported(c)&&\n(delete d.scaytDict,a.config.scayt_uiTabs[2]=0,CKEDITOR.plugins.scayt.alarmCompatibilityMessage());return d}});a.contextMenu&&a.addMenuItems&&(a.contextMenu.addListener(function(b,c){var d=a.scayt,h,m;d&&(m=d.getSelectionNode())&&(h=f.menuGenerator(a,m),d.showBanner(\".\"+a.contextMenu._.definition.panel.className.split(\" \").join(\" .\")));return h}),a.contextMenu._.onHide=CKEDITOR.tools.override(a.contextMenu._.onHide,function(b){return function(){var c=a.scayt;c&&c.hideBanner();return b.apply(this)}}))},\naddMenuItems:function(a){var f=this,b=CKEDITOR.plugins.scayt;a.addMenuGroup(\"scaytButton\");for(var c=a.config.scayt_contextMenuItemsOrder.split(\"|\"),d=0;d<c.length;d++)c[d]=\"scayt_\"+c[d];if((c=[\"grayt_description\",\"grayt_suggest\",\"grayt_control\"].concat(c))&&c.length)for(d=0;d<c.length;d++)a.addMenuGroup(c[d],d-10);a.addCommand(\"scaytToggle\",{exec:function(a){var c=a.scayt;b.state.scayt[a.name]=!b.state.scayt[a.name];!0===b.state.scayt[a.name]?c||b.createScayt(a):c&&b.destroy(a)}});a.addCommand(\"scaytAbout\",\n{exec:function(a){a.scayt.tabToOpen=\"about\";b.openDialog(f.dialogName,a)}});a.addCommand(\"scaytOptions\",{exec:function(a){a.scayt.tabToOpen=\"options\";b.openDialog(f.dialogName,a)}});a.addCommand(\"scaytLangs\",{exec:function(a){a.scayt.tabToOpen=\"langs\";b.openDialog(f.dialogName,a)}});a.addCommand(\"scaytDict\",{exec:function(a){a.scayt.tabToOpen=\"dictionaries\";b.openDialog(f.dialogName,a)}});c={scaytToggle:{label:a.lang.scayt.btn_enable,group:\"scaytButton\",command:\"scaytToggle\"},scaytAbout:{label:a.lang.scayt.btn_about,\ngroup:\"scaytButton\",command:\"scaytAbout\"},scaytOptions:{label:a.lang.scayt.btn_options,group:\"scaytButton\",command:\"scaytOptions\"},scaytLangs:{label:a.lang.scayt.btn_langs,group:\"scaytButton\",command:\"scaytLangs\"},scaytDict:{label:a.lang.scayt.btn_dictionaries,group:\"scaytButton\",command:\"scaytDict\"}};a.plugins.wsc&&(c.WSC={label:a.lang.wsc.toolbar,group:\"scaytButton\",onClick:function(){var b=CKEDITOR.plugins.scayt,c=a.scayt,d=a.elementMode==CKEDITOR.ELEMENT_MODE_INLINE?a.container.getText():a.document.getBody().getText();\n(d=d.replace(/\\s/g,\"\"))?(c&&b.state.scayt[a.name]&&c.setMarkupPaused&&c.setMarkupPaused(!0),a.lockSelection(),a.execCommand(\"checkspell\")):alert(\"Nothing to check!\")}});a.addMenuItems(c)},bindEvents:function(a){var f=CKEDITOR.plugins.scayt,b=a.elementMode==CKEDITOR.ELEMENT_MODE_INLINE,c=function(){f.destroy(a)},d=function(){!f.state.scayt[a.name]||a.readOnly||a.scayt||f.createScayt(a)},l=function(){var c=a.editable();c.attachListener(c,\"focus\",function(c){CKEDITOR.plugins.scayt&&!a.scayt&&setTimeout(d,\n0);c=CKEDITOR.plugins.scayt&&CKEDITOR.plugins.scayt.state.scayt[a.name]&&a.scayt;var g,e;if((b||c)&&a._.savedSelection){c=a._.savedSelection.getSelectedElement();c=!c&&a._.savedSelection.getRanges();for(var f=0;f<c.length;f++)e=c[f],\"string\"===typeof e.startContainer.$.nodeValue&&(g=e.startContainer.getText().length,(g<e.startOffset||g<e.endOffset)&&a.unlockSelection(!1))}},this,null,-10)},k=function(){b?a.config.scayt_inlineModeImmediateMarkup?d():(a.on(\"blur\",function(){setTimeout(c,0)}),a.on(\"focus\",\nd),a.focusManager.hasFocus&&d()):d();l();var g=a.editable();g.attachListener(g,\"mousedown\",function(b){b=b.data.getTarget();var c=a.widgets&&a.widgets.getByElement(b);c&&(c.wrapper=b.getAscendant(function(a){return a.hasAttribute(\"data-cke-widget-wrapper\")},!0))},this,null,-10)};a.on(\"contentDom\",k);a.on(\"beforeCommandExec\",function(b){var c=a.scayt,d=!1,e=!1,k=!0;b.data.name in f.options.disablingCommandExec&&\"wysiwyg\"==a.mode?c&&(f.destroy(a),a.fire(\"scaytButtonState\",CKEDITOR.TRISTATE_DISABLED)):\n\"bold\"!==b.data.name&&\"italic\"!==b.data.name&&\"underline\"!==b.data.name&&\"strike\"!==b.data.name&&\"subscript\"!==b.data.name&&\"superscript\"!==b.data.name&&\"enter\"!==b.data.name&&\"cut\"!==b.data.name&&\"language\"!==b.data.name||!c||(\"cut\"===b.data.name&&(k=!1,e=!0),\"language\"===b.data.name&&(e=d=!0),a.fire(\"reloadMarkupScayt\",{removeOptions:{removeInside:k,forceBookmark:e,language:d},timeout:0}))});a.on(\"beforeSetMode\",function(b){if(\"source\"==b.data){if(b=a.scayt)f.destroy(a),a.fire(\"scaytButtonState\",\nCKEDITOR.TRISTATE_DISABLED);a.document&&a.document.getBody().removeAttribute(\"_jquid\")}});a.on(\"afterCommandExec\",function(b){\"wysiwyg\"!=a.mode||\"undo\"!=b.data.name&&\"redo\"!=b.data.name||setTimeout(function(){f.reloadMarkup(a.scayt)},250)});a.on(\"readOnly\",function(b){var c;b&&(c=a.scayt,!0===b.editor.readOnly?c&&c.fire(\"removeMarkupInDocument\",{}):c?f.reloadMarkup(c):\"wysiwyg\"==b.editor.mode&&!0===f.state.scayt[b.editor.name]&&(f.createScayt(a),b.editor.fire(\"scaytButtonState\",CKEDITOR.TRISTATE_ON)))});\na.on(\"beforeDestroy\",c);a.on(\"setData\",function(){c();(a.elementMode==CKEDITOR.ELEMENT_MODE_INLINE||a.plugins.divarea)&&k()},this,null,50);a.on(\"reloadMarkupScayt\",function(b){var c=b.data&&b.data.removeOptions,d=b.data&&b.data.timeout,e=b.data&&b.data.language,k=a.scayt;k&&setTimeout(function(){e&&(c.selectionNode=a.plugins.language.getCurrentLangElement(a),c.selectionNode=c.selectionNode&&c.selectionNode.$||null);k.removeMarkupInSelectionNode(c);f.reloadMarkup(k)},d||0)});a.on(\"insertElement\",function(){a.fire(\"reloadMarkupScayt\",\n{removeOptions:{forceBookmark:!0}})},this,null,50);a.on(\"insertHtml\",function(){a.scayt&&a.scayt.setFocused&&a.scayt.setFocused(!0);a.fire(\"reloadMarkupScayt\")},this,null,50);a.on(\"insertText\",function(){a.scayt&&a.scayt.setFocused&&a.scayt.setFocused(!0);a.fire(\"reloadMarkupScayt\")},this,null,50);a.on(\"scaytDialogShown\",function(b){b.data.selectPage(a.scayt.tabToOpen)})},parseConfig:function(a){var f=CKEDITOR.plugins.scayt;f.replaceOldOptionsNames(a.config);\"boolean\"!==typeof a.config.scayt_autoStartup&&\n(a.config.scayt_autoStartup=!1);f.state.scayt[a.name]=a.config.scayt_autoStartup;\"boolean\"!==typeof a.config.grayt_autoStartup&&(a.config.grayt_autoStartup=!1);\"boolean\"!==typeof a.config.scayt_inlineModeImmediateMarkup&&(a.config.scayt_inlineModeImmediateMarkup=!1);f.state.grayt[a.name]=a.config.grayt_autoStartup;a.config.scayt_contextCommands||(a.config.scayt_contextCommands=\"ignoreall|add\");a.config.scayt_contextMenuItemsOrder||(a.config.scayt_contextMenuItemsOrder=\"suggest|moresuggest|control\");\na.config.scayt_sLang||(a.config.scayt_sLang=\"en_US\");if(void 0===a.config.scayt_maxSuggestions||\"number\"!=typeof a.config.scayt_maxSuggestions||0>a.config.scayt_maxSuggestions)a.config.scayt_maxSuggestions=3;if(void 0===a.config.scayt_minWordLength||\"number\"!=typeof a.config.scayt_minWordLength||1>a.config.scayt_minWordLength)a.config.scayt_minWordLength=3;if(void 0===a.config.scayt_customDictionaryIds||\"string\"!==typeof a.config.scayt_customDictionaryIds)a.config.scayt_customDictionaryIds=\"\";if(void 0===\na.config.scayt_userDictionaryName||\"string\"!==typeof a.config.scayt_userDictionaryName)a.config.scayt_userDictionaryName=null;if(\"string\"===typeof a.config.scayt_uiTabs&&3===a.config.scayt_uiTabs.split(\",\").length){var b=[],c=[];a.config.scayt_uiTabs=a.config.scayt_uiTabs.split(\",\");CKEDITOR.tools.search(a.config.scayt_uiTabs,function(a){1===Number(a)||0===Number(a)?(c.push(!0),b.push(Number(a))):c.push(!1)});null===CKEDITOR.tools.search(c,!1)?a.config.scayt_uiTabs=b:a.config.scayt_uiTabs=[1,1,1]}else a.config.scayt_uiTabs=\n[1,1,1];\"string\"!=typeof a.config.scayt_serviceProtocol&&(a.config.scayt_serviceProtocol=null);\"string\"!=typeof a.config.scayt_serviceHost&&(a.config.scayt_serviceHost=null);\"string\"!=typeof a.config.scayt_servicePort&&(a.config.scayt_servicePort=null);\"string\"!=typeof a.config.scayt_servicePath&&(a.config.scayt_servicePath=null);a.config.scayt_moreSuggestions||(a.config.scayt_moreSuggestions=\"on\");\"string\"!==typeof a.config.scayt_customerId&&(a.config.scayt_customerId=\"1:WvF0D4-UtPqN1-43nkD4-NKvUm2-daQqk3-LmNiI-z7Ysb4-mwry24-T8YrS3-Q2tpq2\");\n\"string\"!==typeof a.config.scayt_customPunctuation&&(a.config.scayt_customPunctuation=\"-\");\"string\"!==typeof a.config.scayt_srcUrl&&(f=document.location.protocol,f=-1!=f.search(/https?:/)?f:\"http:\",a.config.scayt_srcUrl=f+\"//svc.webspellchecker.net/spellcheck31/wscbundle/wscbundle.js\");\"boolean\"!==typeof CKEDITOR.config.scayt_handleCheckDirty&&(CKEDITOR.config.scayt_handleCheckDirty=!0);\"boolean\"!==typeof CKEDITOR.config.scayt_handleUndoRedo&&(CKEDITOR.config.scayt_handleUndoRedo=!0);CKEDITOR.config.scayt_handleUndoRedo=\nCKEDITOR.plugins.undo?CKEDITOR.config.scayt_handleUndoRedo:!1;\"boolean\"!==typeof a.config.scayt_multiLanguageMode&&(a.config.scayt_multiLanguageMode=!1);\"object\"!==typeof a.config.scayt_multiLanguageStyles&&(a.config.scayt_multiLanguageStyles={});a.config.scayt_ignoreAllCapsWords&&\"boolean\"!==typeof a.config.scayt_ignoreAllCapsWords&&(a.config.scayt_ignoreAllCapsWords=!1);a.config.scayt_ignoreDomainNames&&\"boolean\"!==typeof a.config.scayt_ignoreDomainNames&&(a.config.scayt_ignoreDomainNames=!1);a.config.scayt_ignoreWordsWithMixedCases&&\n\"boolean\"!==typeof a.config.scayt_ignoreWordsWithMixedCases&&(a.config.scayt_ignoreWordsWithMixedCases=!1);a.config.scayt_ignoreWordsWithNumbers&&\"boolean\"!==typeof a.config.scayt_ignoreWordsWithNumbers&&(a.config.scayt_ignoreWordsWithNumbers=!1);if(a.config.scayt_disableOptionsStorage){var f=CKEDITOR.tools.isArray(a.config.scayt_disableOptionsStorage)?a.config.scayt_disableOptionsStorage:\"string\"===typeof a.config.scayt_disableOptionsStorage?[a.config.scayt_disableOptionsStorage]:void 0,d=\"all options lang ignore-all-caps-words ignore-domain-names ignore-words-with-mixed-cases ignore-words-with-numbers\".split(\" \"),\nl=[\"lang\",\"ignore-all-caps-words\",\"ignore-domain-names\",\"ignore-words-with-mixed-cases\",\"ignore-words-with-numbers\"],k=CKEDITOR.tools.search,g=CKEDITOR.tools.indexOf;a.config.scayt_disableOptionsStorage=function(a){for(var b=[],c=0;c<a.length;c++){var f=a[c],q=!!k(a,\"options\");if(!k(d,f)||q&&k(l,function(a){if(\"lang\"===a)return!1}))return;k(l,f)&&l.splice(g(l,f),1);if(\"all\"===f||q&&k(a,\"lang\"))return[];\"options\"===f&&(l=[\"lang\"])}return b=b.concat(l)}(f)}a.config.scayt_disableCache&&\"boolean\"!==typeof a.config.scayt_disableCache&&\n(a.config.scayt_disableCache=!1);if(void 0===a.config.scayt_cacheSize||\"number\"!=typeof a.config.scayt_cacheSize||1>a.config.scayt_cacheSize)a.config.scayt_cacheSize=4E3},addRule:function(a){var f=CKEDITOR.plugins.scayt,b=a.dataProcessor,c=b&&b.htmlFilter,d=a._.elementsPath&&a._.elementsPath.filters,b=b&&b.dataFilter,l=a.addRemoveFormatFilter,k=function(b){if(a.scayt&&(b.hasAttribute(f.options.data_attribute_name)||b.hasAttribute(f.options.problem_grammar_data_attribute)))return!1},g=function(b){var c=\n!0;a.scayt&&(b.hasAttribute(f.options.data_attribute_name)||b.hasAttribute(f.options.problem_grammar_data_attribute))&&(c=!1);return c};d&&d.push(k);b&&b.addRules({elements:{span:function(a){var b=a.hasClass(f.options.misspelled_word_class)&&a.attributes[f.options.data_attribute_name],c=a.hasClass(f.options.problem_grammar_class)&&a.attributes[f.options.problem_grammar_data_attribute];f&&(b||c)&&delete a.name;return a}}});c&&c.addRules({elements:{span:function(a){var b=a.hasClass(f.options.misspelled_word_class)&&\na.attributes[f.options.data_attribute_name],c=a.hasClass(f.options.problem_grammar_class)&&a.attributes[f.options.problem_grammar_data_attribute];f&&(b||c)&&delete a.name;return a}}});l&&l.call(a,g)},scaytMenuDefinition:function(a){var f=this,b=CKEDITOR.plugins.scayt;a=a.scayt;return{scayt:{scayt_ignore:{label:a.getLocal(\"btn_ignore\"),group:\"scayt_control\",order:1,exec:function(a){a.scayt.ignoreWord()}},scayt_ignoreall:{label:a.getLocal(\"btn_ignoreAll\"),group:\"scayt_control\",order:2,exec:function(a){a.scayt.ignoreAllWords()}},\nscayt_add:{label:a.getLocal(\"btn_addWord\"),group:\"scayt_control\",order:3,exec:function(a){var b=a.scayt;setTimeout(function(){b.addWordToUserDictionary()},10)}},scayt_option:{label:a.getLocal(\"btn_options\"),group:\"scayt_control\",order:4,exec:function(a){a.scayt.tabToOpen=\"options\";b.openDialog(f.dialogName,a)},verification:function(a){return 1==a.config.scayt_uiTabs[0]?!0:!1}},scayt_language:{label:a.getLocal(\"btn_langs\"),group:\"scayt_control\",order:5,exec:function(a){a.scayt.tabToOpen=\"langs\";b.openDialog(f.dialogName,\na)},verification:function(a){return 1==a.config.scayt_uiTabs[1]?!0:!1}},scayt_dictionary:{label:a.getLocal(\"btn_dictionaries\"),group:\"scayt_control\",order:6,exec:function(a){a.scayt.tabToOpen=\"dictionaries\";b.openDialog(f.dialogName,a)},verification:function(a){return 1==a.config.scayt_uiTabs[2]?!0:!1}},scayt_about:{label:a.getLocal(\"btn_about\"),group:\"scayt_control\",order:7,exec:function(a){a.scayt.tabToOpen=\"about\";b.openDialog(f.dialogName,a)}}},grayt:{grayt_problemdescription:{label:\"Grammar problem description\",\ngroup:\"grayt_description\",order:1,state:CKEDITOR.TRISTATE_DISABLED,exec:function(a){}},grayt_ignore:{label:a.getLocal(\"btn_ignore\"),group:\"grayt_control\",order:2,exec:function(a){a.scayt.ignorePhrase()}},grayt_ignoreall:{label:a.getLocal(\"btn_ignoreAll\"),group:\"grayt_control\",order:3,exec:function(a){a.scayt.ignoreAllPhrases()}}}}},buildSuggestionMenuItems:function(a,f,b){var c={},d={},l=b?\"word\":\"phrase\",k=b?\"startGrammarCheck\":\"startSpellCheck\",g=a.scayt;if(0<f.length&&\"no_any_suggestions\"!==f[0])if(b)for(b=\n0;b<f.length;b++){var h=\"scayt_suggest_\"+CKEDITOR.plugins.scayt.suggestions[b].replace(\" \",\"_\");a.addCommand(h,this.createCommand(CKEDITOR.plugins.scayt.suggestions[b],l,k));b<a.config.scayt_maxSuggestions?(a.addMenuItem(h,{label:f[b],command:h,group:\"scayt_suggest\",order:b+1}),c[h]=CKEDITOR.TRISTATE_OFF):(a.addMenuItem(h,{label:f[b],command:h,group:\"scayt_moresuggest\",order:b+1}),d[h]=CKEDITOR.TRISTATE_OFF,\"on\"===a.config.scayt_moreSuggestions&&(a.addMenuItem(\"scayt_moresuggest\",{label:g.getLocal(\"btn_moreSuggestions\"),\ngroup:\"scayt_moresuggest\",order:10,getItems:function(){return d}}),c.scayt_moresuggest=CKEDITOR.TRISTATE_OFF))}else for(b=0;b<f.length;b++)h=\"grayt_suggest_\"+CKEDITOR.plugins.scayt.suggestions[b].replace(\" \",\"_\"),a.addCommand(h,this.createCommand(CKEDITOR.plugins.scayt.suggestions[b],l,k)),a.addMenuItem(h,{label:f[b],command:h,group:\"grayt_suggest\",order:b+1}),c[h]=CKEDITOR.TRISTATE_OFF;else c.no_scayt_suggest=CKEDITOR.TRISTATE_DISABLED,a.addCommand(\"no_scayt_suggest\",{exec:function(){}}),a.addMenuItem(\"no_scayt_suggest\",\n{label:g.getLocal(\"btn_noSuggestions\")||\"no_scayt_suggest\",command:\"no_scayt_suggest\",group:\"scayt_suggest\",order:0});return c},menuGenerator:function(a,f){var b=a.scayt,c=this.scaytMenuDefinition(a),d={},l=a.config.scayt_contextCommands.split(\"|\"),k=f.getAttribute(b.getLangAttribute())||b.getLang(),g,h,m,e;h=b.isScaytNode(f);m=b.isGraytNode(f);h?(c=c.scayt,g=f.getAttribute(b.getScaytNodeAttributeName()),b.fire(\"getSuggestionsList\",{lang:k,word:g}),d=this.buildSuggestionMenuItems(a,CKEDITOR.plugins.scayt.suggestions,\nh)):m&&(c=c.grayt,d=f.getAttribute(b.getGraytNodeAttributeName()),b.getGraytNodeRuleAttributeName?(g=f.getAttribute(b.getGraytNodeRuleAttributeName()),b.getProblemDescriptionText(d,g,k)):b.getProblemDescriptionText(d,k),e=b.getProblemDescriptionText(d,g,k),c.grayt_problemdescription&&e&&(e=e.replace(/([.!?])\\s/g,\"$1\\x3cbr\\x3e\"),c.grayt_problemdescription.label=e),b.fire(\"getGrammarSuggestionsList\",{lang:k,phrase:d,rule:g}),d=this.buildSuggestionMenuItems(a,CKEDITOR.plugins.scayt.suggestions,h));if(h&&\n\"off\"==a.config.scayt_contextCommands)return d;for(var n in c)h&&-1==CKEDITOR.tools.indexOf(l,n.replace(\"scayt_\",\"\"))&&\"all\"!=a.config.scayt_contextCommands||m&&\"grayt_problemdescription\"!==n&&-1==CKEDITOR.tools.indexOf(l,n.replace(\"grayt_\",\"\"))&&\"all\"!=a.config.scayt_contextCommands||(d[n]=\"undefined\"!=typeof c[n].state?c[n].state:CKEDITOR.TRISTATE_OFF,\"function\"!==typeof c[n].verification||c[n].verification(a)||delete d[n],a.addCommand(n,{exec:c[n].exec}),a.addMenuItem(n,{label:a.lang.scayt[c[n].label]||\nc[n].label,command:n,group:c[n].group,order:c[n].order}));return d},createCommand:function(a,f,b){return{exec:function(c){c=c.scayt;var d={};d[f]=a;c.replaceSelectionNode(d);\"startGrammarCheck\"===b&&c.removeMarkupInSelectionNode({grammarOnly:!0});c.fire(b)}}}}),CKEDITOR.plugins.scayt={charsToObserve:[{charName:\"cke-fillingChar\",charCode:function(){var a=CKEDITOR.version.match(/^\\d(\\.\\d*)*/),a=a&&a[0],f;if(a){f=\"4.5.7\";var b,a=a.replace(/\\./g,\"\");f=f.replace(/\\./g,\"\");b=a.length-f.length;b=0<=b?b:\n0;f=parseInt(a)>=parseInt(f)*Math.pow(10,b)}return f?Array(7).join(String.fromCharCode(8203)):String.fromCharCode(8203)}()}],state:{scayt:{},grayt:{}},warningCounter:0,suggestions:[],options:{disablingCommandExec:{source:!0,newpage:!0,templates:!0},data_attribute_name:\"data-scayt-word\",misspelled_word_class:\"scayt-misspell-word\",problem_grammar_data_attribute:\"data-grayt-phrase\",problem_grammar_class:\"gramm-problem\"},backCompatibilityMap:{scayt_service_protocol:\"scayt_serviceProtocol\",scayt_service_host:\"scayt_serviceHost\",\nscayt_service_port:\"scayt_servicePort\",scayt_service_path:\"scayt_servicePath\",scayt_customerid:\"scayt_customerId\"},openDialog:function(a,f){var b=f.scayt;b.isAllModulesReady&&!1===b.isAllModulesReady()||(f.lockSelection(),f.openDialog(a))},alarmCompatibilityMessage:function(){5>this.warningCounter&&(console.warn(\"You are using the latest version of SCAYT plugin for CKEditor with the old application version. In order to have access to the newest features, it is recommended to upgrade the application version to latest one as well. Contact us for more details at support@webspellchecker.net.\"),\nthis.warningCounter+=1)},isNewUdSupported:function(a){return a.getUserDictionary?!0:!1},reloadMarkup:function(a){var f;a&&(f=a.getScaytLangList(),a.reloadMarkup?a.reloadMarkup():(this.alarmCompatibilityMessage(),f&&f.ltr&&f.rtl&&a.fire(\"startSpellCheck, startGrammarCheck\")))},replaceOldOptionsNames:function(a){for(var f in a)f in this.backCompatibilityMap&&(a[this.backCompatibilityMap[f]]=a[f],delete a[f])},createScayt:function(a){var f=this,b=CKEDITOR.plugins.scayt;this.loadScaytLibrary(a,function(a){function d(a){return new SCAYT.CKSCAYT(a,\nfunction(){},function(){})}var l;a.window&&(l=\"BODY\"==a.editable().$.nodeName?a.window.getFrame():a.editable());if(l){l={lang:a.config.scayt_sLang,container:l.$,customDictionary:a.config.scayt_customDictionaryIds,userDictionaryName:a.config.scayt_userDictionaryName,localization:a.langCode,customer_id:a.config.scayt_customerId,customPunctuation:a.config.scayt_customPunctuation,debug:a.config.scayt_debug,data_attribute_name:f.options.data_attribute_name,misspelled_word_class:f.options.misspelled_word_class,\nproblem_grammar_data_attribute:f.options.problem_grammar_data_attribute,problem_grammar_class:f.options.problem_grammar_class,\"options-to-restore\":a.config.scayt_disableOptionsStorage,focused:a.editable().hasFocus,ignoreElementsRegex:a.config.scayt_elementsToIgnore,ignoreGraytElementsRegex:a.config.grayt_elementsToIgnore,minWordLength:a.config.scayt_minWordLength,multiLanguageMode:a.config.scayt_multiLanguageMode,multiLanguageStyles:a.config.scayt_multiLanguageStyles,graytAutoStartup:a.config.grayt_autoStartup,\ndisableCache:a.config.scayt_disableCache,cacheSize:a.config.scayt_cacheSize,charsToObserve:b.charsToObserve};a.config.scayt_serviceProtocol&&(l.service_protocol=a.config.scayt_serviceProtocol);a.config.scayt_serviceHost&&(l.service_host=a.config.scayt_serviceHost);a.config.scayt_servicePort&&(l.service_port=a.config.scayt_servicePort);a.config.scayt_servicePath&&(l.service_path=a.config.scayt_servicePath);\"boolean\"===typeof a.config.scayt_ignoreAllCapsWords&&(l[\"ignore-all-caps-words\"]=a.config.scayt_ignoreAllCapsWords);\n\"boolean\"===typeof a.config.scayt_ignoreDomainNames&&(l[\"ignore-domain-names\"]=a.config.scayt_ignoreDomainNames);\"boolean\"===typeof a.config.scayt_ignoreWordsWithMixedCases&&(l[\"ignore-words-with-mixed-cases\"]=a.config.scayt_ignoreWordsWithMixedCases);\"boolean\"===typeof a.config.scayt_ignoreWordsWithNumbers&&(l[\"ignore-words-with-numbers\"]=a.config.scayt_ignoreWordsWithNumbers);var k;try{k=d(l)}catch(g){f.alarmCompatibilityMessage(),delete l.charsToObserve,k=d(l)}k.subscribe(\"suggestionListSend\",\nfunction(a){for(var b={},c=[],d=0;d<a.suggestionList.length;d++)b[\"word_\"+a.suggestionList[d]]||(b[\"word_\"+a.suggestionList[d]]=a.suggestionList[d],c.push(a.suggestionList[d]));CKEDITOR.plugins.scayt.suggestions=c});k.subscribe(\"selectionIsChanged\",function(b){a.getSelection().isLocked&&\"restoreSelection\"!==b.action&&a.lockSelection();\"restoreSelection\"===b.action&&a.selectionChange(!0)});k.subscribe(\"graytStateChanged\",function(d){b.state.grayt[a.name]=d.state});k.addMarkupHandler&&k.addMarkupHandler(function(b){var d=\na.editable(),e=d.getCustomData(b.charName);e&&(e.$=b.node,d.setCustomData(b.charName,e))});a.scayt=k;a.fire(\"scaytButtonState\",a.readOnly?CKEDITOR.TRISTATE_DISABLED:CKEDITOR.TRISTATE_ON)}else b.state.scayt[a.name]=!1})},destroy:function(a){a.scayt&&a.scayt.destroy();delete a.scayt;a.fire(\"scaytButtonState\",CKEDITOR.TRISTATE_OFF)},loadScaytLibrary:function(a,f){var b,c=function(){CKEDITOR.fireOnce(\"scaytReady\");a.scayt||\"function\"===typeof f&&f(a)};\"undefined\"===typeof window.SCAYT||\"function\"!==typeof window.SCAYT.CKSCAYT?\n(b=a.config.scayt_srcUrl,CKEDITOR.scriptLoader.load(b,function(a){a&&c()})):window.SCAYT&&\"function\"===typeof window.SCAYT.CKSCAYT&&c()}},CKEDITOR.on(\"dialogDefinition\",function(a){var f=a.data.name;a=a.data.definition.dialog;\"scaytDialog\"!==f&&\"checkspell\"!==f&&(a.on(\"show\",function(a){a=a.sender&&a.sender.getParentEditor();var c=CKEDITOR.plugins.scayt,d=a.scayt;d&&c.state.scayt[a.name]&&d.setMarkupPaused&&d.setMarkupPaused(!0)}),a.on(\"hide\",function(a){a=a.sender&&a.sender.getParentEditor();var c=\nCKEDITOR.plugins.scayt,d=a.scayt;d&&c.state.scayt[a.name]&&d.setMarkupPaused&&d.setMarkupPaused(!1)}));if(\"scaytDialog\"===f)a.on(\"cancel\",function(a){return!1},this,null,-1);if(\"checkspell\"===f)a.on(\"cancel\",function(a){a=a.sender&&a.sender.getParentEditor();var c=CKEDITOR.plugins.scayt,d=a.scayt;d&&c.state.scayt[a.name]&&d.setMarkupPaused&&d.setMarkupPaused(!1);a.unlockSelection()},this,null,-2);if(\"link\"===f)a.on(\"ok\",function(a){var c=a.sender&&a.sender.getParentEditor();c&&setTimeout(function(){c.fire(\"reloadMarkupScayt\",\n{removeOptions:{removeInside:!0,forceBookmark:!0},timeout:0})},0)});if(\"replace\"===f)a.on(\"hide\",function(a){a=a.sender&&a.sender.getParentEditor();var c=CKEDITOR.plugins.scayt,d=a.scayt;a&&setTimeout(function(){d&&(d.fire(\"removeMarkupInDocument\",{}),c.reloadMarkup(d))},0)})}),CKEDITOR.on(\"scaytReady\",function(){if(!0===CKEDITOR.config.scayt_handleCheckDirty){var a=CKEDITOR.editor.prototype;a.checkDirty=CKEDITOR.tools.override(a.checkDirty,function(a){return function(){var c=null,d=this.scayt;if(CKEDITOR.plugins.scayt&&\nCKEDITOR.plugins.scayt.state.scayt[this.name]&&this.scayt){if(c=\"ready\"==this.status)var f=d.removeMarkupFromString(this.getSnapshot()),d=d.removeMarkupFromString(this._.previousValue),c=c&&d!==f}else c=a.call(this);return c}});a.resetDirty=CKEDITOR.tools.override(a.resetDirty,function(a){return function(){var c=this.scayt;CKEDITOR.plugins.scayt&&CKEDITOR.plugins.scayt.state.scayt[this.name]&&this.scayt?this._.previousValue=c.removeMarkupFromString(this.getSnapshot()):a.call(this)}})}if(!0===CKEDITOR.config.scayt_handleUndoRedo){var a=\nCKEDITOR.plugins.undo.Image.prototype,f=\"function\"==typeof a.equalsContent?\"equalsContent\":\"equals\";a[f]=CKEDITOR.tools.override(a[f],function(a){return function(c){var d=c.editor.scayt,f=this.contents,k=c.contents,g=null;CKEDITOR.plugins.scayt&&CKEDITOR.plugins.scayt.state.scayt[c.editor.name]&&c.editor.scayt&&(this.contents=d.removeMarkupFromString(f)||\"\",c.contents=d.removeMarkupFromString(k)||\"\");g=a.apply(this,arguments);this.contents=f;c.contents=k;return g}})}}),function(){var a={preserveState:!0,\neditorFocus:!1,readOnly:1,exec:function(a){this.toggleState();this.refresh(a)},refresh:function(a){if(a.document){var b=this.state==CKEDITOR.TRISTATE_ON?\"attachClass\":\"removeClass\";a.editable()[b](\"cke_show_borders\")}}};CKEDITOR.plugins.add(\"showborders\",{modes:{wysiwyg:1},onLoad:function(){var a;a=(CKEDITOR.env.ie6Compat?[\".%1 table.%2,\",\".%1 table.%2 td, .%1 table.%2 th\",\"{\",\"border : #d3d3d3 1px dotted\",\"}\"]:\".%1 table.%2,;.%1 table.%2 \\x3e tr \\x3e td, .%1 table.%2 \\x3e tr \\x3e th,;.%1 table.%2 \\x3e tbody \\x3e tr \\x3e td, .%1 table.%2 \\x3e tbody \\x3e tr \\x3e th,;.%1 table.%2 \\x3e thead \\x3e tr \\x3e td, .%1 table.%2 \\x3e thead \\x3e tr \\x3e th,;.%1 table.%2 \\x3e tfoot \\x3e tr \\x3e td, .%1 table.%2 \\x3e tfoot \\x3e tr \\x3e th;{;border : #d3d3d3 1px dotted;}\".split(\";\")).join(\"\").replace(/%2/g,\n\"cke_show_border\").replace(/%1/g,\"cke_show_borders \");CKEDITOR.addCss(a)},init:function(f){var b=f.addCommand(\"showborders\",a);b.canUndo=!1;!1!==f.config.startupShowBorders&&b.setState(CKEDITOR.TRISTATE_ON);f.on(\"mode\",function(){b.state!=CKEDITOR.TRISTATE_DISABLED&&b.refresh(f)},null,null,100);f.on(\"contentDom\",function(){b.state!=CKEDITOR.TRISTATE_DISABLED&&b.refresh(f)});f.on(\"removeFormatCleanup\",function(a){a=a.data;f.getCommand(\"showborders\").state==CKEDITOR.TRISTATE_ON&&a.is(\"table\")&&(!a.hasAttribute(\"border\")||\n0>=parseInt(a.getAttribute(\"border\"),10))&&a.addClass(\"cke_show_border\")})},afterInit:function(a){var b=a.dataProcessor;a=b&&b.dataFilter;b=b&&b.htmlFilter;a&&a.addRules({elements:{table:function(a){a=a.attributes;var b=a[\"class\"],f=parseInt(a.border,10);f&&!(0>=f)||b&&-1!=b.indexOf(\"cke_show_border\")||(a[\"class\"]=(b||\"\")+\" cke_show_border\")}}});b&&b.addRules({elements:{table:function(a){a=a.attributes;var b=a[\"class\"];b&&(a[\"class\"]=b.replace(\"cke_show_border\",\"\").replace(/\\s{2}/,\" \").replace(/^\\s+|\\s+$/,\n\"\"))}}})}});CKEDITOR.on(\"dialogDefinition\",function(a){var b=a.data.name;if(\"table\"==b||\"tableProperties\"==b)if(a=a.data.definition,b=a.getContents(\"info\").get(\"txtBorder\"),b.commit=CKEDITOR.tools.override(b.commit,function(a){return function(b,f){a.apply(this,arguments);var k=parseInt(this.getValue(),10);f[!k||0>=k?\"addClass\":\"removeClass\"](\"cke_show_border\")}}),a=(a=a.getContents(\"advanced\"))&&a.get(\"advCSSClasses\"))a.setup=CKEDITOR.tools.override(a.setup,function(a){return function(){a.apply(this,\narguments);this.setValue(this.getValue().replace(/cke_show_border/,\"\"))}}),a.commit=CKEDITOR.tools.override(a.commit,function(a){return function(b,f){a.apply(this,arguments);parseInt(f.getAttribute(\"border\"),10)||f.addClass(\"cke_show_border\")}})})}(),function(){CKEDITOR.plugins.add(\"sourcearea\",{init:function(f){function b(){var a=d&&this.equals(CKEDITOR.document.getActive());this.hide();this.setStyle(\"height\",this.getParent().$.clientHeight+\"px\");this.setStyle(\"width\",this.getParent().$.clientWidth+\n\"px\");this.show();a&&this.focus()}if(f.elementMode!=CKEDITOR.ELEMENT_MODE_INLINE){var c=CKEDITOR.plugins.sourcearea;f.addMode(\"source\",function(c){var d=f.ui.space(\"contents\").getDocument().createElement(\"textarea\");d.setStyles(CKEDITOR.tools.extend({width:CKEDITOR.env.ie7Compat?\"99%\":\"100%\",height:\"100%\",resize:\"none\",outline:\"none\",\"text-align\":\"left\"},CKEDITOR.tools.cssVendorPrefix(\"tab-size\",f.config.sourceAreaTabSize||4)));d.setAttribute(\"dir\",\"ltr\");d.addClass(\"cke_source\").addClass(\"cke_reset\").addClass(\"cke_enable_context_menu\");\nf.ui.space(\"contents\").append(d);d=f.editable(new a(f,d));d.setData(f.getData(1));CKEDITOR.env.ie&&(d.attachListener(f,\"resize\",b,d),d.attachListener(CKEDITOR.document.getWindow(),\"resize\",b,d),CKEDITOR.tools.setTimeout(b,0,d));f.fire(\"ariaWidget\",this);c()});f.addCommand(\"source\",c.commands.source);f.ui.addButton&&f.ui.addButton(\"Source\",{label:f.lang.sourcearea.toolbar,command:\"source\",toolbar:\"mode,10\"});f.on(\"mode\",function(){f.getCommand(\"source\").setState(\"source\"==f.mode?CKEDITOR.TRISTATE_ON:\nCKEDITOR.TRISTATE_OFF)});var d=CKEDITOR.env.ie&&9==CKEDITOR.env.version}}});var a=CKEDITOR.tools.createClass({base:CKEDITOR.editable,proto:{setData:function(a){this.setValue(a);this.status=\"ready\";this.editor.fire(\"dataReady\")},getData:function(){return this.getValue()},insertHtml:function(){},insertElement:function(){},insertText:function(){},setReadOnly:function(a){this[(a?\"set\":\"remove\")+\"Attribute\"](\"readOnly\",\"readonly\")},detach:function(){a.baseProto.detach.call(this);this.clearCustomData();\nthis.remove()}}})}(),CKEDITOR.plugins.sourcearea={commands:{source:{modes:{wysiwyg:1,source:1},editorFocus:!1,readOnly:1,exec:function(a){\"wysiwyg\"==a.mode&&a.fire(\"saveSnapshot\");a.getCommand(\"source\").setState(CKEDITOR.TRISTATE_DISABLED);a.setMode(\"source\"==a.mode?\"wysiwyg\":\"source\")},canUndo:!1}}},CKEDITOR.plugins.add(\"specialchar\",{availableLangs:{af:1,ar:1,az:1,bg:1,ca:1,cs:1,cy:1,da:1,de:1,\"de-ch\":1,el:1,en:1,\"en-au\":1,\"en-ca\":1,\"en-gb\":1,eo:1,es:1,\"es-mx\":1,et:1,eu:1,fa:1,fi:1,fr:1,\"fr-ca\":1,\ngl:1,he:1,hr:1,hu:1,id:1,it:1,ja:1,km:1,ko:1,ku:1,lt:1,lv:1,nb:1,nl:1,no:1,oc:1,pl:1,pt:1,\"pt-br\":1,ro:1,ru:1,si:1,sk:1,sl:1,sq:1,sr:1,\"sr-latn\":1,sv:1,th:1,tr:1,tt:1,ug:1,uk:1,vi:1,zh:1,\"zh-cn\":1},requires:\"dialog\",init:function(a){var f=this;CKEDITOR.dialog.add(\"specialchar\",this.path+\"dialogs/specialchar.js\");a.addCommand(\"specialchar\",{exec:function(){var b=a.langCode,b=f.availableLangs[b]?b:f.availableLangs[b.replace(/-.*/,\"\")]?b.replace(/-.*/,\"\"):\"en\";CKEDITOR.scriptLoader.load(CKEDITOR.getUrl(f.path+\n\"dialogs/lang/\"+b+\".js\"),function(){CKEDITOR.tools.extend(a.lang.specialchar,f.langEntries[b]);a.openDialog(\"specialchar\")})},modes:{wysiwyg:1},canUndo:!1});a.ui.addButton&&a.ui.addButton(\"SpecialChar\",{label:a.lang.specialchar.toolbar,command:\"specialchar\",toolbar:\"insert,50\"})}}),CKEDITOR.config.specialChars=\"! \\x26quot; # $ % \\x26amp; ' ( ) * + - . / 0 1 2 3 4 5 6 7 8 9 : ; \\x26lt; \\x3d \\x26gt; ? @ 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 [ ] ^ _ ` 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 { | } ~ \\x26euro; \\x26lsquo; \\x26rsquo; \\x26ldquo; \\x26rdquo; \\x26ndash; \\x26mdash; \\x26iexcl; \\x26cent; \\x26pound; \\x26curren; \\x26yen; \\x26brvbar; \\x26sect; \\x26uml; \\x26copy; \\x26ordf; \\x26laquo; \\x26not; \\x26reg; \\x26macr; \\x26deg; \\x26sup2; \\x26sup3; \\x26acute; \\x26micro; \\x26para; \\x26middot; \\x26cedil; \\x26sup1; \\x26ordm; \\x26raquo; \\x26frac14; \\x26frac12; \\x26frac34; \\x26iquest; \\x26Agrave; \\x26Aacute; \\x26Acirc; \\x26Atilde; \\x26Auml; \\x26Aring; \\x26AElig; \\x26Ccedil; \\x26Egrave; \\x26Eacute; \\x26Ecirc; \\x26Euml; \\x26Igrave; \\x26Iacute; \\x26Icirc; \\x26Iuml; \\x26ETH; \\x26Ntilde; \\x26Ograve; \\x26Oacute; \\x26Ocirc; \\x26Otilde; \\x26Ouml; \\x26times; \\x26Oslash; \\x26Ugrave; \\x26Uacute; \\x26Ucirc; \\x26Uuml; \\x26Yacute; \\x26THORN; \\x26szlig; \\x26agrave; \\x26aacute; \\x26acirc; \\x26atilde; \\x26auml; \\x26aring; \\x26aelig; \\x26ccedil; \\x26egrave; \\x26eacute; \\x26ecirc; \\x26euml; \\x26igrave; \\x26iacute; \\x26icirc; \\x26iuml; \\x26eth; \\x26ntilde; \\x26ograve; \\x26oacute; \\x26ocirc; \\x26otilde; \\x26ouml; \\x26divide; \\x26oslash; \\x26ugrave; \\x26uacute; \\x26ucirc; \\x26uuml; \\x26yacute; \\x26thorn; \\x26yuml; \\x26OElig; \\x26oelig; \\x26#372; \\x26#374 \\x26#373 \\x26#375; \\x26sbquo; \\x26#8219; \\x26bdquo; \\x26hellip; \\x26trade; \\x26#9658; \\x26bull; \\x26rarr; \\x26rArr; \\x26hArr; \\x26diams; \\x26asymp;\".split(\" \"),\nfunction(){CKEDITOR.plugins.add(\"stylescombo\",{requires:\"richcombo\",init:function(a){var f=a.config,b=a.lang.stylescombo,c={},d=[],l=[];a.on(\"stylesSet\",function(b){if(b=b.data.styles){for(var g,h,m,e=0,n=b.length;e<n;e++)(g=b[e],a.blockless&&g.element in CKEDITOR.dtd.$block||\"string\"==typeof g.type&&!CKEDITOR.style.customHandlers[g.type]||(h=g.name,g=new CKEDITOR.style(g),a.filter.customConfig&&!a.filter.check(g)))||(g._name=h,g._.enterMode=f.enterMode,g._.type=m=g.assignedTo||g.type,g._.weight=\ne+1E3*(m==CKEDITOR.STYLE_OBJECT?1:m==CKEDITOR.STYLE_BLOCK?2:3),c[h]=g,d.push(g),l.push(g));d.sort(function(a,b){return a._.weight-b._.weight})}});a.ui.addRichCombo(\"Styles\",{label:b.label,title:b.panelTitle,toolbar:\"styles,10\",allowedContent:l,panel:{css:[CKEDITOR.skin.getPath(\"editor\")].concat(f.contentsCss),multiSelect:!0,attributes:{\"aria-label\":b.panelTitle}},init:function(){var a,c,f,l,e,n;e=0;for(n=d.length;e<n;e++)a=d[e],c=a._name,l=a._.type,l!=f&&(this.startGroup(b[\"panelTitle\"+String(l)]),\nf=l),this.add(c,a.type==CKEDITOR.STYLE_OBJECT?c:a.buildPreview(),c);this.commit()},onClick:function(b){a.focus();a.fire(\"saveSnapshot\");b=c[b];var d=a.elementPath();if(b.group&&b.removeStylesFromSameGroup(a))a.applyStyle(b);else a[b.checkActive(d,a)?\"removeStyle\":\"applyStyle\"](b);a.fire(\"saveSnapshot\")},onRender:function(){a.on(\"selectionChange\",function(b){var d=this.getValue();b=b.data.path.elements;for(var f=0,l=b.length,e;f<l;f++){e=b[f];for(var n in c)if(c[n].checkElementRemovable(e,!0,a)){n!=\nd&&this.setValue(n);return}}this.setValue(\"\")},this)},onOpen:function(){var d=a.getSelection(),d=d.getSelectedElement()||d.getStartElement()||a.editable(),d=a.elementPath(d),g=[0,0,0,0];this.showAll();this.unmarkAll();for(var f in c){var l=c[f],e=l._.type;l.checkApplicable(d,a,a.activeFilter)?g[e]++:this.hideItem(f);l.checkActive(d,a)&&this.mark(f)}g[CKEDITOR.STYLE_BLOCK]||this.hideGroup(b[\"panelTitle\"+String(CKEDITOR.STYLE_BLOCK)]);g[CKEDITOR.STYLE_INLINE]||this.hideGroup(b[\"panelTitle\"+String(CKEDITOR.STYLE_INLINE)]);\ng[CKEDITOR.STYLE_OBJECT]||this.hideGroup(b[\"panelTitle\"+String(CKEDITOR.STYLE_OBJECT)])},refresh:function(){var b=a.elementPath();if(b){for(var d in c)if(c[d].checkApplicable(b,a,a.activeFilter))return;this.setState(CKEDITOR.TRISTATE_DISABLED)}},reset:function(){c={};d=[]}})}})}(),function(){function a(a){return{editorFocus:!1,canUndo:!1,modes:{wysiwyg:1},exec:function(b){if(b.editable().hasFocus){var c=b.getSelection(),g;if(g=(new CKEDITOR.dom.elementPath(c.getCommonAncestor(),c.root)).contains({td:1,\nth:1},1)){var c=b.createRange(),f=CKEDITOR.tools.tryThese(function(){var b=g.getParent().$.cells[g.$.cellIndex+(a?-1:1)];b.parentNode.parentNode;return b},function(){var b=g.getParent(),b=b.getAscendant(\"table\").$.rows[b.$.rowIndex+(a?-1:1)];return b.cells[a?b.cells.length-1:0]});if(f||a)if(f)f=new CKEDITOR.dom.element(f),c.moveToElementEditStart(f),c.checkStartOfBlock()&&c.checkEndOfBlock()||c.selectNodeContents(f);else return!0;else{for(var m=g.getAscendant(\"table\").$,f=g.getParent().$.cells,m=\nnew CKEDITOR.dom.element(m.insertRow(-1),b.document),e=0,n=f.length;e<n;e++)m.append((new CKEDITOR.dom.element(f[e],b.document)).clone(!1,!1)).appendBogus();c.moveToElementEditStart(m)}c.select(!0);return!0}}return!1}}}var f={editorFocus:!1,modes:{wysiwyg:1,source:1}},b={exec:function(a){a.container.focusNext(!0,a.tabIndex)}},c={exec:function(a){a.container.focusPrevious(!0,a.tabIndex)}};CKEDITOR.plugins.add(\"tab\",{init:function(d){for(var l=!1!==d.config.enableTabKeyTools,k=d.config.tabSpaces||0,\ng=\"\";k--;)g+=\" \";if(g)d.on(\"key\",function(a){9==a.data.keyCode&&(d.insertText(g),a.cancel())});if(l)d.on(\"key\",function(a){(9==a.data.keyCode&&d.execCommand(\"selectNextCell\")||a.data.keyCode==CKEDITOR.SHIFT+9&&d.execCommand(\"selectPreviousCell\"))&&a.cancel()});d.addCommand(\"blur\",CKEDITOR.tools.extend(b,f));d.addCommand(\"blurBack\",CKEDITOR.tools.extend(c,f));d.addCommand(\"selectNextCell\",a());d.addCommand(\"selectPreviousCell\",a(!0))}})}(),CKEDITOR.dom.element.prototype.focusNext=function(a,f){var b=\nvoid 0===f?this.getTabIndex():f,c,d,l,k,g,h;if(0>=b)for(g=this.getNextSourceNode(a,CKEDITOR.NODE_ELEMENT);g;){if(g.isVisible()&&0===g.getTabIndex()){l=g;break}g=g.getNextSourceNode(!1,CKEDITOR.NODE_ELEMENT)}else for(g=this.getDocument().getBody().getFirst();g=g.getNextSourceNode(!1,CKEDITOR.NODE_ELEMENT);){if(!c)if(!d&&g.equals(this)){if(d=!0,a){if(!(g=g.getNextSourceNode(!0,CKEDITOR.NODE_ELEMENT)))break;c=1}}else d&&!this.contains(g)&&(c=1);if(g.isVisible()&&!(0>(h=g.getTabIndex()))){if(c&&h==b){l=\ng;break}h>b&&(!l||!k||h<k)?(l=g,k=h):l||0!==h||(l=g,k=h)}}l&&l.focus()},CKEDITOR.dom.element.prototype.focusPrevious=function(a,f){for(var b=void 0===f?this.getTabIndex():f,c,d,l,k=0,g,h=this.getDocument().getBody().getLast();h=h.getPreviousSourceNode(!1,CKEDITOR.NODE_ELEMENT);){if(!c)if(!d&&h.equals(this)){if(d=!0,a){if(!(h=h.getPreviousSourceNode(!0,CKEDITOR.NODE_ELEMENT)))break;c=1}}else d&&!this.contains(h)&&(c=1);if(h.isVisible()&&!(0>(g=h.getTabIndex())))if(0>=b){if(c&&0===g){l=h;break}g>k&&\n(l=h,k=g)}else{if(c&&g==b){l=h;break}g<b&&(!l||g>k)&&(l=h,k=g)}}l&&l.focus()},CKEDITOR.plugins.add(\"table\",{requires:\"dialog\",init:function(a){function f(a){return CKEDITOR.tools.extend(a||{},{contextSensitive:1,refresh:function(a,b){this.setState(b.contains(\"table\",1)?CKEDITOR.TRISTATE_OFF:CKEDITOR.TRISTATE_DISABLED)}})}if(!a.blockless){var b=a.lang.table;a.addCommand(\"table\",new CKEDITOR.dialogCommand(\"table\",{context:\"table\",allowedContent:\"table{width,height,border-collapse}[align,border,cellpadding,cellspacing,summary];caption tbody thead tfoot;th td tr[scope];td{border*,background-color,vertical-align,width,height}[colspan,rowspan];\"+\n(a.plugins.dialogadvtab?\"table\"+a.plugins.dialogadvtab.allowedContent():\"\"),requiredContent:\"table\",contentTransformations:[[\"table{width}: sizeToStyle\",\"table[width]: sizeToAttribute\"],[\"td: splitBorderShorthand\"],[{element:\"table\",right:function(a){if(a.styles){var b;if(a.styles.border)b=CKEDITOR.tools.style.parse.border(a.styles.border);else if(CKEDITOR.env.ie&&8===CKEDITOR.env.version){var f=a.styles;f[\"border-left\"]&&f[\"border-left\"]===f[\"border-right\"]&&f[\"border-right\"]===f[\"border-top\"]&&\nf[\"border-top\"]===f[\"border-bottom\"]&&(b=CKEDITOR.tools.style.parse.border(f[\"border-top\"]))}b&&b.style&&\"solid\"===b.style&&b.width&&0!==parseFloat(b.width)&&(a.attributes.border=1);\"collapse\"==a.styles[\"border-collapse\"]&&(a.attributes.cellspacing=0)}}}]]}));a.addCommand(\"tableProperties\",new CKEDITOR.dialogCommand(\"tableProperties\",f()));a.addCommand(\"tableDelete\",f({exec:function(a){var b=a.elementPath().contains(\"table\",1);if(b){var f=b.getParent(),k=a.editable();1!=f.getChildCount()||f.is(\"td\",\n\"th\")||f.equals(k)||(b=f);a=a.createRange();a.moveToPosition(b,CKEDITOR.POSITION_BEFORE_START);b.remove();a.select()}}}));a.ui.addButton&&a.ui.addButton(\"Table\",{label:b.toolbar,command:\"table\",toolbar:\"insert,30\"});CKEDITOR.dialog.add(\"table\",this.path+\"dialogs/table.js\");CKEDITOR.dialog.add(\"tableProperties\",this.path+\"dialogs/table.js\");a.addMenuItems&&a.addMenuItems({table:{label:b.menu,command:\"tableProperties\",group:\"table\",order:5},tabledelete:{label:b.deleteTable,command:\"tableDelete\",group:\"table\",\norder:1}});a.on(\"doubleclick\",function(a){a.data.element.is(\"table\")&&(a.data.dialog=\"tableProperties\")});a.contextMenu&&a.contextMenu.addListener(function(){return{tabledelete:CKEDITOR.TRISTATE_OFF,table:CKEDITOR.TRISTATE_OFF}})}}}),function(){function a(a,b){function c(a){return b?b.contains(a)&&a.getAscendant(\"table\",!0).equals(b):!0}function d(a){0<e.length||a.type!=CKEDITOR.NODE_ELEMENT||!u.test(a.getName())||a.getCustomData(\"selected_cell\")||(CKEDITOR.dom.element.setMarker(g,a,\"selected_cell\",\n!0),e.push(a))}var e=[],g={};if(!a)return e;for(var f=a.getRanges(),h=0;h<f.length;h++){var k=f[h];if(k.collapsed)(k=k.getCommonAncestor().getAscendant({td:1,th:1},!0))&&c(k)&&e.push(k);else{var k=new CKEDITOR.dom.walker(k),l;for(k.guard=d;l=k.next();)l.type==CKEDITOR.NODE_ELEMENT&&l.is(CKEDITOR.dtd.table)||(l=l.getAscendant({td:1,th:1},!0))&&!l.getCustomData(\"selected_cell\")&&c(l)&&(CKEDITOR.dom.element.setMarker(g,l,\"selected_cell\",!0),e.push(l))}}CKEDITOR.dom.element.clearAllMarkers(g);return e}\nfunction f(b,c){for(var d=p(b)?b:a(b),e=d[0],g=e.getAscendant(\"table\"),e=e.getDocument(),f=d[0].getParent(),h=f.$.rowIndex,d=d[d.length-1],k=d.getParent().$.rowIndex+d.$.rowSpan-1,d=new CKEDITOR.dom.element(g.$.rows[k]),h=c?h:k,f=c?f:d,d=CKEDITOR.tools.buildTableMap(g),g=d[h],h=c?d[h-1]:d[h+1],d=d[0].length,e=e.createElement(\"tr\"),k=0;g[k]&&k<d;k++){var l;1<g[k].rowSpan&&h&&g[k]==h[k]?(l=g[k],l.rowSpan+=1):(l=(new CKEDITOR.dom.element(g[k])).clone(),l.removeAttribute(\"rowSpan\"),l.appendBogus(),e.append(l),\nl=l.$);k+=l.colSpan-1}c?e.insertBefore(f):e.insertAfter(f);return e}function b(c){if(c instanceof CKEDITOR.dom.selection){var d=c.getRanges(),e=a(c),g=e[0].getAscendant(\"table\"),f=CKEDITOR.tools.buildTableMap(g),h=e[0].getParent().$.rowIndex,e=e[e.length-1],k=e.getParent().$.rowIndex+e.$.rowSpan-1,e=[];c.reset();for(c=h;c<=k;c++){for(var l=f[c],m=new CKEDITOR.dom.element(g.$.rows[c]),n=0;n<l.length;n++){var q=new CKEDITOR.dom.element(l[n]),p=q.getParent().$.rowIndex;1==q.$.rowSpan?q.remove():(--q.$.rowSpan,\np==c&&(p=f[c+1],p[n-1]?q.insertAfter(new CKEDITOR.dom.element(p[n-1])):(new CKEDITOR.dom.element(g.$.rows[c+1])).append(q,1)));n+=q.$.colSpan-1}e.push(m)}f=g.$.rows;d[0].moveToPosition(g,CKEDITOR.POSITION_BEFORE_START);h=new CKEDITOR.dom.element(f[k+1]||(0<h?f[h-1]:null)||g.$.parentNode);for(c=e.length;0<=c;c--)b(e[c]);return g.$.parentNode?h:(d[0].select(),null)}c instanceof CKEDITOR.dom.element&&(g=c.getAscendant(\"table\"),1==g.$.rows.length?g.remove():c.remove());return null}function c(a){for(var b=\na.getParent().$.cells,c=0,d=0;d<b.length;d++){var e=b[d],c=c+e.colSpan;if(e==a.$)break}return c-1}function d(a,b){for(var d=b?Infinity:0,e=0;e<a.length;e++){var g=c(a[e]);if(b?g<d:g>d)d=g}return d}function l(b,c){for(var e=p(b)?b:a(b),g=e[0].getAscendant(\"table\"),f=d(e,1),e=d(e),h=c?f:e,k=CKEDITOR.tools.buildTableMap(g),g=[],f=[],e=[],l=k.length,m=0;m<l;m++)g.push(k[m][h]),f.push(c?k[m][h-1]:k[m][h+1]);for(m=0;m<l;m++)g[m]&&(1<g[m].colSpan&&f[m]==g[m]?(k=g[m],k.colSpan+=1):(h=new CKEDITOR.dom.element(g[m]),\nk=h.clone(),k.removeAttribute(\"colSpan\"),k.appendBogus(),k[c?\"insertBefore\":\"insertAfter\"].call(k,h),e.push(k),k=k.$),m+=k.rowSpan-1);return e}function k(b){function c(a){var b,d,e;b=a.getRanges();if(1!==b.length)return a;b=b[0];if(b.collapsed||0!==b.endOffset)return a;d=b.endContainer;e=d.getName().toLowerCase();if(\"td\"!==e&&\"th\"!==e)return a;for((e=d.getPrevious())||(e=d.getParent().getPrevious().getLast());e.type!==CKEDITOR.NODE_TEXT&&\"br\"!==e.getName().toLowerCase();)if(e=e.getLast(),!e)return a;\nb.setEndAt(e,CKEDITOR.POSITION_BEFORE_END);return b.select()}CKEDITOR.env.webkit&&!b.isFake&&(b=c(b));var d=b.getRanges(),e=a(b),g=e[0],f=e[e.length-1],e=g.getAscendant(\"table\"),h=CKEDITOR.tools.buildTableMap(e),k,l,m=[];b.reset();var n=0;for(b=h.length;n<b;n++)for(var q=0,p=h[n].length;q<p;q++)void 0===k&&h[n][q]==g.$&&(k=q),h[n][q]==f.$&&(l=q);for(n=k;n<=l;n++)for(q=0;q<h.length;q++)f=h[q],g=new CKEDITOR.dom.element(e.$.rows[q]),f=new CKEDITOR.dom.element(f[n]),f.$&&(1==f.$.colSpan?f.remove():--f.$.colSpan,\nq+=f.$.rowSpan-1,g.$.cells.length||m.push(g));k=h[0].length-1>l?new CKEDITOR.dom.element(h[0][l+1]):k&&-1!==h[0][k-1].cellIndex?new CKEDITOR.dom.element(h[0][k-1]):new CKEDITOR.dom.element(e.$.parentNode);m.length==b&&(d[0].moveToPosition(e,CKEDITOR.POSITION_AFTER_END),d[0].select(),e.remove());return k}function g(a,b){var c=a.getStartElement().getAscendant({td:1,th:1},!0);if(c){var d=c.clone();d.appendBogus();b?d.insertBefore(c):d.insertAfter(c)}}function h(b){if(b instanceof CKEDITOR.dom.selection){var c=\nb.getRanges(),d=a(b),e=d[0]&&d[0].getAscendant(\"table\"),g;a:{var f=0;g=d.length-1;for(var k={},l,n;l=d[f++];)CKEDITOR.dom.element.setMarker(k,l,\"delete_cell\",!0);for(f=0;l=d[f++];)if((n=l.getPrevious())&&!n.getCustomData(\"delete_cell\")||(n=l.getNext())&&!n.getCustomData(\"delete_cell\")){CKEDITOR.dom.element.clearAllMarkers(k);g=n;break a}CKEDITOR.dom.element.clearAllMarkers(k);f=d[0].getParent();(f=f.getPrevious())?g=f.getLast():(f=d[g].getParent(),g=(f=f.getNext())?f.getChild(0):null)}b.reset();for(b=\nd.length-1;0<=b;b--)h(d[b]);g?m(g,!0):e&&(c[0].moveToPosition(e,CKEDITOR.POSITION_BEFORE_START),c[0].select(),e.remove())}else b instanceof CKEDITOR.dom.element&&(c=b.getParent(),1==c.getChildCount()?c.remove():b.remove())}function m(a,b){var c=a.getDocument(),d=CKEDITOR.document;CKEDITOR.env.ie&&10==CKEDITOR.env.version&&(d.focus(),c.focus());c=new CKEDITOR.dom.range(c);c[\"moveToElementEdit\"+(b?\"End\":\"Start\")](a)||(c.selectNodeContents(a),c.collapse(b?!1:!0));c.select(!0)}function e(a,b,c){a=a[b];\nif(\"undefined\"==typeof c)return a;for(b=0;a&&b<a.length;b++){if(c.is&&a[b]==c.$)return b;if(b==c)return new CKEDITOR.dom.element(a[b])}return c.is?-1:null}function n(b,c,d){var g=a(b),f;if((c?1!=g.length:2>g.length)||(f=b.getCommonAncestor())&&f.type==CKEDITOR.NODE_ELEMENT&&f.is(\"table\"))return!1;var h;b=g[0];f=b.getAscendant(\"table\");var k=CKEDITOR.tools.buildTableMap(f),l=k.length,m=k[0].length,n=b.getParent().$.rowIndex,q=e(k,n,b);if(c){var p;try{var u=parseInt(b.getAttribute(\"rowspan\"),10)||1;\nh=parseInt(b.getAttribute(\"colspan\"),10)||1;p=k[\"up\"==c?n-u:\"down\"==c?n+u:n][\"left\"==c?q-h:\"right\"==c?q+h:q]}catch(y){return!1}if(!p||b.$==p)return!1;g[\"up\"==c||\"left\"==c?\"unshift\":\"push\"](new CKEDITOR.dom.element(p))}c=b.getDocument();var L=n,u=p=0,G=!d&&new CKEDITOR.dom.documentFragment(c),D=0;for(c=0;c<g.length;c++){h=g[c];var N=h.getParent(),Q=h.getFirst(),O=h.$.colSpan,K=h.$.rowSpan,N=N.$.rowIndex,W=e(k,N,h),D=D+O*K,u=Math.max(u,W-q+O);p=Math.max(p,N-n+K);d||(O=h,(K=O.getBogus())&&K.remove(),\nO.trim(),h.getChildren().count()&&(N==L||!Q||Q.isBlockBoundary&&Q.isBlockBoundary({br:1})||(L=G.getLast(CKEDITOR.dom.walker.whitespaces(!0)),!L||L.is&&L.is(\"br\")||G.append(\"br\")),h.moveChildren(G)),c?h.remove():h.setHtml(\"\"));L=N}if(d)return p*u==D;G.moveChildren(b);b.appendBogus();u>=m?b.removeAttribute(\"rowSpan\"):b.$.rowSpan=p;p>=l?b.removeAttribute(\"colSpan\"):b.$.colSpan=u;d=new CKEDITOR.dom.nodeList(f.$.rows);g=d.count();for(c=g-1;0<=c;c--)f=d.getItem(c),f.$.cells.length||(f.remove(),g++);return b}\nfunction q(b,c){var d=a(b);if(1<d.length)return!1;if(c)return!0;var d=d[0],g=d.getParent(),f=g.getAscendant(\"table\"),h=CKEDITOR.tools.buildTableMap(f),k=g.$.rowIndex,l=e(h,k,d),m=d.$.rowSpan,n;if(1<m){n=Math.ceil(m/2);for(var m=Math.floor(m/2),g=k+n,f=new CKEDITOR.dom.element(f.$.rows[g]),h=e(h,g),q,g=d.clone(),k=0;k<h.length;k++)if(q=h[k],q.parentNode==f.$&&k>l){g.insertBefore(new CKEDITOR.dom.element(q));break}else q=null;q||f.append(g)}else for(m=n=1,f=g.clone(),f.insertAfter(g),f.append(g=d.clone()),\nq=e(h,k),l=0;l<q.length;l++)q[l].rowSpan++;g.appendBogus();d.$.rowSpan=n;g.$.rowSpan=m;1==n&&d.removeAttribute(\"rowSpan\");1==m&&g.removeAttribute(\"rowSpan\");return g}function y(b,c){var d=a(b);if(1<d.length)return!1;if(c)return!0;var d=d[0],g=d.getParent(),f=g.getAscendant(\"table\"),f=CKEDITOR.tools.buildTableMap(f),h=e(f,g.$.rowIndex,d),k=d.$.colSpan;if(1<k)g=Math.ceil(k/2),k=Math.floor(k/2);else{for(var k=g=1,l=[],m=0;m<f.length;m++){var n=f[m];l.push(n[h]);1<n[h].rowSpan&&(m+=n[h].rowSpan-1)}for(f=\n0;f<l.length;f++)l[f].colSpan++}f=d.clone();f.insertAfter(d);f.appendBogus();d.$.colSpan=g;f.$.colSpan=k;1==g&&d.removeAttribute(\"colSpan\");1==k&&f.removeAttribute(\"colSpan\");return f}var u=/^(?:td|th)$/,p=CKEDITOR.tools.isArray;CKEDITOR.plugins.tabletools={requires:\"table,dialog,contextmenu\",init:function(c){function d(a){return CKEDITOR.tools.extend(a||{},{contextSensitive:1,refresh:function(a,b){this.setState(b.contains({td:1,th:1},1)?CKEDITOR.TRISTATE_OFF:CKEDITOR.TRISTATE_DISABLED)}})}function e(a,\nb){var d=c.addCommand(a,b);c.addFeature(d)}var p=c.lang.table,u=CKEDITOR.tools.style.parse,x=\"td{width} td{height} td{border-color} td{background-color} td{white-space} td{vertical-align} td{text-align} td[colspan] td[rowspan] th\".split(\" \");e(\"cellProperties\",new CKEDITOR.dialogCommand(\"cellProperties\",d({allowedContent:\"td th{width,height,border-color,background-color,white-space,vertical-align,text-align}[colspan,rowspan]\",requiredContent:x,contentTransformations:[[{element:\"td\",left:function(a){return a.styles.background&&\nu.background(a.styles.background).color},right:function(a){a.styles[\"background-color\"]=u.background(a.styles.background).color}},{element:\"td\",check:\"td{vertical-align}\",left:function(a){return a.attributes&&a.attributes.valign},right:function(a){a.styles[\"vertical-align\"]=a.attributes.valign;delete a.attributes.valign}}],[{element:\"tr\",check:\"td{height}\",left:function(a){return a.styles&&a.styles.height},right:function(a){CKEDITOR.tools.array.forEach(a.children,function(b){b.name in{td:1,th:1}&&\n(b.attributes[\"cke-row-height\"]=a.styles.height)});delete a.styles.height}}],[{element:\"td\",check:\"td{height}\",left:function(a){return(a=a.attributes)&&a[\"cke-row-height\"]},right:function(a){a.styles.height=a.attributes[\"cke-row-height\"];delete a.attributes[\"cke-row-height\"]}}]]})));CKEDITOR.dialog.add(\"cellProperties\",this.path+\"dialogs/tableCell.js\");e(\"rowDelete\",d({requiredContent:\"table\",exec:function(a){a=a.getSelection();(a=b(a))&&m(a)}}));e(\"rowInsertBefore\",d({requiredContent:\"table\",exec:function(b){b=\nb.getSelection();b=a(b);f(b,!0)}}));e(\"rowInsertAfter\",d({requiredContent:\"table\",exec:function(b){b=b.getSelection();b=a(b);f(b)}}));e(\"columnDelete\",d({requiredContent:\"table\",exec:function(a){a=a.getSelection();(a=k(a))&&m(a,!0)}}));e(\"columnInsertBefore\",d({requiredContent:\"table\",exec:function(b){b=b.getSelection();b=a(b);l(b,!0)}}));e(\"columnInsertAfter\",d({requiredContent:\"table\",exec:function(b){b=b.getSelection();b=a(b);l(b)}}));e(\"cellDelete\",d({requiredContent:\"table\",exec:function(a){a=\na.getSelection();h(a)}}));e(\"cellMerge\",d({allowedContent:\"td[colspan,rowspan]\",requiredContent:\"td[colspan,rowspan]\",exec:function(a,b){b.cell=n(a.getSelection());m(b.cell,!0)}}));e(\"cellMergeRight\",d({allowedContent:\"td[colspan]\",requiredContent:\"td[colspan]\",exec:function(a,b){b.cell=n(a.getSelection(),\"right\");m(b.cell,!0)}}));e(\"cellMergeDown\",d({allowedContent:\"td[rowspan]\",requiredContent:\"td[rowspan]\",exec:function(a,b){b.cell=n(a.getSelection(),\"down\");m(b.cell,!0)}}));e(\"cellVerticalSplit\",\nd({allowedContent:\"td[rowspan]\",requiredContent:\"td[rowspan]\",exec:function(a){m(y(a.getSelection()))}}));e(\"cellHorizontalSplit\",d({allowedContent:\"td[colspan]\",requiredContent:\"td[colspan]\",exec:function(a){m(q(a.getSelection()))}}));e(\"cellInsertBefore\",d({requiredContent:\"table\",exec:function(a){a=a.getSelection();g(a,!0)}}));e(\"cellInsertAfter\",d({requiredContent:\"table\",exec:function(a){a=a.getSelection();g(a)}}));c.addMenuItems&&c.addMenuItems({tablecell:{label:p.cell.menu,group:\"tablecell\",\norder:1,getItems:function(){var b=c.getSelection(),d=a(b),b={tablecell_insertBefore:CKEDITOR.TRISTATE_OFF,tablecell_insertAfter:CKEDITOR.TRISTATE_OFF,tablecell_delete:CKEDITOR.TRISTATE_OFF,tablecell_merge:n(b,null,!0)?CKEDITOR.TRISTATE_OFF:CKEDITOR.TRISTATE_DISABLED,tablecell_merge_right:n(b,\"right\",!0)?CKEDITOR.TRISTATE_OFF:CKEDITOR.TRISTATE_DISABLED,tablecell_merge_down:n(b,\"down\",!0)?CKEDITOR.TRISTATE_OFF:CKEDITOR.TRISTATE_DISABLED,tablecell_split_vertical:y(b,!0)?CKEDITOR.TRISTATE_OFF:CKEDITOR.TRISTATE_DISABLED,\ntablecell_split_horizontal:q(b,!0)?CKEDITOR.TRISTATE_OFF:CKEDITOR.TRISTATE_DISABLED};c.filter.check(x)&&(b.tablecell_properties=0<d.length?CKEDITOR.TRISTATE_OFF:CKEDITOR.TRISTATE_DISABLED);return b}},tablecell_insertBefore:{label:p.cell.insertBefore,group:\"tablecell\",command:\"cellInsertBefore\",order:5},tablecell_insertAfter:{label:p.cell.insertAfter,group:\"tablecell\",command:\"cellInsertAfter\",order:10},tablecell_delete:{label:p.cell.deleteCell,group:\"tablecell\",command:\"cellDelete\",order:15},tablecell_merge:{label:p.cell.merge,\ngroup:\"tablecell\",command:\"cellMerge\",order:16},tablecell_merge_right:{label:p.cell.mergeRight,group:\"tablecell\",command:\"cellMergeRight\",order:17},tablecell_merge_down:{label:p.cell.mergeDown,group:\"tablecell\",command:\"cellMergeDown\",order:18},tablecell_split_horizontal:{label:p.cell.splitHorizontal,group:\"tablecell\",command:\"cellHorizontalSplit\",order:19},tablecell_split_vertical:{label:p.cell.splitVertical,group:\"tablecell\",command:\"cellVerticalSplit\",order:20},tablecell_properties:{label:p.cell.title,\ngroup:\"tablecellproperties\",command:\"cellProperties\",order:21},tablerow:{label:p.row.menu,group:\"tablerow\",order:1,getItems:function(){return{tablerow_insertBefore:CKEDITOR.TRISTATE_OFF,tablerow_insertAfter:CKEDITOR.TRISTATE_OFF,tablerow_delete:CKEDITOR.TRISTATE_OFF}}},tablerow_insertBefore:{label:p.row.insertBefore,group:\"tablerow\",command:\"rowInsertBefore\",order:5},tablerow_insertAfter:{label:p.row.insertAfter,group:\"tablerow\",command:\"rowInsertAfter\",order:10},tablerow_delete:{label:p.row.deleteRow,\ngroup:\"tablerow\",command:\"rowDelete\",order:15},tablecolumn:{label:p.column.menu,group:\"tablecolumn\",order:1,getItems:function(){return{tablecolumn_insertBefore:CKEDITOR.TRISTATE_OFF,tablecolumn_insertAfter:CKEDITOR.TRISTATE_OFF,tablecolumn_delete:CKEDITOR.TRISTATE_OFF}}},tablecolumn_insertBefore:{label:p.column.insertBefore,group:\"tablecolumn\",command:\"columnInsertBefore\",order:5},tablecolumn_insertAfter:{label:p.column.insertAfter,group:\"tablecolumn\",command:\"columnInsertAfter\",order:10},tablecolumn_delete:{label:p.column.deleteColumn,\ngroup:\"tablecolumn\",command:\"columnDelete\",order:15}});c.contextMenu&&c.contextMenu.addListener(function(a,b,c){return(a=c.contains({td:1,th:1},1))&&!a.isReadOnly()?{tablecell:CKEDITOR.TRISTATE_OFF,tablerow:CKEDITOR.TRISTATE_OFF,tablecolumn:CKEDITOR.TRISTATE_OFF}:null})},getCellColIndex:c,insertRow:f,insertColumn:l,getSelectedCells:a};CKEDITOR.plugins.add(\"tabletools\",CKEDITOR.plugins.tabletools)}(),CKEDITOR.tools.buildTableMap=function(a,f,b,c,d){a=a.$.rows;b=b||0;c=\"number\"===typeof c?c:a.length-\n1;d=\"number\"===typeof d?d:-1;var l=-1,k=[];for(f=f||0;f<=c;f++){l++;!k[l]&&(k[l]=[]);for(var g=-1,h=b;h<=(-1===d?a[f].cells.length-1:d);h++){var m=a[f].cells[h];if(!m)break;for(g++;k[l][g];)g++;for(var e=isNaN(m.colSpan)?1:m.colSpan,m=isNaN(m.rowSpan)?1:m.rowSpan,n=0;n<m&&!(f+n>c);n++){k[l+n]||(k[l+n]=[]);for(var q=0;q<e;q++)k[l+n][g+q]=a[f].cells[h]}g+=e-1;if(-1!==d&&g>=d)break}}return k},function(){function a(a){return CKEDITOR.plugins.widget&&CKEDITOR.plugins.widget.isDomWidget(a)}function f(a,\nb){var c=a.getAscendant(\"table\"),d=b.getAscendant(\"table\"),e=CKEDITOR.tools.buildTableMap(c),g=m(a),f=m(b),h=[],k={},l,n;c.contains(d)&&(b=b.getAscendant({td:1,th:1}),f=m(b));g>f&&(c=g,g=f,f=c,c=a,a=b,b=c);for(c=0;c<e[g].length;c++)if(a.$===e[g][c]){l=c;break}for(c=0;c<e[f].length;c++)if(b.$===e[f][c]){n=c;break}l>n&&(c=l,l=n,n=c);for(c=g;c<=f;c++)for(g=l;g<=n;g++)d=new CKEDITOR.dom.element(e[c][g]),d.$&&!d.getCustomData(\"selected_cell\")&&(h.push(d),CKEDITOR.dom.element.setMarker(k,d,\"selected_cell\",\n!0));CKEDITOR.dom.element.clearAllMarkers(k);return h}function b(a){if(a)return a=a.clone(),a.enlarge(CKEDITOR.ENLARGE_ELEMENT),(a=a.getEnclosedNode())&&a.is&&a.is(CKEDITOR.dtd.$tableContent)}function c(a){return(a=a.editable().findOne(\".cke_table-faked-selection\"))&&a.getAscendant(\"table\")}function d(a,b){var c=a.editable().find(\".cke_table-faked-selection\"),d=a.editable().findOne(\"[data-cke-table-faked-selection-table]\"),e;a.fire(\"lockSnapshot\");a.editable().removeClass(\"cke_table-faked-selection-editor\");\nfor(e=0;e<c.count();e++)c.getItem(e).removeClass(\"cke_table-faked-selection\");d&&d.data(\"cke-table-faked-selection-table\",!1);a.fire(\"unlockSnapshot\");b&&(v={active:!1},a.getSelection().isInTable()&&a.getSelection().reset())}function l(a,b){var c=[],d,e;for(e=0;e<b.length;e++)d=a.createRange(),d.setStartBefore(b[e]),d.setEndAfter(b[e]),c.push(d);a.getSelection().selectRanges(c)}function k(a){var b=a.editable().find(\".cke_table-faked-selection\");1>b.count()||(b=f(b.getItem(0),b.getItem(b.count()-1)),\nl(a,b))}function g(b,c,e){var g=r(b.getSelection(!0));c=c.is(\"table\")?null:c;var h;(h=v.active&&!v.first)&&!(h=c)&&(h=b.getSelection().getRanges(),h=1<g.length||h[0]&&!h[0].collapsed?!0:!1);if(h)v.first=c||g[0],v.dirty=c?!1:1!==g.length;else if(v.active&&c&&v.first.getAscendant(\"table\").equals(c.getAscendant(\"table\"))){g=f(v.first,c);if(!v.dirty&&1===g.length&&!a(e.data.getTarget()))return d(b,\"mouseup\"===e.name);v.dirty=!0;v.last=c;l(b,g)}}function h(a){var b=(a=a.editor||a.sender.editor)&&a.getSelection(),\nc=b&&b.getRanges()||[],e=c&&c[0].getEnclosedNode(),e=e&&e.type==CKEDITOR.NODE_ELEMENT&&e.is(\"img\"),g;if(b&&(d(a),b.isInTable()&&b.isFake))if(e)a.getSelection().reset();else if(!c[0]._getTableElement({table:1}).hasAttribute(\"data-cke-tableselection-ignored\")){1===c.length&&c[0]._getTableElement()&&c[0]._getTableElement().is(\"table\")&&(g=c[0]._getTableElement());g=r(b,g);a.fire(\"lockSnapshot\");for(b=0;b<g.length;b++)g[b].addClass(\"cke_table-faked-selection\");0<g.length&&(a.editable().addClass(\"cke_table-faked-selection-editor\"),\ng[0].getAscendant(\"table\").data(\"cke-table-faked-selection-table\",\"\"));a.fire(\"unlockSnapshot\")}}function m(a){return a.getAscendant(\"tr\",!0).$.rowIndex}function e(b){function f(a,b){return a&&b?a.equals(b)||a.contains(b)||b.contains(a)||a.getCommonAncestor(b).is(r):!1}function h(a){return!a.getAscendant(\"table\",!0)&&a.getDocument().equals(m.document)}function l(a,b,c,d){if(\"mousedown\"===a.name&&(CKEDITOR.tools.getMouseButton(a)===CKEDITOR.MOUSE_BUTTON_LEFT||!d))return!0;if(b=a.name===(CKEDITOR.env.gecko?\n\"mousedown\":\"mouseup\")&&!h(a.data.getTarget()))a=a.data.getTarget().getAscendant({td:1,th:1},!0),b=!(a&&a.hasClass(\"cke_table-faked-selection\"));return b}if(b.data.getTarget().getName&&(\"mouseup\"===b.name||!a(b.data.getTarget()))){var m=b.editor||b.listenerData.editor,n=m.getSelection(1),q=c(m),p=b.data.getTarget(),u=p&&p.getAscendant({td:1,th:1},!0),p=p&&p.getAscendant(\"table\",!0),r={table:1,thead:1,tbody:1,tfoot:1,tr:1,td:1,th:1};p&&p.hasAttribute(\"data-cke-tableselection-ignored\")||(l(b,n,q,p)&&\nd(m,!0),!v.active&&\"mousedown\"===b.name&&CKEDITOR.tools.getMouseButton(b)===CKEDITOR.MOUSE_BUTTON_LEFT&&p&&(v={active:!0},CKEDITOR.document.on(\"mouseup\",e,null,{editor:m})),(u||p)&&g(m,u||p,b),\"mouseup\"===b.name&&(CKEDITOR.tools.getMouseButton(b)===CKEDITOR.MOUSE_BUTTON_LEFT&&(h(b.data.getTarget())||f(q,p))&&k(m),v={active:!1},CKEDITOR.document.removeListener(\"mouseup\",e)))}}function n(a){var b=a.data.getTarget().getAscendant(\"table\",!0);b&&b.hasAttribute(\"data-cke-tableselection-ignored\")||(b=a.data.getTarget().getAscendant({td:1,\nth:1},!0))&&!b.hasClass(\"cke_table-faked-selection\")&&(a.cancel(),a.data.preventDefault())}function q(a,b){function c(a){a.cancel()}var d=a.getSelection(),e=d.createBookmarks(),g=a.document,f=a.createRange(),h=g.getDocumentElement().$,k=CKEDITOR.env.ie&&9>CKEDITOR.env.version,l=a.blockless||CKEDITOR.env.ie?\"span\":\"div\",m,n,p,q;g.getById(\"cke_table_copybin\")||(m=g.createElement(l),n=g.createElement(l),n.setAttributes({id:\"cke_table_copybin\",\"data-cke-temp\":\"1\"}),m.setStyles({position:\"absolute\",width:\"1px\",\nheight:\"1px\",overflow:\"hidden\"}),m.setStyle(\"ltr\"==a.config.contentsLangDirection?\"left\":\"right\",\"-5000px\"),m.setHtml(a.getSelectedHtml(!0)),a.fire(\"lockSnapshot\"),n.append(m),a.editable().append(n),q=a.on(\"selectionChange\",c,null,null,0),k&&(p=h.scrollTop),f.selectNodeContents(m),f.select(),k&&(h.scrollTop=p),setTimeout(function(){n.remove();d.selectBookmarks(e);q.removeListener();a.fire(\"unlockSnapshot\");b&&(a.extractSelectedHtml(),a.fire(\"saveSnapshot\"))},100))}function y(a){var b=a.editor||a.sender.editor,\nc=b.getSelection();c.isInTable()&&(c.getRanges()[0]._getTableElement({table:1}).hasAttribute(\"data-cke-tableselection-ignored\")||q(b,\"cut\"===a.name))}function u(a){this._reset();a&&this.setSelectedCells(a)}function p(a,b,c){a.on(\"beforeCommandExec\",function(c){-1!==CKEDITOR.tools.array.indexOf(b,c.data.name)&&(c.data.selectedCells=r(a.getSelection()))});a.on(\"afterCommandExec\",function(d){-1!==CKEDITOR.tools.array.indexOf(b,d.data.name)&&c(a,d.data)})}var v={active:!1},w,r,z,t,x;u.prototype={};u.prototype._reset=\nfunction(){this.cells={first:null,last:null,all:[]};this.rows={first:null,last:null}};u.prototype.setSelectedCells=function(a){this._reset();a=a.slice(0);this._arraySortByDOMOrder(a);this.cells.all=a;this.cells.first=a[0];this.cells.last=a[a.length-1];this.rows.first=a[0].getAscendant(\"tr\");this.rows.last=this.cells.last.getAscendant(\"tr\")};u.prototype.getTableMap=function(){var a=z(this.cells.first),b;a:{b=this.cells.last;var c=b.getAscendant(\"table\"),d=m(b),c=CKEDITOR.tools.buildTableMap(c),e;for(e=\n0;e<c[d].length;e++)if((new CKEDITOR.dom.element(c[d][e])).equals(b)){b=e;break a}b=void 0}return CKEDITOR.tools.buildTableMap(this._getTable(),m(this.rows.first),a,m(this.rows.last),b)};u.prototype._getTable=function(){return this.rows.first.getAscendant(\"table\")};u.prototype.insertRow=function(a,b,c){if(\"undefined\"===typeof a)a=1;else if(0>=a)return;for(var d=this.cells.first.$.cellIndex,e=this.cells.last.$.cellIndex,g=c?[]:this.cells.all,f,h=0;h<a;h++)f=t(c?this.cells.all:g,b),f=CKEDITOR.tools.array.filter(f.find(\"td, th\").toArray(),\nfunction(a){return c?!0:a.$.cellIndex>=d&&a.$.cellIndex<=e}),g=b?f.concat(g):g.concat(f);this.setSelectedCells(g)};u.prototype.insertColumn=function(a){function b(a){a=m(a);return a>=e&&a<=g}if(\"undefined\"===typeof a)a=1;else if(0>=a)return;for(var c=this.cells,d=c.all,e=m(c.first),g=m(c.last),c=0;c<a;c++)d=d.concat(CKEDITOR.tools.array.filter(x(d),b));this.setSelectedCells(d)};u.prototype.emptyCells=function(a){a=a||this.cells.all;for(var b=0;b<a.length;b++)a[b].setHtml(\"\")};u.prototype._arraySortByDOMOrder=\nfunction(a){a.sort(function(a,b){return a.getPosition(b)&CKEDITOR.POSITION_PRECEDING?-1:1})};var A={onPaste:function(a){function c(a){return Math.max.apply(null,CKEDITOR.tools.array.map(a,function(a){return a.length},0))}function d(a){var b=e.createRange();b.selectNodeContents(a);b.select()}var e=a.editor,g=e.getSelection(),h=g.getRanges(),h=h.length&&h[0]._getTableElement({table:1});if(!h||!h.hasAttribute(\"data-cke-tableselection-ignored\")){var k=r(g),h=this.findTableInPastedContent(e,a.data.dataValue),\nm=g.isInTable(!0)&&this.isBoundarySelection(g),n,p;!k.length||1===k.length&&!b(g.getRanges()[0])&&!m||m&&!h||(k=k[0].getAscendant(\"table\"),n=new u(r(g,k)),e.once(\"afterPaste\",function(){var a;if(p){a=new CKEDITOR.dom.element(p[0][0]);var b=p[p.length-1];a=f(a,new CKEDITOR.dom.element(b[b.length-1]))}else a=n.cells.all;l(e,a)}),h?(a.stop(),m?(n.insertRow(1,1===m,!0),g.selectElement(n.rows.first)):(n.emptyCells(),l(e,n.cells.all)),a=n.getTableMap(),p=CKEDITOR.tools.buildTableMap(h),n.insertRow(p.length-\na.length),n.insertColumn(c(p)-c(a)),a=n.getTableMap(),this.pasteTable(n,a,p),e.fire(\"saveSnapshot\"),setTimeout(function(){e.fire(\"afterPaste\")},0)):(d(n.cells.first),e.once(\"afterPaste\",function(){e.fire(\"lockSnapshot\");n.emptyCells(n.cells.all.slice(1));l(e,n.cells.all);e.fire(\"unlockSnapshot\")})))}},isBoundarySelection:function(a){a=a.getRanges()[0];var b=a.endContainer.getAscendant(\"tr\",!0);if(b&&a.collapsed){if(a.checkBoundaryOfElement(b,CKEDITOR.START))return 1;if(a.checkBoundaryOfElement(b,\nCKEDITOR.END))return 2}return 0},findTableInPastedContent:function(a,b){var c=a.dataProcessor,d=new CKEDITOR.dom.element(\"body\");c||(c=new CKEDITOR.htmlDataProcessor(a));d.setHtml(c.toHtml(b),{fixForBody:!1});return 1<d.getChildCount()?null:d.findOne(\"table\")},pasteTable:function(a,b,c){var d,e=z(a.cells.first),g=a._getTable(),f={},h,k,l,m;for(l=0;l<c.length;l++)for(h=new CKEDITOR.dom.element(g.$.rows[a.rows.first.$.rowIndex+l]),m=0;m<c[l].length;m++)if(k=new CKEDITOR.dom.element(c[l][m]),d=b[l]&&\nb[l][m]?new CKEDITOR.dom.element(b[l][m]):null,k&&!k.getCustomData(\"processed\")){if(d&&d.getParent())k.replace(d);else if(0===m||c[l][m-1])(d=0!==m?new CKEDITOR.dom.element(c[l][m-1]):null)&&h.equals(d.getParent())?k.insertAfter(d):0<e?h.$.cells[e]?k.insertAfter(new CKEDITOR.dom.element(h.$.cells[e])):h.append(k):h.append(k,!0);CKEDITOR.dom.element.setMarker(f,k,\"processed\",!0)}else k.getCustomData(\"processed\")&&d&&d.remove();CKEDITOR.dom.element.clearAllMarkers(f)}};CKEDITOR.plugins.tableselection=\n{getCellsBetween:f,keyboardIntegration:function(a){function b(a){var c=a.getEnclosedNode();c&&\"function\"===typeof c.is&&c.is({td:1,th:1})?c.setText(\"\"):a.deleteContents();CKEDITOR.tools.array.forEach(a._find(\"td\"),function(a){a.appendBogus()})}var c=a.editable();c.attachListener(c,\"keydown\",function(a){function c(b,d){if(!d.length)return null;var g=a.createRange(),f=CKEDITOR.dom.range.mergeRanges(d);CKEDITOR.tools.array.forEach(f,function(a){a.enlarge(CKEDITOR.ENLARGE_ELEMENT)});var h=f[0].getBoundaryNodes(),\nk=h.startNode,h=h.endNode;if(k&&k.is&&k.is(e)){for(var l=k.getAscendant(\"table\",!0),m=k.getPreviousSourceNode(!1,CKEDITOR.NODE_ELEMENT,l),n=!1,p=function(a){return!k.contains(a)&&a.is&&a.is(\"td\",\"th\")};m&&!p(m);)m=m.getPreviousSourceNode(!1,CKEDITOR.NODE_ELEMENT,l);!m&&h&&h.is&&!h.is(\"table\")&&h.getNext()&&(m=h.getNext().findOne(\"td, th\"),n=!0);if(m)g[\"moveToElementEdit\"+(n?\"Start\":\"End\")](m);else g.setStartBefore(k.getAscendant(\"table\",!0)),g.collapse(!0);f[0].deleteContents();return[g]}if(k)return g.moveToElementEditablePosition(k),\n[g]}var d={37:1,38:1,39:1,40:1,8:1,46:1,13:1},e=CKEDITOR.tools.extend({table:1},CKEDITOR.dtd.$tableContent);delete e.td;delete e.th;return function(e){var g=e.data.getKey(),f=e.data.getKeystroke(),h,k=37===g||38==g,l,m,n;if(d[g]&&!a.readOnly&&(h=a.getSelection())&&h.isInTable()&&h.isFake){l=h.getRanges();m=l[0]._getTableElement();n=l[l.length-1]._getTableElement();if(13!==g||a.plugins.enterkey)e.data.preventDefault(),e.cancel();if(36<g&&41>g)l[0].moveToElementEditablePosition(k?m:n,!k),h.selectRanges([l[0]]);\nelse if(13!==g||13===f||f===CKEDITOR.SHIFT+13){for(e=0;e<l.length;e++)b(l[e]);(e=c(m,l))?l=e:l[0].moveToElementEditablePosition(m);h.selectRanges(l);13===g&&a.plugins.enterkey?(a.fire(\"lockSnapshot\"),13===f?a.execCommand(\"enter\"):a.execCommand(\"shiftEnter\"),a.fire(\"unlockSnapshot\"),a.fire(\"saveSnapshot\")):13!==g&&a.fire(\"saveSnapshot\")}}}}(a),null,null,-1);c.attachListener(c,\"keypress\",function(c){var d=a.getSelection(),e=c.data.$.charCode||13===c.data.getKey(),g;if(!a.readOnly&&d&&d.isInTable()&&\nd.isFake&&e&&!(c.data.getKeystroke()&CKEDITOR.CTRL)){c=d.getRanges();e=c[0].getEnclosedNode().getAscendant({td:1,th:1},!0);for(g=0;g<c.length;g++)b(c[g]);e&&(c[0].moveToElementEditablePosition(e),d.selectRanges([c[0]]))}},null,null,-1)}};CKEDITOR.plugins.add(\"tableselection\",{requires:\"clipboard,tabletools\",isSupportedEnvironment:function(){return!(CKEDITOR.env.ie&&11>CKEDITOR.env.version)},onLoad:function(){w=CKEDITOR.plugins.tabletools;r=w.getSelectedCells;z=w.getCellColIndex;t=w.insertRow;x=w.insertColumn;\nCKEDITOR.document.appendStyleSheet(this.path+\"styles/tableselection.css\")},init:function(a){this.isSupportedEnvironment()&&(a.addContentsCss&&a.addContentsCss(this.path+\"styles/tableselection.css\"),a.on(\"contentDom\",function(){var b=a.editable(),c=b.isInline()?b:a.document,d={editor:a};b.attachListener(c,\"mousedown\",e,null,d);b.attachListener(c,\"mousemove\",e,null,d);b.attachListener(c,\"mouseup\",e,null,d);b.attachListener(b,\"dragstart\",n);b.attachListener(a,\"selectionCheck\",h);CKEDITOR.plugins.tableselection.keyboardIntegration(a);\nCKEDITOR.plugins.clipboard&&!CKEDITOR.plugins.clipboard.isCustomCopyCutSupported&&(b.attachListener(b,\"cut\",y),b.attachListener(b,\"copy\",y))}),a.on(\"paste\",A.onPaste,A),p(a,\"rowInsertBefore rowInsertAfter columnInsertBefore columnInsertAfter cellInsertBefore cellInsertAfter\".split(\" \"),function(a,b){l(a,b.selectedCells)}),p(a,[\"cellMerge\",\"cellMergeRight\",\"cellMergeDown\"],function(a,b){l(a,[b.commandData.cell])}),p(a,[\"cellDelete\"],function(a){d(a,!0)}))}})}(),\"use strict\",function(){var a=[CKEDITOR.CTRL+\n90,CKEDITOR.CTRL+89,CKEDITOR.CTRL+CKEDITOR.SHIFT+90],f={8:1,46:1};CKEDITOR.plugins.add(\"undo\",{init:function(c){function d(a){e.enabled&&!1!==a.data.command.canUndo&&e.save()}function f(){e.enabled=c.readOnly?!1:\"wysiwyg\"==c.mode;e.onChange()}var e=c.undoManager=new b(c),k=e.editingHandler=new l(e),q=c.addCommand(\"undo\",{exec:function(){e.undo()&&(c.selectionChange(),this.fire(\"afterUndo\"))},startDisabled:!0,canUndo:!1}),y=c.addCommand(\"redo\",{exec:function(){e.redo()&&(c.selectionChange(),this.fire(\"afterRedo\"))},\nstartDisabled:!0,canUndo:!1});c.setKeystroke([[a[0],\"undo\"],[a[1],\"redo\"],[a[2],\"redo\"]]);e.onChange=function(){q.setState(e.undoable()?CKEDITOR.TRISTATE_OFF:CKEDITOR.TRISTATE_DISABLED);y.setState(e.redoable()?CKEDITOR.TRISTATE_OFF:CKEDITOR.TRISTATE_DISABLED)};c.on(\"beforeCommandExec\",d);c.on(\"afterCommandExec\",d);c.on(\"saveSnapshot\",function(a){e.save(a.data&&a.data.contentOnly)});c.on(\"contentDom\",k.attachListeners,k);c.on(\"instanceReady\",function(){c.fire(\"saveSnapshot\")});c.on(\"beforeModeUnload\",\nfunction(){\"wysiwyg\"==c.mode&&e.save(!0)});c.on(\"mode\",f);c.on(\"readOnly\",f);c.ui.addButton&&(c.ui.addButton(\"Undo\",{label:c.lang.undo.undo,command:\"undo\",toolbar:\"undo,10\"}),c.ui.addButton(\"Redo\",{label:c.lang.undo.redo,command:\"redo\",toolbar:\"undo,20\"}));c.resetUndo=function(){e.reset();c.fire(\"saveSnapshot\")};c.on(\"updateSnapshot\",function(){e.currentImage&&e.update()});c.on(\"lockSnapshot\",function(a){a=a.data;e.lock(a&&a.dontUpdate,a&&a.forceUpdate)});c.on(\"unlockSnapshot\",e.unlock,e)}});CKEDITOR.plugins.undo=\n{};var b=CKEDITOR.plugins.undo.UndoManager=function(a){this.strokesRecorded=[0,0];this.locked=null;this.previousKeyGroup=-1;this.limit=a.config.undoStackSize||20;this.strokesLimit=25;this.editor=a;this.reset()};b.prototype={type:function(a,c){var d=b.getKeyGroup(a),e=this.strokesRecorded[d]+1;c=c||e>=this.strokesLimit;this.typing||(this.hasUndo=this.typing=!0,this.hasRedo=!1,this.onChange());c?(e=0,this.editor.fire(\"saveSnapshot\")):this.editor.fire(\"change\");this.strokesRecorded[d]=e;this.previousKeyGroup=\nd},keyGroupChanged:function(a){return b.getKeyGroup(a)!=this.previousKeyGroup},reset:function(){this.snapshots=[];this.index=-1;this.currentImage=null;this.hasRedo=this.hasUndo=!1;this.locked=null;this.resetType()},resetType:function(){this.strokesRecorded=[0,0];this.typing=!1;this.previousKeyGroup=-1},refreshState:function(){this.hasUndo=!!this.getNextImage(!0);this.hasRedo=!!this.getNextImage(!1);this.resetType();this.onChange()},save:function(a,b,d){var e=this.editor;if(this.locked||\"ready\"!=e.status||\n\"wysiwyg\"!=e.mode)return!1;var f=e.editable();if(!f||\"ready\"!=f.status)return!1;f=this.snapshots;b||(b=new c(e));if(!1===b.contents)return!1;if(this.currentImage)if(b.equalsContent(this.currentImage)){if(a||b.equalsSelection(this.currentImage))return!1}else!1!==d&&e.fire(\"change\");f.splice(this.index+1,f.length-this.index-1);f.length==this.limit&&f.shift();this.index=f.push(b)-1;this.currentImage=b;!1!==d&&this.refreshState();return!0},restoreImage:function(a){var b=this.editor,c;a.bookmarks&&(b.focus(),\nc=b.getSelection());this.locked={level:999};this.editor.loadSnapshot(a.contents);a.bookmarks?c.selectBookmarks(a.bookmarks):CKEDITOR.env.ie&&(c=this.editor.document.getBody().$.createTextRange(),c.collapse(!0),c.select());this.locked=null;this.index=a.index;this.currentImage=this.snapshots[this.index];this.update();this.refreshState();b.fire(\"change\")},getNextImage:function(a){var b=this.snapshots,c=this.currentImage,d;if(c)if(a)for(d=this.index-1;0<=d;d--){if(a=b[d],!c.equalsContent(a))return a.index=\nd,a}else for(d=this.index+1;d<b.length;d++)if(a=b[d],!c.equalsContent(a))return a.index=d,a;return null},redoable:function(){return this.enabled&&this.hasRedo},undoable:function(){return this.enabled&&this.hasUndo},undo:function(){if(this.undoable()){this.save(!0);var a=this.getNextImage(!0);if(a)return this.restoreImage(a),!0}return!1},redo:function(){if(this.redoable()&&(this.save(!0),this.redoable())){var a=this.getNextImage(!1);if(a)return this.restoreImage(a),!0}return!1},update:function(a){if(!this.locked){a||\n(a=new c(this.editor));for(var b=this.index,d=this.snapshots;0<b&&this.currentImage.equalsContent(d[b-1]);)--b;d.splice(b,this.index-b+1,a);this.index=b;this.currentImage=a}},updateSelection:function(a){if(!this.snapshots.length)return!1;var b=this.snapshots,c=b[b.length-1];return c.equalsContent(a)&&!c.equalsSelection(a)?(this.currentImage=b[b.length-1]=a,!0):!1},lock:function(a,b){if(this.locked)this.locked.level++;else if(a)this.locked={level:1};else{var d=null;if(b)d=!0;else{var e=new c(this.editor,\n!0);this.currentImage&&this.currentImage.equalsContent(e)&&(d=e)}this.locked={update:d,level:1}}},unlock:function(){if(this.locked&&!--this.locked.level){var a=this.locked.update;this.locked=null;if(!0===a)this.update();else if(a){var b=new c(this.editor,!0);a.equalsContent(b)||this.update()}}}};b.navigationKeyCodes={37:1,38:1,39:1,40:1,36:1,35:1,33:1,34:1};b.keyGroups={PRINTABLE:0,FUNCTIONAL:1};b.isNavigationKey=function(a){return!!b.navigationKeyCodes[a]};b.getKeyGroup=function(a){var c=b.keyGroups;\nreturn f[a]?c.FUNCTIONAL:c.PRINTABLE};b.getOppositeKeyGroup=function(a){var c=b.keyGroups;return a==c.FUNCTIONAL?c.PRINTABLE:c.FUNCTIONAL};b.ieFunctionalKeysBug=function(a){return CKEDITOR.env.ie&&b.getKeyGroup(a)==b.keyGroups.FUNCTIONAL};var c=CKEDITOR.plugins.undo.Image=function(a,b){this.editor=a;a.fire(\"beforeUndoImage\");var c=a.getSnapshot();CKEDITOR.env.ie&&c&&(c=c.replace(/\\s+data-cke-expando=\".*?\"/g,\"\"));this.contents=c;b||(this.bookmarks=(c=c&&a.getSelection())&&c.createBookmarks2(!0));a.fire(\"afterUndoImage\")},\nd=/\\b(?:href|src|name)=\"[^\"]*?\"/gi;c.prototype={equalsContent:function(a){var b=this.contents;a=a.contents;CKEDITOR.env.ie&&(CKEDITOR.env.ie7Compat||CKEDITOR.env.quirks)&&(b=b.replace(d,\"\"),a=a.replace(d,\"\"));return b!=a?!1:!0},equalsSelection:function(a){var b=this.bookmarks;a=a.bookmarks;if(b||a){if(!b||!a||b.length!=a.length)return!1;for(var c=0;c<b.length;c++){var d=b[c],f=a[c];if(d.startOffset!=f.startOffset||d.endOffset!=f.endOffset||!CKEDITOR.tools.arrayCompare(d.start,f.start)||!CKEDITOR.tools.arrayCompare(d.end,\nf.end))return!1}}return!0}};var l=CKEDITOR.plugins.undo.NativeEditingHandler=function(a){this.undoManager=a;this.ignoreInputEvent=!1;this.keyEventsStack=new k;this.lastKeydownImage=null};l.prototype={onKeydown:function(d){var f=d.data.getKey();if(229!==f)if(-1<CKEDITOR.tools.indexOf(a,d.data.getKeystroke()))d.data.preventDefault();else if(this.keyEventsStack.cleanUp(d),d=this.undoManager,this.keyEventsStack.getLast(f)||this.keyEventsStack.push(f),this.lastKeydownImage=new c(d.editor),b.isNavigationKey(f)||\nthis.undoManager.keyGroupChanged(f))if(d.strokesRecorded[0]||d.strokesRecorded[1])d.save(!1,this.lastKeydownImage,!1),d.resetType()},onInput:function(){if(this.ignoreInputEvent)this.ignoreInputEvent=!1;else{var a=this.keyEventsStack.getLast();a||(a=this.keyEventsStack.push(0));this.keyEventsStack.increment(a.keyCode);this.keyEventsStack.getTotalInputs()>=this.undoManager.strokesLimit&&(this.undoManager.type(a.keyCode,!0),this.keyEventsStack.resetInputs())}},onKeyup:function(a){var d=this.undoManager;\na=a.data.getKey();var f=this.keyEventsStack.getTotalInputs();this.keyEventsStack.remove(a);if(!(b.ieFunctionalKeysBug(a)&&this.lastKeydownImage&&this.lastKeydownImage.equalsContent(new c(d.editor,!0))))if(0<f)d.type(a);else if(b.isNavigationKey(a))this.onNavigationKey(!0)},onNavigationKey:function(a){var b=this.undoManager;!a&&b.save(!0,null,!1)||b.updateSelection(new c(b.editor));b.resetType()},ignoreInputEventListener:function(){this.ignoreInputEvent=!0},activateInputEventListener:function(){this.ignoreInputEvent=\n!1},attachListeners:function(){var a=this.undoManager.editor,c=a.editable(),d=this;c.attachListener(c,\"keydown\",function(a){d.onKeydown(a);if(b.ieFunctionalKeysBug(a.data.getKey()))d.onInput()},null,null,999);c.attachListener(c,CKEDITOR.env.ie?\"keypress\":\"input\",d.onInput,d,null,999);c.attachListener(c,\"keyup\",d.onKeyup,d,null,999);c.attachListener(c,\"paste\",d.ignoreInputEventListener,d,null,999);c.attachListener(c,\"drop\",d.ignoreInputEventListener,d,null,999);a.on(\"afterPaste\",d.activateInputEventListener,\nd,null,999);c.attachListener(c.isInline()?c:a.document.getDocumentElement(),\"click\",function(){d.onNavigationKey()},null,null,999);c.attachListener(this.undoManager.editor,\"blur\",function(){d.keyEventsStack.remove(9)},null,null,999)}};var k=CKEDITOR.plugins.undo.KeyEventsStack=function(){this.stack=[]};k.prototype={push:function(a){a=this.stack.push({keyCode:a,inputs:0});return this.stack[a-1]},getLastIndex:function(a){if(\"number\"!=typeof a)return this.stack.length-1;for(var b=this.stack.length;b--;)if(this.stack[b].keyCode==\na)return b;return-1},getLast:function(a){a=this.getLastIndex(a);return-1!=a?this.stack[a]:null},increment:function(a){this.getLast(a).inputs++},remove:function(a){a=this.getLastIndex(a);-1!=a&&this.stack.splice(a,1)},resetInputs:function(a){if(\"number\"==typeof a)this.getLast(a).inputs=0;else for(a=this.stack.length;a--;)this.stack[a].inputs=0},getTotalInputs:function(){for(var a=this.stack.length,b=0;a--;)b+=this.stack[a].inputs;return b},cleanUp:function(a){a=a.data.$;a.ctrlKey||a.metaKey||this.remove(17);\na.shiftKey||this.remove(16);a.altKey||this.remove(18)}}}(),\"use strict\",function(){function a(a,b){CKEDITOR.tools.extend(this,{editor:a,editable:a.editable(),doc:a.document,win:a.window},b,!0);this.inline=this.editable.isInline();this.inline||(this.frame=this.win.getFrame());this.target=this[this.inline?\"editable\":\"doc\"]}function f(a,b){CKEDITOR.tools.extend(this,b,{editor:a},!0)}function b(a,b){var c=a.editable();CKEDITOR.tools.extend(this,{editor:a,editable:c,inline:c.isInline(),doc:a.document,\nwin:a.window,container:CKEDITOR.document.getBody(),winTop:CKEDITOR.document.getWindow()},b,!0);this.hidden={};this.visible={};this.inline||(this.frame=this.win.getFrame());this.queryViewport();var f=CKEDITOR.tools.bind(this.queryViewport,this),g=CKEDITOR.tools.bind(this.hideVisible,this),k=CKEDITOR.tools.bind(this.removeAll,this);c.attachListener(this.winTop,\"resize\",f);c.attachListener(this.winTop,\"scroll\",f);c.attachListener(this.winTop,\"resize\",g);c.attachListener(this.win,\"scroll\",g);c.attachListener(this.inline?\nc:this.frame,\"mouseout\",function(a){var b=a.data.$.clientX;a=a.data.$.clientY;this.queryViewport();(b<=this.rect.left||b>=this.rect.right||a<=this.rect.top||a>=this.rect.bottom)&&this.hideVisible();(0>=b||b>=this.winTopPane.width||0>=a||a>=this.winTopPane.height)&&this.hideVisible()},this);c.attachListener(a,\"resize\",f);c.attachListener(a,\"mode\",k);a.on(\"destroy\",k);this.lineTpl=(new CKEDITOR.template('\\x3cdiv data-cke-lineutils-line\\x3d\"1\" class\\x3d\"cke_reset_all\" style\\x3d\"{lineStyle}\"\\x3e\\x3cspan style\\x3d\"{tipLeftStyle}\"\\x3e\\x26nbsp;\\x3c/span\\x3e\\x3cspan style\\x3d\"{tipRightStyle}\"\\x3e\\x26nbsp;\\x3c/span\\x3e\\x3c/div\\x3e')).output({lineStyle:CKEDITOR.tools.writeCssText(CKEDITOR.tools.extend({},\nl,this.lineStyle,!0)),tipLeftStyle:CKEDITOR.tools.writeCssText(CKEDITOR.tools.extend({},d,{left:\"0px\",\"border-left-color\":\"red\",\"border-width\":\"6px 0 6px 6px\"},this.tipCss,this.tipLeftStyle,!0)),tipRightStyle:CKEDITOR.tools.writeCssText(CKEDITOR.tools.extend({},d,{right:\"0px\",\"border-right-color\":\"red\",\"border-width\":\"6px 6px 6px 0\"},this.tipCss,this.tipRightStyle,!0))})}function c(a){var b;if(b=a&&a.type==CKEDITOR.NODE_ELEMENT)b=!(k[a.getComputedStyle(\"float\")]||k[a.getAttribute(\"align\")]);return b&&\n!g[a.getComputedStyle(\"position\")]}CKEDITOR.plugins.add(\"lineutils\");CKEDITOR.LINEUTILS_BEFORE=1;CKEDITOR.LINEUTILS_AFTER=2;CKEDITOR.LINEUTILS_INSIDE=4;a.prototype={start:function(a){var b=this,c=this.editor,d=this.doc,f,g,k,l,v=CKEDITOR.tools.eventsBuffer(50,function(){c.readOnly||\"wysiwyg\"!=c.mode||(b.relations={},(g=d.$.elementFromPoint(k,l))&&g.nodeType&&(f=new CKEDITOR.dom.element(g),b.traverseSearch(f),isNaN(k+l)||b.pixelSearch(f,k,l),a&&a(b.relations,k,l)))});this.listener=this.editable.attachListener(this.target,\n\"mousemove\",function(a){k=a.data.$.clientX;l=a.data.$.clientY;v.input()});this.editable.attachListener(this.inline?this.editable:this.frame,\"mouseout\",function(){v.reset()})},stop:function(){this.listener&&this.listener.removeListener()},getRange:function(){var a={};a[CKEDITOR.LINEUTILS_BEFORE]=CKEDITOR.POSITION_BEFORE_START;a[CKEDITOR.LINEUTILS_AFTER]=CKEDITOR.POSITION_AFTER_END;a[CKEDITOR.LINEUTILS_INSIDE]=CKEDITOR.POSITION_AFTER_START;return function(b){var c=this.editor.createRange();c.moveToPosition(this.relations[b.uid].element,\na[b.type]);return c}}(),store:function(){function a(b,c,d){var f=b.getUniqueId();f in d?d[f].type|=c:d[f]={element:b,type:c}}return function(b,d){var f;d&CKEDITOR.LINEUTILS_AFTER&&c(f=b.getNext())&&f.isVisible()&&(a(f,CKEDITOR.LINEUTILS_BEFORE,this.relations),d^=CKEDITOR.LINEUTILS_AFTER);d&CKEDITOR.LINEUTILS_INSIDE&&c(f=b.getFirst())&&f.isVisible()&&(a(f,CKEDITOR.LINEUTILS_BEFORE,this.relations),d^=CKEDITOR.LINEUTILS_INSIDE);a(b,d,this.relations)}}(),traverseSearch:function(a){var b,d,f;do if(f=a.$[\"data-cke-expando\"],\n!(f&&f in this.relations)){if(a.equals(this.editable))break;if(c(a))for(b in this.lookups)(d=this.lookups[b](a))&&this.store(a,d)}while((!a||a.type!=CKEDITOR.NODE_ELEMENT||\"true\"!=a.getAttribute(\"contenteditable\"))&&(a=a.getParent()))},pixelSearch:function(){function a(d,f,g,h,k){for(var l=0,v;k(g);){g+=h;if(25==++l)break;if(v=this.doc.$.elementFromPoint(f,g))if(v==d)l=0;else if(b(d,v)&&(l=0,c(v=new CKEDITOR.dom.element(v))))return v}}var b=CKEDITOR.env.ie||CKEDITOR.env.webkit?function(a,b){return a.contains(b)}:\nfunction(a,b){return!!(a.compareDocumentPosition(b)&16)};return function(b,d,f){var g=this.win.getViewPaneSize().height,k=a.call(this,b.$,d,f,-1,function(a){return 0<a});d=a.call(this,b.$,d,f,1,function(a){return a<g});if(k)for(this.traverseSearch(k);!k.getParent().equals(b);)k=k.getParent();if(d)for(this.traverseSearch(d);!d.getParent().equals(b);)d=d.getParent();for(;k||d;){k&&(k=k.getNext(c));if(!k||k.equals(d))break;this.traverseSearch(k);d&&(d=d.getPrevious(c));if(!d||d.equals(k))break;this.traverseSearch(d)}}}(),\ngreedySearch:function(){this.relations={};for(var a=this.editable.getElementsByTag(\"*\"),b=0,d,f,g;d=a.getItem(b++);)if(!d.equals(this.editable)&&d.type==CKEDITOR.NODE_ELEMENT&&(d.hasAttribute(\"contenteditable\")||!d.isReadOnly())&&c(d)&&d.isVisible())for(g in this.lookups)(f=this.lookups[g](d))&&this.store(d,f);return this.relations}};f.prototype={locate:function(){function a(b,d){var f=b.element[d===CKEDITOR.LINEUTILS_BEFORE?\"getPrevious\":\"getNext\"]();return f&&c(f)?(b.siblingRect=f.getClientRect(),\nd==CKEDITOR.LINEUTILS_BEFORE?(b.siblingRect.bottom+b.elementRect.top)/2:(b.elementRect.bottom+b.siblingRect.top)/2):d==CKEDITOR.LINEUTILS_BEFORE?b.elementRect.top:b.elementRect.bottom}return function(b){var c;this.locations={};for(var d in b)c=b[d],c.elementRect=c.element.getClientRect(),c.type&CKEDITOR.LINEUTILS_BEFORE&&this.store(d,CKEDITOR.LINEUTILS_BEFORE,a(c,CKEDITOR.LINEUTILS_BEFORE)),c.type&CKEDITOR.LINEUTILS_AFTER&&this.store(d,CKEDITOR.LINEUTILS_AFTER,a(c,CKEDITOR.LINEUTILS_AFTER)),c.type&\nCKEDITOR.LINEUTILS_INSIDE&&this.store(d,CKEDITOR.LINEUTILS_INSIDE,(c.elementRect.top+c.elementRect.bottom)/2);return this.locations}}(),sort:function(){var a,b,c,d;return function(f,g){a=this.locations;b=[];for(var k in a)for(var l in a[k])if(c=Math.abs(f-a[k][l]),b.length){for(d=0;d<b.length;d++)if(c<b[d].dist){b.splice(d,0,{uid:+k,type:l,dist:c});break}d==b.length&&b.push({uid:+k,type:l,dist:c})}else b.push({uid:+k,type:l,dist:c});return\"undefined\"!=typeof g?b.slice(0,g):b}}(),store:function(a,\nb,c){this.locations[a]||(this.locations[a]={});this.locations[a][b]=c}};var d={display:\"block\",width:\"0px\",height:\"0px\",\"border-color\":\"transparent\",\"border-style\":\"solid\",position:\"absolute\",top:\"-6px\"},l={height:\"0px\",\"border-top\":\"1px dashed red\",position:\"absolute\",\"z-index\":9999};b.prototype={removeAll:function(){for(var a in this.hidden)this.hidden[a].remove(),delete this.hidden[a];for(a in this.visible)this.visible[a].remove(),delete this.visible[a]},hideLine:function(a){var b=a.getUniqueId();\na.hide();this.hidden[b]=a;delete this.visible[b]},showLine:function(a){var b=a.getUniqueId();a.show();this.visible[b]=a;delete this.hidden[b]},hideVisible:function(){for(var a in this.visible)this.hideLine(this.visible[a])},placeLine:function(a,b){var c,d,f;if(c=this.getStyle(a.uid,a.type)){for(f in this.visible)if(this.visible[f].getCustomData(\"hash\")!==this.hash){d=this.visible[f];break}if(!d)for(f in this.hidden)if(this.hidden[f].getCustomData(\"hash\")!==this.hash){this.showLine(d=this.hidden[f]);\nbreak}d||this.showLine(d=this.addLine());d.setCustomData(\"hash\",this.hash);this.visible[d.getUniqueId()]=d;d.setStyles(c);b&&b(d)}},getStyle:function(a,b){var c=this.relations[a],d=this.locations[a][b],f={};f.width=c.siblingRect?Math.max(c.siblingRect.width,c.elementRect.width):c.elementRect.width;f.top=this.inline?d+this.winTopScroll.y-this.rect.relativeY:this.rect.top+this.winTopScroll.y+d;if(f.top-this.winTopScroll.y<this.rect.top||f.top-this.winTopScroll.y>this.rect.bottom)return!1;this.inline?\nf.left=c.elementRect.left-this.rect.relativeX:(0<c.elementRect.left?f.left=this.rect.left+c.elementRect.left:(f.width+=c.elementRect.left,f.left=this.rect.left),0<(c=f.left+f.width-(this.rect.left+this.winPane.width))&&(f.width-=c));f.left+=this.winTopScroll.x;for(var g in f)f[g]=CKEDITOR.tools.cssLength(f[g]);return f},addLine:function(){var a=CKEDITOR.dom.element.createFromHtml(this.lineTpl);a.appendTo(this.container);return a},prepare:function(a,b){this.relations=a;this.locations=b;this.hash=Math.random()},\ncleanup:function(){var a,b;for(b in this.visible)a=this.visible[b],a.getCustomData(\"hash\")!==this.hash&&this.hideLine(a)},queryViewport:function(){this.winPane=this.win.getViewPaneSize();this.winTopScroll=this.winTop.getScrollPosition();this.winTopPane=this.winTop.getViewPaneSize();this.rect=this.getClientRect(this.inline?this.editable:this.frame)},getClientRect:function(a){a=a.getClientRect();var b=this.container.getDocumentPosition(),c=this.container.getComputedStyle(\"position\");a.relativeX=a.relativeY=\n0;\"static\"!=c&&(a.relativeY=b.y,a.relativeX=b.x,a.top-=a.relativeY,a.bottom-=a.relativeY,a.left-=a.relativeX,a.right-=a.relativeX);return a}};var k={left:1,right:1,center:1},g={absolute:1,fixed:1};CKEDITOR.plugins.lineutils={finder:a,locator:f,liner:b}}(),function(){function a(a){return a.getName&&!a.hasAttribute(\"data-cke-temp\")}CKEDITOR.plugins.add(\"widgetselection\",{init:function(a){if(CKEDITOR.env.webkit){var b=CKEDITOR.plugins.widgetselection;a.on(\"contentDom\",function(a){a=a.editor;var d=a.editable();\nd.attachListener(d,\"keydown\",function(a){a.data.getKeystroke()==CKEDITOR.CTRL+65&&CKEDITOR.tools.setTimeout(function(){b.addFillers(d)||b.removeFillers(d)},0)},null,null,-1);a.on(\"selectionCheck\",function(a){b.removeFillers(a.editor.editable())});a.on(\"paste\",function(a){a.data.dataValue=b.cleanPasteData(a.data.dataValue)});\"selectall\"in a.plugins&&b.addSelectAllIntegration(a)})}}});CKEDITOR.plugins.widgetselection={startFiller:null,endFiller:null,fillerAttribute:\"data-cke-filler-webkit\",fillerContent:\"\\x26nbsp;\",\nfillerTagName:\"div\",addFillers:function(f){var b=f.editor;if(!this.isWholeContentSelected(f)&&0<f.getChildCount()){var c=f.getFirst(a),d=f.getLast(a);c&&c.type==CKEDITOR.NODE_ELEMENT&&!c.isEditable()&&(this.startFiller=this.createFiller(),f.append(this.startFiller,1));d&&d.type==CKEDITOR.NODE_ELEMENT&&!d.isEditable()&&(this.endFiller=this.createFiller(!0),f.append(this.endFiller,0));if(this.hasFiller(f))return b=b.createRange(),b.selectNodeContents(f),b.select(),!0}return!1},removeFillers:function(a){if(this.hasFiller(a)&&\n!this.isWholeContentSelected(a)){var b=a.findOne(this.fillerTagName+\"[\"+this.fillerAttribute+\"\\x3dstart]\"),c=a.findOne(this.fillerTagName+\"[\"+this.fillerAttribute+\"\\x3dend]\");this.startFiller&&b&&this.startFiller.equals(b)?this.removeFiller(this.startFiller,a):this.startFiller=b;this.endFiller&&c&&this.endFiller.equals(c)?this.removeFiller(this.endFiller,a):this.endFiller=c}},cleanPasteData:function(a){a&&a.length&&(a=a.replace(this.createFillerRegex(),\"\").replace(this.createFillerRegex(!0),\"\"));\nreturn a},isWholeContentSelected:function(a){var b=a.editor.getSelection().getRanges()[0];return!b||b&&b.collapsed?!1:(b=b.clone(),b.enlarge(CKEDITOR.ENLARGE_ELEMENT),!!(b&&a&&b.startContainer&&b.endContainer&&0===b.startOffset&&b.endOffset===a.getChildCount()&&b.startContainer.equals(a)&&b.endContainer.equals(a)))},hasFiller:function(a){return 0<a.find(this.fillerTagName+\"[\"+this.fillerAttribute+\"]\").count()},createFiller:function(a){var b=new CKEDITOR.dom.element(this.fillerTagName);b.setHtml(this.fillerContent);\nb.setAttribute(this.fillerAttribute,a?\"end\":\"start\");b.setAttribute(\"data-cke-temp\",1);b.setStyles({display:\"block\",width:0,height:0,padding:0,border:0,margin:0,position:\"absolute\",top:0,left:\"-9999px\",opacity:0,overflow:\"hidden\"});return b},removeFiller:function(a,b){if(a){var c=b.editor,d=b.editor.getSelection().getRanges()[0].startPath(),l=c.createRange(),k,g;d.contains(a)&&(k=a.getHtml(),g=!0);d=\"start\"==a.getAttribute(this.fillerAttribute);a.remove();k&&0<k.length&&k!=this.fillerContent?(b.insertHtmlIntoRange(k,\nc.getSelection().getRanges()[0]),l.setStartAt(b.getChild(b.getChildCount()-1),CKEDITOR.POSITION_BEFORE_END),c.getSelection().selectRanges([l])):g&&(d?l.setStartAt(b.getFirst().getNext(),CKEDITOR.POSITION_AFTER_START):l.setEndAt(b.getLast().getPrevious(),CKEDITOR.POSITION_BEFORE_END),b.editor.getSelection().selectRanges([l]))}},createFillerRegex:function(a){var b=this.createFiller(a).getOuterHtml().replace(/style=\"[^\"]*\"/gi,'style\\x3d\"[^\"]*\"').replace(/>[^<]*</gi,\"\\x3e[^\\x3c]*\\x3c\");return new RegExp((a?\n\"\":\"^\")+b+(a?\"$\":\"\"))},addSelectAllIntegration:function(a){var b=this;a.editable().attachListener(a,\"beforeCommandExec\",function(c){var d=a.editable();\"selectAll\"==c.data.name&&d&&b.addFillers(d)},null,null,9999)}}}(),\"use strict\",function(){function a(a){this.editor=a;this.registered={};this.instances={};this.selected=[];this.widgetHoldingFocusedEditable=this.focused=null;this._={nextId:0,upcasts:[],upcastCallbacks:[],filters:{}};H(this);C(this);this.on(\"checkWidgets\",k);this.editor.on(\"contentDomInvalidated\",\nthis.checkWidgets,this);B(this);t(this);x(this);z(this);A(this)}function f(a,b,c,d,e){var g=a.editor;CKEDITOR.tools.extend(this,d,{editor:g,id:b,inline:\"span\"==c.getParent().getName(),element:c,data:CKEDITOR.tools.extend({},\"function\"==typeof d.defaults?d.defaults():d.defaults),dataReady:!1,inited:!1,ready:!1,edit:f.prototype.edit,focusedEditable:null,definition:d,repository:a,draggable:!1!==d.draggable,_:{downcastFn:d.downcast&&\"string\"==typeof d.downcast?d.downcasts[d.downcast]:d.downcast}},!0);\na.fire(\"instanceCreated\",this);ha(this,d);this.init&&this.init();this.inited=!0;(a=this.element.data(\"cke-widget-data\"))&&this.setData(JSON.parse(decodeURIComponent(a)));e&&this.setData(e);this.data.classes||this.setData(\"classes\",this.getClasses());this.dataReady=!0;U(this);this.fire(\"data\",this.data);this.isInited()&&g.editable().contains(this.wrapper)&&(this.ready=!0,this.fire(\"ready\"))}function b(a,b,c){CKEDITOR.dom.element.call(this,b.$);this.editor=a;this._={};b=this.filter=c.filter;CKEDITOR.dtd[this.getName()].p?\n(this.enterMode=b?b.getAllowedEnterMode(a.enterMode):a.enterMode,this.shiftEnterMode=b?b.getAllowedEnterMode(a.shiftEnterMode,!0):a.shiftEnterMode):this.enterMode=this.shiftEnterMode=CKEDITOR.ENTER_BR}function c(a,b){a.addCommand(b.name,{exec:function(a,c){function d(){a.widgets.finalizeCreation(h)}var e=a.widgets.focused;if(e&&e.name==b.name)e.edit();else if(b.insert)b.insert({editor:a,commandData:c});else if(b.template){var e=\"function\"==typeof b.defaults?b.defaults():b.defaults,e=CKEDITOR.dom.element.createFromHtml(b.template.output(e)),\nf,g=a.widgets.wrapElement(e,b.name),h=new CKEDITOR.dom.documentFragment(g.getDocument());h.append(g);(f=a.widgets.initOn(e,b,c&&c.startupData))?(e=f.once(\"edit\",function(b){if(b.data.dialog)f.once(\"dialog\",function(b){b=b.data;var c,e;c=b.once(\"ok\",d,null,null,20);e=b.once(\"cancel\",function(b){b.data&&!1===b.data.hide||a.widgets.destroy(f,!0)});b.once(\"hide\",function(){c.removeListener();e.removeListener()})});else d()},null,null,999),f.edit(),e.removeListener()):d()}},allowedContent:b.allowedContent,\nrequiredContent:b.requiredContent,contentForms:b.contentForms,contentTransformations:b.contentTransformations})}function d(a,b){function c(a,d){var e=b.upcast.split(\",\"),f,g;for(g=0;g<e.length;g++)if(f=e[g],f===a.name)return b.upcasts[f].call(this,a,d);return!1}function d(b,c,e){var f=CKEDITOR.tools.getIndex(a._.upcasts,function(a){return a[2]>e});0>f&&(f=a._.upcasts.length);a._.upcasts.splice(f,0,[CKEDITOR.tools.bind(b,c),c.name,e])}var e=b.upcast,f=b.upcastPriority||10;e&&(\"string\"==typeof e?d(c,\nb,f):d(e,b,f))}function l(a,b){a.focused=null;if(b.isInited()){var c=b.editor.checkDirty();a.fire(\"widgetBlurred\",{widget:b});b.setFocused(!1);!c&&b.editor.resetDirty()}}function k(a){a=a.data;if(\"wysiwyg\"==this.editor.mode){var b=this.editor.editable(),c=this.instances,d,e,g,h;if(b){for(d in c)c[d].isReady()&&!b.contains(c[d].wrapper)&&this.destroy(c[d],!0);if(a&&a.initOnlyNew)c=this.initOnAll();else{var k=b.find(\".cke_widget_wrapper\"),c=[];d=0;for(e=k.count();d<e;d++){g=k.getItem(d);if(h=!this.getByElement(g,\n!0)){a:{h=p;for(var l=g;l=l.getParent();)if(h(l)){h=!0;break a}h=!1}h=!h}h&&b.contains(g)&&(g.addClass(\"cke_widget_new\"),c.push(this.initOn(g.getFirst(f.isDomWidgetElement))))}}a&&a.focusInited&&1==c.length&&c[0].focus()}}}function g(a){if(\"undefined\"!=typeof a.attributes&&a.attributes[\"data-widget\"]){var b=h(a),c=m(a),d=!1;b&&b.value&&b.value.match(/^\\s/g)&&(b.parent.attributes[\"data-cke-white-space-first\"]=1,b.value=b.value.replace(/^\\s/g,\"\\x26nbsp;\"),d=!0);c&&c.value&&c.value.match(/\\s$/g)&&(c.parent.attributes[\"data-cke-white-space-last\"]=\n1,c.value=c.value.replace(/\\s$/g,\"\\x26nbsp;\"),d=!0);d&&(a.attributes[\"data-cke-widget-white-space\"]=1)}}function h(a){return a.find(function(a){return 3===a.type},!0).shift()}function m(a){return a.find(function(a){return 3===a.type},!0).pop()}function e(a,b,c){if(!c.allowedContent&&!c.disallowedContent)return null;var d=this._.filters[a];d||(this._.filters[a]=d={});a=d[b];a||(a=c.allowedContent?new CKEDITOR.filter(c.allowedContent):this.editor.filter.clone(),d[b]=a,c.disallowedContent&&a.disallow(c.disallowedContent));\nreturn a}function n(a){var b=[],c=a._.upcasts,d=a._.upcastCallbacks;return{toBeWrapped:b,iterator:function(a){var e,g,h,k,l;if(\"data-cke-widget-wrapper\"in a.attributes)return(a=a.getFirst(f.isParserWidgetElement))&&b.push([a]),!1;if(\"data-widget\"in a.attributes)return b.push([a]),!1;if(l=c.length){if(a.attributes[\"data-cke-widget-upcasted\"])return!1;k=0;for(e=d.length;k<e;++k)if(!1===d[k](a))return;for(k=0;k<l;++k)if(e=c[k],h={},g=e[0](a,h))return g instanceof CKEDITOR.htmlParser.element&&(a=g),a.attributes[\"data-cke-widget-data\"]=\nencodeURIComponent(JSON.stringify(h)),a.attributes[\"data-cke-widget-upcasted\"]=1,b.push([a,e[1]]),!1}}}}function q(a,b){return{tabindex:-1,contenteditable:\"false\",\"data-cke-widget-wrapper\":1,\"data-cke-filter\":\"off\",\"class\":\"cke_widget_wrapper cke_widget_new cke_widget_\"+(a?\"inline\":\"block\")+(b?\" cke_widget_\"+b:\"\")}}function y(a,b,c){if(a.type==CKEDITOR.NODE_ELEMENT){var d=CKEDITOR.dtd[a.name];if(d&&!d[c.name]){var d=a.split(b),e=a.parent;b=d.getIndex();a.children.length||(--b,a.remove());d.children.length||\nd.remove();return y(e,b,c)}}a.add(c,b)}function u(a,b){return\"boolean\"==typeof a.inline?a.inline:!!CKEDITOR.dtd.$inline[b]}function p(a){return a.hasAttribute(\"data-cke-temp\")}function v(a,b,c,d){var e=a.editor;e.fire(\"lockSnapshot\");c?(d=c.data(\"cke-widget-editable\"),d=b.editables[d],a.widgetHoldingFocusedEditable=b,b.focusedEditable=d,c.addClass(\"cke_widget_editable_focused\"),d.filter&&e.setActiveFilter(d.filter),e.setActiveEnterMode(d.enterMode,d.shiftEnterMode)):(d||b.focusedEditable.removeClass(\"cke_widget_editable_focused\"),\nb.focusedEditable=null,a.widgetHoldingFocusedEditable=null,e.setActiveFilter(null),e.setActiveEnterMode(null,null));e.fire(\"unlockSnapshot\")}function w(a){a.contextMenu&&a.contextMenu.addListener(function(b){if(b=a.widgets.getByElement(b,!0))return b.fire(\"contextMenu\",{})})}function r(a,b){return CKEDITOR.tools.trim(b)}function z(a){var b=a.editor,c=CKEDITOR.plugins.lineutils;b.on(\"dragstart\",function(c){var d=c.data.target;f.isDomDragHandler(d)&&(d=a.getByElement(d),c.data.dataTransfer.setData(\"cke/widget-id\",\nd.id),b.focus(),d.focus())});b.on(\"drop\",function(c){var d=c.data.dataTransfer,e=d.getData(\"cke/widget-id\"),f=d.getTransferType(b),d=b.createRange();\"\"!==e&&f===CKEDITOR.DATA_TRANSFER_CROSS_EDITORS?c.cancel():\"\"!==e&&f==CKEDITOR.DATA_TRANSFER_INTERNAL&&(e=a.instances[e])&&(d.setStartBefore(e.wrapper),d.setEndAfter(e.wrapper),c.data.dragRange=d,delete CKEDITOR.plugins.clipboard.dragStartContainerChildCount,delete CKEDITOR.plugins.clipboard.dragEndContainerChildCount,c.data.dataTransfer.setData(\"text/html\",\nb.editable().getHtmlFromRange(d).getHtml()),b.widgets.destroy(e,!0))});b.on(\"contentDom\",function(){var d=b.editable();CKEDITOR.tools.extend(a,{finder:new c.finder(b,{lookups:{\"default\":function(b){if(!b.is(CKEDITOR.dtd.$listItem)&&b.is(CKEDITOR.dtd.$block)&&!f.isDomNestedEditable(b)&&!a._.draggedWidget.wrapper.contains(b)){var c=f.getNestedEditable(d,b);if(c){b=a._.draggedWidget;if(a.getByElement(c)==b)return;c=CKEDITOR.filter.instances[c.data(\"cke-filter\")];b=b.requiredContent;if(c&&b&&!c.check(b))return}return CKEDITOR.LINEUTILS_BEFORE|\nCKEDITOR.LINEUTILS_AFTER}}}}),locator:new c.locator(b),liner:new c.liner(b,{lineStyle:{cursor:\"move !important\",\"border-top-color\":\"#666\"},tipLeftStyle:{\"border-left-color\":\"#666\"},tipRightStyle:{\"border-right-color\":\"#666\"}})},!0)})}function t(a){var b=a.editor;b.on(\"contentDom\",function(){var c=b.editable(),d=c.isInline()?c:b.document,e,g;c.attachListener(d,\"mousedown\",function(c){var d=c.data.getTarget();e=d instanceof CKEDITOR.dom.element?a.getByElement(d):null;g=0;e&&(e.inline&&d.type==CKEDITOR.NODE_ELEMENT&&\nd.hasAttribute(\"data-cke-widget-drag-handler\")?(g=1,a.focused!=e&&b.getSelection().removeAllRanges()):f.getNestedEditable(e.wrapper,d)?e=null:(c.data.preventDefault(),CKEDITOR.env.ie||e.focus()))});c.attachListener(d,\"mouseup\",function(){g&&e&&e.wrapper&&(g=0,e.focus())});CKEDITOR.env.ie&&c.attachListener(d,\"mouseup\",function(){setTimeout(function(){e&&e.wrapper&&c.contains(e.wrapper)&&(e.focus(),e=null)})})});b.on(\"doubleclick\",function(b){var c=a.getByElement(b.data.element);if(c&&!f.getNestedEditable(c.wrapper,\nb.data.element))return c.fire(\"doubleclick\",{element:b.data.element})},null,null,1)}function x(a){a.editor.on(\"key\",function(b){var c=a.focused,d=a.widgetHoldingFocusedEditable,e;c?e=c.fire(\"key\",{keyCode:b.data.keyCode}):d&&(c=b.data.keyCode,b=d.focusedEditable,c==CKEDITOR.CTRL+65?(c=b.getBogus(),d=d.editor.createRange(),d.selectNodeContents(b),c&&d.setEndAt(c,CKEDITOR.POSITION_BEFORE_START),d.select(),e=!1):8==c||46==c?(e=d.editor.getSelection().getRanges(),d=e[0],e=!(1==e.length&&d.collapsed&&\nd.checkBoundaryOfElement(b,CKEDITOR[8==c?\"START\":\"END\"]))):e=void 0);return e},null,null,1)}function A(a){function b(c){a.focused&&E(a.focused,\"cut\"==c.name)}var c=a.editor;c.on(\"contentDom\",function(){var a=c.editable();a.attachListener(a,\"copy\",b);a.attachListener(a,\"cut\",b)})}function B(a){var b=a.editor;b.on(\"selectionCheck\",function(){a.fire(\"checkSelection\")});a.on(\"checkSelection\",a.checkSelection,a);b.on(\"selectionChange\",function(c){var d=(c=f.getNestedEditable(b.editable(),c.data.selection.getStartElement()))&&\na.getByElement(c),e=a.widgetHoldingFocusedEditable;e?e===d&&e.focusedEditable.equals(c)||(v(a,e,null),d&&c&&v(a,d,c)):d&&c&&v(a,d,c)});b.on(\"dataReady\",function(){F(a).commit()});b.on(\"blur\",function(){var b;(b=a.focused)&&l(a,b);(b=a.widgetHoldingFocusedEditable)&&v(a,b,null)})}function C(a){var b=a.editor,c={};b.on(\"toDataFormat\",function(b){var d=CKEDITOR.tools.getNextNumber(),e=[];b.data.downcastingSessionId=d;c[d]=e;b.data.dataValue.forEach(function(b){var c=b.attributes,d;if(\"data-cke-widget-white-space\"in\nc){d=h(b);var g=m(b);d.parent.attributes[\"data-cke-white-space-first\"]&&(d.value=d.value.replace(/^&nbsp;/g,\" \"));g.parent.attributes[\"data-cke-white-space-last\"]&&(g.value=g.value.replace(/&nbsp;$/g,\" \"))}if(\"data-cke-widget-id\"in c){if(c=a.instances[c[\"data-cke-widget-id\"]])d=b.getFirst(f.isParserWidgetElement),e.push({wrapper:b,element:d,widget:c,editables:{}}),\"1\"!=d.attributes[\"data-cke-widget-keep-attr\"]&&delete d.attributes[\"data-widget\"]}else if(\"data-cke-widget-editable\"in c)return 0<e.length&&\n(e[e.length-1].editables[c[\"data-cke-widget-editable\"]]=b),!1},CKEDITOR.NODE_ELEMENT,!0)},null,null,8);b.on(\"toDataFormat\",function(a){if(a.data.downcastingSessionId){a=c[a.data.downcastingSessionId];for(var b,d,e,f,g,h;b=a.shift();){d=b.widget;e=b.element;f=d._.downcastFn&&d._.downcastFn.call(d,e);for(h in b.editables)g=b.editables[h],delete g.attributes.contenteditable,g.setHtml(d.editables[h].getData());f||(f=e);b.wrapper.replaceWith(f)}}},null,null,13);b.on(\"contentDomUnload\",function(){a.destroyAll(!0)})}\nfunction H(a){var b=a.editor,c,d;b.on(\"toHtml\",function(b){var d=n(a),e;for(b.data.dataValue.forEach(d.iterator,CKEDITOR.NODE_ELEMENT,!0);e=d.toBeWrapped.pop();){var g=e[0],h=g.parent;h.type==CKEDITOR.NODE_ELEMENT&&h.attributes[\"data-cke-widget-wrapper\"]&&h.replaceWith(g);a.wrapElement(e[0],e[1])}c=b.data.protectedWhitespaces?3==b.data.dataValue.children.length&&f.isParserWidgetWrapper(b.data.dataValue.children[1]):1==b.data.dataValue.children.length&&f.isParserWidgetWrapper(b.data.dataValue.children[0])},\nnull,null,8);b.on(\"dataReady\",function(){if(d)for(var c=b.editable().find(\".cke_widget_wrapper\"),e,g,h=0,k=c.count();h<k;++h)e=c.getItem(h),g=e.getFirst(f.isDomWidgetElement),g.type==CKEDITOR.NODE_ELEMENT&&g.data(\"widget\")?(g.replace(e),a.wrapElement(g)):e.remove();d=0;a.destroyAll(!0);a.initOnAll()});b.on(\"loadSnapshot\",function(b){/data-cke-widget/.test(b.data)&&(d=1);a.destroyAll(!0)},null,null,9);b.on(\"paste\",function(a){a=a.data;a.dataValue=a.dataValue.replace(ca,r);a.range&&(a=f.getNestedEditable(b.editable(),\na.range.startContainer))&&(a=CKEDITOR.filter.instances[a.data(\"cke-filter\")])&&b.setActiveFilter(a)});b.on(\"afterInsertHtml\",function(d){d.data.intoRange?a.checkWidgets({initOnlyNew:!0}):(b.fire(\"lockSnapshot\"),a.checkWidgets({initOnlyNew:!0,focusInited:c}),b.fire(\"unlockSnapshot\"))})}function F(a){var b=a.selected,c=[],d=b.slice(0),e=null;return{select:function(a){0>CKEDITOR.tools.indexOf(b,a)&&c.push(a);a=CKEDITOR.tools.indexOf(d,a);0<=a&&d.splice(a,1);return this},focus:function(a){e=a;return this},\ncommit:function(){var f=a.focused!==e,g,h;a.editor.fire(\"lockSnapshot\");for(f&&(g=a.focused)&&l(a,g);g=d.pop();)b.splice(CKEDITOR.tools.indexOf(b,g),1),g.isInited()&&(h=g.editor.checkDirty(),g.setSelected(!1),!h&&g.editor.resetDirty());f&&e&&(h=a.editor.checkDirty(),a.focused=e,a.fire(\"widgetFocused\",{widget:e}),e.setFocused(!0),!h&&a.editor.resetDirty());for(;g=c.pop();)b.push(g),g.setSelected(!0);a.editor.fire(\"unlockSnapshot\")}}}function I(a,b,c){var d=0;b=L(b);var e=a.data.classes||{},f;if(b){for(e=\nCKEDITOR.tools.clone(e);f=b.pop();)c?e[f]||(d=e[f]=1):e[f]&&(delete e[f],d=1);d&&a.setData(\"classes\",e)}}function J(a){a.cancel()}function E(a,b){var c=a.editor,d=c.document,e=CKEDITOR.env.edge&&16<=CKEDITOR.env.version;if(!d.getById(\"cke_copybin\")){var f=!c.blockless&&!CKEDITOR.env.ie||e?\"div\":\"span\",e=d.createElement(f),g=d.createElement(f),f=CKEDITOR.env.ie&&9>CKEDITOR.env.version;g.setAttributes({id:\"cke_copybin\",\"data-cke-temp\":\"1\"});e.setStyles({position:\"absolute\",width:\"1px\",height:\"1px\",\noverflow:\"hidden\"});e.setStyle(\"ltr\"==c.config.contentsLangDirection?\"left\":\"right\",\"-5000px\");var h=c.createRange();h.setStartBefore(a.wrapper);h.setEndAfter(a.wrapper);e.setHtml('\\x3cspan data-cke-copybin-start\\x3d\"1\"\\x3e​\\x3c/span\\x3e'+c.editable().getHtmlFromRange(h).getHtml()+'\\x3cspan data-cke-copybin-end\\x3d\"1\"\\x3e​\\x3c/span\\x3e');c.fire(\"saveSnapshot\");c.fire(\"lockSnapshot\");g.append(e);c.editable().append(g);var k=c.on(\"selectionChange\",J,null,null,0),l=a.repository.on(\"checkSelection\",J,\nnull,null,0);if(f)var m=d.getDocumentElement().$,n=m.scrollTop;h=c.createRange();h.selectNodeContents(e);h.select();f&&(m.scrollTop=n);setTimeout(function(){b||a.focus();g.remove();k.removeListener();l.removeListener();c.fire(\"unlockSnapshot\");b&&!c.readOnly&&(a.repository.del(a),c.fire(\"saveSnapshot\"))},100)}}function L(a){return(a=(a=a.getDefinition().attributes)&&a[\"class\"])?a.split(/\\s+/):null}function G(){var a=CKEDITOR.document.getActive(),b=this.editor,c=b.editable();(c.isInline()?c:b.document.getWindow().getFrame()).equals(a)&&\nb.focusManager.focus(c)}function D(){CKEDITOR.env.gecko&&this.editor.unlockSelection();CKEDITOR.env.webkit||(this.editor.forceNextSelectionCheck(),this.editor.selectionChange(1))}function N(a){var b=null;a.on(\"data\",function(){var a=this.data.classes,c;if(b!=a){for(c in b)a&&a[c]||this.removeClass(c);for(c in a)this.addClass(c);b=a}})}function Q(a){a.on(\"data\",function(){if(a.wrapper){var b=this.getLabel?this.getLabel():this.editor.lang.widget.label.replace(/%1/,this.pathName||this.element.getName());\na.wrapper.setAttribute(\"role\",\"region\");a.wrapper.setAttribute(\"aria-label\",b)}},null,null,9999)}function O(a){if(a.draggable){var b=a.editor,c=a.wrapper.getLast(f.isDomDragHandlerContainer),d;c?d=c.findOne(\"img\"):(c=new CKEDITOR.dom.element(\"span\",b.document),c.setAttributes({\"class\":\"cke_reset cke_widget_drag_handler_container\",style:\"background:rgba(220,220,220,0.5);background-image:url(\"+b.plugins.widget.path+\"images/handle.png)\"}),d=new CKEDITOR.dom.element(\"img\",b.document),d.setAttributes({\"class\":\"cke_reset cke_widget_drag_handler\",\n\"data-cke-widget-drag-handler\":\"1\",src:CKEDITOR.tools.transparentImageData,width:15,title:b.lang.widget.move,height:15,role:\"presentation\"}),a.inline&&d.setAttribute(\"draggable\",\"true\"),c.append(d),a.wrapper.append(c));a.wrapper.on(\"dragover\",function(a){a.data.preventDefault()});a.wrapper.on(\"mouseenter\",a.updateDragHandlerPosition,a);setTimeout(function(){a.on(\"data\",a.updateDragHandlerPosition,a)},50);if(!a.inline&&(d.on(\"mousedown\",K,a),CKEDITOR.env.ie&&9>CKEDITOR.env.version))d.on(\"dragstart\",\nfunction(a){a.data.preventDefault(!0)});a.dragHandlerContainer=c}}function K(a){function b(){var c;for(p.reset();c=h.pop();)c.removeListener();var d=k;c=a.sender;var e=this.repository.finder,f=this.repository.liner,g=this.editor,l=this.editor.editable();CKEDITOR.tools.isEmpty(f.visible)||(d=e.getRange(d[0]),this.focus(),g.fire(\"drop\",{dropRange:d,target:d.startContainer}));l.removeClass(\"cke_widget_dragging\");f.hideVisible();g.fire(\"dragend\",{target:c})}if(CKEDITOR.tools.getMouseButton(a)===CKEDITOR.MOUSE_BUTTON_LEFT){var c=\nthis.repository.finder,d=this.repository.locator,e=this.repository.liner,f=this.editor,g=f.editable(),h=[],k=[],l,m;this.repository._.draggedWidget=this;var n=c.greedySearch(),p=CKEDITOR.tools.eventsBuffer(50,function(){l=d.locate(n);k=d.sort(m,1);k.length&&(e.prepare(n,l),e.placeLine(k[0]),e.cleanup())});g.addClass(\"cke_widget_dragging\");h.push(g.on(\"mousemove\",function(a){m=a.data.$.clientY;p.input()}));f.fire(\"dragstart\",{target:a.sender});h.push(f.document.once(\"mouseup\",b,this));g.isInline()||\nh.push(CKEDITOR.document.once(\"mouseup\",b,this))}}function W(a){var b,c,d=a.editables;a.editables={};if(a.editables)for(b in d)c=d[b],a.initEditable(b,\"string\"==typeof c?{selector:c}:c)}function R(a){if(a.mask){var b=a.wrapper.findOne(\".cke_widget_mask\");b||(b=new CKEDITOR.dom.element(\"img\",a.editor.document),b.setAttributes({src:CKEDITOR.tools.transparentImageData,\"class\":\"cke_reset cke_widget_mask\"}),a.wrapper.append(b));a.mask=b}}function Z(a){if(a.parts){var b={},c,d;for(d in a.parts)c=a.wrapper.findOne(a.parts[d]),\nb[d]=c;a.parts=b}}function ha(a,b){X(a);Z(a);W(a);R(a);O(a);N(a);Q(a);if(CKEDITOR.env.ie&&9>CKEDITOR.env.version)a.wrapper.on(\"dragstart\",function(b){var c=b.data.getTarget();f.getNestedEditable(a,c)||a.inline&&f.isDomDragHandler(c)||b.data.preventDefault()});a.wrapper.removeClass(\"cke_widget_new\");a.element.addClass(\"cke_widget_element\");a.on(\"key\",function(b){b=b.data.keyCode;if(13==b)a.edit();else{if(b==CKEDITOR.CTRL+67||b==CKEDITOR.CTRL+88){E(a,b==CKEDITOR.CTRL+88);return}if(b in V||CKEDITOR.CTRL&\nb||CKEDITOR.ALT&b)return}return!1},null,null,999);a.on(\"doubleclick\",function(b){a.edit()&&b.cancel()});if(b.data)a.on(\"data\",b.data);if(b.edit)a.on(\"edit\",b.edit)}function X(a){(a.wrapper=a.element.getParent()).setAttribute(\"data-cke-widget-id\",a.id)}function U(a){a.element.data(\"cke-widget-data\",encodeURIComponent(JSON.stringify(a.data)))}function ba(){function a(){}function b(a,c,d){return d&&this.checkElement(a)?(a=d.widgets.getByElement(a,!0))&&a.checkStyleActive(this):!1}function c(a){function b(a,\nc,d){for(var e=a.length,f=0;f<e;){if(c.call(d,a[f],f,a))return a[f];f++}}function e(a){function b(a,c){var d=CKEDITOR.tools.object.keys(a),e=CKEDITOR.tools.object.keys(c);if(d.length!==e.length)return!1;for(var f in a)if((\"object\"!==typeof a[f]||\"object\"!==typeof c[f]||!b(a[f],c[f]))&&a[f]!==c[f])return!1;return!0}return function(c){return b(a.getDefinition(),c.getDefinition())}}var f=a.widget,g;d[f]||(d[f]={});for(var h=0,k=a.group.length;h<k;h++)g=a.group[h],d[f][g]||(d[f][g]=[]),g=d[f][g],b(g,\ne(a))||g.push(a)}var d={};CKEDITOR.style.addCustomHandler({type:\"widget\",setup:function(a){this.widget=a.widget;(this.group=\"string\"==typeof a.group?[a.group]:a.group)&&c(this)},apply:function(a){var b;a instanceof CKEDITOR.editor&&this.checkApplicable(a.elementPath(),a)&&(b=a.widgets.focused,this.group&&this.removeStylesFromSameGroup(a),b.applyStyle(this))},remove:function(a){a instanceof CKEDITOR.editor&&this.checkApplicable(a.elementPath(),a)&&a.widgets.focused.removeStyle(this)},removeStylesFromSameGroup:function(a){var b,\nc,e=!1;if(!(a instanceof CKEDITOR.editor))return!1;c=a.elementPath();if(this.checkApplicable(c,a))for(var f=0,g=this.group.length;f<g;f++){b=d[this.widget][this.group[f]];for(var h=0;h<b.length;h++)b[h]!==this&&b[h].checkActive(c,a)&&(a.widgets.focused.removeStyle(b[h]),e=!0)}return e},checkActive:function(a,b){return this.checkElementMatch(a.lastElement,0,b)},checkApplicable:function(a,b){return b instanceof CKEDITOR.editor?this.checkElement(a.lastElement):!1},checkElementMatch:b,checkElementRemovable:b,\ncheckElement:function(a){return f.isDomWidgetWrapper(a)?(a=a.getFirst(f.isDomWidgetElement))&&a.data(\"widget\")==this.widget:!1},buildPreview:function(a){return a||this._.definition.name},toAllowedContentRules:function(a){if(!a)return null;a=a.widgets.registered[this.widget];var b,c={};if(!a)return null;if(a.styleableElements){b=this.getClassesArray();if(!b)return null;c[a.styleableElements]={classes:b,propertiesOnly:!0};return c}return a.styleToAllowedContentRules?a.styleToAllowedContentRules(this):\nnull},getClassesArray:function(){var a=this._.definition.attributes&&this._.definition.attributes[\"class\"];return a?CKEDITOR.tools.trim(a).split(/\\s+/):null},applyToRange:a,removeFromRange:a,applyToObject:a})}CKEDITOR.plugins.add(\"widget\",{requires:\"lineutils,clipboard,widgetselection\",onLoad:function(){void 0!==CKEDITOR.document.$.querySelectorAll&&(CKEDITOR.addCss(\".cke_widget_wrapper{position:relative;outline:none}.cke_widget_inline{display:inline-block}.cke_widget_wrapper:hover\\x3e.cke_widget_element{outline:2px solid #ffd25c;cursor:default}.cke_widget_wrapper:hover .cke_widget_editable{outline:2px solid #ffd25c}.cke_widget_wrapper.cke_widget_focused\\x3e.cke_widget_element,.cke_widget_wrapper .cke_widget_editable.cke_widget_editable_focused{outline:2px solid #47a4f5}.cke_widget_editable{cursor:text}.cke_widget_drag_handler_container{position:absolute;width:15px;height:0;display:none;opacity:0.75;transition:height 0s 0.2s;line-height:0}.cke_widget_wrapper:hover\\x3e.cke_widget_drag_handler_container{height:15px;transition:none}.cke_widget_drag_handler_container:hover{opacity:1}img.cke_widget_drag_handler{cursor:move;width:15px;height:15px;display:inline-block}.cke_widget_mask{position:absolute;top:0;left:0;width:100%;height:100%;display:block}.cke_editable.cke_widget_dragging, .cke_editable.cke_widget_dragging *{cursor:move !important}\"),\nba())},beforeInit:function(b){void 0!==CKEDITOR.document.$.querySelectorAll&&(b.widgets=new a(b))},afterInit:function(a){if(void 0!==CKEDITOR.document.$.querySelectorAll){var b=a.widgets.registered,c,d,e;for(d in b)c=b[d],(e=c.button)&&a.ui.addButton&&a.ui.addButton(CKEDITOR.tools.capitalize(c.name,!0),{label:e,command:c.name,toolbar:\"insert,10\"});w(a)}}});a.prototype={MIN_SELECTION_CHECK_INTERVAL:500,add:function(a,b){b=CKEDITOR.tools.prototypedCopy(b);b.name=a;b._=b._||{};this.editor.fire(\"widgetDefinition\",\nb);b.template&&(b.template=new CKEDITOR.template(b.template));c(this.editor,b);d(this,b);return this.registered[a]=b},addUpcastCallback:function(a){this._.upcastCallbacks.push(a)},checkSelection:function(){var a=this.editor.getSelection(),b=a.getSelectedElement(),c=F(this),d;if(b&&(d=this.getByElement(b,!0)))return c.focus(d).select(d).commit();a=a.getRanges()[0];if(!a||a.collapsed)return c.commit();a=new CKEDITOR.dom.walker(a);for(a.evaluator=f.isDomWidgetWrapper;b=a.next();)c.select(this.getByElement(b));\nc.commit()},checkWidgets:function(a){this.fire(\"checkWidgets\",CKEDITOR.tools.copy(a||{}))},del:function(a){if(this.focused===a){var b=a.editor,c=b.createRange(),d;(d=c.moveToClosestEditablePosition(a.wrapper,!0))||(d=c.moveToClosestEditablePosition(a.wrapper,!1));d&&b.getSelection().selectRanges([c])}a.wrapper.remove();this.destroy(a,!0)},destroy:function(a,b){this.widgetHoldingFocusedEditable===a&&v(this,a,null,b);a.destroy(b);delete this.instances[a.id];this.fire(\"instanceDestroyed\",a)},destroyAll:function(a,\nb){var c,d,e=this.instances;if(b&&!a){d=b.find(\".cke_widget_wrapper\");for(var e=d.count(),f=0;f<e;++f)(c=this.getByElement(d.getItem(f),!0))&&this.destroy(c)}else for(d in e)c=e[d],this.destroy(c,a)},finalizeCreation:function(a){(a=a.getFirst())&&f.isDomWidgetWrapper(a)&&(this.editor.insertElement(a),a=this.getByElement(a),a.ready=!0,a.fire(\"ready\"),a.focus())},getByElement:function(){function a(c){return c.is(b)&&c.data(\"cke-widget-id\")}var b={div:1,span:1};return function(b,c){if(!b)return null;\nvar d=a(b);if(!c&&!d){var e=this.editor.editable();do b=b.getParent();while(b&&!b.equals(e)&&!(d=a(b)))}return this.instances[d]||null}}(),initOn:function(a,b,c){b?\"string\"==typeof b&&(b=this.registered[b]):b=this.registered[a.data(\"widget\")];if(!b)return null;var d=this.wrapElement(a,b.name);return d?d.hasClass(\"cke_widget_new\")?(a=new f(this,this._.nextId++,a,b,c),a.isInited()?this.instances[a.id]=a:null):this.getByElement(a):null},initOnAll:function(a){a=(a||this.editor.editable()).find(\".cke_widget_new\");\nfor(var b=[],c,d=a.count();d--;)(c=this.initOn(a.getItem(d).getFirst(f.isDomWidgetElement)))&&b.push(c);return b},onWidget:function(a){var b=Array.prototype.slice.call(arguments);b.shift();for(var c in this.instances){var d=this.instances[c];d.name==a&&d.on.apply(d,b)}this.on(\"instanceCreated\",function(c){c=c.data;c.name==a&&c.on.apply(c,b)})},parseElementClasses:function(a){if(!a)return null;a=CKEDITOR.tools.trim(a).split(/\\s+/);for(var b,c={},d=0;b=a.pop();)-1==b.indexOf(\"cke_\")&&(c[b]=d=1);return d?\nc:null},wrapElement:function(a,b){var c=null,d,e;if(a instanceof CKEDITOR.dom.element){b=b||a.data(\"widget\");d=this.registered[b];if(!d)return null;if((c=a.getParent())&&c.type==CKEDITOR.NODE_ELEMENT&&c.data(\"cke-widget-wrapper\"))return c;a.hasAttribute(\"data-cke-widget-keep-attr\")||a.data(\"cke-widget-keep-attr\",a.data(\"widget\")?1:0);a.data(\"widget\",b);(e=u(d,a.getName()))&&g(a);c=new CKEDITOR.dom.element(e?\"span\":\"div\");c.setAttributes(q(e,b));c.data(\"cke-display-name\",d.pathName?d.pathName:a.getName());\na.getParent(!0)&&c.replace(a);a.appendTo(c)}else if(a instanceof CKEDITOR.htmlParser.element){b=b||a.attributes[\"data-widget\"];d=this.registered[b];if(!d)return null;if((c=a.parent)&&c.type==CKEDITOR.NODE_ELEMENT&&c.attributes[\"data-cke-widget-wrapper\"])return c;\"data-cke-widget-keep-attr\"in a.attributes||(a.attributes[\"data-cke-widget-keep-attr\"]=a.attributes[\"data-widget\"]?1:0);b&&(a.attributes[\"data-widget\"]=b);(e=u(d,a.name))&&g(a);c=new CKEDITOR.htmlParser.element(e?\"span\":\"div\",q(e,b));c.attributes[\"data-cke-display-name\"]=\nd.pathName?d.pathName:a.name;d=a.parent;var f;d&&(f=a.getIndex(),a.remove());c.add(a);d&&y(d,f,c)}return c},_tests_createEditableFilter:e};CKEDITOR.event.implementOn(a.prototype);f.prototype={addClass:function(a){this.element.addClass(a);this.wrapper.addClass(f.WRAPPER_CLASS_PREFIX+a)},applyStyle:function(a){I(this,a,1)},checkStyleActive:function(a){a=L(a);var b;if(!a)return!1;for(;b=a.pop();)if(!this.hasClass(b))return!1;return!0},destroy:function(a){this.fire(\"destroy\");if(this.editables)for(var b in this.editables)this.destroyEditable(b,\na);a||(\"0\"==this.element.data(\"cke-widget-keep-attr\")&&this.element.removeAttribute(\"data-widget\"),this.element.removeAttributes([\"data-cke-widget-data\",\"data-cke-widget-keep-attr\"]),this.element.removeClass(\"cke_widget_element\"),this.element.replace(this.wrapper));this.wrapper=null},destroyEditable:function(a,b){var c=this.editables[a],d=!0;c.removeListener(\"focus\",D);c.removeListener(\"blur\",G);this.editor.focusManager.remove(c);if(c.filter){for(var e in this.repository.instances){var f=this.repository.instances[e];\nf.editables&&(f=f.editables[a])&&f!==c&&c.filter===f.filter&&(d=!1)}d&&(c.filter.destroy(),(d=this.repository._.filters[this.name])&&delete d[a])}b||(this.repository.destroyAll(!1,c),c.removeClass(\"cke_widget_editable\"),c.removeClass(\"cke_widget_editable_focused\"),c.removeAttributes([\"contenteditable\",\"data-cke-widget-editable\",\"data-cke-enter-mode\"]));delete this.editables[a]},edit:function(){var a={dialog:this.dialog},b=this;if(!1===this.fire(\"edit\",a)||!a.dialog)return!1;this.editor.openDialog(a.dialog,\nfunction(a){var c,d;!1!==b.fire(\"dialog\",a)&&(c=a.on(\"show\",function(){a.setupContent(b)}),d=a.on(\"ok\",function(){var c,d=b.on(\"data\",function(a){c=1;a.cancel()},null,null,0);b.editor.fire(\"saveSnapshot\");a.commitContent(b);d.removeListener();c&&(b.fire(\"data\",b.data),b.editor.fire(\"saveSnapshot\"))}),a.once(\"hide\",function(){c.removeListener();d.removeListener()}))});return!0},getClasses:function(){return this.repository.parseElementClasses(this.element.getAttribute(\"class\"))},hasClass:function(a){return this.element.hasClass(a)},\ninitEditable:function(a,c){var d=this._findOneNotNested(c.selector);return d&&d.is(CKEDITOR.dtd.$editable)?(d=new b(this.editor,d,{filter:e.call(this.repository,this.name,a,c)}),this.editables[a]=d,d.setAttributes({contenteditable:\"true\",\"data-cke-widget-editable\":a,\"data-cke-enter-mode\":d.enterMode}),d.filter&&d.data(\"cke-filter\",d.filter.id),d.addClass(\"cke_widget_editable\"),d.removeClass(\"cke_widget_editable_focused\"),c.pathName&&d.data(\"cke-display-name\",c.pathName),this.editor.focusManager.add(d),\nd.on(\"focus\",D,this),CKEDITOR.env.ie&&d.on(\"blur\",G,this),d._.initialSetData=!0,d.setData(d.getHtml()),!0):!1},_findOneNotNested:function(a){a=this.wrapper.find(a);for(var b,c,d=0;d<a.count();d++)if(b=a.getItem(d),c=b.getAscendant(f.isDomWidgetWrapper),this.wrapper.equals(c))return b;return null},isInited:function(){return!(!this.wrapper||!this.inited)},isReady:function(){return this.isInited()&&this.ready},focus:function(){var a=this.editor.getSelection();if(a){var b=this.editor.checkDirty();a.fake(this.wrapper);\n!b&&this.editor.resetDirty()}this.editor.focus()},removeClass:function(a){this.element.removeClass(a);this.wrapper.removeClass(f.WRAPPER_CLASS_PREFIX+a)},removeStyle:function(a){I(this,a,0)},setData:function(a,b){var c=this.data,d=0;if(\"string\"==typeof a)c[a]!==b&&(c[a]=b,d=1);else{var e=a;for(a in e)c[a]!==e[a]&&(d=1,c[a]=e[a])}d&&this.dataReady&&(U(this),this.fire(\"data\",c));return this},setFocused:function(a){this.wrapper[a?\"addClass\":\"removeClass\"](\"cke_widget_focused\");this.fire(a?\"focus\":\"blur\");\nreturn this},setSelected:function(a){this.wrapper[a?\"addClass\":\"removeClass\"](\"cke_widget_selected\");this.fire(a?\"select\":\"deselect\");return this},updateDragHandlerPosition:function(){var a=this.editor,b=this.element.$,c=this._.dragHandlerOffset,b={x:b.offsetLeft,y:b.offsetTop-15};c&&b.x==c.x&&b.y==c.y||(c=a.checkDirty(),a.fire(\"lockSnapshot\"),this.dragHandlerContainer.setStyles({top:b.y+\"px\",left:b.x+\"px\",display:\"block\"}),a.fire(\"unlockSnapshot\"),!c&&a.resetDirty(),this._.dragHandlerOffset=b)}};\nCKEDITOR.event.implementOn(f.prototype);f.getNestedEditable=function(a,b){return!b||b.equals(a)?null:f.isDomNestedEditable(b)?b:f.getNestedEditable(a,b.getParent())};f.isDomDragHandler=function(a){return a.type==CKEDITOR.NODE_ELEMENT&&a.hasAttribute(\"data-cke-widget-drag-handler\")};f.isDomDragHandlerContainer=function(a){return a.type==CKEDITOR.NODE_ELEMENT&&a.hasClass(\"cke_widget_drag_handler_container\")};f.isDomNestedEditable=function(a){return a.type==CKEDITOR.NODE_ELEMENT&&a.hasAttribute(\"data-cke-widget-editable\")};\nf.isDomWidgetElement=function(a){return a.type==CKEDITOR.NODE_ELEMENT&&a.hasAttribute(\"data-widget\")};f.isDomWidgetWrapper=function(a){return a.type==CKEDITOR.NODE_ELEMENT&&a.hasAttribute(\"data-cke-widget-wrapper\")};f.isDomWidget=function(a){return a?this.isDomWidgetWrapper(a)||this.isDomWidgetElement(a):!1};f.isParserWidgetElement=function(a){return a.type==CKEDITOR.NODE_ELEMENT&&!!a.attributes[\"data-widget\"]};f.isParserWidgetWrapper=function(a){return a.type==CKEDITOR.NODE_ELEMENT&&!!a.attributes[\"data-cke-widget-wrapper\"]};\nf.WRAPPER_CLASS_PREFIX=\"cke_widget_wrapper_\";b.prototype=CKEDITOR.tools.extend(CKEDITOR.tools.prototypedCopy(CKEDITOR.dom.element.prototype),{setData:function(a){this._.initialSetData||this.editor.widgets.destroyAll(!1,this);this._.initialSetData=!1;a=this.editor.dataProcessor.toHtml(a,{context:this.getName(),filter:this.filter,enterMode:this.enterMode});this.setHtml(a);this.editor.widgets.initOnAll(this)},getData:function(){return this.editor.dataProcessor.toDataFormat(this.getHtml(),{context:this.getName(),\nfilter:this.filter,enterMode:this.enterMode})}});var ca=/^(?:<(?:div|span)(?: data-cke-temp=\"1\")?(?: id=\"cke_copybin\")?(?: data-cke-temp=\"1\")?>)?(?:<(?:div|span)(?: style=\"[^\"]+\")?>)?<span [^>]*data-cke-copybin-start=\"1\"[^>]*>.?<\\/span>([\\s\\S]+)<span [^>]*data-cke-copybin-end=\"1\"[^>]*>.?<\\/span>(?:<\\/(?:div|span)>)?(?:<\\/(?:div|span)>)?$/i,V={37:1,38:1,39:1,40:1,8:1,46:1};V[CKEDITOR.SHIFT+121]=1;CKEDITOR.plugins.widget=f;f.repository=a;f.nestedEditable=b}(),function(){function a(a,c,d){this.editor=\na;this.notification=null;this._message=new CKEDITOR.template(c);this._singularMessage=d?new CKEDITOR.template(d):null;this._tasks=[];this._doneTasks=this._doneWeights=this._totalWeights=0}function f(a){this._weight=a||1;this._doneWeight=0;this._isCanceled=!1}CKEDITOR.plugins.add(\"notificationaggregator\",{requires:\"notification\"});a.prototype={createTask:function(a){a=a||{};var c=!this.notification,d;c&&(this.notification=this._createNotification());d=this._addTask(a);d.on(\"updated\",this._onTaskUpdate,\nthis);d.on(\"done\",this._onTaskDone,this);d.on(\"canceled\",function(){this._removeTask(d)},this);this.update();c&&this.notification.show();return d},update:function(){this._updateNotification();this.isFinished()&&this.fire(\"finished\")},getPercentage:function(){return 0===this.getTaskCount()?1:this._doneWeights/this._totalWeights},isFinished:function(){return this.getDoneTaskCount()===this.getTaskCount()},getTaskCount:function(){return this._tasks.length},getDoneTaskCount:function(){return this._doneTasks},\n_updateNotification:function(){this.notification.update({message:this._getNotificationMessage(),progress:this.getPercentage()})},_getNotificationMessage:function(){var a=this.getTaskCount(),c={current:this.getDoneTaskCount(),max:a,percentage:Math.round(100*this.getPercentage())};return(1==a&&this._singularMessage?this._singularMessage:this._message).output(c)},_createNotification:function(){return new CKEDITOR.plugins.notification(this.editor,{type:\"progress\"})},_addTask:function(a){a=new f(a.weight);\nthis._tasks.push(a);this._totalWeights+=a._weight;return a},_removeTask:function(a){var c=CKEDITOR.tools.indexOf(this._tasks,a);-1!==c&&(a._doneWeight&&(this._doneWeights-=a._doneWeight),this._totalWeights-=a._weight,this._tasks.splice(c,1),this.update())},_onTaskUpdate:function(a){this._doneWeights+=a.data;this.update()},_onTaskDone:function(){this._doneTasks+=1;this.update()}};CKEDITOR.event.implementOn(a.prototype);f.prototype={done:function(){this.update(this._weight)},update:function(a){if(!this.isDone()&&\n!this.isCanceled()){a=Math.min(this._weight,a);var c=a-this._doneWeight;this._doneWeight=a;this.fire(\"updated\",c);this.isDone()&&this.fire(\"done\")}},cancel:function(){this.isDone()||this.isCanceled()||(this._isCanceled=!0,this.fire(\"canceled\"))},isDone:function(){return this._weight===this._doneWeight},isCanceled:function(){return this._isCanceled}};CKEDITOR.event.implementOn(f.prototype);CKEDITOR.plugins.notificationAggregator=a;CKEDITOR.plugins.notificationAggregator.task=f}(),\"use strict\",function(){CKEDITOR.plugins.add(\"uploadwidget\",\n{requires:\"widget,clipboard,filetools,notificationaggregator\",init:function(a){a.filter.allow(\"*[!data-widget,!data-cke-upload-id]\")},isSupportedEnvironment:function(){return CKEDITOR.plugins.clipboard.isFileApiSupported}});CKEDITOR.fileTools||(CKEDITOR.fileTools={});CKEDITOR.tools.extend(CKEDITOR.fileTools,{addUploadWidget:function(a,f,b){var c=CKEDITOR.fileTools,d=a.uploadRepository,l=b.supportedTypes?10:20;if(b.fileToElement)a.on(\"paste\",function(b){b=b.data;var g=a.widgets.registered[f],h=b.dataTransfer,\nl=h.getFilesCount(),e=g.loadMethod||\"loadAndUpload\",n,q;if(!b.dataValue&&l)for(q=0;q<l;q++)if(n=h.getFile(q),!g.supportedTypes||c.isTypeSupported(n,g.supportedTypes)){var y=g.fileToElement(n);n=d.create(n,void 0,g.loaderType);y&&(n[e](g.uploadUrl,g.additionalRequestParameters),CKEDITOR.fileTools.markElement(y,f,n.id),\"loadAndUpload\"!=e&&\"upload\"!=e||g.skipNotifications||CKEDITOR.fileTools.bindNotifications(a,n),b.dataValue+=y.getOuterHtml())}},null,null,l);CKEDITOR.tools.extend(b,{downcast:function(){return new CKEDITOR.htmlParser.text(\"\")},\ninit:function(){var b=this,c=this.wrapper.findOne(\"[data-cke-upload-id]\").data(\"cke-upload-id\"),f=d.loaders[c],l=CKEDITOR.tools.capitalize,e,n;f.on(\"update\",function(d){if(\"abort\"===f.status&&\"function\"===typeof b.onAbort)b.onAbort(f);if(b.wrapper&&b.wrapper.getParent()){a.fire(\"lockSnapshot\");d=\"on\"+l(f.status);if(\"abort\"===f.status||\"function\"!==typeof b[d]||!1!==b[d](f))n=\"cke_upload_\"+f.status,b.wrapper&&n!=e&&(e&&b.wrapper.removeClass(e),b.wrapper.addClass(n),e=n),\"error\"!=f.status&&\"abort\"!=\nf.status||a.widgets.del(b);a.fire(\"unlockSnapshot\")}else CKEDITOR.instances[a.name]&&a.editable().find('[data-cke-upload-id\\x3d\"'+c+'\"]').count()||f.abort(),d.removeListener()});f.update()},replaceWith:function(b,c){if(\"\"===b.trim())a.widgets.del(this);else{var d=this==a.widgets.focused,f=a.editable(),e=a.createRange(),l,q;d||(q=a.getSelection().createBookmarks());e.setStartBefore(this.wrapper);e.setEndAfter(this.wrapper);d&&(l=e.createBookmark());f.insertHtmlIntoRange(b,e,c);a.widgets.checkWidgets({initOnlyNew:!0});\na.widgets.destroy(this,!0);d?(e.moveToBookmark(l),e.select()):a.getSelection().selectBookmarks(q)}},_getLoader:function(){var a=this.wrapper.findOne(\"[data-cke-upload-id]\");return a?this.editor.uploadRepository.loaders[a.data(\"cke-upload-id\")]:null}});a.widgets.add(f,b)},markElement:function(a,f,b){a.setAttributes({\"data-cke-upload-id\":b,\"data-widget\":f})},bindNotifications:function(a,f){function b(){c=a._.uploadWidgetNotificaionAggregator;if(!c||c.isFinished())c=a._.uploadWidgetNotificaionAggregator=\nnew CKEDITOR.plugins.notificationAggregator(a,a.lang.uploadwidget.uploadMany,a.lang.uploadwidget.uploadOne),c.once(\"finished\",function(){var b=c.getTaskCount();0===b?c.notification.hide():c.notification.update({message:1==b?a.lang.uploadwidget.doneOne:a.lang.uploadwidget.doneMany.replace(\"%1\",b),type:\"success\",important:1})})}var c,d=null;f.on(\"update\",function(){!d&&f.uploadTotal&&(b(),d=c.createTask({weight:f.uploadTotal}));d&&\"uploading\"==f.status&&d.update(f.uploaded)});f.on(\"uploaded\",function(){d&&\nd.done()});f.on(\"error\",function(){d&&d.cancel();a.showNotification(f.message,\"warning\")});f.on(\"abort\",function(){d&&d.cancel();CKEDITOR.instances[a.name]&&a.showNotification(a.lang.uploadwidget.abort,\"info\")})}})}(),\"use strict\",function(){function a(a){9>=a&&(a=\"0\"+a);return String(a)}function f(c){var d=new Date,d=[d.getFullYear(),d.getMonth()+1,d.getDate(),d.getHours(),d.getMinutes(),d.getSeconds()];b+=1;return\"image-\"+CKEDITOR.tools.array.map(d,a).join(\"\")+\"-\"+b+\".\"+c}var b=0;CKEDITOR.plugins.add(\"uploadimage\",\n{requires:\"uploadwidget\",onLoad:function(){CKEDITOR.addCss(\".cke_upload_uploading img{opacity: 0.3}\")},isSupportedEnvironment:function(){return CKEDITOR.plugins.clipboard.isFileApiSupported},init:function(a){if(this.isSupportedEnvironment()){var b=CKEDITOR.fileTools,l=b.getUploadUrl(a.config,\"image\");l&&(b.addUploadWidget(a,\"uploadimage\",{supportedTypes:/image\\/(jpeg|png|gif|bmp)/,uploadUrl:l,fileToElement:function(){var a=new CKEDITOR.dom.element(\"img\");a.setAttribute(\"src\",\"data:image/gif;base64,R0lGODlhDgAOAIAAAAAAAP///yH5BAAAAAAALAAAAAAOAA4AAAIMhI+py+0Po5y02qsKADs\\x3d\");\nreturn a},parts:{img:\"img\"},onUploading:function(a){this.parts.img.setAttribute(\"src\",a.data)},onUploaded:function(a){var b=this.parts.img.$;this.replaceWith('\\x3cimg src\\x3d\"'+a.url+'\" width\\x3d\"'+(a.responseData.width||b.naturalWidth)+'\" height\\x3d\"'+(a.responseData.height||b.naturalHeight)+'\"\\x3e')}}),a.on(\"paste\",function(k){if(k.data.dataValue.match(/<img[\\s\\S]+data:/i)){k=k.data;var g=document.implementation.createHTMLDocument(\"\"),g=new CKEDITOR.dom.element(g.body),h,m,e;g.data(\"cke-editable\",\n1);g.appendHtml(k.dataValue);h=g.find(\"img\");for(e=0;e<h.count();e++){m=h.getItem(e);var n=m.getAttribute(\"src\"),q=n&&\"data:\"==n.substring(0,5),y=null===m.data(\"cke-realelement\");q&&y&&!m.data(\"cke-upload-id\")&&!m.isReadOnly(1)&&(q=(q=n.match(/image\\/([a-z]+?);/i))&&q[1]||\"jpg\",n=a.uploadRepository.create(n,f(q)),n.upload(l),b.markElement(m,\"uploadimage\",n.id),b.bindNotifications(a,n))}k.dataValue=g.getHtml()}}))}}})}(),CKEDITOR.plugins.add(\"wsc\",{requires:\"dialog\",parseApi:function(a){a.config.wsc_onFinish=\n\"function\"===typeof a.config.wsc_onFinish?a.config.wsc_onFinish:function(){};a.config.wsc_onClose=\"function\"===typeof a.config.wsc_onClose?a.config.wsc_onClose:function(){}},parseConfig:function(a){a.config.wsc_customerId=a.config.wsc_customerId||CKEDITOR.config.wsc_customerId||\"1:ua3xw1-2XyGJ3-GWruD3-6OFNT1-oXcuB1-nR6Bp4-hgQHc-EcYng3-sdRXG3-NOfFk\";a.config.wsc_customDictionaryIds=a.config.wsc_customDictionaryIds||CKEDITOR.config.wsc_customDictionaryIds||\"\";a.config.wsc_userDictionaryName=a.config.wsc_userDictionaryName||\nCKEDITOR.config.wsc_userDictionaryName||\"\";a.config.wsc_customLoaderScript=a.config.wsc_customLoaderScript||CKEDITOR.config.wsc_customLoaderScript;a.config.wsc_interfaceLang=a.config.wsc_interfaceLang;CKEDITOR.config.wsc_cmd=a.config.wsc_cmd||CKEDITOR.config.wsc_cmd||\"spell\";CKEDITOR.config.wsc_version=\"v4.3.0-master-d769233\";CKEDITOR.config.wsc_removeGlobalVariable=!0},onLoad:function(a){\"moono-lisa\"==(CKEDITOR.skinName||a.config.skin)&&CKEDITOR.document.appendStyleSheet(CKEDITOR.getUrl(this.path+\n\"skins/\"+CKEDITOR.skin.name+\"/wsc.css\"))},init:function(a){var f=CKEDITOR.env;this.parseConfig(a);this.parseApi(a);a.addCommand(\"checkspell\",new CKEDITOR.dialogCommand(\"checkspell\")).modes={wysiwyg:!CKEDITOR.env.opera&&!CKEDITOR.env.air&&document.domain==window.location.hostname&&!(f.ie&&(8>f.version||f.quirks))};\"undefined\"==typeof a.plugins.scayt&&a.ui.addButton&&a.ui.addButton(\"SpellChecker\",{label:a.lang.wsc.toolbar,click:function(a){var c=a.elementMode==CKEDITOR.ELEMENT_MODE_INLINE?a.container.getText():\na.document.getBody().getText();(c=c.replace(/\\s/g,\"\"))?a.execCommand(\"checkspell\"):alert(\"Nothing to check!\")},toolbar:\"spellchecker,10\"});CKEDITOR.dialog.add(\"checkspell\",this.path+(CKEDITOR.env.ie&&7>=CKEDITOR.env.version?\"dialogs/wsc_ie.js\":window.postMessage?\"dialogs/wsc.js\":\"dialogs/wsc_ie.js\"))}}),function(){function a(a){function b(a){var c=!1;e.attachListener(e,\"keydown\",function(){var b=g.getBody().getElementsByTag(a);if(!c){for(var d=0;d<b.count();d++)b.getItem(d).setCustomData(\"retain\",\n!0);c=!0}},null,null,1);e.attachListener(e,\"keyup\",function(){var b=g.getElementsByTag(a);c&&(1==b.count()&&!b.getItem(0).getCustomData(\"retain\")&&CKEDITOR.tools.isEmpty(b.getItem(0).getAttributes())&&b.getItem(0).remove(1),c=!1)})}var c=this.editor,g=a.document,h=g.body,m=g.getElementById(\"cke_actscrpt\");m&&m.parentNode.removeChild(m);(m=g.getElementById(\"cke_shimscrpt\"))&&m.parentNode.removeChild(m);(m=g.getElementById(\"cke_basetagscrpt\"))&&m.parentNode.removeChild(m);h.contentEditable=!0;CKEDITOR.env.ie&&\n(h.hideFocus=!0,h.disabled=!0,h.removeAttribute(\"disabled\"));delete this._.isLoadingData;this.$=h;g=new CKEDITOR.dom.document(g);this.setup();this.fixInitialSelection();var e=this;CKEDITOR.env.ie&&!CKEDITOR.env.edge&&g.getDocumentElement().addClass(g.$.compatMode);CKEDITOR.env.ie&&!CKEDITOR.env.edge&&c.enterMode!=CKEDITOR.ENTER_P?b(\"p\"):CKEDITOR.env.edge&&15>CKEDITOR.env.version&&c.enterMode!=CKEDITOR.ENTER_DIV&&b(\"div\");if(CKEDITOR.env.webkit||CKEDITOR.env.ie&&10<CKEDITOR.env.version)g.getDocumentElement().on(\"mousedown\",\nfunction(a){a.data.getTarget().is(\"html\")&&setTimeout(function(){c.editable().focus()})});f(c);try{c.document.$.execCommand(\"2D-position\",!1,!0)}catch(n){}(CKEDITOR.env.gecko||CKEDITOR.env.ie&&\"CSS1Compat\"==c.document.$.compatMode)&&this.attachListener(this,\"keydown\",function(a){var b=a.data.getKeystroke();if(33==b||34==b)if(CKEDITOR.env.ie)setTimeout(function(){c.getSelection().scrollIntoView()},0);else if(c.window.$.innerHeight>this.$.offsetHeight){var d=c.createRange();d[33==b?\"moveToElementEditStart\":\n\"moveToElementEditEnd\"](this);d.select();a.data.preventDefault()}});CKEDITOR.env.ie&&this.attachListener(g,\"blur\",function(){try{g.$.selection.empty()}catch(a){}});CKEDITOR.env.iOS&&this.attachListener(g,\"touchend\",function(){a.focus()});h=c.document.getElementsByTag(\"title\").getItem(0);h.data(\"cke-title\",h.getText());CKEDITOR.env.ie&&(c.document.$.title=this._.docTitle);CKEDITOR.tools.setTimeout(function(){\"unloaded\"==this.status&&(this.status=\"ready\");c.fire(\"contentDom\");this._.isPendingFocus&&\n(c.focus(),this._.isPendingFocus=!1);setTimeout(function(){c.fire(\"dataReady\")},0)},0,this)}function f(a){function b(){var f;a.editable().attachListener(a,\"selectionChange\",function(){var b=a.getSelection().getSelectedElement();b&&(f&&(f.detachEvent(\"onresizestart\",c),f=null),b.$.attachEvent(\"onresizestart\",c),f=b.$)})}function c(a){a.returnValue=!1}if(CKEDITOR.env.gecko)try{var f=a.document.$;f.execCommand(\"enableObjectResizing\",!1,!a.config.disableObjectResizing);f.execCommand(\"enableInlineTableEditing\",\n!1,!a.config.disableNativeTableHandles)}catch(h){}else CKEDITOR.env.ie&&11>CKEDITOR.env.version&&a.config.disableObjectResizing&&b(a)}function b(){var a=[];if(8<=CKEDITOR.document.$.documentMode){a.push(\"html.CSS1Compat [contenteditable\\x3dfalse]{min-height:0 !important}\");var b=[],c;for(c in CKEDITOR.dtd.$removeEmpty)b.push(\"html.CSS1Compat \"+c+\"[contenteditable\\x3dfalse]\");a.push(b.join(\",\")+\"{display:inline-block}\")}else CKEDITOR.env.gecko&&(a.push(\"html{height:100% !important}\"),a.push(\"img:-moz-broken{-moz-force-broken-image-icon:1;min-width:24px;min-height:24px}\"));\na.push(\"html{cursor:text;*cursor:auto}\");a.push(\"img,input,textarea{cursor:default}\");return a.join(\"\\n\")}var c;CKEDITOR.plugins.add(\"wysiwygarea\",{init:function(a){a.config.fullPage&&a.addFeature({allowedContent:\"html head title; style [media,type]; body (*)[id]; meta link [*]\",requiredContent:\"body\"});a.addMode(\"wysiwyg\",function(b){function f(e){e&&e.removeListener();a.editable(new c(a,h.$.contentWindow.document.body));a.setData(a.getData(1),b)}var g=\"document.open();\"+(CKEDITOR.env.ie?\"(\"+CKEDITOR.tools.fixDomain+\n\")();\":\"\")+\"document.close();\",g=CKEDITOR.env.air?\"javascript:void(0)\":CKEDITOR.env.ie&&!CKEDITOR.env.edge?\"javascript:void(function(){\"+encodeURIComponent(g)+\"}())\":\"\",h=CKEDITOR.dom.element.createFromHtml('\\x3ciframe src\\x3d\"'+g+'\" frameBorder\\x3d\"0\"\\x3e\\x3c/iframe\\x3e');h.setStyles({width:\"100%\",height:\"100%\"});h.addClass(\"cke_wysiwyg_frame\").addClass(\"cke_reset\");g=a.ui.space(\"contents\");g.append(h);var m=CKEDITOR.env.ie&&!CKEDITOR.env.edge||CKEDITOR.env.gecko;if(m)h.on(\"load\",f);var e=a.title,\nn=a.fire(\"ariaEditorHelpLabel\",{}).label;e&&(CKEDITOR.env.ie&&n&&(e+=\", \"+n),h.setAttribute(\"title\",e));if(n){var e=CKEDITOR.tools.getNextId(),q=CKEDITOR.dom.element.createFromHtml('\\x3cspan id\\x3d\"'+e+'\" class\\x3d\"cke_voice_label\"\\x3e'+n+\"\\x3c/span\\x3e\");g.append(q,1);h.setAttribute(\"aria-describedby\",e)}a.on(\"beforeModeUnload\",function(a){a.removeListener();q&&q.remove()});h.setAttributes({tabIndex:a.tabIndex,allowTransparency:\"true\"});!m&&f();a.fire(\"ariaWidget\",h)})}});CKEDITOR.editor.prototype.addContentsCss=\nfunction(a){var b=this.config,c=b.contentsCss;CKEDITOR.tools.isArray(c)||(b.contentsCss=c?[c]:[]);b.contentsCss.push(a)};c=CKEDITOR.tools.createClass({$:function(){this.base.apply(this,arguments);this._.frameLoadedHandler=CKEDITOR.tools.addFunction(function(b){CKEDITOR.tools.setTimeout(a,0,this,b)},this);this._.docTitle=this.getWindow().getFrame().getAttribute(\"title\")},base:CKEDITOR.editable,proto:{setData:function(a,c){var f=this.editor;if(c)this.setHtml(a),this.fixInitialSelection(),f.fire(\"dataReady\");\nelse{this._.isLoadingData=!0;f._.dataStore={id:1};var g=f.config,h=g.fullPage,m=g.docType,e=CKEDITOR.tools.buildStyleHtml(b()).replace(/<style>/,'\\x3cstyle data-cke-temp\\x3d\"1\"\\x3e');h||(e+=CKEDITOR.tools.buildStyleHtml(f.config.contentsCss));var n=g.baseHref?'\\x3cbase href\\x3d\"'+g.baseHref+'\" data-cke-temp\\x3d\"1\" /\\x3e':\"\";h&&(a=a.replace(/<!DOCTYPE[^>]*>/i,function(a){f.docType=m=a;return\"\"}).replace(/<\\?xml\\s[^\\?]*\\?>/i,function(a){f.xmlDeclaration=a;return\"\"}));a=f.dataProcessor.toHtml(a);h?(/<body[\\s|>]/.test(a)||\n(a=\"\\x3cbody\\x3e\"+a),/<html[\\s|>]/.test(a)||(a=\"\\x3chtml\\x3e\"+a+\"\\x3c/html\\x3e\"),/<head[\\s|>]/.test(a)?/<title[\\s|>]/.test(a)||(a=a.replace(/<head[^>]*>/,\"$\\x26\\x3ctitle\\x3e\\x3c/title\\x3e\")):a=a.replace(/<html[^>]*>/,\"$\\x26\\x3chead\\x3e\\x3ctitle\\x3e\\x3c/title\\x3e\\x3c/head\\x3e\"),n&&(a=a.replace(/<head[^>]*?>/,\"$\\x26\"+n)),a=a.replace(/<\\/head\\s*>/,e+\"$\\x26\"),a=m+a):a=g.docType+'\\x3chtml dir\\x3d\"'+g.contentsLangDirection+'\" lang\\x3d\"'+(g.contentsLanguage||f.langCode)+'\"\\x3e\\x3chead\\x3e\\x3ctitle\\x3e'+\nthis._.docTitle+\"\\x3c/title\\x3e\"+n+e+\"\\x3c/head\\x3e\\x3cbody\"+(g.bodyId?' id\\x3d\"'+g.bodyId+'\"':\"\")+(g.bodyClass?' class\\x3d\"'+g.bodyClass+'\"':\"\")+\"\\x3e\"+a+\"\\x3c/body\\x3e\\x3c/html\\x3e\";CKEDITOR.env.gecko&&(a=a.replace(/<body/,'\\x3cbody contenteditable\\x3d\"true\" '),2E4>CKEDITOR.env.version&&(a=a.replace(/<body[^>]*>/,\"$\\x26\\x3c!-- cke-content-start --\\x3e\")));g='\\x3cscript id\\x3d\"cke_actscrpt\" type\\x3d\"text/javascript\"'+(CKEDITOR.env.ie?' defer\\x3d\"defer\" ':\"\")+\"\\x3evar wasLoaded\\x3d0;function onload(){if(!wasLoaded)window.parent.CKEDITOR.tools.callFunction(\"+\nthis._.frameLoadedHandler+\",window);wasLoaded\\x3d1;}\"+(CKEDITOR.env.ie?\"onload();\":'document.addEventListener(\"DOMContentLoaded\", onload, false );')+\"\\x3c/script\\x3e\";CKEDITOR.env.ie&&9>CKEDITOR.env.version&&(g+='\\x3cscript id\\x3d\"cke_shimscrpt\"\\x3ewindow.parent.CKEDITOR.tools.enableHtml5Elements(document)\\x3c/script\\x3e');n&&CKEDITOR.env.ie&&10>CKEDITOR.env.version&&(g+='\\x3cscript id\\x3d\"cke_basetagscrpt\"\\x3evar baseTag \\x3d document.querySelector( \"base\" );baseTag.href \\x3d baseTag.href;\\x3c/script\\x3e');\na=a.replace(/(?=\\s*<\\/(:?head)>)/,g);this.clearCustomData();this.clearListeners();f.fire(\"contentDomUnload\");var q=this.getDocument();try{q.write(a)}catch(y){setTimeout(function(){q.write(a)},0)}}},getData:function(a){if(a)return this.getHtml();a=this.editor;var b=a.config,c=b.fullPage,f=c&&a.docType,h=c&&a.xmlDeclaration,m=this.getDocument(),c=c?m.getDocumentElement().getOuterHtml():m.getBody().getHtml();CKEDITOR.env.gecko&&b.enterMode!=CKEDITOR.ENTER_BR&&(c=c.replace(/<br>(?=\\s*(:?$|<\\/body>))/,\n\"\"));c=a.dataProcessor.toDataFormat(c);h&&(c=h+\"\\n\"+c);f&&(c=f+\"\\n\"+c);return c},focus:function(){this._.isLoadingData?this._.isPendingFocus=!0:c.baseProto.focus.call(this)},detach:function(){var a=this.editor,b=a.document,f;try{f=a.window.getFrame()}catch(g){}c.baseProto.detach.call(this);this.clearCustomData();b.getDocumentElement().clearCustomData();CKEDITOR.tools.removeFunction(this._.frameLoadedHandler);f&&f.getParent()?(f.clearCustomData(),(a=f.removeCustomData(\"onResize\"))&&a.removeListener(),\nf.remove()):CKEDITOR.warn(\"editor-destroy-iframe\")}}})}(),CKEDITOR.config.disableObjectResizing=!1,CKEDITOR.config.disableNativeTableHandles=!0,CKEDITOR.config.disableNativeSpellChecker=!0,CKEDITOR.config.plugins=\"dialogui,dialog,a11yhelp,about,basicstyles,blockquote,notification,button,toolbar,clipboard,panel,floatpanel,menu,contextmenu,elementspath,indent,indentlist,list,enterkey,entities,popup,filetools,filebrowser,floatingspace,listblock,richcombo,format,horizontalrule,htmlwriter,image,fakeobjects,link,magicline,maximize,pastefromword,pastetext,removeformat,resize,menubutton,scayt,showborders,sourcearea,specialchar,stylescombo,tab,table,tabletools,tableselection,undo,lineutils,widgetselection,widget,notificationaggregator,uploadwidget,uploadimage,wsc,wysiwygarea\",\nCKEDITOR.config.skin=\"moono-lisa\",function(){var a=function(a,b){var c=CKEDITOR.getUrl(\"plugins/\"+b);a=a.split(\",\");for(var d=0;d<a.length;d++)CKEDITOR.skin.icons[a[d]]={path:c,offset:-a[++d],bgsize:a[++d]}};CKEDITOR.env.hidpi?a(\"about,0,,bold,24,,italic,48,,strike,72,,subscript,96,,superscript,120,,underline,144,,bidiltr,168,,bidirtl,192,,blockquote,216,,copy-rtl,240,,copy,264,,cut-rtl,288,,cut,312,,paste-rtl,336,,paste,360,,codesnippet,384,,bgcolor,408,,textcolor,432,,copyformatting,456,,creatediv,480,,docprops-rtl,504,,docprops,528,,easyimagealigncenter,552,,easyimagealignleft,576,,easyimagealignright,600,,easyimagealt,624,,easyimagefull,648,,easyimageside,672,,easyimageupload,696,,embed,720,,embedsemantic,744,,emojipanel,768,,find-rtl,792,,find,816,,replace,840,,flash,864,,button,888,,checkbox,912,,form,936,,hiddenfield,960,,imagebutton,984,,radio,1008,,select-rtl,1032,,select,1056,,textarea-rtl,1080,,textarea,1104,,textfield-rtl,1128,,textfield,1152,,horizontalrule,1176,,iframe,1200,,image,1224,,indent-rtl,1248,,indent,1272,,outdent-rtl,1296,,outdent,1320,,justifyblock,1344,,justifycenter,1368,,justifyleft,1392,,justifyright,1416,,language,1440,,anchor-rtl,1464,,anchor,1488,,link,1512,,unlink,1536,,bulletedlist-rtl,1560,,bulletedlist,1584,,numberedlist-rtl,1608,,numberedlist,1632,,mathjax,1656,,maximize,1680,,newpage-rtl,1704,,newpage,1728,,pagebreak-rtl,1752,,pagebreak,1776,,pastefromword-rtl,1800,,pastefromword,1824,,pastetext-rtl,1848,,pastetext,1872,,placeholder,1896,,preview-rtl,1920,,preview,1944,,print,1968,,removeformat,1992,,save,2016,,scayt,2040,,selectall,2064,,showblocks-rtl,2088,,showblocks,2112,,smiley,2136,,source-rtl,2160,,source,2184,,sourcedialog-rtl,2208,,sourcedialog,2232,,specialchar,2256,,table,2280,,templates-rtl,2304,,templates,2328,,uicolor,2352,,redo-rtl,2376,,redo,2400,,undo-rtl,2424,,undo,2448,,simplebox,4944,auto,spellchecker,2496,\",\n\"icons_hidpi.png\"):a(\"about,0,auto,bold,24,auto,italic,48,auto,strike,72,auto,subscript,96,auto,superscript,120,auto,underline,144,auto,bidiltr,168,auto,bidirtl,192,auto,blockquote,216,auto,copy-rtl,240,auto,copy,264,auto,cut-rtl,288,auto,cut,312,auto,paste-rtl,336,auto,paste,360,auto,codesnippet,384,auto,bgcolor,408,auto,textcolor,432,auto,copyformatting,456,auto,creatediv,480,auto,docprops-rtl,504,auto,docprops,528,auto,easyimagealigncenter,552,auto,easyimagealignleft,576,auto,easyimagealignright,600,auto,easyimagealt,624,auto,easyimagefull,648,auto,easyimageside,672,auto,easyimageupload,696,auto,embed,720,auto,embedsemantic,744,auto,emojipanel,768,auto,find-rtl,792,auto,find,816,auto,replace,840,auto,flash,864,auto,button,888,auto,checkbox,912,auto,form,936,auto,hiddenfield,960,auto,imagebutton,984,auto,radio,1008,auto,select-rtl,1032,auto,select,1056,auto,textarea-rtl,1080,auto,textarea,1104,auto,textfield-rtl,1128,auto,textfield,1152,auto,horizontalrule,1176,auto,iframe,1200,auto,image,1224,auto,indent-rtl,1248,auto,indent,1272,auto,outdent-rtl,1296,auto,outdent,1320,auto,justifyblock,1344,auto,justifycenter,1368,auto,justifyleft,1392,auto,justifyright,1416,auto,language,1440,auto,anchor-rtl,1464,auto,anchor,1488,auto,link,1512,auto,unlink,1536,auto,bulletedlist-rtl,1560,auto,bulletedlist,1584,auto,numberedlist-rtl,1608,auto,numberedlist,1632,auto,mathjax,1656,auto,maximize,1680,auto,newpage-rtl,1704,auto,newpage,1728,auto,pagebreak-rtl,1752,auto,pagebreak,1776,auto,pastefromword-rtl,1800,auto,pastefromword,1824,auto,pastetext-rtl,1848,auto,pastetext,1872,auto,placeholder,1896,auto,preview-rtl,1920,auto,preview,1944,auto,print,1968,auto,removeformat,1992,auto,save,2016,auto,scayt,2040,auto,selectall,2064,auto,showblocks-rtl,2088,auto,showblocks,2112,auto,smiley,2136,auto,source-rtl,2160,auto,source,2184,auto,sourcedialog-rtl,2208,auto,sourcedialog,2232,auto,specialchar,2256,auto,table,2280,auto,templates-rtl,2304,auto,templates,2328,auto,uicolor,2352,auto,redo-rtl,2376,auto,redo,2400,auto,undo-rtl,2424,auto,undo,2448,auto,simplebox,2472,auto,spellchecker,2496,auto\",\n\"icons.png\")}())})();"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/adminlte/bower_components/ckeditor/config.js",
    "content": "/**\n * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see https://ckeditor.com/legal/ckeditor-oss-license\n */\n\nCKEDITOR.editorConfig = function( config ) {\n\t// Define changes to default configuration here.\n\t// For complete reference see:\n\t// https://ckeditor.com/docs/ckeditor4/latest/api/CKEDITOR_config.html\n\n\t// The toolbar groups arrangement, optimized for two toolbar rows.\n\tconfig.toolbarGroups = [\n\t\t{ name: 'clipboard',   groups: [ 'clipboard', 'undo' ] },\n\t\t{ name: 'editing',     groups: [ 'find', 'selection', 'spellchecker' ] },\n\t\t{ name: 'links' },\n\t\t{ name: 'insert' },\n\t\t{ name: 'forms' },\n\t\t{ name: 'tools' },\n\t\t{ name: 'document',\t   groups: [ 'mode', 'document', 'doctools' ] },\n\t\t{ name: 'others' },\n\t\t'/',\n\t\t{ name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ] },\n\t\t{ name: 'paragraph',   groups: [ 'list', 'indent', 'blocks', 'align', 'bidi' ] },\n\t\t{ name: 'styles' },\n\t\t{ name: 'colors' }\n\t];\n\n\t// Remove some buttons provided by the standard plugins, which are\n\t// not needed in the Standard(s) toolbar.\n\tconfig.removeButtons = 'PasteFromWord,Scayt,Anchor';\n\n\t// Set the most common block elements.\n\tconfig.format_tags = 'p;h1;h2;h3;pre';\n\n\t// Simplify the dialog windows.\n\tconfig.removeDialogTabs = 'image:advanced;link:advanced';\n};\n"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/adminlte/bower_components/ckeditor/contents.css",
    "content": "/*\nCopyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.\nFor licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n*/\n\nbody\n{\n\t/* Font */\n\t/* Emoji fonts are added to visualise them nicely in Internet Explorer. */\n\tfont-family: sans-serif, Arial, Verdana, \"Trebuchet MS\", \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\";\n\tfont-size: 12px;\n\n\t/* Text color */\n\tcolor: #333;\n\n\t/* Remove the background color to make it transparent. */\n\tbackground-color: #fff;\n\n\tmargin: 20px;\n}\n\n.cke_editable\n{\n\tfont-size: 13px;\n\tline-height: 1.6;\n\n\t/* Fix for missing scrollbars with RTL texts. (#10488) */\n\tword-wrap: break-word;\n}\n\nblockquote\n{\n\tfont-style: italic;\n\tfont-family: Georgia, Times, \"Times New Roman\", serif;\n\tpadding: 2px 0;\n\tborder-style: solid;\n\tborder-color: #ccc;\n\tborder-width: 0;\n}\n\n.cke_contents_ltr blockquote\n{\n\tpadding-left: 20px;\n\tpadding-right: 8px;\n\tborder-left-width: 5px;\n}\n\n.cke_contents_rtl blockquote\n{\n\tpadding-left: 8px;\n\tpadding-right: 20px;\n\tborder-right-width: 5px;\n}\n\na\n{\n\tcolor: #0782C1;\n}\n\nol,ul,dl\n{\n\t/* IE7: reset rtl list margin. (#7334) */\n\t*margin-right: 0px;\n\t/* Preserved spaces for list items with text direction different than the list. (#6249,#8049)*/\n\tpadding: 0 40px;\n}\n\nh1,h2,h3,h4,h5,h6\n{\n\tfont-weight: normal;\n\tline-height: 1.2;\n}\n\nhr\n{\n\tborder: 0px;\n\tborder-top: 1px solid #ccc;\n}\n\nimg.right\n{\n\tborder: 1px solid #ccc;\n\tfloat: right;\n\tmargin-left: 15px;\n\tpadding: 5px;\n}\n\nimg.left\n{\n\tborder: 1px solid #ccc;\n\tfloat: left;\n\tmargin-right: 15px;\n\tpadding: 5px;\n}\n\npre\n{\n\twhite-space: pre-wrap; /* CSS 2.1 */\n\tword-wrap: break-word; /* IE7 */\n\t-moz-tab-size: 4;\n\ttab-size: 4;\n}\n\n.marker\n{\n\tbackground-color: Yellow;\n}\n\nspan[lang]\n{\n\tfont-style: italic;\n}\n\nfigure\n{\n\ttext-align: center;\n\toutline: solid 1px #ccc;\n\tbackground: rgba(0,0,0,0.05);\n\tpadding: 10px;\n\tmargin: 10px 20px;\n\tdisplay: inline-block;\n}\n\nfigure > figcaption\n{\n\ttext-align: center;\n\tdisplay: block; /* For IE8 */\n}\n\na > img {\n\tpadding: 1px;\n\tmargin: 1px;\n\tborder: none;\n\toutline: 1px solid #0782C1;\n}\n\n/* Widget Styles */\n.code-featured\n{\n\tborder: 5px solid red;\n}\n\n.math-featured\n{\n\tpadding: 20px;\n\tbox-shadow: 0 0 2px rgba(200, 0, 0, 1);\n\tbackground-color: rgba(255, 0, 0, 0.05);\n\tmargin: 10px;\n}\n\n.image-clean\n{\n\tborder: 0;\n\tbackground: none;\n\tpadding: 0;\n}\n\n.image-clean > figcaption\n{\n\tfont-size: .9em;\n\ttext-align: right;\n}\n\n.image-grayscale\n{\n\tbackground-color: white;\n\tcolor: #666;\n}\n\n.image-grayscale img, img.image-grayscale\n{\n\tfilter: grayscale(100%);\n}\n\n.embed-240p\n{\n\tmax-width: 426px;\n\tmax-height: 240px;\n\tmargin:0 auto;\n}\n\n.embed-360p\n{\n\tmax-width: 640px;\n\tmax-height: 360px;\n\tmargin:0 auto;\n}\n\n.embed-480p\n{\n\tmax-width: 854px;\n\tmax-height: 480px;\n\tmargin:0 auto;\n}\n\n.embed-720p\n{\n\tmax-width: 1280px;\n\tmax-height: 720px;\n\tmargin:0 auto;\n}\n\n.embed-1080p\n{\n\tmax-width: 1920px;\n\tmax-height: 1080px;\n\tmargin:0 auto;\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/adminlte/bower_components/ckeditor/lang/zh-cn.js",
    "content": "﻿/*\nCopyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.\nFor licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n*/\nCKEDITOR.lang['zh-cn']={\"wsc\":{\"btnIgnore\":\"忽略\",\"btnIgnoreAll\":\"全部忽略\",\"btnReplace\":\"替换\",\"btnReplaceAll\":\"全部替换\",\"btnUndo\":\"撤消\",\"changeTo\":\"更改为\",\"errorLoading\":\"加载应该服务主机时出错: %s.\",\"ieSpellDownload\":\"拼写检查插件还没安装, 您是否想现在就下载?\",\"manyChanges\":\"拼写检查完成: 更改了 %1 个单词\",\"noChanges\":\"拼写检查完成: 没有更改任何单词\",\"noMispell\":\"拼写检查完成: 没有发现拼写错误\",\"noSuggestions\":\"- 没有建议 -\",\"notAvailable\":\"抱歉, 服务目前暂不可用\",\"notInDic\":\"没有在字典里\",\"oneChange\":\"拼写检查完成: 更改了一个单词\",\"progress\":\"正在进行拼写检查...\",\"title\":\"拼写检查\",\"toolbar\":\"拼写检查\"},\"widget\":{\"move\":\"点击并拖拽以移动\",\"label\":\"%1 小部件\"},\"uploadwidget\":{\"abort\":\"上传已被用户中止\",\"doneOne\":\"文件上传成功\",\"doneMany\":\"成功上传了 %1 个文件\",\"uploadOne\":\"正在上传文件（{percentage}%）...\",\"uploadMany\":\"正在上传文件，{max} 中的 {current}（{percentage}%）...\"},\"undo\":{\"redo\":\"重做\",\"undo\":\"撤消\"},\"toolbar\":{\"toolbarCollapse\":\"折叠工具栏\",\"toolbarExpand\":\"展开工具栏\",\"toolbarGroups\":{\"document\":\"文档\",\"clipboard\":\"剪贴板/撤销\",\"editing\":\"编辑\",\"forms\":\"表单\",\"basicstyles\":\"基本格式\",\"paragraph\":\"段落\",\"links\":\"链接\",\"insert\":\"插入\",\"styles\":\"样式\",\"colors\":\"颜色\",\"tools\":\"工具\"},\"toolbars\":\"工具栏\"},\"table\":{\"border\":\"边框\",\"caption\":\"标题\",\"cell\":{\"menu\":\"单元格\",\"insertBefore\":\"在左侧插入单元格\",\"insertAfter\":\"在右侧插入单元格\",\"deleteCell\":\"删除单元格\",\"merge\":\"合并单元格\",\"mergeRight\":\"向右合并单元格\",\"mergeDown\":\"向下合并单元格\",\"splitHorizontal\":\"水平拆分单元格\",\"splitVertical\":\"垂直拆分单元格\",\"title\":\"单元格属性\",\"cellType\":\"单元格类型\",\"rowSpan\":\"纵跨行数\",\"colSpan\":\"横跨列数\",\"wordWrap\":\"自动换行\",\"hAlign\":\"水平对齐\",\"vAlign\":\"垂直对齐\",\"alignBaseline\":\"基线\",\"bgColor\":\"背景颜色\",\"borderColor\":\"边框颜色\",\"data\":\"数据\",\"header\":\"表头\",\"yes\":\"是\",\"no\":\"否\",\"invalidWidth\":\"单元格宽度必须为数字格式\",\"invalidHeight\":\"单元格高度必须为数字格式\",\"invalidRowSpan\":\"行跨度必须为整数格式\",\"invalidColSpan\":\"列跨度必须为整数格式\",\"chooseColor\":\"选择\"},\"cellPad\":\"边距\",\"cellSpace\":\"间距\",\"column\":{\"menu\":\"列\",\"insertBefore\":\"在左侧插入列\",\"insertAfter\":\"在右侧插入列\",\"deleteColumn\":\"删除列\"},\"columns\":\"列数\",\"deleteTable\":\"删除表格\",\"headers\":\"标题单元格\",\"headersBoth\":\"第一列和第一行\",\"headersColumn\":\"第一列\",\"headersNone\":\"无\",\"headersRow\":\"第一行\",\"heightUnit\":\"height unit\",\"invalidBorder\":\"边框粗细必须为数字格式\",\"invalidCellPadding\":\"单元格填充必须为数字格式\",\"invalidCellSpacing\":\"单元格间距必须为数字格式\",\"invalidCols\":\"指定的行数必须大于零\",\"invalidHeight\":\"表格高度必须为数字格式\",\"invalidRows\":\"指定的列数必须大于零\",\"invalidWidth\":\"表格宽度必须为数字格式\",\"menu\":\"表格属性\",\"row\":{\"menu\":\"行\",\"insertBefore\":\"在上方插入行\",\"insertAfter\":\"在下方插入行\",\"deleteRow\":\"删除行\"},\"rows\":\"行数\",\"summary\":\"摘要\",\"title\":\"表格属性\",\"toolbar\":\"表格\",\"widthPc\":\"百分比\",\"widthPx\":\"像素\",\"widthUnit\":\"宽度单位\"},\"stylescombo\":{\"label\":\"样式\",\"panelTitle\":\"样式\",\"panelTitle1\":\"块级元素样式\",\"panelTitle2\":\"内联元素样式\",\"panelTitle3\":\"对象元素样式\"},\"specialchar\":{\"options\":\"特殊符号选项\",\"title\":\"选择特殊符号\",\"toolbar\":\"插入特殊符号\"},\"sourcearea\":{\"toolbar\":\"源码\"},\"scayt\":{\"btn_about\":\"关于即时拼写检查\",\"btn_dictionaries\":\"字典\",\"btn_disable\":\"禁用即时拼写检查\",\"btn_enable\":\"启用即时拼写检查\",\"btn_langs\":\"语言\",\"btn_options\":\"选项\",\"text_title\":\"即时拼写检查\"},\"removeformat\":{\"toolbar\":\"清除格式\"},\"pastetext\":{\"button\":\"粘贴为无格式文本\",\"pasteNotification\":\"您的浏览器不支持通过工具栏或右键菜单进行粘贴，请按 %1 进行粘贴。\",\"title\":\"粘贴为无格式文本\"},\"pastefromword\":{\"confirmCleanup\":\"您要粘贴的内容好像是来自 MS Word，是否要清除 MS Word 格式后再粘贴？\",\"error\":\"由于内部错误无法清理要粘贴的数据\",\"title\":\"从 MS Word 粘贴\",\"toolbar\":\"从 MS Word 粘贴\"},\"notification\":{\"closed\":\"通知已关闭\"},\"maximize\":{\"maximize\":\"全屏\",\"minimize\":\"最小化\"},\"magicline\":{\"title\":\"在这插入段落\"},\"list\":{\"bulletedlist\":\"项目列表\",\"numberedlist\":\"编号列表\"},\"link\":{\"acccessKey\":\"访问键\",\"advanced\":\"高级\",\"advisoryContentType\":\"内容类型\",\"advisoryTitle\":\"标题\",\"anchor\":{\"toolbar\":\"插入/编辑锚点链接\",\"menu\":\"锚点链接属性\",\"title\":\"锚点链接属性\",\"name\":\"锚点名称\",\"errorName\":\"请输入锚点名称\",\"remove\":\"删除锚点\"},\"anchorId\":\"按锚点 ID\",\"anchorName\":\"按锚点名称\",\"charset\":\"字符编码\",\"cssClasses\":\"样式类名称\",\"download\":\"强制下载\",\"displayText\":\"显示文本\",\"emailAddress\":\"地址\",\"emailBody\":\"内容\",\"emailSubject\":\"主题\",\"id\":\"ID\",\"info\":\"超链接信息\",\"langCode\":\"语言代码\",\"langDir\":\"语言方向\",\"langDirLTR\":\"从左到右 (LTR)\",\"langDirRTL\":\"从右到左 (RTL)\",\"menu\":\"编辑超链接\",\"name\":\"名称\",\"noAnchors\":\"(此文档没有可用的锚点)\",\"noEmail\":\"请输入电子邮件地址\",\"noUrl\":\"请输入超链接地址\",\"noTel\":\"Please type the phone number\",\"other\":\"<其他>\",\"phoneNumber\":\"Phone number\",\"popupDependent\":\"依附 (NS)\",\"popupFeatures\":\"弹出窗口属性\",\"popupFullScreen\":\"全屏 (IE)\",\"popupLeft\":\"左\",\"popupLocationBar\":\"地址栏\",\"popupMenuBar\":\"菜单栏\",\"popupResizable\":\"可缩放\",\"popupScrollBars\":\"滚动条\",\"popupStatusBar\":\"状态栏\",\"popupToolbar\":\"工具栏\",\"popupTop\":\"右\",\"rel\":\"关联\",\"selectAnchor\":\"选择一个锚点\",\"styles\":\"行内样式\",\"tabIndex\":\"Tab 键次序\",\"target\":\"目标\",\"targetFrame\":\"<框架>\",\"targetFrameName\":\"目标框架名称\",\"targetPopup\":\"<弹出窗口>\",\"targetPopupName\":\"弹出窗口名称\",\"title\":\"超链接\",\"toAnchor\":\"页内锚点链接\",\"toEmail\":\"电子邮件\",\"toUrl\":\"地址\",\"toPhone\":\"Phone\",\"toolbar\":\"插入/编辑超链接\",\"type\":\"超链接类型\",\"unlink\":\"取消超链接\",\"upload\":\"上传\"},\"indent\":{\"indent\":\"增加缩进量\",\"outdent\":\"减少缩进量\"},\"image\":{\"alt\":\"替换文本\",\"border\":\"边框大小\",\"btnUpload\":\"上传到服务器\",\"button2Img\":\"确定要把当前图像按钮转换为普通图像吗？\",\"hSpace\":\"水平间距\",\"img2Button\":\"确定要把当前图像改变为图像按钮吗？\",\"infoTab\":\"图像信息\",\"linkTab\":\"链接\",\"lockRatio\":\"锁定比例\",\"menu\":\"图像属性\",\"resetSize\":\"原始尺寸\",\"title\":\"图像属性\",\"titleButton\":\"图像域属性\",\"upload\":\"上传\",\"urlMissing\":\"缺少图像源文件地址\",\"vSpace\":\"垂直间距\",\"validateBorder\":\"边框大小必须为整数格式\",\"validateHSpace\":\"水平间距必须为整数格式\",\"validateVSpace\":\"垂直间距必须为整数格式\"},\"horizontalrule\":{\"toolbar\":\"插入水平线\"},\"format\":{\"label\":\"格式\",\"panelTitle\":\"格式\",\"tag_address\":\"地址\",\"tag_div\":\"段落(DIV)\",\"tag_h1\":\"标题 1\",\"tag_h2\":\"标题 2\",\"tag_h3\":\"标题 3\",\"tag_h4\":\"标题 4\",\"tag_h5\":\"标题 5\",\"tag_h6\":\"标题 6\",\"tag_p\":\"普通\",\"tag_pre\":\"已编排格式\"},\"filetools\":{\"loadError\":\"读取文件时发生错误\",\"networkError\":\"上传文件时发生网络错误\",\"httpError404\":\"上传文件时发生 HTTP 错误（404：无法找到文件）\",\"httpError403\":\"上传文件时发生 HTTP 错误（403：禁止访问）\",\"httpError\":\"上传文件时发生 HTTP 错误（错误代码：%1）\",\"noUrlError\":\"上传的 URL 未定义\",\"responseError\":\"不正确的服务器响应\"},\"fakeobjects\":{\"anchor\":\"锚点\",\"flash\":\"Flash 动画\",\"hiddenfield\":\"隐藏域\",\"iframe\":\"IFrame\",\"unknown\":\"未知对象\"},\"elementspath\":{\"eleLabel\":\"元素路径\",\"eleTitle\":\"%1 元素\"},\"contextmenu\":{\"options\":\"快捷菜单选项\"},\"clipboard\":{\"copy\":\"复制\",\"copyError\":\"您的浏览器安全设置不允许编辑器自动执行复制操作，请使用键盘快捷键(Ctrl/Cmd+C)来完成。\",\"cut\":\"剪切\",\"cutError\":\"您的浏览器安全设置不允许编辑器自动执行剪切操作，请使用键盘快捷键(Ctrl/Cmd+X)来完成。\",\"paste\":\"粘贴\",\"pasteNotification\":\"您的浏览器不支持通过工具栏或右键菜单进行粘贴，请按 %1 进行粘贴。\",\"pasteArea\":\"粘贴区域\",\"pasteMsg\":\"将您的内容粘贴到下方区域，然后按确定。\"},\"blockquote\":{\"toolbar\":\"块引用\"},\"basicstyles\":{\"bold\":\"加粗\",\"italic\":\"倾斜\",\"strike\":\"删除线\",\"subscript\":\"下标\",\"superscript\":\"上标\",\"underline\":\"下划线\"},\"about\":{\"copy\":\"版权所有 &copy; $1。<br />保留所有权利。\",\"dlgTitle\":\"关于 CKEditor 4\",\"moreInfo\":\"相关授权许可信息请访问我们的网站：\"},\"editor\":\"所见即所得编辑器\",\"editorPanel\":\"所见即所得编辑器面板\",\"common\":{\"editorHelp\":\"按 ALT+0 获得帮助\",\"browseServer\":\"浏览服务器\",\"url\":\"URL\",\"protocol\":\"协议\",\"upload\":\"上传\",\"uploadSubmit\":\"上传到服务器\",\"image\":\"图像\",\"flash\":\"Flash\",\"form\":\"表单\",\"checkbox\":\"复选框\",\"radio\":\"单选按钮\",\"textField\":\"单行文本\",\"textarea\":\"多行文本\",\"hiddenField\":\"隐藏域\",\"button\":\"按钮\",\"select\":\"列表/菜单\",\"imageButton\":\"图像按钮\",\"notSet\":\"<没有设置>\",\"id\":\"ID\",\"name\":\"名称\",\"langDir\":\"语言方向\",\"langDirLtr\":\"从左到右 (LTR)\",\"langDirRtl\":\"从右到左 (RTL)\",\"langCode\":\"语言代码\",\"longDescr\":\"详细说明 URL\",\"cssClass\":\"样式类名称\",\"advisoryTitle\":\"标题\",\"cssStyle\":\"行内样式\",\"ok\":\"确定\",\"cancel\":\"取消\",\"close\":\"关闭\",\"preview\":\"预览\",\"resize\":\"拖拽以改变大小\",\"generalTab\":\"常规\",\"advancedTab\":\"高级\",\"validateNumberFailed\":\"需要输入数字格式\",\"confirmNewPage\":\"当前文档内容未保存，是否确认新建文档？\",\"confirmCancel\":\"部分修改尚未保存，是否确认关闭对话框？\",\"options\":\"选项\",\"target\":\"目标窗口\",\"targetNew\":\"新窗口 (_blank)\",\"targetTop\":\"整页 (_top)\",\"targetSelf\":\"本窗口 (_self)\",\"targetParent\":\"父窗口 (_parent)\",\"langDirLTR\":\"从左到右 (LTR)\",\"langDirRTL\":\"从右到左 (RTL)\",\"styles\":\"样式\",\"cssClasses\":\"样式类\",\"width\":\"宽度\",\"height\":\"高度\",\"align\":\"对齐方式\",\"left\":\"左对齐\",\"right\":\"右对齐\",\"center\":\"居中\",\"justify\":\"两端对齐\",\"alignLeft\":\"左对齐\",\"alignRight\":\"右对齐\",\"alignCenter\":\"居中\",\"alignTop\":\"顶端\",\"alignMiddle\":\"居中\",\"alignBottom\":\"底部\",\"alignNone\":\"无\",\"invalidValue\":\"无效的值。\",\"invalidHeight\":\"高度必须为数字格式\",\"invalidWidth\":\"宽度必须为数字格式\",\"invalidLength\":\"为 \\\"%1\\\" 字段设置的值必须是一个正数或者没有一个有效的度量单位 (%2)。\",\"invalidCssLength\":\"此“%1”字段的值必须为正数，可以包含或不包含一个有效的 CSS 长度单位(px, %, in, cm, mm, em, ex, pt 或 pc)\",\"invalidHtmlLength\":\"此“%1”字段的值必须为正数，可以包含或不包含一个有效的 HTML 长度单位(px 或 %)\",\"invalidInlineStyle\":\"内联样式必须为格式是以分号分隔的一个或多个“属性名 : 属性值”。\",\"cssLengthTooltip\":\"输入一个表示像素值的数字，或加上一个有效的 CSS 长度单位(px, %, in, cm, mm, em, ex, pt 或 pc)。\",\"unavailable\":\"%1<span class=\\\"cke_accessibility\\\">，不可用</span>\",\"keyboard\":{\"8\":\"退格键\",\"13\":\"回车键\",\"16\":\"Shift\",\"17\":\"Ctrl\",\"18\":\"Alt\",\"32\":\"空格键\",\"35\":\"行尾键\",\"36\":\"行首键\",\"46\":\"删除键\",\"112\":\"F1\",\"113\":\"F2\",\"114\":\"F3\",\"115\":\"F4\",\"116\":\"F5\",\"117\":\"F6\",\"118\":\"F7\",\"119\":\"F8\",\"120\":\"F9\",\"121\":\"F10\",\"122\":\"F11\",\"123\":\"F12\",\"124\":\"F13\",\"125\":\"F14\",\"126\":\"F15\",\"127\":\"F16\",\"128\":\"F17\",\"129\":\"F18\",\"130\":\"F19\",\"131\":\"F20\",\"132\":\"F21\",\"133\":\"F22\",\"134\":\"F23\",\"135\":\"F24\",\"224\":\"Command\"},\"keyboardShortcut\":\"快捷键\",\"optionDefault\":\"默认\"}};"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/adminlte/bower_components/ckeditor/plugins/image/dialogs/image.js",
    "content": "﻿/*\n Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.\n For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n*/\n(function(){var u=function(d,k){function u(){var a=arguments,b=this.getContentElement(\"advanced\",\"txtdlgGenStyle\");b&&b.commit.apply(b,a);this.foreach(function(b){b.commit&&\"txtdlgGenStyle\"!=b.id&&b.commit.apply(b,a)})}function g(a){if(!v){v=1;var b=this.getDialog(),c=b.imageElement;if(c){this.commit(1,c);a=[].concat(a);for(var d=a.length,h,e=0;e<d;e++)(h=b.getContentElement.apply(b,a[e].split(\":\")))&&h.setup(1,c)}v=0}}var l=/^\\s*(\\d+)((px)|\\%)?\\s*$/i,y=/(^\\s*(\\d+)((px)|\\%)?\\s*$)|^$/i,q=/^\\d+px$/,\nz=function(){var a=this.getValue(),b=this.getDialog(),c=a.match(l);c&&(\"%\"==c[2]&&m(b,!1),a=c[1]);b.lockRatio&&(c=b.originalElement,\"true\"==c.getCustomData(\"isReady\")&&(\"txtHeight\"==this.id?(a&&\"0\"!=a&&(a=Math.round(a/c.$.height*c.$.width)),isNaN(a)||b.setValueOf(\"info\",\"txtWidth\",a)):(a&&\"0\"!=a&&(a=Math.round(a/c.$.width*c.$.height)),isNaN(a)||b.setValueOf(\"info\",\"txtHeight\",a))));e(b)},e=function(a){if(!a.originalElement||!a.preview)return 1;a.commitContent(4,a.preview);return 0},v,m=function(a,\nb){if(!a.getContentElement(\"info\",\"ratioLock\"))return null;var c=a.originalElement;if(!c)return null;if(\"check\"==b){if(!a.userlockRatio&&\"true\"==c.getCustomData(\"isReady\")){var d=a.getValueOf(\"info\",\"txtWidth\"),h=a.getValueOf(\"info\",\"txtHeight\"),c=c.$.width/c.$.height,e=d/h;a.lockRatio=!1;d||h?1==Math.round(c/e*100)/100&&(a.lockRatio=!0):a.lockRatio=!0}}else void 0!==b?a.lockRatio=b:(a.userlockRatio=1,a.lockRatio=!a.lockRatio);d=CKEDITOR.document.getById(r);a.lockRatio?d.removeClass(\"cke_btn_unlocked\"):\nd.addClass(\"cke_btn_unlocked\");d.setAttribute(\"aria-checked\",a.lockRatio);CKEDITOR.env.hc&&d.getChild(0).setHtml(a.lockRatio?CKEDITOR.env.ie?\"■\":\"▣\":CKEDITOR.env.ie?\"□\":\"▢\");return a.lockRatio},A=function(a,b){var c=a.originalElement;if(\"true\"==c.getCustomData(\"isReady\")){var d=a.getContentElement(\"info\",\"txtWidth\"),h=a.getContentElement(\"info\",\"txtHeight\"),f;b?c=f=0:(f=c.$.width,c=c.$.height);d&&d.setValue(f);h&&h.setValue(c)}e(a)},B=function(a,b){function c(a,b){var c=a.match(l);return c?(\"%\"==\nc[2]&&(c[1]+=\"%\",m(d,!1)),c[1]):b}if(1==a){var d=this.getDialog(),e=\"\",f=\"txtWidth\"==this.id?\"width\":\"height\",g=b.getAttribute(f);g&&(e=c(g,e));e=c(b.getStyle(f),e);this.setValue(e)}},w,t=function(){var a=this.originalElement,b=CKEDITOR.document.getById(n);a.setCustomData(\"isReady\",\"true\");a.removeListener(\"load\",t);a.removeListener(\"error\",f);a.removeListener(\"abort\",f);b&&b.setStyle(\"display\",\"none\");this.dontResetSize||A(this,!1===d.config.image_prefillDimensions);this.firstLoad&&CKEDITOR.tools.setTimeout(function(){m(this,\n\"check\")},0,this);this.dontResetSize=this.firstLoad=!1;e(this)},f=function(){var a=this.originalElement,b=CKEDITOR.document.getById(n);a.removeListener(\"load\",t);a.removeListener(\"error\",f);a.removeListener(\"abort\",f);a=CKEDITOR.getUrl(CKEDITOR.plugins.get(\"image\").path+\"images/noimage.png\");this.preview&&this.preview.setAttribute(\"src\",a);b&&b.setStyle(\"display\",\"none\");m(this,!1)},p=function(a){return CKEDITOR.tools.getNextId()+\"_\"+a},r=p(\"btnLockSizes\"),x=p(\"btnResetSize\"),n=p(\"ImagePreviewLoader\"),\nD=p(\"previewLink\"),C=p(\"previewImage\");return{title:d.lang.image[\"image\"==k?\"title\":\"titleButton\"],minWidth:\"moono-lisa\"==(CKEDITOR.skinName||d.config.skin)?500:420,minHeight:360,onShow:function(){this.linkEditMode=this.imageEditMode=this.linkElement=this.imageElement=!1;this.lockRatio=!0;this.userlockRatio=0;this.dontResetSize=!1;this.firstLoad=!0;this.addLink=!1;var a=this.getParentEditor(),b=a.getSelection(),c=(b=b&&b.getSelectedElement())&&a.elementPath(b).contains(\"a\",1),d=CKEDITOR.document.getById(n);\nd&&d.setStyle(\"display\",\"none\");w=new CKEDITOR.dom.element(\"img\",a.document);this.preview=CKEDITOR.document.getById(C);this.originalElement=a.document.createElement(\"img\");this.originalElement.setAttribute(\"alt\",\"\");this.originalElement.setCustomData(\"isReady\",\"false\");c&&(this.linkElement=c,this.addLink=this.linkEditMode=!0,a=c.getChildren(),1==a.count()&&(d=a.getItem(0),d.type==CKEDITOR.NODE_ELEMENT&&(d.is(\"img\")||d.is(\"input\"))&&(this.imageElement=a.getItem(0),this.imageElement.is(\"img\")?this.imageEditMode=\n\"img\":this.imageElement.is(\"input\")&&(this.imageEditMode=\"input\"))),\"image\"==k&&this.setupContent(2,c));if(this.customImageElement)this.imageEditMode=\"img\",this.imageElement=this.customImageElement,delete this.customImageElement;else if(b&&\"img\"==b.getName()&&!b.data(\"cke-realelement\")||b&&\"input\"==b.getName()&&\"image\"==b.getAttribute(\"type\"))this.imageEditMode=b.getName(),this.imageElement=b;this.imageEditMode&&(this.cleanImageElement=this.imageElement,this.imageElement=this.cleanImageElement.clone(!0,\n!0),this.setupContent(1,this.imageElement));m(this,!0);CKEDITOR.tools.trim(this.getValueOf(\"info\",\"txtUrl\"))||(this.preview.removeAttribute(\"src\"),this.preview.setStyle(\"display\",\"none\"))},onOk:function(){if(this.imageEditMode){var a=this.imageEditMode;\"image\"==k&&\"input\"==a&&confirm(d.lang.image.button2Img)?(this.imageElement=d.document.createElement(\"img\"),this.imageElement.setAttribute(\"alt\",\"\"),d.insertElement(this.imageElement)):\"image\"!=k&&\"img\"==a&&confirm(d.lang.image.img2Button)?(this.imageElement=\nd.document.createElement(\"input\"),this.imageElement.setAttributes({type:\"image\",alt:\"\"}),d.insertElement(this.imageElement)):(this.imageElement=this.cleanImageElement,delete this.cleanImageElement)}else\"image\"==k?this.imageElement=d.document.createElement(\"img\"):(this.imageElement=d.document.createElement(\"input\"),this.imageElement.setAttribute(\"type\",\"image\")),this.imageElement.setAttribute(\"alt\",\"\");this.linkEditMode||(this.linkElement=d.document.createElement(\"a\"));this.commitContent(1,this.imageElement);\nthis.commitContent(2,this.linkElement);this.imageElement.getAttribute(\"style\")||this.imageElement.removeAttribute(\"style\");this.imageEditMode?!this.linkEditMode&&this.addLink?(d.insertElement(this.linkElement),this.imageElement.appendTo(this.linkElement)):this.linkEditMode&&!this.addLink&&(d.getSelection().selectElement(this.linkElement),d.insertElement(this.imageElement)):this.addLink?this.linkEditMode?this.linkElement.equals(d.getSelection().getSelectedElement())?(this.linkElement.setHtml(\"\"),this.linkElement.append(this.imageElement,\n!1)):d.insertElement(this.imageElement):(d.insertElement(this.linkElement),this.linkElement.append(this.imageElement,!1)):d.insertElement(this.imageElement)},onLoad:function(){\"image\"!=k&&this.hidePage(\"Link\");var a=this._.element.getDocument();this.getContentElement(\"info\",\"ratioLock\")&&(this.addFocusable(a.getById(x),5),this.addFocusable(a.getById(r),5));this.commitContent=u},onHide:function(){this.preview&&this.commitContent(8,this.preview);this.originalElement&&(this.originalElement.removeListener(\"load\",\nt),this.originalElement.removeListener(\"error\",f),this.originalElement.removeListener(\"abort\",f),this.originalElement.remove(),this.originalElement=!1);delete this.imageElement},contents:[{id:\"info\",label:d.lang.image.infoTab,accessKey:\"I\",elements:[{type:\"vbox\",padding:0,children:[{type:\"hbox\",widths:[\"280px\",\"110px\"],align:\"right\",className:\"cke_dialog_image_url\",children:[{id:\"txtUrl\",type:\"text\",label:d.lang.common.url,required:!0,onChange:function(){var a=this.getDialog(),b=this.getValue();if(0<\nb.length){var a=this.getDialog(),c=a.originalElement;a.preview&&a.preview.removeStyle(\"display\");c.setCustomData(\"isReady\",\"false\");var d=CKEDITOR.document.getById(n);d&&d.setStyle(\"display\",\"\");c.on(\"load\",t,a);c.on(\"error\",f,a);c.on(\"abort\",f,a);c.setAttribute(\"src\",b);a.preview&&(w.setAttribute(\"src\",b),a.preview.setAttribute(\"src\",w.$.src),e(a))}else a.preview&&(a.preview.removeAttribute(\"src\"),a.preview.setStyle(\"display\",\"none\"))},setup:function(a,b){if(1==a){var c=b.data(\"cke-saved-src\")||\nb.getAttribute(\"src\");this.getDialog().dontResetSize=!0;this.setValue(c);this.setInitValue()}},commit:function(a,b){1==a&&(this.getValue()||this.isChanged())?(b.data(\"cke-saved-src\",this.getValue()),b.setAttribute(\"src\",this.getValue())):8==a&&(b.setAttribute(\"src\",\"\"),b.removeAttribute(\"src\"))},validate:CKEDITOR.dialog.validate.notEmpty(d.lang.image.urlMissing)},{type:\"button\",id:\"browse\",style:\"display:inline-block;margin-top:14px;\",align:\"center\",label:d.lang.common.browseServer,hidden:!0,filebrowser:\"info:txtUrl\"}]}]},\n{id:\"txtAlt\",type:\"text\",label:d.lang.image.alt,accessKey:\"T\",\"default\":\"\",onChange:function(){e(this.getDialog())},setup:function(a,b){1==a&&this.setValue(b.getAttribute(\"alt\"))},commit:function(a,b){1==a?(this.getValue()||this.isChanged())&&b.setAttribute(\"alt\",this.getValue()):4==a?b.setAttribute(\"alt\",this.getValue()):8==a&&b.removeAttribute(\"alt\")}},{type:\"hbox\",children:[{id:\"basic\",type:\"vbox\",children:[{type:\"hbox\",requiredContent:\"img{width,height}\",widths:[\"50%\",\"50%\"],children:[{type:\"vbox\",\npadding:1,children:[{type:\"text\",width:\"45px\",id:\"txtWidth\",label:d.lang.common.width,onKeyUp:z,onChange:function(){g.call(this,\"advanced:txtdlgGenStyle\")},validate:function(){var a=this.getValue().match(y);(a=!(!a||0===parseInt(a[1],10)))||alert(d.lang.common.invalidLength.replace(\"%1\",d.lang.common.width).replace(\"%2\",\"px, %\"));return a},setup:B,commit:function(a,b){var c=this.getValue();1==a?(c&&d.activeFilter.check(\"img{width,height}\")?b.setStyle(\"width\",CKEDITOR.tools.cssLength(c)):b.removeStyle(\"width\"),\nb.removeAttribute(\"width\")):4==a?c.match(l)?b.setStyle(\"width\",CKEDITOR.tools.cssLength(c)):(c=this.getDialog().originalElement,\"true\"==c.getCustomData(\"isReady\")&&b.setStyle(\"width\",c.$.width+\"px\")):8==a&&(b.removeAttribute(\"width\"),b.removeStyle(\"width\"))}},{type:\"text\",id:\"txtHeight\",width:\"45px\",label:d.lang.common.height,onKeyUp:z,onChange:function(){g.call(this,\"advanced:txtdlgGenStyle\")},validate:function(){var a=this.getValue().match(y);(a=!(!a||0===parseInt(a[1],10)))||alert(d.lang.common.invalidLength.replace(\"%1\",\nd.lang.common.height).replace(\"%2\",\"px, %\"));return a},setup:B,commit:function(a,b){var c=this.getValue();1==a?(c&&d.activeFilter.check(\"img{width,height}\")?b.setStyle(\"height\",CKEDITOR.tools.cssLength(c)):b.removeStyle(\"height\"),b.removeAttribute(\"height\")):4==a?c.match(l)?b.setStyle(\"height\",CKEDITOR.tools.cssLength(c)):(c=this.getDialog().originalElement,\"true\"==c.getCustomData(\"isReady\")&&b.setStyle(\"height\",c.$.height+\"px\")):8==a&&(b.removeAttribute(\"height\"),b.removeStyle(\"height\"))}}]},{id:\"ratioLock\",\ntype:\"html\",className:\"cke_dialog_image_ratiolock\",style:\"margin-top:30px;width:40px;height:40px;\",onLoad:function(){var a=CKEDITOR.document.getById(x),b=CKEDITOR.document.getById(r);a&&(a.on(\"click\",function(a){A(this);a.data&&a.data.preventDefault()},this.getDialog()),a.on(\"mouseover\",function(){this.addClass(\"cke_btn_over\")},a),a.on(\"mouseout\",function(){this.removeClass(\"cke_btn_over\")},a));b&&(b.on(\"click\",function(a){m(this);var b=this.originalElement,d=this.getValueOf(\"info\",\"txtWidth\");\"true\"==\nb.getCustomData(\"isReady\")&&d&&(b=b.$.height/b.$.width*d,isNaN(b)||(this.setValueOf(\"info\",\"txtHeight\",Math.round(b)),e(this)));a.data&&a.data.preventDefault()},this.getDialog()),b.on(\"mouseover\",function(){this.addClass(\"cke_btn_over\")},b),b.on(\"mouseout\",function(){this.removeClass(\"cke_btn_over\")},b))},html:'\\x3cdiv\\x3e\\x3ca href\\x3d\"javascript:void(0)\" tabindex\\x3d\"-1\" title\\x3d\"'+d.lang.image.lockRatio+'\" class\\x3d\"cke_btn_locked\" id\\x3d\"'+r+'\" role\\x3d\"checkbox\"\\x3e\\x3cspan class\\x3d\"cke_icon\"\\x3e\\x3c/span\\x3e\\x3cspan class\\x3d\"cke_label\"\\x3e'+\nd.lang.image.lockRatio+'\\x3c/span\\x3e\\x3c/a\\x3e\\x3ca href\\x3d\"javascript:void(0)\" tabindex\\x3d\"-1\" title\\x3d\"'+d.lang.image.resetSize+'\" class\\x3d\"cke_btn_reset\" id\\x3d\"'+x+'\" role\\x3d\"button\"\\x3e\\x3cspan class\\x3d\"cke_label\"\\x3e'+d.lang.image.resetSize+\"\\x3c/span\\x3e\\x3c/a\\x3e\\x3c/div\\x3e\"}]},{type:\"vbox\",padding:1,children:[{type:\"text\",id:\"txtBorder\",requiredContent:\"img{border-width}\",width:\"60px\",label:d.lang.image.border,\"default\":\"\",onKeyUp:function(){e(this.getDialog())},onChange:function(){g.call(this,\n\"advanced:txtdlgGenStyle\")},validate:CKEDITOR.dialog.validate.integer(d.lang.image.validateBorder),setup:function(a,b){if(1==a){var c;c=(c=(c=b.getStyle(\"border-width\"))&&c.match(/^(\\d+px)(?: \\1 \\1 \\1)?$/))&&parseInt(c[1],10);isNaN(parseInt(c,10))&&(c=b.getAttribute(\"border\"));this.setValue(c)}},commit:function(a,b){var c=parseInt(this.getValue(),10);1==a||4==a?(isNaN(c)?!c&&this.isChanged()&&b.removeStyle(\"border\"):(b.setStyle(\"border-width\",CKEDITOR.tools.cssLength(c)),b.setStyle(\"border-style\",\n\"solid\")),1==a&&b.removeAttribute(\"border\")):8==a&&(b.removeAttribute(\"border\"),b.removeStyle(\"border-width\"),b.removeStyle(\"border-style\"),b.removeStyle(\"border-color\"))}},{type:\"text\",id:\"txtHSpace\",requiredContent:\"img{margin-left,margin-right}\",width:\"60px\",label:d.lang.image.hSpace,\"default\":\"\",onKeyUp:function(){e(this.getDialog())},onChange:function(){g.call(this,\"advanced:txtdlgGenStyle\")},validate:CKEDITOR.dialog.validate.integer(d.lang.image.validateHSpace),setup:function(a,b){if(1==a){var c,\nd;c=b.getStyle(\"margin-left\");d=b.getStyle(\"margin-right\");c=c&&c.match(q);d=d&&d.match(q);c=parseInt(c,10);d=parseInt(d,10);c=c==d&&c;isNaN(parseInt(c,10))&&(c=b.getAttribute(\"hspace\"));this.setValue(c)}},commit:function(a,b){var c=parseInt(this.getValue(),10);1==a||4==a?(isNaN(c)?!c&&this.isChanged()&&(b.removeStyle(\"margin-left\"),b.removeStyle(\"margin-right\")):(b.setStyle(\"margin-left\",CKEDITOR.tools.cssLength(c)),b.setStyle(\"margin-right\",CKEDITOR.tools.cssLength(c))),1==a&&b.removeAttribute(\"hspace\")):\n8==a&&(b.removeAttribute(\"hspace\"),b.removeStyle(\"margin-left\"),b.removeStyle(\"margin-right\"))}},{type:\"text\",id:\"txtVSpace\",requiredContent:\"img{margin-top,margin-bottom}\",width:\"60px\",label:d.lang.image.vSpace,\"default\":\"\",onKeyUp:function(){e(this.getDialog())},onChange:function(){g.call(this,\"advanced:txtdlgGenStyle\")},validate:CKEDITOR.dialog.validate.integer(d.lang.image.validateVSpace),setup:function(a,b){if(1==a){var c,d;c=b.getStyle(\"margin-top\");d=b.getStyle(\"margin-bottom\");c=c&&c.match(q);\nd=d&&d.match(q);c=parseInt(c,10);d=parseInt(d,10);c=c==d&&c;isNaN(parseInt(c,10))&&(c=b.getAttribute(\"vspace\"));this.setValue(c)}},commit:function(a,b){var c=parseInt(this.getValue(),10);1==a||4==a?(isNaN(c)?!c&&this.isChanged()&&(b.removeStyle(\"margin-top\"),b.removeStyle(\"margin-bottom\")):(b.setStyle(\"margin-top\",CKEDITOR.tools.cssLength(c)),b.setStyle(\"margin-bottom\",CKEDITOR.tools.cssLength(c))),1==a&&b.removeAttribute(\"vspace\")):8==a&&(b.removeAttribute(\"vspace\"),b.removeStyle(\"margin-top\"),b.removeStyle(\"margin-bottom\"))}},\n{id:\"cmbAlign\",requiredContent:\"img{float}\",type:\"select\",widths:[\"35%\",\"65%\"],style:\"width:90px\",label:d.lang.common.align,\"default\":\"\",items:[[d.lang.common.notSet,\"\"],[d.lang.common.left,\"left\"],[d.lang.common.right,\"right\"]],onChange:function(){e(this.getDialog());g.call(this,\"advanced:txtdlgGenStyle\")},setup:function(a,b){if(1==a){var c=b.getStyle(\"float\");switch(c){case \"inherit\":case \"none\":c=\"\"}!c&&(c=(b.getAttribute(\"align\")||\"\").toLowerCase());this.setValue(c)}},commit:function(a,b){var c=\nthis.getValue();if(1==a||4==a){if(c?b.setStyle(\"float\",c):b.removeStyle(\"float\"),1==a)switch(c=(b.getAttribute(\"align\")||\"\").toLowerCase(),c){case \"left\":case \"right\":b.removeAttribute(\"align\")}}else 8==a&&b.removeStyle(\"float\")}}]}]},{type:\"vbox\",height:\"250px\",children:[{type:\"html\",id:\"htmlPreview\",style:\"width:95%;\",html:\"\\x3cdiv\\x3e\"+CKEDITOR.tools.htmlEncode(d.lang.common.preview)+'\\x3cbr\\x3e\\x3cdiv id\\x3d\"'+n+'\" class\\x3d\"ImagePreviewLoader\" style\\x3d\"display:none\"\\x3e\\x3cdiv class\\x3d\"loading\"\\x3e\\x26nbsp;\\x3c/div\\x3e\\x3c/div\\x3e\\x3cdiv class\\x3d\"ImagePreviewBox\"\\x3e\\x3ctable\\x3e\\x3ctr\\x3e\\x3ctd\\x3e\\x3ca href\\x3d\"javascript:void(0)\" target\\x3d\"_blank\" onclick\\x3d\"return false;\" id\\x3d\"'+\nD+'\"\\x3e\\x3cimg id\\x3d\"'+C+'\" alt\\x3d\"\" /\\x3e\\x3c/a\\x3e'+(d.config.image_previewText||\"Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas feugiat consequat diam. Maecenas metus. Vivamus diam purus, cursus a, commodo non, facilisis vitae, nulla. Aenean dictum lacinia tortor. Nunc iaculis, nibh non iaculis aliquam, orci felis euismod neque, sed ornare massa mauris sed velit. Nulla pretium mi et risus. Fusce mi pede, tempor id, cursus ac, ullamcorper nec, enim. Sed tortor. Curabitur molestie. Duis velit augue, condimentum at, ultrices a, luctus ut, orci. Donec pellentesque egestas eros. Integer cursus, augue in cursus faucibus, eros pede bibendum sem, in tempus tellus justo quis ligula. Etiam eget tortor. Vestibulum rutrum, est ut placerat elementum, lectus nisl aliquam velit, tempor aliquam eros nunc nonummy metus. In eros metus, gravida a, gravida sed, lobortis id, turpis. Ut ultrices, ipsum at venenatis fringilla, sem nulla lacinia tellus, eget aliquet turpis mauris non enim. Nam turpis. Suspendisse lacinia. Curabitur ac tortor ut ipsum egestas elementum. Nunc imperdiet gravida mauris.\")+\n\"\\x3c/td\\x3e\\x3c/tr\\x3e\\x3c/table\\x3e\\x3c/div\\x3e\\x3c/div\\x3e\"}]}]}]},{id:\"Link\",requiredContent:\"a[href]\",label:d.lang.image.linkTab,padding:0,elements:[{id:\"txtUrl\",type:\"text\",label:d.lang.common.url,style:\"width: 100%\",\"default\":\"\",setup:function(a,b){if(2==a){var c=b.data(\"cke-saved-href\");c||(c=b.getAttribute(\"href\"));this.setValue(c)}},commit:function(a,b){if(2==a&&(this.getValue()||this.isChanged())){var c=this.getValue();b.data(\"cke-saved-href\",c);b.setAttribute(\"href\",c);this.getValue()||\n!d.config.image_removeLinkByEmptyURL?this.getDialog().addLink=!0:this.getDialog().addLink=!1}}},{type:\"button\",id:\"browse\",className:\"cke_dialog_image_browse\",filebrowser:{action:\"Browse\",target:\"Link:txtUrl\",url:d.config.filebrowserImageBrowseLinkUrl},style:\"float:right\",hidden:!0,label:d.lang.common.browseServer},{id:\"cmbTarget\",type:\"select\",requiredContent:\"a[target]\",label:d.lang.common.target,\"default\":\"\",items:[[d.lang.common.notSet,\"\"],[d.lang.common.targetNew,\"_blank\"],[d.lang.common.targetTop,\n\"_top\"],[d.lang.common.targetSelf,\"_self\"],[d.lang.common.targetParent,\"_parent\"]],setup:function(a,b){2==a&&this.setValue(b.getAttribute(\"target\")||\"\")},commit:function(a,b){2==a&&(this.getValue()||this.isChanged())&&b.setAttribute(\"target\",this.getValue())}}]},{id:\"Upload\",hidden:!0,filebrowser:\"uploadButton\",label:d.lang.image.upload,elements:[{type:\"file\",id:\"upload\",label:d.lang.image.btnUpload,style:\"height:40px\",size:38},{type:\"fileButton\",id:\"uploadButton\",filebrowser:\"info:txtUrl\",label:d.lang.image.btnUpload,\n\"for\":[\"Upload\",\"upload\"]}]},{id:\"advanced\",label:d.lang.common.advancedTab,elements:[{type:\"hbox\",widths:[\"50%\",\"25%\",\"25%\"],children:[{type:\"text\",id:\"linkId\",requiredContent:\"img[id]\",label:d.lang.common.id,setup:function(a,b){1==a&&this.setValue(b.getAttribute(\"id\"))},commit:function(a,b){1==a&&(this.getValue()||this.isChanged())&&b.setAttribute(\"id\",this.getValue())}},{id:\"cmbLangDir\",type:\"select\",requiredContent:\"img[dir]\",style:\"width : 100px;\",label:d.lang.common.langDir,\"default\":\"\",items:[[d.lang.common.notSet,\n\"\"],[d.lang.common.langDirLtr,\"ltr\"],[d.lang.common.langDirRtl,\"rtl\"]],setup:function(a,b){1==a&&this.setValue(b.getAttribute(\"dir\"))},commit:function(a,b){1==a&&(this.getValue()||this.isChanged())&&b.setAttribute(\"dir\",this.getValue())}},{type:\"text\",id:\"txtLangCode\",requiredContent:\"img[lang]\",label:d.lang.common.langCode,\"default\":\"\",setup:function(a,b){1==a&&this.setValue(b.getAttribute(\"lang\"))},commit:function(a,b){1==a&&(this.getValue()||this.isChanged())&&b.setAttribute(\"lang\",this.getValue())}}]},\n{type:\"text\",id:\"txtGenLongDescr\",requiredContent:\"img[longdesc]\",label:d.lang.common.longDescr,setup:function(a,b){1==a&&this.setValue(b.getAttribute(\"longDesc\"))},commit:function(a,b){1==a&&(this.getValue()||this.isChanged())&&b.setAttribute(\"longDesc\",this.getValue())}},{type:\"hbox\",widths:[\"50%\",\"50%\"],children:[{type:\"text\",id:\"txtGenClass\",requiredContent:\"img(cke-xyz)\",label:d.lang.common.cssClass,\"default\":\"\",setup:function(a,b){1==a&&this.setValue(b.getAttribute(\"class\"))},commit:function(a,\nb){1==a&&(this.getValue()||this.isChanged())&&b.setAttribute(\"class\",this.getValue())}},{type:\"text\",id:\"txtGenTitle\",requiredContent:\"img[title]\",label:d.lang.common.advisoryTitle,\"default\":\"\",onChange:function(){e(this.getDialog())},setup:function(a,b){1==a&&this.setValue(b.getAttribute(\"title\"))},commit:function(a,b){1==a?(this.getValue()||this.isChanged())&&b.setAttribute(\"title\",this.getValue()):4==a?b.setAttribute(\"title\",this.getValue()):8==a&&b.removeAttribute(\"title\")}}]},{type:\"text\",id:\"txtdlgGenStyle\",\nrequiredContent:\"img{cke-xyz}\",label:d.lang.common.cssStyle,validate:CKEDITOR.dialog.validate.inlineStyle(d.lang.common.invalidInlineStyle),\"default\":\"\",setup:function(a,b){if(1==a){var c=b.getAttribute(\"style\");!c&&b.$.style.cssText&&(c=b.$.style.cssText);this.setValue(c);var d=b.$.style.height,c=b.$.style.width,d=(d?d:\"\").match(l),c=(c?c:\"\").match(l);this.attributesInStyle={height:!!d,width:!!c}}},onChange:function(){g.call(this,\"info:cmbFloat info:cmbAlign info:txtVSpace info:txtHSpace info:txtBorder info:txtWidth info:txtHeight\".split(\" \"));\ne(this)},commit:function(a,b){1==a&&(this.getValue()||this.isChanged())&&b.setAttribute(\"style\",this.getValue())}}]}]}};CKEDITOR.dialog.add(\"image\",function(d){return u(d,\"image\")});CKEDITOR.dialog.add(\"imagebutton\",function(d){return u(d,\"imagebutton\")})})();"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/adminlte/bower_components/ckeditor/plugins/link/dialogs/anchor.js",
    "content": "﻿/*\n Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.\n For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n*/\nCKEDITOR.dialog.add(\"anchor\",function(c){function e(b,a){return b.createFakeElement(b.document.createElement(\"a\",{attributes:a}),\"cke_anchor\",\"anchor\")}return{title:c.lang.link.anchor.title,minWidth:300,minHeight:60,onOk:function(){var b=CKEDITOR.tools.trim(this.getValueOf(\"info\",\"txtName\")),a={id:b,name:b,\"data-cke-saved-name\":b};this._.selectedElement?this._.selectedElement.data(\"cke-realelement\")?(b=e(c,a),b.replace(this._.selectedElement),CKEDITOR.env.ie&&c.getSelection().selectElement(b)):this._.selectedElement.setAttributes(a):\n(b=(b=c.getSelection())&&b.getRanges()[0],b.collapsed?(a=e(c,a),b.insertNode(a)):(CKEDITOR.env.ie&&9>CKEDITOR.env.version&&(a[\"class\"]=\"cke_anchor\"),a=new CKEDITOR.style({element:\"a\",attributes:a}),a.type=CKEDITOR.STYLE_INLINE,a.applyToRange(b)))},onHide:function(){delete this._.selectedElement},onShow:function(){var b=c.getSelection(),a;a=b.getRanges()[0];var d=b.getSelectedElement();a.shrink(CKEDITOR.SHRINK_ELEMENT);a=(d=a.getEnclosedNode())&&d.type===CKEDITOR.NODE_ELEMENT&&(\"anchor\"===d.data(\"cke-real-element-type\")||\nd.is(\"a\"))?d:void 0;var f=(d=a&&a.data(\"cke-realelement\"))?CKEDITOR.plugins.link.tryRestoreFakeAnchor(c,a):CKEDITOR.plugins.link.getSelectedLink(c);if(f){this._.selectedElement=f;var e=f.data(\"cke-saved-name\");this.setValueOf(\"info\",\"txtName\",e||\"\");!d&&b.selectElement(f);a&&(this._.selectedElement=a)}this.getContentElement(\"info\",\"txtName\").focus()},contents:[{id:\"info\",label:c.lang.link.anchor.title,accessKey:\"I\",elements:[{type:\"text\",id:\"txtName\",label:c.lang.link.anchor.name,required:!0,validate:function(){return this.getValue()?\n!0:(alert(c.lang.link.anchor.errorName),!1)}}]}]}});"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/adminlte/bower_components/ckeditor/plugins/link/dialogs/link.js",
    "content": "﻿/*\n Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.\n For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n*/\n(function(){function u(){var c=this.getDialog(),p=c._.editor,n=p.config.linkPhoneRegExp,q=p.config.linkPhoneMsg,p=CKEDITOR.dialog.validate.notEmpty(p.lang.link.noTel).apply(this);if(!c.getContentElement(\"info\",\"linkType\")||\"tel\"!=c.getValueOf(\"info\",\"linkType\"))return!0;if(!0!==p)return p;if(n)return CKEDITOR.dialog.validate.regex(n,q).call(this)}CKEDITOR.dialog.add(\"link\",function(c){function p(a,b){var c=a.createRange();c.setStartBefore(b);c.setEndAfter(b);return c}var n=CKEDITOR.plugins.link,q,\nt=function(){var a=this.getDialog(),b=a.getContentElement(\"target\",\"popupFeatures\"),a=a.getContentElement(\"target\",\"linkTargetName\"),r=this.getValue();if(b&&a)switch(b=b.getElement(),b.hide(),a.setValue(\"\"),r){case \"frame\":a.setLabel(c.lang.link.targetFrameName);a.getElement().show();break;case \"popup\":b.show();a.setLabel(c.lang.link.targetPopupName);a.getElement().show();break;default:a.setValue(r),a.getElement().hide()}},l=function(a){a.target&&this.setValue(a.target[this.id]||\"\")},e=function(a){a.advanced&&\nthis.setValue(a.advanced[this.id]||\"\")},k=function(a){a.target||(a.target={});a.target[this.id]=this.getValue()||\"\"},m=function(a){a.advanced||(a.advanced={});a.advanced[this.id]=this.getValue()||\"\"},g=c.lang.common,b=c.lang.link,d;return{title:b.title,minWidth:\"moono-lisa\"==(CKEDITOR.skinName||c.config.skin)?450:350,minHeight:240,contents:[{id:\"info\",label:b.info,title:b.info,elements:[{type:\"text\",id:\"linkDisplayText\",label:b.displayText,setup:function(){this.enable();this.setValue(c.getSelection().getSelectedText());\nq=this.getValue()},commit:function(a){a.linkText=this.isEnabled()?this.getValue():\"\"}},{id:\"linkType\",type:\"select\",label:b.type,\"default\":\"url\",items:[[b.toUrl,\"url\"],[b.toAnchor,\"anchor\"],[b.toEmail,\"email\"],[b.toPhone,\"tel\"]],onChange:function(){var a=this.getDialog(),b=[\"urlOptions\",\"anchorOptions\",\"emailOptions\",\"telOptions\"],r=this.getValue(),f=a.definition.getContents(\"upload\"),f=f&&f.hidden;\"url\"==r?(c.config.linkShowTargetTab&&a.showPage(\"target\"),f||a.showPage(\"upload\")):(a.hidePage(\"target\"),\nf||a.hidePage(\"upload\"));for(f=0;f<b.length;f++){var h=a.getContentElement(\"info\",b[f]);h&&(h=h.getElement().getParent().getParent(),b[f]==r+\"Options\"?h.show():h.hide())}a.layout()},setup:function(a){this.setValue(a.type||\"url\")},commit:function(a){a.type=this.getValue()}},{type:\"vbox\",id:\"urlOptions\",children:[{type:\"hbox\",widths:[\"25%\",\"75%\"],children:[{id:\"protocol\",type:\"select\",label:g.protocol,\"default\":\"http://\",items:[[\"http://‎\",\"http://\"],[\"https://‎\",\"https://\"],[\"ftp://‎\",\"ftp://\"],[\"news://‎\",\n\"news://\"],[b.other,\"\"]],setup:function(a){a.url&&this.setValue(a.url.protocol||\"\")},commit:function(a){a.url||(a.url={});a.url.protocol=this.getValue()}},{type:\"text\",id:\"url\",label:g.url,required:!0,onLoad:function(){this.allowOnChange=!0},onKeyUp:function(){this.allowOnChange=!1;var a=this.getDialog().getContentElement(\"info\",\"protocol\"),b=this.getValue(),c=/^((javascript:)|[#\\/\\.\\?])/i,f=/^(http|https|ftp|news):\\/\\/(?=.)/i.exec(b);f?(this.setValue(b.substr(f[0].length)),a.setValue(f[0].toLowerCase())):\nc.test(b)&&a.setValue(\"\");this.allowOnChange=!0},onChange:function(){if(this.allowOnChange)this.onKeyUp()},validate:function(){var a=this.getDialog();return a.getContentElement(\"info\",\"linkType\")&&\"url\"!=a.getValueOf(\"info\",\"linkType\")?!0:!c.config.linkJavaScriptLinksAllowed&&/javascript\\:/.test(this.getValue())?(alert(g.invalidValue),!1):this.getDialog().fakeObj?!0:CKEDITOR.dialog.validate.notEmpty(b.noUrl).apply(this)},setup:function(a){this.allowOnChange=!1;a.url&&this.setValue(a.url.url);this.allowOnChange=\n!0},commit:function(a){this.onChange();a.url||(a.url={});a.url.url=this.getValue();this.allowOnChange=!1}}],setup:function(){this.getDialog().getContentElement(\"info\",\"linkType\")||this.getElement().show()}},{type:\"button\",id:\"browse\",hidden:\"true\",filebrowser:\"info:url\",label:g.browseServer}]},{type:\"vbox\",id:\"anchorOptions\",width:260,align:\"center\",padding:0,children:[{type:\"fieldset\",id:\"selectAnchorText\",label:b.selectAnchor,setup:function(){d=n.getEditorAnchors(c);this.getElement()[d&&d.length?\n\"show\":\"hide\"]()},children:[{type:\"hbox\",id:\"selectAnchor\",children:[{type:\"select\",id:\"anchorName\",\"default\":\"\",label:b.anchorName,style:\"width: 100%;\",items:[[\"\"]],setup:function(a){this.clear();this.add(\"\");if(d)for(var b=0;b<d.length;b++)d[b].name&&this.add(d[b].name);a.anchor&&this.setValue(a.anchor.name);(a=this.getDialog().getContentElement(\"info\",\"linkType\"))&&\"email\"==a.getValue()&&this.focus()},commit:function(a){a.anchor||(a.anchor={});a.anchor.name=this.getValue()}},{type:\"select\",id:\"anchorId\",\n\"default\":\"\",label:b.anchorId,style:\"width: 100%;\",items:[[\"\"]],setup:function(a){this.clear();this.add(\"\");if(d)for(var b=0;b<d.length;b++)d[b].id&&this.add(d[b].id);a.anchor&&this.setValue(a.anchor.id)},commit:function(a){a.anchor||(a.anchor={});a.anchor.id=this.getValue()}}],setup:function(){this.getElement()[d&&d.length?\"show\":\"hide\"]()}}]},{type:\"html\",id:\"noAnchors\",style:\"text-align: center;\",html:'\\x3cdiv role\\x3d\"note\" tabIndex\\x3d\"-1\"\\x3e'+CKEDITOR.tools.htmlEncode(b.noAnchors)+\"\\x3c/div\\x3e\",\nfocus:!0,setup:function(){this.getElement()[d&&d.length?\"hide\":\"show\"]()}}],setup:function(){this.getDialog().getContentElement(\"info\",\"linkType\")||this.getElement().hide()}},{type:\"vbox\",id:\"emailOptions\",padding:1,children:[{type:\"text\",id:\"emailAddress\",label:b.emailAddress,required:!0,validate:function(){var a=this.getDialog();return a.getContentElement(\"info\",\"linkType\")&&\"email\"==a.getValueOf(\"info\",\"linkType\")?CKEDITOR.dialog.validate.notEmpty(b.noEmail).apply(this):!0},setup:function(a){a.email&&\nthis.setValue(a.email.address);(a=this.getDialog().getContentElement(\"info\",\"linkType\"))&&\"email\"==a.getValue()&&this.select()},commit:function(a){a.email||(a.email={});a.email.address=this.getValue()}},{type:\"text\",id:\"emailSubject\",label:b.emailSubject,setup:function(a){a.email&&this.setValue(a.email.subject)},commit:function(a){a.email||(a.email={});a.email.subject=this.getValue()}},{type:\"textarea\",id:\"emailBody\",label:b.emailBody,rows:3,\"default\":\"\",setup:function(a){a.email&&this.setValue(a.email.body)},\ncommit:function(a){a.email||(a.email={});a.email.body=this.getValue()}}],setup:function(){this.getDialog().getContentElement(\"info\",\"linkType\")||this.getElement().hide()}},{type:\"vbox\",id:\"telOptions\",padding:1,children:[{type:\"tel\",id:\"telNumber\",label:b.phoneNumber,required:!0,validate:u,setup:function(a){a.tel&&this.setValue(a.tel);(a=this.getDialog().getContentElement(\"info\",\"linkType\"))&&\"tel\"==a.getValue()&&this.select()},commit:function(a){a.tel=this.getValue()}}],setup:function(){this.getDialog().getContentElement(\"info\",\n\"linkType\")||this.getElement().hide()}}]},{id:\"target\",requiredContent:\"a[target]\",label:b.target,title:b.target,elements:[{type:\"hbox\",widths:[\"50%\",\"50%\"],children:[{type:\"select\",id:\"linkTargetType\",label:g.target,\"default\":\"notSet\",style:\"width : 100%;\",items:[[g.notSet,\"notSet\"],[b.targetFrame,\"frame\"],[b.targetPopup,\"popup\"],[g.targetNew,\"_blank\"],[g.targetTop,\"_top\"],[g.targetSelf,\"_self\"],[g.targetParent,\"_parent\"]],onChange:t,setup:function(a){a.target&&this.setValue(a.target.type||\"notSet\");\nt.call(this)},commit:function(a){a.target||(a.target={});a.target.type=this.getValue()}},{type:\"text\",id:\"linkTargetName\",label:b.targetFrameName,\"default\":\"\",setup:function(a){a.target&&this.setValue(a.target.name)},commit:function(a){a.target||(a.target={});a.target.name=this.getValue().replace(/([^\\x00-\\x7F]|\\s)/gi,\"\")}}]},{type:\"vbox\",width:\"100%\",align:\"center\",padding:2,id:\"popupFeatures\",children:[{type:\"fieldset\",label:b.popupFeatures,children:[{type:\"hbox\",children:[{type:\"checkbox\",id:\"resizable\",\nlabel:b.popupResizable,setup:l,commit:k},{type:\"checkbox\",id:\"status\",label:b.popupStatusBar,setup:l,commit:k}]},{type:\"hbox\",children:[{type:\"checkbox\",id:\"location\",label:b.popupLocationBar,setup:l,commit:k},{type:\"checkbox\",id:\"toolbar\",label:b.popupToolbar,setup:l,commit:k}]},{type:\"hbox\",children:[{type:\"checkbox\",id:\"menubar\",label:b.popupMenuBar,setup:l,commit:k},{type:\"checkbox\",id:\"fullscreen\",label:b.popupFullScreen,setup:l,commit:k}]},{type:\"hbox\",children:[{type:\"checkbox\",id:\"scrollbars\",\nlabel:b.popupScrollBars,setup:l,commit:k},{type:\"checkbox\",id:\"dependent\",label:b.popupDependent,setup:l,commit:k}]},{type:\"hbox\",children:[{type:\"text\",widths:[\"50%\",\"50%\"],labelLayout:\"horizontal\",label:g.width,id:\"width\",setup:l,commit:k},{type:\"text\",labelLayout:\"horizontal\",widths:[\"50%\",\"50%\"],label:b.popupLeft,id:\"left\",setup:l,commit:k}]},{type:\"hbox\",children:[{type:\"text\",labelLayout:\"horizontal\",widths:[\"50%\",\"50%\"],label:g.height,id:\"height\",setup:l,commit:k},{type:\"text\",labelLayout:\"horizontal\",\nlabel:b.popupTop,widths:[\"50%\",\"50%\"],id:\"top\",setup:l,commit:k}]}]}]}]},{id:\"upload\",label:b.upload,title:b.upload,hidden:!0,filebrowser:\"uploadButton\",elements:[{type:\"file\",id:\"upload\",label:g.upload,style:\"height:40px\",size:29},{type:\"fileButton\",id:\"uploadButton\",label:g.uploadSubmit,filebrowser:\"info:url\",\"for\":[\"upload\",\"upload\"]}]},{id:\"advanced\",label:b.advanced,title:b.advanced,elements:[{type:\"vbox\",padding:1,children:[{type:\"hbox\",widths:[\"45%\",\"35%\",\"20%\"],children:[{type:\"text\",id:\"advId\",\nrequiredContent:\"a[id]\",label:b.id,setup:e,commit:m},{type:\"select\",id:\"advLangDir\",requiredContent:\"a[dir]\",label:b.langDir,\"default\":\"\",style:\"width:110px\",items:[[g.notSet,\"\"],[b.langDirLTR,\"ltr\"],[b.langDirRTL,\"rtl\"]],setup:e,commit:m},{type:\"text\",id:\"advAccessKey\",requiredContent:\"a[accesskey]\",width:\"80px\",label:b.acccessKey,maxLength:1,setup:e,commit:m}]},{type:\"hbox\",widths:[\"45%\",\"35%\",\"20%\"],children:[{type:\"text\",label:b.name,id:\"advName\",requiredContent:\"a[name]\",setup:e,commit:m},{type:\"text\",\nlabel:b.langCode,id:\"advLangCode\",requiredContent:\"a[lang]\",width:\"110px\",\"default\":\"\",setup:e,commit:m},{type:\"text\",label:b.tabIndex,id:\"advTabIndex\",requiredContent:\"a[tabindex]\",width:\"80px\",maxLength:5,setup:e,commit:m}]}]},{type:\"vbox\",padding:1,children:[{type:\"hbox\",widths:[\"45%\",\"55%\"],children:[{type:\"text\",label:b.advisoryTitle,requiredContent:\"a[title]\",\"default\":\"\",id:\"advTitle\",setup:e,commit:m},{type:\"text\",label:b.advisoryContentType,requiredContent:\"a[type]\",\"default\":\"\",id:\"advContentType\",\nsetup:e,commit:m}]},{type:\"hbox\",widths:[\"45%\",\"55%\"],children:[{type:\"text\",label:b.cssClasses,requiredContent:\"a(cke-xyz)\",\"default\":\"\",id:\"advCSSClasses\",setup:e,commit:m},{type:\"text\",label:b.charset,requiredContent:\"a[charset]\",\"default\":\"\",id:\"advCharset\",setup:e,commit:m}]},{type:\"hbox\",widths:[\"45%\",\"55%\"],children:[{type:\"text\",label:b.rel,requiredContent:\"a[rel]\",\"default\":\"\",id:\"advRel\",setup:e,commit:m},{type:\"text\",label:b.styles,requiredContent:\"a{cke-xyz}\",\"default\":\"\",id:\"advStyles\",\nvalidate:CKEDITOR.dialog.validate.inlineStyle(c.lang.common.invalidInlineStyle),setup:e,commit:m}]},{type:\"hbox\",widths:[\"45%\",\"55%\"],children:[{type:\"checkbox\",id:\"download\",requiredContent:\"a[download]\",label:b.download,setup:function(a){void 0!==a.download&&this.setValue(\"checked\",\"checked\")},commit:function(a){this.getValue()&&(a.download=this.getValue())}}]}]}]}],onShow:function(){var a=this.getParentEditor(),b=a.getSelection(),c=this.getContentElement(\"info\",\"linkDisplayText\").getElement().getParent().getParent(),\nf=n.getSelectedLink(a,!0),h=f[0]||null;h&&h.hasAttribute(\"href\")&&(b.getSelectedElement()||b.isInTable()||b.selectElement(h));b=n.parseLinkAttributes(a,h);1>=f.length&&n.showDisplayTextForElement(h,a)?c.show():c.hide();this._.selectedElements=f;this.setupContent(b)},onOk:function(){var a={};this.commitContent(a);if(this._.selectedElements.length){var b=this._.selectedElements,g=n.getLinkAttributes(c,a),f=[],h,d,l,e,k;for(k=0;k<b.length;k++){h=b[k];d=h.data(\"cke-saved-href\");l=h.getHtml();h.setAttributes(g.set);\nh.removeAttributes(g.removed);if(a.linkText&&q!=a.linkText)e=a.linkText;else if(d==l||\"email\"==a.type&&-1!=l.indexOf(\"@\"))e=\"email\"==a.type?a.email.address:g.set[\"data-cke-saved-href\"];e&&h.setText(e);f.push(p(c,h))}c.getSelection().selectRanges(f);delete this._.selectedElements}else{b=n.getLinkAttributes(c,a);g=c.getSelection().getRanges();f=new CKEDITOR.style({element:\"a\",attributes:b.set});h=[];f.type=CKEDITOR.STYLE_INLINE;for(l=0;l<g.length;l++){d=g[l];d.collapsed?(e=new CKEDITOR.dom.text(a.linkText||\n(\"email\"==a.type?a.email.address:b.set[\"data-cke-saved-href\"]),c.document),d.insertNode(e),d.selectNodeContents(e)):q!==a.linkText&&(e=new CKEDITOR.dom.text(a.linkText,c.document),d.shrink(CKEDITOR.SHRINK_TEXT),c.editable().extractHtmlFromRange(d),d.insertNode(e));e=d._find(\"a\");for(k=0;k<e.length;k++)e[k].remove(!0);f.applyToRange(d,c);h.push(d)}c.getSelection().selectRanges(h)}},onLoad:function(){c.config.linkShowAdvancedTab||this.hidePage(\"advanced\");c.config.linkShowTargetTab||this.hidePage(\"target\")},\nonFocus:function(){var a=this.getContentElement(\"info\",\"linkType\");a&&\"url\"==a.getValue()&&(a=this.getContentElement(\"info\",\"url\"),a.select())}}})})();"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/adminlte/bower_components/ckeditor/plugins/scayt/dialogs/dialog.css",
    "content": "div.cke_dialog_ui_scaytItemList {\n\tborder: 1px solid #c9cccf;\n}\n\n.cke_scaytItemList-child {\n\tposition: relative;\n\tpadding: 6px 30px 6px 5px;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cke_scaytItemList-child:hover {\n\tbackground: #ebebeb;\n}\n\n.cke_scaytItemList-child .cke_scaytItemList_remove {\n\tposition: absolute;\n\ttop: 0;\n\tright: 5px;\n\twidth: 26px;\n\theight: 26px;\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/adminlte/bower_components/ckeditor/plugins/scayt/dialogs/options.js",
    "content": "﻿CKEDITOR.dialog.add(\"scaytDialog\",function(d){var c=d.scayt,k='\\x3cp\\x3e\\x3cimg alt\\x3d\"logo\" title\\x3d\"logo\" src\\x3d\"'+c.getLogo()+'\" /\\x3e\\x3c/p\\x3e\\x3cp\\x3e'+c.getLocal(\"version\")+c.getVersion()+'\\x3c/p\\x3e\\x3cp\\x3e\\x3ca href\\x3d\"'+c.getOption(\"CKUserManual\")+'\" target\\x3d\"_blank\" style\\x3d\"text-decoration: underline; color: blue; cursor: pointer;\"\\x3e'+c.getLocal(\"btn_userManual\")+\"\\x3c/a\\x3e\\x3c/p\\x3e\\x3cp\\x3e\"+c.getLocal(\"text_copyrights\")+\"\\x3c/p\\x3e\",n=CKEDITOR.document,l={isChanged:function(){return null===\nthis.newLang||this.currentLang===this.newLang?!1:!0},currentLang:c.getLang(),newLang:null,reset:function(){this.currentLang=c.getLang();this.newLang=null},id:\"lang\"},k=[{id:\"options\",label:c.getLocal(\"tab_options\"),onShow:function(){},elements:[{type:\"vbox\",id:\"scaytOptions\",children:function(){var b=c.getApplicationConfig(),a=[],g={\"ignore-all-caps-words\":\"label_allCaps\",\"ignore-domain-names\":\"label_ignoreDomainNames\",\"ignore-words-with-mixed-cases\":\"label_mixedCase\",\"ignore-words-with-numbers\":\"label_mixedWithDigits\"},\nh;for(h in b)b={type:\"checkbox\"},b.id=h,b.label=c.getLocal(g[h]),a.push(b);return a}(),onShow:function(){this.getChild();for(var b=d.scayt,a=0;a<this.getChild().length;a++)this.getChild()[a].setValue(b.getApplicationConfig()[this.getChild()[a].id])}}]},{id:\"langs\",label:c.getLocal(\"tab_languages\"),elements:[{id:\"leftLangColumn\",type:\"vbox\",align:\"left\",widths:[\"100\"],children:[{type:\"html\",id:\"langBox\",style:\"overflow: hidden; white-space: normal;margin-bottom:15px;\",html:'\\x3cdiv\\x3e\\x3cdiv style\\x3d\"float:left;width:45%;margin-left:5px;\" id\\x3d\"left-col-'+\nd.name+'\" class\\x3d\"scayt-lang-list\"\\x3e\\x3c/div\\x3e\\x3cdiv style\\x3d\"float:left;width:45%;margin-left:15px;\" id\\x3d\"right-col-'+d.name+'\" class\\x3d\"scayt-lang-list\"\\x3e\\x3c/div\\x3e\\x3c/div\\x3e',onShow:function(){var b=d.scayt.getLang();n.getById(\"scaytLang_\"+d.name+\"_\"+b).$.checked=!0}}]}]},{id:\"dictionaries\",label:c.getLocal(\"tab_dictionaries\"),elements:[{type:\"vbox\",id:\"rightCol_col__left\",children:[{type:\"html\",id:\"dictionaryNote\",html:\"\"},{type:\"text\",id:\"dictionaryName\",label:c.getLocal(\"label_fieldNameDic\")||\n\"Dictionary name\",onShow:function(b){var a=b.sender,g=d.scayt;b=SCAYT.prototype.UILib;var h=a.getContentElement(\"dictionaries\",\"dictionaryName\").getInputElement().$;g.isLicensed()||(h.disabled=!0,b.css(h,{cursor:\"not-allowed\"}));setTimeout(function(){a.getContentElement(\"dictionaries\",\"dictionaryNote\").getElement().setText(\"\");null!=g.getUserDictionaryName()&&\"\"!=g.getUserDictionaryName()&&a.getContentElement(\"dictionaries\",\"dictionaryName\").setValue(g.getUserDictionaryName())},0)}},{type:\"hbox\",\nid:\"udButtonsHolder\",align:\"left\",widths:[\"auto\"],style:\"width:auto;\",children:[{type:\"button\",id:\"createDic\",label:c.getLocal(\"btn_createDic\"),title:c.getLocal(\"btn_createDic\"),onLoad:function(){this.getDialog();var b=d.scayt,a=SCAYT.prototype.UILib,g=this.getElement().$,h=this.getElement().getChild(0).$;b.isLicensed()||(a.css(g,{cursor:\"not-allowed\"}),a.css(h,{cursor:\"not-allowed\"}))},onClick:function(){var b=this.getDialog(),a=f,g=d.scayt,h=b.getContentElement(\"dictionaries\",\"dictionaryName\").getValue();\ng.isLicensed()&&g.createUserDictionary(h,function(e){e.error||a.toggleDictionaryState.call(b,\"dictionaryState\");e.dialog=b;e.command=\"create\";e.name=h;d.fire(\"scaytUserDictionaryAction\",e)},function(a){a.dialog=b;a.command=\"create\";a.name=h;d.fire(\"scaytUserDictionaryActionError\",a)})}},{type:\"button\",id:\"restoreDic\",label:c.getLocal(\"btn_connectDic\"),title:c.getLocal(\"btn_connectDic\"),onLoad:function(){this.getDialog();var b=d.scayt,a=SCAYT.prototype.UILib,g=this.getElement().$,h=this.getElement().getChild(0).$;\nb.isLicensed()||(a.css(g,{cursor:\"not-allowed\"}),a.css(h,{cursor:\"not-allowed\"}))},onClick:function(){var b=this.getDialog(),a=d.scayt,g=f,h=b.getContentElement(\"dictionaries\",\"dictionaryName\").getValue();a.isLicensed()&&a.restoreUserDictionary(h,function(a){a.dialog=b;a.error||g.toggleDictionaryState.call(b,\"dictionaryState\");a.command=\"restore\";a.name=h;d.fire(\"scaytUserDictionaryAction\",a)},function(a){a.dialog=b;a.command=\"restore\";a.name=h;d.fire(\"scaytUserDictionaryActionError\",a)})}},{type:\"button\",\nid:\"disconnectDic\",label:c.getLocal(\"btn_disconnectDic\"),title:c.getLocal(\"btn_disconnectDic\"),onClick:function(){var b=this.getDialog(),a=d.scayt,g=f,h=b.getContentElement(\"dictionaries\",\"dictionaryName\"),e=h.getValue();a.isLicensed()&&(a.disconnectFromUserDictionary({}),h.setValue(\"\"),g.toggleDictionaryState.call(b,\"initialState\"),d.fire(\"scaytUserDictionaryAction\",{dialog:b,command:\"disconnect\",name:e}))}},{type:\"button\",id:\"removeDic\",label:c.getLocal(\"btn_deleteDic\"),title:c.getLocal(\"btn_deleteDic\"),\nonClick:function(){var b=this.getDialog(),a=d.scayt,g=f,h=b.getContentElement(\"dictionaries\",\"dictionaryName\"),e=h.getValue();a.isLicensed()&&a.removeUserDictionary(e,function(a){h.setValue(\"\");a.error||g.toggleDictionaryState.call(b,\"initialState\");a.dialog=b;a.command=\"remove\";a.name=e;d.fire(\"scaytUserDictionaryAction\",a)},function(a){a.dialog=b;a.command=\"remove\";a.name=e;d.fire(\"scaytUserDictionaryActionError\",a)})}},{type:\"button\",id:\"renameDic\",label:c.getLocal(\"btn_renameDic\"),title:c.getLocal(\"btn_renameDic\"),\nonClick:function(){var b=this.getDialog(),a=d.scayt,g=b.getContentElement(\"dictionaries\",\"dictionaryName\").getValue();a.isLicensed()&&a.renameUserDictionary(g,function(a){a.dialog=b;a.command=\"rename\";a.name=g;d.fire(\"scaytUserDictionaryAction\",a)},function(a){a.dialog=b;a.command=\"rename\";a.name=g;d.fire(\"scaytUserDictionaryActionError\",a)})}},{type:\"button\",id:\"editDic\",label:c.getLocal(\"btn_goToDic\"),title:c.getLocal(\"btn_goToDic\"),onLoad:function(){this.getDialog()},onClick:function(){var b=this.getDialog(),\na=b.getContentElement(\"dictionaries\",\"addWordField\");f.clearWordList.call(b);a.setValue(\"\");f.getUserDictionary.call(b);f.toggleDictionaryState.call(b,\"wordsState\")}}]},{type:\"hbox\",id:\"dicInfo\",align:\"left\",children:[{type:\"html\",id:\"dicInfoHtml\",html:'\\x3cdiv id\\x3d\"dic_info_editor1\" style\\x3d\"margin:5px auto; width:95%;white-space:normal;\"\\x3e'+(d.scayt.isLicensed&&d.scayt.isLicensed()?'\\x3ca href\\x3d\"'+c.getOption(\"CKUserManual\")+'\" target\\x3d\"_blank\" style\\x3d\"text-decoration: underline; color: blue; cursor: pointer;\"\\x3e'+\nc.getLocal(\"text_descriptionDicForPaid\")+\"\\x3c/a\\x3e\":c.getLocal(\"text_descriptionDicForFree\"))+\"\\x3c/div\\x3e\"}]},{id:\"addWordAction\",type:\"hbox\",style:\"width: 100%; margin-bottom: 0;\",widths:[\"40%\",\"60%\"],children:[{id:\"addWord\",type:\"vbox\",style:\"min-width: 150px;\",children:[{type:\"text\",id:\"addWordField\",label:\"Add word\",maxLength:\"64\"}]},{id:\"addWordButtons\",type:\"vbox\",style:\"margin-top: 20px;\",children:[{type:\"hbox\",id:\"addWordButton\",align:\"left\",children:[{type:\"button\",id:\"addWord\",label:c.getLocal(\"btn_addWord\"),\ntitle:c.getLocal(\"btn_addWord\"),onClick:function(){var b=this.getDialog(),a=d.scayt,g=b.getContentElement(\"dictionaries\",\"itemList\"),h=b.getContentElement(\"dictionaries\",\"addWordField\"),e=h.getValue(),c=a.getOption(\"wordBoundaryRegex\"),f=this;e&&(-1!==e.search(c)?d.fire(\"scaytUserDictionaryAction\",{dialog:b,command:\"wordWithBannedSymbols\",name:e,error:!0}):g.inChildren(e)?(h.setValue(\"\"),d.fire(\"scaytUserDictionaryAction\",{dialog:b,command:\"wordAlreadyAdded\",name:e})):(this.disable(),a.addWordToUserDictionary(e,\nfunction(a){a.error||(h.setValue(\"\"),g.addChild(e,!0));a.dialog=b;a.command=\"addWord\";a.name=e;f.enable();d.fire(\"scaytUserDictionaryAction\",a)},function(a){a.dialog=b;a.command=\"addWord\";a.name=e;f.enable();d.fire(\"scaytUserDictionaryActionError\",a)})))}},{type:\"button\",id:\"backToDic\",label:c.getLocal(\"btn_dictionaryPreferences\"),title:c.getLocal(\"btn_dictionaryPreferences\"),align:\"right\",onClick:function(){var b=this.getDialog(),a=d.scayt;null!=a.getUserDictionaryName()&&\"\"!=a.getUserDictionaryName()?\nf.toggleDictionaryState.call(b,\"dictionaryState\"):f.toggleDictionaryState.call(b,\"initialState\")}}]}]}]},{id:\"wordsHolder\",type:\"hbox\",style:\"width: 100%; height: 170px; margin-bottom: 0;\",children:[{type:\"scaytItemList\",id:\"itemList\",align:\"left\",style:\"width: 100%; height: 170px; overflow: auto\",onClick:function(b){var a=b.data.$;b=d.scayt;var g=SCAYT.prototype.UILib,a=a.target||a.srcElement,h=g.parent(a)[0],e=g.attr(h,\"data-cke-scayt-ud-word\"),c=this.getDialog(),f=c.getContentElement(\"dictionaries\",\n\"itemList\"),q=this;g.hasClass(a,\"cke_scaytItemList_remove\")&&!this.isBlocked()&&(this.block(),b.deleteWordFromUserDictionary(e,function(a){a.error||f.removeChild(h,e);q.unblock();a.dialog=c;a.command=\"deleteWord\";a.name=e;d.fire(\"scaytUserDictionaryAction\",a)},function(a){q.unblock();a.dialog=c;a.command=\"deleteWord\";a.name=e;d.fire(\"scaytUserDictionaryActionError\",a)}))}}]}]}]},{id:\"about\",label:c.getLocal(\"tab_about\"),elements:[{type:\"html\",id:\"about\",style:\"margin: 5px 5px;\",html:'\\x3cdiv\\x3e\\x3cdiv id\\x3d\"scayt_about_\"\\x3e'+\nk+\"\\x3c/div\\x3e\\x3c/div\\x3e\"}]}];d.on(\"scaytUserDictionaryAction\",function(b){var a=SCAYT.prototype.UILib,g=b.data.dialog,d=g.getContentElement(\"dictionaries\",\"dictionaryNote\").getElement(),e=b.editor.scayt,c;void 0===b.data.error?(c=e.getLocal(\"message_success_\"+b.data.command+\"Dic\"),c=c.replace(\"%s\",b.data.name),d.setText(c),a.css(d.$,{color:\"blue\"})):(\"\"===b.data.name?d.setText(e.getLocal(\"message_info_emptyDic\")):(c=e.getLocal(\"message_error_\"+b.data.command+\"Dic\"),c=c.replace(\"%s\",b.data.name),\nd.setText(c)),a.css(d.$,{color:\"red\"}),null!=e.getUserDictionaryName()&&\"\"!=e.getUserDictionaryName()?g.getContentElement(\"dictionaries\",\"dictionaryName\").setValue(e.getUserDictionaryName()):g.getContentElement(\"dictionaries\",\"dictionaryName\").setValue(\"\"))});d.on(\"scaytUserDictionaryActionError\",function(b){var a=SCAYT.prototype.UILib,g=b.data.dialog,d=g.getContentElement(\"dictionaries\",\"dictionaryNote\").getElement(),c=b.editor.scayt,f;\"\"===b.data.name?d.setText(c.getLocal(\"message_info_emptyDic\")):\n(f=c.getLocal(\"message_error_\"+b.data.command+\"Dic\"),f=f.replace(\"%s\",b.data.name),d.setText(f));a.css(d.$,{color:\"red\"});null!=c.getUserDictionaryName()&&\"\"!=c.getUserDictionaryName()?g.getContentElement(\"dictionaries\",\"dictionaryName\").setValue(c.getUserDictionaryName()):g.getContentElement(\"dictionaries\",\"dictionaryName\").setValue(\"\")});var f={title:\"SCAYT\",resizable:CKEDITOR.DIALOG_RESIZE_BOTH,minWidth:\"moono-lisa\"==(CKEDITOR.skinName||d.config.skin)?450:340,minHeight:300,onLoad:function(){if(0!=\nd.config.scayt_uiTabs[1]){var b=f,a=b.getLangBoxes.call(this);this.getContentElement(\"dictionaries\",\"addWordField\");a.getParent().setStyle(\"white-space\",\"normal\");b.renderLangList(a);this.definition.minWidth=this.getSize().width;this.resize(this.definition.minWidth,this.definition.minHeight)}},onCancel:function(){l.reset()},onHide:function(){d.unlockSelection()},onShow:function(){d.fire(\"scaytDialogShown\",this);if(0!=d.config.scayt_uiTabs[2]){var b=this.getContentElement(\"dictionaries\",\"addWordField\");\nf.clearWordList.call(this);b.setValue(\"\");f.getUserDictionary.call(this);f.toggleDictionaryState.call(this,\"wordsState\")}},onOk:function(){var b=f,a=d.scayt;this.getContentElement(\"options\",\"scaytOptions\");b=b.getChangedOption.call(this);a.commitOption({changedOptions:b})},toggleDictionaryButtons:function(b){var a=this.getContentElement(\"dictionaries\",\"existDic\").getElement().getParent(),d=this.getContentElement(\"dictionaries\",\"notExistDic\").getElement().getParent();b?(a.show(),d.hide()):(a.hide(),\nd.show())},getChangedOption:function(){var b={};if(1==d.config.scayt_uiTabs[0])for(var a=this.getContentElement(\"options\",\"scaytOptions\").getChild(),c=0;c<a.length;c++)a[c].isChanged()&&(b[a[c].id]=a[c].getValue());l.isChanged()&&(b[l.id]=d.config.scayt_sLang=l.currentLang=l.newLang);return b},buildRadioInputs:function(b,a,c){c=new CKEDITOR.dom.element(\"div\");var h=\"scaytLang_\"+d.name+\"_\"+a,e=CKEDITOR.dom.element.createFromHtml('\\x3cinput id\\x3d\"'+h+'\" type\\x3d\"radio\"  value\\x3d\"'+a+'\" name\\x3d\"scayt_lang\" /\\x3e'),\nf=new CKEDITOR.dom.element(\"label\"),k=d.scayt;c.setStyles({\"white-space\":\"normal\",position:\"relative\",\"padding-bottom\":\"2px\"});e.on(\"click\",function(a){l.newLang=a.sender.getValue()});f.appendText(b);f.setAttribute(\"for\",h);c.append(e);c.append(f);a===k.getLang()&&(e.setAttribute(\"checked\",!0),e.setAttribute(\"defaultChecked\",\"defaultChecked\"));return c},renderLangList:function(b){var a=d.name.replace(/(:|\\.|\\[|\\]|,|=|@)/g,\"\\\\$1\"),g=b.find(\"#left-col-\"+a).getItem(0);b=b.find(\"#right-col-\"+a).getItem(0);\nvar h=c.getScaytLangList(),a=c.getGraytLangList(),e={},f=[],k=0,l=!1,m;for(m in h.ltr)e[m]=h.ltr[m];for(m in h.rtl)e[m]=h.rtl[m];for(m in e)f.push([m,e[m]]);f.sort(function(a,b){var c=0;a[1]>b[1]?c=1:a[1]<b[1]&&(c=-1);return c});e={};for(l=0;l<f.length;l++)e[f[l][0]]=f[l][1];f=Math.round(f.length/2);for(m in e)k++,l=m in a.ltr||m in a.rtl,this.buildRadioInputs(e[m],m,l).appendTo(k<=f?g:b)},getLangBoxes:function(){return this.getContentElement(\"langs\",\"langBox\").getElement()},toggleDictionaryState:function(b){var a=\nthis.getContentElement(\"dictionaries\",\"dictionaryName\").getElement().getParent(),c=this.getContentElement(\"dictionaries\",\"udButtonsHolder\").getElement().getParent(),d=this.getContentElement(\"dictionaries\",\"createDic\").getElement().getParent(),e=this.getContentElement(\"dictionaries\",\"restoreDic\").getElement().getParent(),f=this.getContentElement(\"dictionaries\",\"disconnectDic\").getElement().getParent(),l=this.getContentElement(\"dictionaries\",\"removeDic\").getElement().getParent(),k=this.getContentElement(\"dictionaries\",\n\"renameDic\").getElement().getParent(),m=this.getContentElement(\"dictionaries\",\"dicInfo\").getElement().getParent(),n=this.getContentElement(\"dictionaries\",\"addWordAction\").getElement().getParent(),p=this.getContentElement(\"dictionaries\",\"wordsHolder\").getElement().getParent();switch(b){case \"initialState\":a.show();c.show();d.show();e.show();f.hide();l.hide();k.hide();m.show();n.hide();p.hide();break;case \"wordsState\":a.hide();c.hide();m.hide();n.show();p.show();break;case \"dictionaryState\":a.show(),\nc.show(),d.hide(),e.hide(),f.show(),l.show(),k.show(),m.show(),n.hide(),p.hide()}},clearWordList:function(){this.getContentElement(\"dictionaries\",\"itemList\").removeAllChild()},getUserDictionary:function(){var b=this,a=d.scayt;a.getUserDictionary(a.getUserDictionaryName(),function(a){a.error||f.renderItemList.call(b,a.wordlist)})},renderItemList:function(b){for(var a=this.getContentElement(\"dictionaries\",\"itemList\"),c=0;c<b.length;c++)a.addChild(b[c])},contents:function(b,a){var c=[],d=a.config.scayt_uiTabs;\nif(d){for(var e in d)1==d[e]&&c.push(b[e]);c.push(b[b.length-1])}else return b;return c}(k,d)};return f});CKEDITOR.tools.extend(CKEDITOR.ui.dialog,{scaytItemList:function(d,c,k){if(arguments.length){var n=this;d.on(\"load\",function(){n.getElement().on(\"click\",function(c){})});CKEDITOR.ui.dialog.uiElement.call(this,d,c,k,\"\",null,null,function(){var d=['\\x3cp class\\x3d\"cke_dialog_ui_',c.type,'\"'];c.style&&d.push('style\\x3d\"'+c.style+'\" ');d.push(\"\\x3e\");d.push(\"\\x3c/p\\x3e\");return d.join(\"\")})}}});\nCKEDITOR.ui.dialog.scaytItemList.prototype=CKEDITOR.tools.extend(new CKEDITOR.ui.dialog.uiElement,{children:[],blocked:!1,addChild:function(d,c){var k=new CKEDITOR.dom.element(\"p\"),n=new CKEDITOR.dom.element(\"a\"),l=this.getElement().getChildren().getItem(0);this.children.push(d);k.addClass(\"cke_scaytItemList-child\");k.setAttribute(\"data-cke-scayt-ud-word\",d);k.appendText(d);n.addClass(\"cke_scaytItemList_remove\");n.addClass(\"cke_dialog_close_button\");n.setAttribute(\"href\",\"javascript:void(0)\");k.append(n);\nl.append(k,c?!0:!1)},inChildren:function(d){return SCAYT.prototype.Utils.inArray(this.children,d)},removeChild:function(d,c){this.children.splice(SCAYT.prototype.Utils.indexOf(this.children,c),1);this.getElement().getChildren().getItem(0).$.removeChild(d)},removeAllChild:function(){this.children=[];this.getElement().getChildren().getItem(0).setHtml(\"\")},block:function(){this.blocked=!0},unblock:function(){this.blocked=!1},isBlocked:function(){return this.blocked}});\n(function(){commonBuilder={build:function(d,c,k){return new CKEDITOR.ui.dialog[c.type](d,c,k)}};CKEDITOR.dialog.addUIElement(\"scaytItemList\",commonBuilder)})();"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/adminlte/bower_components/ckeditor/plugins/scayt/dialogs/toolbar.css",
    "content": "a\n{\n\ttext-decoration:none;\n\tpadding: 2px 4px 4px 6px;\n\tdisplay : block;\n\tborder-width: 1px;\n\tborder-style: solid;\n\tmargin : 0px;\n}\n\na.cke_scayt_toogle:hover,\na.cke_scayt_toogle:focus,\na.cke_scayt_toogle:active\n{\n\tborder-color: #316ac5;\n\tbackground-color: #dff1ff;\n\tcolor : #000;\n\tcursor: pointer;\n\tmargin : 0px;\n}\na.cke_scayt_toogle {\n\tcolor : #316ac5;\n\tborder-color: #fff;\n}\n.scayt_enabled a.cke_scayt_item {\n\tcolor : #316ac5;\n\tborder-color: #fff;\n\tmargin : 0px;\n}\n.scayt_disabled a.cke_scayt_item {\n\tcolor : gray;\n\tborder-color : #fff;\n}\n.scayt_enabled a.cke_scayt_item:hover,\n.scayt_enabled a.cke_scayt_item:focus,\n.scayt_enabled a.cke_scayt_item:active\n{\n\tborder-color: #316ac5;\n\tbackground-color: #dff1ff;\n\tcolor : #000;\n\tcursor: pointer;\n}\n.scayt_disabled a.cke_scayt_item:hover,\n.scayt_disabled a.cke_scayt_item:focus,\n.scayt_disabled a.cke_scayt_item:active\n{\n\tborder-color: gray;\n\tbackground-color: #dff1ff;\n\tcolor : gray;\n\tcursor: no-drop;\n}\n.cke_scayt_set_on, .cke_scayt_set_off\n{\n\tdisplay: none;\n}\n.scayt_enabled .cke_scayt_set_on\n{\n\tdisplay: none;\n}\n.scayt_disabled .cke_scayt_set_on\n{\n\tdisplay: inline;\n}\n.scayt_disabled .cke_scayt_set_off\n{\n\tdisplay: none;\n}\n.scayt_enabled  .cke_scayt_set_off\n{\n\tdisplay: inline;\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/adminlte/bower_components/ckeditor/plugins/scayt/skins/moono-lisa/scayt.css",
    "content": ".scayt-lang-list > div\n{\n    padding-bottom: 6px !important;\n}\n\n.scayt-lang-list > div input\n{\n    margin-right: 4px;\n}\n\n#scayt_about_\n{\n    margin: 30px auto 0 auto;\n}\n\n#scayt_about_ p\n{\n\ttext-align: center;\n\tmargin-bottom: 10px;\n}\n\n.cke_dialog_contents_body div[name=dictionaries] .cke_dialog_ui_hbox_last > a.cke_dialog_ui_button\n{\n    margin-top: 0;\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/adminlte/bower_components/ckeditor/plugins/specialchar/dialogs/lang/zh-cn.js",
    "content": "﻿/*\n Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.\n For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n*/\nCKEDITOR.plugins.setLang(\"specialchar\",\"zh-cn\",{euro:\"欧元符号\",lsquo:\"左单引号\",rsquo:\"右单引号\",ldquo:\"左双引号\",rdquo:\"右双引号\",ndash:\"短划线\",mdash:\"长划线\",iexcl:\"竖翻叹号\",cent:\"分币符号\",pound:\"英镑符号\",curren:\"货币符号\",yen:\"日元符号\",brvbar:\"间断条\",sect:\"节标记\",uml:\"分音符\",copy:\"版权所有标记\",ordf:\"阴性顺序指示符\",laquo:\"左指双尖引号\",not:\"非标记\",reg:\"注册标记\",macr:\"长音符\",deg:\"度标记\",sup2:\"上标二\",sup3:\"上标三\",acute:\"锐音符\",micro:\"微符\",para:\"段落标记\",middot:\"中间点\",cedil:\"下加符\",sup1:\"上标一\",ordm:\"阳性顺序指示符\",raquo:\"右指双尖引号\",frac14:\"普通分数四分之一\",frac12:\"普通分数二分之一\",frac34:\"普通分数四分之三\",iquest:\"竖翻问号\",\nAgrave:\"带抑音符的拉丁文大写字母 A\",Aacute:\"带锐音符的拉丁文大写字母 A\",Acirc:\"带扬抑符的拉丁文大写字母 A\",Atilde:\"带颚化符的拉丁文大写字母 A\",Auml:\"带分音符的拉丁文大写字母 A\",Aring:\"带上圆圈的拉丁文大写字母 A\",AElig:\"拉丁文大写字母 Æ\",Ccedil:\"带下加符的拉丁文大写字母 C\",Egrave:\"带抑音符的拉丁文大写字母 E\",Eacute:\"带锐音符的拉丁文大写字母 E\",Ecirc:\"带扬抑符的拉丁文大写字母 E\",Euml:\"带分音符的拉丁文大写字母 E\",Igrave:\"带抑音符的拉丁文大写字母 I\",Iacute:\"带锐音符的拉丁文大写字母 I\",Icirc:\"带扬抑符的拉丁文大写字母 I\",Iuml:\"带分音符的拉丁文大写字母 I\",ETH:\"拉丁文大写字母 Eth\",Ntilde:\"带颚化符的拉丁文大写字母 N\",Ograve:\"带抑音符的拉丁文大写字母 O\",Oacute:\"带锐音符的拉丁文大写字母 O\",Ocirc:\"带扬抑符的拉丁文大写字母 O\",Otilde:\"带颚化符的拉丁文大写字母 O\",\nOuml:\"带分音符的拉丁文大写字母 O\",times:\"乘号\",Oslash:\"带粗线的拉丁文大写字母 O\",Ugrave:\"带抑音符的拉丁文大写字母 U\",Uacute:\"带锐音符的拉丁文大写字母 U\",Ucirc:\"带扬抑符的拉丁文大写字母 U\",Uuml:\"带分音符的拉丁文大写字母 U\",Yacute:\"带抑音符的拉丁文大写字母 Y\",THORN:\"拉丁文大写字母 Thorn\",szlig:\"拉丁文小写字母清音 S\",agrave:\"带抑音符的拉丁文小写字母 A\",aacute:\"带锐音符的拉丁文小写字母 A\",acirc:\"带扬抑符的拉丁文小写字母 A\",atilde:\"带颚化符的拉丁文小写字母 A\",auml:\"带分音符的拉丁文小写字母 A\",aring:\"带上圆圈的拉丁文小写字母 A\",aelig:\"拉丁文小写字母 Ae\",ccedil:\"带下加符的拉丁文小写字母 C\",egrave:\"带抑音符的拉丁文小写字母 E\",eacute:\"带锐音符的拉丁文小写字母 E\",ecirc:\"带扬抑符的拉丁文小写字母 E\",euml:\"带分音符的拉丁文小写字母 E\",igrave:\"带抑音符的拉丁文小写字母 I\",\niacute:\"带锐音符的拉丁文小写字母 I\",icirc:\"带扬抑符的拉丁文小写字母 I\",iuml:\"带分音符的拉丁文小写字母 I\",eth:\"拉丁文小写字母 Eth\",ntilde:\"带颚化符的拉丁文小写字母 N\",ograve:\"带抑音符的拉丁文小写字母 O\",oacute:\"带锐音符的拉丁文小写字母 O\",ocirc:\"带扬抑符的拉丁文小写字母 O\",otilde:\"带颚化符的拉丁文小写字母 O\",ouml:\"带分音符的拉丁文小写字母 O\",divide:\"除号\",oslash:\"带粗线的拉丁文小写字母 O\",ugrave:\"带抑音符的拉丁文小写字母 U\",uacute:\"带锐音符的拉丁文小写字母 U\",ucirc:\"带扬抑符的拉丁文小写字母 U\",uuml:\"带分音符的拉丁文小写字母 U\",yacute:\"带抑音符的拉丁文小写字母 Y\",thorn:\"拉丁文小写字母 Thorn\",yuml:\"带分音符的拉丁文小写字母 Y\",OElig:\"拉丁文大写连字 Oe\",oelig:\"拉丁文小写连字 Oe\",372:\"带扬抑符的拉丁文大写字母 W\",374:\"带扬抑符的拉丁文大写字母 Y\",\n373:\"带扬抑符的拉丁文小写字母 W\",375:\"带扬抑符的拉丁文小写字母 Y\",sbquo:\"单下 9 形引号\",8219:\"单高横翻 9 形引号\",bdquo:\"双下 9 形引号\",hellip:\"水平省略号\",trade:\"商标标志\",9658:\"实心右指指针\",bull:\"加重号\",rarr:\"向右箭头\",rArr:\"向右双线箭头\",hArr:\"左右双线箭头\",diams:\"实心方块纸牌\",asymp:\"约等于\"});"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/adminlte/bower_components/ckeditor/plugins/specialchar/dialogs/specialchar.js",
    "content": "﻿/*\n Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.\n For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n*/\nCKEDITOR.dialog.add(\"specialchar\",function(k){var e,n=k.lang.specialchar,m=function(c){var b;c=c.data?c.data.getTarget():new CKEDITOR.dom.element(c);\"a\"==c.getName()&&(b=c.getChild(0).getHtml())&&(c.removeClass(\"cke_light_background\"),e.hide(),c=k.document.createElement(\"span\"),c.setHtml(b),k.insertText(c.getText()))},p=CKEDITOR.tools.addFunction(m),l,g=function(c,b){var a;b=b||c.data.getTarget();\"span\"==b.getName()&&(b=b.getParent());if(\"a\"==b.getName()&&(a=b.getChild(0).getHtml())){l&&d(null,l);\nvar f=e.getContentElement(\"info\",\"htmlPreview\").getElement();e.getContentElement(\"info\",\"charPreview\").getElement().setHtml(a);f.setHtml(CKEDITOR.tools.htmlEncode(a));b.getParent().addClass(\"cke_light_background\");l=b}},d=function(c,b){b=b||c.data.getTarget();\"span\"==b.getName()&&(b=b.getParent());\"a\"==b.getName()&&(e.getContentElement(\"info\",\"charPreview\").getElement().setHtml(\"\\x26nbsp;\"),e.getContentElement(\"info\",\"htmlPreview\").getElement().setHtml(\"\\x26nbsp;\"),b.getParent().removeClass(\"cke_light_background\"),\nl=void 0)},q=CKEDITOR.tools.addFunction(function(c){c=new CKEDITOR.dom.event(c);var b=c.getTarget(),a;a=c.getKeystroke();var f=\"rtl\"==k.lang.dir;switch(a){case 38:if(a=b.getParent().getParent().getPrevious())a=a.getChild([b.getParent().getIndex(),0]),a.focus(),d(null,b),g(null,a);c.preventDefault();break;case 40:(a=b.getParent().getParent().getNext())&&(a=a.getChild([b.getParent().getIndex(),0]))&&1==a.type&&(a.focus(),d(null,b),g(null,a));c.preventDefault();break;case 32:m({data:c});c.preventDefault();\nbreak;case f?37:39:if(a=b.getParent().getNext())a=a.getChild(0),1==a.type?(a.focus(),d(null,b),g(null,a),c.preventDefault(!0)):d(null,b);else if(a=b.getParent().getParent().getNext())(a=a.getChild([0,0]))&&1==a.type?(a.focus(),d(null,b),g(null,a),c.preventDefault(!0)):d(null,b);break;case f?39:37:(a=b.getParent().getPrevious())?(a=a.getChild(0),a.focus(),d(null,b),g(null,a),c.preventDefault(!0)):(a=b.getParent().getParent().getPrevious())?(a=a.getLast().getChild(0),a.focus(),d(null,b),g(null,a),c.preventDefault(!0)):\nd(null,b)}});return{title:n.title,minWidth:430,minHeight:280,buttons:[CKEDITOR.dialog.cancelButton],charColumns:17,onLoad:function(){for(var c=this.definition.charColumns,b=k.config.specialChars,a=CKEDITOR.tools.getNextId()+\"_specialchar_table_label\",f=['\\x3ctable role\\x3d\"listbox\" aria-labelledby\\x3d\"'+a+'\" style\\x3d\"width: 320px; height: 100%; border-collapse: separate;\" align\\x3d\"center\" cellspacing\\x3d\"2\" cellpadding\\x3d\"2\" border\\x3d\"0\"\\x3e'],d=0,g=b.length,h,e;d<g;){f.push('\\x3ctr role\\x3d\"presentation\"\\x3e');\nfor(var l=0;l<c;l++,d++){if(h=b[d]){h instanceof Array?(e=h[1],h=h[0]):(e=h.replace(\"\\x26\",\"\").replace(\";\",\"\").replace(\"#\",\"\"),e=n[e]||h);var m=\"cke_specialchar_label_\"+d+\"_\"+CKEDITOR.tools.getNextNumber();f.push('\\x3ctd class\\x3d\"cke_dark_background\" style\\x3d\"cursor: default\" role\\x3d\"presentation\"\\x3e\\x3ca href\\x3d\"javascript: void(0);\" role\\x3d\"option\" aria-posinset\\x3d\"'+(d+1)+'\"',' aria-setsize\\x3d\"'+g+'\"',' aria-labelledby\\x3d\"'+m+'\"',' class\\x3d\"cke_specialchar\" title\\x3d\"',CKEDITOR.tools.htmlEncode(e),\n'\" onkeydown\\x3d\"CKEDITOR.tools.callFunction( '+q+', event, this )\" onclick\\x3d\"CKEDITOR.tools.callFunction('+p+', this); return false;\" tabindex\\x3d\"-1\"\\x3e\\x3cspan style\\x3d\"margin: 0 auto;cursor: inherit\"\\x3e'+h+'\\x3c/span\\x3e\\x3cspan class\\x3d\"cke_voice_label\" id\\x3d\"'+m+'\"\\x3e'+e+\"\\x3c/span\\x3e\\x3c/a\\x3e\")}else f.push('\\x3ctd class\\x3d\"cke_dark_background\"\\x3e\\x26nbsp;');f.push(\"\\x3c/td\\x3e\")}f.push(\"\\x3c/tr\\x3e\")}f.push(\"\\x3c/tbody\\x3e\\x3c/table\\x3e\",'\\x3cspan id\\x3d\"'+a+'\" class\\x3d\"cke_voice_label\"\\x3e'+\nn.options+\"\\x3c/span\\x3e\");this.getContentElement(\"info\",\"charContainer\").getElement().setHtml(f.join(\"\"))},contents:[{id:\"info\",label:k.lang.common.generalTab,title:k.lang.common.generalTab,padding:0,align:\"top\",elements:[{type:\"hbox\",align:\"top\",widths:[\"320px\",\"90px\"],children:[{type:\"html\",id:\"charContainer\",html:\"\",onMouseover:g,onMouseout:d,focus:function(){var c=this.getElement().getElementsByTag(\"a\").getItem(0);setTimeout(function(){c.focus();g(null,c)},0)},onShow:function(){var c=this.getElement().getChild([0,\n0,0,0,0]);setTimeout(function(){c.focus();g(null,c)},0)},onLoad:function(c){e=c.sender}},{type:\"hbox\",align:\"top\",widths:[\"100%\"],children:[{type:\"vbox\",align:\"top\",children:[{type:\"html\",html:\"\\x3cdiv\\x3e\\x3c/div\\x3e\"},{type:\"html\",id:\"charPreview\",className:\"cke_dark_background\",style:\"border:1px solid #eeeeee;font-size:28px;height:40px;width:70px;padding-top:9px;font-family:'Microsoft Sans Serif',Arial,Helvetica,Verdana;text-align:center;\",html:\"\\x3cdiv\\x3e\\x26nbsp;\\x3c/div\\x3e\"},{type:\"html\",\nid:\"htmlPreview\",className:\"cke_dark_background\",style:\"border:1px solid #eeeeee;font-size:14px;height:20px;width:70px;padding-top:2px;font-family:'Microsoft Sans Serif',Arial,Helvetica,Verdana;text-align:center;\",html:\"\\x3cdiv\\x3e\\x26nbsp;\\x3c/div\\x3e\"}]}]}]}]}]}});"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/adminlte/bower_components/ckeditor/plugins/table/dialogs/table.js",
    "content": "﻿/*\n Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.\n For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n*/\n(function(){function w(a){for(var f=0,p=0,n=0,q,e=a.$.rows.length;n<e;n++){q=a.$.rows[n];for(var d=f=0,b,c=q.cells.length;d<c;d++)b=q.cells[d],f+=b.colSpan;f>p&&(p=f)}return p}function t(a){return function(){var f=this.getValue(),f=!!(CKEDITOR.dialog.validate.integer().call(this,f)&&0<f);f||(alert(a),this.select());return f}}function r(a,f){var p=function(e){return new CKEDITOR.dom.element(e,a.document)},r=a.editable(),q=a.plugins.dialogadvtab;return{title:a.lang.table.title,minWidth:310,minHeight:CKEDITOR.env.ie?\n310:280,onLoad:function(){var e=this,a=e.getContentElement(\"advanced\",\"advStyles\");if(a)a.on(\"change\",function(){var a=this.getStyle(\"width\",\"\"),c=e.getContentElement(\"info\",\"txtWidth\");c&&c.setValue(a,!0);a=this.getStyle(\"height\",\"\");(c=e.getContentElement(\"info\",\"txtHeight\"))&&c.setValue(a,!0)})},onShow:function(){var e=a.getSelection(),d=e.getRanges(),b,c=this.getContentElement(\"info\",\"txtRows\"),h=this.getContentElement(\"info\",\"txtCols\"),u=this.getContentElement(\"info\",\"txtWidth\"),l=this.getContentElement(\"info\",\n\"txtHeight\");\"tableProperties\"==f&&((e=e.getSelectedElement())&&e.is(\"table\")?b=e:0<d.length&&(CKEDITOR.env.webkit&&d[0].shrink(CKEDITOR.NODE_ELEMENT),b=a.elementPath(d[0].getCommonAncestor(!0)).contains(\"table\",1)),this._.selectedElement=b);b?(this.setupContent(b),c&&c.disable(),h&&h.disable()):(c&&c.enable(),h&&h.enable());u&&u.onChange();l&&l.onChange()},onOk:function(){var e=a.getSelection(),d=this._.selectedElement&&e.createBookmarks(),b=this._.selectedElement||p(\"table\"),c={};this.commitContent(c,\nb);if(c.info){c=c.info;if(!this._.selectedElement)for(var h=b.append(p(\"tbody\")),f=parseInt(c.txtRows,10)||0,l=parseInt(c.txtCols,10)||0,k=0;k<f;k++)for(var g=h.append(p(\"tr\")),m=0;m<l;m++)g.append(p(\"td\")).appendBogus();f=c.selHeaders;if(!b.$.tHead&&(\"row\"==f||\"both\"==f)){g=b.getElementsByTag(\"thead\").getItem(0);h=b.getElementsByTag(\"tbody\").getItem(0);l=h.getElementsByTag(\"tr\").getItem(0);g||(g=new CKEDITOR.dom.element(\"thead\"),g.insertBefore(h));for(k=0;k<l.getChildCount();k++)h=l.getChild(k),\nh.type!=CKEDITOR.NODE_ELEMENT||h.data(\"cke-bookmark\")||(h.renameNode(\"th\"),h.setAttribute(\"scope\",\"col\"));g.append(l.remove())}if(null!==b.$.tHead&&\"row\"!=f&&\"both\"!=f){g=new CKEDITOR.dom.element(b.$.tHead);for(h=b.getElementsByTag(\"tbody\").getItem(0);0<g.getChildCount();){l=g.getFirst();for(k=0;k<l.getChildCount();k++)m=l.getChild(k),m.type==CKEDITOR.NODE_ELEMENT&&(m.renameNode(\"td\"),m.removeAttribute(\"scope\"));h.append(l,!0)}g.remove()}if(!this.hasColumnHeaders&&(\"col\"==f||\"both\"==f))for(g=0;g<\nb.$.rows.length;g++)m=new CKEDITOR.dom.element(b.$.rows[g].cells[0]),m.renameNode(\"th\"),m.setAttribute(\"scope\",\"row\");if(this.hasColumnHeaders&&\"col\"!=f&&\"both\"!=f)for(k=0;k<b.$.rows.length;k++)g=new CKEDITOR.dom.element(b.$.rows[k]),\"tbody\"==g.getParent().getName()&&(m=new CKEDITOR.dom.element(g.$.cells[0]),m.renameNode(\"td\"),m.removeAttribute(\"scope\"));c.txtHeight?b.setStyle(\"height\",c.txtHeight):b.removeStyle(\"height\");c.txtWidth?b.setStyle(\"width\",c.txtWidth):b.removeStyle(\"width\");b.getAttribute(\"style\")||\nb.removeAttribute(\"style\")}if(this._.selectedElement)try{e.selectBookmarks(d)}catch(n){}else a.insertElement(b),setTimeout(function(){var e=new CKEDITOR.dom.element(b.$.rows[0].cells[0]),c=a.createRange();c.moveToPosition(e,CKEDITOR.POSITION_AFTER_START);c.select()},0)},contents:[{id:\"info\",label:a.lang.table.title,elements:[{type:\"hbox\",widths:[null,null],styles:[\"vertical-align:top\"],children:[{type:\"vbox\",padding:0,children:[{type:\"text\",id:\"txtRows\",\"default\":3,label:a.lang.table.rows,required:!0,\ncontrolStyle:\"width:5em\",validate:t(a.lang.table.invalidRows),setup:function(e){this.setValue(e.$.rows.length)},commit:n},{type:\"text\",id:\"txtCols\",\"default\":2,label:a.lang.table.columns,required:!0,controlStyle:\"width:5em\",validate:t(a.lang.table.invalidCols),setup:function(e){this.setValue(w(e))},commit:n},{type:\"html\",html:\"\\x26nbsp;\"},{type:\"select\",id:\"selHeaders\",requiredContent:\"th\",\"default\":\"\",label:a.lang.table.headers,items:[[a.lang.table.headersNone,\"\"],[a.lang.table.headersRow,\"row\"],\n[a.lang.table.headersColumn,\"col\"],[a.lang.table.headersBoth,\"both\"]],setup:function(e){var a=this.getDialog();a.hasColumnHeaders=!0;for(var b=0;b<e.$.rows.length;b++){var c=e.$.rows[b].cells[0];if(c&&\"th\"!=c.nodeName.toLowerCase()){a.hasColumnHeaders=!1;break}}null!==e.$.tHead?this.setValue(a.hasColumnHeaders?\"both\":\"row\"):this.setValue(a.hasColumnHeaders?\"col\":\"\")},commit:n},{type:\"text\",id:\"txtBorder\",requiredContent:\"table[border]\",\"default\":a.filter.check(\"table[border]\")?1:0,label:a.lang.table.border,\ncontrolStyle:\"width:3em\",validate:CKEDITOR.dialog.validate.number(a.lang.table.invalidBorder),setup:function(a){this.setValue(a.getAttribute(\"border\")||\"\")},commit:function(a,d){this.getValue()?d.setAttribute(\"border\",this.getValue()):d.removeAttribute(\"border\")}},{id:\"cmbAlign\",type:\"select\",requiredContent:\"table[align]\",\"default\":\"\",label:a.lang.common.align,items:[[a.lang.common.notSet,\"\"],[a.lang.common.left,\"left\"],[a.lang.common.center,\"center\"],[a.lang.common.right,\"right\"]],setup:function(a){this.setValue(a.getAttribute(\"align\")||\n\"\")},commit:function(a,d){this.getValue()?d.setAttribute(\"align\",this.getValue()):d.removeAttribute(\"align\")}}]},{type:\"vbox\",padding:0,children:[{type:\"hbox\",widths:[\"5em\"],children:[{type:\"text\",id:\"txtWidth\",requiredContent:\"table{width}\",controlStyle:\"width:5em\",label:a.lang.common.width,title:a.lang.common.cssLengthTooltip,\"default\":a.filter.check(\"table{width}\")?500>r.getSize(\"width\")?\"100%\":500:0,getValue:v,validate:CKEDITOR.dialog.validate.cssLength(a.lang.common.invalidCssLength.replace(\"%1\",\na.lang.common.width)),onChange:function(){var a=this.getDialog().getContentElement(\"advanced\",\"advStyles\");a&&a.updateStyle(\"width\",this.getValue())},setup:function(a){a=a.getStyle(\"width\");this.setValue(a)},commit:n}]},{type:\"hbox\",widths:[\"5em\"],children:[{type:\"text\",id:\"txtHeight\",requiredContent:\"table{height}\",controlStyle:\"width:5em\",label:a.lang.common.height,title:a.lang.common.cssLengthTooltip,\"default\":\"\",getValue:v,validate:CKEDITOR.dialog.validate.cssLength(a.lang.common.invalidCssLength.replace(\"%1\",\na.lang.common.height)),onChange:function(){var a=this.getDialog().getContentElement(\"advanced\",\"advStyles\");a&&a.updateStyle(\"height\",this.getValue())},setup:function(a){(a=a.getStyle(\"height\"))&&this.setValue(a)},commit:n}]},{type:\"html\",html:\"\\x26nbsp;\"},{type:\"text\",id:\"txtCellSpace\",requiredContent:\"table[cellspacing]\",controlStyle:\"width:3em\",label:a.lang.table.cellSpace,\"default\":a.filter.check(\"table[cellspacing]\")?1:0,validate:CKEDITOR.dialog.validate.number(a.lang.table.invalidCellSpacing),\nsetup:function(a){this.setValue(a.getAttribute(\"cellSpacing\")||\"\")},commit:function(a,d){this.getValue()?d.setAttribute(\"cellSpacing\",this.getValue()):d.removeAttribute(\"cellSpacing\")}},{type:\"text\",id:\"txtCellPad\",requiredContent:\"table[cellpadding]\",controlStyle:\"width:3em\",label:a.lang.table.cellPad,\"default\":a.filter.check(\"table[cellpadding]\")?1:0,validate:CKEDITOR.dialog.validate.number(a.lang.table.invalidCellPadding),setup:function(a){this.setValue(a.getAttribute(\"cellPadding\")||\"\")},commit:function(a,\nd){this.getValue()?d.setAttribute(\"cellPadding\",this.getValue()):d.removeAttribute(\"cellPadding\")}}]}]},{type:\"html\",align:\"right\",html:\"\"},{type:\"vbox\",padding:0,children:[{type:\"text\",id:\"txtCaption\",requiredContent:\"caption\",label:a.lang.table.caption,setup:function(a){this.enable();a=a.getElementsByTag(\"caption\");if(0<a.count()){a=a.getItem(0);var d=a.getFirst(CKEDITOR.dom.walker.nodeType(CKEDITOR.NODE_ELEMENT));d&&!d.equals(a.getBogus())?(this.disable(),this.setValue(a.getText())):(a=CKEDITOR.tools.trim(a.getText()),\nthis.setValue(a))}},commit:function(e,d){if(this.isEnabled()){var b=this.getValue(),c=d.getElementsByTag(\"caption\");if(b)0<c.count()?(c=c.getItem(0),c.setHtml(\"\")):(c=new CKEDITOR.dom.element(\"caption\",a.document),d.append(c,!0)),c.append(new CKEDITOR.dom.text(b,a.document));else if(0<c.count())for(b=c.count()-1;0<=b;b--)c.getItem(b).remove()}}},{type:\"text\",id:\"txtSummary\",bidi:!0,requiredContent:\"table[summary]\",label:a.lang.table.summary,setup:function(a){this.setValue(a.getAttribute(\"summary\")||\n\"\")},commit:function(a,d){this.getValue()?d.setAttribute(\"summary\",this.getValue()):d.removeAttribute(\"summary\")}}]}]},q&&q.createAdvancedTab(a,null,\"table\")]}}var v=CKEDITOR.tools.cssLength,n=function(a){var f=this.id;a.info||(a.info={});a.info[f]=this.getValue()};CKEDITOR.dialog.add(\"table\",function(a){return r(a,\"table\")});CKEDITOR.dialog.add(\"tableProperties\",function(a){return r(a,\"tableProperties\")})})();"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/adminlte/bower_components/ckeditor/plugins/tableselection/styles/tableselection.css",
    "content": ".cke_table-faked-selection-editor *::selection, table[data-cke-table-faked-selection-table] *::selection {\n\tbackground: transparent;\n}\n\n.cke_table-faked-selection {\n\tbackground: darkgray !important;\n\tcolor: black;\n}\n.cke_table-faked-selection a {\n\tcolor: black;\n}\n.cke_editable:focus .cke_table-faked-selection {\n\t/* We have to use !important here, as td might specify it's own background, thus table selection\n\twould not be visible. */\n\tbackground: #0076cb !important;\n\tcolor: white;\n}\n.cke_editable:focus .cke_table-faked-selection a {\n\tcolor: white;\n}\n.cke_table-faked-selection::-moz-selection, .cke_table-faked-selection ::-moz-selection {\n\tbackground: transparent;\n}\n.cke_table-faked-selection::selection, .cke_table-faked-selection ::selection {\n\tbackground: transparent;\n}\n\n/* Change the cursor when selecting cells (#706).\n *\n * This solution does not work in IE, Edge and Safari due to upstream isues:\n * https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/3419602/\n * https://bugs.webkit.org/show_bug.cgi?id=53341\n */\ntable[data-cke-table-faked-selection-table] {\n\tcursor: cell;\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/adminlte/bower_components/ckeditor/plugins/wsc/skins/moono-lisa/wsc.css",
    "content": ".cke_dialog_body #overlayBlock,\n.cke_dialog_body #no_check_over\n{\n    top: 39px !important;\n}\n\ndiv[name=SpellTab] .wsc-spelltab-bottom .cke_dialog_ui_vbox td > .cke_dialog_ui_button:first-child\n{\n    margin-top: 4px;\n}\n\ndiv[name=SpellTab] .wsc-spelltab-bottom .cke_dialog_ui_hbox_first .cke_dialog_ui_select > label\n{\n    margin-left: 0;\n}\n\ndiv[name=SpellTab] .wsc-spelltab-bottom .cke_dialog_ui_hbox_first .cke_dialog_ui_select div.cke_dialog_ui_input_select\n{\n    width: 140px !important;\n}\n\ndiv[name=SpellTab] .wsc-spelltab-bottom .cke_dialog_ui_hbox_first .cke_dialog_ui_select select.cke_dialog_ui_input_select,\ndiv[name=Thesaurus] div.cke_dialog_ui_input_select select.cke_dialog_ui_input_select\n{\n    margin-top: 1px;\n}\n\ndiv[name=SpellTab] .wsc-spelltab-bottom .cke_dialog_ui_hbox_first .cke_dialog_ui_select select.cke_dialog_ui_input_select:focus,\ndiv[name=Thesaurus] div.cke_dialog_ui_input_select select.cke_dialog_ui_input_select:focus\n{\n    margin-top: 0;\n}\n\ndiv[name=GrammTab] .cke_dialog_ui_vbox tbody > tr:first-child .cke_dialog_ui_button,\ndiv[name=Thesaurus] .cke_dialog_ui_vbox tbody > tr:first-child .cke_dialog_ui_button\n{\n    margin-top: 4px !important;\n}\n\ndiv[name=Thesaurus] div.cke_dialog_ui_input_select\n{\n    width: 180px !important;\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/adminlte/bower_components/ckeditor/skins/moono-lisa/dialog.css",
    "content": "/*\nCopyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.\nFor licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n*/\n.cke_dialog{visibility:visible}.cke_dialog_body{z-index:1;background:#fff}.cke_dialog strong{font-weight:bold}.cke_dialog_title{font-weight:bold;font-size:12px;cursor:move;position:relative;color:#484848;border-bottom:1px solid #d1d1d1;padding:12px 19px 12px 12px;background:#f8f8f8;letter-spacing:.3px}.cke_dialog_spinner{border-radius:50%;width:12px;height:12px;overflow:hidden;text-indent:-9999em;border:2px solid rgba(102,102,102,0.2);border-left-color:rgba(102,102,102,1);-webkit-animation:dialog_spinner 1s infinite linear;animation:dialog_spinner 1s infinite linear}.cke_browser_ie8 .cke_dialog_spinner,.cke_browser_ie9 .cke_dialog_spinner{background:url(images/spinner.gif) center top no-repeat;width:16px;height:16px;border:0}@-webkit-keyframes dialog_spinner{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes dialog_spinner{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.cke_dialog_contents{background-color:#fff;overflow:auto;padding:15px 10px 5px 10px;margin-top:43px;border-top:1px solid #d1d1d1}.cke_dialog_contents_body{overflow:auto;padding:9px 10px 5px 10px;margin-top:22px}.cke_dialog_footer{text-align:right;position:relative;border-top:1px solid #d1d1d1;background:#f8f8f8}.cke_rtl .cke_dialog_footer{text-align:left}.cke_hc .cke_dialog_footer{outline:0;border-top:1px solid #fff}.cke_dialog .cke_resizer{margin-top:22px}.cke_dialog .cke_resizer_rtl{margin-left:5px}.cke_dialog .cke_resizer_ltr{margin-right:5px}.cke_dialog_tabs{height:33px;display:inline-block;margin:9px 0 0;position:absolute;z-index:2;left:11px}.cke_rtl .cke_dialog_tabs{left:auto;right:11px}a.cke_dialog_tab{height:25px;padding:4px 8px;display:inline-block;cursor:pointer;line-height:26px;outline:0;color:#484848;border:1px solid #d1d1d1;border-radius:3px 3px 0 0;background:#f8f8f8;min-width:90px;text-align:center;margin-left:-1px;letter-spacing:.3px}a.cke_dialog_tab:hover{background-color:#fff}a.cke_dialog_tab:focus{border:2px solid #139ff7;border-bottom-color:#d1d1d1;padding:3px 7px;position:relative;z-index:1}a.cke_dialog_tab_selected{background:#fff;border-bottom-color:#fff;cursor:default;filter:none}a.cke_dialog_tab_selected:hover,a.cke_dialog_tab_selected:focus{border-bottom-color:#fff}.cke_hc a.cke_dialog_tab:hover,.cke_hc a.cke_dialog_tab:focus,.cke_hc a.cke_dialog_tab_selected{border:3px solid;padding:2px 6px}a.cke_dialog_tab_disabled{color:#bababa;cursor:default}.cke_single_page .cke_dialog_tabs{display:none}.cke_single_page .cke_dialog_contents{padding-top:5px;margin-top:0;border-top:0}a.cke_dialog_close_button{background-image:url(images/close.png);background-repeat:no-repeat;background-position:50%;position:absolute;cursor:pointer;text-align:center;height:16px;width:16px;top:11px;z-index:5;opacity:.7;filter:alpha(opacity = 70)}.cke_rtl .cke_dialog_close_button{left:12px}.cke_ltr .cke_dialog_close_button{right:12px}.cke_hc a.cke_dialog_close_button{background-image:none}.cke_hidpi a.cke_dialog_close_button{background-image:url(images/hidpi/close.png);background-size:16px}a.cke_dialog_close_button:hover{opacity:1;filter:alpha(opacity = 100)}a.cke_dialog_close_button span{display:none}.cke_hc a.cke_dialog_close_button span{display:inline;cursor:pointer;font-weight:bold;position:relative;top:3px}div.cke_disabled .cke_dialog_ui_labeled_content div *{background-color:#ddd;cursor:default}.cke_dialog_ui_vbox table,.cke_dialog_ui_hbox table{margin:auto}.cke_dialog_ui_vbox_child{padding:5px 0}.cke_dialog_ui_hbox{width:100%;margin-top:12px}.cke_dialog_ui_hbox_first,.cke_dialog_ui_hbox_child,.cke_dialog_ui_hbox_last{vertical-align:top}.cke_ltr .cke_dialog_ui_hbox_first,.cke_ltr .cke_dialog_ui_hbox_child{padding-right:10px}.cke_rtl .cke_dialog_ui_hbox_first,.cke_rtl .cke_dialog_ui_hbox_child{padding-left:10px}.cke_ltr .cke_dialog_footer_buttons .cke_dialog_ui_hbox_first,.cke_ltr .cke_dialog_footer_buttons .cke_dialog_ui_hbox_child{padding-right:5px}.cke_rtl .cke_dialog_footer_buttons .cke_dialog_ui_hbox_first,.cke_rtl .cke_dialog_footer_buttons .cke_dialog_ui_hbox_child{padding-left:5px;padding-right:0}.cke_hc div.cke_dialog_ui_input_text,.cke_hc div.cke_dialog_ui_input_password,.cke_hc div.cke_dialog_ui_input_tel,.cke_hc div.cke_dialog_ui_input_textarea,.cke_hc div.cke_dialog_ui_input_select,.cke_hc div.cke_dialog_ui_input_file{border:1px solid}textarea.cke_dialog_ui_input_textarea{overflow:auto;resize:none}input.cke_dialog_ui_input_text,input.cke_dialog_ui_input_password,input.cke_dialog_ui_input_tel,textarea.cke_dialog_ui_input_textarea{background-color:#fff;border:1px solid #bcbcbc;padding:4px 6px;outline:0;width:100%;*width:95%;box-sizing:border-box;border-radius:2px;min-height:28px;margin-left:1px}input.cke_dialog_ui_input_text:hover,input.cke_dialog_ui_input_password:hover,input.cke_dialog_ui_input_tel:hover,textarea.cke_dialog_ui_input_textarea:hover{border:1px solid #aeb3b9}input.cke_dialog_ui_input_text:focus,input.cke_dialog_ui_input_password:focus,input.cke_dialog_ui_input_tel:focus,textarea.cke_dialog_ui_input_textarea:focus,select.cke_dialog_ui_input_select:focus{outline:0;border:2px solid #139ff7}input.cke_dialog_ui_input_text:focus{padding-left:5px}textarea.cke_dialog_ui_input_textarea:focus{padding:3px 5px}select.cke_dialog_ui_input_select:focus{margin:0;width:100%!important}input.cke_dialog_ui_checkbox_input,input.cke_dialog_ui_radio_input{margin-left:1px;margin-right:2px}input.cke_dialog_ui_checkbox_input:focus,input.cke_dialog_ui_checkbox_input:active,input.cke_dialog_ui_radio_input:focus,input.cke_dialog_ui_radio_input:active{border:0;outline:2px solid #139ff7}a.cke_dialog_ui_button{display:inline-block;*display:inline;*zoom:1;padding:4px 1px;margin:0;text-align:center;color:#484848;vertical-align:middle;cursor:pointer;border:1px solid #bcbcbc;border-radius:2px;background:#f8f8f8;letter-spacing:.3px;line-height:18px;box-sizing:border-box}.cke_hc a.cke_dialog_ui_button{border-width:3px}span.cke_dialog_ui_button{padding:0 10px;cursor:pointer}a.cke_dialog_ui_button:hover{background:#fff}a.cke_dialog_ui_button:focus,a.cke_dialog_ui_button:active{border:2px solid #139ff7;outline:0;padding:3px 0}.cke_hc a.cke_dialog_ui_button:hover,.cke_hc a.cke_dialog_ui_button:focus,.cke_hc a.cke_dialog_ui_button:active{border:3px solid}.cke_dialog_footer_buttons a.cke_dialog_ui_button span{color:inherit;font-size:12px;font-weight:bold;padding:0 12px}a.cke_dialog_ui_button_ok{color:#fff;background:#09863e;border:1px solid #09863e}.cke_hc a.cke_dialog_ui_button{border:3px solid #bcbcbc}a.cke_dialog_ui_button_ok:hover{background:#53aa78;border-color:#53aa78}a.cke_dialog_ui_button_ok:focus{box-shadow:inset 0 0 0 2px #FFF}a.cke_dialog_ui_button_ok:focus,a.cke_dialog_ui_button_ok:active{border-color:#139ff7}.cke_hc a.cke_dialog_ui_button_ok:hover,.cke_hc a.cke_dialog_ui_button_ok:focus,.cke_hc a.cke_dialog_ui_button_ok:active{border-color:#484848}a.cke_dialog_ui_button_ok.cke_disabled{background:#d1d1d1;border-color:#d1d1d1;cursor:default}a.cke_dialog_ui_button_ok.cke_disabled span{cursor:default}.cke_dialog_footer_buttons{display:inline-table;margin:5px;width:auto;position:relative;vertical-align:middle}div.cke_dialog_ui_input_select{display:table}select.cke_dialog_ui_input_select{height:28px;line-height:28px;background-color:#fff;border:1px solid #bcbcbc;padding:3px 3px 3px 6px;outline:0;border-radius:2px;margin:0 1px;box-sizing:border-box;width:calc(100% - 2px)!important}.cke_dialog_ui_input_file{width:100%;height:25px}.cke_hc .cke_dialog_ui_labeled_content input:focus,.cke_hc .cke_dialog_ui_labeled_content select:focus,.cke_hc .cke_dialog_ui_labeled_content textarea:focus{outline:1px dotted}.cke_dialog_ui_labeled_label{margin-left:1px}.cke_dialog .cke_dark_background{background-color:transparent}.cke_dialog .cke_light_background{background-color:#ebebeb}.cke_dialog .cke_centered{text-align:center}.cke_dialog a.cke_btn_reset{float:right;background:url(images/refresh.png) top left no-repeat;width:16px;height:16px;border:1px none;font-size:1px}.cke_hidpi .cke_dialog a.cke_btn_reset{background-size:16px;background-image:url(images/hidpi/refresh.png)}.cke_rtl .cke_dialog a.cke_btn_reset{float:left}.cke_dialog a.cke_btn_locked,.cke_dialog a.cke_btn_unlocked{float:left;width:16px;height:16px;background-repeat:no-repeat;border:none 1px;font-size:1px}.cke_dialog a.cke_btn_locked,.cke_dialog a.cke_btn_unlocked,.cke_dialog a.cke_btn_reset{margin:2px}.cke_dialog a.cke_btn_locked{background-image:url(images/lock.png)}.cke_dialog a.cke_btn_unlocked{background-image:url(images/lock-open.png)}.cke_rtl .cke_dialog a.cke_btn_locked,.cke_rtl .cke_dialog a.cke_btn_unlocked{float:right}.cke_hidpi .cke_dialog a.cke_btn_unlocked,.cke_hidpi .cke_dialog a.cke_btn_locked{background-size:16px}.cke_hidpi .cke_dialog a.cke_btn_locked{background-image:url(images/hidpi/lock.png)}.cke_hidpi .cke_dialog a.cke_btn_unlocked{background-image:url(images/hidpi/lock-open.png)}.cke_dialog a.cke_btn_locked .cke_icon{display:none}.cke_dialog a.cke_btn_over,.cke_dialog a.cke_btn_locked:hover,.cke_dialog a.cke_btn_locked:focus,.cke_dialog a.cke_btn_locked:active,.cke_dialog a.cke_btn_unlocked:hover,.cke_dialog a.cke_btn_unlocked:focus,.cke_dialog a.cke_btn_unlocked:active,.cke_dialog a.cke_btn_reset:hover,.cke_dialog a.cke_btn_reset:focus,.cke_dialog a.cke_btn_reset:active{cursor:pointer;outline:0;margin:0;border:2px solid #139ff7}.cke_dialog fieldset{border:1px solid #bcbcbc}.cke_dialog fieldset legend{padding:0 6px}.cke_dialog_ui_checkbox,.cke_dialog fieldset .cke_dialog_ui_vbox .cke_dialog_ui_checkbox{display:inline-block}.cke_dialog fieldset .cke_dialog_ui_vbox .cke_dialog_ui_checkbox{padding-top:5px}.cke_dialog_ui_checkbox .cke_dialog_ui_checkbox_input,.cke_dialog_ui_checkbox .cke_dialog_ui_checkbox_input+label,.cke_dialog fieldset .cke_dialog_ui_vbox .cke_dialog_ui_checkbox .cke_dialog_ui_checkbox_input,.cke_dialog fieldset .cke_dialog_ui_vbox .cke_dialog_ui_checkbox .cke_dialog_ui_checkbox_input+label{vertical-align:middle}.cke_dialog .ImagePreviewBox{border:1px ridge #bcbcbc;overflow:scroll;height:200px;width:300px;padding:2px;background-color:white}.cke_dialog .ImagePreviewBox table td{white-space:normal}.cke_dialog .ImagePreviewLoader{position:absolute;white-space:normal;overflow:hidden;height:160px;width:230px;margin:2px;padding:2px;opacity:.9;filter:alpha(opacity = 90);background-color:#e4e4e4}.cke_dialog .FlashPreviewBox{white-space:normal;border:1px solid #bcbcbc;overflow:auto;height:160px;width:390px;padding:2px;background-color:white}.cke_dialog .cke_pastetext{width:346px;height:170px}.cke_dialog .cke_pastetext textarea{width:340px;height:170px;resize:none}.cke_dialog iframe.cke_pasteframe{width:346px;height:130px;background-color:white;border:1px solid #aeb3b9;border-radius:3px}.cke_dialog .cke_hand{cursor:pointer}.cke_disabled{color:#a0a0a0}.cke_dialog_body .cke_label{display:none}.cke_dialog_body label{display:inline;cursor:default;letter-spacing:.3px}.cke_dialog_body label+.cke_dialog_ui_labeled_content{margin-top:2px}.cke_dialog_contents_body .cke_dialog_ui_text,.cke_dialog_contents_body .cke_dialog_ui_select,.cke_dialog_contents_body .cke_dialog_ui_hbox_last>a.cke_dialog_ui_button{margin-top:4px}a.cke_smile{overflow:hidden;display:block;text-align:center;padding:.3em 0}a.cke_smile img{vertical-align:middle}a.cke_specialchar{cursor:inherit;display:block;height:1.25em;padding:.2em .3em;text-align:center}a.cke_smile,a.cke_specialchar{border:2px solid transparent}a.cke_smile:hover,a.cke_smile:focus,a.cke_smile:active,a.cke_specialchar:hover,a.cke_specialchar:focus,a.cke_specialchar:active{background:#fff;outline:0}a.cke_smile:hover,a.cke_specialchar:hover{border-color:#888}a.cke_smile:focus,a.cke_smile:active,a.cke_specialchar:focus,a.cke_specialchar:active{border-color:#139ff7}.cke_dialog_contents a.colorChooser{display:block;margin-top:6px;margin-left:10px;width:80px}.cke_rtl .cke_dialog_contents a.colorChooser{margin-right:10px}.cke_iframe_shim{display:block;position:absolute;top:0;left:0;z-index:-1;filter:alpha(opacity = 0);width:100%;height:100%}.cke_dialog_contents_body .cke_accessibility_legend{margin:2px 7px 2px 2px}.cke_dialog_contents_body .cke_accessibility_legend:focus,.cke_dialog_contents_body .cke_accessibility_legend:active{outline:0;border:2px solid #139ff7;margin:0 5px 0 0}.cke_dialog_contents_body input[type=file]:focus,.cke_dialog_contents_body input[type=file]:active{border:2px solid #139ff7}.cke_dialog_find_fieldset{margin-top:10px!important}.cke_dialog_image_ratiolock{margin-top:52px!important}.cke_dialog_forms_select_order label.cke_dialog_ui_labeled_label{margin-left:0}.cke_dialog_forms_select_order div.cke_dialog_ui_input_select{width:100%}.cke_dialog_forms_select_order_txtsize .cke_dialog_ui_hbox_last{padding-top:4px}.cke_dialog_image_url .cke_dialog_ui_hbox_last,.cke_dialog_flash_url .cke_dialog_ui_hbox_last{vertical-align:bottom}a.cke_dialog_ui_button.cke_dialog_image_browse{margin-top:10px}.cke_dialog_contents_body .cke_tpl_list{border:#bcbcbc 1px solid;margin:1px}.cke_dialog_contents_body .cke_tpl_list:focus,.cke_dialog_contents_body .cke_tpl_list:active{outline:0;margin:0;border:2px solid #139ff7}.cke_dialog_contents_body .cke_tpl_list a:focus,.cke_dialog_contents_body .cke_tpl_list a:active{outline:0}.cke_dialog_contents_body .cke_tpl_list a:focus .cke_tpl_item,.cke_dialog_contents_body .cke_tpl_list a:active .cke_tpl_item{border:2px solid #139ff7;padding:6px}"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/adminlte/bower_components/ckeditor/skins/moono-lisa/dialog_ie.css",
    "content": "/*\nCopyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.\nFor licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n*/\n.cke_dialog{visibility:visible}.cke_dialog_body{z-index:1;background:#fff}.cke_dialog strong{font-weight:bold}.cke_dialog_title{font-weight:bold;font-size:12px;cursor:move;position:relative;color:#484848;border-bottom:1px solid #d1d1d1;padding:12px 19px 12px 12px;background:#f8f8f8;letter-spacing:.3px}.cke_dialog_spinner{border-radius:50%;width:12px;height:12px;overflow:hidden;text-indent:-9999em;border:2px solid rgba(102,102,102,0.2);border-left-color:rgba(102,102,102,1);-webkit-animation:dialog_spinner 1s infinite linear;animation:dialog_spinner 1s infinite linear}.cke_browser_ie8 .cke_dialog_spinner,.cke_browser_ie9 .cke_dialog_spinner{background:url(images/spinner.gif) center top no-repeat;width:16px;height:16px;border:0}@-webkit-keyframes dialog_spinner{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes dialog_spinner{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.cke_dialog_contents{background-color:#fff;overflow:auto;padding:15px 10px 5px 10px;margin-top:43px;border-top:1px solid #d1d1d1}.cke_dialog_contents_body{overflow:auto;padding:9px 10px 5px 10px;margin-top:22px}.cke_dialog_footer{text-align:right;position:relative;border-top:1px solid #d1d1d1;background:#f8f8f8}.cke_rtl .cke_dialog_footer{text-align:left}.cke_hc .cke_dialog_footer{outline:0;border-top:1px solid #fff}.cke_dialog .cke_resizer{margin-top:22px}.cke_dialog .cke_resizer_rtl{margin-left:5px}.cke_dialog .cke_resizer_ltr{margin-right:5px}.cke_dialog_tabs{height:33px;display:inline-block;margin:9px 0 0;position:absolute;z-index:2;left:11px}.cke_rtl .cke_dialog_tabs{left:auto;right:11px}a.cke_dialog_tab{height:25px;padding:4px 8px;display:inline-block;cursor:pointer;line-height:26px;outline:0;color:#484848;border:1px solid #d1d1d1;border-radius:3px 3px 0 0;background:#f8f8f8;min-width:90px;text-align:center;margin-left:-1px;letter-spacing:.3px}a.cke_dialog_tab:hover{background-color:#fff}a.cke_dialog_tab:focus{border:2px solid #139ff7;border-bottom-color:#d1d1d1;padding:3px 7px;position:relative;z-index:1}a.cke_dialog_tab_selected{background:#fff;border-bottom-color:#fff;cursor:default;filter:none}a.cke_dialog_tab_selected:hover,a.cke_dialog_tab_selected:focus{border-bottom-color:#fff}.cke_hc a.cke_dialog_tab:hover,.cke_hc a.cke_dialog_tab:focus,.cke_hc a.cke_dialog_tab_selected{border:3px solid;padding:2px 6px}a.cke_dialog_tab_disabled{color:#bababa;cursor:default}.cke_single_page .cke_dialog_tabs{display:none}.cke_single_page .cke_dialog_contents{padding-top:5px;margin-top:0;border-top:0}a.cke_dialog_close_button{background-image:url(images/close.png);background-repeat:no-repeat;background-position:50%;position:absolute;cursor:pointer;text-align:center;height:16px;width:16px;top:11px;z-index:5;opacity:.7;filter:alpha(opacity = 70)}.cke_rtl .cke_dialog_close_button{left:12px}.cke_ltr .cke_dialog_close_button{right:12px}.cke_hc a.cke_dialog_close_button{background-image:none}.cke_hidpi a.cke_dialog_close_button{background-image:url(images/hidpi/close.png);background-size:16px}a.cke_dialog_close_button:hover{opacity:1;filter:alpha(opacity = 100)}a.cke_dialog_close_button span{display:none}.cke_hc a.cke_dialog_close_button span{display:inline;cursor:pointer;font-weight:bold;position:relative;top:3px}div.cke_disabled .cke_dialog_ui_labeled_content div *{background-color:#ddd;cursor:default}.cke_dialog_ui_vbox table,.cke_dialog_ui_hbox table{margin:auto}.cke_dialog_ui_vbox_child{padding:5px 0}.cke_dialog_ui_hbox{width:100%;margin-top:12px}.cke_dialog_ui_hbox_first,.cke_dialog_ui_hbox_child,.cke_dialog_ui_hbox_last{vertical-align:top}.cke_ltr .cke_dialog_ui_hbox_first,.cke_ltr .cke_dialog_ui_hbox_child{padding-right:10px}.cke_rtl .cke_dialog_ui_hbox_first,.cke_rtl .cke_dialog_ui_hbox_child{padding-left:10px}.cke_ltr .cke_dialog_footer_buttons .cke_dialog_ui_hbox_first,.cke_ltr .cke_dialog_footer_buttons .cke_dialog_ui_hbox_child{padding-right:5px}.cke_rtl .cke_dialog_footer_buttons .cke_dialog_ui_hbox_first,.cke_rtl .cke_dialog_footer_buttons .cke_dialog_ui_hbox_child{padding-left:5px;padding-right:0}.cke_hc div.cke_dialog_ui_input_text,.cke_hc div.cke_dialog_ui_input_password,.cke_hc div.cke_dialog_ui_input_tel,.cke_hc div.cke_dialog_ui_input_textarea,.cke_hc div.cke_dialog_ui_input_select,.cke_hc div.cke_dialog_ui_input_file{border:1px solid}textarea.cke_dialog_ui_input_textarea{overflow:auto;resize:none}input.cke_dialog_ui_input_text,input.cke_dialog_ui_input_password,input.cke_dialog_ui_input_tel,textarea.cke_dialog_ui_input_textarea{background-color:#fff;border:1px solid #bcbcbc;padding:4px 6px;outline:0;width:100%;*width:95%;box-sizing:border-box;border-radius:2px;min-height:28px;margin-left:1px}input.cke_dialog_ui_input_text:hover,input.cke_dialog_ui_input_password:hover,input.cke_dialog_ui_input_tel:hover,textarea.cke_dialog_ui_input_textarea:hover{border:1px solid #aeb3b9}input.cke_dialog_ui_input_text:focus,input.cke_dialog_ui_input_password:focus,input.cke_dialog_ui_input_tel:focus,textarea.cke_dialog_ui_input_textarea:focus,select.cke_dialog_ui_input_select:focus{outline:0;border:2px solid #139ff7}input.cke_dialog_ui_input_text:focus{padding-left:5px}textarea.cke_dialog_ui_input_textarea:focus{padding:3px 5px}select.cke_dialog_ui_input_select:focus{margin:0;width:100%!important}input.cke_dialog_ui_checkbox_input,input.cke_dialog_ui_radio_input{margin-left:1px;margin-right:2px}input.cke_dialog_ui_checkbox_input:focus,input.cke_dialog_ui_checkbox_input:active,input.cke_dialog_ui_radio_input:focus,input.cke_dialog_ui_radio_input:active{border:0;outline:2px solid #139ff7}a.cke_dialog_ui_button{display:inline-block;*display:inline;*zoom:1;padding:4px 1px;margin:0;text-align:center;color:#484848;vertical-align:middle;cursor:pointer;border:1px solid #bcbcbc;border-radius:2px;background:#f8f8f8;letter-spacing:.3px;line-height:18px;box-sizing:border-box}.cke_hc a.cke_dialog_ui_button{border-width:3px}span.cke_dialog_ui_button{padding:0 10px;cursor:pointer}a.cke_dialog_ui_button:hover{background:#fff}a.cke_dialog_ui_button:focus,a.cke_dialog_ui_button:active{border:2px solid #139ff7;outline:0;padding:3px 0}.cke_hc a.cke_dialog_ui_button:hover,.cke_hc a.cke_dialog_ui_button:focus,.cke_hc a.cke_dialog_ui_button:active{border:3px solid}.cke_dialog_footer_buttons a.cke_dialog_ui_button span{color:inherit;font-size:12px;font-weight:bold;padding:0 12px}a.cke_dialog_ui_button_ok{color:#fff;background:#09863e;border:1px solid #09863e}.cke_hc a.cke_dialog_ui_button{border:3px solid #bcbcbc}a.cke_dialog_ui_button_ok:hover{background:#53aa78;border-color:#53aa78}a.cke_dialog_ui_button_ok:focus{box-shadow:inset 0 0 0 2px #FFF}a.cke_dialog_ui_button_ok:focus,a.cke_dialog_ui_button_ok:active{border-color:#139ff7}.cke_hc a.cke_dialog_ui_button_ok:hover,.cke_hc a.cke_dialog_ui_button_ok:focus,.cke_hc a.cke_dialog_ui_button_ok:active{border-color:#484848}a.cke_dialog_ui_button_ok.cke_disabled{background:#d1d1d1;border-color:#d1d1d1;cursor:default}a.cke_dialog_ui_button_ok.cke_disabled span{cursor:default}.cke_dialog_footer_buttons{display:inline-table;margin:5px;width:auto;position:relative;vertical-align:middle}div.cke_dialog_ui_input_select{display:table}select.cke_dialog_ui_input_select{height:28px;line-height:28px;background-color:#fff;border:1px solid #bcbcbc;padding:3px 3px 3px 6px;outline:0;border-radius:2px;margin:0 1px;box-sizing:border-box;width:calc(100% - 2px)!important}.cke_dialog_ui_input_file{width:100%;height:25px}.cke_hc .cke_dialog_ui_labeled_content input:focus,.cke_hc .cke_dialog_ui_labeled_content select:focus,.cke_hc .cke_dialog_ui_labeled_content textarea:focus{outline:1px dotted}.cke_dialog_ui_labeled_label{margin-left:1px}.cke_dialog .cke_dark_background{background-color:transparent}.cke_dialog .cke_light_background{background-color:#ebebeb}.cke_dialog .cke_centered{text-align:center}.cke_dialog a.cke_btn_reset{float:right;background:url(images/refresh.png) top left no-repeat;width:16px;height:16px;border:1px none;font-size:1px}.cke_hidpi .cke_dialog a.cke_btn_reset{background-size:16px;background-image:url(images/hidpi/refresh.png)}.cke_rtl .cke_dialog a.cke_btn_reset{float:left}.cke_dialog a.cke_btn_locked,.cke_dialog a.cke_btn_unlocked{float:left;width:16px;height:16px;background-repeat:no-repeat;border:none 1px;font-size:1px}.cke_dialog a.cke_btn_locked,.cke_dialog a.cke_btn_unlocked,.cke_dialog a.cke_btn_reset{margin:2px}.cke_dialog a.cke_btn_locked{background-image:url(images/lock.png)}.cke_dialog a.cke_btn_unlocked{background-image:url(images/lock-open.png)}.cke_rtl .cke_dialog a.cke_btn_locked,.cke_rtl .cke_dialog a.cke_btn_unlocked{float:right}.cke_hidpi .cke_dialog a.cke_btn_unlocked,.cke_hidpi .cke_dialog a.cke_btn_locked{background-size:16px}.cke_hidpi .cke_dialog a.cke_btn_locked{background-image:url(images/hidpi/lock.png)}.cke_hidpi .cke_dialog a.cke_btn_unlocked{background-image:url(images/hidpi/lock-open.png)}.cke_dialog a.cke_btn_locked .cke_icon{display:none}.cke_dialog a.cke_btn_over,.cke_dialog a.cke_btn_locked:hover,.cke_dialog a.cke_btn_locked:focus,.cke_dialog a.cke_btn_locked:active,.cke_dialog a.cke_btn_unlocked:hover,.cke_dialog a.cke_btn_unlocked:focus,.cke_dialog a.cke_btn_unlocked:active,.cke_dialog a.cke_btn_reset:hover,.cke_dialog a.cke_btn_reset:focus,.cke_dialog a.cke_btn_reset:active{cursor:pointer;outline:0;margin:0;border:2px solid #139ff7}.cke_dialog fieldset{border:1px solid #bcbcbc}.cke_dialog fieldset legend{padding:0 6px}.cke_dialog_ui_checkbox,.cke_dialog fieldset .cke_dialog_ui_vbox .cke_dialog_ui_checkbox{display:inline-block}.cke_dialog fieldset .cke_dialog_ui_vbox .cke_dialog_ui_checkbox{padding-top:5px}.cke_dialog_ui_checkbox .cke_dialog_ui_checkbox_input,.cke_dialog_ui_checkbox .cke_dialog_ui_checkbox_input+label,.cke_dialog fieldset .cke_dialog_ui_vbox .cke_dialog_ui_checkbox .cke_dialog_ui_checkbox_input,.cke_dialog fieldset .cke_dialog_ui_vbox .cke_dialog_ui_checkbox .cke_dialog_ui_checkbox_input+label{vertical-align:middle}.cke_dialog .ImagePreviewBox{border:1px ridge #bcbcbc;overflow:scroll;height:200px;width:300px;padding:2px;background-color:white}.cke_dialog .ImagePreviewBox table td{white-space:normal}.cke_dialog .ImagePreviewLoader{position:absolute;white-space:normal;overflow:hidden;height:160px;width:230px;margin:2px;padding:2px;opacity:.9;filter:alpha(opacity = 90);background-color:#e4e4e4}.cke_dialog .FlashPreviewBox{white-space:normal;border:1px solid #bcbcbc;overflow:auto;height:160px;width:390px;padding:2px;background-color:white}.cke_dialog .cke_pastetext{width:346px;height:170px}.cke_dialog .cke_pastetext textarea{width:340px;height:170px;resize:none}.cke_dialog iframe.cke_pasteframe{width:346px;height:130px;background-color:white;border:1px solid #aeb3b9;border-radius:3px}.cke_dialog .cke_hand{cursor:pointer}.cke_disabled{color:#a0a0a0}.cke_dialog_body .cke_label{display:none}.cke_dialog_body label{display:inline;cursor:default;letter-spacing:.3px}.cke_dialog_body label+.cke_dialog_ui_labeled_content{margin-top:2px}.cke_dialog_contents_body .cke_dialog_ui_text,.cke_dialog_contents_body .cke_dialog_ui_select,.cke_dialog_contents_body .cke_dialog_ui_hbox_last>a.cke_dialog_ui_button{margin-top:4px}a.cke_smile{overflow:hidden;display:block;text-align:center;padding:.3em 0}a.cke_smile img{vertical-align:middle}a.cke_specialchar{cursor:inherit;display:block;height:1.25em;padding:.2em .3em;text-align:center}a.cke_smile,a.cke_specialchar{border:2px solid transparent}a.cke_smile:hover,a.cke_smile:focus,a.cke_smile:active,a.cke_specialchar:hover,a.cke_specialchar:focus,a.cke_specialchar:active{background:#fff;outline:0}a.cke_smile:hover,a.cke_specialchar:hover{border-color:#888}a.cke_smile:focus,a.cke_smile:active,a.cke_specialchar:focus,a.cke_specialchar:active{border-color:#139ff7}.cke_dialog_contents a.colorChooser{display:block;margin-top:6px;margin-left:10px;width:80px}.cke_rtl .cke_dialog_contents a.colorChooser{margin-right:10px}.cke_iframe_shim{display:block;position:absolute;top:0;left:0;z-index:-1;filter:alpha(opacity = 0);width:100%;height:100%}.cke_dialog_contents_body .cke_accessibility_legend{margin:2px 7px 2px 2px}.cke_dialog_contents_body .cke_accessibility_legend:focus,.cke_dialog_contents_body .cke_accessibility_legend:active{outline:0;border:2px solid #139ff7;margin:0 5px 0 0}.cke_dialog_contents_body input[type=file]:focus,.cke_dialog_contents_body input[type=file]:active{border:2px solid #139ff7}.cke_dialog_find_fieldset{margin-top:10px!important}.cke_dialog_image_ratiolock{margin-top:52px!important}.cke_dialog_forms_select_order label.cke_dialog_ui_labeled_label{margin-left:0}.cke_dialog_forms_select_order div.cke_dialog_ui_input_select{width:100%}.cke_dialog_forms_select_order_txtsize .cke_dialog_ui_hbox_last{padding-top:4px}.cke_dialog_image_url .cke_dialog_ui_hbox_last,.cke_dialog_flash_url .cke_dialog_ui_hbox_last{vertical-align:bottom}a.cke_dialog_ui_button.cke_dialog_image_browse{margin-top:10px}.cke_dialog_contents_body .cke_tpl_list{border:#bcbcbc 1px solid;margin:1px}.cke_dialog_contents_body .cke_tpl_list:focus,.cke_dialog_contents_body .cke_tpl_list:active{outline:0;margin:0;border:2px solid #139ff7}.cke_dialog_contents_body .cke_tpl_list a:focus,.cke_dialog_contents_body .cke_tpl_list a:active{outline:0}.cke_dialog_contents_body .cke_tpl_list a:focus .cke_tpl_item,.cke_dialog_contents_body .cke_tpl_list a:active .cke_tpl_item{border:2px solid #139ff7;padding:6px}.cke_rtl input.cke_dialog_ui_input_text,.cke_rtl input.cke_dialog_ui_input_password,.cke_rtl input.cke_dialog_ui_input_tel{padding-right:2px}.cke_rtl div.cke_dialog_ui_input_text,.cke_rtl div.cke_dialog_ui_input_password,.cke_rtl div.cke_dialog_ui_input_tel{padding-left:2px}.cke_rtl div.cke_dialog_ui_input_text{padding-right:1px}.cke_rtl .cke_dialog_ui_vbox_child,.cke_rtl .cke_dialog_ui_hbox_child,.cke_rtl .cke_dialog_ui_hbox_first,.cke_rtl .cke_dialog_ui_hbox_last{padding-right:2px!important}.cke_hc .cke_dialog_title,.cke_hc .cke_dialog_footer,.cke_hc a.cke_dialog_tab,.cke_hc a.cke_dialog_ui_button,.cke_hc a.cke_dialog_ui_button:hover,.cke_hc a.cke_dialog_ui_button_ok,.cke_hc a.cke_dialog_ui_button_ok:hover{filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.cke_hc div.cke_dialog_ui_input_text,.cke_hc div.cke_dialog_ui_input_password,.cke_hc div.cke_dialog_ui_input_tel,.cke_hc div.cke_dialog_ui_input_textarea,.cke_hc div.cke_dialog_ui_input_select,.cke_hc div.cke_dialog_ui_input_file{border:0}"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/adminlte/bower_components/ckeditor/skins/moono-lisa/dialog_ie8.css",
    "content": "/*\nCopyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.\nFor licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n*/\n.cke_dialog{visibility:visible}.cke_dialog_body{z-index:1;background:#fff}.cke_dialog strong{font-weight:bold}.cke_dialog_title{font-weight:bold;font-size:12px;cursor:move;position:relative;color:#484848;border-bottom:1px solid #d1d1d1;padding:12px 19px 12px 12px;background:#f8f8f8;letter-spacing:.3px}.cke_dialog_spinner{border-radius:50%;width:12px;height:12px;overflow:hidden;text-indent:-9999em;border:2px solid rgba(102,102,102,0.2);border-left-color:rgba(102,102,102,1);-webkit-animation:dialog_spinner 1s infinite linear;animation:dialog_spinner 1s infinite linear}.cke_browser_ie8 .cke_dialog_spinner,.cke_browser_ie9 .cke_dialog_spinner{background:url(images/spinner.gif) center top no-repeat;width:16px;height:16px;border:0}@-webkit-keyframes dialog_spinner{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes dialog_spinner{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.cke_dialog_contents{background-color:#fff;overflow:auto;padding:15px 10px 5px 10px;margin-top:43px;border-top:1px solid #d1d1d1}.cke_dialog_contents_body{overflow:auto;padding:9px 10px 5px 10px;margin-top:22px}.cke_dialog_footer{text-align:right;position:relative;border-top:1px solid #d1d1d1;background:#f8f8f8}.cke_rtl .cke_dialog_footer{text-align:left}.cke_hc .cke_dialog_footer{outline:0;border-top:1px solid #fff}.cke_dialog .cke_resizer{margin-top:22px}.cke_dialog .cke_resizer_rtl{margin-left:5px}.cke_dialog .cke_resizer_ltr{margin-right:5px}.cke_dialog_tabs{height:33px;display:inline-block;margin:9px 0 0;position:absolute;z-index:2;left:11px}.cke_rtl .cke_dialog_tabs{left:auto;right:11px}a.cke_dialog_tab{height:25px;padding:4px 8px;display:inline-block;cursor:pointer;line-height:26px;outline:0;color:#484848;border:1px solid #d1d1d1;border-radius:3px 3px 0 0;background:#f8f8f8;min-width:90px;text-align:center;margin-left:-1px;letter-spacing:.3px}a.cke_dialog_tab:hover{background-color:#fff}a.cke_dialog_tab:focus{border:2px solid #139ff7;border-bottom-color:#d1d1d1;padding:3px 7px;position:relative;z-index:1}a.cke_dialog_tab_selected{background:#fff;border-bottom-color:#fff;cursor:default;filter:none}a.cke_dialog_tab_selected:hover,a.cke_dialog_tab_selected:focus{border-bottom-color:#fff}.cke_hc a.cke_dialog_tab:hover,.cke_hc a.cke_dialog_tab:focus,.cke_hc a.cke_dialog_tab_selected{border:3px solid;padding:2px 6px}a.cke_dialog_tab_disabled{color:#bababa;cursor:default}.cke_single_page .cke_dialog_tabs{display:none}.cke_single_page .cke_dialog_contents{padding-top:5px;margin-top:0;border-top:0}a.cke_dialog_close_button{background-image:url(images/close.png);background-repeat:no-repeat;background-position:50%;position:absolute;cursor:pointer;text-align:center;height:16px;width:16px;top:11px;z-index:5;opacity:.7;filter:alpha(opacity = 70)}.cke_rtl .cke_dialog_close_button{left:12px}.cke_ltr .cke_dialog_close_button{right:12px}.cke_hc a.cke_dialog_close_button{background-image:none}.cke_hidpi a.cke_dialog_close_button{background-image:url(images/hidpi/close.png);background-size:16px}a.cke_dialog_close_button:hover{opacity:1;filter:alpha(opacity = 100)}a.cke_dialog_close_button span{display:none}.cke_hc a.cke_dialog_close_button span{display:inline;cursor:pointer;font-weight:bold;position:relative;top:3px}div.cke_disabled .cke_dialog_ui_labeled_content div *{background-color:#ddd;cursor:default}.cke_dialog_ui_vbox table,.cke_dialog_ui_hbox table{margin:auto}.cke_dialog_ui_vbox_child{padding:5px 0}.cke_dialog_ui_hbox{width:100%;margin-top:12px}.cke_dialog_ui_hbox_first,.cke_dialog_ui_hbox_child,.cke_dialog_ui_hbox_last{vertical-align:top}.cke_ltr .cke_dialog_ui_hbox_first,.cke_ltr .cke_dialog_ui_hbox_child{padding-right:10px}.cke_rtl .cke_dialog_ui_hbox_first,.cke_rtl .cke_dialog_ui_hbox_child{padding-left:10px}.cke_ltr .cke_dialog_footer_buttons .cke_dialog_ui_hbox_first,.cke_ltr .cke_dialog_footer_buttons .cke_dialog_ui_hbox_child{padding-right:5px}.cke_rtl .cke_dialog_footer_buttons .cke_dialog_ui_hbox_first,.cke_rtl .cke_dialog_footer_buttons .cke_dialog_ui_hbox_child{padding-left:5px;padding-right:0}.cke_hc div.cke_dialog_ui_input_text,.cke_hc div.cke_dialog_ui_input_password,.cke_hc div.cke_dialog_ui_input_tel,.cke_hc div.cke_dialog_ui_input_textarea,.cke_hc div.cke_dialog_ui_input_select,.cke_hc div.cke_dialog_ui_input_file{border:1px solid}textarea.cke_dialog_ui_input_textarea{overflow:auto;resize:none}input.cke_dialog_ui_input_text,input.cke_dialog_ui_input_password,input.cke_dialog_ui_input_tel,textarea.cke_dialog_ui_input_textarea{background-color:#fff;border:1px solid #bcbcbc;padding:4px 6px;outline:0;width:100%;*width:95%;box-sizing:border-box;border-radius:2px;min-height:28px;margin-left:1px}input.cke_dialog_ui_input_text:hover,input.cke_dialog_ui_input_password:hover,input.cke_dialog_ui_input_tel:hover,textarea.cke_dialog_ui_input_textarea:hover{border:1px solid #aeb3b9}input.cke_dialog_ui_input_text:focus,input.cke_dialog_ui_input_password:focus,input.cke_dialog_ui_input_tel:focus,textarea.cke_dialog_ui_input_textarea:focus,select.cke_dialog_ui_input_select:focus{outline:0;border:2px solid #139ff7}input.cke_dialog_ui_input_text:focus{padding-left:5px}textarea.cke_dialog_ui_input_textarea:focus{padding:3px 5px}select.cke_dialog_ui_input_select:focus{margin:0;width:100%!important}input.cke_dialog_ui_checkbox_input,input.cke_dialog_ui_radio_input{margin-left:1px;margin-right:2px}input.cke_dialog_ui_checkbox_input:focus,input.cke_dialog_ui_checkbox_input:active,input.cke_dialog_ui_radio_input:focus,input.cke_dialog_ui_radio_input:active{border:0;outline:2px solid #139ff7}a.cke_dialog_ui_button{display:inline-block;*display:inline;*zoom:1;padding:4px 1px;margin:0;text-align:center;color:#484848;vertical-align:middle;cursor:pointer;border:1px solid #bcbcbc;border-radius:2px;background:#f8f8f8;letter-spacing:.3px;line-height:18px;box-sizing:border-box}.cke_hc a.cke_dialog_ui_button{border-width:3px}span.cke_dialog_ui_button{padding:0 10px;cursor:pointer}a.cke_dialog_ui_button:hover{background:#fff}a.cke_dialog_ui_button:focus,a.cke_dialog_ui_button:active{border:2px solid #139ff7;outline:0;padding:3px 0}.cke_hc a.cke_dialog_ui_button:hover,.cke_hc a.cke_dialog_ui_button:focus,.cke_hc a.cke_dialog_ui_button:active{border:3px solid}.cke_dialog_footer_buttons a.cke_dialog_ui_button span{color:inherit;font-size:12px;font-weight:bold;padding:0 12px}a.cke_dialog_ui_button_ok{color:#fff;background:#09863e;border:1px solid #09863e}.cke_hc a.cke_dialog_ui_button{border:3px solid #bcbcbc}a.cke_dialog_ui_button_ok:hover{background:#53aa78;border-color:#53aa78}a.cke_dialog_ui_button_ok:focus{box-shadow:inset 0 0 0 2px #FFF}a.cke_dialog_ui_button_ok:focus,a.cke_dialog_ui_button_ok:active{border-color:#139ff7}.cke_hc a.cke_dialog_ui_button_ok:hover,.cke_hc a.cke_dialog_ui_button_ok:focus,.cke_hc a.cke_dialog_ui_button_ok:active{border-color:#484848}a.cke_dialog_ui_button_ok.cke_disabled{background:#d1d1d1;border-color:#d1d1d1;cursor:default}a.cke_dialog_ui_button_ok.cke_disabled span{cursor:default}.cke_dialog_footer_buttons{display:inline-table;margin:5px;width:auto;position:relative;vertical-align:middle}div.cke_dialog_ui_input_select{display:table}select.cke_dialog_ui_input_select{height:28px;line-height:28px;background-color:#fff;border:1px solid #bcbcbc;padding:3px 3px 3px 6px;outline:0;border-radius:2px;margin:0 1px;box-sizing:border-box;width:calc(100% - 2px)!important}.cke_dialog_ui_input_file{width:100%;height:25px}.cke_hc .cke_dialog_ui_labeled_content input:focus,.cke_hc .cke_dialog_ui_labeled_content select:focus,.cke_hc .cke_dialog_ui_labeled_content textarea:focus{outline:1px dotted}.cke_dialog_ui_labeled_label{margin-left:1px}.cke_dialog .cke_dark_background{background-color:transparent}.cke_dialog .cke_light_background{background-color:#ebebeb}.cke_dialog .cke_centered{text-align:center}.cke_dialog a.cke_btn_reset{float:right;background:url(images/refresh.png) top left no-repeat;width:16px;height:16px;border:1px none;font-size:1px}.cke_hidpi .cke_dialog a.cke_btn_reset{background-size:16px;background-image:url(images/hidpi/refresh.png)}.cke_rtl .cke_dialog a.cke_btn_reset{float:left}.cke_dialog a.cke_btn_locked,.cke_dialog a.cke_btn_unlocked{float:left;width:16px;height:16px;background-repeat:no-repeat;border:none 1px;font-size:1px}.cke_dialog a.cke_btn_locked,.cke_dialog a.cke_btn_unlocked,.cke_dialog a.cke_btn_reset{margin:2px}.cke_dialog a.cke_btn_locked{background-image:url(images/lock.png)}.cke_dialog a.cke_btn_unlocked{background-image:url(images/lock-open.png)}.cke_rtl .cke_dialog a.cke_btn_locked,.cke_rtl .cke_dialog a.cke_btn_unlocked{float:right}.cke_hidpi .cke_dialog a.cke_btn_unlocked,.cke_hidpi .cke_dialog a.cke_btn_locked{background-size:16px}.cke_hidpi .cke_dialog a.cke_btn_locked{background-image:url(images/hidpi/lock.png)}.cke_hidpi .cke_dialog a.cke_btn_unlocked{background-image:url(images/hidpi/lock-open.png)}.cke_dialog a.cke_btn_locked .cke_icon{display:none}.cke_dialog a.cke_btn_over,.cke_dialog a.cke_btn_locked:hover,.cke_dialog a.cke_btn_locked:focus,.cke_dialog a.cke_btn_locked:active,.cke_dialog a.cke_btn_unlocked:hover,.cke_dialog a.cke_btn_unlocked:focus,.cke_dialog a.cke_btn_unlocked:active,.cke_dialog a.cke_btn_reset:hover,.cke_dialog a.cke_btn_reset:focus,.cke_dialog a.cke_btn_reset:active{cursor:pointer;outline:0;margin:0;border:2px solid #139ff7}.cke_dialog fieldset{border:1px solid #bcbcbc}.cke_dialog fieldset legend{padding:0 6px}.cke_dialog_ui_checkbox,.cke_dialog fieldset .cke_dialog_ui_vbox .cke_dialog_ui_checkbox{display:inline-block}.cke_dialog fieldset .cke_dialog_ui_vbox .cke_dialog_ui_checkbox{padding-top:5px}.cke_dialog_ui_checkbox .cke_dialog_ui_checkbox_input,.cke_dialog_ui_checkbox .cke_dialog_ui_checkbox_input+label,.cke_dialog fieldset .cke_dialog_ui_vbox .cke_dialog_ui_checkbox .cke_dialog_ui_checkbox_input,.cke_dialog fieldset .cke_dialog_ui_vbox .cke_dialog_ui_checkbox .cke_dialog_ui_checkbox_input+label{vertical-align:middle}.cke_dialog .ImagePreviewBox{border:1px ridge #bcbcbc;overflow:scroll;height:200px;width:300px;padding:2px;background-color:white}.cke_dialog .ImagePreviewBox table td{white-space:normal}.cke_dialog .ImagePreviewLoader{position:absolute;white-space:normal;overflow:hidden;height:160px;width:230px;margin:2px;padding:2px;opacity:.9;filter:alpha(opacity = 90);background-color:#e4e4e4}.cke_dialog .FlashPreviewBox{white-space:normal;border:1px solid #bcbcbc;overflow:auto;height:160px;width:390px;padding:2px;background-color:white}.cke_dialog .cke_pastetext{width:346px;height:170px}.cke_dialog .cke_pastetext textarea{width:340px;height:170px;resize:none}.cke_dialog iframe.cke_pasteframe{width:346px;height:130px;background-color:white;border:1px solid #aeb3b9;border-radius:3px}.cke_dialog .cke_hand{cursor:pointer}.cke_disabled{color:#a0a0a0}.cke_dialog_body .cke_label{display:none}.cke_dialog_body label{display:inline;cursor:default;letter-spacing:.3px}.cke_dialog_body label+.cke_dialog_ui_labeled_content{margin-top:2px}.cke_dialog_contents_body .cke_dialog_ui_text,.cke_dialog_contents_body .cke_dialog_ui_select,.cke_dialog_contents_body .cke_dialog_ui_hbox_last>a.cke_dialog_ui_button{margin-top:4px}a.cke_smile{overflow:hidden;display:block;text-align:center;padding:.3em 0}a.cke_smile img{vertical-align:middle}a.cke_specialchar{cursor:inherit;display:block;height:1.25em;padding:.2em .3em;text-align:center}a.cke_smile,a.cke_specialchar{border:2px solid transparent}a.cke_smile:hover,a.cke_smile:focus,a.cke_smile:active,a.cke_specialchar:hover,a.cke_specialchar:focus,a.cke_specialchar:active{background:#fff;outline:0}a.cke_smile:hover,a.cke_specialchar:hover{border-color:#888}a.cke_smile:focus,a.cke_smile:active,a.cke_specialchar:focus,a.cke_specialchar:active{border-color:#139ff7}.cke_dialog_contents a.colorChooser{display:block;margin-top:6px;margin-left:10px;width:80px}.cke_rtl .cke_dialog_contents a.colorChooser{margin-right:10px}.cke_iframe_shim{display:block;position:absolute;top:0;left:0;z-index:-1;filter:alpha(opacity = 0);width:100%;height:100%}.cke_dialog_contents_body .cke_accessibility_legend{margin:2px 7px 2px 2px}.cke_dialog_contents_body .cke_accessibility_legend:focus,.cke_dialog_contents_body .cke_accessibility_legend:active{outline:0;border:2px solid #139ff7;margin:0 5px 0 0}.cke_dialog_contents_body input[type=file]:focus,.cke_dialog_contents_body input[type=file]:active{border:2px solid #139ff7}.cke_dialog_find_fieldset{margin-top:10px!important}.cke_dialog_image_ratiolock{margin-top:52px!important}.cke_dialog_forms_select_order label.cke_dialog_ui_labeled_label{margin-left:0}.cke_dialog_forms_select_order div.cke_dialog_ui_input_select{width:100%}.cke_dialog_forms_select_order_txtsize .cke_dialog_ui_hbox_last{padding-top:4px}.cke_dialog_image_url .cke_dialog_ui_hbox_last,.cke_dialog_flash_url .cke_dialog_ui_hbox_last{vertical-align:bottom}a.cke_dialog_ui_button.cke_dialog_image_browse{margin-top:10px}.cke_dialog_contents_body .cke_tpl_list{border:#bcbcbc 1px solid;margin:1px}.cke_dialog_contents_body .cke_tpl_list:focus,.cke_dialog_contents_body .cke_tpl_list:active{outline:0;margin:0;border:2px solid #139ff7}.cke_dialog_contents_body .cke_tpl_list a:focus,.cke_dialog_contents_body .cke_tpl_list a:active{outline:0}.cke_dialog_contents_body .cke_tpl_list a:focus .cke_tpl_item,.cke_dialog_contents_body .cke_tpl_list a:active .cke_tpl_item{border:2px solid #139ff7;padding:6px}.cke_rtl input.cke_dialog_ui_input_text,.cke_rtl input.cke_dialog_ui_input_password,.cke_rtl input.cke_dialog_ui_input_tel{padding-right:2px}.cke_rtl div.cke_dialog_ui_input_text,.cke_rtl div.cke_dialog_ui_input_password,.cke_rtl div.cke_dialog_ui_input_tel{padding-left:2px}.cke_rtl div.cke_dialog_ui_input_text{padding-right:1px}.cke_rtl .cke_dialog_ui_vbox_child,.cke_rtl .cke_dialog_ui_hbox_child,.cke_rtl .cke_dialog_ui_hbox_first,.cke_rtl .cke_dialog_ui_hbox_last{padding-right:2px!important}.cke_hc .cke_dialog_title,.cke_hc .cke_dialog_footer,.cke_hc a.cke_dialog_tab,.cke_hc a.cke_dialog_ui_button,.cke_hc a.cke_dialog_ui_button:hover,.cke_hc a.cke_dialog_ui_button_ok,.cke_hc a.cke_dialog_ui_button_ok:hover{filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.cke_hc div.cke_dialog_ui_input_text,.cke_hc div.cke_dialog_ui_input_password,.cke_hc div.cke_dialog_ui_input_tel,.cke_hc div.cke_dialog_ui_input_textarea,.cke_hc div.cke_dialog_ui_input_select,.cke_hc div.cke_dialog_ui_input_file{border:0}a.cke_dialog_ui_button{min-height:18px}input.cke_dialog_ui_input_text,input.cke_dialog_ui_input_password,input.cke_dialog_ui_input_tel,textarea.cke_dialog_ui_input_textarea{min-height:18px}input.cke_dialog_ui_input_text:focus,input.cke_dialog_ui_input_password:focus,input.cke_dialog_ui_input_tel:focus,textarea.cke_dialog_ui_input_textarea:focus{padding-top:4px;padding-bottom:2px}select.cke_dialog_ui_input_select{width:100%!important}select.cke_dialog_ui_input_select:focus{margin-left:1px;width:100%!important;padding-top:2px;padding-bottom:2px}"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/adminlte/bower_components/ckeditor/skins/moono-lisa/dialog_iequirks.css",
    "content": "/*\nCopyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.\nFor licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n*/\n.cke_dialog{visibility:visible}.cke_dialog_body{z-index:1;background:#fff}.cke_dialog strong{font-weight:bold}.cke_dialog_title{font-weight:bold;font-size:12px;cursor:move;position:relative;color:#484848;border-bottom:1px solid #d1d1d1;padding:12px 19px 12px 12px;background:#f8f8f8;letter-spacing:.3px}.cke_dialog_spinner{border-radius:50%;width:12px;height:12px;overflow:hidden;text-indent:-9999em;border:2px solid rgba(102,102,102,0.2);border-left-color:rgba(102,102,102,1);-webkit-animation:dialog_spinner 1s infinite linear;animation:dialog_spinner 1s infinite linear}.cke_browser_ie8 .cke_dialog_spinner,.cke_browser_ie9 .cke_dialog_spinner{background:url(images/spinner.gif) center top no-repeat;width:16px;height:16px;border:0}@-webkit-keyframes dialog_spinner{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes dialog_spinner{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.cke_dialog_contents{background-color:#fff;overflow:auto;padding:15px 10px 5px 10px;margin-top:43px;border-top:1px solid #d1d1d1}.cke_dialog_contents_body{overflow:auto;padding:9px 10px 5px 10px;margin-top:22px}.cke_dialog_footer{text-align:right;position:relative;border-top:1px solid #d1d1d1;background:#f8f8f8}.cke_rtl .cke_dialog_footer{text-align:left}.cke_hc .cke_dialog_footer{outline:0;border-top:1px solid #fff}.cke_dialog .cke_resizer{margin-top:22px}.cke_dialog .cke_resizer_rtl{margin-left:5px}.cke_dialog .cke_resizer_ltr{margin-right:5px}.cke_dialog_tabs{height:33px;display:inline-block;margin:9px 0 0;position:absolute;z-index:2;left:11px}.cke_rtl .cke_dialog_tabs{left:auto;right:11px}a.cke_dialog_tab{height:25px;padding:4px 8px;display:inline-block;cursor:pointer;line-height:26px;outline:0;color:#484848;border:1px solid #d1d1d1;border-radius:3px 3px 0 0;background:#f8f8f8;min-width:90px;text-align:center;margin-left:-1px;letter-spacing:.3px}a.cke_dialog_tab:hover{background-color:#fff}a.cke_dialog_tab:focus{border:2px solid #139ff7;border-bottom-color:#d1d1d1;padding:3px 7px;position:relative;z-index:1}a.cke_dialog_tab_selected{background:#fff;border-bottom-color:#fff;cursor:default;filter:none}a.cke_dialog_tab_selected:hover,a.cke_dialog_tab_selected:focus{border-bottom-color:#fff}.cke_hc a.cke_dialog_tab:hover,.cke_hc a.cke_dialog_tab:focus,.cke_hc a.cke_dialog_tab_selected{border:3px solid;padding:2px 6px}a.cke_dialog_tab_disabled{color:#bababa;cursor:default}.cke_single_page .cke_dialog_tabs{display:none}.cke_single_page .cke_dialog_contents{padding-top:5px;margin-top:0;border-top:0}a.cke_dialog_close_button{background-image:url(images/close.png);background-repeat:no-repeat;background-position:50%;position:absolute;cursor:pointer;text-align:center;height:16px;width:16px;top:11px;z-index:5;opacity:.7;filter:alpha(opacity = 70)}.cke_rtl .cke_dialog_close_button{left:12px}.cke_ltr .cke_dialog_close_button{right:12px}.cke_hc a.cke_dialog_close_button{background-image:none}.cke_hidpi a.cke_dialog_close_button{background-image:url(images/hidpi/close.png);background-size:16px}a.cke_dialog_close_button:hover{opacity:1;filter:alpha(opacity = 100)}a.cke_dialog_close_button span{display:none}.cke_hc a.cke_dialog_close_button span{display:inline;cursor:pointer;font-weight:bold;position:relative;top:3px}div.cke_disabled .cke_dialog_ui_labeled_content div *{background-color:#ddd;cursor:default}.cke_dialog_ui_vbox table,.cke_dialog_ui_hbox table{margin:auto}.cke_dialog_ui_vbox_child{padding:5px 0}.cke_dialog_ui_hbox{width:100%;margin-top:12px}.cke_dialog_ui_hbox_first,.cke_dialog_ui_hbox_child,.cke_dialog_ui_hbox_last{vertical-align:top}.cke_ltr .cke_dialog_ui_hbox_first,.cke_ltr .cke_dialog_ui_hbox_child{padding-right:10px}.cke_rtl .cke_dialog_ui_hbox_first,.cke_rtl .cke_dialog_ui_hbox_child{padding-left:10px}.cke_ltr .cke_dialog_footer_buttons .cke_dialog_ui_hbox_first,.cke_ltr .cke_dialog_footer_buttons .cke_dialog_ui_hbox_child{padding-right:5px}.cke_rtl .cke_dialog_footer_buttons .cke_dialog_ui_hbox_first,.cke_rtl .cke_dialog_footer_buttons .cke_dialog_ui_hbox_child{padding-left:5px;padding-right:0}.cke_hc div.cke_dialog_ui_input_text,.cke_hc div.cke_dialog_ui_input_password,.cke_hc div.cke_dialog_ui_input_tel,.cke_hc div.cke_dialog_ui_input_textarea,.cke_hc div.cke_dialog_ui_input_select,.cke_hc div.cke_dialog_ui_input_file{border:1px solid}textarea.cke_dialog_ui_input_textarea{overflow:auto;resize:none}input.cke_dialog_ui_input_text,input.cke_dialog_ui_input_password,input.cke_dialog_ui_input_tel,textarea.cke_dialog_ui_input_textarea{background-color:#fff;border:1px solid #bcbcbc;padding:4px 6px;outline:0;width:100%;*width:95%;box-sizing:border-box;border-radius:2px;min-height:28px;margin-left:1px}input.cke_dialog_ui_input_text:hover,input.cke_dialog_ui_input_password:hover,input.cke_dialog_ui_input_tel:hover,textarea.cke_dialog_ui_input_textarea:hover{border:1px solid #aeb3b9}input.cke_dialog_ui_input_text:focus,input.cke_dialog_ui_input_password:focus,input.cke_dialog_ui_input_tel:focus,textarea.cke_dialog_ui_input_textarea:focus,select.cke_dialog_ui_input_select:focus{outline:0;border:2px solid #139ff7}input.cke_dialog_ui_input_text:focus{padding-left:5px}textarea.cke_dialog_ui_input_textarea:focus{padding:3px 5px}select.cke_dialog_ui_input_select:focus{margin:0;width:100%!important}input.cke_dialog_ui_checkbox_input,input.cke_dialog_ui_radio_input{margin-left:1px;margin-right:2px}input.cke_dialog_ui_checkbox_input:focus,input.cke_dialog_ui_checkbox_input:active,input.cke_dialog_ui_radio_input:focus,input.cke_dialog_ui_radio_input:active{border:0;outline:2px solid #139ff7}a.cke_dialog_ui_button{display:inline-block;*display:inline;*zoom:1;padding:4px 1px;margin:0;text-align:center;color:#484848;vertical-align:middle;cursor:pointer;border:1px solid #bcbcbc;border-radius:2px;background:#f8f8f8;letter-spacing:.3px;line-height:18px;box-sizing:border-box}.cke_hc a.cke_dialog_ui_button{border-width:3px}span.cke_dialog_ui_button{padding:0 10px;cursor:pointer}a.cke_dialog_ui_button:hover{background:#fff}a.cke_dialog_ui_button:focus,a.cke_dialog_ui_button:active{border:2px solid #139ff7;outline:0;padding:3px 0}.cke_hc a.cke_dialog_ui_button:hover,.cke_hc a.cke_dialog_ui_button:focus,.cke_hc a.cke_dialog_ui_button:active{border:3px solid}.cke_dialog_footer_buttons a.cke_dialog_ui_button span{color:inherit;font-size:12px;font-weight:bold;padding:0 12px}a.cke_dialog_ui_button_ok{color:#fff;background:#09863e;border:1px solid #09863e}.cke_hc a.cke_dialog_ui_button{border:3px solid #bcbcbc}a.cke_dialog_ui_button_ok:hover{background:#53aa78;border-color:#53aa78}a.cke_dialog_ui_button_ok:focus{box-shadow:inset 0 0 0 2px #FFF}a.cke_dialog_ui_button_ok:focus,a.cke_dialog_ui_button_ok:active{border-color:#139ff7}.cke_hc a.cke_dialog_ui_button_ok:hover,.cke_hc a.cke_dialog_ui_button_ok:focus,.cke_hc a.cke_dialog_ui_button_ok:active{border-color:#484848}a.cke_dialog_ui_button_ok.cke_disabled{background:#d1d1d1;border-color:#d1d1d1;cursor:default}a.cke_dialog_ui_button_ok.cke_disabled span{cursor:default}.cke_dialog_footer_buttons{display:inline-table;margin:5px;width:auto;position:relative;vertical-align:middle}div.cke_dialog_ui_input_select{display:table}select.cke_dialog_ui_input_select{height:28px;line-height:28px;background-color:#fff;border:1px solid #bcbcbc;padding:3px 3px 3px 6px;outline:0;border-radius:2px;margin:0 1px;box-sizing:border-box;width:calc(100% - 2px)!important}.cke_dialog_ui_input_file{width:100%;height:25px}.cke_hc .cke_dialog_ui_labeled_content input:focus,.cke_hc .cke_dialog_ui_labeled_content select:focus,.cke_hc .cke_dialog_ui_labeled_content textarea:focus{outline:1px dotted}.cke_dialog_ui_labeled_label{margin-left:1px}.cke_dialog .cke_dark_background{background-color:transparent}.cke_dialog .cke_light_background{background-color:#ebebeb}.cke_dialog .cke_centered{text-align:center}.cke_dialog a.cke_btn_reset{float:right;background:url(images/refresh.png) top left no-repeat;width:16px;height:16px;border:1px none;font-size:1px}.cke_hidpi .cke_dialog a.cke_btn_reset{background-size:16px;background-image:url(images/hidpi/refresh.png)}.cke_rtl .cke_dialog a.cke_btn_reset{float:left}.cke_dialog a.cke_btn_locked,.cke_dialog a.cke_btn_unlocked{float:left;width:16px;height:16px;background-repeat:no-repeat;border:none 1px;font-size:1px}.cke_dialog a.cke_btn_locked,.cke_dialog a.cke_btn_unlocked,.cke_dialog a.cke_btn_reset{margin:2px}.cke_dialog a.cke_btn_locked{background-image:url(images/lock.png)}.cke_dialog a.cke_btn_unlocked{background-image:url(images/lock-open.png)}.cke_rtl .cke_dialog a.cke_btn_locked,.cke_rtl .cke_dialog a.cke_btn_unlocked{float:right}.cke_hidpi .cke_dialog a.cke_btn_unlocked,.cke_hidpi .cke_dialog a.cke_btn_locked{background-size:16px}.cke_hidpi .cke_dialog a.cke_btn_locked{background-image:url(images/hidpi/lock.png)}.cke_hidpi .cke_dialog a.cke_btn_unlocked{background-image:url(images/hidpi/lock-open.png)}.cke_dialog a.cke_btn_locked .cke_icon{display:none}.cke_dialog a.cke_btn_over,.cke_dialog a.cke_btn_locked:hover,.cke_dialog a.cke_btn_locked:focus,.cke_dialog a.cke_btn_locked:active,.cke_dialog a.cke_btn_unlocked:hover,.cke_dialog a.cke_btn_unlocked:focus,.cke_dialog a.cke_btn_unlocked:active,.cke_dialog a.cke_btn_reset:hover,.cke_dialog a.cke_btn_reset:focus,.cke_dialog a.cke_btn_reset:active{cursor:pointer;outline:0;margin:0;border:2px solid #139ff7}.cke_dialog fieldset{border:1px solid #bcbcbc}.cke_dialog fieldset legend{padding:0 6px}.cke_dialog_ui_checkbox,.cke_dialog fieldset .cke_dialog_ui_vbox .cke_dialog_ui_checkbox{display:inline-block}.cke_dialog fieldset .cke_dialog_ui_vbox .cke_dialog_ui_checkbox{padding-top:5px}.cke_dialog_ui_checkbox .cke_dialog_ui_checkbox_input,.cke_dialog_ui_checkbox .cke_dialog_ui_checkbox_input+label,.cke_dialog fieldset .cke_dialog_ui_vbox .cke_dialog_ui_checkbox .cke_dialog_ui_checkbox_input,.cke_dialog fieldset .cke_dialog_ui_vbox .cke_dialog_ui_checkbox .cke_dialog_ui_checkbox_input+label{vertical-align:middle}.cke_dialog .ImagePreviewBox{border:1px ridge #bcbcbc;overflow:scroll;height:200px;width:300px;padding:2px;background-color:white}.cke_dialog .ImagePreviewBox table td{white-space:normal}.cke_dialog .ImagePreviewLoader{position:absolute;white-space:normal;overflow:hidden;height:160px;width:230px;margin:2px;padding:2px;opacity:.9;filter:alpha(opacity = 90);background-color:#e4e4e4}.cke_dialog .FlashPreviewBox{white-space:normal;border:1px solid #bcbcbc;overflow:auto;height:160px;width:390px;padding:2px;background-color:white}.cke_dialog .cke_pastetext{width:346px;height:170px}.cke_dialog .cke_pastetext textarea{width:340px;height:170px;resize:none}.cke_dialog iframe.cke_pasteframe{width:346px;height:130px;background-color:white;border:1px solid #aeb3b9;border-radius:3px}.cke_dialog .cke_hand{cursor:pointer}.cke_disabled{color:#a0a0a0}.cke_dialog_body .cke_label{display:none}.cke_dialog_body label{display:inline;cursor:default;letter-spacing:.3px}.cke_dialog_body label+.cke_dialog_ui_labeled_content{margin-top:2px}.cke_dialog_contents_body .cke_dialog_ui_text,.cke_dialog_contents_body .cke_dialog_ui_select,.cke_dialog_contents_body .cke_dialog_ui_hbox_last>a.cke_dialog_ui_button{margin-top:4px}a.cke_smile{overflow:hidden;display:block;text-align:center;padding:.3em 0}a.cke_smile img{vertical-align:middle}a.cke_specialchar{cursor:inherit;display:block;height:1.25em;padding:.2em .3em;text-align:center}a.cke_smile,a.cke_specialchar{border:2px solid transparent}a.cke_smile:hover,a.cke_smile:focus,a.cke_smile:active,a.cke_specialchar:hover,a.cke_specialchar:focus,a.cke_specialchar:active{background:#fff;outline:0}a.cke_smile:hover,a.cke_specialchar:hover{border-color:#888}a.cke_smile:focus,a.cke_smile:active,a.cke_specialchar:focus,a.cke_specialchar:active{border-color:#139ff7}.cke_dialog_contents a.colorChooser{display:block;margin-top:6px;margin-left:10px;width:80px}.cke_rtl .cke_dialog_contents a.colorChooser{margin-right:10px}.cke_iframe_shim{display:block;position:absolute;top:0;left:0;z-index:-1;filter:alpha(opacity = 0);width:100%;height:100%}.cke_dialog_contents_body .cke_accessibility_legend{margin:2px 7px 2px 2px}.cke_dialog_contents_body .cke_accessibility_legend:focus,.cke_dialog_contents_body .cke_accessibility_legend:active{outline:0;border:2px solid #139ff7;margin:0 5px 0 0}.cke_dialog_contents_body input[type=file]:focus,.cke_dialog_contents_body input[type=file]:active{border:2px solid #139ff7}.cke_dialog_find_fieldset{margin-top:10px!important}.cke_dialog_image_ratiolock{margin-top:52px!important}.cke_dialog_forms_select_order label.cke_dialog_ui_labeled_label{margin-left:0}.cke_dialog_forms_select_order div.cke_dialog_ui_input_select{width:100%}.cke_dialog_forms_select_order_txtsize .cke_dialog_ui_hbox_last{padding-top:4px}.cke_dialog_image_url .cke_dialog_ui_hbox_last,.cke_dialog_flash_url .cke_dialog_ui_hbox_last{vertical-align:bottom}a.cke_dialog_ui_button.cke_dialog_image_browse{margin-top:10px}.cke_dialog_contents_body .cke_tpl_list{border:#bcbcbc 1px solid;margin:1px}.cke_dialog_contents_body .cke_tpl_list:focus,.cke_dialog_contents_body .cke_tpl_list:active{outline:0;margin:0;border:2px solid #139ff7}.cke_dialog_contents_body .cke_tpl_list a:focus,.cke_dialog_contents_body .cke_tpl_list a:active{outline:0}.cke_dialog_contents_body .cke_tpl_list a:focus .cke_tpl_item,.cke_dialog_contents_body .cke_tpl_list a:active .cke_tpl_item{border:2px solid #139ff7;padding:6px}.cke_rtl input.cke_dialog_ui_input_text,.cke_rtl input.cke_dialog_ui_input_password,.cke_rtl input.cke_dialog_ui_input_tel{padding-right:2px}.cke_rtl div.cke_dialog_ui_input_text,.cke_rtl div.cke_dialog_ui_input_password,.cke_rtl div.cke_dialog_ui_input_tel{padding-left:2px}.cke_rtl div.cke_dialog_ui_input_text{padding-right:1px}.cke_rtl .cke_dialog_ui_vbox_child,.cke_rtl .cke_dialog_ui_hbox_child,.cke_rtl .cke_dialog_ui_hbox_first,.cke_rtl .cke_dialog_ui_hbox_last{padding-right:2px!important}.cke_hc .cke_dialog_title,.cke_hc .cke_dialog_footer,.cke_hc a.cke_dialog_tab,.cke_hc a.cke_dialog_ui_button,.cke_hc a.cke_dialog_ui_button:hover,.cke_hc a.cke_dialog_ui_button_ok,.cke_hc a.cke_dialog_ui_button_ok:hover{filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.cke_hc div.cke_dialog_ui_input_text,.cke_hc div.cke_dialog_ui_input_password,.cke_hc div.cke_dialog_ui_input_tel,.cke_hc div.cke_dialog_ui_input_textarea,.cke_hc div.cke_dialog_ui_input_select,.cke_hc div.cke_dialog_ui_input_file{border:0}.cke_dialog_footer{filter:\"\"}"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/adminlte/bower_components/ckeditor/skins/moono-lisa/editor.css",
    "content": "/*\nCopyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.\nFor licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n*/\n.cke_reset{margin:0;padding:0;border:0;background:transparent;text-decoration:none;width:auto;height:auto;vertical-align:baseline;box-sizing:content-box;position:static;transition:none}.cke_reset_all,.cke_reset_all *,.cke_reset_all a,.cke_reset_all textarea{margin:0;padding:0;border:0;background:transparent;text-decoration:none;width:auto;height:auto;vertical-align:baseline;box-sizing:content-box;position:static;transition:none;border-collapse:collapse;font:normal normal normal 12px Arial,Helvetica,Tahoma,Verdana,Sans-Serif;color:#000;text-align:left;white-space:nowrap;cursor:auto;float:none}.cke_reset_all .cke_rtl *{text-align:right}.cke_reset_all iframe{vertical-align:inherit}.cke_reset_all textarea{white-space:pre-wrap}.cke_reset_all textarea,.cke_reset_all input[type=\"text\"],.cke_reset_all input[type=\"password\"]{cursor:text}.cke_reset_all textarea[disabled],.cke_reset_all input[type=\"text\"][disabled],.cke_reset_all input[type=\"password\"][disabled]{cursor:default}.cke_reset_all fieldset{padding:10px;border:2px groove #e0dfe3}.cke_reset_all select{box-sizing:border-box}.cke_reset_all table{table-layout:auto}.cke_chrome{display:block;border:1px solid #d1d1d1;padding:0}.cke_inner{display:block;background:#fff;padding:0;-webkit-touch-callout:none}.cke_float{border:0}.cke_float .cke_inner{padding-bottom:0}.cke_top,.cke_contents,.cke_bottom{display:block;overflow:hidden}.cke_top{border-bottom:1px solid #d1d1d1;background:#f8f8f8;padding:6px 8px 2px;white-space:normal}.cke_float .cke_top{border:1px solid #d1d1d1}.cke_bottom{padding:6px 8px 2px;position:relative;border-top:1px solid #d1d1d1;background:#f8f8f8}.cke_browser_ios .cke_contents{overflow-y:auto;-webkit-overflow-scrolling:touch}.cke_resizer{width:0;height:0;overflow:hidden;border-width:10px 10px 0 0;border-color:transparent #bcbcbc transparent transparent;border-style:dashed solid dashed dashed;font-size:0;vertical-align:bottom;margin-top:6px;margin-bottom:2px}.cke_hc .cke_resizer{font-size:15px;width:auto;height:auto;border-width:0}.cke_resizer_ltr{cursor:se-resize;float:right;margin-right:-4px}.cke_resizer_rtl{border-width:10px 0 0 10px;border-color:transparent transparent transparent #bcbcbc;border-style:dashed dashed dashed solid;cursor:sw-resize;float:left;margin-left:-4px;right:auto}.cke_wysiwyg_div{display:block;height:100%;overflow:auto;padding:0 8px;outline-style:none;box-sizing:border-box}.cke_panel{visibility:visible;width:120px;height:100px;overflow:hidden;background-color:#fff;border:1px solid #d1d1d1}.cke_menu_panel{padding:0;margin:0}.cke_combopanel{width:150px;height:170px}.cke_panel_frame{width:100%;height:100%;font-size:12px;overflow:auto;overflow-x:hidden}.cke_panel_container{overflow-y:auto;overflow-x:hidden}.cke_panel_block:focus{outline:0}.cke_panel_list{margin:0;padding:0;list-style-type:none;white-space:nowrap}.cke_panel_listItem{margin:0;padding:0}.cke_panel_listItem a{padding:6px 7px;display:block;color:inherit!important;text-decoration:none;overflow:hidden;text-overflow:ellipsis}.cke_hc .cke_panel_listItem a{border-style:none}.cke_panel_listItem.cke_selected a,.cke_panel_listItem a:hover,.cke_panel_listItem a:focus,.cke_panel_listItem a:active{background-color:#e9e9e9}.cke_panel_listItem a:focus{outline:1px dotted #000}.cke_hc .cke_panel_listItem a:hover,.cke_hc .cke_panel_listItem a:focus,.cke_hc .cke_panel_listItem a:active{border:2px solid;padding:4px 5px}.cke_panel_listItem p,.cke_panel_listItem h1,.cke_panel_listItem h2,.cke_panel_listItem h3,.cke_panel_listItem h4,.cke_panel_listItem h5,.cke_panel_listItem h6,.cke_panel_listItem pre{margin-top:0;margin-bottom:0}.cke_panel_grouptitle{cursor:default;font-size:11px;font-weight:bold;white-space:nowrap;margin:0;padding:6px 6px 7px 6px;color:#484848;border-bottom:1px solid #d1d1d1;background:#f8f8f8}.cke_colorblock{padding:10px;font-size:11px;font-family:'Microsoft Sans Serif',Tahoma,Arial,Verdana,Sans-Serif}.cke_colorblock,.cke_colorblock a{text-decoration:none;color:#000}a.cke_colorbox{padding:2px;float:left;width:20px;height:20px}.cke_rtl a.cke_colorbox{float:right}a:hover.cke_colorbox,a:focus.cke_colorbox,a:active.cke_colorbox{outline:0;padding:0;border:2px solid #139ff7}a:hover.cke_colorbox{border-color:#bcbcbc}span.cke_colorbox{width:20px;height:20px;float:left}.cke_rtl span.cke_colorbox{float:right}a.cke_colorauto,a.cke_colormore{border:#fff 1px solid;padding:3px;display:block;cursor:pointer}a.cke_colorauto{padding:0;border:1px solid transparent;margin-bottom:6px;height:26px;line-height:26px}a.cke_colormore{margin-top:10px;height:20px;line-height:19px}a:hover.cke_colorauto,a:hover.cke_colormore,a:focus.cke_colorauto,a:focus.cke_colormore,a:active.cke_colorauto,a:active.cke_colormore{outline:0;border:#139ff7 1px solid;background-color:#f8f8f8}a:hover.cke_colorauto,a:hover.cke_colormore{border-color:#bcbcbc}.cke_colorauto span.cke_colorbox{width:18px;height:18px;border:1px solid #808080;margin-left:1px;margin-top:3px}.cke_rtl .cke_colorauto span.cke_colorbox{margin-left:0;margin-right:1px}span.cke_colorbox[style*=\"#ffffff\"],span.cke_colorbox[style*=\"#FFFFFF\"],span.cke_colorbox[style=\"background-color:#fff\"],span.cke_colorbox[style=\"background-color:#FFF\"],span.cke_colorbox[style*=\"rgb(255,255,255)\"],span.cke_colorbox[style*=\"rgb(255, 255, 255)\"]{border:1px solid #808080;width:18px;height:18px}.cke_toolbar{float:left}.cke_rtl .cke_toolbar{float:right}.cke_toolgroup{border:0;float:left;margin:1px 2px 6px 0;padding-right:3px}.cke_rtl .cke_toolgroup{float:right;margin:1px 0 6px 2px;padding-left:3px;padding-right:0}.cke_hc .cke_toolgroup{margin-right:5px;margin-bottom:5px}.cke_hc.cke_rtl .cke_toolgroup{margin-right:0;margin-left:5px}a.cke_button{display:inline-block;height:18px;padding:4px 6px;outline:0;cursor:default;float:left;border:0;position:relative}a.cke_button_expandable{padding:4px 5px}.cke_rtl a.cke_button{float:right}.cke_hc a.cke_button{border:1px solid black;padding:3px 5px;margin:0 3px 5px 0}.cke_hc.cke_rtl a.cke_button{margin:0 0 5px 3px}a.cke_button_on{background:#fff;border:1px #bcbcbc solid;padding:3px 5px}a.cke_button_expandable.cke_button_on{padding:3px 4px}a.cke_button_off:hover,a.cke_button_off:focus,a.cke_button_off:active{background:#e5e5e5;border:1px #bcbcbc solid;padding:3px 5px}a.cke_button_expandable.cke_button_off:hover,a.cke_button_expandable.cke_button_off:focus,a.cke_button_expandable.cke_button_off:active{padding:3px 4px}.cke_hc a.cke_button_on,.cke_hc a.cke_button_off:hover,.cke_hc a.cke_button_off:focus,.cke_hc a.cke_button_off:active{background:#e5e5e5;border:3px solid #000;padding:1px 3px}a.cke_button_disabled:hover,a.cke_button_disabled:focus,a.cke_button_disabled:active{border:0;padding:4px 6px;background-color:transparent}a.cke_button_expandable.cke_button_disabled:hover,a.cke_button_expandable.cke_button_disabled:active{padding:4px 5px}a.cke_button_disabled:focus{border:1px #bcbcbc solid;padding:3px 5px}a.cke_button_expandable.cke_button_disabled:focus{padding:3px 4px}.cke_hc a.cke_button_disabled:hover,.cke_hc a.cke_button_disabled:focus,.cke_hc a.cke_button_disabled:active{border:1px solid #acacac;padding:3px 5px;margin:0 3px 5px 0}.cke_hc a.cke_button_disabled:focus{border:3px solid #000;padding:1px 3px}.cke_hc.cke_rtl a.cke_button_disabled:hover,.cke_hc.cke_rtl a.cke_button_disabled:focus,.cke_hc.cke_rtl a.cke_button_disabled:active{margin:0 0 5px 3px}a.cke_button_disabled .cke_button_icon,a.cke_button_disabled .cke_button_arrow{opacity:.3}.cke_hc a.cke_button_disabled{border-color:#acacac}.cke_hc a.cke_button_disabled .cke_button_icon,.cke_hc a.cke_button_disabled .cke_button_label{opacity:.5}.cke_toolgroup a.cke_button:last-child:after,.cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{content:\"\";position:absolute;height:18px;width:0;border-right:1px solid #bcbcbc;margin-top:4px;top:0;right:-3px}.cke_rtl .cke_toolgroup a.cke_button:last-child:after,.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{border-right:0;right:auto;border-left:1px solid #bcbcbc;top:0;left:-3px}.cke_hc .cke_toolgroup a.cke_button:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_disabled:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{border-color:#000;top:0;right:-7px}.cke_hc.cke_rtl .cke_toolgroup a.cke_button:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{top:0;right:auto;left:-7px}.cke_toolgroup a.cke_button:hover:last-child:after,.cke_toolgroup a.cke_button:focus:last-child:after,.cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-1px;right:-4px}.cke_rtl .cke_toolgroup a.cke_button:hover:last-child:after,.cke_rtl .cke_toolgroup a.cke_button:focus:last-child:after,.cke_rtl .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-1px;right:auto;left:-4px}.cke_hc .cke_toolgroup a.cke_button:hover:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-2px;right:-9px}.cke_hc.cke_rtl .cke_toolgroup a.cke_button:hover:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-2px;right:auto;left:-9px}.cke_toolbar.cke_toolbar_last .cke_toolgroup a.cke_button:last-child:after{content:none;border:0;width:0;height:0}.cke_button_icon{cursor:inherit;background-repeat:no-repeat;margin-top:1px;width:16px;height:16px;float:left;display:inline-block}.cke_rtl .cke_button_icon{float:right}.cke_hc .cke_button_icon{display:none}.cke_button_label{display:none;padding-left:3px;margin-top:1px;line-height:17px;vertical-align:middle;float:left;cursor:default;color:#484848}.cke_rtl .cke_button_label{padding-right:3px;padding-left:0;float:right}.cke_hc .cke_button_label{padding:0;display:inline-block;font-size:12px}.cke_button_arrow{display:inline-block;margin:8px 0 0 3px;width:0;height:0;cursor:default;vertical-align:top;border-left:3px solid transparent;border-right:3px solid transparent;border-top:3px solid #484848}.cke_rtl .cke_button_arrow{margin-right:5px;margin-left:0}.cke_hc .cke_button_arrow{font-size:10px;margin:3px 0 0 3px;width:auto;border:0}.cke_toolbar_separator{float:left;background-color:#bcbcbc;margin:4px 2px 0 2px;height:18px;width:1px}.cke_rtl .cke_toolbar_separator{float:right}.cke_hc .cke_toolbar_separator{background-color:#000;margin-left:2px;margin-right:5px;margin-bottom:9px}.cke_hc.cke_rtl .cke_toolbar_separator{margin-left:5px;margin-right:2px}.cke_toolbar_break{display:block;clear:left}.cke_rtl .cke_toolbar_break{clear:right}a.cke_toolbox_collapser{width:12px;height:11px;float:right;margin:11px 0 0;font-size:0;cursor:default;text-align:center;border:1px solid #bcbcbc}.cke_rtl .cke_toolbox_collapser{float:left}.cke_toolbox_collapser:hover{background:#e5e5e5}.cke_toolbox_collapser.cke_toolbox_collapser_min{margin:0 2px 4px}.cke_toolbox_collapser .cke_arrow{display:inline-block;height:0;width:0;font-size:0;margin-top:1px;border:3px solid transparent;border-bottom-color:#484848}.cke_toolbox_collapser.cke_toolbox_collapser_min .cke_arrow{margin-top:4px;border-bottom-color:transparent;border-top-color:#484848}.cke_hc .cke_toolbox_collapser .cke_arrow{font-size:8px;width:auto;border:0;margin-top:0}.cke_menuitem span{cursor:default}.cke_menubutton{display:block}.cke_hc .cke_menubutton{padding:2px}.cke_menubutton:hover,.cke_menubutton:focus,.cke_menubutton:active{background-color:#e9e9e9;display:block;outline:1px dotted}.cke_menubutton:hover{outline:0}.cke_hc .cke_menubutton:hover,.cke_hc .cke_menubutton:focus,.cke_hc .cke_menubutton:active{border:2px solid;padding:0}.cke_menubutton_disabled:hover,.cke_menubutton_disabled:focus,.cke_menubutton_disabled:active{background-color:transparent;outline:0}.cke_menubutton_inner{display:table-row}.cke_menubutton_icon,.cke_menubutton_label,.cke_menuarrow{display:table-cell}.cke_menubutton_icon{background-color:#f8f8f8;padding:6px 4px}.cke_hc .cke_menubutton_icon{height:16px;width:0;padding:4px 0}.cke_menubutton:hover .cke_menubutton_icon,.cke_menubutton:focus .cke_menubutton_icon,.cke_menubutton:active .cke_menubutton_icon{background-color:#e9e9e9}.cke_menubutton_disabled:hover .cke_menubutton_icon,.cke_menubutton_disabled:focus .cke_menubutton_icon,.cke_menubutton_disabled:active .cke_menubutton_icon{background-color:#f8f8f8;outline:0}.cke_menuitem .cke_menubutton_on{background-color:#e9e9e9;border:1px solid #dedede;outline:0}.cke_menubutton_on .cke_menubutton_icon{padding-right:3px;background-color:#e9e9e9}.cke_menubutton_label{padding:0 5px;background-color:transparent;width:100%;vertical-align:middle}.cke_menubutton_shortcut{color:#979797}.cke_menubutton_disabled .cke_menubutton_label{opacity:.3;filter:alpha(opacity=30)}.cke_panel_frame .cke_menubutton_label{display:none}.cke_menuseparator{background-color:#d1d1d1;height:1px}.cke_menuarrow{background:transparent url(images/arrow.png) no-repeat 0 10px;padding:0 5px}.cke_rtl .cke_menuarrow{background-position:5px -13px;background-repeat:no-repeat}.cke_hc .cke_menuarrow{background-image:none}.cke_menuarrow span{display:none}.cke_hc .cke_menuarrow span{vertical-align:middle;display:inline}.cke_combo{display:inline-block;float:left;position:relative;margin-bottom:5px}.cke_rtl .cke_combo{float:right}.cke_hc .cke_combo{margin-top:1px;margin-bottom:10px}.cke_combo:after{content:\"\";position:absolute;height:18px;width:0;border-right:1px solid #bcbcbc;margin-top:5px;top:0;right:0}.cke_rtl .cke_combo:after{border-right:0;border-left:1px solid #bcbcbc;right:auto;left:0}.cke_hc .cke_combo:after{border-color:#000}a.cke_combo_button{cursor:default;display:inline-block;float:left;margin:0;padding:1px}.cke_rtl a.cke_combo_button{float:right}.cke_hc a.cke_combo_button{padding:4px}.cke_combo_on a.cke_combo_button,.cke_combo_off a.cke_combo_button:hover,.cke_combo_off a.cke_combo_button:focus,.cke_combo_off a.cke_combo_button:active{background:#e5e5e5;border:1px solid #bcbcbc;padding:0 0 0 1px;margin-left:-1px}.cke_combo_off a.cke_combo_button:focus{outline:0}.cke_combo_on a.cke_combo_button,.cke_combo_off a.cke_combo_button:active{background:#fff}.cke_rtl .cke_combo_on a.cke_combo_button,.cke_rtl .cke_combo_off a.cke_combo_button:hover,.cke_rtl .cke_combo_off a.cke_combo_button:focus,.cke_rtl .cke_combo_off a.cke_combo_button:active{padding:0 1px 0 0;margin-left:0;margin-right:-1px}.cke_hc .cke_combo_on a.cke_combo_button,.cke_hc .cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_combo_off a.cke_combo_button:active{border:3px solid #000;padding:1px 1px 1px 2px}.cke_hc.cke_rtl .cke_combo_on a.cke_combo_button,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:hover,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:focus,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:active{padding:1px 2px 1px 1px}.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0 0 0 3px;margin-left:-3px}.cke_rtl .cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0 3px 0 0;margin-left:0;margin-right:-3px}.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px 1px 1px 7px;margin-left:-6px}.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px 7px 1px 1px;margin-left:0;margin-right:-6px}.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0;margin:0}.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px;margin:0}.cke_toolbar .cke_combo+.cke_toolbar_end,.cke_toolbar .cke_combo+.cke_toolgroup{margin-right:0;margin-left:2px}.cke_rtl .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_rtl .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:0;margin-right:2px}.cke_hc .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_hc .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:5px}.cke_hc.cke_rtl .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_hc.cke_rtl .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:0;margin-right:5px}.cke_toolbar.cke_toolbar_last .cke_combo:nth-last-child(-n+2):after{content:none;border:0;width:0;height:0}.cke_combo_text{line-height:26px;padding-left:10px;text-overflow:ellipsis;overflow:hidden;float:left;cursor:default;color:#484848;width:60px}.cke_rtl .cke_combo_text{float:right;text-align:right;padding-left:0;padding-right:10px}.cke_hc .cke_combo_text{line-height:18px;font-size:12px}.cke_combo_open{cursor:default;display:inline-block;font-size:0;height:19px;line-height:17px;margin:1px 10px 1px;width:5px}.cke_hc .cke_combo_open{height:12px}.cke_combo_arrow{cursor:default;margin:11px 0 0;float:left;height:0;width:0;font-size:0;border-left:3px solid transparent;border-right:3px solid transparent;border-top:3px solid #484848}.cke_hc .cke_combo_arrow{font-size:10px;width:auto;border:0;margin-top:3px}.cke_combo_label{display:none;float:left;line-height:26px;vertical-align:top;margin-right:5px}.cke_rtl .cke_combo_label{float:right;margin-left:5px;margin-right:0}.cke_combo_disabled .cke_combo_inlinelabel,.cke_combo_disabled .cke_combo_open{opacity:.3}.cke_path{float:left;margin:-2px 0 2px}a.cke_path_item,span.cke_path_empty{display:inline-block;float:left;padding:3px 4px;margin-right:2px;cursor:default;text-decoration:none;outline:0;border:0;color:#484848;font-weight:bold;font-size:11px}.cke_rtl .cke_path,.cke_rtl .cke_path_item,.cke_rtl .cke_path_empty{float:right}a.cke_path_item:hover,a.cke_path_item:focus,a.cke_path_item:active{background-color:#e5e5e5}.cke_hc a.cke_path_item:hover,.cke_hc a.cke_path_item:focus,.cke_hc a.cke_path_item:active{border:2px solid;padding:1px 2px}.cke_button__source_label,.cke_button__sourcedialog_label{display:inline}.cke_combopanel__fontsize{width:135px}textarea.cke_source{font-family:'Courier New',Monospace;font-size:small;background-color:#fff;white-space:pre-wrap;border:0;padding:0;margin:0;display:block}.cke_wysiwyg_frame,.cke_wysiwyg_div{background-color:#fff}.cke_notifications_area{pointer-events:none}.cke_notification{pointer-events:auto;position:relative;margin:10px;width:300px;color:white;text-align:center;opacity:.95;filter:alpha(opacity = 95);-webkit-animation:fadeIn .7s;animation:fadeIn .7s}.cke_notification_message a{color:#12306f}@-webkit-keyframes fadeIn{from{opacity:.4}to{opacity:.95}}@keyframes fadeIn{from{opacity:.4}to{opacity:.95}}.cke_notification_success{background:#72b572;border:1px solid #63a563}.cke_notification_warning{background:#c83939;border:1px solid #902b2b}.cke_notification_info{background:#2e9ad0;border:1px solid #0f74a8}.cke_notification_info span.cke_notification_progress{background-color:#0f74a8;display:block;padding:0;margin:0;height:100%;overflow:hidden;position:absolute;z-index:1}.cke_notification_message{position:relative;margin:4px 23px 3px;font-family:Arial,Helvetica,sans-serif;font-size:12px;line-height:18px;z-index:4;text-overflow:ellipsis;overflow:hidden}.cke_notification_close{background-image:url(images/close.png);background-repeat:no-repeat;background-position:50%;position:absolute;cursor:pointer;text-align:center;height:20px;width:20px;top:1px;right:1px;padding:0;margin:0;z-index:5;opacity:.6;filter:alpha(opacity = 60)}.cke_notification_close:hover{opacity:1;filter:alpha(opacity = 100)}.cke_notification_close span{display:none}.cke_notification_warning a.cke_notification_close{opacity:.8;filter:alpha(opacity = 80)}.cke_notification_warning a.cke_notification_close:hover{opacity:1;filter:alpha(opacity = 100)}.cke_chrome{visibility:inherit}.cke_voice_label{display:none}legend.cke_voice_label{display:none}.cke_button__about_icon{background:url(icons.png?t=J5S9) no-repeat 0 -0px!important}.cke_button__bold_icon{background:url(icons.png?t=J5S9) no-repeat 0 -24px!important}.cke_button__italic_icon{background:url(icons.png?t=J5S9) no-repeat 0 -48px!important}.cke_button__strike_icon{background:url(icons.png?t=J5S9) no-repeat 0 -72px!important}.cke_button__subscript_icon{background:url(icons.png?t=J5S9) no-repeat 0 -96px!important}.cke_button__superscript_icon{background:url(icons.png?t=J5S9) no-repeat 0 -120px!important}.cke_button__underline_icon{background:url(icons.png?t=J5S9) no-repeat 0 -144px!important}.cke_button__bidiltr_icon{background:url(icons.png?t=J5S9) no-repeat 0 -168px!important}.cke_button__bidirtl_icon{background:url(icons.png?t=J5S9) no-repeat 0 -192px!important}.cke_button__blockquote_icon{background:url(icons.png?t=J5S9) no-repeat 0 -216px!important}.cke_rtl .cke_button__copy_icon,.cke_mixed_dir_content .cke_rtl .cke_button__copy_icon{background:url(icons.png?t=J5S9) no-repeat 0 -240px!important}.cke_ltr .cke_button__copy_icon{background:url(icons.png?t=J5S9) no-repeat 0 -264px!important}.cke_rtl .cke_button__cut_icon,.cke_mixed_dir_content .cke_rtl .cke_button__cut_icon{background:url(icons.png?t=J5S9) no-repeat 0 -288px!important}.cke_ltr .cke_button__cut_icon{background:url(icons.png?t=J5S9) no-repeat 0 -312px!important}.cke_rtl .cke_button__paste_icon,.cke_mixed_dir_content .cke_rtl .cke_button__paste_icon{background:url(icons.png?t=J5S9) no-repeat 0 -336px!important}.cke_ltr .cke_button__paste_icon{background:url(icons.png?t=J5S9) no-repeat 0 -360px!important}.cke_button__codesnippet_icon{background:url(icons.png?t=J5S9) no-repeat 0 -384px!important}.cke_button__bgcolor_icon{background:url(icons.png?t=J5S9) no-repeat 0 -408px!important}.cke_button__textcolor_icon{background:url(icons.png?t=J5S9) no-repeat 0 -432px!important}.cke_button__copyformatting_icon{background:url(icons.png?t=J5S9) no-repeat 0 -456px!important}.cke_button__creatediv_icon{background:url(icons.png?t=J5S9) no-repeat 0 -480px!important}.cke_rtl .cke_button__docprops_icon,.cke_mixed_dir_content .cke_rtl .cke_button__docprops_icon{background:url(icons.png?t=J5S9) no-repeat 0 -504px!important}.cke_ltr .cke_button__docprops_icon{background:url(icons.png?t=J5S9) no-repeat 0 -528px!important}.cke_button__easyimagealigncenter_icon{background:url(icons.png?t=J5S9) no-repeat 0 -552px!important}.cke_button__easyimagealignleft_icon{background:url(icons.png?t=J5S9) no-repeat 0 -576px!important}.cke_button__easyimagealignright_icon{background:url(icons.png?t=J5S9) no-repeat 0 -600px!important}.cke_button__easyimagealt_icon{background:url(icons.png?t=J5S9) no-repeat 0 -624px!important}.cke_button__easyimagefull_icon{background:url(icons.png?t=J5S9) no-repeat 0 -648px!important}.cke_button__easyimageside_icon{background:url(icons.png?t=J5S9) no-repeat 0 -672px!important}.cke_button__easyimageupload_icon{background:url(icons.png?t=J5S9) no-repeat 0 -696px!important}.cke_button__embed_icon{background:url(icons.png?t=J5S9) no-repeat 0 -720px!important}.cke_button__embedsemantic_icon{background:url(icons.png?t=J5S9) no-repeat 0 -744px!important}.cke_button__emojipanel_icon{background:url(icons.png?t=J5S9) no-repeat 0 -768px!important}.cke_rtl .cke_button__find_icon,.cke_mixed_dir_content .cke_rtl .cke_button__find_icon{background:url(icons.png?t=J5S9) no-repeat 0 -792px!important}.cke_ltr .cke_button__find_icon{background:url(icons.png?t=J5S9) no-repeat 0 -816px!important}.cke_button__replace_icon{background:url(icons.png?t=J5S9) no-repeat 0 -840px!important}.cke_button__flash_icon{background:url(icons.png?t=J5S9) no-repeat 0 -864px!important}.cke_button__button_icon{background:url(icons.png?t=J5S9) no-repeat 0 -888px!important}.cke_button__checkbox_icon{background:url(icons.png?t=J5S9) no-repeat 0 -912px!important}.cke_button__form_icon{background:url(icons.png?t=J5S9) no-repeat 0 -936px!important}.cke_button__hiddenfield_icon{background:url(icons.png?t=J5S9) no-repeat 0 -960px!important}.cke_button__imagebutton_icon{background:url(icons.png?t=J5S9) no-repeat 0 -984px!important}.cke_button__radio_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1008px!important}.cke_rtl .cke_button__select_icon,.cke_mixed_dir_content .cke_rtl .cke_button__select_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1032px!important}.cke_ltr .cke_button__select_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1056px!important}.cke_rtl .cke_button__textarea_icon,.cke_mixed_dir_content .cke_rtl .cke_button__textarea_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1080px!important}.cke_ltr .cke_button__textarea_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1104px!important}.cke_rtl .cke_button__textfield_icon,.cke_mixed_dir_content .cke_rtl .cke_button__textfield_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1128px!important}.cke_ltr .cke_button__textfield_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1152px!important}.cke_button__horizontalrule_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1176px!important}.cke_button__iframe_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1200px!important}.cke_button__image_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1224px!important}.cke_rtl .cke_button__indent_icon,.cke_mixed_dir_content .cke_rtl .cke_button__indent_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1248px!important}.cke_ltr .cke_button__indent_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1272px!important}.cke_rtl .cke_button__outdent_icon,.cke_mixed_dir_content .cke_rtl .cke_button__outdent_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1296px!important}.cke_ltr .cke_button__outdent_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1320px!important}.cke_button__justifyblock_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1344px!important}.cke_button__justifycenter_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1368px!important}.cke_button__justifyleft_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1392px!important}.cke_button__justifyright_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1416px!important}.cke_button__language_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1440px!important}.cke_rtl .cke_button__anchor_icon,.cke_mixed_dir_content .cke_rtl .cke_button__anchor_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1464px!important}.cke_ltr .cke_button__anchor_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1488px!important}.cke_button__link_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1512px!important}.cke_button__unlink_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1536px!important}.cke_rtl .cke_button__bulletedlist_icon,.cke_mixed_dir_content .cke_rtl .cke_button__bulletedlist_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1560px!important}.cke_ltr .cke_button__bulletedlist_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1584px!important}.cke_rtl .cke_button__numberedlist_icon,.cke_mixed_dir_content .cke_rtl .cke_button__numberedlist_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1608px!important}.cke_ltr .cke_button__numberedlist_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1632px!important}.cke_button__mathjax_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1656px!important}.cke_button__maximize_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1680px!important}.cke_rtl .cke_button__newpage_icon,.cke_mixed_dir_content .cke_rtl .cke_button__newpage_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1704px!important}.cke_ltr .cke_button__newpage_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1728px!important}.cke_rtl .cke_button__pagebreak_icon,.cke_mixed_dir_content .cke_rtl .cke_button__pagebreak_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1752px!important}.cke_ltr .cke_button__pagebreak_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1776px!important}.cke_rtl .cke_button__pastefromword_icon,.cke_mixed_dir_content .cke_rtl .cke_button__pastefromword_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1800px!important}.cke_ltr .cke_button__pastefromword_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1824px!important}.cke_rtl .cke_button__pastetext_icon,.cke_mixed_dir_content .cke_rtl .cke_button__pastetext_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1848px!important}.cke_ltr .cke_button__pastetext_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1872px!important}.cke_button__placeholder_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1896px!important}.cke_rtl .cke_button__preview_icon,.cke_mixed_dir_content .cke_rtl .cke_button__preview_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1920px!important}.cke_ltr .cke_button__preview_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1944px!important}.cke_button__print_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1968px!important}.cke_button__removeformat_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1992px!important}.cke_button__save_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2016px!important}.cke_button__scayt_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2040px!important}.cke_button__selectall_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2064px!important}.cke_rtl .cke_button__showblocks_icon,.cke_mixed_dir_content .cke_rtl .cke_button__showblocks_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2088px!important}.cke_ltr .cke_button__showblocks_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2112px!important}.cke_button__smiley_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2136px!important}.cke_rtl .cke_button__source_icon,.cke_mixed_dir_content .cke_rtl .cke_button__source_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2160px!important}.cke_ltr .cke_button__source_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2184px!important}.cke_rtl .cke_button__sourcedialog_icon,.cke_mixed_dir_content .cke_rtl .cke_button__sourcedialog_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2208px!important}.cke_ltr .cke_button__sourcedialog_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2232px!important}.cke_button__specialchar_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2256px!important}.cke_button__table_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2280px!important}.cke_rtl .cke_button__templates_icon,.cke_mixed_dir_content .cke_rtl .cke_button__templates_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2304px!important}.cke_ltr .cke_button__templates_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2328px!important}.cke_button__uicolor_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2352px!important}.cke_rtl .cke_button__redo_icon,.cke_mixed_dir_content .cke_rtl .cke_button__redo_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2376px!important}.cke_ltr .cke_button__redo_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2400px!important}.cke_rtl .cke_button__undo_icon,.cke_mixed_dir_content .cke_rtl .cke_button__undo_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2424px!important}.cke_ltr .cke_button__undo_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2448px!important}.cke_button__simplebox_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2472px!important}.cke_button__spellchecker_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2496px!important}.cke_hidpi .cke_button__about_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -0px!important;background-size:16px!important}.cke_hidpi .cke_button__bold_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -24px!important;background-size:16px!important}.cke_hidpi .cke_button__italic_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -48px!important;background-size:16px!important}.cke_hidpi .cke_button__strike_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -72px!important;background-size:16px!important}.cke_hidpi .cke_button__subscript_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -96px!important;background-size:16px!important}.cke_hidpi .cke_button__superscript_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -120px!important;background-size:16px!important}.cke_hidpi .cke_button__underline_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -144px!important;background-size:16px!important}.cke_hidpi .cke_button__bidiltr_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -168px!important;background-size:16px!important}.cke_hidpi .cke_button__bidirtl_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -192px!important;background-size:16px!important}.cke_hidpi .cke_button__blockquote_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -216px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__copy_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__copy_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -240px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__copy_icon,.cke_ltr.cke_hidpi .cke_button__copy_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -264px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__cut_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__cut_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -288px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__cut_icon,.cke_ltr.cke_hidpi .cke_button__cut_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -312px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__paste_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__paste_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -336px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__paste_icon,.cke_ltr.cke_hidpi .cke_button__paste_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -360px!important;background-size:16px!important}.cke_hidpi .cke_button__codesnippet_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -384px!important;background-size:16px!important}.cke_hidpi .cke_button__bgcolor_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -408px!important;background-size:16px!important}.cke_hidpi .cke_button__textcolor_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -432px!important;background-size:16px!important}.cke_hidpi .cke_button__copyformatting_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -456px!important;background-size:16px!important}.cke_hidpi .cke_button__creatediv_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -480px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__docprops_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__docprops_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -504px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__docprops_icon,.cke_ltr.cke_hidpi .cke_button__docprops_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -528px!important;background-size:16px!important}.cke_hidpi .cke_button__easyimagealigncenter_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -552px!important;background-size:16px!important}.cke_hidpi .cke_button__easyimagealignleft_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -576px!important;background-size:16px!important}.cke_hidpi .cke_button__easyimagealignright_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -600px!important;background-size:16px!important}.cke_hidpi .cke_button__easyimagealt_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -624px!important;background-size:16px!important}.cke_hidpi .cke_button__easyimagefull_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -648px!important;background-size:16px!important}.cke_hidpi .cke_button__easyimageside_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -672px!important;background-size:16px!important}.cke_hidpi .cke_button__easyimageupload_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -696px!important;background-size:16px!important}.cke_hidpi .cke_button__embed_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -720px!important;background-size:16px!important}.cke_hidpi .cke_button__embedsemantic_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -744px!important;background-size:16px!important}.cke_hidpi .cke_button__emojipanel_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -768px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__find_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__find_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -792px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__find_icon,.cke_ltr.cke_hidpi .cke_button__find_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -816px!important;background-size:16px!important}.cke_hidpi .cke_button__replace_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -840px!important;background-size:16px!important}.cke_hidpi .cke_button__flash_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -864px!important;background-size:16px!important}.cke_hidpi .cke_button__button_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -888px!important;background-size:16px!important}.cke_hidpi .cke_button__checkbox_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -912px!important;background-size:16px!important}.cke_hidpi .cke_button__form_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -936px!important;background-size:16px!important}.cke_hidpi .cke_button__hiddenfield_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -960px!important;background-size:16px!important}.cke_hidpi .cke_button__imagebutton_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -984px!important;background-size:16px!important}.cke_hidpi .cke_button__radio_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1008px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__select_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__select_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1032px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__select_icon,.cke_ltr.cke_hidpi .cke_button__select_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1056px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__textarea_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__textarea_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1080px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__textarea_icon,.cke_ltr.cke_hidpi .cke_button__textarea_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1104px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__textfield_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__textfield_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1128px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__textfield_icon,.cke_ltr.cke_hidpi .cke_button__textfield_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1152px!important;background-size:16px!important}.cke_hidpi .cke_button__horizontalrule_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1176px!important;background-size:16px!important}.cke_hidpi .cke_button__iframe_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1200px!important;background-size:16px!important}.cke_hidpi .cke_button__image_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1224px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__indent_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__indent_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1248px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__indent_icon,.cke_ltr.cke_hidpi .cke_button__indent_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1272px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__outdent_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__outdent_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1296px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__outdent_icon,.cke_ltr.cke_hidpi .cke_button__outdent_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1320px!important;background-size:16px!important}.cke_hidpi .cke_button__justifyblock_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1344px!important;background-size:16px!important}.cke_hidpi .cke_button__justifycenter_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1368px!important;background-size:16px!important}.cke_hidpi .cke_button__justifyleft_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1392px!important;background-size:16px!important}.cke_hidpi .cke_button__justifyright_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1416px!important;background-size:16px!important}.cke_hidpi .cke_button__language_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1440px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__anchor_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__anchor_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1464px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__anchor_icon,.cke_ltr.cke_hidpi .cke_button__anchor_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1488px!important;background-size:16px!important}.cke_hidpi .cke_button__link_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1512px!important;background-size:16px!important}.cke_hidpi .cke_button__unlink_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1536px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__bulletedlist_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__bulletedlist_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1560px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__bulletedlist_icon,.cke_ltr.cke_hidpi .cke_button__bulletedlist_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1584px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__numberedlist_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__numberedlist_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1608px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__numberedlist_icon,.cke_ltr.cke_hidpi .cke_button__numberedlist_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1632px!important;background-size:16px!important}.cke_hidpi .cke_button__mathjax_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1656px!important;background-size:16px!important}.cke_hidpi .cke_button__maximize_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1680px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__newpage_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__newpage_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1704px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__newpage_icon,.cke_ltr.cke_hidpi .cke_button__newpage_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1728px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__pagebreak_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__pagebreak_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1752px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__pagebreak_icon,.cke_ltr.cke_hidpi .cke_button__pagebreak_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1776px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__pastefromword_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__pastefromword_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1800px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__pastefromword_icon,.cke_ltr.cke_hidpi .cke_button__pastefromword_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1824px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__pastetext_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__pastetext_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1848px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__pastetext_icon,.cke_ltr.cke_hidpi .cke_button__pastetext_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1872px!important;background-size:16px!important}.cke_hidpi .cke_button__placeholder_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1896px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__preview_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__preview_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1920px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__preview_icon,.cke_ltr.cke_hidpi .cke_button__preview_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1944px!important;background-size:16px!important}.cke_hidpi .cke_button__print_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1968px!important;background-size:16px!important}.cke_hidpi .cke_button__removeformat_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1992px!important;background-size:16px!important}.cke_hidpi .cke_button__save_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2016px!important;background-size:16px!important}.cke_hidpi .cke_button__scayt_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2040px!important;background-size:16px!important}.cke_hidpi .cke_button__selectall_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2064px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__showblocks_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__showblocks_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2088px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__showblocks_icon,.cke_ltr.cke_hidpi .cke_button__showblocks_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2112px!important;background-size:16px!important}.cke_hidpi .cke_button__smiley_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2136px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__source_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__source_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2160px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__source_icon,.cke_ltr.cke_hidpi .cke_button__source_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2184px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__sourcedialog_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__sourcedialog_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2208px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__sourcedialog_icon,.cke_ltr.cke_hidpi .cke_button__sourcedialog_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2232px!important;background-size:16px!important}.cke_hidpi .cke_button__specialchar_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2256px!important;background-size:16px!important}.cke_hidpi .cke_button__table_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2280px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__templates_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__templates_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2304px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__templates_icon,.cke_ltr.cke_hidpi .cke_button__templates_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2328px!important;background-size:16px!important}.cke_hidpi .cke_button__uicolor_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2352px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__redo_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__redo_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2376px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__redo_icon,.cke_ltr.cke_hidpi .cke_button__redo_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2400px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__undo_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__undo_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2424px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__undo_icon,.cke_ltr.cke_hidpi .cke_button__undo_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2448px!important;background-size:16px!important}.cke_hidpi .cke_button__simplebox_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -4944px!important}.cke_hidpi .cke_button__spellchecker_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2496px!important;background-size:16px!important}"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/adminlte/bower_components/ckeditor/skins/moono-lisa/editor_gecko.css",
    "content": "/*\nCopyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.\nFor licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n*/\n.cke_reset{margin:0;padding:0;border:0;background:transparent;text-decoration:none;width:auto;height:auto;vertical-align:baseline;box-sizing:content-box;position:static;transition:none}.cke_reset_all,.cke_reset_all *,.cke_reset_all a,.cke_reset_all textarea{margin:0;padding:0;border:0;background:transparent;text-decoration:none;width:auto;height:auto;vertical-align:baseline;box-sizing:content-box;position:static;transition:none;border-collapse:collapse;font:normal normal normal 12px Arial,Helvetica,Tahoma,Verdana,Sans-Serif;color:#000;text-align:left;white-space:nowrap;cursor:auto;float:none}.cke_reset_all .cke_rtl *{text-align:right}.cke_reset_all iframe{vertical-align:inherit}.cke_reset_all textarea{white-space:pre-wrap}.cke_reset_all textarea,.cke_reset_all input[type=\"text\"],.cke_reset_all input[type=\"password\"]{cursor:text}.cke_reset_all textarea[disabled],.cke_reset_all input[type=\"text\"][disabled],.cke_reset_all input[type=\"password\"][disabled]{cursor:default}.cke_reset_all fieldset{padding:10px;border:2px groove #e0dfe3}.cke_reset_all select{box-sizing:border-box}.cke_reset_all table{table-layout:auto}.cke_chrome{display:block;border:1px solid #d1d1d1;padding:0}.cke_inner{display:block;background:#fff;padding:0;-webkit-touch-callout:none}.cke_float{border:0}.cke_float .cke_inner{padding-bottom:0}.cke_top,.cke_contents,.cke_bottom{display:block;overflow:hidden}.cke_top{border-bottom:1px solid #d1d1d1;background:#f8f8f8;padding:6px 8px 2px;white-space:normal}.cke_float .cke_top{border:1px solid #d1d1d1}.cke_bottom{padding:6px 8px 2px;position:relative;border-top:1px solid #d1d1d1;background:#f8f8f8}.cke_browser_ios .cke_contents{overflow-y:auto;-webkit-overflow-scrolling:touch}.cke_resizer{width:0;height:0;overflow:hidden;border-width:10px 10px 0 0;border-color:transparent #bcbcbc transparent transparent;border-style:dashed solid dashed dashed;font-size:0;vertical-align:bottom;margin-top:6px;margin-bottom:2px}.cke_hc .cke_resizer{font-size:15px;width:auto;height:auto;border-width:0}.cke_resizer_ltr{cursor:se-resize;float:right;margin-right:-4px}.cke_resizer_rtl{border-width:10px 0 0 10px;border-color:transparent transparent transparent #bcbcbc;border-style:dashed dashed dashed solid;cursor:sw-resize;float:left;margin-left:-4px;right:auto}.cke_wysiwyg_div{display:block;height:100%;overflow:auto;padding:0 8px;outline-style:none;box-sizing:border-box}.cke_panel{visibility:visible;width:120px;height:100px;overflow:hidden;background-color:#fff;border:1px solid #d1d1d1}.cke_menu_panel{padding:0;margin:0}.cke_combopanel{width:150px;height:170px}.cke_panel_frame{width:100%;height:100%;font-size:12px;overflow:auto;overflow-x:hidden}.cke_panel_container{overflow-y:auto;overflow-x:hidden}.cke_panel_block:focus{outline:0}.cke_panel_list{margin:0;padding:0;list-style-type:none;white-space:nowrap}.cke_panel_listItem{margin:0;padding:0}.cke_panel_listItem a{padding:6px 7px;display:block;color:inherit!important;text-decoration:none;overflow:hidden;text-overflow:ellipsis}.cke_hc .cke_panel_listItem a{border-style:none}.cke_panel_listItem.cke_selected a,.cke_panel_listItem a:hover,.cke_panel_listItem a:focus,.cke_panel_listItem a:active{background-color:#e9e9e9}.cke_panel_listItem a:focus{outline:1px dotted #000}.cke_hc .cke_panel_listItem a:hover,.cke_hc .cke_panel_listItem a:focus,.cke_hc .cke_panel_listItem a:active{border:2px solid;padding:4px 5px}.cke_panel_listItem p,.cke_panel_listItem h1,.cke_panel_listItem h2,.cke_panel_listItem h3,.cke_panel_listItem h4,.cke_panel_listItem h5,.cke_panel_listItem h6,.cke_panel_listItem pre{margin-top:0;margin-bottom:0}.cke_panel_grouptitle{cursor:default;font-size:11px;font-weight:bold;white-space:nowrap;margin:0;padding:6px 6px 7px 6px;color:#484848;border-bottom:1px solid #d1d1d1;background:#f8f8f8}.cke_colorblock{padding:10px;font-size:11px;font-family:'Microsoft Sans Serif',Tahoma,Arial,Verdana,Sans-Serif}.cke_colorblock,.cke_colorblock a{text-decoration:none;color:#000}a.cke_colorbox{padding:2px;float:left;width:20px;height:20px}.cke_rtl a.cke_colorbox{float:right}a:hover.cke_colorbox,a:focus.cke_colorbox,a:active.cke_colorbox{outline:0;padding:0;border:2px solid #139ff7}a:hover.cke_colorbox{border-color:#bcbcbc}span.cke_colorbox{width:20px;height:20px;float:left}.cke_rtl span.cke_colorbox{float:right}a.cke_colorauto,a.cke_colormore{border:#fff 1px solid;padding:3px;display:block;cursor:pointer}a.cke_colorauto{padding:0;border:1px solid transparent;margin-bottom:6px;height:26px;line-height:26px}a.cke_colormore{margin-top:10px;height:20px;line-height:19px}a:hover.cke_colorauto,a:hover.cke_colormore,a:focus.cke_colorauto,a:focus.cke_colormore,a:active.cke_colorauto,a:active.cke_colormore{outline:0;border:#139ff7 1px solid;background-color:#f8f8f8}a:hover.cke_colorauto,a:hover.cke_colormore{border-color:#bcbcbc}.cke_colorauto span.cke_colorbox{width:18px;height:18px;border:1px solid #808080;margin-left:1px;margin-top:3px}.cke_rtl .cke_colorauto span.cke_colorbox{margin-left:0;margin-right:1px}span.cke_colorbox[style*=\"#ffffff\"],span.cke_colorbox[style*=\"#FFFFFF\"],span.cke_colorbox[style=\"background-color:#fff\"],span.cke_colorbox[style=\"background-color:#FFF\"],span.cke_colorbox[style*=\"rgb(255,255,255)\"],span.cke_colorbox[style*=\"rgb(255, 255, 255)\"]{border:1px solid #808080;width:18px;height:18px}.cke_toolbar{float:left}.cke_rtl .cke_toolbar{float:right}.cke_toolgroup{border:0;float:left;margin:1px 2px 6px 0;padding-right:3px}.cke_rtl .cke_toolgroup{float:right;margin:1px 0 6px 2px;padding-left:3px;padding-right:0}.cke_hc .cke_toolgroup{margin-right:5px;margin-bottom:5px}.cke_hc.cke_rtl .cke_toolgroup{margin-right:0;margin-left:5px}a.cke_button{display:inline-block;height:18px;padding:4px 6px;outline:0;cursor:default;float:left;border:0;position:relative}a.cke_button_expandable{padding:4px 5px}.cke_rtl a.cke_button{float:right}.cke_hc a.cke_button{border:1px solid black;padding:3px 5px;margin:0 3px 5px 0}.cke_hc.cke_rtl a.cke_button{margin:0 0 5px 3px}a.cke_button_on{background:#fff;border:1px #bcbcbc solid;padding:3px 5px}a.cke_button_expandable.cke_button_on{padding:3px 4px}a.cke_button_off:hover,a.cke_button_off:focus,a.cke_button_off:active{background:#e5e5e5;border:1px #bcbcbc solid;padding:3px 5px}a.cke_button_expandable.cke_button_off:hover,a.cke_button_expandable.cke_button_off:focus,a.cke_button_expandable.cke_button_off:active{padding:3px 4px}.cke_hc a.cke_button_on,.cke_hc a.cke_button_off:hover,.cke_hc a.cke_button_off:focus,.cke_hc a.cke_button_off:active{background:#e5e5e5;border:3px solid #000;padding:1px 3px}a.cke_button_disabled:hover,a.cke_button_disabled:focus,a.cke_button_disabled:active{border:0;padding:4px 6px;background-color:transparent}a.cke_button_expandable.cke_button_disabled:hover,a.cke_button_expandable.cke_button_disabled:active{padding:4px 5px}a.cke_button_disabled:focus{border:1px #bcbcbc solid;padding:3px 5px}a.cke_button_expandable.cke_button_disabled:focus{padding:3px 4px}.cke_hc a.cke_button_disabled:hover,.cke_hc a.cke_button_disabled:focus,.cke_hc a.cke_button_disabled:active{border:1px solid #acacac;padding:3px 5px;margin:0 3px 5px 0}.cke_hc a.cke_button_disabled:focus{border:3px solid #000;padding:1px 3px}.cke_hc.cke_rtl a.cke_button_disabled:hover,.cke_hc.cke_rtl a.cke_button_disabled:focus,.cke_hc.cke_rtl a.cke_button_disabled:active{margin:0 0 5px 3px}a.cke_button_disabled .cke_button_icon,a.cke_button_disabled .cke_button_arrow{opacity:.3}.cke_hc a.cke_button_disabled{border-color:#acacac}.cke_hc a.cke_button_disabled .cke_button_icon,.cke_hc a.cke_button_disabled .cke_button_label{opacity:.5}.cke_toolgroup a.cke_button:last-child:after,.cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{content:\"\";position:absolute;height:18px;width:0;border-right:1px solid #bcbcbc;margin-top:4px;top:0;right:-3px}.cke_rtl .cke_toolgroup a.cke_button:last-child:after,.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{border-right:0;right:auto;border-left:1px solid #bcbcbc;top:0;left:-3px}.cke_hc .cke_toolgroup a.cke_button:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_disabled:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{border-color:#000;top:0;right:-7px}.cke_hc.cke_rtl .cke_toolgroup a.cke_button:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{top:0;right:auto;left:-7px}.cke_toolgroup a.cke_button:hover:last-child:after,.cke_toolgroup a.cke_button:focus:last-child:after,.cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-1px;right:-4px}.cke_rtl .cke_toolgroup a.cke_button:hover:last-child:after,.cke_rtl .cke_toolgroup a.cke_button:focus:last-child:after,.cke_rtl .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-1px;right:auto;left:-4px}.cke_hc .cke_toolgroup a.cke_button:hover:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-2px;right:-9px}.cke_hc.cke_rtl .cke_toolgroup a.cke_button:hover:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-2px;right:auto;left:-9px}.cke_toolbar.cke_toolbar_last .cke_toolgroup a.cke_button:last-child:after{content:none;border:0;width:0;height:0}.cke_button_icon{cursor:inherit;background-repeat:no-repeat;margin-top:1px;width:16px;height:16px;float:left;display:inline-block}.cke_rtl .cke_button_icon{float:right}.cke_hc .cke_button_icon{display:none}.cke_button_label{display:none;padding-left:3px;margin-top:1px;line-height:17px;vertical-align:middle;float:left;cursor:default;color:#484848}.cke_rtl .cke_button_label{padding-right:3px;padding-left:0;float:right}.cke_hc .cke_button_label{padding:0;display:inline-block;font-size:12px}.cke_button_arrow{display:inline-block;margin:8px 0 0 3px;width:0;height:0;cursor:default;vertical-align:top;border-left:3px solid transparent;border-right:3px solid transparent;border-top:3px solid #484848}.cke_rtl .cke_button_arrow{margin-right:5px;margin-left:0}.cke_hc .cke_button_arrow{font-size:10px;margin:3px 0 0 3px;width:auto;border:0}.cke_toolbar_separator{float:left;background-color:#bcbcbc;margin:4px 2px 0 2px;height:18px;width:1px}.cke_rtl .cke_toolbar_separator{float:right}.cke_hc .cke_toolbar_separator{background-color:#000;margin-left:2px;margin-right:5px;margin-bottom:9px}.cke_hc.cke_rtl .cke_toolbar_separator{margin-left:5px;margin-right:2px}.cke_toolbar_break{display:block;clear:left}.cke_rtl .cke_toolbar_break{clear:right}a.cke_toolbox_collapser{width:12px;height:11px;float:right;margin:11px 0 0;font-size:0;cursor:default;text-align:center;border:1px solid #bcbcbc}.cke_rtl .cke_toolbox_collapser{float:left}.cke_toolbox_collapser:hover{background:#e5e5e5}.cke_toolbox_collapser.cke_toolbox_collapser_min{margin:0 2px 4px}.cke_toolbox_collapser .cke_arrow{display:inline-block;height:0;width:0;font-size:0;margin-top:1px;border:3px solid transparent;border-bottom-color:#484848}.cke_toolbox_collapser.cke_toolbox_collapser_min .cke_arrow{margin-top:4px;border-bottom-color:transparent;border-top-color:#484848}.cke_hc .cke_toolbox_collapser .cke_arrow{font-size:8px;width:auto;border:0;margin-top:0}.cke_menuitem span{cursor:default}.cke_menubutton{display:block}.cke_hc .cke_menubutton{padding:2px}.cke_menubutton:hover,.cke_menubutton:focus,.cke_menubutton:active{background-color:#e9e9e9;display:block;outline:1px dotted}.cke_menubutton:hover{outline:0}.cke_hc .cke_menubutton:hover,.cke_hc .cke_menubutton:focus,.cke_hc .cke_menubutton:active{border:2px solid;padding:0}.cke_menubutton_disabled:hover,.cke_menubutton_disabled:focus,.cke_menubutton_disabled:active{background-color:transparent;outline:0}.cke_menubutton_inner{display:table-row}.cke_menubutton_icon,.cke_menubutton_label,.cke_menuarrow{display:table-cell}.cke_menubutton_icon{background-color:#f8f8f8;padding:6px 4px}.cke_hc .cke_menubutton_icon{height:16px;width:0;padding:4px 0}.cke_menubutton:hover .cke_menubutton_icon,.cke_menubutton:focus .cke_menubutton_icon,.cke_menubutton:active .cke_menubutton_icon{background-color:#e9e9e9}.cke_menubutton_disabled:hover .cke_menubutton_icon,.cke_menubutton_disabled:focus .cke_menubutton_icon,.cke_menubutton_disabled:active .cke_menubutton_icon{background-color:#f8f8f8;outline:0}.cke_menuitem .cke_menubutton_on{background-color:#e9e9e9;border:1px solid #dedede;outline:0}.cke_menubutton_on .cke_menubutton_icon{padding-right:3px;background-color:#e9e9e9}.cke_menubutton_label{padding:0 5px;background-color:transparent;width:100%;vertical-align:middle}.cke_menubutton_shortcut{color:#979797}.cke_menubutton_disabled .cke_menubutton_label{opacity:.3;filter:alpha(opacity=30)}.cke_panel_frame .cke_menubutton_label{display:none}.cke_menuseparator{background-color:#d1d1d1;height:1px}.cke_menuarrow{background:transparent url(images/arrow.png) no-repeat 0 10px;padding:0 5px}.cke_rtl .cke_menuarrow{background-position:5px -13px;background-repeat:no-repeat}.cke_hc .cke_menuarrow{background-image:none}.cke_menuarrow span{display:none}.cke_hc .cke_menuarrow span{vertical-align:middle;display:inline}.cke_combo{display:inline-block;float:left;position:relative;margin-bottom:5px}.cke_rtl .cke_combo{float:right}.cke_hc .cke_combo{margin-top:1px;margin-bottom:10px}.cke_combo:after{content:\"\";position:absolute;height:18px;width:0;border-right:1px solid #bcbcbc;margin-top:5px;top:0;right:0}.cke_rtl .cke_combo:after{border-right:0;border-left:1px solid #bcbcbc;right:auto;left:0}.cke_hc .cke_combo:after{border-color:#000}a.cke_combo_button{cursor:default;display:inline-block;float:left;margin:0;padding:1px}.cke_rtl a.cke_combo_button{float:right}.cke_hc a.cke_combo_button{padding:4px}.cke_combo_on a.cke_combo_button,.cke_combo_off a.cke_combo_button:hover,.cke_combo_off a.cke_combo_button:focus,.cke_combo_off a.cke_combo_button:active{background:#e5e5e5;border:1px solid #bcbcbc;padding:0 0 0 1px;margin-left:-1px}.cke_combo_off a.cke_combo_button:focus{outline:0}.cke_combo_on a.cke_combo_button,.cke_combo_off a.cke_combo_button:active{background:#fff}.cke_rtl .cke_combo_on a.cke_combo_button,.cke_rtl .cke_combo_off a.cke_combo_button:hover,.cke_rtl .cke_combo_off a.cke_combo_button:focus,.cke_rtl .cke_combo_off a.cke_combo_button:active{padding:0 1px 0 0;margin-left:0;margin-right:-1px}.cke_hc .cke_combo_on a.cke_combo_button,.cke_hc .cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_combo_off a.cke_combo_button:active{border:3px solid #000;padding:1px 1px 1px 2px}.cke_hc.cke_rtl .cke_combo_on a.cke_combo_button,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:hover,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:focus,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:active{padding:1px 2px 1px 1px}.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0 0 0 3px;margin-left:-3px}.cke_rtl .cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0 3px 0 0;margin-left:0;margin-right:-3px}.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px 1px 1px 7px;margin-left:-6px}.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px 7px 1px 1px;margin-left:0;margin-right:-6px}.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0;margin:0}.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px;margin:0}.cke_toolbar .cke_combo+.cke_toolbar_end,.cke_toolbar .cke_combo+.cke_toolgroup{margin-right:0;margin-left:2px}.cke_rtl .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_rtl .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:0;margin-right:2px}.cke_hc .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_hc .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:5px}.cke_hc.cke_rtl .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_hc.cke_rtl .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:0;margin-right:5px}.cke_toolbar.cke_toolbar_last .cke_combo:nth-last-child(-n+2):after{content:none;border:0;width:0;height:0}.cke_combo_text{line-height:26px;padding-left:10px;text-overflow:ellipsis;overflow:hidden;float:left;cursor:default;color:#484848;width:60px}.cke_rtl .cke_combo_text{float:right;text-align:right;padding-left:0;padding-right:10px}.cke_hc .cke_combo_text{line-height:18px;font-size:12px}.cke_combo_open{cursor:default;display:inline-block;font-size:0;height:19px;line-height:17px;margin:1px 10px 1px;width:5px}.cke_hc .cke_combo_open{height:12px}.cke_combo_arrow{cursor:default;margin:11px 0 0;float:left;height:0;width:0;font-size:0;border-left:3px solid transparent;border-right:3px solid transparent;border-top:3px solid #484848}.cke_hc .cke_combo_arrow{font-size:10px;width:auto;border:0;margin-top:3px}.cke_combo_label{display:none;float:left;line-height:26px;vertical-align:top;margin-right:5px}.cke_rtl .cke_combo_label{float:right;margin-left:5px;margin-right:0}.cke_combo_disabled .cke_combo_inlinelabel,.cke_combo_disabled .cke_combo_open{opacity:.3}.cke_path{float:left;margin:-2px 0 2px}a.cke_path_item,span.cke_path_empty{display:inline-block;float:left;padding:3px 4px;margin-right:2px;cursor:default;text-decoration:none;outline:0;border:0;color:#484848;font-weight:bold;font-size:11px}.cke_rtl .cke_path,.cke_rtl .cke_path_item,.cke_rtl .cke_path_empty{float:right}a.cke_path_item:hover,a.cke_path_item:focus,a.cke_path_item:active{background-color:#e5e5e5}.cke_hc a.cke_path_item:hover,.cke_hc a.cke_path_item:focus,.cke_hc a.cke_path_item:active{border:2px solid;padding:1px 2px}.cke_button__source_label,.cke_button__sourcedialog_label{display:inline}.cke_combopanel__fontsize{width:135px}textarea.cke_source{font-family:'Courier New',Monospace;font-size:small;background-color:#fff;white-space:pre-wrap;border:0;padding:0;margin:0;display:block}.cke_wysiwyg_frame,.cke_wysiwyg_div{background-color:#fff}.cke_notifications_area{pointer-events:none}.cke_notification{pointer-events:auto;position:relative;margin:10px;width:300px;color:white;text-align:center;opacity:.95;filter:alpha(opacity = 95);-webkit-animation:fadeIn .7s;animation:fadeIn .7s}.cke_notification_message a{color:#12306f}@-webkit-keyframes fadeIn{from{opacity:.4}to{opacity:.95}}@keyframes fadeIn{from{opacity:.4}to{opacity:.95}}.cke_notification_success{background:#72b572;border:1px solid #63a563}.cke_notification_warning{background:#c83939;border:1px solid #902b2b}.cke_notification_info{background:#2e9ad0;border:1px solid #0f74a8}.cke_notification_info span.cke_notification_progress{background-color:#0f74a8;display:block;padding:0;margin:0;height:100%;overflow:hidden;position:absolute;z-index:1}.cke_notification_message{position:relative;margin:4px 23px 3px;font-family:Arial,Helvetica,sans-serif;font-size:12px;line-height:18px;z-index:4;text-overflow:ellipsis;overflow:hidden}.cke_notification_close{background-image:url(images/close.png);background-repeat:no-repeat;background-position:50%;position:absolute;cursor:pointer;text-align:center;height:20px;width:20px;top:1px;right:1px;padding:0;margin:0;z-index:5;opacity:.6;filter:alpha(opacity = 60)}.cke_notification_close:hover{opacity:1;filter:alpha(opacity = 100)}.cke_notification_close span{display:none}.cke_notification_warning a.cke_notification_close{opacity:.8;filter:alpha(opacity = 80)}.cke_notification_warning a.cke_notification_close:hover{opacity:1;filter:alpha(opacity = 100)}.cke_chrome{visibility:inherit}.cke_voice_label{display:none}legend.cke_voice_label{display:none}.cke_button__about_icon{background:url(icons.png?t=J5S9) no-repeat 0 -0px!important}.cke_button__bold_icon{background:url(icons.png?t=J5S9) no-repeat 0 -24px!important}.cke_button__italic_icon{background:url(icons.png?t=J5S9) no-repeat 0 -48px!important}.cke_button__strike_icon{background:url(icons.png?t=J5S9) no-repeat 0 -72px!important}.cke_button__subscript_icon{background:url(icons.png?t=J5S9) no-repeat 0 -96px!important}.cke_button__superscript_icon{background:url(icons.png?t=J5S9) no-repeat 0 -120px!important}.cke_button__underline_icon{background:url(icons.png?t=J5S9) no-repeat 0 -144px!important}.cke_button__bidiltr_icon{background:url(icons.png?t=J5S9) no-repeat 0 -168px!important}.cke_button__bidirtl_icon{background:url(icons.png?t=J5S9) no-repeat 0 -192px!important}.cke_button__blockquote_icon{background:url(icons.png?t=J5S9) no-repeat 0 -216px!important}.cke_rtl .cke_button__copy_icon,.cke_mixed_dir_content .cke_rtl .cke_button__copy_icon{background:url(icons.png?t=J5S9) no-repeat 0 -240px!important}.cke_ltr .cke_button__copy_icon{background:url(icons.png?t=J5S9) no-repeat 0 -264px!important}.cke_rtl .cke_button__cut_icon,.cke_mixed_dir_content .cke_rtl .cke_button__cut_icon{background:url(icons.png?t=J5S9) no-repeat 0 -288px!important}.cke_ltr .cke_button__cut_icon{background:url(icons.png?t=J5S9) no-repeat 0 -312px!important}.cke_rtl .cke_button__paste_icon,.cke_mixed_dir_content .cke_rtl .cke_button__paste_icon{background:url(icons.png?t=J5S9) no-repeat 0 -336px!important}.cke_ltr .cke_button__paste_icon{background:url(icons.png?t=J5S9) no-repeat 0 -360px!important}.cke_button__codesnippet_icon{background:url(icons.png?t=J5S9) no-repeat 0 -384px!important}.cke_button__bgcolor_icon{background:url(icons.png?t=J5S9) no-repeat 0 -408px!important}.cke_button__textcolor_icon{background:url(icons.png?t=J5S9) no-repeat 0 -432px!important}.cke_button__copyformatting_icon{background:url(icons.png?t=J5S9) no-repeat 0 -456px!important}.cke_button__creatediv_icon{background:url(icons.png?t=J5S9) no-repeat 0 -480px!important}.cke_rtl .cke_button__docprops_icon,.cke_mixed_dir_content .cke_rtl .cke_button__docprops_icon{background:url(icons.png?t=J5S9) no-repeat 0 -504px!important}.cke_ltr .cke_button__docprops_icon{background:url(icons.png?t=J5S9) no-repeat 0 -528px!important}.cke_button__easyimagealigncenter_icon{background:url(icons.png?t=J5S9) no-repeat 0 -552px!important}.cke_button__easyimagealignleft_icon{background:url(icons.png?t=J5S9) no-repeat 0 -576px!important}.cke_button__easyimagealignright_icon{background:url(icons.png?t=J5S9) no-repeat 0 -600px!important}.cke_button__easyimagealt_icon{background:url(icons.png?t=J5S9) no-repeat 0 -624px!important}.cke_button__easyimagefull_icon{background:url(icons.png?t=J5S9) no-repeat 0 -648px!important}.cke_button__easyimageside_icon{background:url(icons.png?t=J5S9) no-repeat 0 -672px!important}.cke_button__easyimageupload_icon{background:url(icons.png?t=J5S9) no-repeat 0 -696px!important}.cke_button__embed_icon{background:url(icons.png?t=J5S9) no-repeat 0 -720px!important}.cke_button__embedsemantic_icon{background:url(icons.png?t=J5S9) no-repeat 0 -744px!important}.cke_button__emojipanel_icon{background:url(icons.png?t=J5S9) no-repeat 0 -768px!important}.cke_rtl .cke_button__find_icon,.cke_mixed_dir_content .cke_rtl .cke_button__find_icon{background:url(icons.png?t=J5S9) no-repeat 0 -792px!important}.cke_ltr .cke_button__find_icon{background:url(icons.png?t=J5S9) no-repeat 0 -816px!important}.cke_button__replace_icon{background:url(icons.png?t=J5S9) no-repeat 0 -840px!important}.cke_button__flash_icon{background:url(icons.png?t=J5S9) no-repeat 0 -864px!important}.cke_button__button_icon{background:url(icons.png?t=J5S9) no-repeat 0 -888px!important}.cke_button__checkbox_icon{background:url(icons.png?t=J5S9) no-repeat 0 -912px!important}.cke_button__form_icon{background:url(icons.png?t=J5S9) no-repeat 0 -936px!important}.cke_button__hiddenfield_icon{background:url(icons.png?t=J5S9) no-repeat 0 -960px!important}.cke_button__imagebutton_icon{background:url(icons.png?t=J5S9) no-repeat 0 -984px!important}.cke_button__radio_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1008px!important}.cke_rtl .cke_button__select_icon,.cke_mixed_dir_content .cke_rtl .cke_button__select_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1032px!important}.cke_ltr .cke_button__select_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1056px!important}.cke_rtl .cke_button__textarea_icon,.cke_mixed_dir_content .cke_rtl .cke_button__textarea_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1080px!important}.cke_ltr .cke_button__textarea_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1104px!important}.cke_rtl .cke_button__textfield_icon,.cke_mixed_dir_content .cke_rtl .cke_button__textfield_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1128px!important}.cke_ltr .cke_button__textfield_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1152px!important}.cke_button__horizontalrule_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1176px!important}.cke_button__iframe_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1200px!important}.cke_button__image_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1224px!important}.cke_rtl .cke_button__indent_icon,.cke_mixed_dir_content .cke_rtl .cke_button__indent_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1248px!important}.cke_ltr .cke_button__indent_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1272px!important}.cke_rtl .cke_button__outdent_icon,.cke_mixed_dir_content .cke_rtl .cke_button__outdent_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1296px!important}.cke_ltr .cke_button__outdent_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1320px!important}.cke_button__justifyblock_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1344px!important}.cke_button__justifycenter_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1368px!important}.cke_button__justifyleft_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1392px!important}.cke_button__justifyright_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1416px!important}.cke_button__language_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1440px!important}.cke_rtl .cke_button__anchor_icon,.cke_mixed_dir_content .cke_rtl .cke_button__anchor_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1464px!important}.cke_ltr .cke_button__anchor_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1488px!important}.cke_button__link_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1512px!important}.cke_button__unlink_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1536px!important}.cke_rtl .cke_button__bulletedlist_icon,.cke_mixed_dir_content .cke_rtl .cke_button__bulletedlist_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1560px!important}.cke_ltr .cke_button__bulletedlist_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1584px!important}.cke_rtl .cke_button__numberedlist_icon,.cke_mixed_dir_content .cke_rtl .cke_button__numberedlist_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1608px!important}.cke_ltr .cke_button__numberedlist_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1632px!important}.cke_button__mathjax_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1656px!important}.cke_button__maximize_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1680px!important}.cke_rtl .cke_button__newpage_icon,.cke_mixed_dir_content .cke_rtl .cke_button__newpage_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1704px!important}.cke_ltr .cke_button__newpage_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1728px!important}.cke_rtl .cke_button__pagebreak_icon,.cke_mixed_dir_content .cke_rtl .cke_button__pagebreak_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1752px!important}.cke_ltr .cke_button__pagebreak_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1776px!important}.cke_rtl .cke_button__pastefromword_icon,.cke_mixed_dir_content .cke_rtl .cke_button__pastefromword_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1800px!important}.cke_ltr .cke_button__pastefromword_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1824px!important}.cke_rtl .cke_button__pastetext_icon,.cke_mixed_dir_content .cke_rtl .cke_button__pastetext_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1848px!important}.cke_ltr .cke_button__pastetext_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1872px!important}.cke_button__placeholder_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1896px!important}.cke_rtl .cke_button__preview_icon,.cke_mixed_dir_content .cke_rtl .cke_button__preview_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1920px!important}.cke_ltr .cke_button__preview_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1944px!important}.cke_button__print_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1968px!important}.cke_button__removeformat_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1992px!important}.cke_button__save_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2016px!important}.cke_button__scayt_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2040px!important}.cke_button__selectall_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2064px!important}.cke_rtl .cke_button__showblocks_icon,.cke_mixed_dir_content .cke_rtl .cke_button__showblocks_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2088px!important}.cke_ltr .cke_button__showblocks_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2112px!important}.cke_button__smiley_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2136px!important}.cke_rtl .cke_button__source_icon,.cke_mixed_dir_content .cke_rtl .cke_button__source_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2160px!important}.cke_ltr .cke_button__source_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2184px!important}.cke_rtl .cke_button__sourcedialog_icon,.cke_mixed_dir_content .cke_rtl .cke_button__sourcedialog_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2208px!important}.cke_ltr .cke_button__sourcedialog_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2232px!important}.cke_button__specialchar_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2256px!important}.cke_button__table_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2280px!important}.cke_rtl .cke_button__templates_icon,.cke_mixed_dir_content .cke_rtl .cke_button__templates_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2304px!important}.cke_ltr .cke_button__templates_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2328px!important}.cke_button__uicolor_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2352px!important}.cke_rtl .cke_button__redo_icon,.cke_mixed_dir_content .cke_rtl .cke_button__redo_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2376px!important}.cke_ltr .cke_button__redo_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2400px!important}.cke_rtl .cke_button__undo_icon,.cke_mixed_dir_content .cke_rtl .cke_button__undo_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2424px!important}.cke_ltr .cke_button__undo_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2448px!important}.cke_button__simplebox_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2472px!important}.cke_button__spellchecker_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2496px!important}.cke_hidpi .cke_button__about_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -0px!important;background-size:16px!important}.cke_hidpi .cke_button__bold_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -24px!important;background-size:16px!important}.cke_hidpi .cke_button__italic_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -48px!important;background-size:16px!important}.cke_hidpi .cke_button__strike_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -72px!important;background-size:16px!important}.cke_hidpi .cke_button__subscript_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -96px!important;background-size:16px!important}.cke_hidpi .cke_button__superscript_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -120px!important;background-size:16px!important}.cke_hidpi .cke_button__underline_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -144px!important;background-size:16px!important}.cke_hidpi .cke_button__bidiltr_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -168px!important;background-size:16px!important}.cke_hidpi .cke_button__bidirtl_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -192px!important;background-size:16px!important}.cke_hidpi .cke_button__blockquote_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -216px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__copy_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__copy_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -240px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__copy_icon,.cke_ltr.cke_hidpi .cke_button__copy_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -264px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__cut_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__cut_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -288px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__cut_icon,.cke_ltr.cke_hidpi .cke_button__cut_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -312px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__paste_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__paste_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -336px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__paste_icon,.cke_ltr.cke_hidpi .cke_button__paste_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -360px!important;background-size:16px!important}.cke_hidpi .cke_button__codesnippet_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -384px!important;background-size:16px!important}.cke_hidpi .cke_button__bgcolor_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -408px!important;background-size:16px!important}.cke_hidpi .cke_button__textcolor_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -432px!important;background-size:16px!important}.cke_hidpi .cke_button__copyformatting_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -456px!important;background-size:16px!important}.cke_hidpi .cke_button__creatediv_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -480px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__docprops_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__docprops_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -504px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__docprops_icon,.cke_ltr.cke_hidpi .cke_button__docprops_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -528px!important;background-size:16px!important}.cke_hidpi .cke_button__easyimagealigncenter_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -552px!important;background-size:16px!important}.cke_hidpi .cke_button__easyimagealignleft_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -576px!important;background-size:16px!important}.cke_hidpi .cke_button__easyimagealignright_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -600px!important;background-size:16px!important}.cke_hidpi .cke_button__easyimagealt_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -624px!important;background-size:16px!important}.cke_hidpi .cke_button__easyimagefull_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -648px!important;background-size:16px!important}.cke_hidpi .cke_button__easyimageside_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -672px!important;background-size:16px!important}.cke_hidpi .cke_button__easyimageupload_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -696px!important;background-size:16px!important}.cke_hidpi .cke_button__embed_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -720px!important;background-size:16px!important}.cke_hidpi .cke_button__embedsemantic_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -744px!important;background-size:16px!important}.cke_hidpi .cke_button__emojipanel_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -768px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__find_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__find_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -792px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__find_icon,.cke_ltr.cke_hidpi .cke_button__find_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -816px!important;background-size:16px!important}.cke_hidpi .cke_button__replace_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -840px!important;background-size:16px!important}.cke_hidpi .cke_button__flash_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -864px!important;background-size:16px!important}.cke_hidpi .cke_button__button_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -888px!important;background-size:16px!important}.cke_hidpi .cke_button__checkbox_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -912px!important;background-size:16px!important}.cke_hidpi .cke_button__form_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -936px!important;background-size:16px!important}.cke_hidpi .cke_button__hiddenfield_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -960px!important;background-size:16px!important}.cke_hidpi .cke_button__imagebutton_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -984px!important;background-size:16px!important}.cke_hidpi .cke_button__radio_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1008px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__select_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__select_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1032px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__select_icon,.cke_ltr.cke_hidpi .cke_button__select_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1056px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__textarea_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__textarea_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1080px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__textarea_icon,.cke_ltr.cke_hidpi .cke_button__textarea_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1104px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__textfield_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__textfield_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1128px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__textfield_icon,.cke_ltr.cke_hidpi .cke_button__textfield_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1152px!important;background-size:16px!important}.cke_hidpi .cke_button__horizontalrule_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1176px!important;background-size:16px!important}.cke_hidpi .cke_button__iframe_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1200px!important;background-size:16px!important}.cke_hidpi .cke_button__image_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1224px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__indent_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__indent_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1248px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__indent_icon,.cke_ltr.cke_hidpi .cke_button__indent_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1272px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__outdent_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__outdent_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1296px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__outdent_icon,.cke_ltr.cke_hidpi .cke_button__outdent_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1320px!important;background-size:16px!important}.cke_hidpi .cke_button__justifyblock_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1344px!important;background-size:16px!important}.cke_hidpi .cke_button__justifycenter_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1368px!important;background-size:16px!important}.cke_hidpi .cke_button__justifyleft_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1392px!important;background-size:16px!important}.cke_hidpi .cke_button__justifyright_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1416px!important;background-size:16px!important}.cke_hidpi .cke_button__language_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1440px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__anchor_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__anchor_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1464px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__anchor_icon,.cke_ltr.cke_hidpi .cke_button__anchor_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1488px!important;background-size:16px!important}.cke_hidpi .cke_button__link_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1512px!important;background-size:16px!important}.cke_hidpi .cke_button__unlink_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1536px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__bulletedlist_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__bulletedlist_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1560px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__bulletedlist_icon,.cke_ltr.cke_hidpi .cke_button__bulletedlist_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1584px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__numberedlist_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__numberedlist_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1608px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__numberedlist_icon,.cke_ltr.cke_hidpi .cke_button__numberedlist_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1632px!important;background-size:16px!important}.cke_hidpi .cke_button__mathjax_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1656px!important;background-size:16px!important}.cke_hidpi .cke_button__maximize_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1680px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__newpage_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__newpage_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1704px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__newpage_icon,.cke_ltr.cke_hidpi .cke_button__newpage_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1728px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__pagebreak_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__pagebreak_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1752px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__pagebreak_icon,.cke_ltr.cke_hidpi .cke_button__pagebreak_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1776px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__pastefromword_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__pastefromword_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1800px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__pastefromword_icon,.cke_ltr.cke_hidpi .cke_button__pastefromword_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1824px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__pastetext_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__pastetext_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1848px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__pastetext_icon,.cke_ltr.cke_hidpi .cke_button__pastetext_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1872px!important;background-size:16px!important}.cke_hidpi .cke_button__placeholder_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1896px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__preview_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__preview_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1920px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__preview_icon,.cke_ltr.cke_hidpi .cke_button__preview_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1944px!important;background-size:16px!important}.cke_hidpi .cke_button__print_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1968px!important;background-size:16px!important}.cke_hidpi .cke_button__removeformat_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1992px!important;background-size:16px!important}.cke_hidpi .cke_button__save_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2016px!important;background-size:16px!important}.cke_hidpi .cke_button__scayt_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2040px!important;background-size:16px!important}.cke_hidpi .cke_button__selectall_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2064px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__showblocks_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__showblocks_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2088px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__showblocks_icon,.cke_ltr.cke_hidpi .cke_button__showblocks_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2112px!important;background-size:16px!important}.cke_hidpi .cke_button__smiley_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2136px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__source_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__source_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2160px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__source_icon,.cke_ltr.cke_hidpi .cke_button__source_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2184px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__sourcedialog_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__sourcedialog_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2208px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__sourcedialog_icon,.cke_ltr.cke_hidpi .cke_button__sourcedialog_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2232px!important;background-size:16px!important}.cke_hidpi .cke_button__specialchar_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2256px!important;background-size:16px!important}.cke_hidpi .cke_button__table_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2280px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__templates_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__templates_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2304px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__templates_icon,.cke_ltr.cke_hidpi .cke_button__templates_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2328px!important;background-size:16px!important}.cke_hidpi .cke_button__uicolor_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2352px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__redo_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__redo_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2376px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__redo_icon,.cke_ltr.cke_hidpi .cke_button__redo_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2400px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__undo_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__undo_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2424px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__undo_icon,.cke_ltr.cke_hidpi .cke_button__undo_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2448px!important;background-size:16px!important}.cke_hidpi .cke_button__simplebox_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -4944px!important}.cke_hidpi .cke_button__spellchecker_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2496px!important;background-size:16px!important}.cke_bottom{padding-bottom:3px}.cke_combo_text{margin-bottom:-1px;margin-top:1px}"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/adminlte/bower_components/ckeditor/skins/moono-lisa/editor_ie.css",
    "content": "/*\nCopyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.\nFor licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n*/\n.cke_reset{margin:0;padding:0;border:0;background:transparent;text-decoration:none;width:auto;height:auto;vertical-align:baseline;box-sizing:content-box;position:static;transition:none}.cke_reset_all,.cke_reset_all *,.cke_reset_all a,.cke_reset_all textarea{margin:0;padding:0;border:0;background:transparent;text-decoration:none;width:auto;height:auto;vertical-align:baseline;box-sizing:content-box;position:static;transition:none;border-collapse:collapse;font:normal normal normal 12px Arial,Helvetica,Tahoma,Verdana,Sans-Serif;color:#000;text-align:left;white-space:nowrap;cursor:auto;float:none}.cke_reset_all .cke_rtl *{text-align:right}.cke_reset_all iframe{vertical-align:inherit}.cke_reset_all textarea{white-space:pre-wrap}.cke_reset_all textarea,.cke_reset_all input[type=\"text\"],.cke_reset_all input[type=\"password\"]{cursor:text}.cke_reset_all textarea[disabled],.cke_reset_all input[type=\"text\"][disabled],.cke_reset_all input[type=\"password\"][disabled]{cursor:default}.cke_reset_all fieldset{padding:10px;border:2px groove #e0dfe3}.cke_reset_all select{box-sizing:border-box}.cke_reset_all table{table-layout:auto}.cke_chrome{display:block;border:1px solid #d1d1d1;padding:0}.cke_inner{display:block;background:#fff;padding:0;-webkit-touch-callout:none}.cke_float{border:0}.cke_float .cke_inner{padding-bottom:0}.cke_top,.cke_contents,.cke_bottom{display:block;overflow:hidden}.cke_top{border-bottom:1px solid #d1d1d1;background:#f8f8f8;padding:6px 8px 2px;white-space:normal}.cke_float .cke_top{border:1px solid #d1d1d1}.cke_bottom{padding:6px 8px 2px;position:relative;border-top:1px solid #d1d1d1;background:#f8f8f8}.cke_browser_ios .cke_contents{overflow-y:auto;-webkit-overflow-scrolling:touch}.cke_resizer{width:0;height:0;overflow:hidden;border-width:10px 10px 0 0;border-color:transparent #bcbcbc transparent transparent;border-style:dashed solid dashed dashed;font-size:0;vertical-align:bottom;margin-top:6px;margin-bottom:2px}.cke_hc .cke_resizer{font-size:15px;width:auto;height:auto;border-width:0}.cke_resizer_ltr{cursor:se-resize;float:right;margin-right:-4px}.cke_resizer_rtl{border-width:10px 0 0 10px;border-color:transparent transparent transparent #bcbcbc;border-style:dashed dashed dashed solid;cursor:sw-resize;float:left;margin-left:-4px;right:auto}.cke_wysiwyg_div{display:block;height:100%;overflow:auto;padding:0 8px;outline-style:none;box-sizing:border-box}.cke_panel{visibility:visible;width:120px;height:100px;overflow:hidden;background-color:#fff;border:1px solid #d1d1d1}.cke_menu_panel{padding:0;margin:0}.cke_combopanel{width:150px;height:170px}.cke_panel_frame{width:100%;height:100%;font-size:12px;overflow:auto;overflow-x:hidden}.cke_panel_container{overflow-y:auto;overflow-x:hidden}.cke_panel_block:focus{outline:0}.cke_panel_list{margin:0;padding:0;list-style-type:none;white-space:nowrap}.cke_panel_listItem{margin:0;padding:0}.cke_panel_listItem a{padding:6px 7px;display:block;color:inherit!important;text-decoration:none;overflow:hidden;text-overflow:ellipsis}.cke_hc .cke_panel_listItem a{border-style:none}.cke_panel_listItem.cke_selected a,.cke_panel_listItem a:hover,.cke_panel_listItem a:focus,.cke_panel_listItem a:active{background-color:#e9e9e9}.cke_panel_listItem a:focus{outline:1px dotted #000}.cke_hc .cke_panel_listItem a:hover,.cke_hc .cke_panel_listItem a:focus,.cke_hc .cke_panel_listItem a:active{border:2px solid;padding:4px 5px}.cke_panel_listItem p,.cke_panel_listItem h1,.cke_panel_listItem h2,.cke_panel_listItem h3,.cke_panel_listItem h4,.cke_panel_listItem h5,.cke_panel_listItem h6,.cke_panel_listItem pre{margin-top:0;margin-bottom:0}.cke_panel_grouptitle{cursor:default;font-size:11px;font-weight:bold;white-space:nowrap;margin:0;padding:6px 6px 7px 6px;color:#484848;border-bottom:1px solid #d1d1d1;background:#f8f8f8}.cke_colorblock{padding:10px;font-size:11px;font-family:'Microsoft Sans Serif',Tahoma,Arial,Verdana,Sans-Serif}.cke_colorblock,.cke_colorblock a{text-decoration:none;color:#000}a.cke_colorbox{padding:2px;float:left;width:20px;height:20px}.cke_rtl a.cke_colorbox{float:right}a:hover.cke_colorbox,a:focus.cke_colorbox,a:active.cke_colorbox{outline:0;padding:0;border:2px solid #139ff7}a:hover.cke_colorbox{border-color:#bcbcbc}span.cke_colorbox{width:20px;height:20px;float:left}.cke_rtl span.cke_colorbox{float:right}a.cke_colorauto,a.cke_colormore{border:#fff 1px solid;padding:3px;display:block;cursor:pointer}a.cke_colorauto{padding:0;border:1px solid transparent;margin-bottom:6px;height:26px;line-height:26px}a.cke_colormore{margin-top:10px;height:20px;line-height:19px}a:hover.cke_colorauto,a:hover.cke_colormore,a:focus.cke_colorauto,a:focus.cke_colormore,a:active.cke_colorauto,a:active.cke_colormore{outline:0;border:#139ff7 1px solid;background-color:#f8f8f8}a:hover.cke_colorauto,a:hover.cke_colormore{border-color:#bcbcbc}.cke_colorauto span.cke_colorbox{width:18px;height:18px;border:1px solid #808080;margin-left:1px;margin-top:3px}.cke_rtl .cke_colorauto span.cke_colorbox{margin-left:0;margin-right:1px}span.cke_colorbox[style*=\"#ffffff\"],span.cke_colorbox[style*=\"#FFFFFF\"],span.cke_colorbox[style=\"background-color:#fff\"],span.cke_colorbox[style=\"background-color:#FFF\"],span.cke_colorbox[style*=\"rgb(255,255,255)\"],span.cke_colorbox[style*=\"rgb(255, 255, 255)\"]{border:1px solid #808080;width:18px;height:18px}.cke_toolbar{float:left}.cke_rtl .cke_toolbar{float:right}.cke_toolgroup{border:0;float:left;margin:1px 2px 6px 0;padding-right:3px}.cke_rtl .cke_toolgroup{float:right;margin:1px 0 6px 2px;padding-left:3px;padding-right:0}.cke_hc .cke_toolgroup{margin-right:5px;margin-bottom:5px}.cke_hc.cke_rtl .cke_toolgroup{margin-right:0;margin-left:5px}a.cke_button{display:inline-block;height:18px;padding:4px 6px;outline:0;cursor:default;float:left;border:0;position:relative}a.cke_button_expandable{padding:4px 5px}.cke_rtl a.cke_button{float:right}.cke_hc a.cke_button{border:1px solid black;padding:3px 5px;margin:0 3px 5px 0}.cke_hc.cke_rtl a.cke_button{margin:0 0 5px 3px}a.cke_button_on{background:#fff;border:1px #bcbcbc solid;padding:3px 5px}a.cke_button_expandable.cke_button_on{padding:3px 4px}a.cke_button_off:hover,a.cke_button_off:focus,a.cke_button_off:active{background:#e5e5e5;border:1px #bcbcbc solid;padding:3px 5px}a.cke_button_expandable.cke_button_off:hover,a.cke_button_expandable.cke_button_off:focus,a.cke_button_expandable.cke_button_off:active{padding:3px 4px}.cke_hc a.cke_button_on,.cke_hc a.cke_button_off:hover,.cke_hc a.cke_button_off:focus,.cke_hc a.cke_button_off:active{background:#e5e5e5;border:3px solid #000;padding:1px 3px}a.cke_button_disabled:hover,a.cke_button_disabled:focus,a.cke_button_disabled:active{border:0;padding:4px 6px;background-color:transparent}a.cke_button_expandable.cke_button_disabled:hover,a.cke_button_expandable.cke_button_disabled:active{padding:4px 5px}a.cke_button_disabled:focus{border:1px #bcbcbc solid;padding:3px 5px}a.cke_button_expandable.cke_button_disabled:focus{padding:3px 4px}.cke_hc a.cke_button_disabled:hover,.cke_hc a.cke_button_disabled:focus,.cke_hc a.cke_button_disabled:active{border:1px solid #acacac;padding:3px 5px;margin:0 3px 5px 0}.cke_hc a.cke_button_disabled:focus{border:3px solid #000;padding:1px 3px}.cke_hc.cke_rtl a.cke_button_disabled:hover,.cke_hc.cke_rtl a.cke_button_disabled:focus,.cke_hc.cke_rtl a.cke_button_disabled:active{margin:0 0 5px 3px}a.cke_button_disabled .cke_button_icon,a.cke_button_disabled .cke_button_arrow{opacity:.3}.cke_hc a.cke_button_disabled{border-color:#acacac}.cke_hc a.cke_button_disabled .cke_button_icon,.cke_hc a.cke_button_disabled .cke_button_label{opacity:.5}.cke_toolgroup a.cke_button:last-child:after,.cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{content:\"\";position:absolute;height:18px;width:0;border-right:1px solid #bcbcbc;margin-top:4px;top:0;right:-3px}.cke_rtl .cke_toolgroup a.cke_button:last-child:after,.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{border-right:0;right:auto;border-left:1px solid #bcbcbc;top:0;left:-3px}.cke_hc .cke_toolgroup a.cke_button:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_disabled:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{border-color:#000;top:0;right:-7px}.cke_hc.cke_rtl .cke_toolgroup a.cke_button:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{top:0;right:auto;left:-7px}.cke_toolgroup a.cke_button:hover:last-child:after,.cke_toolgroup a.cke_button:focus:last-child:after,.cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-1px;right:-4px}.cke_rtl .cke_toolgroup a.cke_button:hover:last-child:after,.cke_rtl .cke_toolgroup a.cke_button:focus:last-child:after,.cke_rtl .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-1px;right:auto;left:-4px}.cke_hc .cke_toolgroup a.cke_button:hover:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-2px;right:-9px}.cke_hc.cke_rtl .cke_toolgroup a.cke_button:hover:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-2px;right:auto;left:-9px}.cke_toolbar.cke_toolbar_last .cke_toolgroup a.cke_button:last-child:after{content:none;border:0;width:0;height:0}.cke_button_icon{cursor:inherit;background-repeat:no-repeat;margin-top:1px;width:16px;height:16px;float:left;display:inline-block}.cke_rtl .cke_button_icon{float:right}.cke_hc .cke_button_icon{display:none}.cke_button_label{display:none;padding-left:3px;margin-top:1px;line-height:17px;vertical-align:middle;float:left;cursor:default;color:#484848}.cke_rtl .cke_button_label{padding-right:3px;padding-left:0;float:right}.cke_hc .cke_button_label{padding:0;display:inline-block;font-size:12px}.cke_button_arrow{display:inline-block;margin:8px 0 0 3px;width:0;height:0;cursor:default;vertical-align:top;border-left:3px solid transparent;border-right:3px solid transparent;border-top:3px solid #484848}.cke_rtl .cke_button_arrow{margin-right:5px;margin-left:0}.cke_hc .cke_button_arrow{font-size:10px;margin:3px 0 0 3px;width:auto;border:0}.cke_toolbar_separator{float:left;background-color:#bcbcbc;margin:4px 2px 0 2px;height:18px;width:1px}.cke_rtl .cke_toolbar_separator{float:right}.cke_hc .cke_toolbar_separator{background-color:#000;margin-left:2px;margin-right:5px;margin-bottom:9px}.cke_hc.cke_rtl .cke_toolbar_separator{margin-left:5px;margin-right:2px}.cke_toolbar_break{display:block;clear:left}.cke_rtl .cke_toolbar_break{clear:right}a.cke_toolbox_collapser{width:12px;height:11px;float:right;margin:11px 0 0;font-size:0;cursor:default;text-align:center;border:1px solid #bcbcbc}.cke_rtl .cke_toolbox_collapser{float:left}.cke_toolbox_collapser:hover{background:#e5e5e5}.cke_toolbox_collapser.cke_toolbox_collapser_min{margin:0 2px 4px}.cke_toolbox_collapser .cke_arrow{display:inline-block;height:0;width:0;font-size:0;margin-top:1px;border:3px solid transparent;border-bottom-color:#484848}.cke_toolbox_collapser.cke_toolbox_collapser_min .cke_arrow{margin-top:4px;border-bottom-color:transparent;border-top-color:#484848}.cke_hc .cke_toolbox_collapser .cke_arrow{font-size:8px;width:auto;border:0;margin-top:0}.cke_menuitem span{cursor:default}.cke_menubutton{display:block}.cke_hc .cke_menubutton{padding:2px}.cke_menubutton:hover,.cke_menubutton:focus,.cke_menubutton:active{background-color:#e9e9e9;display:block;outline:1px dotted}.cke_menubutton:hover{outline:0}.cke_hc .cke_menubutton:hover,.cke_hc .cke_menubutton:focus,.cke_hc .cke_menubutton:active{border:2px solid;padding:0}.cke_menubutton_disabled:hover,.cke_menubutton_disabled:focus,.cke_menubutton_disabled:active{background-color:transparent;outline:0}.cke_menubutton_inner{display:table-row}.cke_menubutton_icon,.cke_menubutton_label,.cke_menuarrow{display:table-cell}.cke_menubutton_icon{background-color:#f8f8f8;padding:6px 4px}.cke_hc .cke_menubutton_icon{height:16px;width:0;padding:4px 0}.cke_menubutton:hover .cke_menubutton_icon,.cke_menubutton:focus .cke_menubutton_icon,.cke_menubutton:active .cke_menubutton_icon{background-color:#e9e9e9}.cke_menubutton_disabled:hover .cke_menubutton_icon,.cke_menubutton_disabled:focus .cke_menubutton_icon,.cke_menubutton_disabled:active .cke_menubutton_icon{background-color:#f8f8f8;outline:0}.cke_menuitem .cke_menubutton_on{background-color:#e9e9e9;border:1px solid #dedede;outline:0}.cke_menubutton_on .cke_menubutton_icon{padding-right:3px;background-color:#e9e9e9}.cke_menubutton_label{padding:0 5px;background-color:transparent;width:100%;vertical-align:middle}.cke_menubutton_shortcut{color:#979797}.cke_menubutton_disabled .cke_menubutton_label{opacity:.3;filter:alpha(opacity=30)}.cke_panel_frame .cke_menubutton_label{display:none}.cke_menuseparator{background-color:#d1d1d1;height:1px}.cke_menuarrow{background:transparent url(images/arrow.png) no-repeat 0 10px;padding:0 5px}.cke_rtl .cke_menuarrow{background-position:5px -13px;background-repeat:no-repeat}.cke_hc .cke_menuarrow{background-image:none}.cke_menuarrow span{display:none}.cke_hc .cke_menuarrow span{vertical-align:middle;display:inline}.cke_combo{display:inline-block;float:left;position:relative;margin-bottom:5px}.cke_rtl .cke_combo{float:right}.cke_hc .cke_combo{margin-top:1px;margin-bottom:10px}.cke_combo:after{content:\"\";position:absolute;height:18px;width:0;border-right:1px solid #bcbcbc;margin-top:5px;top:0;right:0}.cke_rtl .cke_combo:after{border-right:0;border-left:1px solid #bcbcbc;right:auto;left:0}.cke_hc .cke_combo:after{border-color:#000}a.cke_combo_button{cursor:default;display:inline-block;float:left;margin:0;padding:1px}.cke_rtl a.cke_combo_button{float:right}.cke_hc a.cke_combo_button{padding:4px}.cke_combo_on a.cke_combo_button,.cke_combo_off a.cke_combo_button:hover,.cke_combo_off a.cke_combo_button:focus,.cke_combo_off a.cke_combo_button:active{background:#e5e5e5;border:1px solid #bcbcbc;padding:0 0 0 1px;margin-left:-1px}.cke_combo_off a.cke_combo_button:focus{outline:0}.cke_combo_on a.cke_combo_button,.cke_combo_off a.cke_combo_button:active{background:#fff}.cke_rtl .cke_combo_on a.cke_combo_button,.cke_rtl .cke_combo_off a.cke_combo_button:hover,.cke_rtl .cke_combo_off a.cke_combo_button:focus,.cke_rtl .cke_combo_off a.cke_combo_button:active{padding:0 1px 0 0;margin-left:0;margin-right:-1px}.cke_hc .cke_combo_on a.cke_combo_button,.cke_hc .cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_combo_off a.cke_combo_button:active{border:3px solid #000;padding:1px 1px 1px 2px}.cke_hc.cke_rtl .cke_combo_on a.cke_combo_button,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:hover,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:focus,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:active{padding:1px 2px 1px 1px}.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0 0 0 3px;margin-left:-3px}.cke_rtl .cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0 3px 0 0;margin-left:0;margin-right:-3px}.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px 1px 1px 7px;margin-left:-6px}.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px 7px 1px 1px;margin-left:0;margin-right:-6px}.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0;margin:0}.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px;margin:0}.cke_toolbar .cke_combo+.cke_toolbar_end,.cke_toolbar .cke_combo+.cke_toolgroup{margin-right:0;margin-left:2px}.cke_rtl .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_rtl .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:0;margin-right:2px}.cke_hc .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_hc .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:5px}.cke_hc.cke_rtl .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_hc.cke_rtl .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:0;margin-right:5px}.cke_toolbar.cke_toolbar_last .cke_combo:nth-last-child(-n+2):after{content:none;border:0;width:0;height:0}.cke_combo_text{line-height:26px;padding-left:10px;text-overflow:ellipsis;overflow:hidden;float:left;cursor:default;color:#484848;width:60px}.cke_rtl .cke_combo_text{float:right;text-align:right;padding-left:0;padding-right:10px}.cke_hc .cke_combo_text{line-height:18px;font-size:12px}.cke_combo_open{cursor:default;display:inline-block;font-size:0;height:19px;line-height:17px;margin:1px 10px 1px;width:5px}.cke_hc .cke_combo_open{height:12px}.cke_combo_arrow{cursor:default;margin:11px 0 0;float:left;height:0;width:0;font-size:0;border-left:3px solid transparent;border-right:3px solid transparent;border-top:3px solid #484848}.cke_hc .cke_combo_arrow{font-size:10px;width:auto;border:0;margin-top:3px}.cke_combo_label{display:none;float:left;line-height:26px;vertical-align:top;margin-right:5px}.cke_rtl .cke_combo_label{float:right;margin-left:5px;margin-right:0}.cke_combo_disabled .cke_combo_inlinelabel,.cke_combo_disabled .cke_combo_open{opacity:.3}.cke_path{float:left;margin:-2px 0 2px}a.cke_path_item,span.cke_path_empty{display:inline-block;float:left;padding:3px 4px;margin-right:2px;cursor:default;text-decoration:none;outline:0;border:0;color:#484848;font-weight:bold;font-size:11px}.cke_rtl .cke_path,.cke_rtl .cke_path_item,.cke_rtl .cke_path_empty{float:right}a.cke_path_item:hover,a.cke_path_item:focus,a.cke_path_item:active{background-color:#e5e5e5}.cke_hc a.cke_path_item:hover,.cke_hc a.cke_path_item:focus,.cke_hc a.cke_path_item:active{border:2px solid;padding:1px 2px}.cke_button__source_label,.cke_button__sourcedialog_label{display:inline}.cke_combopanel__fontsize{width:135px}textarea.cke_source{font-family:'Courier New',Monospace;font-size:small;background-color:#fff;white-space:pre-wrap;border:0;padding:0;margin:0;display:block}.cke_wysiwyg_frame,.cke_wysiwyg_div{background-color:#fff}.cke_notifications_area{pointer-events:none}.cke_notification{pointer-events:auto;position:relative;margin:10px;width:300px;color:white;text-align:center;opacity:.95;filter:alpha(opacity = 95);-webkit-animation:fadeIn .7s;animation:fadeIn .7s}.cke_notification_message a{color:#12306f}@-webkit-keyframes fadeIn{from{opacity:.4}to{opacity:.95}}@keyframes fadeIn{from{opacity:.4}to{opacity:.95}}.cke_notification_success{background:#72b572;border:1px solid #63a563}.cke_notification_warning{background:#c83939;border:1px solid #902b2b}.cke_notification_info{background:#2e9ad0;border:1px solid #0f74a8}.cke_notification_info span.cke_notification_progress{background-color:#0f74a8;display:block;padding:0;margin:0;height:100%;overflow:hidden;position:absolute;z-index:1}.cke_notification_message{position:relative;margin:4px 23px 3px;font-family:Arial,Helvetica,sans-serif;font-size:12px;line-height:18px;z-index:4;text-overflow:ellipsis;overflow:hidden}.cke_notification_close{background-image:url(images/close.png);background-repeat:no-repeat;background-position:50%;position:absolute;cursor:pointer;text-align:center;height:20px;width:20px;top:1px;right:1px;padding:0;margin:0;z-index:5;opacity:.6;filter:alpha(opacity = 60)}.cke_notification_close:hover{opacity:1;filter:alpha(opacity = 100)}.cke_notification_close span{display:none}.cke_notification_warning a.cke_notification_close{opacity:.8;filter:alpha(opacity = 80)}.cke_notification_warning a.cke_notification_close:hover{opacity:1;filter:alpha(opacity = 100)}.cke_chrome{visibility:inherit}.cke_voice_label{display:none}legend.cke_voice_label{display:none}.cke_button__about_icon{background:url(icons.png?t=J5S9) no-repeat 0 -0px!important}.cke_button__bold_icon{background:url(icons.png?t=J5S9) no-repeat 0 -24px!important}.cke_button__italic_icon{background:url(icons.png?t=J5S9) no-repeat 0 -48px!important}.cke_button__strike_icon{background:url(icons.png?t=J5S9) no-repeat 0 -72px!important}.cke_button__subscript_icon{background:url(icons.png?t=J5S9) no-repeat 0 -96px!important}.cke_button__superscript_icon{background:url(icons.png?t=J5S9) no-repeat 0 -120px!important}.cke_button__underline_icon{background:url(icons.png?t=J5S9) no-repeat 0 -144px!important}.cke_button__bidiltr_icon{background:url(icons.png?t=J5S9) no-repeat 0 -168px!important}.cke_button__bidirtl_icon{background:url(icons.png?t=J5S9) no-repeat 0 -192px!important}.cke_button__blockquote_icon{background:url(icons.png?t=J5S9) no-repeat 0 -216px!important}.cke_rtl .cke_button__copy_icon,.cke_mixed_dir_content .cke_rtl .cke_button__copy_icon{background:url(icons.png?t=J5S9) no-repeat 0 -240px!important}.cke_ltr .cke_button__copy_icon{background:url(icons.png?t=J5S9) no-repeat 0 -264px!important}.cke_rtl .cke_button__cut_icon,.cke_mixed_dir_content .cke_rtl .cke_button__cut_icon{background:url(icons.png?t=J5S9) no-repeat 0 -288px!important}.cke_ltr .cke_button__cut_icon{background:url(icons.png?t=J5S9) no-repeat 0 -312px!important}.cke_rtl .cke_button__paste_icon,.cke_mixed_dir_content .cke_rtl .cke_button__paste_icon{background:url(icons.png?t=J5S9) no-repeat 0 -336px!important}.cke_ltr .cke_button__paste_icon{background:url(icons.png?t=J5S9) no-repeat 0 -360px!important}.cke_button__codesnippet_icon{background:url(icons.png?t=J5S9) no-repeat 0 -384px!important}.cke_button__bgcolor_icon{background:url(icons.png?t=J5S9) no-repeat 0 -408px!important}.cke_button__textcolor_icon{background:url(icons.png?t=J5S9) no-repeat 0 -432px!important}.cke_button__copyformatting_icon{background:url(icons.png?t=J5S9) no-repeat 0 -456px!important}.cke_button__creatediv_icon{background:url(icons.png?t=J5S9) no-repeat 0 -480px!important}.cke_rtl .cke_button__docprops_icon,.cke_mixed_dir_content .cke_rtl .cke_button__docprops_icon{background:url(icons.png?t=J5S9) no-repeat 0 -504px!important}.cke_ltr .cke_button__docprops_icon{background:url(icons.png?t=J5S9) no-repeat 0 -528px!important}.cke_button__easyimagealigncenter_icon{background:url(icons.png?t=J5S9) no-repeat 0 -552px!important}.cke_button__easyimagealignleft_icon{background:url(icons.png?t=J5S9) no-repeat 0 -576px!important}.cke_button__easyimagealignright_icon{background:url(icons.png?t=J5S9) no-repeat 0 -600px!important}.cke_button__easyimagealt_icon{background:url(icons.png?t=J5S9) no-repeat 0 -624px!important}.cke_button__easyimagefull_icon{background:url(icons.png?t=J5S9) no-repeat 0 -648px!important}.cke_button__easyimageside_icon{background:url(icons.png?t=J5S9) no-repeat 0 -672px!important}.cke_button__easyimageupload_icon{background:url(icons.png?t=J5S9) no-repeat 0 -696px!important}.cke_button__embed_icon{background:url(icons.png?t=J5S9) no-repeat 0 -720px!important}.cke_button__embedsemantic_icon{background:url(icons.png?t=J5S9) no-repeat 0 -744px!important}.cke_button__emojipanel_icon{background:url(icons.png?t=J5S9) no-repeat 0 -768px!important}.cke_rtl .cke_button__find_icon,.cke_mixed_dir_content .cke_rtl .cke_button__find_icon{background:url(icons.png?t=J5S9) no-repeat 0 -792px!important}.cke_ltr .cke_button__find_icon{background:url(icons.png?t=J5S9) no-repeat 0 -816px!important}.cke_button__replace_icon{background:url(icons.png?t=J5S9) no-repeat 0 -840px!important}.cke_button__flash_icon{background:url(icons.png?t=J5S9) no-repeat 0 -864px!important}.cke_button__button_icon{background:url(icons.png?t=J5S9) no-repeat 0 -888px!important}.cke_button__checkbox_icon{background:url(icons.png?t=J5S9) no-repeat 0 -912px!important}.cke_button__form_icon{background:url(icons.png?t=J5S9) no-repeat 0 -936px!important}.cke_button__hiddenfield_icon{background:url(icons.png?t=J5S9) no-repeat 0 -960px!important}.cke_button__imagebutton_icon{background:url(icons.png?t=J5S9) no-repeat 0 -984px!important}.cke_button__radio_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1008px!important}.cke_rtl .cke_button__select_icon,.cke_mixed_dir_content .cke_rtl .cke_button__select_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1032px!important}.cke_ltr .cke_button__select_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1056px!important}.cke_rtl .cke_button__textarea_icon,.cke_mixed_dir_content .cke_rtl .cke_button__textarea_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1080px!important}.cke_ltr .cke_button__textarea_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1104px!important}.cke_rtl .cke_button__textfield_icon,.cke_mixed_dir_content .cke_rtl .cke_button__textfield_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1128px!important}.cke_ltr .cke_button__textfield_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1152px!important}.cke_button__horizontalrule_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1176px!important}.cke_button__iframe_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1200px!important}.cke_button__image_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1224px!important}.cke_rtl .cke_button__indent_icon,.cke_mixed_dir_content .cke_rtl .cke_button__indent_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1248px!important}.cke_ltr .cke_button__indent_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1272px!important}.cke_rtl .cke_button__outdent_icon,.cke_mixed_dir_content .cke_rtl .cke_button__outdent_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1296px!important}.cke_ltr .cke_button__outdent_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1320px!important}.cke_button__justifyblock_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1344px!important}.cke_button__justifycenter_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1368px!important}.cke_button__justifyleft_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1392px!important}.cke_button__justifyright_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1416px!important}.cke_button__language_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1440px!important}.cke_rtl .cke_button__anchor_icon,.cke_mixed_dir_content .cke_rtl .cke_button__anchor_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1464px!important}.cke_ltr .cke_button__anchor_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1488px!important}.cke_button__link_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1512px!important}.cke_button__unlink_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1536px!important}.cke_rtl .cke_button__bulletedlist_icon,.cke_mixed_dir_content .cke_rtl .cke_button__bulletedlist_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1560px!important}.cke_ltr .cke_button__bulletedlist_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1584px!important}.cke_rtl .cke_button__numberedlist_icon,.cke_mixed_dir_content .cke_rtl .cke_button__numberedlist_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1608px!important}.cke_ltr .cke_button__numberedlist_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1632px!important}.cke_button__mathjax_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1656px!important}.cke_button__maximize_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1680px!important}.cke_rtl .cke_button__newpage_icon,.cke_mixed_dir_content .cke_rtl .cke_button__newpage_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1704px!important}.cke_ltr .cke_button__newpage_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1728px!important}.cke_rtl .cke_button__pagebreak_icon,.cke_mixed_dir_content .cke_rtl .cke_button__pagebreak_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1752px!important}.cke_ltr .cke_button__pagebreak_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1776px!important}.cke_rtl .cke_button__pastefromword_icon,.cke_mixed_dir_content .cke_rtl .cke_button__pastefromword_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1800px!important}.cke_ltr .cke_button__pastefromword_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1824px!important}.cke_rtl .cke_button__pastetext_icon,.cke_mixed_dir_content .cke_rtl .cke_button__pastetext_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1848px!important}.cke_ltr .cke_button__pastetext_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1872px!important}.cke_button__placeholder_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1896px!important}.cke_rtl .cke_button__preview_icon,.cke_mixed_dir_content .cke_rtl .cke_button__preview_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1920px!important}.cke_ltr .cke_button__preview_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1944px!important}.cke_button__print_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1968px!important}.cke_button__removeformat_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1992px!important}.cke_button__save_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2016px!important}.cke_button__scayt_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2040px!important}.cke_button__selectall_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2064px!important}.cke_rtl .cke_button__showblocks_icon,.cke_mixed_dir_content .cke_rtl .cke_button__showblocks_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2088px!important}.cke_ltr .cke_button__showblocks_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2112px!important}.cke_button__smiley_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2136px!important}.cke_rtl .cke_button__source_icon,.cke_mixed_dir_content .cke_rtl .cke_button__source_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2160px!important}.cke_ltr .cke_button__source_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2184px!important}.cke_rtl .cke_button__sourcedialog_icon,.cke_mixed_dir_content .cke_rtl .cke_button__sourcedialog_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2208px!important}.cke_ltr .cke_button__sourcedialog_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2232px!important}.cke_button__specialchar_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2256px!important}.cke_button__table_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2280px!important}.cke_rtl .cke_button__templates_icon,.cke_mixed_dir_content .cke_rtl .cke_button__templates_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2304px!important}.cke_ltr .cke_button__templates_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2328px!important}.cke_button__uicolor_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2352px!important}.cke_rtl .cke_button__redo_icon,.cke_mixed_dir_content .cke_rtl .cke_button__redo_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2376px!important}.cke_ltr .cke_button__redo_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2400px!important}.cke_rtl .cke_button__undo_icon,.cke_mixed_dir_content .cke_rtl .cke_button__undo_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2424px!important}.cke_ltr .cke_button__undo_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2448px!important}.cke_button__simplebox_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2472px!important}.cke_button__spellchecker_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2496px!important}.cke_hidpi .cke_button__about_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -0px!important;background-size:16px!important}.cke_hidpi .cke_button__bold_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -24px!important;background-size:16px!important}.cke_hidpi .cke_button__italic_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -48px!important;background-size:16px!important}.cke_hidpi .cke_button__strike_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -72px!important;background-size:16px!important}.cke_hidpi .cke_button__subscript_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -96px!important;background-size:16px!important}.cke_hidpi .cke_button__superscript_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -120px!important;background-size:16px!important}.cke_hidpi .cke_button__underline_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -144px!important;background-size:16px!important}.cke_hidpi .cke_button__bidiltr_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -168px!important;background-size:16px!important}.cke_hidpi .cke_button__bidirtl_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -192px!important;background-size:16px!important}.cke_hidpi .cke_button__blockquote_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -216px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__copy_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__copy_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -240px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__copy_icon,.cke_ltr.cke_hidpi .cke_button__copy_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -264px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__cut_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__cut_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -288px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__cut_icon,.cke_ltr.cke_hidpi .cke_button__cut_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -312px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__paste_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__paste_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -336px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__paste_icon,.cke_ltr.cke_hidpi .cke_button__paste_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -360px!important;background-size:16px!important}.cke_hidpi .cke_button__codesnippet_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -384px!important;background-size:16px!important}.cke_hidpi .cke_button__bgcolor_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -408px!important;background-size:16px!important}.cke_hidpi .cke_button__textcolor_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -432px!important;background-size:16px!important}.cke_hidpi .cke_button__copyformatting_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -456px!important;background-size:16px!important}.cke_hidpi .cke_button__creatediv_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -480px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__docprops_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__docprops_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -504px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__docprops_icon,.cke_ltr.cke_hidpi .cke_button__docprops_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -528px!important;background-size:16px!important}.cke_hidpi .cke_button__easyimagealigncenter_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -552px!important;background-size:16px!important}.cke_hidpi .cke_button__easyimagealignleft_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -576px!important;background-size:16px!important}.cke_hidpi .cke_button__easyimagealignright_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -600px!important;background-size:16px!important}.cke_hidpi .cke_button__easyimagealt_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -624px!important;background-size:16px!important}.cke_hidpi .cke_button__easyimagefull_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -648px!important;background-size:16px!important}.cke_hidpi .cke_button__easyimageside_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -672px!important;background-size:16px!important}.cke_hidpi .cke_button__easyimageupload_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -696px!important;background-size:16px!important}.cke_hidpi .cke_button__embed_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -720px!important;background-size:16px!important}.cke_hidpi .cke_button__embedsemantic_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -744px!important;background-size:16px!important}.cke_hidpi .cke_button__emojipanel_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -768px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__find_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__find_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -792px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__find_icon,.cke_ltr.cke_hidpi .cke_button__find_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -816px!important;background-size:16px!important}.cke_hidpi .cke_button__replace_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -840px!important;background-size:16px!important}.cke_hidpi .cke_button__flash_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -864px!important;background-size:16px!important}.cke_hidpi .cke_button__button_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -888px!important;background-size:16px!important}.cke_hidpi .cke_button__checkbox_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -912px!important;background-size:16px!important}.cke_hidpi .cke_button__form_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -936px!important;background-size:16px!important}.cke_hidpi .cke_button__hiddenfield_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -960px!important;background-size:16px!important}.cke_hidpi .cke_button__imagebutton_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -984px!important;background-size:16px!important}.cke_hidpi .cke_button__radio_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1008px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__select_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__select_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1032px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__select_icon,.cke_ltr.cke_hidpi .cke_button__select_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1056px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__textarea_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__textarea_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1080px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__textarea_icon,.cke_ltr.cke_hidpi .cke_button__textarea_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1104px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__textfield_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__textfield_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1128px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__textfield_icon,.cke_ltr.cke_hidpi .cke_button__textfield_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1152px!important;background-size:16px!important}.cke_hidpi .cke_button__horizontalrule_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1176px!important;background-size:16px!important}.cke_hidpi .cke_button__iframe_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1200px!important;background-size:16px!important}.cke_hidpi .cke_button__image_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1224px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__indent_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__indent_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1248px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__indent_icon,.cke_ltr.cke_hidpi .cke_button__indent_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1272px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__outdent_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__outdent_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1296px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__outdent_icon,.cke_ltr.cke_hidpi .cke_button__outdent_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1320px!important;background-size:16px!important}.cke_hidpi .cke_button__justifyblock_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1344px!important;background-size:16px!important}.cke_hidpi .cke_button__justifycenter_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1368px!important;background-size:16px!important}.cke_hidpi .cke_button__justifyleft_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1392px!important;background-size:16px!important}.cke_hidpi .cke_button__justifyright_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1416px!important;background-size:16px!important}.cke_hidpi .cke_button__language_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1440px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__anchor_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__anchor_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1464px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__anchor_icon,.cke_ltr.cke_hidpi .cke_button__anchor_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1488px!important;background-size:16px!important}.cke_hidpi .cke_button__link_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1512px!important;background-size:16px!important}.cke_hidpi .cke_button__unlink_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1536px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__bulletedlist_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__bulletedlist_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1560px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__bulletedlist_icon,.cke_ltr.cke_hidpi .cke_button__bulletedlist_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1584px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__numberedlist_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__numberedlist_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1608px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__numberedlist_icon,.cke_ltr.cke_hidpi .cke_button__numberedlist_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1632px!important;background-size:16px!important}.cke_hidpi .cke_button__mathjax_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1656px!important;background-size:16px!important}.cke_hidpi .cke_button__maximize_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1680px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__newpage_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__newpage_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1704px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__newpage_icon,.cke_ltr.cke_hidpi .cke_button__newpage_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1728px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__pagebreak_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__pagebreak_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1752px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__pagebreak_icon,.cke_ltr.cke_hidpi .cke_button__pagebreak_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1776px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__pastefromword_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__pastefromword_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1800px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__pastefromword_icon,.cke_ltr.cke_hidpi .cke_button__pastefromword_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1824px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__pastetext_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__pastetext_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1848px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__pastetext_icon,.cke_ltr.cke_hidpi .cke_button__pastetext_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1872px!important;background-size:16px!important}.cke_hidpi .cke_button__placeholder_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1896px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__preview_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__preview_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1920px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__preview_icon,.cke_ltr.cke_hidpi .cke_button__preview_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1944px!important;background-size:16px!important}.cke_hidpi .cke_button__print_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1968px!important;background-size:16px!important}.cke_hidpi .cke_button__removeformat_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1992px!important;background-size:16px!important}.cke_hidpi .cke_button__save_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2016px!important;background-size:16px!important}.cke_hidpi .cke_button__scayt_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2040px!important;background-size:16px!important}.cke_hidpi .cke_button__selectall_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2064px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__showblocks_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__showblocks_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2088px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__showblocks_icon,.cke_ltr.cke_hidpi .cke_button__showblocks_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2112px!important;background-size:16px!important}.cke_hidpi .cke_button__smiley_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2136px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__source_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__source_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2160px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__source_icon,.cke_ltr.cke_hidpi .cke_button__source_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2184px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__sourcedialog_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__sourcedialog_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2208px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__sourcedialog_icon,.cke_ltr.cke_hidpi .cke_button__sourcedialog_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2232px!important;background-size:16px!important}.cke_hidpi .cke_button__specialchar_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2256px!important;background-size:16px!important}.cke_hidpi .cke_button__table_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2280px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__templates_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__templates_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2304px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__templates_icon,.cke_ltr.cke_hidpi .cke_button__templates_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2328px!important;background-size:16px!important}.cke_hidpi .cke_button__uicolor_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2352px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__redo_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__redo_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2376px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__redo_icon,.cke_ltr.cke_hidpi .cke_button__redo_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2400px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__undo_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__undo_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2424px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__undo_icon,.cke_ltr.cke_hidpi .cke_button__undo_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2448px!important;background-size:16px!important}.cke_hidpi .cke_button__simplebox_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -4944px!important}.cke_hidpi .cke_button__spellchecker_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2496px!important;background-size:16px!important}a.cke_button_disabled,a.cke_button_disabled:hover,a.cke_button_disabled:focus,a.cke_button_disabled:active{filter:alpha(opacity = 30)}.cke_button_disabled .cke_button_icon{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#00ffffff,endColorstr=#00ffffff)}.cke_button_off:hover,.cke_button_off:focus,.cke_button_off:active{filter:alpha(opacity = 100)}.cke_combo_disabled .cke_combo_inlinelabel,.cke_combo_disabled .cke_combo_open{filter:alpha(opacity = 30)}.cke_toolbox_collapser{border:1px solid #a6a6a6}.cke_toolbox_collapser .cke_arrow{margin-top:1px}.cke_hc .cke_top,.cke_hc .cke_bottom,.cke_hc .cke_combo_button,.cke_hc a.cke_combo_button:hover,.cke_hc a.cke_combo_button:focus,.cke_hc .cke_toolgroup,.cke_hc .cke_button_on,.cke_hc a.cke_button_off:hover,.cke_hc a.cke_button_off:focus,.cke_hc a.cke_button_off:active,.cke_hc .cke_toolbox_collapser,.cke_hc .cke_toolbox_collapser:hover,.cke_hc .cke_panel_grouptitle{filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/adminlte/bower_components/ckeditor/skins/moono-lisa/editor_ie8.css",
    "content": "/*\nCopyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.\nFor licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n*/\n.cke_reset{margin:0;padding:0;border:0;background:transparent;text-decoration:none;width:auto;height:auto;vertical-align:baseline;box-sizing:content-box;position:static;transition:none}.cke_reset_all,.cke_reset_all *,.cke_reset_all a,.cke_reset_all textarea{margin:0;padding:0;border:0;background:transparent;text-decoration:none;width:auto;height:auto;vertical-align:baseline;box-sizing:content-box;position:static;transition:none;border-collapse:collapse;font:normal normal normal 12px Arial,Helvetica,Tahoma,Verdana,Sans-Serif;color:#000;text-align:left;white-space:nowrap;cursor:auto;float:none}.cke_reset_all .cke_rtl *{text-align:right}.cke_reset_all iframe{vertical-align:inherit}.cke_reset_all textarea{white-space:pre-wrap}.cke_reset_all textarea,.cke_reset_all input[type=\"text\"],.cke_reset_all input[type=\"password\"]{cursor:text}.cke_reset_all textarea[disabled],.cke_reset_all input[type=\"text\"][disabled],.cke_reset_all input[type=\"password\"][disabled]{cursor:default}.cke_reset_all fieldset{padding:10px;border:2px groove #e0dfe3}.cke_reset_all select{box-sizing:border-box}.cke_reset_all table{table-layout:auto}.cke_chrome{display:block;border:1px solid #d1d1d1;padding:0}.cke_inner{display:block;background:#fff;padding:0;-webkit-touch-callout:none}.cke_float{border:0}.cke_float .cke_inner{padding-bottom:0}.cke_top,.cke_contents,.cke_bottom{display:block;overflow:hidden}.cke_top{border-bottom:1px solid #d1d1d1;background:#f8f8f8;padding:6px 8px 2px;white-space:normal}.cke_float .cke_top{border:1px solid #d1d1d1}.cke_bottom{padding:6px 8px 2px;position:relative;border-top:1px solid #d1d1d1;background:#f8f8f8}.cke_browser_ios .cke_contents{overflow-y:auto;-webkit-overflow-scrolling:touch}.cke_resizer{width:0;height:0;overflow:hidden;border-width:10px 10px 0 0;border-color:transparent #bcbcbc transparent transparent;border-style:dashed solid dashed dashed;font-size:0;vertical-align:bottom;margin-top:6px;margin-bottom:2px}.cke_hc .cke_resizer{font-size:15px;width:auto;height:auto;border-width:0}.cke_resizer_ltr{cursor:se-resize;float:right;margin-right:-4px}.cke_resizer_rtl{border-width:10px 0 0 10px;border-color:transparent transparent transparent #bcbcbc;border-style:dashed dashed dashed solid;cursor:sw-resize;float:left;margin-left:-4px;right:auto}.cke_wysiwyg_div{display:block;height:100%;overflow:auto;padding:0 8px;outline-style:none;box-sizing:border-box}.cke_panel{visibility:visible;width:120px;height:100px;overflow:hidden;background-color:#fff;border:1px solid #d1d1d1}.cke_menu_panel{padding:0;margin:0}.cke_combopanel{width:150px;height:170px}.cke_panel_frame{width:100%;height:100%;font-size:12px;overflow:auto;overflow-x:hidden}.cke_panel_container{overflow-y:auto;overflow-x:hidden}.cke_panel_block:focus{outline:0}.cke_panel_list{margin:0;padding:0;list-style-type:none;white-space:nowrap}.cke_panel_listItem{margin:0;padding:0}.cke_panel_listItem a{padding:6px 7px;display:block;color:inherit!important;text-decoration:none;overflow:hidden;text-overflow:ellipsis}.cke_hc .cke_panel_listItem a{border-style:none}.cke_panel_listItem.cke_selected a,.cke_panel_listItem a:hover,.cke_panel_listItem a:focus,.cke_panel_listItem a:active{background-color:#e9e9e9}.cke_panel_listItem a:focus{outline:1px dotted #000}.cke_hc .cke_panel_listItem a:hover,.cke_hc .cke_panel_listItem a:focus,.cke_hc .cke_panel_listItem a:active{border:2px solid;padding:4px 5px}.cke_panel_listItem p,.cke_panel_listItem h1,.cke_panel_listItem h2,.cke_panel_listItem h3,.cke_panel_listItem h4,.cke_panel_listItem h5,.cke_panel_listItem h6,.cke_panel_listItem pre{margin-top:0;margin-bottom:0}.cke_panel_grouptitle{cursor:default;font-size:11px;font-weight:bold;white-space:nowrap;margin:0;padding:6px 6px 7px 6px;color:#484848;border-bottom:1px solid #d1d1d1;background:#f8f8f8}.cke_colorblock{padding:10px;font-size:11px;font-family:'Microsoft Sans Serif',Tahoma,Arial,Verdana,Sans-Serif}.cke_colorblock,.cke_colorblock a{text-decoration:none;color:#000}a.cke_colorbox{padding:2px;float:left;width:20px;height:20px}.cke_rtl a.cke_colorbox{float:right}a:hover.cke_colorbox,a:focus.cke_colorbox,a:active.cke_colorbox{outline:0;padding:0;border:2px solid #139ff7}a:hover.cke_colorbox{border-color:#bcbcbc}span.cke_colorbox{width:20px;height:20px;float:left}.cke_rtl span.cke_colorbox{float:right}a.cke_colorauto,a.cke_colormore{border:#fff 1px solid;padding:3px;display:block;cursor:pointer}a.cke_colorauto{padding:0;border:1px solid transparent;margin-bottom:6px;height:26px;line-height:26px}a.cke_colormore{margin-top:10px;height:20px;line-height:19px}a:hover.cke_colorauto,a:hover.cke_colormore,a:focus.cke_colorauto,a:focus.cke_colormore,a:active.cke_colorauto,a:active.cke_colormore{outline:0;border:#139ff7 1px solid;background-color:#f8f8f8}a:hover.cke_colorauto,a:hover.cke_colormore{border-color:#bcbcbc}.cke_colorauto span.cke_colorbox{width:18px;height:18px;border:1px solid #808080;margin-left:1px;margin-top:3px}.cke_rtl .cke_colorauto span.cke_colorbox{margin-left:0;margin-right:1px}span.cke_colorbox[style*=\"#ffffff\"],span.cke_colorbox[style*=\"#FFFFFF\"],span.cke_colorbox[style=\"background-color:#fff\"],span.cke_colorbox[style=\"background-color:#FFF\"],span.cke_colorbox[style*=\"rgb(255,255,255)\"],span.cke_colorbox[style*=\"rgb(255, 255, 255)\"]{border:1px solid #808080;width:18px;height:18px}.cke_toolbar{float:left}.cke_rtl .cke_toolbar{float:right}.cke_toolgroup{border:0;float:left;margin:1px 2px 6px 0;padding-right:3px}.cke_rtl .cke_toolgroup{float:right;margin:1px 0 6px 2px;padding-left:3px;padding-right:0}.cke_hc .cke_toolgroup{margin-right:5px;margin-bottom:5px}.cke_hc.cke_rtl .cke_toolgroup{margin-right:0;margin-left:5px}a.cke_button{display:inline-block;height:18px;padding:4px 6px;outline:0;cursor:default;float:left;border:0;position:relative}a.cke_button_expandable{padding:4px 5px}.cke_rtl a.cke_button{float:right}.cke_hc a.cke_button{border:1px solid black;padding:3px 5px;margin:0 3px 5px 0}.cke_hc.cke_rtl a.cke_button{margin:0 0 5px 3px}a.cke_button_on{background:#fff;border:1px #bcbcbc solid;padding:3px 5px}a.cke_button_expandable.cke_button_on{padding:3px 4px}a.cke_button_off:hover,a.cke_button_off:focus,a.cke_button_off:active{background:#e5e5e5;border:1px #bcbcbc solid;padding:3px 5px}a.cke_button_expandable.cke_button_off:hover,a.cke_button_expandable.cke_button_off:focus,a.cke_button_expandable.cke_button_off:active{padding:3px 4px}.cke_hc a.cke_button_on,.cke_hc a.cke_button_off:hover,.cke_hc a.cke_button_off:focus,.cke_hc a.cke_button_off:active{background:#e5e5e5;border:3px solid #000;padding:1px 3px}a.cke_button_disabled:hover,a.cke_button_disabled:focus,a.cke_button_disabled:active{border:0;padding:4px 6px;background-color:transparent}a.cke_button_expandable.cke_button_disabled:hover,a.cke_button_expandable.cke_button_disabled:active{padding:4px 5px}a.cke_button_disabled:focus{border:1px #bcbcbc solid;padding:3px 5px}a.cke_button_expandable.cke_button_disabled:focus{padding:3px 4px}.cke_hc a.cke_button_disabled:hover,.cke_hc a.cke_button_disabled:focus,.cke_hc a.cke_button_disabled:active{border:1px solid #acacac;padding:3px 5px;margin:0 3px 5px 0}.cke_hc a.cke_button_disabled:focus{border:3px solid #000;padding:1px 3px}.cke_hc.cke_rtl a.cke_button_disabled:hover,.cke_hc.cke_rtl a.cke_button_disabled:focus,.cke_hc.cke_rtl a.cke_button_disabled:active{margin:0 0 5px 3px}a.cke_button_disabled .cke_button_icon,a.cke_button_disabled .cke_button_arrow{opacity:.3}.cke_hc a.cke_button_disabled{border-color:#acacac}.cke_hc a.cke_button_disabled .cke_button_icon,.cke_hc a.cke_button_disabled .cke_button_label{opacity:.5}.cke_toolgroup a.cke_button:last-child:after,.cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{content:\"\";position:absolute;height:18px;width:0;border-right:1px solid #bcbcbc;margin-top:4px;top:0;right:-3px}.cke_rtl .cke_toolgroup a.cke_button:last-child:after,.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{border-right:0;right:auto;border-left:1px solid #bcbcbc;top:0;left:-3px}.cke_hc .cke_toolgroup a.cke_button:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_disabled:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{border-color:#000;top:0;right:-7px}.cke_hc.cke_rtl .cke_toolgroup a.cke_button:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{top:0;right:auto;left:-7px}.cke_toolgroup a.cke_button:hover:last-child:after,.cke_toolgroup a.cke_button:focus:last-child:after,.cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-1px;right:-4px}.cke_rtl .cke_toolgroup a.cke_button:hover:last-child:after,.cke_rtl .cke_toolgroup a.cke_button:focus:last-child:after,.cke_rtl .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-1px;right:auto;left:-4px}.cke_hc .cke_toolgroup a.cke_button:hover:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-2px;right:-9px}.cke_hc.cke_rtl .cke_toolgroup a.cke_button:hover:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-2px;right:auto;left:-9px}.cke_toolbar.cke_toolbar_last .cke_toolgroup a.cke_button:last-child:after{content:none;border:0;width:0;height:0}.cke_button_icon{cursor:inherit;background-repeat:no-repeat;margin-top:1px;width:16px;height:16px;float:left;display:inline-block}.cke_rtl .cke_button_icon{float:right}.cke_hc .cke_button_icon{display:none}.cke_button_label{display:none;padding-left:3px;margin-top:1px;line-height:17px;vertical-align:middle;float:left;cursor:default;color:#484848}.cke_rtl .cke_button_label{padding-right:3px;padding-left:0;float:right}.cke_hc .cke_button_label{padding:0;display:inline-block;font-size:12px}.cke_button_arrow{display:inline-block;margin:8px 0 0 3px;width:0;height:0;cursor:default;vertical-align:top;border-left:3px solid transparent;border-right:3px solid transparent;border-top:3px solid #484848}.cke_rtl .cke_button_arrow{margin-right:5px;margin-left:0}.cke_hc .cke_button_arrow{font-size:10px;margin:3px 0 0 3px;width:auto;border:0}.cke_toolbar_separator{float:left;background-color:#bcbcbc;margin:4px 2px 0 2px;height:18px;width:1px}.cke_rtl .cke_toolbar_separator{float:right}.cke_hc .cke_toolbar_separator{background-color:#000;margin-left:2px;margin-right:5px;margin-bottom:9px}.cke_hc.cke_rtl .cke_toolbar_separator{margin-left:5px;margin-right:2px}.cke_toolbar_break{display:block;clear:left}.cke_rtl .cke_toolbar_break{clear:right}a.cke_toolbox_collapser{width:12px;height:11px;float:right;margin:11px 0 0;font-size:0;cursor:default;text-align:center;border:1px solid #bcbcbc}.cke_rtl .cke_toolbox_collapser{float:left}.cke_toolbox_collapser:hover{background:#e5e5e5}.cke_toolbox_collapser.cke_toolbox_collapser_min{margin:0 2px 4px}.cke_toolbox_collapser .cke_arrow{display:inline-block;height:0;width:0;font-size:0;margin-top:1px;border:3px solid transparent;border-bottom-color:#484848}.cke_toolbox_collapser.cke_toolbox_collapser_min .cke_arrow{margin-top:4px;border-bottom-color:transparent;border-top-color:#484848}.cke_hc .cke_toolbox_collapser .cke_arrow{font-size:8px;width:auto;border:0;margin-top:0}.cke_menuitem span{cursor:default}.cke_menubutton{display:block}.cke_hc .cke_menubutton{padding:2px}.cke_menubutton:hover,.cke_menubutton:focus,.cke_menubutton:active{background-color:#e9e9e9;display:block;outline:1px dotted}.cke_menubutton:hover{outline:0}.cke_hc .cke_menubutton:hover,.cke_hc .cke_menubutton:focus,.cke_hc .cke_menubutton:active{border:2px solid;padding:0}.cke_menubutton_disabled:hover,.cke_menubutton_disabled:focus,.cke_menubutton_disabled:active{background-color:transparent;outline:0}.cke_menubutton_inner{display:table-row}.cke_menubutton_icon,.cke_menubutton_label,.cke_menuarrow{display:table-cell}.cke_menubutton_icon{background-color:#f8f8f8;padding:6px 4px}.cke_hc .cke_menubutton_icon{height:16px;width:0;padding:4px 0}.cke_menubutton:hover .cke_menubutton_icon,.cke_menubutton:focus .cke_menubutton_icon,.cke_menubutton:active .cke_menubutton_icon{background-color:#e9e9e9}.cke_menubutton_disabled:hover .cke_menubutton_icon,.cke_menubutton_disabled:focus .cke_menubutton_icon,.cke_menubutton_disabled:active .cke_menubutton_icon{background-color:#f8f8f8;outline:0}.cke_menuitem .cke_menubutton_on{background-color:#e9e9e9;border:1px solid #dedede;outline:0}.cke_menubutton_on .cke_menubutton_icon{padding-right:3px;background-color:#e9e9e9}.cke_menubutton_label{padding:0 5px;background-color:transparent;width:100%;vertical-align:middle}.cke_menubutton_shortcut{color:#979797}.cke_menubutton_disabled .cke_menubutton_label{opacity:.3;filter:alpha(opacity=30)}.cke_panel_frame .cke_menubutton_label{display:none}.cke_menuseparator{background-color:#d1d1d1;height:1px}.cke_menuarrow{background:transparent url(images/arrow.png) no-repeat 0 10px;padding:0 5px}.cke_rtl .cke_menuarrow{background-position:5px -13px;background-repeat:no-repeat}.cke_hc .cke_menuarrow{background-image:none}.cke_menuarrow span{display:none}.cke_hc .cke_menuarrow span{vertical-align:middle;display:inline}.cke_combo{display:inline-block;float:left;position:relative;margin-bottom:5px}.cke_rtl .cke_combo{float:right}.cke_hc .cke_combo{margin-top:1px;margin-bottom:10px}.cke_combo:after{content:\"\";position:absolute;height:18px;width:0;border-right:1px solid #bcbcbc;margin-top:5px;top:0;right:0}.cke_rtl .cke_combo:after{border-right:0;border-left:1px solid #bcbcbc;right:auto;left:0}.cke_hc .cke_combo:after{border-color:#000}a.cke_combo_button{cursor:default;display:inline-block;float:left;margin:0;padding:1px}.cke_rtl a.cke_combo_button{float:right}.cke_hc a.cke_combo_button{padding:4px}.cke_combo_on a.cke_combo_button,.cke_combo_off a.cke_combo_button:hover,.cke_combo_off a.cke_combo_button:focus,.cke_combo_off a.cke_combo_button:active{background:#e5e5e5;border:1px solid #bcbcbc;padding:0 0 0 1px;margin-left:-1px}.cke_combo_off a.cke_combo_button:focus{outline:0}.cke_combo_on a.cke_combo_button,.cke_combo_off a.cke_combo_button:active{background:#fff}.cke_rtl .cke_combo_on a.cke_combo_button,.cke_rtl .cke_combo_off a.cke_combo_button:hover,.cke_rtl .cke_combo_off a.cke_combo_button:focus,.cke_rtl .cke_combo_off a.cke_combo_button:active{padding:0 1px 0 0;margin-left:0;margin-right:-1px}.cke_hc .cke_combo_on a.cke_combo_button,.cke_hc .cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_combo_off a.cke_combo_button:active{border:3px solid #000;padding:1px 1px 1px 2px}.cke_hc.cke_rtl .cke_combo_on a.cke_combo_button,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:hover,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:focus,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:active{padding:1px 2px 1px 1px}.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0 0 0 3px;margin-left:-3px}.cke_rtl .cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0 3px 0 0;margin-left:0;margin-right:-3px}.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px 1px 1px 7px;margin-left:-6px}.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px 7px 1px 1px;margin-left:0;margin-right:-6px}.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0;margin:0}.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px;margin:0}.cke_toolbar .cke_combo+.cke_toolbar_end,.cke_toolbar .cke_combo+.cke_toolgroup{margin-right:0;margin-left:2px}.cke_rtl .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_rtl .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:0;margin-right:2px}.cke_hc .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_hc .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:5px}.cke_hc.cke_rtl .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_hc.cke_rtl .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:0;margin-right:5px}.cke_toolbar.cke_toolbar_last .cke_combo:nth-last-child(-n+2):after{content:none;border:0;width:0;height:0}.cke_combo_text{line-height:26px;padding-left:10px;text-overflow:ellipsis;overflow:hidden;float:left;cursor:default;color:#484848;width:60px}.cke_rtl .cke_combo_text{float:right;text-align:right;padding-left:0;padding-right:10px}.cke_hc .cke_combo_text{line-height:18px;font-size:12px}.cke_combo_open{cursor:default;display:inline-block;font-size:0;height:19px;line-height:17px;margin:1px 10px 1px;width:5px}.cke_hc .cke_combo_open{height:12px}.cke_combo_arrow{cursor:default;margin:11px 0 0;float:left;height:0;width:0;font-size:0;border-left:3px solid transparent;border-right:3px solid transparent;border-top:3px solid #484848}.cke_hc .cke_combo_arrow{font-size:10px;width:auto;border:0;margin-top:3px}.cke_combo_label{display:none;float:left;line-height:26px;vertical-align:top;margin-right:5px}.cke_rtl .cke_combo_label{float:right;margin-left:5px;margin-right:0}.cke_combo_disabled .cke_combo_inlinelabel,.cke_combo_disabled .cke_combo_open{opacity:.3}.cke_path{float:left;margin:-2px 0 2px}a.cke_path_item,span.cke_path_empty{display:inline-block;float:left;padding:3px 4px;margin-right:2px;cursor:default;text-decoration:none;outline:0;border:0;color:#484848;font-weight:bold;font-size:11px}.cke_rtl .cke_path,.cke_rtl .cke_path_item,.cke_rtl .cke_path_empty{float:right}a.cke_path_item:hover,a.cke_path_item:focus,a.cke_path_item:active{background-color:#e5e5e5}.cke_hc a.cke_path_item:hover,.cke_hc a.cke_path_item:focus,.cke_hc a.cke_path_item:active{border:2px solid;padding:1px 2px}.cke_button__source_label,.cke_button__sourcedialog_label{display:inline}.cke_combopanel__fontsize{width:135px}textarea.cke_source{font-family:'Courier New',Monospace;font-size:small;background-color:#fff;white-space:pre-wrap;border:0;padding:0;margin:0;display:block}.cke_wysiwyg_frame,.cke_wysiwyg_div{background-color:#fff}.cke_notifications_area{pointer-events:none}.cke_notification{pointer-events:auto;position:relative;margin:10px;width:300px;color:white;text-align:center;opacity:.95;filter:alpha(opacity = 95);-webkit-animation:fadeIn .7s;animation:fadeIn .7s}.cke_notification_message a{color:#12306f}@-webkit-keyframes fadeIn{from{opacity:.4}to{opacity:.95}}@keyframes fadeIn{from{opacity:.4}to{opacity:.95}}.cke_notification_success{background:#72b572;border:1px solid #63a563}.cke_notification_warning{background:#c83939;border:1px solid #902b2b}.cke_notification_info{background:#2e9ad0;border:1px solid #0f74a8}.cke_notification_info span.cke_notification_progress{background-color:#0f74a8;display:block;padding:0;margin:0;height:100%;overflow:hidden;position:absolute;z-index:1}.cke_notification_message{position:relative;margin:4px 23px 3px;font-family:Arial,Helvetica,sans-serif;font-size:12px;line-height:18px;z-index:4;text-overflow:ellipsis;overflow:hidden}.cke_notification_close{background-image:url(images/close.png);background-repeat:no-repeat;background-position:50%;position:absolute;cursor:pointer;text-align:center;height:20px;width:20px;top:1px;right:1px;padding:0;margin:0;z-index:5;opacity:.6;filter:alpha(opacity = 60)}.cke_notification_close:hover{opacity:1;filter:alpha(opacity = 100)}.cke_notification_close span{display:none}.cke_notification_warning a.cke_notification_close{opacity:.8;filter:alpha(opacity = 80)}.cke_notification_warning a.cke_notification_close:hover{opacity:1;filter:alpha(opacity = 100)}.cke_chrome{visibility:inherit}.cke_voice_label{display:none}legend.cke_voice_label{display:none}.cke_button__about_icon{background:url(icons.png?t=J5S9) no-repeat 0 -0px!important}.cke_button__bold_icon{background:url(icons.png?t=J5S9) no-repeat 0 -24px!important}.cke_button__italic_icon{background:url(icons.png?t=J5S9) no-repeat 0 -48px!important}.cke_button__strike_icon{background:url(icons.png?t=J5S9) no-repeat 0 -72px!important}.cke_button__subscript_icon{background:url(icons.png?t=J5S9) no-repeat 0 -96px!important}.cke_button__superscript_icon{background:url(icons.png?t=J5S9) no-repeat 0 -120px!important}.cke_button__underline_icon{background:url(icons.png?t=J5S9) no-repeat 0 -144px!important}.cke_button__bidiltr_icon{background:url(icons.png?t=J5S9) no-repeat 0 -168px!important}.cke_button__bidirtl_icon{background:url(icons.png?t=J5S9) no-repeat 0 -192px!important}.cke_button__blockquote_icon{background:url(icons.png?t=J5S9) no-repeat 0 -216px!important}.cke_rtl .cke_button__copy_icon,.cke_mixed_dir_content .cke_rtl .cke_button__copy_icon{background:url(icons.png?t=J5S9) no-repeat 0 -240px!important}.cke_ltr .cke_button__copy_icon{background:url(icons.png?t=J5S9) no-repeat 0 -264px!important}.cke_rtl .cke_button__cut_icon,.cke_mixed_dir_content .cke_rtl .cke_button__cut_icon{background:url(icons.png?t=J5S9) no-repeat 0 -288px!important}.cke_ltr .cke_button__cut_icon{background:url(icons.png?t=J5S9) no-repeat 0 -312px!important}.cke_rtl .cke_button__paste_icon,.cke_mixed_dir_content .cke_rtl .cke_button__paste_icon{background:url(icons.png?t=J5S9) no-repeat 0 -336px!important}.cke_ltr .cke_button__paste_icon{background:url(icons.png?t=J5S9) no-repeat 0 -360px!important}.cke_button__codesnippet_icon{background:url(icons.png?t=J5S9) no-repeat 0 -384px!important}.cke_button__bgcolor_icon{background:url(icons.png?t=J5S9) no-repeat 0 -408px!important}.cke_button__textcolor_icon{background:url(icons.png?t=J5S9) no-repeat 0 -432px!important}.cke_button__copyformatting_icon{background:url(icons.png?t=J5S9) no-repeat 0 -456px!important}.cke_button__creatediv_icon{background:url(icons.png?t=J5S9) no-repeat 0 -480px!important}.cke_rtl .cke_button__docprops_icon,.cke_mixed_dir_content .cke_rtl .cke_button__docprops_icon{background:url(icons.png?t=J5S9) no-repeat 0 -504px!important}.cke_ltr .cke_button__docprops_icon{background:url(icons.png?t=J5S9) no-repeat 0 -528px!important}.cke_button__easyimagealigncenter_icon{background:url(icons.png?t=J5S9) no-repeat 0 -552px!important}.cke_button__easyimagealignleft_icon{background:url(icons.png?t=J5S9) no-repeat 0 -576px!important}.cke_button__easyimagealignright_icon{background:url(icons.png?t=J5S9) no-repeat 0 -600px!important}.cke_button__easyimagealt_icon{background:url(icons.png?t=J5S9) no-repeat 0 -624px!important}.cke_button__easyimagefull_icon{background:url(icons.png?t=J5S9) no-repeat 0 -648px!important}.cke_button__easyimageside_icon{background:url(icons.png?t=J5S9) no-repeat 0 -672px!important}.cke_button__easyimageupload_icon{background:url(icons.png?t=J5S9) no-repeat 0 -696px!important}.cke_button__embed_icon{background:url(icons.png?t=J5S9) no-repeat 0 -720px!important}.cke_button__embedsemantic_icon{background:url(icons.png?t=J5S9) no-repeat 0 -744px!important}.cke_button__emojipanel_icon{background:url(icons.png?t=J5S9) no-repeat 0 -768px!important}.cke_rtl .cke_button__find_icon,.cke_mixed_dir_content .cke_rtl .cke_button__find_icon{background:url(icons.png?t=J5S9) no-repeat 0 -792px!important}.cke_ltr .cke_button__find_icon{background:url(icons.png?t=J5S9) no-repeat 0 -816px!important}.cke_button__replace_icon{background:url(icons.png?t=J5S9) no-repeat 0 -840px!important}.cke_button__flash_icon{background:url(icons.png?t=J5S9) no-repeat 0 -864px!important}.cke_button__button_icon{background:url(icons.png?t=J5S9) no-repeat 0 -888px!important}.cke_button__checkbox_icon{background:url(icons.png?t=J5S9) no-repeat 0 -912px!important}.cke_button__form_icon{background:url(icons.png?t=J5S9) no-repeat 0 -936px!important}.cke_button__hiddenfield_icon{background:url(icons.png?t=J5S9) no-repeat 0 -960px!important}.cke_button__imagebutton_icon{background:url(icons.png?t=J5S9) no-repeat 0 -984px!important}.cke_button__radio_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1008px!important}.cke_rtl .cke_button__select_icon,.cke_mixed_dir_content .cke_rtl .cke_button__select_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1032px!important}.cke_ltr .cke_button__select_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1056px!important}.cke_rtl .cke_button__textarea_icon,.cke_mixed_dir_content .cke_rtl .cke_button__textarea_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1080px!important}.cke_ltr .cke_button__textarea_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1104px!important}.cke_rtl .cke_button__textfield_icon,.cke_mixed_dir_content .cke_rtl .cke_button__textfield_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1128px!important}.cke_ltr .cke_button__textfield_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1152px!important}.cke_button__horizontalrule_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1176px!important}.cke_button__iframe_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1200px!important}.cke_button__image_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1224px!important}.cke_rtl .cke_button__indent_icon,.cke_mixed_dir_content .cke_rtl .cke_button__indent_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1248px!important}.cke_ltr .cke_button__indent_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1272px!important}.cke_rtl .cke_button__outdent_icon,.cke_mixed_dir_content .cke_rtl .cke_button__outdent_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1296px!important}.cke_ltr .cke_button__outdent_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1320px!important}.cke_button__justifyblock_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1344px!important}.cke_button__justifycenter_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1368px!important}.cke_button__justifyleft_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1392px!important}.cke_button__justifyright_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1416px!important}.cke_button__language_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1440px!important}.cke_rtl .cke_button__anchor_icon,.cke_mixed_dir_content .cke_rtl .cke_button__anchor_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1464px!important}.cke_ltr .cke_button__anchor_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1488px!important}.cke_button__link_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1512px!important}.cke_button__unlink_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1536px!important}.cke_rtl .cke_button__bulletedlist_icon,.cke_mixed_dir_content .cke_rtl .cke_button__bulletedlist_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1560px!important}.cke_ltr .cke_button__bulletedlist_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1584px!important}.cke_rtl .cke_button__numberedlist_icon,.cke_mixed_dir_content .cke_rtl .cke_button__numberedlist_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1608px!important}.cke_ltr .cke_button__numberedlist_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1632px!important}.cke_button__mathjax_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1656px!important}.cke_button__maximize_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1680px!important}.cke_rtl .cke_button__newpage_icon,.cke_mixed_dir_content .cke_rtl .cke_button__newpage_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1704px!important}.cke_ltr .cke_button__newpage_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1728px!important}.cke_rtl .cke_button__pagebreak_icon,.cke_mixed_dir_content .cke_rtl .cke_button__pagebreak_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1752px!important}.cke_ltr .cke_button__pagebreak_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1776px!important}.cke_rtl .cke_button__pastefromword_icon,.cke_mixed_dir_content .cke_rtl .cke_button__pastefromword_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1800px!important}.cke_ltr .cke_button__pastefromword_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1824px!important}.cke_rtl .cke_button__pastetext_icon,.cke_mixed_dir_content .cke_rtl .cke_button__pastetext_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1848px!important}.cke_ltr .cke_button__pastetext_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1872px!important}.cke_button__placeholder_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1896px!important}.cke_rtl .cke_button__preview_icon,.cke_mixed_dir_content .cke_rtl .cke_button__preview_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1920px!important}.cke_ltr .cke_button__preview_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1944px!important}.cke_button__print_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1968px!important}.cke_button__removeformat_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1992px!important}.cke_button__save_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2016px!important}.cke_button__scayt_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2040px!important}.cke_button__selectall_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2064px!important}.cke_rtl .cke_button__showblocks_icon,.cke_mixed_dir_content .cke_rtl .cke_button__showblocks_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2088px!important}.cke_ltr .cke_button__showblocks_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2112px!important}.cke_button__smiley_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2136px!important}.cke_rtl .cke_button__source_icon,.cke_mixed_dir_content .cke_rtl .cke_button__source_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2160px!important}.cke_ltr .cke_button__source_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2184px!important}.cke_rtl .cke_button__sourcedialog_icon,.cke_mixed_dir_content .cke_rtl .cke_button__sourcedialog_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2208px!important}.cke_ltr .cke_button__sourcedialog_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2232px!important}.cke_button__specialchar_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2256px!important}.cke_button__table_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2280px!important}.cke_rtl .cke_button__templates_icon,.cke_mixed_dir_content .cke_rtl .cke_button__templates_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2304px!important}.cke_ltr .cke_button__templates_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2328px!important}.cke_button__uicolor_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2352px!important}.cke_rtl .cke_button__redo_icon,.cke_mixed_dir_content .cke_rtl .cke_button__redo_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2376px!important}.cke_ltr .cke_button__redo_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2400px!important}.cke_rtl .cke_button__undo_icon,.cke_mixed_dir_content .cke_rtl .cke_button__undo_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2424px!important}.cke_ltr .cke_button__undo_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2448px!important}.cke_button__simplebox_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2472px!important}.cke_button__spellchecker_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2496px!important}.cke_hidpi .cke_button__about_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -0px!important;background-size:16px!important}.cke_hidpi .cke_button__bold_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -24px!important;background-size:16px!important}.cke_hidpi .cke_button__italic_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -48px!important;background-size:16px!important}.cke_hidpi .cke_button__strike_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -72px!important;background-size:16px!important}.cke_hidpi .cke_button__subscript_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -96px!important;background-size:16px!important}.cke_hidpi .cke_button__superscript_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -120px!important;background-size:16px!important}.cke_hidpi .cke_button__underline_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -144px!important;background-size:16px!important}.cke_hidpi .cke_button__bidiltr_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -168px!important;background-size:16px!important}.cke_hidpi .cke_button__bidirtl_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -192px!important;background-size:16px!important}.cke_hidpi .cke_button__blockquote_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -216px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__copy_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__copy_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -240px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__copy_icon,.cke_ltr.cke_hidpi .cke_button__copy_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -264px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__cut_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__cut_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -288px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__cut_icon,.cke_ltr.cke_hidpi .cke_button__cut_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -312px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__paste_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__paste_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -336px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__paste_icon,.cke_ltr.cke_hidpi .cke_button__paste_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -360px!important;background-size:16px!important}.cke_hidpi .cke_button__codesnippet_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -384px!important;background-size:16px!important}.cke_hidpi .cke_button__bgcolor_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -408px!important;background-size:16px!important}.cke_hidpi .cke_button__textcolor_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -432px!important;background-size:16px!important}.cke_hidpi .cke_button__copyformatting_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -456px!important;background-size:16px!important}.cke_hidpi .cke_button__creatediv_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -480px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__docprops_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__docprops_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -504px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__docprops_icon,.cke_ltr.cke_hidpi .cke_button__docprops_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -528px!important;background-size:16px!important}.cke_hidpi .cke_button__easyimagealigncenter_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -552px!important;background-size:16px!important}.cke_hidpi .cke_button__easyimagealignleft_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -576px!important;background-size:16px!important}.cke_hidpi .cke_button__easyimagealignright_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -600px!important;background-size:16px!important}.cke_hidpi .cke_button__easyimagealt_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -624px!important;background-size:16px!important}.cke_hidpi .cke_button__easyimagefull_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -648px!important;background-size:16px!important}.cke_hidpi .cke_button__easyimageside_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -672px!important;background-size:16px!important}.cke_hidpi .cke_button__easyimageupload_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -696px!important;background-size:16px!important}.cke_hidpi .cke_button__embed_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -720px!important;background-size:16px!important}.cke_hidpi .cke_button__embedsemantic_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -744px!important;background-size:16px!important}.cke_hidpi .cke_button__emojipanel_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -768px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__find_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__find_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -792px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__find_icon,.cke_ltr.cke_hidpi .cke_button__find_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -816px!important;background-size:16px!important}.cke_hidpi .cke_button__replace_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -840px!important;background-size:16px!important}.cke_hidpi .cke_button__flash_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -864px!important;background-size:16px!important}.cke_hidpi .cke_button__button_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -888px!important;background-size:16px!important}.cke_hidpi .cke_button__checkbox_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -912px!important;background-size:16px!important}.cke_hidpi .cke_button__form_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -936px!important;background-size:16px!important}.cke_hidpi .cke_button__hiddenfield_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -960px!important;background-size:16px!important}.cke_hidpi .cke_button__imagebutton_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -984px!important;background-size:16px!important}.cke_hidpi .cke_button__radio_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1008px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__select_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__select_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1032px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__select_icon,.cke_ltr.cke_hidpi .cke_button__select_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1056px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__textarea_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__textarea_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1080px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__textarea_icon,.cke_ltr.cke_hidpi .cke_button__textarea_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1104px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__textfield_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__textfield_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1128px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__textfield_icon,.cke_ltr.cke_hidpi .cke_button__textfield_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1152px!important;background-size:16px!important}.cke_hidpi .cke_button__horizontalrule_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1176px!important;background-size:16px!important}.cke_hidpi .cke_button__iframe_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1200px!important;background-size:16px!important}.cke_hidpi .cke_button__image_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1224px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__indent_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__indent_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1248px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__indent_icon,.cke_ltr.cke_hidpi .cke_button__indent_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1272px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__outdent_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__outdent_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1296px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__outdent_icon,.cke_ltr.cke_hidpi .cke_button__outdent_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1320px!important;background-size:16px!important}.cke_hidpi .cke_button__justifyblock_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1344px!important;background-size:16px!important}.cke_hidpi .cke_button__justifycenter_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1368px!important;background-size:16px!important}.cke_hidpi .cke_button__justifyleft_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1392px!important;background-size:16px!important}.cke_hidpi .cke_button__justifyright_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1416px!important;background-size:16px!important}.cke_hidpi .cke_button__language_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1440px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__anchor_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__anchor_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1464px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__anchor_icon,.cke_ltr.cke_hidpi .cke_button__anchor_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1488px!important;background-size:16px!important}.cke_hidpi .cke_button__link_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1512px!important;background-size:16px!important}.cke_hidpi .cke_button__unlink_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1536px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__bulletedlist_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__bulletedlist_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1560px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__bulletedlist_icon,.cke_ltr.cke_hidpi .cke_button__bulletedlist_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1584px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__numberedlist_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__numberedlist_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1608px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__numberedlist_icon,.cke_ltr.cke_hidpi .cke_button__numberedlist_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1632px!important;background-size:16px!important}.cke_hidpi .cke_button__mathjax_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1656px!important;background-size:16px!important}.cke_hidpi .cke_button__maximize_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1680px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__newpage_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__newpage_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1704px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__newpage_icon,.cke_ltr.cke_hidpi .cke_button__newpage_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1728px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__pagebreak_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__pagebreak_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1752px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__pagebreak_icon,.cke_ltr.cke_hidpi .cke_button__pagebreak_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1776px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__pastefromword_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__pastefromword_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1800px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__pastefromword_icon,.cke_ltr.cke_hidpi .cke_button__pastefromword_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1824px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__pastetext_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__pastetext_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1848px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__pastetext_icon,.cke_ltr.cke_hidpi .cke_button__pastetext_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1872px!important;background-size:16px!important}.cke_hidpi .cke_button__placeholder_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1896px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__preview_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__preview_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1920px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__preview_icon,.cke_ltr.cke_hidpi .cke_button__preview_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1944px!important;background-size:16px!important}.cke_hidpi .cke_button__print_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1968px!important;background-size:16px!important}.cke_hidpi .cke_button__removeformat_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1992px!important;background-size:16px!important}.cke_hidpi .cke_button__save_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2016px!important;background-size:16px!important}.cke_hidpi .cke_button__scayt_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2040px!important;background-size:16px!important}.cke_hidpi .cke_button__selectall_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2064px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__showblocks_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__showblocks_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2088px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__showblocks_icon,.cke_ltr.cke_hidpi .cke_button__showblocks_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2112px!important;background-size:16px!important}.cke_hidpi .cke_button__smiley_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2136px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__source_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__source_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2160px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__source_icon,.cke_ltr.cke_hidpi .cke_button__source_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2184px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__sourcedialog_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__sourcedialog_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2208px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__sourcedialog_icon,.cke_ltr.cke_hidpi .cke_button__sourcedialog_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2232px!important;background-size:16px!important}.cke_hidpi .cke_button__specialchar_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2256px!important;background-size:16px!important}.cke_hidpi .cke_button__table_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2280px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__templates_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__templates_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2304px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__templates_icon,.cke_ltr.cke_hidpi .cke_button__templates_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2328px!important;background-size:16px!important}.cke_hidpi .cke_button__uicolor_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2352px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__redo_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__redo_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2376px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__redo_icon,.cke_ltr.cke_hidpi .cke_button__redo_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2400px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__undo_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__undo_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2424px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__undo_icon,.cke_ltr.cke_hidpi .cke_button__undo_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2448px!important;background-size:16px!important}.cke_hidpi .cke_button__simplebox_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -4944px!important}.cke_hidpi .cke_button__spellchecker_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2496px!important;background-size:16px!important}a.cke_button_disabled,a.cke_button_disabled:hover,a.cke_button_disabled:focus,a.cke_button_disabled:active{filter:alpha(opacity = 30)}.cke_button_disabled .cke_button_icon{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#00ffffff,endColorstr=#00ffffff)}.cke_button_off:hover,.cke_button_off:focus,.cke_button_off:active{filter:alpha(opacity = 100)}.cke_combo_disabled .cke_combo_inlinelabel,.cke_combo_disabled .cke_combo_open{filter:alpha(opacity = 30)}.cke_toolbox_collapser{border:1px solid #a6a6a6}.cke_toolbox_collapser .cke_arrow{margin-top:1px}.cke_hc .cke_top,.cke_hc .cke_bottom,.cke_hc .cke_combo_button,.cke_hc a.cke_combo_button:hover,.cke_hc a.cke_combo_button:focus,.cke_hc .cke_toolgroup,.cke_hc .cke_button_on,.cke_hc a.cke_button_off:hover,.cke_hc a.cke_button_off:focus,.cke_hc a.cke_button_off:active,.cke_hc .cke_toolbox_collapser,.cke_hc .cke_toolbox_collapser:hover,.cke_hc .cke_panel_grouptitle{filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.cke_toolbox_collapser .cke_arrow{border-width:4px}.cke_toolbox_collapser.cke_toolbox_collapser_min .cke_arrow{border-width:3px}.cke_toolbox_collapser .cke_arrow{margin-top:0}.cke_toolbar{position:relative}.cke_rtl .cke_toolbar_end{right:auto;left:0}.cke_toolbar_end:after{content:\"\";position:absolute;height:18px;width:0;border-right:1px solid #bcbcbc;margin-top:4px;top:1px;right:2px}.cke_rtl .cke_toolbar_end:after{right:auto;left:2px}.cke_hc .cke_toolbar_end:after{top:2px;right:5px;border-color:#000}.cke_hc.cke_rtl .cke_toolbar_end:after{right:auto;left:5px}.cke_combo+.cke_toolbar_end:after,.cke_toolbar.cke_toolbar_last .cke_toolbar_end:after{content:none;border:0}.cke_combo+.cke_toolgroup+.cke_toolbar_end:after{right:0}.cke_rtl .cke_combo+.cke_toolgroup+.cke_toolbar_end:after{right:auto;left:0}"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/adminlte/bower_components/ckeditor/skins/moono-lisa/editor_iequirks.css",
    "content": "/*\nCopyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.\nFor licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n*/\n.cke_reset{margin:0;padding:0;border:0;background:transparent;text-decoration:none;width:auto;height:auto;vertical-align:baseline;box-sizing:content-box;position:static;transition:none}.cke_reset_all,.cke_reset_all *,.cke_reset_all a,.cke_reset_all textarea{margin:0;padding:0;border:0;background:transparent;text-decoration:none;width:auto;height:auto;vertical-align:baseline;box-sizing:content-box;position:static;transition:none;border-collapse:collapse;font:normal normal normal 12px Arial,Helvetica,Tahoma,Verdana,Sans-Serif;color:#000;text-align:left;white-space:nowrap;cursor:auto;float:none}.cke_reset_all .cke_rtl *{text-align:right}.cke_reset_all iframe{vertical-align:inherit}.cke_reset_all textarea{white-space:pre-wrap}.cke_reset_all textarea,.cke_reset_all input[type=\"text\"],.cke_reset_all input[type=\"password\"]{cursor:text}.cke_reset_all textarea[disabled],.cke_reset_all input[type=\"text\"][disabled],.cke_reset_all input[type=\"password\"][disabled]{cursor:default}.cke_reset_all fieldset{padding:10px;border:2px groove #e0dfe3}.cke_reset_all select{box-sizing:border-box}.cke_reset_all table{table-layout:auto}.cke_chrome{display:block;border:1px solid #d1d1d1;padding:0}.cke_inner{display:block;background:#fff;padding:0;-webkit-touch-callout:none}.cke_float{border:0}.cke_float .cke_inner{padding-bottom:0}.cke_top,.cke_contents,.cke_bottom{display:block;overflow:hidden}.cke_top{border-bottom:1px solid #d1d1d1;background:#f8f8f8;padding:6px 8px 2px;white-space:normal}.cke_float .cke_top{border:1px solid #d1d1d1}.cke_bottom{padding:6px 8px 2px;position:relative;border-top:1px solid #d1d1d1;background:#f8f8f8}.cke_browser_ios .cke_contents{overflow-y:auto;-webkit-overflow-scrolling:touch}.cke_resizer{width:0;height:0;overflow:hidden;border-width:10px 10px 0 0;border-color:transparent #bcbcbc transparent transparent;border-style:dashed solid dashed dashed;font-size:0;vertical-align:bottom;margin-top:6px;margin-bottom:2px}.cke_hc .cke_resizer{font-size:15px;width:auto;height:auto;border-width:0}.cke_resizer_ltr{cursor:se-resize;float:right;margin-right:-4px}.cke_resizer_rtl{border-width:10px 0 0 10px;border-color:transparent transparent transparent #bcbcbc;border-style:dashed dashed dashed solid;cursor:sw-resize;float:left;margin-left:-4px;right:auto}.cke_wysiwyg_div{display:block;height:100%;overflow:auto;padding:0 8px;outline-style:none;box-sizing:border-box}.cke_panel{visibility:visible;width:120px;height:100px;overflow:hidden;background-color:#fff;border:1px solid #d1d1d1}.cke_menu_panel{padding:0;margin:0}.cke_combopanel{width:150px;height:170px}.cke_panel_frame{width:100%;height:100%;font-size:12px;overflow:auto;overflow-x:hidden}.cke_panel_container{overflow-y:auto;overflow-x:hidden}.cke_panel_block:focus{outline:0}.cke_panel_list{margin:0;padding:0;list-style-type:none;white-space:nowrap}.cke_panel_listItem{margin:0;padding:0}.cke_panel_listItem a{padding:6px 7px;display:block;color:inherit!important;text-decoration:none;overflow:hidden;text-overflow:ellipsis}.cke_hc .cke_panel_listItem a{border-style:none}.cke_panel_listItem.cke_selected a,.cke_panel_listItem a:hover,.cke_panel_listItem a:focus,.cke_panel_listItem a:active{background-color:#e9e9e9}.cke_panel_listItem a:focus{outline:1px dotted #000}.cke_hc .cke_panel_listItem a:hover,.cke_hc .cke_panel_listItem a:focus,.cke_hc .cke_panel_listItem a:active{border:2px solid;padding:4px 5px}.cke_panel_listItem p,.cke_panel_listItem h1,.cke_panel_listItem h2,.cke_panel_listItem h3,.cke_panel_listItem h4,.cke_panel_listItem h5,.cke_panel_listItem h6,.cke_panel_listItem pre{margin-top:0;margin-bottom:0}.cke_panel_grouptitle{cursor:default;font-size:11px;font-weight:bold;white-space:nowrap;margin:0;padding:6px 6px 7px 6px;color:#484848;border-bottom:1px solid #d1d1d1;background:#f8f8f8}.cke_colorblock{padding:10px;font-size:11px;font-family:'Microsoft Sans Serif',Tahoma,Arial,Verdana,Sans-Serif}.cke_colorblock,.cke_colorblock a{text-decoration:none;color:#000}a.cke_colorbox{padding:2px;float:left;width:20px;height:20px}.cke_rtl a.cke_colorbox{float:right}a:hover.cke_colorbox,a:focus.cke_colorbox,a:active.cke_colorbox{outline:0;padding:0;border:2px solid #139ff7}a:hover.cke_colorbox{border-color:#bcbcbc}span.cke_colorbox{width:20px;height:20px;float:left}.cke_rtl span.cke_colorbox{float:right}a.cke_colorauto,a.cke_colormore{border:#fff 1px solid;padding:3px;display:block;cursor:pointer}a.cke_colorauto{padding:0;border:1px solid transparent;margin-bottom:6px;height:26px;line-height:26px}a.cke_colormore{margin-top:10px;height:20px;line-height:19px}a:hover.cke_colorauto,a:hover.cke_colormore,a:focus.cke_colorauto,a:focus.cke_colormore,a:active.cke_colorauto,a:active.cke_colormore{outline:0;border:#139ff7 1px solid;background-color:#f8f8f8}a:hover.cke_colorauto,a:hover.cke_colormore{border-color:#bcbcbc}.cke_colorauto span.cke_colorbox{width:18px;height:18px;border:1px solid #808080;margin-left:1px;margin-top:3px}.cke_rtl .cke_colorauto span.cke_colorbox{margin-left:0;margin-right:1px}span.cke_colorbox[style*=\"#ffffff\"],span.cke_colorbox[style*=\"#FFFFFF\"],span.cke_colorbox[style=\"background-color:#fff\"],span.cke_colorbox[style=\"background-color:#FFF\"],span.cke_colorbox[style*=\"rgb(255,255,255)\"],span.cke_colorbox[style*=\"rgb(255, 255, 255)\"]{border:1px solid #808080;width:18px;height:18px}.cke_toolbar{float:left}.cke_rtl .cke_toolbar{float:right}.cke_toolgroup{border:0;float:left;margin:1px 2px 6px 0;padding-right:3px}.cke_rtl .cke_toolgroup{float:right;margin:1px 0 6px 2px;padding-left:3px;padding-right:0}.cke_hc .cke_toolgroup{margin-right:5px;margin-bottom:5px}.cke_hc.cke_rtl .cke_toolgroup{margin-right:0;margin-left:5px}a.cke_button{display:inline-block;height:18px;padding:4px 6px;outline:0;cursor:default;float:left;border:0;position:relative}a.cke_button_expandable{padding:4px 5px}.cke_rtl a.cke_button{float:right}.cke_hc a.cke_button{border:1px solid black;padding:3px 5px;margin:0 3px 5px 0}.cke_hc.cke_rtl a.cke_button{margin:0 0 5px 3px}a.cke_button_on{background:#fff;border:1px #bcbcbc solid;padding:3px 5px}a.cke_button_expandable.cke_button_on{padding:3px 4px}a.cke_button_off:hover,a.cke_button_off:focus,a.cke_button_off:active{background:#e5e5e5;border:1px #bcbcbc solid;padding:3px 5px}a.cke_button_expandable.cke_button_off:hover,a.cke_button_expandable.cke_button_off:focus,a.cke_button_expandable.cke_button_off:active{padding:3px 4px}.cke_hc a.cke_button_on,.cke_hc a.cke_button_off:hover,.cke_hc a.cke_button_off:focus,.cke_hc a.cke_button_off:active{background:#e5e5e5;border:3px solid #000;padding:1px 3px}a.cke_button_disabled:hover,a.cke_button_disabled:focus,a.cke_button_disabled:active{border:0;padding:4px 6px;background-color:transparent}a.cke_button_expandable.cke_button_disabled:hover,a.cke_button_expandable.cke_button_disabled:active{padding:4px 5px}a.cke_button_disabled:focus{border:1px #bcbcbc solid;padding:3px 5px}a.cke_button_expandable.cke_button_disabled:focus{padding:3px 4px}.cke_hc a.cke_button_disabled:hover,.cke_hc a.cke_button_disabled:focus,.cke_hc a.cke_button_disabled:active{border:1px solid #acacac;padding:3px 5px;margin:0 3px 5px 0}.cke_hc a.cke_button_disabled:focus{border:3px solid #000;padding:1px 3px}.cke_hc.cke_rtl a.cke_button_disabled:hover,.cke_hc.cke_rtl a.cke_button_disabled:focus,.cke_hc.cke_rtl a.cke_button_disabled:active{margin:0 0 5px 3px}a.cke_button_disabled .cke_button_icon,a.cke_button_disabled .cke_button_arrow{opacity:.3}.cke_hc a.cke_button_disabled{border-color:#acacac}.cke_hc a.cke_button_disabled .cke_button_icon,.cke_hc a.cke_button_disabled .cke_button_label{opacity:.5}.cke_toolgroup a.cke_button:last-child:after,.cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{content:\"\";position:absolute;height:18px;width:0;border-right:1px solid #bcbcbc;margin-top:4px;top:0;right:-3px}.cke_rtl .cke_toolgroup a.cke_button:last-child:after,.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{border-right:0;right:auto;border-left:1px solid #bcbcbc;top:0;left:-3px}.cke_hc .cke_toolgroup a.cke_button:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_disabled:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{border-color:#000;top:0;right:-7px}.cke_hc.cke_rtl .cke_toolgroup a.cke_button:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{top:0;right:auto;left:-7px}.cke_toolgroup a.cke_button:hover:last-child:after,.cke_toolgroup a.cke_button:focus:last-child:after,.cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-1px;right:-4px}.cke_rtl .cke_toolgroup a.cke_button:hover:last-child:after,.cke_rtl .cke_toolgroup a.cke_button:focus:last-child:after,.cke_rtl .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-1px;right:auto;left:-4px}.cke_hc .cke_toolgroup a.cke_button:hover:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-2px;right:-9px}.cke_hc.cke_rtl .cke_toolgroup a.cke_button:hover:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-2px;right:auto;left:-9px}.cke_toolbar.cke_toolbar_last .cke_toolgroup a.cke_button:last-child:after{content:none;border:0;width:0;height:0}.cke_button_icon{cursor:inherit;background-repeat:no-repeat;margin-top:1px;width:16px;height:16px;float:left;display:inline-block}.cke_rtl .cke_button_icon{float:right}.cke_hc .cke_button_icon{display:none}.cke_button_label{display:none;padding-left:3px;margin-top:1px;line-height:17px;vertical-align:middle;float:left;cursor:default;color:#484848}.cke_rtl .cke_button_label{padding-right:3px;padding-left:0;float:right}.cke_hc .cke_button_label{padding:0;display:inline-block;font-size:12px}.cke_button_arrow{display:inline-block;margin:8px 0 0 3px;width:0;height:0;cursor:default;vertical-align:top;border-left:3px solid transparent;border-right:3px solid transparent;border-top:3px solid #484848}.cke_rtl .cke_button_arrow{margin-right:5px;margin-left:0}.cke_hc .cke_button_arrow{font-size:10px;margin:3px 0 0 3px;width:auto;border:0}.cke_toolbar_separator{float:left;background-color:#bcbcbc;margin:4px 2px 0 2px;height:18px;width:1px}.cke_rtl .cke_toolbar_separator{float:right}.cke_hc .cke_toolbar_separator{background-color:#000;margin-left:2px;margin-right:5px;margin-bottom:9px}.cke_hc.cke_rtl .cke_toolbar_separator{margin-left:5px;margin-right:2px}.cke_toolbar_break{display:block;clear:left}.cke_rtl .cke_toolbar_break{clear:right}a.cke_toolbox_collapser{width:12px;height:11px;float:right;margin:11px 0 0;font-size:0;cursor:default;text-align:center;border:1px solid #bcbcbc}.cke_rtl .cke_toolbox_collapser{float:left}.cke_toolbox_collapser:hover{background:#e5e5e5}.cke_toolbox_collapser.cke_toolbox_collapser_min{margin:0 2px 4px}.cke_toolbox_collapser .cke_arrow{display:inline-block;height:0;width:0;font-size:0;margin-top:1px;border:3px solid transparent;border-bottom-color:#484848}.cke_toolbox_collapser.cke_toolbox_collapser_min .cke_arrow{margin-top:4px;border-bottom-color:transparent;border-top-color:#484848}.cke_hc .cke_toolbox_collapser .cke_arrow{font-size:8px;width:auto;border:0;margin-top:0}.cke_menuitem span{cursor:default}.cke_menubutton{display:block}.cke_hc .cke_menubutton{padding:2px}.cke_menubutton:hover,.cke_menubutton:focus,.cke_menubutton:active{background-color:#e9e9e9;display:block;outline:1px dotted}.cke_menubutton:hover{outline:0}.cke_hc .cke_menubutton:hover,.cke_hc .cke_menubutton:focus,.cke_hc .cke_menubutton:active{border:2px solid;padding:0}.cke_menubutton_disabled:hover,.cke_menubutton_disabled:focus,.cke_menubutton_disabled:active{background-color:transparent;outline:0}.cke_menubutton_inner{display:table-row}.cke_menubutton_icon,.cke_menubutton_label,.cke_menuarrow{display:table-cell}.cke_menubutton_icon{background-color:#f8f8f8;padding:6px 4px}.cke_hc .cke_menubutton_icon{height:16px;width:0;padding:4px 0}.cke_menubutton:hover .cke_menubutton_icon,.cke_menubutton:focus .cke_menubutton_icon,.cke_menubutton:active .cke_menubutton_icon{background-color:#e9e9e9}.cke_menubutton_disabled:hover .cke_menubutton_icon,.cke_menubutton_disabled:focus .cke_menubutton_icon,.cke_menubutton_disabled:active .cke_menubutton_icon{background-color:#f8f8f8;outline:0}.cke_menuitem .cke_menubutton_on{background-color:#e9e9e9;border:1px solid #dedede;outline:0}.cke_menubutton_on .cke_menubutton_icon{padding-right:3px;background-color:#e9e9e9}.cke_menubutton_label{padding:0 5px;background-color:transparent;width:100%;vertical-align:middle}.cke_menubutton_shortcut{color:#979797}.cke_menubutton_disabled .cke_menubutton_label{opacity:.3;filter:alpha(opacity=30)}.cke_panel_frame .cke_menubutton_label{display:none}.cke_menuseparator{background-color:#d1d1d1;height:1px}.cke_menuarrow{background:transparent url(images/arrow.png) no-repeat 0 10px;padding:0 5px}.cke_rtl .cke_menuarrow{background-position:5px -13px;background-repeat:no-repeat}.cke_hc .cke_menuarrow{background-image:none}.cke_menuarrow span{display:none}.cke_hc .cke_menuarrow span{vertical-align:middle;display:inline}.cke_combo{display:inline-block;float:left;position:relative;margin-bottom:5px}.cke_rtl .cke_combo{float:right}.cke_hc .cke_combo{margin-top:1px;margin-bottom:10px}.cke_combo:after{content:\"\";position:absolute;height:18px;width:0;border-right:1px solid #bcbcbc;margin-top:5px;top:0;right:0}.cke_rtl .cke_combo:after{border-right:0;border-left:1px solid #bcbcbc;right:auto;left:0}.cke_hc .cke_combo:after{border-color:#000}a.cke_combo_button{cursor:default;display:inline-block;float:left;margin:0;padding:1px}.cke_rtl a.cke_combo_button{float:right}.cke_hc a.cke_combo_button{padding:4px}.cke_combo_on a.cke_combo_button,.cke_combo_off a.cke_combo_button:hover,.cke_combo_off a.cke_combo_button:focus,.cke_combo_off a.cke_combo_button:active{background:#e5e5e5;border:1px solid #bcbcbc;padding:0 0 0 1px;margin-left:-1px}.cke_combo_off a.cke_combo_button:focus{outline:0}.cke_combo_on a.cke_combo_button,.cke_combo_off a.cke_combo_button:active{background:#fff}.cke_rtl .cke_combo_on a.cke_combo_button,.cke_rtl .cke_combo_off a.cke_combo_button:hover,.cke_rtl .cke_combo_off a.cke_combo_button:focus,.cke_rtl .cke_combo_off a.cke_combo_button:active{padding:0 1px 0 0;margin-left:0;margin-right:-1px}.cke_hc .cke_combo_on a.cke_combo_button,.cke_hc .cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_combo_off a.cke_combo_button:active{border:3px solid #000;padding:1px 1px 1px 2px}.cke_hc.cke_rtl .cke_combo_on a.cke_combo_button,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:hover,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:focus,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:active{padding:1px 2px 1px 1px}.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0 0 0 3px;margin-left:-3px}.cke_rtl .cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0 3px 0 0;margin-left:0;margin-right:-3px}.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px 1px 1px 7px;margin-left:-6px}.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px 7px 1px 1px;margin-left:0;margin-right:-6px}.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0;margin:0}.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px;margin:0}.cke_toolbar .cke_combo+.cke_toolbar_end,.cke_toolbar .cke_combo+.cke_toolgroup{margin-right:0;margin-left:2px}.cke_rtl .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_rtl .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:0;margin-right:2px}.cke_hc .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_hc .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:5px}.cke_hc.cke_rtl .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_hc.cke_rtl .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:0;margin-right:5px}.cke_toolbar.cke_toolbar_last .cke_combo:nth-last-child(-n+2):after{content:none;border:0;width:0;height:0}.cke_combo_text{line-height:26px;padding-left:10px;text-overflow:ellipsis;overflow:hidden;float:left;cursor:default;color:#484848;width:60px}.cke_rtl .cke_combo_text{float:right;text-align:right;padding-left:0;padding-right:10px}.cke_hc .cke_combo_text{line-height:18px;font-size:12px}.cke_combo_open{cursor:default;display:inline-block;font-size:0;height:19px;line-height:17px;margin:1px 10px 1px;width:5px}.cke_hc .cke_combo_open{height:12px}.cke_combo_arrow{cursor:default;margin:11px 0 0;float:left;height:0;width:0;font-size:0;border-left:3px solid transparent;border-right:3px solid transparent;border-top:3px solid #484848}.cke_hc .cke_combo_arrow{font-size:10px;width:auto;border:0;margin-top:3px}.cke_combo_label{display:none;float:left;line-height:26px;vertical-align:top;margin-right:5px}.cke_rtl .cke_combo_label{float:right;margin-left:5px;margin-right:0}.cke_combo_disabled .cke_combo_inlinelabel,.cke_combo_disabled .cke_combo_open{opacity:.3}.cke_path{float:left;margin:-2px 0 2px}a.cke_path_item,span.cke_path_empty{display:inline-block;float:left;padding:3px 4px;margin-right:2px;cursor:default;text-decoration:none;outline:0;border:0;color:#484848;font-weight:bold;font-size:11px}.cke_rtl .cke_path,.cke_rtl .cke_path_item,.cke_rtl .cke_path_empty{float:right}a.cke_path_item:hover,a.cke_path_item:focus,a.cke_path_item:active{background-color:#e5e5e5}.cke_hc a.cke_path_item:hover,.cke_hc a.cke_path_item:focus,.cke_hc a.cke_path_item:active{border:2px solid;padding:1px 2px}.cke_button__source_label,.cke_button__sourcedialog_label{display:inline}.cke_combopanel__fontsize{width:135px}textarea.cke_source{font-family:'Courier New',Monospace;font-size:small;background-color:#fff;white-space:pre-wrap;border:0;padding:0;margin:0;display:block}.cke_wysiwyg_frame,.cke_wysiwyg_div{background-color:#fff}.cke_notifications_area{pointer-events:none}.cke_notification{pointer-events:auto;position:relative;margin:10px;width:300px;color:white;text-align:center;opacity:.95;filter:alpha(opacity = 95);-webkit-animation:fadeIn .7s;animation:fadeIn .7s}.cke_notification_message a{color:#12306f}@-webkit-keyframes fadeIn{from{opacity:.4}to{opacity:.95}}@keyframes fadeIn{from{opacity:.4}to{opacity:.95}}.cke_notification_success{background:#72b572;border:1px solid #63a563}.cke_notification_warning{background:#c83939;border:1px solid #902b2b}.cke_notification_info{background:#2e9ad0;border:1px solid #0f74a8}.cke_notification_info span.cke_notification_progress{background-color:#0f74a8;display:block;padding:0;margin:0;height:100%;overflow:hidden;position:absolute;z-index:1}.cke_notification_message{position:relative;margin:4px 23px 3px;font-family:Arial,Helvetica,sans-serif;font-size:12px;line-height:18px;z-index:4;text-overflow:ellipsis;overflow:hidden}.cke_notification_close{background-image:url(images/close.png);background-repeat:no-repeat;background-position:50%;position:absolute;cursor:pointer;text-align:center;height:20px;width:20px;top:1px;right:1px;padding:0;margin:0;z-index:5;opacity:.6;filter:alpha(opacity = 60)}.cke_notification_close:hover{opacity:1;filter:alpha(opacity = 100)}.cke_notification_close span{display:none}.cke_notification_warning a.cke_notification_close{opacity:.8;filter:alpha(opacity = 80)}.cke_notification_warning a.cke_notification_close:hover{opacity:1;filter:alpha(opacity = 100)}.cke_chrome{visibility:inherit}.cke_voice_label{display:none}legend.cke_voice_label{display:none}.cke_button__about_icon{background:url(icons.png?t=J5S9) no-repeat 0 -0px!important}.cke_button__bold_icon{background:url(icons.png?t=J5S9) no-repeat 0 -24px!important}.cke_button__italic_icon{background:url(icons.png?t=J5S9) no-repeat 0 -48px!important}.cke_button__strike_icon{background:url(icons.png?t=J5S9) no-repeat 0 -72px!important}.cke_button__subscript_icon{background:url(icons.png?t=J5S9) no-repeat 0 -96px!important}.cke_button__superscript_icon{background:url(icons.png?t=J5S9) no-repeat 0 -120px!important}.cke_button__underline_icon{background:url(icons.png?t=J5S9) no-repeat 0 -144px!important}.cke_button__bidiltr_icon{background:url(icons.png?t=J5S9) no-repeat 0 -168px!important}.cke_button__bidirtl_icon{background:url(icons.png?t=J5S9) no-repeat 0 -192px!important}.cke_button__blockquote_icon{background:url(icons.png?t=J5S9) no-repeat 0 -216px!important}.cke_rtl .cke_button__copy_icon,.cke_mixed_dir_content .cke_rtl .cke_button__copy_icon{background:url(icons.png?t=J5S9) no-repeat 0 -240px!important}.cke_ltr .cke_button__copy_icon{background:url(icons.png?t=J5S9) no-repeat 0 -264px!important}.cke_rtl .cke_button__cut_icon,.cke_mixed_dir_content .cke_rtl .cke_button__cut_icon{background:url(icons.png?t=J5S9) no-repeat 0 -288px!important}.cke_ltr .cke_button__cut_icon{background:url(icons.png?t=J5S9) no-repeat 0 -312px!important}.cke_rtl .cke_button__paste_icon,.cke_mixed_dir_content .cke_rtl .cke_button__paste_icon{background:url(icons.png?t=J5S9) no-repeat 0 -336px!important}.cke_ltr .cke_button__paste_icon{background:url(icons.png?t=J5S9) no-repeat 0 -360px!important}.cke_button__codesnippet_icon{background:url(icons.png?t=J5S9) no-repeat 0 -384px!important}.cke_button__bgcolor_icon{background:url(icons.png?t=J5S9) no-repeat 0 -408px!important}.cke_button__textcolor_icon{background:url(icons.png?t=J5S9) no-repeat 0 -432px!important}.cke_button__copyformatting_icon{background:url(icons.png?t=J5S9) no-repeat 0 -456px!important}.cke_button__creatediv_icon{background:url(icons.png?t=J5S9) no-repeat 0 -480px!important}.cke_rtl .cke_button__docprops_icon,.cke_mixed_dir_content .cke_rtl .cke_button__docprops_icon{background:url(icons.png?t=J5S9) no-repeat 0 -504px!important}.cke_ltr .cke_button__docprops_icon{background:url(icons.png?t=J5S9) no-repeat 0 -528px!important}.cke_button__easyimagealigncenter_icon{background:url(icons.png?t=J5S9) no-repeat 0 -552px!important}.cke_button__easyimagealignleft_icon{background:url(icons.png?t=J5S9) no-repeat 0 -576px!important}.cke_button__easyimagealignright_icon{background:url(icons.png?t=J5S9) no-repeat 0 -600px!important}.cke_button__easyimagealt_icon{background:url(icons.png?t=J5S9) no-repeat 0 -624px!important}.cke_button__easyimagefull_icon{background:url(icons.png?t=J5S9) no-repeat 0 -648px!important}.cke_button__easyimageside_icon{background:url(icons.png?t=J5S9) no-repeat 0 -672px!important}.cke_button__easyimageupload_icon{background:url(icons.png?t=J5S9) no-repeat 0 -696px!important}.cke_button__embed_icon{background:url(icons.png?t=J5S9) no-repeat 0 -720px!important}.cke_button__embedsemantic_icon{background:url(icons.png?t=J5S9) no-repeat 0 -744px!important}.cke_button__emojipanel_icon{background:url(icons.png?t=J5S9) no-repeat 0 -768px!important}.cke_rtl .cke_button__find_icon,.cke_mixed_dir_content .cke_rtl .cke_button__find_icon{background:url(icons.png?t=J5S9) no-repeat 0 -792px!important}.cke_ltr .cke_button__find_icon{background:url(icons.png?t=J5S9) no-repeat 0 -816px!important}.cke_button__replace_icon{background:url(icons.png?t=J5S9) no-repeat 0 -840px!important}.cke_button__flash_icon{background:url(icons.png?t=J5S9) no-repeat 0 -864px!important}.cke_button__button_icon{background:url(icons.png?t=J5S9) no-repeat 0 -888px!important}.cke_button__checkbox_icon{background:url(icons.png?t=J5S9) no-repeat 0 -912px!important}.cke_button__form_icon{background:url(icons.png?t=J5S9) no-repeat 0 -936px!important}.cke_button__hiddenfield_icon{background:url(icons.png?t=J5S9) no-repeat 0 -960px!important}.cke_button__imagebutton_icon{background:url(icons.png?t=J5S9) no-repeat 0 -984px!important}.cke_button__radio_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1008px!important}.cke_rtl .cke_button__select_icon,.cke_mixed_dir_content .cke_rtl .cke_button__select_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1032px!important}.cke_ltr .cke_button__select_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1056px!important}.cke_rtl .cke_button__textarea_icon,.cke_mixed_dir_content .cke_rtl .cke_button__textarea_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1080px!important}.cke_ltr .cke_button__textarea_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1104px!important}.cke_rtl .cke_button__textfield_icon,.cke_mixed_dir_content .cke_rtl .cke_button__textfield_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1128px!important}.cke_ltr .cke_button__textfield_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1152px!important}.cke_button__horizontalrule_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1176px!important}.cke_button__iframe_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1200px!important}.cke_button__image_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1224px!important}.cke_rtl .cke_button__indent_icon,.cke_mixed_dir_content .cke_rtl .cke_button__indent_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1248px!important}.cke_ltr .cke_button__indent_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1272px!important}.cke_rtl .cke_button__outdent_icon,.cke_mixed_dir_content .cke_rtl .cke_button__outdent_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1296px!important}.cke_ltr .cke_button__outdent_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1320px!important}.cke_button__justifyblock_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1344px!important}.cke_button__justifycenter_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1368px!important}.cke_button__justifyleft_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1392px!important}.cke_button__justifyright_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1416px!important}.cke_button__language_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1440px!important}.cke_rtl .cke_button__anchor_icon,.cke_mixed_dir_content .cke_rtl .cke_button__anchor_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1464px!important}.cke_ltr .cke_button__anchor_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1488px!important}.cke_button__link_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1512px!important}.cke_button__unlink_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1536px!important}.cke_rtl .cke_button__bulletedlist_icon,.cke_mixed_dir_content .cke_rtl .cke_button__bulletedlist_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1560px!important}.cke_ltr .cke_button__bulletedlist_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1584px!important}.cke_rtl .cke_button__numberedlist_icon,.cke_mixed_dir_content .cke_rtl .cke_button__numberedlist_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1608px!important}.cke_ltr .cke_button__numberedlist_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1632px!important}.cke_button__mathjax_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1656px!important}.cke_button__maximize_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1680px!important}.cke_rtl .cke_button__newpage_icon,.cke_mixed_dir_content .cke_rtl .cke_button__newpage_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1704px!important}.cke_ltr .cke_button__newpage_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1728px!important}.cke_rtl .cke_button__pagebreak_icon,.cke_mixed_dir_content .cke_rtl .cke_button__pagebreak_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1752px!important}.cke_ltr .cke_button__pagebreak_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1776px!important}.cke_rtl .cke_button__pastefromword_icon,.cke_mixed_dir_content .cke_rtl .cke_button__pastefromword_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1800px!important}.cke_ltr .cke_button__pastefromword_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1824px!important}.cke_rtl .cke_button__pastetext_icon,.cke_mixed_dir_content .cke_rtl .cke_button__pastetext_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1848px!important}.cke_ltr .cke_button__pastetext_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1872px!important}.cke_button__placeholder_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1896px!important}.cke_rtl .cke_button__preview_icon,.cke_mixed_dir_content .cke_rtl .cke_button__preview_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1920px!important}.cke_ltr .cke_button__preview_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1944px!important}.cke_button__print_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1968px!important}.cke_button__removeformat_icon{background:url(icons.png?t=J5S9) no-repeat 0 -1992px!important}.cke_button__save_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2016px!important}.cke_button__scayt_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2040px!important}.cke_button__selectall_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2064px!important}.cke_rtl .cke_button__showblocks_icon,.cke_mixed_dir_content .cke_rtl .cke_button__showblocks_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2088px!important}.cke_ltr .cke_button__showblocks_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2112px!important}.cke_button__smiley_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2136px!important}.cke_rtl .cke_button__source_icon,.cke_mixed_dir_content .cke_rtl .cke_button__source_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2160px!important}.cke_ltr .cke_button__source_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2184px!important}.cke_rtl .cke_button__sourcedialog_icon,.cke_mixed_dir_content .cke_rtl .cke_button__sourcedialog_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2208px!important}.cke_ltr .cke_button__sourcedialog_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2232px!important}.cke_button__specialchar_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2256px!important}.cke_button__table_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2280px!important}.cke_rtl .cke_button__templates_icon,.cke_mixed_dir_content .cke_rtl .cke_button__templates_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2304px!important}.cke_ltr .cke_button__templates_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2328px!important}.cke_button__uicolor_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2352px!important}.cke_rtl .cke_button__redo_icon,.cke_mixed_dir_content .cke_rtl .cke_button__redo_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2376px!important}.cke_ltr .cke_button__redo_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2400px!important}.cke_rtl .cke_button__undo_icon,.cke_mixed_dir_content .cke_rtl .cke_button__undo_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2424px!important}.cke_ltr .cke_button__undo_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2448px!important}.cke_button__simplebox_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2472px!important}.cke_button__spellchecker_icon{background:url(icons.png?t=J5S9) no-repeat 0 -2496px!important}.cke_hidpi .cke_button__about_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -0px!important;background-size:16px!important}.cke_hidpi .cke_button__bold_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -24px!important;background-size:16px!important}.cke_hidpi .cke_button__italic_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -48px!important;background-size:16px!important}.cke_hidpi .cke_button__strike_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -72px!important;background-size:16px!important}.cke_hidpi .cke_button__subscript_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -96px!important;background-size:16px!important}.cke_hidpi .cke_button__superscript_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -120px!important;background-size:16px!important}.cke_hidpi .cke_button__underline_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -144px!important;background-size:16px!important}.cke_hidpi .cke_button__bidiltr_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -168px!important;background-size:16px!important}.cke_hidpi .cke_button__bidirtl_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -192px!important;background-size:16px!important}.cke_hidpi .cke_button__blockquote_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -216px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__copy_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__copy_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -240px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__copy_icon,.cke_ltr.cke_hidpi .cke_button__copy_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -264px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__cut_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__cut_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -288px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__cut_icon,.cke_ltr.cke_hidpi .cke_button__cut_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -312px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__paste_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__paste_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -336px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__paste_icon,.cke_ltr.cke_hidpi .cke_button__paste_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -360px!important;background-size:16px!important}.cke_hidpi .cke_button__codesnippet_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -384px!important;background-size:16px!important}.cke_hidpi .cke_button__bgcolor_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -408px!important;background-size:16px!important}.cke_hidpi .cke_button__textcolor_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -432px!important;background-size:16px!important}.cke_hidpi .cke_button__copyformatting_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -456px!important;background-size:16px!important}.cke_hidpi .cke_button__creatediv_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -480px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__docprops_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__docprops_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -504px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__docprops_icon,.cke_ltr.cke_hidpi .cke_button__docprops_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -528px!important;background-size:16px!important}.cke_hidpi .cke_button__easyimagealigncenter_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -552px!important;background-size:16px!important}.cke_hidpi .cke_button__easyimagealignleft_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -576px!important;background-size:16px!important}.cke_hidpi .cke_button__easyimagealignright_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -600px!important;background-size:16px!important}.cke_hidpi .cke_button__easyimagealt_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -624px!important;background-size:16px!important}.cke_hidpi .cke_button__easyimagefull_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -648px!important;background-size:16px!important}.cke_hidpi .cke_button__easyimageside_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -672px!important;background-size:16px!important}.cke_hidpi .cke_button__easyimageupload_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -696px!important;background-size:16px!important}.cke_hidpi .cke_button__embed_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -720px!important;background-size:16px!important}.cke_hidpi .cke_button__embedsemantic_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -744px!important;background-size:16px!important}.cke_hidpi .cke_button__emojipanel_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -768px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__find_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__find_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -792px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__find_icon,.cke_ltr.cke_hidpi .cke_button__find_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -816px!important;background-size:16px!important}.cke_hidpi .cke_button__replace_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -840px!important;background-size:16px!important}.cke_hidpi .cke_button__flash_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -864px!important;background-size:16px!important}.cke_hidpi .cke_button__button_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -888px!important;background-size:16px!important}.cke_hidpi .cke_button__checkbox_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -912px!important;background-size:16px!important}.cke_hidpi .cke_button__form_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -936px!important;background-size:16px!important}.cke_hidpi .cke_button__hiddenfield_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -960px!important;background-size:16px!important}.cke_hidpi .cke_button__imagebutton_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -984px!important;background-size:16px!important}.cke_hidpi .cke_button__radio_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1008px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__select_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__select_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1032px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__select_icon,.cke_ltr.cke_hidpi .cke_button__select_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1056px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__textarea_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__textarea_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1080px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__textarea_icon,.cke_ltr.cke_hidpi .cke_button__textarea_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1104px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__textfield_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__textfield_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1128px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__textfield_icon,.cke_ltr.cke_hidpi .cke_button__textfield_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1152px!important;background-size:16px!important}.cke_hidpi .cke_button__horizontalrule_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1176px!important;background-size:16px!important}.cke_hidpi .cke_button__iframe_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1200px!important;background-size:16px!important}.cke_hidpi .cke_button__image_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1224px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__indent_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__indent_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1248px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__indent_icon,.cke_ltr.cke_hidpi .cke_button__indent_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1272px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__outdent_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__outdent_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1296px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__outdent_icon,.cke_ltr.cke_hidpi .cke_button__outdent_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1320px!important;background-size:16px!important}.cke_hidpi .cke_button__justifyblock_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1344px!important;background-size:16px!important}.cke_hidpi .cke_button__justifycenter_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1368px!important;background-size:16px!important}.cke_hidpi .cke_button__justifyleft_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1392px!important;background-size:16px!important}.cke_hidpi .cke_button__justifyright_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1416px!important;background-size:16px!important}.cke_hidpi .cke_button__language_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1440px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__anchor_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__anchor_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1464px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__anchor_icon,.cke_ltr.cke_hidpi .cke_button__anchor_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1488px!important;background-size:16px!important}.cke_hidpi .cke_button__link_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1512px!important;background-size:16px!important}.cke_hidpi .cke_button__unlink_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1536px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__bulletedlist_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__bulletedlist_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1560px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__bulletedlist_icon,.cke_ltr.cke_hidpi .cke_button__bulletedlist_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1584px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__numberedlist_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__numberedlist_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1608px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__numberedlist_icon,.cke_ltr.cke_hidpi .cke_button__numberedlist_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1632px!important;background-size:16px!important}.cke_hidpi .cke_button__mathjax_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1656px!important;background-size:16px!important}.cke_hidpi .cke_button__maximize_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1680px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__newpage_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__newpage_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1704px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__newpage_icon,.cke_ltr.cke_hidpi .cke_button__newpage_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1728px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__pagebreak_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__pagebreak_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1752px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__pagebreak_icon,.cke_ltr.cke_hidpi .cke_button__pagebreak_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1776px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__pastefromword_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__pastefromword_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1800px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__pastefromword_icon,.cke_ltr.cke_hidpi .cke_button__pastefromword_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1824px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__pastetext_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__pastetext_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1848px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__pastetext_icon,.cke_ltr.cke_hidpi .cke_button__pastetext_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1872px!important;background-size:16px!important}.cke_hidpi .cke_button__placeholder_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1896px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__preview_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__preview_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1920px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__preview_icon,.cke_ltr.cke_hidpi .cke_button__preview_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1944px!important;background-size:16px!important}.cke_hidpi .cke_button__print_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1968px!important;background-size:16px!important}.cke_hidpi .cke_button__removeformat_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -1992px!important;background-size:16px!important}.cke_hidpi .cke_button__save_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2016px!important;background-size:16px!important}.cke_hidpi .cke_button__scayt_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2040px!important;background-size:16px!important}.cke_hidpi .cke_button__selectall_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2064px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__showblocks_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__showblocks_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2088px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__showblocks_icon,.cke_ltr.cke_hidpi .cke_button__showblocks_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2112px!important;background-size:16px!important}.cke_hidpi .cke_button__smiley_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2136px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__source_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__source_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2160px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__source_icon,.cke_ltr.cke_hidpi .cke_button__source_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2184px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__sourcedialog_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__sourcedialog_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2208px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__sourcedialog_icon,.cke_ltr.cke_hidpi .cke_button__sourcedialog_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2232px!important;background-size:16px!important}.cke_hidpi .cke_button__specialchar_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2256px!important;background-size:16px!important}.cke_hidpi .cke_button__table_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2280px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__templates_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__templates_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2304px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__templates_icon,.cke_ltr.cke_hidpi .cke_button__templates_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2328px!important;background-size:16px!important}.cke_hidpi .cke_button__uicolor_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2352px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__redo_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__redo_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2376px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__redo_icon,.cke_ltr.cke_hidpi .cke_button__redo_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2400px!important;background-size:16px!important}.cke_rtl.cke_hidpi .cke_button__undo_icon,.cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__undo_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2424px!important;background-size:16px!important}.cke_hidpi .cke_ltr .cke_button__undo_icon,.cke_ltr.cke_hidpi .cke_button__undo_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2448px!important;background-size:16px!important}.cke_hidpi .cke_button__simplebox_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -4944px!important}.cke_hidpi .cke_button__spellchecker_icon{background:url(icons_hidpi.png?t=J5S9) no-repeat 0 -2496px!important;background-size:16px!important}a.cke_button_disabled,a.cke_button_disabled:hover,a.cke_button_disabled:focus,a.cke_button_disabled:active{filter:alpha(opacity = 30)}.cke_button_disabled .cke_button_icon{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#00ffffff,endColorstr=#00ffffff)}.cke_button_off:hover,.cke_button_off:focus,.cke_button_off:active{filter:alpha(opacity = 100)}.cke_combo_disabled .cke_combo_inlinelabel,.cke_combo_disabled .cke_combo_open{filter:alpha(opacity = 30)}.cke_toolbox_collapser{border:1px solid #a6a6a6}.cke_toolbox_collapser .cke_arrow{margin-top:1px}.cke_hc .cke_top,.cke_hc .cke_bottom,.cke_hc .cke_combo_button,.cke_hc a.cke_combo_button:hover,.cke_hc a.cke_combo_button:focus,.cke_hc .cke_toolgroup,.cke_hc .cke_button_on,.cke_hc a.cke_button_off:hover,.cke_hc a.cke_button_off:focus,.cke_hc a.cke_button_off:active,.cke_hc .cke_toolbox_collapser,.cke_hc .cke_toolbox_collapser:hover,.cke_hc .cke_panel_grouptitle{filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.cke_top,.cke_contents,.cke_bottom{width:100%}.cke_button_arrow{font-size:0}.cke_rtl .cke_toolgroup,.cke_rtl .cke_toolbar_separator,.cke_rtl .cke_button,.cke_rtl .cke_button *,.cke_rtl .cke_combo,.cke_rtl .cke_combo *,.cke_rtl .cke_path_item,.cke_rtl .cke_path_item *,.cke_rtl .cke_path_empty{float:none}.cke_rtl .cke_toolgroup,.cke_rtl .cke_toolbar_separator,.cke_rtl .cke_combo_button,.cke_rtl .cke_combo_button *,.cke_rtl .cke_button,.cke_rtl .cke_button_icon{display:inline-block;vertical-align:top}.cke_rtl .cke_button_icon{float:none}.cke_resizer{width:10px}.cke_source{white-space:normal}.cke_bottom{position:static}.cke_colorbox{font-size:0}"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/adminlte/bower_components/ckeditor/skins/moono-lisa/readme.md",
    "content": "\"Moono-lisa\" Skin\n=================\n\nThis skin has been made a **default skin** starting from CKEditor 4.6.0 and is maintained by the core developers.\n\nFor more information about skins, please check the [CKEditor Skin SDK](https://ckeditor.com/docs/ckeditor4/latest/guide/skin_sdk_intro.html)\ndocumentation.\n\nFeatures\n-------------------\n\"Moono-lisa\" is a monochromatic skin, which offers a modern, flat and minimalistic look which blends very well in modern design.\nIt comes with the following features:\n\n- Chameleon feature with brightness.\n- High-contrast compatibility.\n- Graphics source provided in SVG.\n\nDirectory Structure\n-------------------\n\nCSS parts:\n- **editor.css**: the main CSS file. It's simply loading several other files, for easier maintenance,\n- **mainui.css**: the file contains styles of entire editor outline structures,\n- **toolbar.css**: the file contains styles of the editor toolbar space (top),\n- **richcombo.css**: the file contains styles of the rich combo ui elements on toolbar,\n- **panel.css**: the file contains styles of the rich combo drop-down, it's not loaded\nuntil the first panel open up,\n- **elementspath.css**: the file contains styles of the editor elements path bar (bottom),\n- **menu.css**: the file contains styles of all editor menus including context menu and button drop-down,\nit's not loaded until the first menu open up,\n- **dialog.css**: the CSS files for the dialog UI, it's not loaded until the first dialog open,\n- **reset.css**: the file defines the basis of style resets among all editor UI spaces,\n- **preset.css**: the file defines the default styles of some UI elements reflecting the skin preference,\n- **editor_XYZ.css** and **dialog_XYZ.css**: browser specific CSS hacks.\n\nOther parts:\n- **skin.js**: the only JavaScript part of the skin that registers the skin, its browser specific files and its icons and defines the Chameleon feature,\n- **images/**: contains a fill general used images,\n- **dev/**: contains SVG and PNG source of the skin icons.\n\nLicense\n-------\n\nCopyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.\n\nFor licensing, see LICENSE.md or [https://ckeditor.com/legal/ckeditor-oss-license](https://ckeditor.com/legal/ckeditor-oss-license)\n"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/adminlte/bower_components/ckeditor/styles.js",
    "content": "﻿/**\n * Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n// This file contains style definitions that can be used by CKEditor plugins.\n//\n// The most common use for it is the \"stylescombo\" plugin which shows the Styles drop-down\n// list containing all styles in the editor toolbar. Other plugins, like\n// the \"div\" plugin, use a subset of the styles for their features.\n//\n// If you do not have plugins that depend on this file in your editor build, you can simply\n// ignore it. Otherwise it is strongly recommended to customize this file to match your\n// website requirements and design properly.\n//\n// For more information refer to: https://ckeditor.com/docs/ckeditor4/latest/guide/dev_styles.html#style-rules\n\nCKEDITOR.stylesSet.add( 'default', [\n\t/* Block styles */\n\n\t// These styles are already available in the \"Format\" drop-down list (\"format\" plugin),\n\t// so they are not needed here by default. You may enable them to avoid\n\t// placing the \"Format\" combo in the toolbar, maintaining the same features.\n\t/*\n\t{ name: 'Paragraph',\t\telement: 'p' },\n\t{ name: 'Heading 1',\t\telement: 'h1' },\n\t{ name: 'Heading 2',\t\telement: 'h2' },\n\t{ name: 'Heading 3',\t\telement: 'h3' },\n\t{ name: 'Heading 4',\t\telement: 'h4' },\n\t{ name: 'Heading 5',\t\telement: 'h5' },\n\t{ name: 'Heading 6',\t\telement: 'h6' },\n\t{ name: 'Preformatted Text',element: 'pre' },\n\t{ name: 'Address',\t\t\telement: 'address' },\n\t*/\n\n\t{ name: 'Italic Title',\t\telement: 'h2', styles: { 'font-style': 'italic' } },\n\t{ name: 'Subtitle',\t\t\telement: 'h3', styles: { 'color': '#aaa', 'font-style': 'italic' } },\n\t{\n\t\tname: 'Special Container',\n\t\telement: 'div',\n\t\tstyles: {\n\t\t\tpadding: '5px 10px',\n\t\t\tbackground: '#eee',\n\t\t\tborder: '1px solid #ccc'\n\t\t}\n\t},\n\n\t/* Inline styles */\n\n\t// These are core styles available as toolbar buttons. You may opt enabling\n\t// some of them in the Styles drop-down list, removing them from the toolbar.\n\t// (This requires the \"stylescombo\" plugin.)\n\t/*\n\t{ name: 'Strong',\t\t\telement: 'strong', overrides: 'b' },\n\t{ name: 'Emphasis',\t\t\telement: 'em'\t, overrides: 'i' },\n\t{ name: 'Underline',\t\telement: 'u' },\n\t{ name: 'Strikethrough',\telement: 'strike' },\n\t{ name: 'Subscript',\t\telement: 'sub' },\n\t{ name: 'Superscript',\t\telement: 'sup' },\n\t*/\n\n\t{ name: 'Marker',\t\t\telement: 'span', attributes: { 'class': 'marker' } },\n\n\t{ name: 'Big',\t\t\t\telement: 'big' },\n\t{ name: 'Small',\t\t\telement: 'small' },\n\t{ name: 'Typewriter',\t\telement: 'tt' },\n\n\t{ name: 'Computer Code',\telement: 'code' },\n\t{ name: 'Keyboard Phrase',\telement: 'kbd' },\n\t{ name: 'Sample Text',\t\telement: 'samp' },\n\t{ name: 'Variable',\t\t\telement: 'var' },\n\n\t{ name: 'Deleted Text',\t\telement: 'del' },\n\t{ name: 'Inserted Text',\telement: 'ins' },\n\n\t{ name: 'Cited Work',\t\telement: 'cite' },\n\t{ name: 'Inline Quotation',\telement: 'q' },\n\n\t{ name: 'Language: RTL',\telement: 'span', attributes: { 'dir': 'rtl' } },\n\t{ name: 'Language: LTR',\telement: 'span', attributes: { 'dir': 'ltr' } },\n\n\t/* Object styles */\n\n\t{\n\t\tname: 'Styled Image (left)',\n\t\telement: 'img',\n\t\tattributes: { 'class': 'left' }\n\t},\n\n\t{\n\t\tname: 'Styled Image (right)',\n\t\telement: 'img',\n\t\tattributes: { 'class': 'right' }\n\t},\n\n\t{\n\t\tname: 'Compact Table',\n\t\telement: 'table',\n\t\tattributes: {\n\t\t\tcellpadding: '5',\n\t\t\tcellspacing: '0',\n\t\t\tborder: '1',\n\t\t\tbordercolor: '#ccc'\n\t\t},\n\t\tstyles: {\n\t\t\t'border-collapse': 'collapse'\n\t\t}\n\t},\n\n\t{ name: 'Borderless Table',\t\telement: 'table',\tstyles: { 'border-style': 'hidden', 'background-color': '#E6E6FA' } },\n\t{ name: 'Square Bulleted List',\telement: 'ul',\t\tstyles: { 'list-style-type': 'square' } },\n\n\t/* Widget styles */\n\n\t{ name: 'Clean Image', type: 'widget', widget: 'image', attributes: { 'class': 'image-clean' } },\n\t{ name: 'Grayscale Image', type: 'widget', widget: 'image', attributes: { 'class': 'image-grayscale' } },\n\n\t{ name: 'Featured Snippet', type: 'widget', widget: 'codeSnippet', attributes: { 'class': 'code-featured' } },\n\n\t{ name: 'Featured Formula', type: 'widget', widget: 'mathjax', attributes: { 'class': 'math-featured' } },\n\n\t{ name: '240p', type: 'widget', widget: 'embedSemantic', attributes: { 'class': 'embed-240p' }, group: 'size' },\n\t{ name: '360p', type: 'widget', widget: 'embedSemantic', attributes: { 'class': 'embed-360p' }, group: 'size' },\n\t{ name: '480p', type: 'widget', widget: 'embedSemantic', attributes: { 'class': 'embed-480p' }, group: 'size' },\n\t{ name: '720p', type: 'widget', widget: 'embedSemantic', attributes: { 'class': 'embed-720p' }, group: 'size' },\n\t{ name: '1080p', type: 'widget', widget: 'embedSemantic', attributes: { 'class': 'embed-1080p' }, group: 'size' },\n\n\t// Adding space after the style name is an intended workaround. For now, there\n\t// is no option to create two styles with the same name for different widget types. See https://dev.ckeditor.com/ticket/16664.\n\t{ name: '240p ', type: 'widget', widget: 'embed', attributes: { 'class': 'embed-240p' }, group: 'size' },\n\t{ name: '360p ', type: 'widget', widget: 'embed', attributes: { 'class': 'embed-360p' }, group: 'size' },\n\t{ name: '480p ', type: 'widget', widget: 'embed', attributes: { 'class': 'embed-480p' }, group: 'size' },\n\t{ name: '720p ', type: 'widget', widget: 'embed', attributes: { 'class': 'embed-720p' }, group: 'size' },\n\t{ name: '1080p ', type: 'widget', widget: 'embed', attributes: { 'class': 'embed-1080p' }, group: 'size' }\n\n] );\n\n"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/adminlte/bower_components/fastclick/fastclick.js",
    "content": ";(function () {\n\t'use strict';\n\n\t/**\n\t * @preserve FastClick: polyfill to remove click delays on browsers with touch UIs.\n\t *\n\t * @codingstandard ftlabs-jsv2\n\t * @copyright The Financial Times Limited [All Rights Reserved]\n\t * @license MIT License (see LICENSE.txt)\n\t */\n\n\t/*jslint browser:true, node:true*/\n\t/*global define, Event, Node*/\n\n\n\t/**\n\t * Instantiate fast-clicking listeners on the specified layer.\n\t *\n\t * @constructor\n\t * @param {Element} layer The layer to listen on\n\t * @param {Object} [options={}] The options to override the defaults\n\t */\n\tfunction FastClick(layer, options) {\n\t\tvar oldOnClick;\n\n\t\toptions = options || {};\n\n\t\t/**\n\t\t * Whether a click is currently being tracked.\n\t\t *\n\t\t * @type boolean\n\t\t */\n\t\tthis.trackingClick = false;\n\n\n\t\t/**\n\t\t * Timestamp for when click tracking started.\n\t\t *\n\t\t * @type number\n\t\t */\n\t\tthis.trackingClickStart = 0;\n\n\n\t\t/**\n\t\t * The element being tracked for a click.\n\t\t *\n\t\t * @type EventTarget\n\t\t */\n\t\tthis.targetElement = null;\n\n\n\t\t/**\n\t\t * X-coordinate of touch start event.\n\t\t *\n\t\t * @type number\n\t\t */\n\t\tthis.touchStartX = 0;\n\n\n\t\t/**\n\t\t * Y-coordinate of touch start event.\n\t\t *\n\t\t * @type number\n\t\t */\n\t\tthis.touchStartY = 0;\n\n\n\t\t/**\n\t\t * ID of the last touch, retrieved from Touch.identifier.\n\t\t *\n\t\t * @type number\n\t\t */\n\t\tthis.lastTouchIdentifier = 0;\n\n\n\t\t/**\n\t\t * Touchmove boundary, beyond which a click will be cancelled.\n\t\t *\n\t\t * @type number\n\t\t */\n\t\tthis.touchBoundary = options.touchBoundary || 10;\n\n\n\t\t/**\n\t\t * The FastClick layer.\n\t\t *\n\t\t * @type Element\n\t\t */\n\t\tthis.layer = layer;\n\n\t\t/**\n\t\t * The minimum time between tap(touchstart and touchend) events\n\t\t *\n\t\t * @type number\n\t\t */\n\t\tthis.tapDelay = options.tapDelay || 200;\n\n\t\t/**\n\t\t * The maximum time for a tap\n\t\t *\n\t\t * @type number\n\t\t */\n\t\tthis.tapTimeout = options.tapTimeout || 700;\n\n\t\tif (FastClick.notNeeded(layer)) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Some old versions of Android don't have Function.prototype.bind\n\t\tfunction bind(method, context) {\n\t\t\treturn function() { return method.apply(context, arguments); };\n\t\t}\n\n\n\t\tvar methods = ['onMouse', 'onClick', 'onTouchStart', 'onTouchMove', 'onTouchEnd', 'onTouchCancel'];\n\t\tvar context = this;\n\t\tfor (var i = 0, l = methods.length; i < l; i++) {\n\t\t\tcontext[methods[i]] = bind(context[methods[i]], context);\n\t\t}\n\n\t\t// Set up event handlers as required\n\t\tif (deviceIsAndroid) {\n\t\t\tlayer.addEventListener('mouseover', this.onMouse, true);\n\t\t\tlayer.addEventListener('mousedown', this.onMouse, true);\n\t\t\tlayer.addEventListener('mouseup', this.onMouse, true);\n\t\t}\n\n\t\tlayer.addEventListener('click', this.onClick, true);\n\t\tlayer.addEventListener('touchstart', this.onTouchStart, false);\n\t\tlayer.addEventListener('touchmove', this.onTouchMove, false);\n\t\tlayer.addEventListener('touchend', this.onTouchEnd, false);\n\t\tlayer.addEventListener('touchcancel', this.onTouchCancel, false);\n\n\t\t// Hack is required for browsers that don't support Event#stopImmediatePropagation (e.g. Android 2)\n\t\t// which is how FastClick normally stops click events bubbling to callbacks registered on the FastClick\n\t\t// layer when they are cancelled.\n\t\tif (!Event.prototype.stopImmediatePropagation) {\n\t\t\tlayer.removeEventListener = function(type, callback, capture) {\n\t\t\t\tvar rmv = Node.prototype.removeEventListener;\n\t\t\t\tif (type === 'click') {\n\t\t\t\t\trmv.call(layer, type, callback.hijacked || callback, capture);\n\t\t\t\t} else {\n\t\t\t\t\trmv.call(layer, type, callback, capture);\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tlayer.addEventListener = function(type, callback, capture) {\n\t\t\t\tvar adv = Node.prototype.addEventListener;\n\t\t\t\tif (type === 'click') {\n\t\t\t\t\tadv.call(layer, type, callback.hijacked || (callback.hijacked = function(event) {\n\t\t\t\t\t\tif (!event.propagationStopped) {\n\t\t\t\t\t\t\tcallback(event);\n\t\t\t\t\t\t}\n\t\t\t\t\t}), capture);\n\t\t\t\t} else {\n\t\t\t\t\tadv.call(layer, type, callback, capture);\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t\t// If a handler is already declared in the element's onclick attribute, it will be fired before\n\t\t// FastClick's onClick handler. Fix this by pulling out the user-defined handler function and\n\t\t// adding it as listener.\n\t\tif (typeof layer.onclick === 'function') {\n\n\t\t\t// Android browser on at least 3.2 requires a new reference to the function in layer.onclick\n\t\t\t// - the old one won't work if passed to addEventListener directly.\n\t\t\toldOnClick = layer.onclick;\n\t\t\tlayer.addEventListener('click', function(event) {\n\t\t\t\toldOnClick(event);\n\t\t\t}, false);\n\t\t\tlayer.onclick = null;\n\t\t}\n\t}\n\n\t/**\n\t* Windows Phone 8.1 fakes user agent string to look like Android and iPhone.\n\t*\n\t* @type boolean\n\t*/\n\tvar deviceIsWindowsPhone = navigator.userAgent.indexOf(\"Windows Phone\") >= 0;\n\n\t/**\n\t * Android requires exceptions.\n\t *\n\t * @type boolean\n\t */\n\tvar deviceIsAndroid = navigator.userAgent.indexOf('Android') > 0 && !deviceIsWindowsPhone;\n\n\n\t/**\n\t * iOS requires exceptions.\n\t *\n\t * @type boolean\n\t */\n\tvar deviceIsIOS = /iP(ad|hone|od)/.test(navigator.userAgent) && !deviceIsWindowsPhone;\n\n\n\t/**\n\t * iOS 4 requires an exception for select elements.\n\t *\n\t * @type boolean\n\t */\n\tvar deviceIsIOS4 = deviceIsIOS && (/OS 4_\\d(_\\d)?/).test(navigator.userAgent);\n\n\n\t/**\n\t * iOS 6.0-7.* requires the target element to be manually derived\n\t *\n\t * @type boolean\n\t */\n\tvar deviceIsIOSWithBadTarget = deviceIsIOS && (/OS [6-7]_\\d/).test(navigator.userAgent);\n\n\t/**\n\t * BlackBerry requires exceptions.\n\t *\n\t * @type boolean\n\t */\n\tvar deviceIsBlackBerry10 = navigator.userAgent.indexOf('BB10') > 0;\n\n\t/**\n\t * Determine whether a given element requires a native click.\n\t *\n\t * @param {EventTarget|Element} target Target DOM element\n\t * @returns {boolean} Returns true if the element needs a native click\n\t */\n\tFastClick.prototype.needsClick = function(target) {\n\t\tswitch (target.nodeName.toLowerCase()) {\n\n\t\t// Don't send a synthetic click to disabled inputs (issue #62)\n\t\tcase 'button':\n\t\tcase 'select':\n\t\tcase 'textarea':\n\t\t\tif (target.disabled) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tbreak;\n\t\tcase 'input':\n\n\t\t\t// File inputs need real clicks on iOS 6 due to a browser bug (issue #68)\n\t\t\tif ((deviceIsIOS && target.type === 'file') || target.disabled) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tbreak;\n\t\tcase 'label':\n\t\tcase 'iframe': // iOS8 homescreen apps can prevent events bubbling into frames\n\t\tcase 'video':\n\t\t\treturn true;\n\t\t}\n\n\t\treturn (/\\bneedsclick\\b/).test(target.className);\n\t};\n\n\n\t/**\n\t * Determine whether a given element requires a call to focus to simulate click into element.\n\t *\n\t * @param {EventTarget|Element} target Target DOM element\n\t * @returns {boolean} Returns true if the element requires a call to focus to simulate native click.\n\t */\n\tFastClick.prototype.needsFocus = function(target) {\n\t\tswitch (target.nodeName.toLowerCase()) {\n\t\tcase 'textarea':\n\t\t\treturn true;\n\t\tcase 'select':\n\t\t\treturn !deviceIsAndroid;\n\t\tcase 'input':\n\t\t\tswitch (target.type) {\n\t\t\tcase 'button':\n\t\t\tcase 'checkbox':\n\t\t\tcase 'file':\n\t\t\tcase 'image':\n\t\t\tcase 'radio':\n\t\t\tcase 'submit':\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// No point in attempting to focus disabled inputs\n\t\t\treturn !target.disabled && !target.readOnly;\n\t\tdefault:\n\t\t\treturn (/\\bneedsfocus\\b/).test(target.className);\n\t\t}\n\t};\n\n\n\t/**\n\t * Send a click event to the specified element.\n\t *\n\t * @param {EventTarget|Element} targetElement\n\t * @param {Event} event\n\t */\n\tFastClick.prototype.sendClick = function(targetElement, event) {\n\t\tvar clickEvent, touch;\n\n\t\t// On some Android devices activeElement needs to be blurred otherwise the synthetic click will have no effect (#24)\n\t\tif (document.activeElement && document.activeElement !== targetElement) {\n\t\t\tdocument.activeElement.blur();\n\t\t}\n\n\t\ttouch = event.changedTouches[0];\n\n\t\t// Synthesise a click event, with an extra attribute so it can be tracked\n\t\tclickEvent = document.createEvent('MouseEvents');\n\t\tclickEvent.initMouseEvent(this.determineEventType(targetElement), true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null);\n\t\tclickEvent.forwardedTouchEvent = true;\n\t\ttargetElement.dispatchEvent(clickEvent);\n\t};\n\n\tFastClick.prototype.determineEventType = function(targetElement) {\n\n\t\t//Issue #159: Android Chrome Select Box does not open with a synthetic click event\n\t\tif (deviceIsAndroid && targetElement.tagName.toLowerCase() === 'select') {\n\t\t\treturn 'mousedown';\n\t\t}\n\n\t\treturn 'click';\n\t};\n\n\n\t/**\n\t * @param {EventTarget|Element} targetElement\n\t */\n\tFastClick.prototype.focus = function(targetElement) {\n\t\tvar length;\n\n\t\t// Issue #160: on iOS 7, some input elements (e.g. date datetime month) throw a vague TypeError on setSelectionRange. These elements don't have an integer value for the selectionStart and selectionEnd properties, but unfortunately that can't be used for detection because accessing the properties also throws a TypeError. Just check the type instead. Filed as Apple bug #15122724.\n\t\tif (deviceIsIOS && targetElement.setSelectionRange && targetElement.type.indexOf('date') !== 0 && targetElement.type !== 'time' && targetElement.type !== 'month') {\n\t\t\tlength = targetElement.value.length;\n\t\t\ttargetElement.setSelectionRange(length, length);\n\t\t} else {\n\t\t\ttargetElement.focus();\n\t\t}\n\t};\n\n\n\t/**\n\t * Check whether the given target element is a child of a scrollable layer and if so, set a flag on it.\n\t *\n\t * @param {EventTarget|Element} targetElement\n\t */\n\tFastClick.prototype.updateScrollParent = function(targetElement) {\n\t\tvar scrollParent, parentElement;\n\n\t\tscrollParent = targetElement.fastClickScrollParent;\n\n\t\t// Attempt to discover whether the target element is contained within a scrollable layer. Re-check if the\n\t\t// target element was moved to another parent.\n\t\tif (!scrollParent || !scrollParent.contains(targetElement)) {\n\t\t\tparentElement = targetElement;\n\t\t\tdo {\n\t\t\t\tif (parentElement.scrollHeight > parentElement.offsetHeight) {\n\t\t\t\t\tscrollParent = parentElement;\n\t\t\t\t\ttargetElement.fastClickScrollParent = parentElement;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tparentElement = parentElement.parentElement;\n\t\t\t} while (parentElement);\n\t\t}\n\n\t\t// Always update the scroll top tracker if possible.\n\t\tif (scrollParent) {\n\t\t\tscrollParent.fastClickLastScrollTop = scrollParent.scrollTop;\n\t\t}\n\t};\n\n\n\t/**\n\t * @param {EventTarget} targetElement\n\t * @returns {Element|EventTarget}\n\t */\n\tFastClick.prototype.getTargetElementFromEventTarget = function(eventTarget) {\n\n\t\t// On some older browsers (notably Safari on iOS 4.1 - see issue #56) the event target may be a text node.\n\t\tif (eventTarget.nodeType === Node.TEXT_NODE) {\n\t\t\treturn eventTarget.parentNode;\n\t\t}\n\n\t\treturn eventTarget;\n\t};\n\n\n\t/**\n\t * On touch start, record the position and scroll offset.\n\t *\n\t * @param {Event} event\n\t * @returns {boolean}\n\t */\n\tFastClick.prototype.onTouchStart = function(event) {\n\t\tvar targetElement, touch, selection;\n\n\t\t// Ignore multiple touches, otherwise pinch-to-zoom is prevented if both fingers are on the FastClick element (issue #111).\n\t\tif (event.targetTouches.length > 1) {\n\t\t\treturn true;\n\t\t}\n\n\t\ttargetElement = this.getTargetElementFromEventTarget(event.target);\n\t\ttouch = event.targetTouches[0];\n\n\t\tif (deviceIsIOS) {\n\n\t\t\t// Only trusted events will deselect text on iOS (issue #49)\n\t\t\tselection = window.getSelection();\n\t\t\tif (selection.rangeCount && !selection.isCollapsed) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tif (!deviceIsIOS4) {\n\n\t\t\t\t// Weird things happen on iOS when an alert or confirm dialog is opened from a click event callback (issue #23):\n\t\t\t\t// when the user next taps anywhere else on the page, new touchstart and touchend events are dispatched\n\t\t\t\t// with the same identifier as the touch event that previously triggered the click that triggered the alert.\n\t\t\t\t// Sadly, there is an issue on iOS 4 that causes some normal touch events to have the same identifier as an\n\t\t\t\t// immediately preceeding touch event (issue #52), so this fix is unavailable on that platform.\n\t\t\t\t// Issue 120: touch.identifier is 0 when Chrome dev tools 'Emulate touch events' is set with an iOS device UA string,\n\t\t\t\t// which causes all touch events to be ignored. As this block only applies to iOS, and iOS identifiers are always long,\n\t\t\t\t// random integers, it's safe to to continue if the identifier is 0 here.\n\t\t\t\tif (touch.identifier && touch.identifier === this.lastTouchIdentifier) {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tthis.lastTouchIdentifier = touch.identifier;\n\n\t\t\t\t// If the target element is a child of a scrollable layer (using -webkit-overflow-scrolling: touch) and:\n\t\t\t\t// 1) the user does a fling scroll on the scrollable layer\n\t\t\t\t// 2) the user stops the fling scroll with another tap\n\t\t\t\t// then the event.target of the last 'touchend' event will be the element that was under the user's finger\n\t\t\t\t// when the fling scroll was started, causing FastClick to send a click event to that layer - unless a check\n\t\t\t\t// is made to ensure that a parent layer was not scrolled before sending a synthetic click (issue #42).\n\t\t\t\tthis.updateScrollParent(targetElement);\n\t\t\t}\n\t\t}\n\n\t\tthis.trackingClick = true;\n\t\tthis.trackingClickStart = event.timeStamp;\n\t\tthis.targetElement = targetElement;\n\n\t\tthis.touchStartX = touch.pageX;\n\t\tthis.touchStartY = touch.pageY;\n\n\t\t// Prevent phantom clicks on fast double-tap (issue #36)\n\t\tif ((event.timeStamp - this.lastClickTime) < this.tapDelay) {\n\t\t\tevent.preventDefault();\n\t\t}\n\n\t\treturn true;\n\t};\n\n\n\t/**\n\t * Based on a touchmove event object, check whether the touch has moved past a boundary since it started.\n\t *\n\t * @param {Event} event\n\t * @returns {boolean}\n\t */\n\tFastClick.prototype.touchHasMoved = function(event) {\n\t\tvar touch = event.changedTouches[0], boundary = this.touchBoundary;\n\n\t\tif (Math.abs(touch.pageX - this.touchStartX) > boundary || Math.abs(touch.pageY - this.touchStartY) > boundary) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t};\n\n\n\t/**\n\t * Update the last position.\n\t *\n\t * @param {Event} event\n\t * @returns {boolean}\n\t */\n\tFastClick.prototype.onTouchMove = function(event) {\n\t\tif (!this.trackingClick) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// If the touch has moved, cancel the click tracking\n\t\tif (this.targetElement !== this.getTargetElementFromEventTarget(event.target) || this.touchHasMoved(event)) {\n\t\t\tthis.trackingClick = false;\n\t\t\tthis.targetElement = null;\n\t\t}\n\n\t\treturn true;\n\t};\n\n\n\t/**\n\t * Attempt to find the labelled control for the given label element.\n\t *\n\t * @param {EventTarget|HTMLLabelElement} labelElement\n\t * @returns {Element|null}\n\t */\n\tFastClick.prototype.findControl = function(labelElement) {\n\n\t\t// Fast path for newer browsers supporting the HTML5 control attribute\n\t\tif (labelElement.control !== undefined) {\n\t\t\treturn labelElement.control;\n\t\t}\n\n\t\t// All browsers under test that support touch events also support the HTML5 htmlFor attribute\n\t\tif (labelElement.htmlFor) {\n\t\t\treturn document.getElementById(labelElement.htmlFor);\n\t\t}\n\n\t\t// If no for attribute exists, attempt to retrieve the first labellable descendant element\n\t\t// the list of which is defined here: http://www.w3.org/TR/html5/forms.html#category-label\n\t\treturn labelElement.querySelector('button, input:not([type=hidden]), keygen, meter, output, progress, select, textarea');\n\t};\n\n\n\t/**\n\t * On touch end, determine whether to send a click event at once.\n\t *\n\t * @param {Event} event\n\t * @returns {boolean}\n\t */\n\tFastClick.prototype.onTouchEnd = function(event) {\n\t\tvar forElement, trackingClickStart, targetTagName, scrollParent, touch, targetElement = this.targetElement;\n\n\t\tif (!this.trackingClick) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Prevent phantom clicks on fast double-tap (issue #36)\n\t\tif ((event.timeStamp - this.lastClickTime) < this.tapDelay) {\n\t\t\tthis.cancelNextClick = true;\n\t\t\treturn true;\n\t\t}\n\n\t\tif ((event.timeStamp - this.trackingClickStart) > this.tapTimeout) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Reset to prevent wrong click cancel on input (issue #156).\n\t\tthis.cancelNextClick = false;\n\n\t\tthis.lastClickTime = event.timeStamp;\n\n\t\ttrackingClickStart = this.trackingClickStart;\n\t\tthis.trackingClick = false;\n\t\tthis.trackingClickStart = 0;\n\n\t\t// On some iOS devices, the targetElement supplied with the event is invalid if the layer\n\t\t// is performing a transition or scroll, and has to be re-detected manually. Note that\n\t\t// for this to function correctly, it must be called *after* the event target is checked!\n\t\t// See issue #57; also filed as rdar://13048589 .\n\t\tif (deviceIsIOSWithBadTarget) {\n\t\t\ttouch = event.changedTouches[0];\n\n\t\t\t// In certain cases arguments of elementFromPoint can be negative, so prevent setting targetElement to null\n\t\t\ttargetElement = document.elementFromPoint(touch.pageX - window.pageXOffset, touch.pageY - window.pageYOffset) || targetElement;\n\t\t\ttargetElement.fastClickScrollParent = this.targetElement.fastClickScrollParent;\n\t\t}\n\n\t\ttargetTagName = targetElement.tagName.toLowerCase();\n\t\tif (targetTagName === 'label') {\n\t\t\tforElement = this.findControl(targetElement);\n\t\t\tif (forElement) {\n\t\t\t\tthis.focus(targetElement);\n\t\t\t\tif (deviceIsAndroid) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\ttargetElement = forElement;\n\t\t\t}\n\t\t} else if (this.needsFocus(targetElement)) {\n\n\t\t\t// Case 1: If the touch started a while ago (best guess is 100ms based on tests for issue #36) then focus will be triggered anyway. Return early and unset the target element reference so that the subsequent click will be allowed through.\n\t\t\t// Case 2: Without this exception for input elements tapped when the document is contained in an iframe, then any inputted text won't be visible even though the value attribute is updated as the user types (issue #37).\n\t\t\tif ((event.timeStamp - trackingClickStart) > 100 || (deviceIsIOS && window.top !== window && targetTagName === 'input')) {\n\t\t\t\tthis.targetElement = null;\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tthis.focus(targetElement);\n\t\t\tthis.sendClick(targetElement, event);\n\n\t\t\t// Select elements need the event to go through on iOS 4, otherwise the selector menu won't open.\n\t\t\t// Also this breaks opening selects when VoiceOver is active on iOS6, iOS7 (and possibly others)\n\t\t\tif (!deviceIsIOS || targetTagName !== 'select') {\n\t\t\t\tthis.targetElement = null;\n\t\t\t\tevent.preventDefault();\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\tif (deviceIsIOS && !deviceIsIOS4) {\n\n\t\t\t// Don't send a synthetic click event if the target element is contained within a parent layer that was scrolled\n\t\t\t// and this tap is being used to stop the scrolling (usually initiated by a fling - issue #42).\n\t\t\tscrollParent = targetElement.fastClickScrollParent;\n\t\t\tif (scrollParent && scrollParent.fastClickLastScrollTop !== scrollParent.scrollTop) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\t// Prevent the actual click from going though - unless the target node is marked as requiring\n\t\t// real clicks or if it is in the whitelist in which case only non-programmatic clicks are permitted.\n\t\tif (!this.needsClick(targetElement)) {\n\t\t\tevent.preventDefault();\n\t\t\tthis.sendClick(targetElement, event);\n\t\t}\n\n\t\treturn false;\n\t};\n\n\n\t/**\n\t * On touch cancel, stop tracking the click.\n\t *\n\t * @returns {void}\n\t */\n\tFastClick.prototype.onTouchCancel = function() {\n\t\tthis.trackingClick = false;\n\t\tthis.targetElement = null;\n\t};\n\n\n\t/**\n\t * Determine mouse events which should be permitted.\n\t *\n\t * @param {Event} event\n\t * @returns {boolean}\n\t */\n\tFastClick.prototype.onMouse = function(event) {\n\n\t\t// If a target element was never set (because a touch event was never fired) allow the event\n\t\tif (!this.targetElement) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif (event.forwardedTouchEvent) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Programmatically generated events targeting a specific element should be permitted\n\t\tif (!event.cancelable) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Derive and check the target element to see whether the mouse event needs to be permitted;\n\t\t// unless explicitly enabled, prevent non-touch click events from triggering actions,\n\t\t// to prevent ghost/doubleclicks.\n\t\tif (!this.needsClick(this.targetElement) || this.cancelNextClick) {\n\n\t\t\t// Prevent any user-added listeners declared on FastClick element from being fired.\n\t\t\tif (event.stopImmediatePropagation) {\n\t\t\t\tevent.stopImmediatePropagation();\n\t\t\t} else {\n\n\t\t\t\t// Part of the hack for browsers that don't support Event#stopImmediatePropagation (e.g. Android 2)\n\t\t\t\tevent.propagationStopped = true;\n\t\t\t}\n\n\t\t\t// Cancel the event\n\t\t\tevent.stopPropagation();\n\t\t\tevent.preventDefault();\n\n\t\t\treturn false;\n\t\t}\n\n\t\t// If the mouse event is permitted, return true for the action to go through.\n\t\treturn true;\n\t};\n\n\n\t/**\n\t * On actual clicks, determine whether this is a touch-generated click, a click action occurring\n\t * naturally after a delay after a touch (which needs to be cancelled to avoid duplication), or\n\t * an actual click which should be permitted.\n\t *\n\t * @param {Event} event\n\t * @returns {boolean}\n\t */\n\tFastClick.prototype.onClick = function(event) {\n\t\tvar permitted;\n\n\t\t// It's possible for another FastClick-like library delivered with third-party code to fire a click event before FastClick does (issue #44). In that case, set the click-tracking flag back to false and return early. This will cause onTouchEnd to return early.\n\t\tif (this.trackingClick) {\n\t\t\tthis.targetElement = null;\n\t\t\tthis.trackingClick = false;\n\t\t\treturn true;\n\t\t}\n\n\t\t// Very odd behaviour on iOS (issue #18): if a submit element is present inside a form and the user hits enter in the iOS simulator or clicks the Go button on the pop-up OS keyboard the a kind of 'fake' click event will be triggered with the submit-type input element as the target.\n\t\tif (event.target.type === 'submit' && event.detail === 0) {\n\t\t\treturn true;\n\t\t}\n\n\t\tpermitted = this.onMouse(event);\n\n\t\t// Only unset targetElement if the click is not permitted. This will ensure that the check for !targetElement in onMouse fails and the browser's click doesn't go through.\n\t\tif (!permitted) {\n\t\t\tthis.targetElement = null;\n\t\t}\n\n\t\t// If clicks are permitted, return true for the action to go through.\n\t\treturn permitted;\n\t};\n\n\n\t/**\n\t * Remove all FastClick's event listeners.\n\t *\n\t * @returns {void}\n\t */\n\tFastClick.prototype.destroy = function() {\n\t\tvar layer = this.layer;\n\n\t\tif (deviceIsAndroid) {\n\t\t\tlayer.removeEventListener('mouseover', this.onMouse, true);\n\t\t\tlayer.removeEventListener('mousedown', this.onMouse, true);\n\t\t\tlayer.removeEventListener('mouseup', this.onMouse, true);\n\t\t}\n\n\t\tlayer.removeEventListener('click', this.onClick, true);\n\t\tlayer.removeEventListener('touchstart', this.onTouchStart, false);\n\t\tlayer.removeEventListener('touchmove', this.onTouchMove, false);\n\t\tlayer.removeEventListener('touchend', this.onTouchEnd, false);\n\t\tlayer.removeEventListener('touchcancel', this.onTouchCancel, false);\n\t};\n\n\n\t/**\n\t * Check whether FastClick is needed.\n\t *\n\t * @param {Element} layer The layer to listen on\n\t */\n\tFastClick.notNeeded = function(layer) {\n\t\tvar metaViewport;\n\t\tvar chromeVersion;\n\t\tvar blackberryVersion;\n\t\tvar firefoxVersion;\n\n\t\t// Devices that don't support touch don't need FastClick\n\t\tif (typeof window.ontouchstart === 'undefined') {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Chrome version - zero for other browsers\n\t\tchromeVersion = +(/Chrome\\/([0-9]+)/.exec(navigator.userAgent) || [,0])[1];\n\n\t\tif (chromeVersion) {\n\n\t\t\tif (deviceIsAndroid) {\n\t\t\t\tmetaViewport = document.querySelector('meta[name=viewport]');\n\n\t\t\t\tif (metaViewport) {\n\t\t\t\t\t// Chrome on Android with user-scalable=\"no\" doesn't need FastClick (issue #89)\n\t\t\t\t\tif (metaViewport.content.indexOf('user-scalable=no') !== -1) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t\t// Chrome 32 and above with width=device-width or less don't need FastClick\n\t\t\t\t\tif (chromeVersion > 31 && document.documentElement.scrollWidth <= window.outerWidth) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t// Chrome desktop doesn't need FastClick (issue #15)\n\t\t\t} else {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\tif (deviceIsBlackBerry10) {\n\t\t\tblackberryVersion = navigator.userAgent.match(/Version\\/([0-9]*)\\.([0-9]*)/);\n\n\t\t\t// BlackBerry 10.3+ does not require Fastclick library.\n\t\t\t// https://github.com/ftlabs/fastclick/issues/251\n\t\t\tif (blackberryVersion[1] >= 10 && blackberryVersion[2] >= 3) {\n\t\t\t\tmetaViewport = document.querySelector('meta[name=viewport]');\n\n\t\t\t\tif (metaViewport) {\n\t\t\t\t\t// user-scalable=no eliminates click delay.\n\t\t\t\t\tif (metaViewport.content.indexOf('user-scalable=no') !== -1) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t\t// width=device-width (or less than device-width) eliminates click delay.\n\t\t\t\t\tif (document.documentElement.scrollWidth <= window.outerWidth) {\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\n\t\t// IE10 with -ms-touch-action: none or manipulation, which disables double-tap-to-zoom (issue #97)\n\t\tif (layer.style.msTouchAction === 'none' || layer.style.touchAction === 'manipulation') {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Firefox version - zero for other browsers\n\t\tfirefoxVersion = +(/Firefox\\/([0-9]+)/.exec(navigator.userAgent) || [,0])[1];\n\n\t\tif (firefoxVersion >= 27) {\n\t\t\t// Firefox 27+ does not have tap delay if the content is not zoomable - https://bugzilla.mozilla.org/show_bug.cgi?id=922896\n\n\t\t\tmetaViewport = document.querySelector('meta[name=viewport]');\n\t\t\tif (metaViewport && (metaViewport.content.indexOf('user-scalable=no') !== -1 || document.documentElement.scrollWidth <= window.outerWidth)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\t// IE11: prefixed -ms-touch-action is no longer supported and it's recomended to use non-prefixed version\n\t\t// http://msdn.microsoft.com/en-us/library/windows/apps/Hh767313.aspx\n\t\tif (layer.style.touchAction === 'none' || layer.style.touchAction === 'manipulation') {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t};\n\n\n\t/**\n\t * Factory method for creating a FastClick object\n\t *\n\t * @param {Element} layer The layer to listen on\n\t * @param {Object} [options={}] The options to override the defaults\n\t */\n\tFastClick.attach = function(layer, options) {\n\t\treturn new FastClick(layer, options);\n\t};\n\n\n\tif (typeof define === 'function' && typeof define.amd === 'object' && define.amd) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine(function() {\n\t\t\treturn FastClick;\n\t\t});\n\t} else if (typeof module !== 'undefined' && module.exports) {\n\t\tmodule.exports = FastClick.attach;\n\t\tmodule.exports.FastClick = FastClick;\n\t} else {\n\t\twindow.FastClick = FastClick;\n\t}\n}());\n"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/adminlte/plugins/iCheck/square/blue.css",
    "content": "/* iCheck plugin Square skin, blue\n----------------------------------- */\n.icheckbox_square-blue,\n.iradio_square-blue {\n    display: inline-block;\n    *display: inline;\n    vertical-align: middle;\n    margin: 0;\n    padding: 0;\n    width: 22px;\n    height: 22px;\n    background: url(blue.png) no-repeat;\n    border: none;\n    cursor: pointer;\n}\n\n.icheckbox_square-blue {\n    background-position: 0 0;\n}\n    .icheckbox_square-blue.hover {\n        background-position: -24px 0;\n    }\n    .icheckbox_square-blue.checked {\n        background-position: -48px 0;\n    }\n    .icheckbox_square-blue.disabled {\n        background-position: -72px 0;\n        cursor: default;\n    }\n    .icheckbox_square-blue.checked.disabled {\n        background-position: -96px 0;\n    }\n\n.iradio_square-blue {\n    background-position: -120px 0;\n}\n    .iradio_square-blue.hover {\n        background-position: -144px 0;\n    }\n    .iradio_square-blue.checked {\n        background-position: -168px 0;\n    }\n    .iradio_square-blue.disabled {\n        background-position: -192px 0;\n        cursor: default;\n    }\n    .iradio_square-blue.checked.disabled {\n        background-position: -216px 0;\n    }\n\n/* Retina support */\n@media only screen and (-webkit-min-device-pixel-ratio: 1.5),\n       only screen and (-moz-min-device-pixel-ratio: 1.5),\n       only screen and (-o-min-device-pixel-ratio: 3/2),\n       only screen and (min-device-pixel-ratio: 1.5) {\n    .icheckbox_square-blue,\n    .iradio_square-blue {\n        background-image: url(blue@2x.png);\n        -webkit-background-size: 240px 24px;\n        background-size: 240px 24px;\n    }\n}"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/biz/common/admin.setting.js",
    "content": "/*!\n* Admin Setting for XXL-BOOT\n* ================\n*\n* 1、logout：         退出登录\n* 2、updatePwd：      修改密码\n* 3、slideToTop：     回到顶部\n* 4、change skin：    切换皮肤\n* 5、menu/sidebar-toggle： 菜单/侧边来，展示切换\n*\n* @author       xuxueli\n* @repository   https://github.com/xuxueli/xxl-boot\n*/\n$(function(){\n\n    // ---------------------- logout ----------------------\n\n    /**\n     * logout\n     */\n    $(\"#logoutBtn\").click(function(){\n        layer.confirm( I18n.logout_confirm , {\n            icon: 3,\n            title: I18n.system_tips ,\n            btn: [ I18n.system_ok, I18n.system_cancel ]\n        }, function(index){\n            layer.close(index);\n\n            $.post(base_url + \"/auth/logout\", function(data, status) {\n                if (data.code == \"200\") {\n                    layer.msg( I18n.logout_success );\n                    setTimeout(function(){\n                        window.location.href = base_url + \"/\";\n                    }, 500);\n                } else {\n                    layer.open({\n                        title: I18n.system_tips ,\n                        btn: [ I18n.system_ok ],\n                        content: (data.msg || I18n.logout_fail),\n                        icon: '2'\n                    });\n                }\n            });\n        });\n\n    });\n\n    // ---------------------- update pwd ----------------------\n\n    /**\n     * updatePwd Modal\n     */\n    let updatePwd = $(`\n        <!-- 修改密码.模态框 -->\n        <div class=\"modal fade\" id=\"updatePwdModal\" tabindex=\"-1\" role=\"dialog\"  aria-hidden=\"true\">\n            <div class=\"modal-dialog \">\n                <div class=\"modal-content\">\n                    <div class=\"modal-header\">\n                        <button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\"><span aria-hidden=\"true\">×</span></button>\n                        <h4 class=\"modal-title\" >` + I18n.change_pwd +`</h4>\n                    </div>\n                    <div class=\"modal-body\">\n                        <form class=\"form-horizontal form\" role=\"form\" >\n                            <div class=\"form-group\">\n                                <label for=\"lastname\" class=\"col-sm-2 control-label\">` + I18n.change_pwd_field_oldpwd +`<font color=\"red\">*</font></label>\n                                <div class=\"col-sm-10\"><input type=\"text\" class=\"form-control\" name=\"oldPassword\" placeholder=\"` + I18n.system_please_input + I18n.change_pwd_field_oldpwd + `\" maxlength=\"20\" ></div>\n                            </div>\n                            <div class=\"form-group\">\n                                <label for=\"lastname\" class=\"col-sm-2 control-label\">` + I18n.change_pwd_field_newpwd +` <font color=\"red\">*</font></label>\n                                <div class=\"col-sm-10\"><input type=\"text\" class=\"form-control\" name=\"password\" placeholder=\"` + I18n.system_please_input + I18n.change_pwd_field_newpwd + `\" maxlength=\"20\" ></div>\n                            </div>\n                            <hr>\n                            <div class=\"form-group\">\n                                <div class=\"col-sm-offset-3 col-sm-6\">\n                                    <button type=\"submit\" class=\"btn btn-primary\"  >` + I18n.system_save +`</button>\n                                    <button type=\"button\" class=\"btn btn-default\" data-dismiss=\"modal\">` + I18n.system_cancel +`</button>\n                                </div>\n                            </div>\n                        </form>\n                    </div>\n                </div>\n            </div>\n        </div>\n    `);\n    $('.wrapper').append(updatePwd);\n\n    /**\n     * updatePwd\n     */\n    $('#updatePwd').on('click', function(){\n        $('#updatePwdModal').modal({backdrop: false, keyboard: false}).modal('show');\n    });\n    var updatePwdModalValidate = $(\"#updatePwdModal .form\").validate({\n        errorElement : 'span',\n        errorClass : 'help-block',\n        focusInvalid : true,\n        rules : {\n            oldPassword : {\n                required : true ,\n                rangelength:[4,50]\n            },\n            password : {\n                required : true ,\n                rangelength:[4,50]\n            }\n        },\n        messages : {\n            oldPassword : {\n                required : I18n.system_please_input +I18n.change_pwd_field_oldpwd,\n                rangelength : \"密码长度限制为4~50\"\n            },\n            password : {\n                required : I18n.system_please_input +I18n.change_pwd_field_newpwd,\n                rangelength : \"密码长度限制为4~50\"\n            }\n        },\n        highlight : function(element) {\n            $(element).closest('.form-group').addClass('has-error');\n        },\n        success : function(label) {\n            label.closest('.form-group').removeClass('has-error');\n            label.remove();\n        },\n        errorPlacement : function(error, element) {\n            element.parent('div').append(error);\n        },\n        submitHandler : function(form) {\n            $.post(base_url + \"/auth/updatePwd\",  $(\"#updatePwdModal .form\").serialize(), function(data, status) {\n                if (data.code == 200) {\n                    $('#updatePwdModal').modal('hide');\n\n                    layer.msg( I18n.change_pwd_suc_to_logout );\n                    setTimeout(function(){\n                        $.post(base_url + \"/auth/logout\", function(data, status) {\n                            if (data.code == 200) {\n                                window.location.href = base_url + \"/\";\n                            } else {\n                                layer.open({\n                                    icon: '2',\n                                    content: (data.msg|| I18n.logout_fail)\n                                });\n                            }\n                        });\n                    }, 500);\n                } else {\n                    layer.open({\n                        icon: '2',\n                        content: (data.msg|| I18n.change_pwd + I18n.system_fail )\n                    });\n                }\n            });\n        }\n    });\n    $(\"#updatePwdModal\").on('hide.bs.modal', function () {\n        $(\"#updatePwdModal .form\")[0].reset();\n        updatePwdModalValidate.resetForm();\n        $(\"#updatePwdModal .form .form-group\").removeClass(\"has-error\");\n    });\n\n    // ---------------------- slideToTop ----------------------\n\n    /**\n     * slideToTop Html\n     */\n    var slideToTop = $(\"<div />\");\n    slideToTop.html('<i class=\"fa fa-chevron-up\"></i>');\n    slideToTop.css({\n        position: 'fixed',\n        bottom: '20px',\n        right: '25px',\n        width: '40px',\n        height: '40px',\n        color: '#eee',\n        'font-size': '',\n        'line-height': '40px',\n        'text-align': 'center',\n        'background-color': '#222d32',\n        cursor: 'pointer',\n        'border-radius': '5px',\n        'z-index': '99999',\n        opacity: '.7',\n        'display': 'none'\n    });\n    slideToTop.on('mouseenter', function () {\n        $(this).css('opacity', '1');\n    });\n    slideToTop.on('mouseout', function () {\n        $(this).css('opacity', '.7');\n    });\n    $('.wrapper').append(slideToTop);\n    $(window).scroll(function () {\n        if ($(window).scrollTop() >= 150) {\n            if (!$(slideToTop).is(':visible')) {\n                $(slideToTop).fadeIn(500);\n            }\n        } else {\n            $(slideToTop).fadeOut(500);\n        }\n    });\n\n    /**\n     * slideToTop click\n     */\n    $(slideToTop).click(function () {\n        $(\"html,body\").animate({\t\t// firefox ie not support body, chrome support body. but found that new version chrome not support body too.\n            scrollTop: 0\n        }, 100);\n    });\n\n    // ---------------------- change skin ----------------------\n\n    /**\n     * skinModal\n     */\n    let skinModal = $(`\n        <!-- 主题切换.模态框 -->\n        <div class=\"modal fade\" id=\"skinModal\" tabindex=\"-1\" role=\"dialog\"  aria-hidden=\"true\">\n            <div class=\"modal-dialog \">\n                <div class=\"modal-content\">\n                    <div class=\"modal-header\">\n                        <button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\"><span aria-hidden=\"true\">×</span></button>\n                        <h4 class=\"modal-title\" >` + I18n.change_skin +`</h4>\n                    </div>\n                    <div class=\"modal-body\">\n                        <!-- 主题列表 -->\n                        <ul class=\"list-unstyled clearfix\" >\n                            <!-- level 1 -->\n                            <li style=\"float:left; width: 33.33333%; padding: 5px;\">\n                                <a href=\"javascript:\" data-skin='skin-blue' style=\"display: block; box-shadow: 0 0 3px rgba(0,0,0,0.4)\" class=\"clearfix full-opacity-hover\">\n                                    <span style=\"width: 20%; float: left; height: 13px; background: #367fa9\"></span>\n                                    <span style=\"width: 80%; float: left; height: 13px;\" class='bg-light-blue'></span>\n                                    <span style=\"width: 20%; float: left; height: 30px; background: #222d32\"></span>\n                                    <span style=\"width: 80%; float: left; height: 30px; background: #f4f5f7\"></span>\n                                </a>\n                                <p class=\"text-center\">Blue</p>\n                            </li>\n                            <li style=\"float:left; width: 33.33333%; padding: 5px;\">\n                                <a href=\"javascript:\" data-skin=\"skin-black\" style=\"display: block; box-shadow: 0 0 3px rgba(0,0,0,0.4)\" class=\"clearfix full-opacity-hover\">\n                                    <span style=\"width: 20%; float: left; height: 13px; background: #fefefe\"></span>\n                                    <span style=\"width: 80%; float: left; height: 13px; background: #fefefe\"></span>\n                                    <span style=\"width: 20%; float: left; height: 30px; background: #222d32\"></span>\n                                    <span style=\"width: 80%; float: left; height: 30px; background: #f4f5f7\"></span>\n                                </a>\n                                <p class=\"text-center\">Black</p>\n                            </li>\n                            <li style=\"float:left; width: 33.33333%; padding: 5px;\">\n                                <a href=\"javascript:\" data-skin=\"skin-purple\" style=\"display: block; box-shadow: 0 0 3px rgba(0,0,0,0.4)\" class=\"clearfix full-opacity-hover\">\n                                    <span style=\"width: 20%; float: left; height: 13px;\" class='bg-purple-active'></span>\n                                    <span style=\"width: 80%; float: left; height: 13px;\" class='bg-purple'></span>\n                                    <span style=\"width: 20%; float: left; height: 30px; background: #222d32\"></span>\n                                    <span style=\"width: 80%; float: left; height: 30px; background: #f4f5f7\"></span>\n                                </a>\n                                <p class=\"text-center\">Purple</p>\n                            </li>\n                            \n                            <!-- level 2 -->\n                            <li style=\"float:left; width: 33.33333%; padding: 5px;\">\n                                <a href=\"javascript:\" data-skin=\"skin-green\" style=\"display: block; box-shadow: 0 0 3px rgba(0,0,0,0.4)\" class=\"clearfix full-opacity-hover\">\n                                    <span style=\"width: 20%; float: left; height: 13px;\" class='bg-green-active'></span>\n                                    <span style=\"width: 80%; float: left; height: 13px;\" class='bg-green'></span>\n                                    <span style=\"width: 20%; float: left; height: 30px; background: #222d32\"></span>\n                                    <span style=\"width: 80%; float: left; height: 30px; background: #f4f5f7\"></span>\n                                </a>\n                                <p class=\"text-center\">Green</p>\n                            </li>\n                            <li style=\"float:left; width: 33.33333%; padding: 5px;\">\n                                <a href=\"javascript:\" data-skin=\"skin-red\" style=\"display: block; box-shadow: 0 0 3px rgba(0,0,0,0.4)\" class=\"clearfix full-opacity-hover\">\n                                    <span style=\"width: 20%; float: left; height: 13px;\" class='bg-red-active'></span>\n                                    <span style=\"width: 80%; float: left; height: 13px;\" class='bg-red'></span>\n                                    <span style=\"width: 20%; float: left; height: 30px; background: #222d32\"></span>\n                                    <span style=\"width: 80%; float: left; height: 30px; background: #f4f5f7\"></span>\n                                </a>\n                                <p class=\"text-center\">Red</p>\n                            </li>\n                            <li style=\"float:left; width: 33.33333%; padding: 5px;\">\n                                <a href=\"javascript:\" data-skin=\"skin-yellow\" style=\"display: block; box-shadow: 0 0 3px rgba(0,0,0,0.4)\" class=\"clearfix full-opacity-hover\">\n                                    <span style=\"width: 20%; float: left; height: 13px;\" class='bg-yellow-active'></span>\n                                    <span style=\"width: 80%; float: left; height: 13px;\" class='bg-yellow'></span>\n                                    <span style=\"width: 20%; float: left; height: 30px; background: #222d32\"></span>\n                                    <span style=\"width: 80%; float: left; height: 30px; background: #f4f5f7\"></span>\n                                </a>\n                                <p class=\"text-center\">Yellow</p>\n                            </li>\n                            \n                            <!-- level 3 -->\n                            <li style=\"float:left; width: 33.33333%; padding: 5px;\">\n                                <a href=\"javascript:\" data-skin=\"skin-blue-light\" style=\"display: block; box-shadow: 0 0 3px rgba(0,0,0,0.4)\" class=\"clearfix full-opacity-hover\">\n                                    <span style=\"width: 20%; float: left; height: 13px; background: #367fa9\"></span>\n                                    <span style=\"width: 80%; float: left; height: 13px;\" class='bg-light-blue'></span>\n                                    <span style=\"width: 20%; float: left; height: 30px; background: #f9fafc\"></span>\n                                    <span style=\"width: 80%; float: left; height: 30px; background: #f4f5f7\"></span>\n                                </a>\n                                <p class=\"text-center\">Blue(Light)</p>\n                            </li>\n                            <li style=\"float:left; width: 33.33333%; padding: 5px;\">\n                                <a href=\"javascript:\" data-skin=\"skin-black-light\" style=\"display: block; box-shadow: 0 0 3px rgba(0,0,0,0.4)\" class=\"clearfix full-opacity-hover\">\n                                    <span style=\"width: 20%; float: left; height: 13px; background: #fefefe\"></span>\n                                    <span style=\"width: 80%; float: left; height: 13px; background: #fefefe\"></span>\n                                    <span style=\"width: 20%; float: left; height: 30px; background: #f9fafc\"></span>\n                                    <span style=\"width: 80%; float: left; height: 30px; background: #f4f5f7\"></span>\n                                </a>\n                                <p class=\"text-center\">Black(Light)</p>\n                            </li>\n                            <li style=\"float:left; width: 33.33333%; padding: 5px;\">\n                                <a href=\"javascript:\" data-skin=\"skin-purple-light\" style=\"display: block; box-shadow: 0 0 3px rgba(0,0,0,0.4)\" class=\"clearfix full-opacity-hover\">\n                                    <span style=\"width: 20%; float: left; height: 13px;\" class='bg-purple-active'></span>\n                                    <span style=\"width: 80%; float: left; height: 13px;\" class='bg-purple'></span>\n                                    <span style=\"width: 20%; float: left; height: 30px; background: #f9fafc\"></span>\n                                    <span style=\"width: 80%; float: left; height: 30px; background: #f4f5f7\"></span>\n                                </a>\n                                <p class=\"text-center\">Purple(Light)</p>\n                            </li>\n                            \n                            <!-- level 4 -->\n                            <li style=\"float:left; width: 33.33333%; padding: 5px;\">\n                                <a href=\"javascript:\" data-skin=\"skin-green-light\" style=\"display: block; box-shadow: 0 0 3px rgba(0,0,0,0.4)\" class=\"clearfix full-opacity-hover\">\n                                    <span style=\"width: 20%; float: left; height: 13px;\" class='bg-green-active'></span>\n                                    <span style=\"width: 80%; float: left; height: 13px;\" class='bg-green'></span>\n                                    <span style=\"width: 20%; float: left; height: 30px; background: #f9fafc\"></span>\n                                    <span style=\"width: 80%; float: left; height: 30px; background: #f4f5f7\"></span>\n                                </a>\n                                <p class=\"text-center\">Green(Light)</p>\n                            </li>\n                            <li style=\"float:left; width: 33.33333%; padding: 5px;\">\n                                <a href=\"javascript:\" data-skin=\"skin-red-light\" style=\"display: block; box-shadow: 0 0 3px rgba(0,0,0,0.4)\" class=\"clearfix full-opacity-hover\">\n                                    <span style=\"width: 20%; float: left; height: 13px;\" class='bg-red-active'></span>\n                                    <span style=\"width: 80%; float: left; height: 13px;\" class='bg-red'></span>\n                                    <span style=\"width: 20%; float: left; height: 30px; background: #f9fafc\"></span>\n                                    <span style=\"width: 80%; float: left; height: 30px; background: #f4f5f7\"></span>\n                                </a>\n                                <p class=\"text-center\">Red(Light)</p>\n                            </li>\n                            <li style=\"float:left; width: 33.33333%; padding: 5px;\">\n                                <a href=\"javascript:\" data-skin=\"skin-yellow-light\" style=\"display: block; box-shadow: 0 0 3px rgba(0,0,0,0.4)\" class=\"clearfix full-opacity-hover\">\n                                    <span style=\"width: 20%; float: left; height: 13px;\" class='bg-yellow-active'></span>\n                                    <span style=\"width: 80%; float: left; height: 13px;\" class='bg-yellow'></span>\n                                    <span style=\"width: 20%; float: left; height: 30px; background: #f9fafc\"></span>\n                                    <span style=\"width: 80%; float: left; height: 30px; background: #f4f5f7\"></span>\n                                </a>\n                                <p class=\"text-center\">Yellow(Light)</p>\n                            </li>\n                            \n                            <!-- style -->\n                            <style>\n                                .list-unstyled{margin:10px;}\n                                .full-opacity-hover{opacity:1;filter:alpha(opacity=1);border:1px solid #fff}\n                                .full-opacity-hover:hover{border:1px solid silver;}\n                            </style>\n                        </ul>\n                    </div>\n                </div>\n            </div>\n        </div>\n    `);\n    $('.wrapper').append(skinModal);\n\n    /**\n     * skin opt\n     */\n    $('#changeSkin').on('click', function(){\n        $('#skinModal').modal({backdrop: true, keyboard: false}).modal('show');\n    });\n\n    /**\n     * skin list\n     */\n    var skins = [\n        \"skin-blue\",\n        \"skin-black\",\n        \"skin-purple\",\n        \"skin-green\",\n        \"skin-red\",\n        \"skin-yellow\",\n        \"skin-blue-light\",\n        \"skin-black-light\",\n        \"skin-purple-light\",\n        \"skin-green-light\",\n        \"skin-red-light\",\n        \"skin-yellow-light\"\n    ];\n\n    /**\n     * skin change\n     */\n    $(\"[data-skin]\").on('click', function(e) {\n        var skin = $(this).data('skin');\n        $.each(skins, function (i) {\n            $(\"body\").removeClass(skins[i]);\n        });\n        $(\"body\").addClass(skin);\n        store('admin_skin', skin);\n        return false;\n    });\n\n    /**\n     * skin init\n     */\n    let skin = loadStore('admin_skin');\n    if (skin) {\n        $.each(skins, function (i) {\n            $(\"body\").removeClass(skins[i]);\n        });\n        $(\"body\").addClass(skin);\n    }\n\n    // ---------------------- localStorage ----------------------\n\n    /**\n     * store\n     */\n    function store(name, val) {\n        if (typeof (Storage) !== \"undefined\") {\n            localStorage.setItem(name, val);\n        } else {\n            window.alert('Please use a modern browser to properly view this template!');\n        }\n    }\n\n    /**\n     * get\n     */\n    function loadStore(name) {\n        if (typeof (Storage) !== \"undefined\") {\n            return localStorage.getItem(name);\n        } else {\n            window.alert('Please use a modern browser to properly view this template!');\n        }\n    }\n\n    // ---------------------- menu, sidebar-toggle ----------------------\n\n    // init menu speed\n    $('.sidebar-menu').attr('data-animation-speed', 1);\n\n    // init menu status\n    let sidebar = loadStore('admin_sidebar_status');\n    if ( 'close' === sidebar ) {\n        $('body').addClass('sidebar-collapse');\n    } else {\n        $('body').removeClass('sidebar-collapse');\n    }\n\n    // change menu status\n    $('.sidebar-toggle').click(function(){\n        if ( 'close' === loadStore('admin_sidebar_status') ) {\n            store('admin_sidebar_status', 'open')\n        } else {\n            store('admin_sidebar_status', 'close')\n        }\n    });\n\n});\n"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/biz/common/admin.tab.css",
    "content": "/* admin tab start */\nhtml,\nbody {\n    height: 100% !important;\n    min-height: 0px !important;\n}\n\nbody .wrapper{\n    height: 100% !important;\n    min-height: 0px !important;\n}\n\nbody .content-wrapper{\n    /*for footer*/\n    height:calc(100% - 36px);\n}\n\nbody .sidebar{\n    overflow: hidden;\n}\n\n.content-tabs {\n    position: relative;\n    height: 35px;\n    background: #fafafa;\n    line-height: 35px;\n}\n\n.content-tabs .roll-nav,\n.page-tabs-list {\n    position: absolute;\n    width: 40px;\n    height: 35px;\n    text-align: center;\n    color: #999;\n    z-index: 2;\n    top: 0;\n}\n\n.content-tabs .roll-left {\n    left: 0;\n    border-right: solid 1px #eee;\n}\n\n.content-tabs .roll-right {\n    right: 0;\n    border-left: solid 1px #eee;\n}\n\n.content-tabs button {\n    background: #fff;\n    border: 0;\n    height: 35px;\n    width: 40px;\n    outline: none;\n}\n\n.content-tabs button:hover {\n    background: #fafafa;\n}\n\nnav.page-tabs {\n    margin-left: 40px;\n    width: 100000px;\n    height: 35px;\n    overflow: hidden;\n}\n\nnav.page-tabs .page-tabs-content {\n    float: left;\n}\n\n.page-tabs a {\n    display: block;\n    float: left;\n    border-right: solid 1px #eee;\n    padding: 0 15px;\n}\n\n.page-tabs a i:hover {\n    color: #c00;\n}\n\n.page-tabs a:hover,\n.content-tabs .roll-nav:hover {\n    color: #777;\n    background: #f2f2f2;\n    cursor: pointer;\n}\n\n.roll-right.J_tabRight {\n    right: 200px;\n}\n\n.roll-right.btn-group {\n    right: 120px;\n    width: 80px;\n    padding: 0;\n}\n\n.roll-right.btn-group button {\n    width: 80px;\n}\n\n.roll-right.J_tabExit, .roll-right.tabReload {\n    right: 60px;\n    background: #fff;\n    height: 35px;\n    width: 60px;\n    outline: none;\n}\n\n.roll-right.J_tabExit, .roll-right.fullscreen {\n    background: #fff;\n    height: 35px;\n    width: 60px;\n    outline: none;\n}\n\n.dropdown-menu-right {\n    left: auto;\n}\n\n#content-main {\n    height: calc(100% - 50px);\n    overflow: hidden;\n}\n\n.fixed-nav #content-main {\n    height: calc(100% - 80px);\n    overflow: hidden;\n}\n\n.content-tabs {\n    height: 37px;\n    border-bottom: solid 2px #d2d6de;\n}\n\n.page-tabs a {\n    color: #999;\n}\n\n.page-tabs a i {\n    color: #ccc;\n}\n\n.page-tabs a.active {\n    background: #2f4050;\n    color: #ccc;\n}\n\n.page-tabs a.active:hover,\n.page-tabs a.active i:hover {\n    background: #2f4050;\n    color: #fff;\n}\n\n/** 遮罩层 **/\n.loaderbox {\n    display: inline-block;\n    min-width: 125px;\n    padding: 10px;\n    margin: 0 auto;\n    color: #000 !important;\n    font-size: 13px;\n    font-weight: 400;\n    text-align: center;\n    vertical-align: middle;\n    border: 1px solid #ddd;\n    background-color: #eee;\n    -webkit-border-radius: 2px;\n    -moz-border-radius: 2px;\n    -ms-border-radius: 2px;\n    -o-border-radius: 2px;\n    border-radius: 2px;\n    -webkit-box-shadow: 0 1px 8px rgba(0, 0, 0, 0.1);\n    -moz-box-shadow: 0 1px 8px rgba(0, 0, 0, 0.1);\n    box-shadow: 0 1px 8px rgba(0, 0, 0, 0.1);\n}\n\n.loaderbox .loading-activity {\n    float: left;\n    width: 18px;\n    height: 18px;\n    border: solid 2px transparent;\n    border-top-color: #000;\n    border-left-color: #000;\n    border-radius: 10px;\n    -webkit-animation: pace-spinner 400ms linear infinite;\n    -moz-animation: pace-spinner 400ms linear infinite;\n    -ms-animation: pace-spinner 400ms linear infinite;\n    -o-animation: pace-spinner 400ms linear infinite;\n    animation: pace-spinner 400ms linear infinite;\n}\n\n.dropdown-menu {\n    min-width: 100px;\n}\n\n.main-footer {\n    height: 37px;\n    border-top: solid 2px #d2d6de;\n    padding: 8px 20px 12px 20px;\n}\n/* admin tab end */\n\n/* nprogress start */\n#nprogress .bar {\n    background: #FFFFFF !important;\n}\n#nprogress .peg {\n    box-shadow: 0 0 10px #FFFFFF, 0 0 5px #FFFFFF !important;\n}\n#nprogress .spinner-icon {\n    border-top-color: #FFFFFF !important;\n    border-left-color: #FFFFFF !important;\n}\n/* nprogress end */\n\n/* menu start */\n.treeview-menu>li>a {\n    padding-top: 8px;\n    padding-bottom: 8px;\n}\n/* menu end */\n"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/biz/common/admin.tab.js",
    "content": "/*!\n* Admin Tab for XXL-BOOT\n* ================\n*\n* 1、menu：\n*      - J_menuItem:        菜单\n* 2、tab：\n*      - J_tabLeft:         左移按扭\n*      - J_menuTabs:\n*          - J_menuTab :    菜单Tab\n*      - J_tabRight:        右移按扭\n*      - J_tabCloseOther:   关闭其他Tab\n*      - J_tabCloseAll :    关闭所有Tab\n* 3、contont\n*      - J_mainContent\n*          - J_iframe :     页面iframe\n*\n* @author       xuxueli\n* @repository   https://github.com/xuxueli/xxl-boot\n*/\n(function($) {\n\n    $.extend({\n        adminTab: {\n            initTab: function(options) {\n\n                /**\n                 * 点击菜单：打开Tab，展示Menu页面\n                 */\n                $('.J_menuItem').on('click', function (){\n                    // 获取Tab属性\n                    let tabSrc = $(this).attr('href');\n                    let tabName = $.trim($(this).text());\n\n                    // open tab\n                    return openTab(tabSrc, tabName);\n                });\n\n                /**\n                 * Tab关闭（x按钮）：关闭菜单页面\n                 */\n                $('.J_menuTabs').on('click', '.J_menuTab i', closeTab);\n\n                /**\n                 * Tab单击（切换/激活）：展示Tab页面 + 左侧菜单active更新\n                 */\n                $('.J_menuTabs').on('click', '.J_menuTab', activeTab);\n\n                /**\n                 * 选项卡-左移按扭：查看左侧隐藏的选项卡\n                 */\n                $('.J_tabLeft').on('click', scrollTabLeft);\n\n                /**\n                 * 选项卡-右移按扭：查看右侧隐藏的选项卡\n                 */\n                $('.J_tabRight').on('click', scrollTabRight);\n\n                /**\n                 * Tab-刷新按钮：刷新active的 Tab 页面\n                 */\n                $('.tabReload').on('click', refreshTab);\n\n                /**\n                 * 关闭其他选项卡\n                 */\n                $('.J_tabCloseOther').on('click', closeOtherTabs);\n\n                /**\n                 * 关闭当前选项卡\n                 */\n                $('.tabCloseCurrent').on('click', tabCloseCurrent);\n\n                /**\n                 * 关闭全部选项卡\n                 */\n                $('.J_tabCloseAll').on('click', tabCloseAll);\n\n                /**\n                 * 全屏显示\n                 */\n                $('#fullScreen').on('click', function () {\n                    let currentHash = window.location.hash;\n                    $(document).toggleFullScreen();\n\n                    // reset\n                    if (currentHash) {\n                        setTimeout(function (){\n                            window.location.hash = currentHash;\n                        },50)\n                    }\n                });\n\n                /**\n                 * 默认打开菜单Tab：优先尝试打开url路径TAB，兜底打开首个菜单\n                 */\n                openDefaultTab();\n            },\n            openTab: function(options, isCloseCurrent) {\n                // 当前页面是否关闭\n                if (isCloseCurrent) {\n                    tabCloseCurrent();\n                }\n                // 打开Tab页面\n                return openTab(options.tabSrc, options.tabName);\n            }\n        }\n    });\n\n    // -------------------- tab：open default --------------------\n\n    /**\n     * 默认打开菜单Tab：初始化首页菜单，然后 尝试打开url路径TAB\n     */\n    function openDefaultTab() {\n        // load url\n        let tabSrc = window.location.hash.slice(1);\n\n        // 1、首页菜单：初始化\n        let $firstMenuItem = $(\".J_menuItem:first\");\n        if ($firstMenuItem.length > 0) {\n            $firstMenuItem.click();\n            // 首页菜单特殊逻辑，不允许关闭\n            $('.J_menuTab[data-id=\"' + $firstMenuItem.attr('href') + '\"] i').remove();\n        }\n\n        // 2、URL匹配到菜单，初始化\n        if (tabSrc === '' || tabSrc === undefined || tabSrc === null) {\n            // URL菜单路径不存在则pass\n            return;\n        }\n        setTimeout(function (){\n            var $menuItem = $('.J_menuItem').filter('a[href$=\"' + decodeURI(tabSrc) + '\"]');\n            if ($menuItem.length > 0) {\n                // URL匹配到菜单，初始化\n                $menuItem.click();\n                return;\n            } else {\n                // 匹配失败，兜底直接打开\n                openTab(tabSrc, tabSrc);\n            }\n        }, 100)\n\n    }\n\n    // -------------------- tab：open、close --------------------\n\n    /**\n     * 打开Tab：根据 url + 名称\n     *\n     * @param tabSrc\n     * @param tabName\n     * @returns {boolean}\n     */\n    function openTab(tabSrc, tabName) {\n        // 0、valid dateurl\n        if (tabSrc === undefined || $.trim(tabSrc).length === 0){\n            return false;\n        }\n        if (tabName === undefined || $.trim(tabName).length === 0){\n            tabName = tabSrc;\n        }\n        let tabNameShow = tabName.length > 15 ? tabName.substring(0, 15) + '...' : tabName;\n\n        // 1、菜单Menu联动 + 页面锚点（hash参数）更新\n        activeMenuAndPath(tabSrc);\n\n        // 2、匹配已存在Tab，切换/active展示\n        let tabExist = false;\n        $('.J_menuTab').each(function () {\n            // 匹配成功\n            if ($(this).data('id') === tabSrc) {\n                // Tab是否展示，若否则切换展示\n                if (!$(this).hasClass('active')) {\n                    $(this).addClass('active').siblings('.J_menuTab').removeClass('active');\n                    scrollToTab(this);\n                    // 显示Tab对应的内容区\n                    $('.J_mainContent .J_iframe').each(function () {\n                        if ($(this).data('id') === tabSrc) {\n                            $(this).show().siblings('.J_iframe').hide();\n                            return false;\n                        }\n                    });\n                }\n                tabExist = true;\n                return false;\n            }\n        });\n        if (tabExist) {\n            return false;\n        }\n\n        // 3、Tab不存在，初始化新Tab + IFrame\n        // build Tab (other tab no-active)\n        $('.J_menuTab').removeClass('active');\n        var tabStr = '<a href=\"javascript:;\" class=\"active J_menuTab\" data-id=\"' + tabSrc + '\" title=\"'+ tabName +'\" >' + tabNameShow + ' <i class=\"fa fa-times-circle\"></i></a>';\n\n        // build IFrame (other ifame hide)\n        var iframeStr = '<iframe class=\"J_iframe\" width=\"100%\" height=\"100%\" src=\"' + tabSrc + '\" frameborder=\"0\" data-id=\"' + tabSrc + '\" seamless></iframe>';\n\n        // 4、添加Tab + IFrame\n        // append iframe\n        $('.J_mainContent').find('iframe.J_iframe').hide();\n        $('.J_mainContent').append(iframeStr);\n        // append tab\n        $('.J_menuTabs .page-tabs-content').append(tabStr);\n\n        // 添加遮罩层\n        NProgress.inc(0.2);\n        NProgress.configure({\n            easing: 'ease',         // 动画缓动函数 (默认: 'ease')\n            speed: 500,             // 动画速度（毫秒）(默认: 200)\n            showSpinner: true      // 是否显示旋转图标 (默认: true)\n        });\n        NProgress.start();\n\n        // load iframe\n        let $iframe = $('.J_mainContent iframe:visible');\n        $iframe.on('load', function () {\n            NProgress.done();\n        }).on('error', function () {\n            NProgress.done();\n            // 处理加载失败情况，防止跳转\n            console.error('iframe load error, src = ' + $(this).attr('src'));\n        });\n\n        // 5、滚动到已激活的Tab\n        scrollToTab($('.J_menuTab.active'));\n        return false;\n    }\n\n    /**\n     * 关闭Tab：根据点击 Tab元素\n     *\n     * @returns {boolean}\n     */\n    function closeTab() {\n        // param\n        var closeTabId = $(this).parents('.J_menuTab').data('id');\n        var currentWidth = $(this).parents('.J_menuTab').width();\n\n        // process\n        if ($(this).parents('.J_menuTab').hasClass('active')) {\n            // 1、当前元素处于活动状态\n\n            // 当前元素后面有同辈元素，使后面的一个元素处于活动状态\n            if ($(this).parents('.J_menuTab').next('.J_menuTab').length > 0) {\n                // 后一个Tab，激活 Tab\n                var activeId = $(this).parents('.J_menuTab').next('.J_menuTab:eq(0)').data('id');\n                $(this).parents('.J_menuTab').next('.J_menuTab:eq(0)').addClass('active');\n\n                // 后一个Tab，激活 iframe\n                $('.J_mainContent .J_iframe').each(function () {\n                    if ($(this).data('id') === activeId) {\n                        $(this).show().siblings('.J_iframe').hide();\n                        return false;\n                    }\n                });\n\n                var marginLeftVal = parseInt($('.page-tabs-content').css('margin-left'));\n                if (marginLeftVal < 0) {\n                    $('.page-tabs-content').animate({\n                        marginLeft: (marginLeftVal + currentWidth) + 'px'\n                    }, \"fast\");\n                }\n\n                //  移除 当前 Tab\n                $(this).parents('.J_menuTab').remove();\n\n                // 移除 当前 iframe\n                $('.J_mainContent .J_iframe').each(function () {\n                    if ($(this).data('id') === closeTabId) {\n                        $(this).remove();\n                        return false;\n                    }\n                });\n            }\n\n            // 当前元素后面没有同辈元素，使当前元素的上一个元素处于活动状态\n            if ($(this).parents('.J_menuTab').prev('.J_menuTab').length > 0) {\n                // 前一个Tab，激活 Tab\n                var activeId = $(this).parents('.J_menuTab').prev('.J_menuTab:last').data('id');\n                $(this).parents('.J_menuTab').prev('.J_menuTab:last').addClass('active');\n\n                // 前一个Tab，激活 iframe\n                $('.J_mainContent .J_iframe').each(function () {\n                    if ($(this).data('id') == activeId) {\n                        $(this).show().siblings('.J_iframe').hide();\n                        return false;\n                    }\n                });\n\n                //  移除 当前 Tab\n                $(this).parents('.J_menuTab').remove();\n\n                // 移除 当前 iframe\n                $('.J_mainContent .J_iframe').each(function () {\n                    if ($(this).data('id') === closeTabId) {\n                        $(this).remove();\n                        return false;\n                    }\n                });\n            }\n        } else {\n            // 2、当前元素不处于活动状态\n\n            //  移除 当前 Tab\n            $(this).parents('.J_menuTab').remove();\n\n            // 移除 当前 iframe\n            $('.J_mainContent .J_iframe').each(function () {\n                if ($(this).data('id') == closeTabId) {\n                    $(this).remove();\n                    return false;\n                }\n            });\n\n            // 滚动到active状态 Tab\n            scrollToTab($('.J_menuTab.active'));\n        }\n\n        // 3、菜单Menu联动 + 页面锚点（hash参数）更新\n        activeMenuAndPath($('.page-tabs-content').find('.active').attr('data-id'));\n        return false;\n    }\n\n    /**\n     * 菜单Menu联动 + 页面锚点（hash参数）更新\n     */\n    function activeMenuAndPath(tabSrc) {\n\n        // 页面锚点（hash参数）更新\n        window.location.hash = tabSrc;\n\n        // 菜单Menu切换/active\n        $(\".sidebar-menu ul li, .sidebar-menu li\").removeClass(\"active\");\n        $('.J_menuItem').each(function () {\n            if ($(this).attr('href') === tabSrc) {\n\n                // 菜单Menu切换/active\n                $(this).parents(\"li\").addClass(\"active\");\n\n\n                return true;\n            }\n        })\n        return false;\n    }\n\n    /**\n     * Tab单击（切换/激活）：展示Tab页面 + 左侧菜单active更新\n     */\n    function activeTab() {\n        // 是否已激活 active，避免重复处理\n        if (!$(this).hasClass('active')) {\n            // 待激活Tab信息\n            let tabSrc = $(this).data('id');\n\n            // Ifame 切换展示\n            $('.J_mainContent .J_iframe').each(function () {\n                if ($(this).data('id') === tabSrc) {\n                    $(this).show().siblings('.J_iframe').hide();\n                    return false;\n                }\n            });\n\n            // Tab 激活\n            $(this).addClass('active').siblings('.J_menuTab').removeClass('active');\n            scrollToTab(this);\n\n            // 菜单Menu联动\n            activeMenuAndPath(tabSrc);\n        }\n    }\n\n    // -------------------- tab: scroll --------------------\n\n    /**\n     * 滚动到指定选项卡\n     */\n    function scrollToTab(element) {\n\n        // 当前元素左侧宽度\n        var marginLeftVal = calSumWidth($(element).prevAll()), marginRightVal = calSumWidth($(element).nextAll());\n        // Tab外部区域宽度\n        var tabOuterWidth = calSumWidth($(\".content-tabs\").children().not(\".J_menuTabs\"));\n        // 可视区域Tab宽度\n        var visibleWidth = $(\".content-tabs\").outerWidth(true) - tabOuterWidth;\n        // 实际滚动宽度\n        var scrollVal = 0;\n        if ($(\".page-tabs-content\").outerWidth() < visibleWidth) {\n            scrollVal = 0;\n        } else if (marginRightVal <= (visibleWidth - $(element).outerWidth(true) - $(element).next().outerWidth(true))) {\n            if ((visibleWidth - $(element).next().outerWidth(true)) > marginRightVal) {\n                scrollVal = marginLeftVal;\n                var tabElement = element;\n                while ((scrollVal - $(tabElement).outerWidth()) > ($(\".page-tabs-content\").outerWidth() - visibleWidth)) {\n                    scrollVal -= $(tabElement).prev().outerWidth();\n                    tabElement = $(tabElement).prev();\n                }\n            }\n        } else if (marginLeftVal > (visibleWidth - $(element).outerWidth(true) - $(element).prev().outerWidth(true))) {\n            scrollVal = marginLeftVal - $(element).prev().outerWidth(true);\n        }\n\n        // 滚动处理\n        $('.page-tabs-content').animate({\n            marginLeft: 0 - scrollVal + 'px'\n        }, \"fast\");\n    }\n\n    /**\n     * 计算元素集合的总宽度\n     */\n    function calSumWidth(elements) {\n        var width = 0;\n        $(elements).each(function () {\n            width += $(this).outerWidth(true);\n        });\n        return width;\n    }\n\n    // -------------------- tab: scroll-left、scroll-right、 --------------------\n\n    /**\n     * 选项卡-左移按扭：查看左侧隐藏的选项卡\n     */\n    function scrollTabLeft() {\n\n        // 当前元素左侧宽度\n        var marginLeftVal = Math.abs(parseInt($('.page-tabs-content').css('margin-left')));\n        // Tab外部区域宽度\n        var tabOuterWidth = calSumWidth($(\".content-tabs\").children().not(\".J_menuTabs\"));\n        // 可视区域tab宽度\n        var visibleWidth = $(\".content-tabs\").outerWidth(true) - tabOuterWidth;\n        // 实际滚动宽度\n        var scrollVal = 0;\n        if ($(\".page-tabs-content\").width() < visibleWidth) {\n            return false;\n        } else {\n            var tabElement = $(\".J_menuTab:first\");\n            var offsetVal = 0;\n            while ((offsetVal + $(tabElement).outerWidth(true)) <= marginLeftVal) {//找到离当前tab最近的元素\n                offsetVal += $(tabElement).outerWidth(true);\n                tabElement = $(tabElement).next();\n            }\n            offsetVal = 0;\n            if (calSumWidth($(tabElement).prevAll()) > visibleWidth) {\n                while ((offsetVal + $(tabElement).outerWidth(true)) < (visibleWidth) && tabElement.length > 0) {\n                    offsetVal += $(tabElement).outerWidth(true);\n                    tabElement = $(tabElement).prev();\n                }\n                scrollVal = calSumWidth($(tabElement).prevAll());\n            }\n        }\n\n        // 滚动处理\n        $('.page-tabs-content').animate({\n            marginLeft: 0 - scrollVal + 'px'\n        }, \"fast\");\n    }\n\n    /**\n     * 选项卡-右移按扭：查看右侧隐藏的选项卡\n     */\n    function scrollTabRight() {\n\n        // 当前元素左侧宽度\n        var marginLeftVal = Math.abs(parseInt($('.page-tabs-content').css('margin-left')));\n        // 可视区域非tab宽度\n        var tabOuterWidth = calSumWidth($(\".content-tabs\").children().not(\".J_menuTabs\"));\n        // 可视区域tab宽度\n        var visibleWidth = $(\".content-tabs\").outerWidth(true) - tabOuterWidth;\n        // 实际滚动宽度\n        var scrollVal = 0;\n        if ($(\".page-tabs-content\").width() < visibleWidth) {\n            return false;\n        } else {\n            var tabElement = $(\".J_menuTab:first\");\n            var offsetVal = 0;\n            while ((offsetVal + $(tabElement).outerWidth(true)) <= marginLeftVal) {//找到离当前tab最近的元素\n                offsetVal += $(tabElement).outerWidth(true);\n                tabElement = $(tabElement).next();\n            }\n            offsetVal = 0;\n            while ((offsetVal + $(tabElement).outerWidth(true)) < (visibleWidth) && tabElement.length > 0) {\n                offsetVal += $(tabElement).outerWidth(true);\n                tabElement = $(tabElement).next();\n            }\n            scrollVal = calSumWidth($(tabElement).prevAll());\n            if (scrollVal > 0) {\n                $('.page-tabs-content').animate({\n                    marginLeft: 0 - scrollVal + 'px'\n                }, \"fast\");\n            }\n        }\n    }\n\n    // -------------------- tab: refresh、close-other、close-current、close-all --------------------\n\n    /**\n     * Tab-刷新按钮：刷新active的 Tab 页面\n     */\n    function refreshTab() {\n\n        // 显示进度条\n        NProgress.inc(0.2);\n        NProgress.configure({\n            easing: 'ease',         // 动画缓动函数 (默认: 'ease')\n            speed: 500,             // 动画速度（毫秒）(默认: 200)\n            showSpinner: true       // 是否显示旋转图标 (默认: true)\n        });\n        NProgress.start();\n\n        // 1、获取当前激活的 Tab\n        var tabSrc = $('.page-tabs-content').find('.active').attr('data-id');\n        var target = $('.J_iframe[data-id=\"' + tabSrc + '\"]');\n        var url = target.attr('src');\n\n        // 2、重新加载页面\n        // target.attr('src', url).ready();\n        target.attr('src', url).on('load', function () {\n            NProgress.done();\n\n            // 3、菜单Menu联动 + 页面锚点（hash参数）更新\n            activeMenuAndPath($('.page-tabs-content').find('.active').attr('data-id'));\n\n        }).on('error', function () {\n            NProgress.done();\n            // 处理加载失败情况，防止跳转\n            console.error('iframe load error, src = ' + $(this).attr('src'));\n        });\n    }\n\n    /**\n     * 选项卡-Tab双击：刷新菜单页面\n     */\n    /*$('.J_menuTabs').on('dblclick', '.J_menuTab', refreshTab);*/\n\n    /**\n     * 滚动到已激活的选项卡\n     */\n    /*$('.J_tabShowActive').on('click', showActiveTab);\n    function showActiveTab(){\n        scrollToTab($('.J_menuTab.active'));\n    }*/\n\n    /**\n     * 关闭其他选项卡\n     */\n    function closeOtherTabs(){\n        $('.page-tabs-content').children(\"[data-id]\").not(\":first\").not(\".active\").each(function () {\n            $('.J_iframe[data-id=\"' + $(this).data('id') + '\"]').remove();\n            $(this).remove();\n        });\n        $('.page-tabs-content').css(\"margin-left\", \"0\");\n    }\n\n    /**\n     * 关闭当前选项卡\n     */\n    function tabCloseCurrent() {\n        $('.page-tabs-content').find('.active i').trigger(\"click\");\n    }\n\n    /**\n     * 关闭全部选项卡\n     */\n    function tabCloseAll(){\n        // 保留 第一个 Tab，其他删除（Tab+iframe）\n        $('.page-tabs-content').children(\"[data-id]\").not(\":first\").each(function () {\n            $('.J_iframe[data-id=\"' + $(this).data('id') + '\"]').remove();\n            $(this).remove();\n        });\n        // 第一个 Tab 激活/展示（Tab+iframe）\n        $('.page-tabs-content').children(\"[data-id]:first\").each(function () {\n            $('.J_iframe[data-id=\"' + $(this).data('id') + '\"]').show();\n            $(this).addClass(\"active\");\n        });\n        $('.page-tabs-content').css(\"margin-left\", \"0\");\n\n        // 菜单Menu联动 + 页面锚点（hash参数）更新\n        activeMenuAndPath($('.page-tabs-content').find('.active').attr('data-id'));\n    }\n\n\n})(jQuery);\n"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/biz/common/admin.table.js",
    "content": "/*!\n* Admin Table for XXL-BOOT\n* ================\n*\n* 1、data_filter：\n*      searchBtn：       搜索\n*      resetBtn：        重置\n* 2、data_operation：\n*      action：\n*          - add：       新增\n*          - update：    更新\n*          - delete：    删除\n*      style：\n*          - selectOnlyOne： 单选\n*          - selectAny：     多选\n* 3、data_list\n*      mainDataTable：   表格\n*\n* @author       xuxueli\n* @repository   https://github.com/xuxueli/xxl-boot\n*/\n(function($) {\n\n    $.extend({\n        adminTable: {\n            table :null,\n            options: {},\n            selectIds: function () {\n                // get select rows\n                let rows = this.table.bootstrapTable('getSelections');\n                // find select ids\n                return (rows && rows.length > 0) ? rows.map(row => row.id) : [];\n            },\n            selectRows: function () {\n                // get select rows\n                return this.table.bootstrapTable('getSelections');\n            },\n            initTable: function(options) {\n                // parse param\n                this.table = $(options.table);\n                this.options = options;\n\n                // init filter\n                initSearch(this.table, options);\n                initReset(options);\n\n                // init table\n                initAdminTable(this.table, options);\n            },\n            initTreeTable: function(options) {\n                // parse param\n                this.table = $(options.table);\n\n                // init filter\n                initSearch(this.table, options);\n                initReset(options);\n\n                // init tree table\n                initAdminTreeTable(this.table, options);\n            },\n            initDelete: function(options) {\n                initDeleteFun(this.table, options);\n            },\n            initAdd: function(options) {\n                initAddFun(options);\n            },\n            initUpdate: function(options) {\n                initUpdateFun(this.table, options);\n            }\n        }\n    });\n\n    /**\n     * init search\n     */\n    function initSearch(table, options){\n        // search\n        $('#data_filter .searchBtn').on('click', function(){\n\n            // searchHandler\n            let searchHandler = options.searchHandler;\n            if (typeof searchHandler === 'function') {\n                searchHandler();\n                return;\n            }\n\n            // do search\n            $(table).bootstrapTable('refresh');\n\n        });\n    }\n\n    /**\n     * init reset\n     */\n    function initReset(options) {\n\n        // reset\n        $('#data_filter .resetBtn').on('click', function(){\n\n            // reset\n            let resetHandler = options.resetHandler;\n            if (typeof resetHandler === 'function') {\n                // resetHandler\n                resetHandler();\n            } else {\n                // do reset\n\n                // input\n                $('#data_filter input[type=\"text\"]').val('');\n                // select\n                $('#data_filter select').each(function() {\n                    $(this).prop('selectedIndex', 0);\n                });\n                // checkbox\n                $('#data_filter input[type=\"checkbox\"]').prop('checked', false);\n                // radio\n                $('#data_filter input[type=\"radio\"]').prop('checked', false);\n            }\n\n            // do search\n            $('#data_filter .searchBtn').click();\n        });\n    }\n\n    /**\n     * init admin table\n     *\n     * @param table\n     * @param url\n     * @param queryParams\n     * @param columns\n     */\n    function initAdminTable(table, options) {\n\n        // parse param\n        let url = options.url;\n        let queryParams = options.queryParams;\n        let columns = options.columns;\n\n        // init table\n        $(table).bootstrapTable({\n            url: url,\n            method: \"post\",\n            contentType: \"application/x-www-form-urlencoded\",\n            queryParamsType: \"limit\",\n            queryParams: queryParams,       // bootstrapTable -> queryParams\n            sidePagination: \"server\",\t\t// server side page\n            responseHandler: function (result) {\n                // custome\n                if (options.responseHandler) {\n                    return options.responseHandler(result);\n                }\n\n                // valid\n                if (result.code !== 200) {\n                    layer.msg(result.msg || (I18n.system_opt+I18n.system_fail));\n                    return {\n                        total: 0,\n                        rows: []\n                    }\n                }\n\n                // default\n                return {\n                    \"total\": result.data.total,\n                    \"rows\": result.data.data\n                };\n            },\n            columns: columns,\n            clickToSelect: true, \t\t\t// 是否启用点击选中行\n            multipleSelectRow: true,        // 启动多选行：点击 选择单行，Shift+点击 选择连续行, Commond+点击 非连续选择多行\n            sortable: false, \t\t\t\t// 是否启用排序\n            pagination: true, \t\t\t\t// 是否显示分页\n            pageNumber: 1, \t\t\t\t\t// 默认第一页\n            pageList: [10, 25, 50, 100] , \t// 可供选择的每页的行数（*）\n            smartDisplay: false,\t\t\t// 当总记录数小于分页数，是否显示可选项\n            paginationParts:  ['pageInfoShort', 'pageSize', 'pageList'],\n            paginationPreText: '<<',\t\t// 跳转页面的 上一页按钮\n            paginationNextText: '>>',\t\t// 跳转页面的 下一页按钮\n            paginationLoop: false,          // 是否循环翻页\n            showRefresh: true,\t\t\t\t// 显示刷新按钮\n            showColumns: true,\t\t\t\t// 显示/隐藏列\n            minimumCountColumns: 2,\t\t\t// 最少允许的列数\n            // onLoadSuccess: function(data) {}\n            onAll: function(name, args) {\n                // filter\n                if (!(['check.bs.table', \"uncheck.bs.table\", \"check-all.bs.table\", \"uncheck-all.bs.table\", 'post-body.bs.table'].indexOf(name) > -1)) {\n                    return false;\n                }\n                var rows = $(table).bootstrapTable('getSelections');\n                var selectLen = rows.length;\n\n                if (selectLen > 0) {\n                    $(\"#data_operation .selectAny\").removeClass('disabled');\n                } else {\n                    $(\"#data_operation .selectAny\").addClass('disabled');\n                }\n                if (selectLen === 1) {\n                    $(\"#data_operation .selectOnlyOne\").removeClass('disabled');\n                } else {\n                    $(\"#data_operation .selectOnlyOne\").addClass('disabled');\n                }\n            }\n        });\n\n        // toolbar 样式调整；\n        var toolbarElement = document.querySelector('.fixed-table-toolbar');\n        if (toolbarElement) {\n            toolbarElement.classList.remove('fixed-table-toolbar');\n        }\n    }\n\n    function initAdminTreeTable(table, options) {\n\n        // parse param\n        let url = options.url;\n        let queryParams = options.queryParams;\n        let columns = options.columns;\n\n        // table\n        var mainDataTable = $(\"#data_list\").bootstrapTable({\n            url: url,\n            method: \"post\",\n            contentType: \"application/x-www-form-urlencoded\",\n            queryParams: queryParams,\n            responseHandler: function(result) {\n                if (result.code !== 200) {\n                    layer.open({\n                        icon: '2',\n                        content: result.msg\n                    });\n                    return ;\n                }\n                return result.data;\n            },\n            treeEnable:true,\n            idField: 'id',\t\t\t\t\t// 树形id\n            parentIdField: 'parentId',\t\t// 父级字段\n            treeShowField: 'name',\t\t\t// 树形字段\n            onPostBody: function(data) {\n                $(\"#data_list\").treegrid({\n                    treeColumn: 1,\t\t\t\t\t\t\t\t\t\t\t\t// 选择第几列作为树形字段\n                    initialState: 'expanded',\t\t\t\t\t\t\t\t\t// 默认展开；expanded、collapsed\n                    expanderExpandedClass: 'fa fa-fw  fa-minus-square-o',\t\t// 树形展开图标\n                    expanderCollapsedClass: 'fa fa-fw  fa-plus-square-o',\t\t// 树形折叠图标\n                    onChange () {\n                        $(\"#data_list\").bootstrapTable('resetView')\t\t\t\t// 树形表格重绘\n                    }\n                })\n            },\n            columns:columns,\n            clickToSelect: true, \t\t\t// 是否启用点击选中行\n            multipleSelectRow: true,        // 启动多选行：点击 选择单行，Shift+点击 选择连续行, Commond+点击 非连续选择多行\n            sortable: false, \t\t\t\t// 是否启用排序\n            showRefresh: true,\t\t\t\t// 显示刷新按钮\n            showColumns: true,\t\t\t\t// 显示/隐藏列\n            minimumCountColumns: 2,\t\t\t// 最少允许的列数\n            onAll: function(name, args) {\n                // filter\n                if (!(['check.bs.table', \"uncheck.bs.table\", \"check-all.bs.table\", \"uncheck-all.bs.table\"].indexOf(name) > -1)) {\n                    return false;\n                }\n                var rows = mainDataTable.bootstrapTable('getSelections');\n                var selectLen = rows.length;\n\n                if (selectLen > 0) {\n                    $(\"#data_operation .selectAny\").removeClass('disabled');\n                } else {\n                    $(\"#data_operation .selectAny\").addClass('disabled');\n                }\n                if (selectLen === 1) {\n                    $(\"#data_operation .selectOnlyOne\").removeClass('disabled');\n                } else {\n                    $(\"#data_operation .selectOnlyOne\").addClass('disabled');\n                }\n            }\n        });\n\n        // toolbar 样式调整；\n        var toolbarElement = document.querySelector('.fixed-table-toolbar');\n        if (toolbarElement) {\n            toolbarElement.classList.remove('fixed-table-toolbar');\n        }\n    }\n\n    /**\n     * init delete\n     */\n    function initDeleteFun(table, options) {\n        // parse param\n        let url = options.url;\n\n        // delete\n        $(\"#data_operation\").on('click', '.delete',function() {\n            // get select rows\n            var rows = $(table).bootstrapTable('getSelections');\n\n            // find select ids\n            const selectIds = (rows && rows.length > 0) ? rows.map(row => row.id) : [];\n            if (selectIds.length <= 0) {\n                layer.msg(I18n.system_please_choose + I18n.system_data);\n                return;\n            }\n\n            // do delete\n            layer.confirm( I18n.system_ok + I18n.system_opt_del + '?', {\n                icon: 3,\n                title: I18n.system_tips ,\n                btn: [ I18n.system_ok, I18n.system_cancel ]\n            }, function(index){\n                layer.close(index);\n\n                $.ajax({\n                    type : 'POST',\n                    url : url,\n                    data : {\n                        \"ids\" : selectIds\n                    },\n                    dataType : \"json\",\n                    success : function(data){\n                        if (data.code === 200) {\n                            layer.msg( I18n.system_opt_del + I18n.system_success );\n                            // refresh table\n                            $('#data_filter .searchBtn').click();\n                        } else {\n                            layer.msg( data.msg || I18n.system_opt_del + I18n.system_fail );\n                        }\n                    },\n                    error: function(xhr, status, error) {\n                        // Handle error\n                        console.log(\"Error: \" + error);\n                        layer.open({\n                            icon: '2',\n                            content: (I18n.system_opt_del + I18n.system_fail)\n                        });\n                    }\n                });\n            });\n        });\n    }\n\n    /**\n     * init add\n     */\n    function initAddFun(options) {\n\n        // parse param\n        let url = options.url;\n        let rules = options.rules;\n        let messages = options.messages;\n        let writeFormData = options.writeFormData;\n        let readFormData = options.readFormData;\n\n        // add\n        $(\"#data_operation .add\").click(function(){\n            // reset\n            addModalValidate.resetForm();\n            $(\"#addModal .form\")[0].reset();\n            $(\"#addModal .form .form-group\").removeClass(\"has-error\");\n\n            // write FormData\n            if (typeof writeFormData === 'function') {\n                writeFormData();\n            }\n\n            // show\n            $('#addModal').modal({backdrop: false, keyboard: false}).modal('show');\n        });\n        var addModalValidate = $(\"#addModal .form\").validate({\n            errorElement : 'span',\n            errorClass : 'help-block',\n            focusInvalid : true,\n            rules : rules,                      // jquery.validate -> rules\n            messages : messages,                // jquery.validate -> messages\n            highlight : function(element) {\n                $(element).closest('.form-group').addClass('has-error');\n            },\n            success : function(label) {\n                label.closest('.form-group').removeClass('has-error');\n                label.remove();\n            },\n            errorPlacement : function(error, element) {\n                element.parent('div').append(error);\n            },\n            submitHandler : function(form) {\n                // post\n                $.post(url, readFormData(), function(data, status) {\n                    if (data.code === 200) {\n                        $('#addModal').modal('hide');\n                        layer.msg( I18n.system_opt_add + I18n.system_success );\n\n                        // refresh table\n                        $('#data_filter .searchBtn').click();\n                    } else {\n                        layer.open({\n                            title: I18n.system_tips ,\n                            btn: [ I18n.system_ok ],\n                            content: (data.msg || I18n.system_opt_add + I18n.system_fail ),\n                            icon: '2'\n                        });\n                    }\n                });\n            }\n        });\n    }\n\n    /**\n     * init update\n     */\n    function initUpdateFun(table, options) {\n\n        // parse param\n        let url = options.url;\n        let rules = options.rules;\n        let messages = options.messages;\n        let writeFormData = options.writeFormData;\n        let readFormData = options.readFormData;\n\n        // update\n        $(\"#data_operation .update\").click(function(){\n            // get select rows\n            var rows = $(table).bootstrapTable('getSelections');\n\n            // find select row\n            if (rows.length !== 1) {\n                layer.msg(I18n.system_please_choose + I18n.system_one + I18n.system_data);\n                return;\n            }\n            var row = rows[0];\n\n            // reset\n            $(\"#updateModal .form\")[0].reset();\n            $(\"#updateModal .form .form-group\").removeClass(\"has-error\");\n            updateModalValidate.resetForm();\n\n            // write FormData\n            writeFormData(row);\n\n            // show\n            $('#updateModal').modal({backdrop: false, keyboard: false}).modal('show');\n        });\n        var updateModalValidate = $(\"#updateModal .form\").validate({\n            errorElement : 'span',\n            errorClass : 'help-block',\n            focusInvalid : true,\n            highlight : function(element) {\n                $(element).closest('.form-group').addClass('has-error');\n            },\n            success : function(label) {\n                label.closest('.form-group').removeClass('has-error');\n                label.remove();\n            },\n            errorPlacement : function(error, element) {\n                element.parent('div').append(error);\n            },\n            rules : rules,                      // jquery.validate -> rules\n            messages : messages,                // jquery.validate -> messages\n            submitHandler : function(form) {\n\n                // request\n                var paramData = readFormData();\n\n                $.post(url, paramData, function(data, status) {\n                    if (data.code === 200) {\n                        $('#updateModal').modal('hide');\n                        layer.msg( I18n.system_opt_edit + I18n.system_success );\n\n                        // refresh table\n                        $('#data_filter .searchBtn').click();\n                    } else {\n                        layer.open({\n                            title: I18n.system_tips ,\n                            btn: [ I18n.system_ok ],\n                            content: (data.msg || I18n.system_opt_edit + I18n.system_fail ),\n                            icon: '2'\n                        });\n                    }\n                });\n            }\n        });\n    }\n\n})(jQuery);"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/biz/common/admin.util.js",
    "content": "/*!\n* Admin Util for XXL-BOOT\n* ================\n*\n* 1、openTab：    打开新页面，兼容iframe和window.open\n*\n* @author       xuxueli\n* @repository   https://github.com/xuxueli/xxl-boot\n*/\n$(function(){\n\n\n    // ---------------------- openTab ----------------------\n\n    /**\n     * 打开新页面，兼容iframe和window.open\n     *\n     * @param tabSrc            tab访问地址\n     * @param tabName           tab展示名称\n     * @param isCloseCurrent    是否关闭当前页\n     */\n    window.openTab = function (tabSrc, tabName, isCloseCurrent) {\n        // open tab\n        if (window.parent.$.adminTab) {\n            window.parent.$.adminTab.openTab({\n                tabSrc: tabSrc,\n                tabName: tabName\n            }, isCloseCurrent)\n        } else {\n            if (isCloseCurrent) {\n                window.open(tabSrc, '_self');\n            } else {\n                window.open(tabSrc, '_blank');\n            }\n        }\n    }\n\n    // ---------------------- isOpenWithTab ----------------------\n\n    /**\n     * 是否在Tab中打开\n     */\n    window.isOpenWithTab = function () {\n        return !!window.parent.$.adminTab;\n    }\n\n});\n"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/plugins/codemirror/addon/hint/anyword-hint.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: https://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n\n  var WORD = /[\\w$]+/, RANGE = 500;\n\n  CodeMirror.registerHelper(\"hint\", \"anyword\", function(editor, options) {\n    var word = options && options.word || WORD;\n    var range = options && options.range || RANGE;\n    var cur = editor.getCursor(), curLine = editor.getLine(cur.line);\n    var end = cur.ch, start = end;\n    while (start && word.test(curLine.charAt(start - 1))) --start;\n    var curWord = start != end && curLine.slice(start, end);\n\n    var list = options && options.list || [], seen = {};\n    var re = new RegExp(word.source, \"g\");\n    for (var dir = -1; dir <= 1; dir += 2) {\n      var line = cur.line, endLine = Math.min(Math.max(line + dir * range, editor.firstLine()), editor.lastLine()) + dir;\n      for (; line != endLine; line += dir) {\n        var text = editor.getLine(line), m;\n        while (m = re.exec(text)) {\n          if (line == cur.line && m[0] === curWord) continue;\n          if ((!curWord || m[0].lastIndexOf(curWord, 0) == 0) && !Object.prototype.hasOwnProperty.call(seen, m[0])) {\n            seen[m[0]] = true;\n            list.push(m[0]);\n          }\n        }\n      }\n    }\n    return {list: list, from: CodeMirror.Pos(cur.line, start), to: CodeMirror.Pos(cur.line, end)};\n  });\n});\n"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/plugins/codemirror/addon/hint/show-hint.css",
    "content": ".CodeMirror-hints {\n  position: absolute;\n  z-index: 10;\n  overflow: hidden;\n  list-style: none;\n\n  margin: 0;\n  padding: 2px;\n\n  -webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2);\n  -moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2);\n  box-shadow: 2px 3px 5px rgba(0,0,0,.2);\n  border-radius: 3px;\n  border: 1px solid silver;\n\n  background: white;\n  font-size: 90%;\n  font-family: monospace;\n\n  max-height: 20em;\n  overflow-y: auto;\n}\n\n.CodeMirror-hint {\n  margin: 0;\n  padding: 0 4px;\n  border-radius: 2px;\n  white-space: pre;\n  color: black;\n  cursor: pointer;\n}\n\nli.CodeMirror-hint-active {\n  background: #08f;\n  color: white;\n}\n"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/plugins/codemirror/addon/hint/show-hint.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: https://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n\n  var HINT_ELEMENT_CLASS        = \"CodeMirror-hint\";\n  var ACTIVE_HINT_ELEMENT_CLASS = \"CodeMirror-hint-active\";\n\n  // This is the old interface, kept around for now to stay\n  // backwards-compatible.\n  CodeMirror.showHint = function(cm, getHints, options) {\n    if (!getHints) return cm.showHint(options);\n    if (options && options.async) getHints.async = true;\n    var newOpts = {hint: getHints};\n    if (options) for (var prop in options) newOpts[prop] = options[prop];\n    return cm.showHint(newOpts);\n  };\n\n  CodeMirror.defineExtension(\"showHint\", function(options) {\n    options = parseOptions(this, this.getCursor(\"start\"), options);\n    var selections = this.listSelections()\n    if (selections.length > 1) return;\n    // By default, don't allow completion when something is selected.\n    // A hint function can have a `supportsSelection` property to\n    // indicate that it can handle selections.\n    if (this.somethingSelected()) {\n      if (!options.hint.supportsSelection) return;\n      // Don't try with cross-line selections\n      for (var i = 0; i < selections.length; i++)\n        if (selections[i].head.line != selections[i].anchor.line) return;\n    }\n\n    if (this.state.completionActive) this.state.completionActive.close();\n    var completion = this.state.completionActive = new Completion(this, options);\n    if (!completion.options.hint) return;\n\n    CodeMirror.signal(this, \"startCompletion\", this);\n    completion.update(true);\n  });\n\n  function Completion(cm, options) {\n    this.cm = cm;\n    this.options = options;\n    this.widget = null;\n    this.debounce = 0;\n    this.tick = 0;\n    this.startPos = this.cm.getCursor(\"start\");\n    this.startLen = this.cm.getLine(this.startPos.line).length - this.cm.getSelection().length;\n\n    var self = this;\n    cm.on(\"cursorActivity\", this.activityFunc = function() { self.cursorActivity(); });\n  }\n\n  var requestAnimationFrame = window.requestAnimationFrame || function(fn) {\n    return setTimeout(fn, 1000/60);\n  };\n  var cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout;\n\n  Completion.prototype = {\n    close: function() {\n      if (!this.active()) return;\n      this.cm.state.completionActive = null;\n      this.tick = null;\n      this.cm.off(\"cursorActivity\", this.activityFunc);\n\n      if (this.widget && this.data) CodeMirror.signal(this.data, \"close\");\n      if (this.widget) this.widget.close();\n      CodeMirror.signal(this.cm, \"endCompletion\", this.cm);\n    },\n\n    active: function() {\n      return this.cm.state.completionActive == this;\n    },\n\n    pick: function(data, i) {\n      var completion = data.list[i];\n      if (completion.hint) completion.hint(this.cm, data, completion);\n      else this.cm.replaceRange(getText(completion), completion.from || data.from,\n                                completion.to || data.to, \"complete\");\n      CodeMirror.signal(data, \"pick\", completion);\n      this.close();\n    },\n\n    cursorActivity: function() {\n      if (this.debounce) {\n        cancelAnimationFrame(this.debounce);\n        this.debounce = 0;\n      }\n\n      var pos = this.cm.getCursor(), line = this.cm.getLine(pos.line);\n      if (pos.line != this.startPos.line || line.length - pos.ch != this.startLen - this.startPos.ch ||\n          pos.ch < this.startPos.ch || this.cm.somethingSelected() ||\n          (!pos.ch || this.options.closeCharacters.test(line.charAt(pos.ch - 1)))) {\n        this.close();\n      } else {\n        var self = this;\n        this.debounce = requestAnimationFrame(function() {self.update();});\n        if (this.widget) this.widget.disable();\n      }\n    },\n\n    update: function(first) {\n      if (this.tick == null) return\n      var self = this, myTick = ++this.tick\n      fetchHints(this.options.hint, this.cm, this.options, function(data) {\n        if (self.tick == myTick) self.finishUpdate(data, first)\n      })\n    },\n\n    finishUpdate: function(data, first) {\n      if (this.data) CodeMirror.signal(this.data, \"update\");\n\n      var picked = (this.widget && this.widget.picked) || (first && this.options.completeSingle);\n      if (this.widget) this.widget.close();\n\n      this.data = data;\n\n      if (data && data.list.length) {\n        if (picked && data.list.length == 1) {\n          this.pick(data, 0);\n        } else {\n          this.widget = new Widget(this, data);\n          CodeMirror.signal(data, \"shown\");\n        }\n      }\n    }\n  };\n\n  function parseOptions(cm, pos, options) {\n    var editor = cm.options.hintOptions;\n    var out = {};\n    for (var prop in defaultOptions) out[prop] = defaultOptions[prop];\n    if (editor) for (var prop in editor)\n      if (editor[prop] !== undefined) out[prop] = editor[prop];\n    if (options) for (var prop in options)\n      if (options[prop] !== undefined) out[prop] = options[prop];\n    if (out.hint.resolve) out.hint = out.hint.resolve(cm, pos)\n    return out;\n  }\n\n  function getText(completion) {\n    if (typeof completion == \"string\") return completion;\n    else return completion.text;\n  }\n\n  function buildKeyMap(completion, handle) {\n    var baseMap = {\n      Up: function() {handle.moveFocus(-1);},\n      Down: function() {handle.moveFocus(1);},\n      PageUp: function() {handle.moveFocus(-handle.menuSize() + 1, true);},\n      PageDown: function() {handle.moveFocus(handle.menuSize() - 1, true);},\n      Home: function() {handle.setFocus(0);},\n      End: function() {handle.setFocus(handle.length - 1);},\n      Enter: handle.pick,\n      Tab: handle.pick,\n      Esc: handle.close\n    };\n    var custom = completion.options.customKeys;\n    var ourMap = custom ? {} : baseMap;\n    function addBinding(key, val) {\n      var bound;\n      if (typeof val != \"string\")\n        bound = function(cm) { return val(cm, handle); };\n      // This mechanism is deprecated\n      else if (baseMap.hasOwnProperty(val))\n        bound = baseMap[val];\n      else\n        bound = val;\n      ourMap[key] = bound;\n    }\n    if (custom)\n      for (var key in custom) if (custom.hasOwnProperty(key))\n        addBinding(key, custom[key]);\n    var extra = completion.options.extraKeys;\n    if (extra)\n      for (var key in extra) if (extra.hasOwnProperty(key))\n        addBinding(key, extra[key]);\n    return ourMap;\n  }\n\n  function getHintElement(hintsElement, el) {\n    while (el && el != hintsElement) {\n      if (el.nodeName.toUpperCase() === \"LI\" && el.parentNode == hintsElement) return el;\n      el = el.parentNode;\n    }\n  }\n\n  function Widget(completion, data) {\n    this.completion = completion;\n    this.data = data;\n    this.picked = false;\n    var widget = this, cm = completion.cm;\n\n    var hints = this.hints = document.createElement(\"ul\");\n    var theme = completion.cm.options.theme;\n    hints.className = \"CodeMirror-hints \" + theme;\n    this.selectedHint = data.selectedHint || 0;\n\n    var completions = data.list;\n    for (var i = 0; i < completions.length; ++i) {\n      var elt = hints.appendChild(document.createElement(\"li\")), cur = completions[i];\n      var className = HINT_ELEMENT_CLASS + (i != this.selectedHint ? \"\" : \" \" + ACTIVE_HINT_ELEMENT_CLASS);\n      if (cur.className != null) className = cur.className + \" \" + className;\n      elt.className = className;\n      if (cur.render) cur.render(elt, data, cur);\n      else elt.appendChild(document.createTextNode(cur.displayText || getText(cur)));\n      elt.hintId = i;\n    }\n\n    var pos = cm.cursorCoords(completion.options.alignWithWord ? data.from : null);\n    var left = pos.left, top = pos.bottom, below = true;\n    hints.style.left = left + \"px\";\n    hints.style.top = top + \"px\";\n    // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor.\n    var winW = window.innerWidth || Math.max(document.body.offsetWidth, document.documentElement.offsetWidth);\n    var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight);\n    (completion.options.container || document.body).appendChild(hints);\n    var box = hints.getBoundingClientRect(), overlapY = box.bottom - winH;\n    var scrolls = hints.scrollHeight > hints.clientHeight + 1\n    var startScroll = cm.getScrollInfo();\n\n    if (overlapY > 0) {\n      var height = box.bottom - box.top, curTop = pos.top - (pos.bottom - box.top);\n      if (curTop - height > 0) { // Fits above cursor\n        hints.style.top = (top = pos.top - height) + \"px\";\n        below = false;\n      } else if (height > winH) {\n        hints.style.height = (winH - 5) + \"px\";\n        hints.style.top = (top = pos.bottom - box.top) + \"px\";\n        var cursor = cm.getCursor();\n        if (data.from.ch != cursor.ch) {\n          pos = cm.cursorCoords(cursor);\n          hints.style.left = (left = pos.left) + \"px\";\n          box = hints.getBoundingClientRect();\n        }\n      }\n    }\n    var overlapX = box.right - winW;\n    if (overlapX > 0) {\n      if (box.right - box.left > winW) {\n        hints.style.width = (winW - 5) + \"px\";\n        overlapX -= (box.right - box.left) - winW;\n      }\n      hints.style.left = (left = pos.left - overlapX) + \"px\";\n    }\n    if (scrolls) for (var node = hints.firstChild; node; node = node.nextSibling)\n      node.style.paddingRight = cm.display.nativeBarWidth + \"px\"\n\n    cm.addKeyMap(this.keyMap = buildKeyMap(completion, {\n      moveFocus: function(n, avoidWrap) { widget.changeActive(widget.selectedHint + n, avoidWrap); },\n      setFocus: function(n) { widget.changeActive(n); },\n      menuSize: function() { return widget.screenAmount(); },\n      length: completions.length,\n      close: function() { completion.close(); },\n      pick: function() { widget.pick(); },\n      data: data\n    }));\n\n    if (completion.options.closeOnUnfocus) {\n      var closingOnBlur;\n      cm.on(\"blur\", this.onBlur = function() { closingOnBlur = setTimeout(function() { completion.close(); }, 100); });\n      cm.on(\"focus\", this.onFocus = function() { clearTimeout(closingOnBlur); });\n    }\n\n    cm.on(\"scroll\", this.onScroll = function() {\n      var curScroll = cm.getScrollInfo(), editor = cm.getWrapperElement().getBoundingClientRect();\n      var newTop = top + startScroll.top - curScroll.top;\n      var point = newTop - (window.pageYOffset || (document.documentElement || document.body).scrollTop);\n      if (!below) point += hints.offsetHeight;\n      if (point <= editor.top || point >= editor.bottom) return completion.close();\n      hints.style.top = newTop + \"px\";\n      hints.style.left = (left + startScroll.left - curScroll.left) + \"px\";\n    });\n\n    CodeMirror.on(hints, \"dblclick\", function(e) {\n      var t = getHintElement(hints, e.target || e.srcElement);\n      if (t && t.hintId != null) {widget.changeActive(t.hintId); widget.pick();}\n    });\n\n    CodeMirror.on(hints, \"click\", function(e) {\n      var t = getHintElement(hints, e.target || e.srcElement);\n      if (t && t.hintId != null) {\n        widget.changeActive(t.hintId);\n        if (completion.options.completeOnSingleClick) widget.pick();\n      }\n    });\n\n    CodeMirror.on(hints, \"mousedown\", function() {\n      setTimeout(function(){cm.focus();}, 20);\n    });\n\n    CodeMirror.signal(data, \"select\", completions[this.selectedHint], hints.childNodes[this.selectedHint]);\n    return true;\n  }\n\n  Widget.prototype = {\n    close: function() {\n      if (this.completion.widget != this) return;\n      this.completion.widget = null;\n      this.hints.parentNode.removeChild(this.hints);\n      this.completion.cm.removeKeyMap(this.keyMap);\n\n      var cm = this.completion.cm;\n      if (this.completion.options.closeOnUnfocus) {\n        cm.off(\"blur\", this.onBlur);\n        cm.off(\"focus\", this.onFocus);\n      }\n      cm.off(\"scroll\", this.onScroll);\n    },\n\n    disable: function() {\n      this.completion.cm.removeKeyMap(this.keyMap);\n      var widget = this;\n      this.keyMap = {Enter: function() { widget.picked = true; }};\n      this.completion.cm.addKeyMap(this.keyMap);\n    },\n\n    pick: function() {\n      this.completion.pick(this.data, this.selectedHint);\n    },\n\n    changeActive: function(i, avoidWrap) {\n      if (i >= this.data.list.length)\n        i = avoidWrap ? this.data.list.length - 1 : 0;\n      else if (i < 0)\n        i = avoidWrap ? 0  : this.data.list.length - 1;\n      if (this.selectedHint == i) return;\n      var node = this.hints.childNodes[this.selectedHint];\n      if (node) node.className = node.className.replace(\" \" + ACTIVE_HINT_ELEMENT_CLASS, \"\");\n      node = this.hints.childNodes[this.selectedHint = i];\n      node.className += \" \" + ACTIVE_HINT_ELEMENT_CLASS;\n      if (node.offsetTop < this.hints.scrollTop)\n        this.hints.scrollTop = node.offsetTop - 3;\n      else if (node.offsetTop + node.offsetHeight > this.hints.scrollTop + this.hints.clientHeight)\n        this.hints.scrollTop = node.offsetTop + node.offsetHeight - this.hints.clientHeight + 3;\n      CodeMirror.signal(this.data, \"select\", this.data.list[this.selectedHint], node);\n    },\n\n    screenAmount: function() {\n      return Math.floor(this.hints.clientHeight / this.hints.firstChild.offsetHeight) || 1;\n    }\n  };\n\n  function applicableHelpers(cm, helpers) {\n    if (!cm.somethingSelected()) return helpers\n    var result = []\n    for (var i = 0; i < helpers.length; i++)\n      if (helpers[i].supportsSelection) result.push(helpers[i])\n    return result\n  }\n\n  function fetchHints(hint, cm, options, callback) {\n    if (hint.async) {\n      hint(cm, callback, options)\n    } else {\n      var result = hint(cm, options)\n      if (result && result.then) result.then(callback)\n      else callback(result)\n    }\n  }\n\n  function resolveAutoHints(cm, pos) {\n    var helpers = cm.getHelpers(pos, \"hint\"), words\n    if (helpers.length) {\n      var resolved = function(cm, callback, options) {\n        var app = applicableHelpers(cm, helpers);\n        function run(i) {\n          if (i == app.length) return callback(null)\n          fetchHints(app[i], cm, options, function(result) {\n            if (result && result.list.length > 0) callback(result)\n            else run(i + 1)\n          })\n        }\n        run(0)\n      }\n      resolved.async = true\n      resolved.supportsSelection = true\n      return resolved\n    } else if (words = cm.getHelper(cm.getCursor(), \"hintWords\")) {\n      return function(cm) { return CodeMirror.hint.fromList(cm, {words: words}) }\n    } else if (CodeMirror.hint.anyword) {\n      return function(cm, options) { return CodeMirror.hint.anyword(cm, options) }\n    } else {\n      return function() {}\n    }\n  }\n\n  CodeMirror.registerHelper(\"hint\", \"auto\", {\n    resolve: resolveAutoHints\n  });\n\n  CodeMirror.registerHelper(\"hint\", \"fromList\", function(cm, options) {\n    var cur = cm.getCursor(), token = cm.getTokenAt(cur)\n    var term, from = CodeMirror.Pos(cur.line, token.start), to = cur\n    if (token.start < cur.ch && /\\w/.test(token.string.charAt(cur.ch - token.start - 1))) {\n      term = token.string.substr(0, cur.ch - token.start)\n    } else {\n      term = \"\"\n      from = cur\n    }\n    var found = [];\n    for (var i = 0; i < options.words.length; i++) {\n      var word = options.words[i];\n      if (word.slice(0, term.length) == term)\n        found.push(word);\n    }\n\n    if (found.length) return {list: found, from: from, to: to};\n  });\n\n  CodeMirror.commands.autocomplete = CodeMirror.showHint;\n\n  var defaultOptions = {\n    hint: CodeMirror.hint.auto,\n    completeSingle: true,\n    alignWithWord: true,\n    closeCharacters: /[\\s()\\[\\]{};:>,]/,\n    closeOnUnfocus: true,\n    completeOnSingleClick: true,\n    container: null,\n    customKeys: null,\n    extraKeys: null\n  };\n\n  CodeMirror.defineOption(\"hintOptions\", null);\n});\n"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/plugins/codemirror/lib/codemirror.css",
    "content": "/* BASICS */\n\n.CodeMirror {\n  /* Set height, width, borders, and global font properties here */\n  font-family: monospace;\n  height: 300px;\n  color: black;\n  direction: ltr;\n}\n\n/* PADDING */\n\n.CodeMirror-lines {\n  padding: 4px 0; /* Vertical padding around content */\n}\n.CodeMirror pre {\n  padding: 0 4px; /* Horizontal padding of content */\n}\n\n.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {\n  background-color: white; /* The little square between H and V scrollbars */\n}\n\n/* GUTTER */\n\n.CodeMirror-gutters {\n  border-right: 1px solid #ddd;\n  background-color: #f7f7f7;\n  white-space: nowrap;\n}\n.CodeMirror-linenumbers {}\n.CodeMirror-linenumber {\n  padding: 0 3px 0 5px;\n  min-width: 20px;\n  text-align: right;\n  color: #999;\n  white-space: nowrap;\n}\n\n.CodeMirror-guttermarker { color: black; }\n.CodeMirror-guttermarker-subtle { color: #999; }\n\n/* CURSOR */\n\n.CodeMirror-cursor {\n  border-left: 1px solid black;\n  border-right: none;\n  width: 0;\n}\n/* Shown when moving in bi-directional text */\n.CodeMirror div.CodeMirror-secondarycursor {\n  border-left: 1px solid silver;\n}\n.cm-fat-cursor .CodeMirror-cursor {\n  width: auto;\n  border: 0 !important;\n  background: #7e7;\n}\n.cm-fat-cursor div.CodeMirror-cursors {\n  z-index: 1;\n}\n.cm-fat-cursor-mark {\n  background-color: rgba(20, 255, 20, 0.5);\n  -webkit-animation: blink 1.06s steps(1) infinite;\n  -moz-animation: blink 1.06s steps(1) infinite;\n  animation: blink 1.06s steps(1) infinite;\n}\n.cm-animate-fat-cursor {\n  width: auto;\n  border: 0;\n  -webkit-animation: blink 1.06s steps(1) infinite;\n  -moz-animation: blink 1.06s steps(1) infinite;\n  animation: blink 1.06s steps(1) infinite;\n  background-color: #7e7;\n}\n@-moz-keyframes blink {\n  0% {}\n  50% { background-color: transparent; }\n  100% {}\n}\n@-webkit-keyframes blink {\n  0% {}\n  50% { background-color: transparent; }\n  100% {}\n}\n@keyframes blink {\n  0% {}\n  50% { background-color: transparent; }\n  100% {}\n}\n\n/* Can style cursor different in overwrite (non-insert) mode */\n.CodeMirror-overwrite .CodeMirror-cursor {}\n\n.cm-tab { display: inline-block; text-decoration: inherit; }\n\n.CodeMirror-rulers {\n  position: absolute;\n  left: 0; right: 0; top: -50px; bottom: -20px;\n  overflow: hidden;\n}\n.CodeMirror-ruler {\n  border-left: 1px solid #ccc;\n  top: 0; bottom: 0;\n  position: absolute;\n}\n\n/* DEFAULT THEME */\n\n.cm-s-default .cm-header {color: blue;}\n.cm-s-default .cm-quote {color: #090;}\n.cm-negative {color: #d44;}\n.cm-positive {color: #292;}\n.cm-header, .cm-strong {font-weight: bold;}\n.cm-em {font-style: italic;}\n.cm-link {text-decoration: underline;}\n.cm-strikethrough {text-decoration: line-through;}\n\n.cm-s-default .cm-keyword {color: #708;}\n.cm-s-default .cm-atom {color: #219;}\n.cm-s-default .cm-number {color: #164;}\n.cm-s-default .cm-def {color: #00f;}\n.cm-s-default .cm-variable,\n.cm-s-default .cm-punctuation,\n.cm-s-default .cm-property,\n.cm-s-default .cm-operator {}\n.cm-s-default .cm-variable-2 {color: #05a;}\n.cm-s-default .cm-variable-3, .cm-s-default .cm-type {color: #085;}\n.cm-s-default .cm-comment {color: #a50;}\n.cm-s-default .cm-string {color: #a11;}\n.cm-s-default .cm-string-2 {color: #f50;}\n.cm-s-default .cm-meta {color: #555;}\n.cm-s-default .cm-qualifier {color: #555;}\n.cm-s-default .cm-builtin {color: #30a;}\n.cm-s-default .cm-bracket {color: #997;}\n.cm-s-default .cm-tag {color: #170;}\n.cm-s-default .cm-attribute {color: #00c;}\n.cm-s-default .cm-hr {color: #999;}\n.cm-s-default .cm-link {color: #00c;}\n\n.cm-s-default .cm-error {color: #f00;}\n.cm-invalidchar {color: #f00;}\n\n.CodeMirror-composing { border-bottom: 2px solid; }\n\n/* Default styles for common addons */\n\ndiv.CodeMirror span.CodeMirror-matchingbracket {color: #0b0;}\ndiv.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;}\n.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }\n.CodeMirror-activeline-background {background: #e8f2ff;}\n\n/* STOP */\n\n/* The rest of this file contains styles related to the mechanics of\n   the editor. You probably shouldn't touch them. */\n\n.CodeMirror {\n  position: relative;\n  overflow: hidden;\n  background: white;\n}\n\n.CodeMirror-scroll {\n  overflow: scroll !important; /* Things will break if this is overridden */\n  /* 30px is the magic margin used to hide the element's real scrollbars */\n  /* See overflow: hidden in .CodeMirror */\n  margin-bottom: -30px; margin-right: -30px;\n  padding-bottom: 30px;\n  height: 100%;\n  outline: none; /* Prevent dragging from highlighting the element */\n  position: relative;\n}\n.CodeMirror-sizer {\n  position: relative;\n  border-right: 30px solid transparent;\n}\n\n/* The fake, visible scrollbars. Used to force redraw during scrolling\n   before actual scrolling happens, thus preventing shaking and\n   flickering artifacts. */\n.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {\n  position: absolute;\n  z-index: 6;\n  display: none;\n}\n.CodeMirror-vscrollbar {\n  right: 0; top: 0;\n  overflow-x: hidden;\n  overflow-y: scroll;\n}\n.CodeMirror-hscrollbar {\n  bottom: 0; left: 0;\n  overflow-y: hidden;\n  overflow-x: scroll;\n}\n.CodeMirror-scrollbar-filler {\n  right: 0; bottom: 0;\n}\n.CodeMirror-gutter-filler {\n  left: 0; bottom: 0;\n}\n\n.CodeMirror-gutters {\n  position: absolute; left: 0; top: 0;\n  min-height: 100%;\n  z-index: 3;\n}\n.CodeMirror-gutter {\n  white-space: normal;\n  height: 100%;\n  display: inline-block;\n  vertical-align: top;\n  margin-bottom: -30px;\n}\n.CodeMirror-gutter-wrapper {\n  position: absolute;\n  z-index: 4;\n  background: none !important;\n  border: none !important;\n}\n.CodeMirror-gutter-background {\n  position: absolute;\n  top: 0; bottom: 0;\n  z-index: 4;\n}\n.CodeMirror-gutter-elt {\n  position: absolute;\n  cursor: default;\n  z-index: 4;\n}\n.CodeMirror-gutter-wrapper ::selection { background-color: transparent }\n.CodeMirror-gutter-wrapper ::-moz-selection { background-color: transparent }\n\n.CodeMirror-lines {\n  cursor: text;\n  min-height: 1px; /* prevents collapsing before first draw */\n}\n.CodeMirror pre {\n  /* Reset some styles that the rest of the page might have set */\n  -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;\n  border-width: 0;\n  background: transparent;\n  font-family: inherit;\n  font-size: inherit;\n  margin: 0;\n  white-space: pre;\n  word-wrap: normal;\n  line-height: inherit;\n  color: inherit;\n  z-index: 2;\n  position: relative;\n  overflow: visible;\n  -webkit-tap-highlight-color: transparent;\n  -webkit-font-variant-ligatures: contextual;\n  font-variant-ligatures: contextual;\n}\n.CodeMirror-wrap pre {\n  word-wrap: break-word;\n  white-space: pre-wrap;\n  word-break: normal;\n}\n\n.CodeMirror-linebackground {\n  position: absolute;\n  left: 0; right: 0; top: 0; bottom: 0;\n  z-index: 0;\n}\n\n.CodeMirror-linewidget {\n  position: relative;\n  z-index: 2;\n  padding: 0.1px; /* Force widget margins to stay inside of the container */\n}\n\n.CodeMirror-widget {}\n\n.CodeMirror-rtl pre { direction: rtl; }\n\n.CodeMirror-code {\n  outline: none;\n}\n\n/* Force content-box sizing for the elements where we expect it */\n.CodeMirror-scroll,\n.CodeMirror-sizer,\n.CodeMirror-gutter,\n.CodeMirror-gutters,\n.CodeMirror-linenumber {\n  -moz-box-sizing: content-box;\n  box-sizing: content-box;\n}\n\n.CodeMirror-measure {\n  position: absolute;\n  width: 100%;\n  height: 0;\n  overflow: hidden;\n  visibility: hidden;\n}\n\n.CodeMirror-cursor {\n  position: absolute;\n  pointer-events: none;\n}\n.CodeMirror-measure pre { position: static; }\n\ndiv.CodeMirror-cursors {\n  visibility: hidden;\n  position: relative;\n  z-index: 3;\n}\ndiv.CodeMirror-dragcursors {\n  visibility: visible;\n}\n\n.CodeMirror-focused div.CodeMirror-cursors {\n  visibility: visible;\n}\n\n.CodeMirror-selected { background: #d9d9d9; }\n.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }\n.CodeMirror-crosshair { cursor: crosshair; }\n.CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }\n.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }\n\n.cm-searching {\n  background-color: #ffa;\n  background-color: rgba(255, 255, 0, .4);\n}\n\n/* Used to force a border model for a node */\n.cm-force-border { padding-right: .1px; }\n\n@media print {\n  /* Hide the cursor when printing */\n  .CodeMirror div.CodeMirror-cursors {\n    visibility: hidden;\n  }\n}\n\n/* See issue #2901 */\n.cm-tab-wrap-hack:after { content: ''; }\n\n/* Help users use markselection to safely style text background */\nspan.CodeMirror-selectedtext { background: none; }\n"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/plugins/codemirror/lib/codemirror.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: https://codemirror.net/LICENSE\n\n// This is CodeMirror (https://codemirror.net), a code editor\n// implemented in JavaScript on top of the browser's DOM.\n//\n// You can find some technical background for some of the code below\n// at http://marijnhaverbeke.nl/blog/#cm-internals .\n\n(function (global, factory) {\n  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :\n  typeof define === 'function' && define.amd ? define(factory) :\n  (global.CodeMirror = factory());\n}(this, (function () { 'use strict';\n\n  // Kludges for bugs and behavior differences that can't be feature\n  // detected are enabled based on userAgent etc sniffing.\n  var userAgent = navigator.userAgent;\n  var platform = navigator.platform;\n\n  var gecko = /gecko\\/\\d/i.test(userAgent);\n  var ie_upto10 = /MSIE \\d/.test(userAgent);\n  var ie_11up = /Trident\\/(?:[7-9]|\\d{2,})\\..*rv:(\\d+)/.exec(userAgent);\n  var edge = /Edge\\/(\\d+)/.exec(userAgent);\n  var ie = ie_upto10 || ie_11up || edge;\n  var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : +(edge || ie_11up)[1]);\n  var webkit = !edge && /WebKit\\//.test(userAgent);\n  var qtwebkit = webkit && /Qt\\/\\d+\\.\\d+/.test(userAgent);\n  var chrome = !edge && /Chrome\\//.test(userAgent);\n  var presto = /Opera\\//.test(userAgent);\n  var safari = /Apple Computer/.test(navigator.vendor);\n  var mac_geMountainLion = /Mac OS X 1\\d\\D([8-9]|\\d\\d)\\D/.test(userAgent);\n  var phantom = /PhantomJS/.test(userAgent);\n\n  var ios = !edge && /AppleWebKit/.test(userAgent) && /Mobile\\/\\w+/.test(userAgent);\n  var android = /Android/.test(userAgent);\n  // This is woefully incomplete. Suggestions for alternative methods welcome.\n  var mobile = ios || android || /webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent);\n  var mac = ios || /Mac/.test(platform);\n  var chromeOS = /\\bCrOS\\b/.test(userAgent);\n  var windows = /win/i.test(platform);\n\n  var presto_version = presto && userAgent.match(/Version\\/(\\d*\\.\\d*)/);\n  if (presto_version) { presto_version = Number(presto_version[1]); }\n  if (presto_version && presto_version >= 15) { presto = false; webkit = true; }\n  // Some browsers use the wrong event properties to signal cmd/ctrl on OS X\n  var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11));\n  var captureRightClick = gecko || (ie && ie_version >= 9);\n\n  function classTest(cls) { return new RegExp(\"(^|\\\\s)\" + cls + \"(?:$|\\\\s)\\\\s*\") }\n\n  var rmClass = function(node, cls) {\n    var current = node.className;\n    var match = classTest(cls).exec(current);\n    if (match) {\n      var after = current.slice(match.index + match[0].length);\n      node.className = current.slice(0, match.index) + (after ? match[1] + after : \"\");\n    }\n  };\n\n  function removeChildren(e) {\n    for (var count = e.childNodes.length; count > 0; --count)\n      { e.removeChild(e.firstChild); }\n    return e\n  }\n\n  function removeChildrenAndAdd(parent, e) {\n    return removeChildren(parent).appendChild(e)\n  }\n\n  function elt(tag, content, className, style) {\n    var e = document.createElement(tag);\n    if (className) { e.className = className; }\n    if (style) { e.style.cssText = style; }\n    if (typeof content == \"string\") { e.appendChild(document.createTextNode(content)); }\n    else if (content) { for (var i = 0; i < content.length; ++i) { e.appendChild(content[i]); } }\n    return e\n  }\n  // wrapper for elt, which removes the elt from the accessibility tree\n  function eltP(tag, content, className, style) {\n    var e = elt(tag, content, className, style);\n    e.setAttribute(\"role\", \"presentation\");\n    return e\n  }\n\n  var range;\n  if (document.createRange) { range = function(node, start, end, endNode) {\n    var r = document.createRange();\n    r.setEnd(endNode || node, end);\n    r.setStart(node, start);\n    return r\n  }; }\n  else { range = function(node, start, end) {\n    var r = document.body.createTextRange();\n    try { r.moveToElementText(node.parentNode); }\n    catch(e) { return r }\n    r.collapse(true);\n    r.moveEnd(\"character\", end);\n    r.moveStart(\"character\", start);\n    return r\n  }; }\n\n  function contains(parent, child) {\n    if (child.nodeType == 3) // Android browser always returns false when child is a textnode\n      { child = child.parentNode; }\n    if (parent.contains)\n      { return parent.contains(child) }\n    do {\n      if (child.nodeType == 11) { child = child.host; }\n      if (child == parent) { return true }\n    } while (child = child.parentNode)\n  }\n\n  function activeElt() {\n    // IE and Edge may throw an \"Unspecified Error\" when accessing document.activeElement.\n    // IE < 10 will throw when accessed while the page is loading or in an iframe.\n    // IE > 9 and Edge will throw when accessed in an iframe if document.body is unavailable.\n    var activeElement;\n    try {\n      activeElement = document.activeElement;\n    } catch(e) {\n      activeElement = document.body || null;\n    }\n    while (activeElement && activeElement.shadowRoot && activeElement.shadowRoot.activeElement)\n      { activeElement = activeElement.shadowRoot.activeElement; }\n    return activeElement\n  }\n\n  function addClass(node, cls) {\n    var current = node.className;\n    if (!classTest(cls).test(current)) { node.className += (current ? \" \" : \"\") + cls; }\n  }\n  function joinClasses(a, b) {\n    var as = a.split(\" \");\n    for (var i = 0; i < as.length; i++)\n      { if (as[i] && !classTest(as[i]).test(b)) { b += \" \" + as[i]; } }\n    return b\n  }\n\n  var selectInput = function(node) { node.select(); };\n  if (ios) // Mobile Safari apparently has a bug where select() is broken.\n    { selectInput = function(node) { node.selectionStart = 0; node.selectionEnd = node.value.length; }; }\n  else if (ie) // Suppress mysterious IE10 errors\n    { selectInput = function(node) { try { node.select(); } catch(_e) {} }; }\n\n  function bind(f) {\n    var args = Array.prototype.slice.call(arguments, 1);\n    return function(){return f.apply(null, args)}\n  }\n\n  function copyObj(obj, target, overwrite) {\n    if (!target) { target = {}; }\n    for (var prop in obj)\n      { if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop)))\n        { target[prop] = obj[prop]; } }\n    return target\n  }\n\n  // Counts the column offset in a string, taking tabs into account.\n  // Used mostly to find indentation.\n  function countColumn(string, end, tabSize, startIndex, startValue) {\n    if (end == null) {\n      end = string.search(/[^\\s\\u00a0]/);\n      if (end == -1) { end = string.length; }\n    }\n    for (var i = startIndex || 0, n = startValue || 0;;) {\n      var nextTab = string.indexOf(\"\\t\", i);\n      if (nextTab < 0 || nextTab >= end)\n        { return n + (end - i) }\n      n += nextTab - i;\n      n += tabSize - (n % tabSize);\n      i = nextTab + 1;\n    }\n  }\n\n  var Delayed = function() {this.id = null;};\n  Delayed.prototype.set = function (ms, f) {\n    clearTimeout(this.id);\n    this.id = setTimeout(f, ms);\n  };\n\n  function indexOf(array, elt) {\n    for (var i = 0; i < array.length; ++i)\n      { if (array[i] == elt) { return i } }\n    return -1\n  }\n\n  // Number of pixels added to scroller and sizer to hide scrollbar\n  var scrollerGap = 30;\n\n  // Returned or thrown by various protocols to signal 'I'm not\n  // handling this'.\n  var Pass = {toString: function(){return \"CodeMirror.Pass\"}};\n\n  // Reused option objects for setSelection & friends\n  var sel_dontScroll = {scroll: false}, sel_mouse = {origin: \"*mouse\"}, sel_move = {origin: \"+move\"};\n\n  // The inverse of countColumn -- find the offset that corresponds to\n  // a particular column.\n  function findColumn(string, goal, tabSize) {\n    for (var pos = 0, col = 0;;) {\n      var nextTab = string.indexOf(\"\\t\", pos);\n      if (nextTab == -1) { nextTab = string.length; }\n      var skipped = nextTab - pos;\n      if (nextTab == string.length || col + skipped >= goal)\n        { return pos + Math.min(skipped, goal - col) }\n      col += nextTab - pos;\n      col += tabSize - (col % tabSize);\n      pos = nextTab + 1;\n      if (col >= goal) { return pos }\n    }\n  }\n\n  var spaceStrs = [\"\"];\n  function spaceStr(n) {\n    while (spaceStrs.length <= n)\n      { spaceStrs.push(lst(spaceStrs) + \" \"); }\n    return spaceStrs[n]\n  }\n\n  function lst(arr) { return arr[arr.length-1] }\n\n  function map(array, f) {\n    var out = [];\n    for (var i = 0; i < array.length; i++) { out[i] = f(array[i], i); }\n    return out\n  }\n\n  function insertSorted(array, value, score) {\n    var pos = 0, priority = score(value);\n    while (pos < array.length && score(array[pos]) <= priority) { pos++; }\n    array.splice(pos, 0, value);\n  }\n\n  function nothing() {}\n\n  function createObj(base, props) {\n    var inst;\n    if (Object.create) {\n      inst = Object.create(base);\n    } else {\n      nothing.prototype = base;\n      inst = new nothing();\n    }\n    if (props) { copyObj(props, inst); }\n    return inst\n  }\n\n  var nonASCIISingleCaseWordChar = /[\\u00df\\u0587\\u0590-\\u05f4\\u0600-\\u06ff\\u3040-\\u309f\\u30a0-\\u30ff\\u3400-\\u4db5\\u4e00-\\u9fcc\\uac00-\\ud7af]/;\n  function isWordCharBasic(ch) {\n    return /\\w/.test(ch) || ch > \"\\x80\" &&\n      (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch))\n  }\n  function isWordChar(ch, helper) {\n    if (!helper) { return isWordCharBasic(ch) }\n    if (helper.source.indexOf(\"\\\\w\") > -1 && isWordCharBasic(ch)) { return true }\n    return helper.test(ch)\n  }\n\n  function isEmpty(obj) {\n    for (var n in obj) { if (obj.hasOwnProperty(n) && obj[n]) { return false } }\n    return true\n  }\n\n  // Extending unicode characters. A series of a non-extending char +\n  // any number of extending chars is treated as a single unit as far\n  // as editing and measuring is concerned. This is not fully correct,\n  // since some scripts/fonts/browsers also treat other configurations\n  // of code points as a group.\n  var extendingChars = /[\\u0300-\\u036f\\u0483-\\u0489\\u0591-\\u05bd\\u05bf\\u05c1\\u05c2\\u05c4\\u05c5\\u05c7\\u0610-\\u061a\\u064b-\\u065e\\u0670\\u06d6-\\u06dc\\u06de-\\u06e4\\u06e7\\u06e8\\u06ea-\\u06ed\\u0711\\u0730-\\u074a\\u07a6-\\u07b0\\u07eb-\\u07f3\\u0816-\\u0819\\u081b-\\u0823\\u0825-\\u0827\\u0829-\\u082d\\u0900-\\u0902\\u093c\\u0941-\\u0948\\u094d\\u0951-\\u0955\\u0962\\u0963\\u0981\\u09bc\\u09be\\u09c1-\\u09c4\\u09cd\\u09d7\\u09e2\\u09e3\\u0a01\\u0a02\\u0a3c\\u0a41\\u0a42\\u0a47\\u0a48\\u0a4b-\\u0a4d\\u0a51\\u0a70\\u0a71\\u0a75\\u0a81\\u0a82\\u0abc\\u0ac1-\\u0ac5\\u0ac7\\u0ac8\\u0acd\\u0ae2\\u0ae3\\u0b01\\u0b3c\\u0b3e\\u0b3f\\u0b41-\\u0b44\\u0b4d\\u0b56\\u0b57\\u0b62\\u0b63\\u0b82\\u0bbe\\u0bc0\\u0bcd\\u0bd7\\u0c3e-\\u0c40\\u0c46-\\u0c48\\u0c4a-\\u0c4d\\u0c55\\u0c56\\u0c62\\u0c63\\u0cbc\\u0cbf\\u0cc2\\u0cc6\\u0ccc\\u0ccd\\u0cd5\\u0cd6\\u0ce2\\u0ce3\\u0d3e\\u0d41-\\u0d44\\u0d4d\\u0d57\\u0d62\\u0d63\\u0dca\\u0dcf\\u0dd2-\\u0dd4\\u0dd6\\u0ddf\\u0e31\\u0e34-\\u0e3a\\u0e47-\\u0e4e\\u0eb1\\u0eb4-\\u0eb9\\u0ebb\\u0ebc\\u0ec8-\\u0ecd\\u0f18\\u0f19\\u0f35\\u0f37\\u0f39\\u0f71-\\u0f7e\\u0f80-\\u0f84\\u0f86\\u0f87\\u0f90-\\u0f97\\u0f99-\\u0fbc\\u0fc6\\u102d-\\u1030\\u1032-\\u1037\\u1039\\u103a\\u103d\\u103e\\u1058\\u1059\\u105e-\\u1060\\u1071-\\u1074\\u1082\\u1085\\u1086\\u108d\\u109d\\u135f\\u1712-\\u1714\\u1732-\\u1734\\u1752\\u1753\\u1772\\u1773\\u17b7-\\u17bd\\u17c6\\u17c9-\\u17d3\\u17dd\\u180b-\\u180d\\u18a9\\u1920-\\u1922\\u1927\\u1928\\u1932\\u1939-\\u193b\\u1a17\\u1a18\\u1a56\\u1a58-\\u1a5e\\u1a60\\u1a62\\u1a65-\\u1a6c\\u1a73-\\u1a7c\\u1a7f\\u1b00-\\u1b03\\u1b34\\u1b36-\\u1b3a\\u1b3c\\u1b42\\u1b6b-\\u1b73\\u1b80\\u1b81\\u1ba2-\\u1ba5\\u1ba8\\u1ba9\\u1c2c-\\u1c33\\u1c36\\u1c37\\u1cd0-\\u1cd2\\u1cd4-\\u1ce0\\u1ce2-\\u1ce8\\u1ced\\u1dc0-\\u1de6\\u1dfd-\\u1dff\\u200c\\u200d\\u20d0-\\u20f0\\u2cef-\\u2cf1\\u2de0-\\u2dff\\u302a-\\u302f\\u3099\\u309a\\ua66f-\\ua672\\ua67c\\ua67d\\ua6f0\\ua6f1\\ua802\\ua806\\ua80b\\ua825\\ua826\\ua8c4\\ua8e0-\\ua8f1\\ua926-\\ua92d\\ua947-\\ua951\\ua980-\\ua982\\ua9b3\\ua9b6-\\ua9b9\\ua9bc\\uaa29-\\uaa2e\\uaa31\\uaa32\\uaa35\\uaa36\\uaa43\\uaa4c\\uaab0\\uaab2-\\uaab4\\uaab7\\uaab8\\uaabe\\uaabf\\uaac1\\uabe5\\uabe8\\uabed\\udc00-\\udfff\\ufb1e\\ufe00-\\ufe0f\\ufe20-\\ufe26\\uff9e\\uff9f]/;\n  function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch) }\n\n  // Returns a number from the range [`0`; `str.length`] unless `pos` is outside that range.\n  function skipExtendingChars(str, pos, dir) {\n    while ((dir < 0 ? pos > 0 : pos < str.length) && isExtendingChar(str.charAt(pos))) { pos += dir; }\n    return pos\n  }\n\n  // Returns the value from the range [`from`; `to`] that satisfies\n  // `pred` and is closest to `from`. Assumes that at least `to`\n  // satisfies `pred`. Supports `from` being greater than `to`.\n  function findFirst(pred, from, to) {\n    // At any point we are certain `to` satisfies `pred`, don't know\n    // whether `from` does.\n    var dir = from > to ? -1 : 1;\n    for (;;) {\n      if (from == to) { return from }\n      var midF = (from + to) / 2, mid = dir < 0 ? Math.ceil(midF) : Math.floor(midF);\n      if (mid == from) { return pred(mid) ? from : to }\n      if (pred(mid)) { to = mid; }\n      else { from = mid + dir; }\n    }\n  }\n\n  // The display handles the DOM integration, both for input reading\n  // and content drawing. It holds references to DOM nodes and\n  // display-related state.\n\n  function Display(place, doc, input) {\n    var d = this;\n    this.input = input;\n\n    // Covers bottom-right square when both scrollbars are present.\n    d.scrollbarFiller = elt(\"div\", null, \"CodeMirror-scrollbar-filler\");\n    d.scrollbarFiller.setAttribute(\"cm-not-content\", \"true\");\n    // Covers bottom of gutter when coverGutterNextToScrollbar is on\n    // and h scrollbar is present.\n    d.gutterFiller = elt(\"div\", null, \"CodeMirror-gutter-filler\");\n    d.gutterFiller.setAttribute(\"cm-not-content\", \"true\");\n    // Will contain the actual code, positioned to cover the viewport.\n    d.lineDiv = eltP(\"div\", null, \"CodeMirror-code\");\n    // Elements are added to these to represent selection and cursors.\n    d.selectionDiv = elt(\"div\", null, null, \"position: relative; z-index: 1\");\n    d.cursorDiv = elt(\"div\", null, \"CodeMirror-cursors\");\n    // A visibility: hidden element used to find the size of things.\n    d.measure = elt(\"div\", null, \"CodeMirror-measure\");\n    // When lines outside of the viewport are measured, they are drawn in this.\n    d.lineMeasure = elt(\"div\", null, \"CodeMirror-measure\");\n    // Wraps everything that needs to exist inside the vertically-padded coordinate system\n    d.lineSpace = eltP(\"div\", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv],\n                      null, \"position: relative; outline: none\");\n    var lines = eltP(\"div\", [d.lineSpace], \"CodeMirror-lines\");\n    // Moved around its parent to cover visible view.\n    d.mover = elt(\"div\", [lines], null, \"position: relative\");\n    // Set to the height of the document, allowing scrolling.\n    d.sizer = elt(\"div\", [d.mover], \"CodeMirror-sizer\");\n    d.sizerWidth = null;\n    // Behavior of elts with overflow: auto and padding is\n    // inconsistent across browsers. This is used to ensure the\n    // scrollable area is big enough.\n    d.heightForcer = elt(\"div\", null, null, \"position: absolute; height: \" + scrollerGap + \"px; width: 1px;\");\n    // Will contain the gutters, if any.\n    d.gutters = elt(\"div\", null, \"CodeMirror-gutters\");\n    d.lineGutter = null;\n    // Actual scrollable element.\n    d.scroller = elt(\"div\", [d.sizer, d.heightForcer, d.gutters], \"CodeMirror-scroll\");\n    d.scroller.setAttribute(\"tabIndex\", \"-1\");\n    // The element in which the editor lives.\n    d.wrapper = elt(\"div\", [d.scrollbarFiller, d.gutterFiller, d.scroller], \"CodeMirror\");\n\n    // Work around IE7 z-index bug (not perfect, hence IE7 not really being supported)\n    if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; }\n    if (!webkit && !(gecko && mobile)) { d.scroller.draggable = true; }\n\n    if (place) {\n      if (place.appendChild) { place.appendChild(d.wrapper); }\n      else { place(d.wrapper); }\n    }\n\n    // Current rendered range (may be bigger than the view window).\n    d.viewFrom = d.viewTo = doc.first;\n    d.reportedViewFrom = d.reportedViewTo = doc.first;\n    // Information about the rendered lines.\n    d.view = [];\n    d.renderedView = null;\n    // Holds info about a single rendered line when it was rendered\n    // for measurement, while not in view.\n    d.externalMeasured = null;\n    // Empty space (in pixels) above the view\n    d.viewOffset = 0;\n    d.lastWrapHeight = d.lastWrapWidth = 0;\n    d.updateLineNumbers = null;\n\n    d.nativeBarWidth = d.barHeight = d.barWidth = 0;\n    d.scrollbarsClipped = false;\n\n    // Used to only resize the line number gutter when necessary (when\n    // the amount of lines crosses a boundary that makes its width change)\n    d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null;\n    // Set to true when a non-horizontal-scrolling line widget is\n    // added. As an optimization, line widget aligning is skipped when\n    // this is false.\n    d.alignWidgets = false;\n\n    d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;\n\n    // Tracks the maximum line length so that the horizontal scrollbar\n    // can be kept static when scrolling.\n    d.maxLine = null;\n    d.maxLineLength = 0;\n    d.maxLineChanged = false;\n\n    // Used for measuring wheel scrolling granularity\n    d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null;\n\n    // True when shift is held down.\n    d.shift = false;\n\n    // Used to track whether anything happened since the context menu\n    // was opened.\n    d.selForContextMenu = null;\n\n    d.activeTouch = null;\n\n    input.init(d);\n  }\n\n  // Find the line object corresponding to the given line number.\n  function getLine(doc, n) {\n    n -= doc.first;\n    if (n < 0 || n >= doc.size) { throw new Error(\"There is no line \" + (n + doc.first) + \" in the document.\") }\n    var chunk = doc;\n    while (!chunk.lines) {\n      for (var i = 0;; ++i) {\n        var child = chunk.children[i], sz = child.chunkSize();\n        if (n < sz) { chunk = child; break }\n        n -= sz;\n      }\n    }\n    return chunk.lines[n]\n  }\n\n  // Get the part of a document between two positions, as an array of\n  // strings.\n  function getBetween(doc, start, end) {\n    var out = [], n = start.line;\n    doc.iter(start.line, end.line + 1, function (line) {\n      var text = line.text;\n      if (n == end.line) { text = text.slice(0, end.ch); }\n      if (n == start.line) { text = text.slice(start.ch); }\n      out.push(text);\n      ++n;\n    });\n    return out\n  }\n  // Get the lines between from and to, as array of strings.\n  function getLines(doc, from, to) {\n    var out = [];\n    doc.iter(from, to, function (line) { out.push(line.text); }); // iter aborts when callback returns truthy value\n    return out\n  }\n\n  // Update the height of a line, propagating the height change\n  // upwards to parent nodes.\n  function updateLineHeight(line, height) {\n    var diff = height - line.height;\n    if (diff) { for (var n = line; n; n = n.parent) { n.height += diff; } }\n  }\n\n  // Given a line object, find its line number by walking up through\n  // its parent links.\n  function lineNo(line) {\n    if (line.parent == null) { return null }\n    var cur = line.parent, no = indexOf(cur.lines, line);\n    for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) {\n      for (var i = 0;; ++i) {\n        if (chunk.children[i] == cur) { break }\n        no += chunk.children[i].chunkSize();\n      }\n    }\n    return no + cur.first\n  }\n\n  // Find the line at the given vertical position, using the height\n  // information in the document tree.\n  function lineAtHeight(chunk, h) {\n    var n = chunk.first;\n    outer: do {\n      for (var i$1 = 0; i$1 < chunk.children.length; ++i$1) {\n        var child = chunk.children[i$1], ch = child.height;\n        if (h < ch) { chunk = child; continue outer }\n        h -= ch;\n        n += child.chunkSize();\n      }\n      return n\n    } while (!chunk.lines)\n    var i = 0;\n    for (; i < chunk.lines.length; ++i) {\n      var line = chunk.lines[i], lh = line.height;\n      if (h < lh) { break }\n      h -= lh;\n    }\n    return n + i\n  }\n\n  function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size}\n\n  function lineNumberFor(options, i) {\n    return String(options.lineNumberFormatter(i + options.firstLineNumber))\n  }\n\n  // A Pos instance represents a position within the text.\n  function Pos(line, ch, sticky) {\n    if ( sticky === void 0 ) sticky = null;\n\n    if (!(this instanceof Pos)) { return new Pos(line, ch, sticky) }\n    this.line = line;\n    this.ch = ch;\n    this.sticky = sticky;\n  }\n\n  // Compare two positions, return 0 if they are the same, a negative\n  // number when a is less, and a positive number otherwise.\n  function cmp(a, b) { return a.line - b.line || a.ch - b.ch }\n\n  function equalCursorPos(a, b) { return a.sticky == b.sticky && cmp(a, b) == 0 }\n\n  function copyPos(x) {return Pos(x.line, x.ch)}\n  function maxPos(a, b) { return cmp(a, b) < 0 ? b : a }\n  function minPos(a, b) { return cmp(a, b) < 0 ? a : b }\n\n  // Most of the external API clips given positions to make sure they\n  // actually exist within the document.\n  function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1))}\n  function clipPos(doc, pos) {\n    if (pos.line < doc.first) { return Pos(doc.first, 0) }\n    var last = doc.first + doc.size - 1;\n    if (pos.line > last) { return Pos(last, getLine(doc, last).text.length) }\n    return clipToLen(pos, getLine(doc, pos.line).text.length)\n  }\n  function clipToLen(pos, linelen) {\n    var ch = pos.ch;\n    if (ch == null || ch > linelen) { return Pos(pos.line, linelen) }\n    else if (ch < 0) { return Pos(pos.line, 0) }\n    else { return pos }\n  }\n  function clipPosArray(doc, array) {\n    var out = [];\n    for (var i = 0; i < array.length; i++) { out[i] = clipPos(doc, array[i]); }\n    return out\n  }\n\n  // Optimize some code when these features are not used.\n  var sawReadOnlySpans = false, sawCollapsedSpans = false;\n\n  function seeReadOnlySpans() {\n    sawReadOnlySpans = true;\n  }\n\n  function seeCollapsedSpans() {\n    sawCollapsedSpans = true;\n  }\n\n  // TEXTMARKER SPANS\n\n  function MarkedSpan(marker, from, to) {\n    this.marker = marker;\n    this.from = from; this.to = to;\n  }\n\n  // Search an array of spans for a span matching the given marker.\n  function getMarkedSpanFor(spans, marker) {\n    if (spans) { for (var i = 0; i < spans.length; ++i) {\n      var span = spans[i];\n      if (span.marker == marker) { return span }\n    } }\n  }\n  // Remove a span from an array, returning undefined if no spans are\n  // left (we don't store arrays for lines without spans).\n  function removeMarkedSpan(spans, span) {\n    var r;\n    for (var i = 0; i < spans.length; ++i)\n      { if (spans[i] != span) { (r || (r = [])).push(spans[i]); } }\n    return r\n  }\n  // Add a span to a line.\n  function addMarkedSpan(line, span) {\n    line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span];\n    span.marker.attachLine(line);\n  }\n\n  // Used for the algorithm that adjusts markers for a change in the\n  // document. These functions cut an array of spans at a given\n  // character position, returning an array of remaining chunks (or\n  // undefined if nothing remains).\n  function markedSpansBefore(old, startCh, isInsert) {\n    var nw;\n    if (old) { for (var i = 0; i < old.length; ++i) {\n      var span = old[i], marker = span.marker;\n      var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh);\n      if (startsBefore || span.from == startCh && marker.type == \"bookmark\" && (!isInsert || !span.marker.insertLeft)) {\n        var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh)\n        ;(nw || (nw = [])).push(new MarkedSpan(marker, span.from, endsAfter ? null : span.to));\n      }\n    } }\n    return nw\n  }\n  function markedSpansAfter(old, endCh, isInsert) {\n    var nw;\n    if (old) { for (var i = 0; i < old.length; ++i) {\n      var span = old[i], marker = span.marker;\n      var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh);\n      if (endsAfter || span.from == endCh && marker.type == \"bookmark\" && (!isInsert || span.marker.insertLeft)) {\n        var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh)\n        ;(nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh,\n                                              span.to == null ? null : span.to - endCh));\n      }\n    } }\n    return nw\n  }\n\n  // Given a change object, compute the new set of marker spans that\n  // cover the line in which the change took place. Removes spans\n  // entirely within the change, reconnects spans belonging to the\n  // same marker that appear on both sides of the change, and cuts off\n  // spans partially within the change. Returns an array of span\n  // arrays with one element for each line in (after) the change.\n  function stretchSpansOverChange(doc, change) {\n    if (change.full) { return null }\n    var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans;\n    var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans;\n    if (!oldFirst && !oldLast) { return null }\n\n    var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0;\n    // Get the spans that 'stick out' on both sides\n    var first = markedSpansBefore(oldFirst, startCh, isInsert);\n    var last = markedSpansAfter(oldLast, endCh, isInsert);\n\n    // Next, merge those two ends\n    var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0);\n    if (first) {\n      // Fix up .to properties of first\n      for (var i = 0; i < first.length; ++i) {\n        var span = first[i];\n        if (span.to == null) {\n          var found = getMarkedSpanFor(last, span.marker);\n          if (!found) { span.to = startCh; }\n          else if (sameLine) { span.to = found.to == null ? null : found.to + offset; }\n        }\n      }\n    }\n    if (last) {\n      // Fix up .from in last (or move them into first in case of sameLine)\n      for (var i$1 = 0; i$1 < last.length; ++i$1) {\n        var span$1 = last[i$1];\n        if (span$1.to != null) { span$1.to += offset; }\n        if (span$1.from == null) {\n          var found$1 = getMarkedSpanFor(first, span$1.marker);\n          if (!found$1) {\n            span$1.from = offset;\n            if (sameLine) { (first || (first = [])).push(span$1); }\n          }\n        } else {\n          span$1.from += offset;\n          if (sameLine) { (first || (first = [])).push(span$1); }\n        }\n      }\n    }\n    // Make sure we didn't create any zero-length spans\n    if (first) { first = clearEmptySpans(first); }\n    if (last && last != first) { last = clearEmptySpans(last); }\n\n    var newMarkers = [first];\n    if (!sameLine) {\n      // Fill gap with whole-line-spans\n      var gap = change.text.length - 2, gapMarkers;\n      if (gap > 0 && first)\n        { for (var i$2 = 0; i$2 < first.length; ++i$2)\n          { if (first[i$2].to == null)\n            { (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i$2].marker, null, null)); } } }\n      for (var i$3 = 0; i$3 < gap; ++i$3)\n        { newMarkers.push(gapMarkers); }\n      newMarkers.push(last);\n    }\n    return newMarkers\n  }\n\n  // Remove spans that are empty and don't have a clearWhenEmpty\n  // option of false.\n  function clearEmptySpans(spans) {\n    for (var i = 0; i < spans.length; ++i) {\n      var span = spans[i];\n      if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false)\n        { spans.splice(i--, 1); }\n    }\n    if (!spans.length) { return null }\n    return spans\n  }\n\n  // Used to 'clip' out readOnly ranges when making a change.\n  function removeReadOnlyRanges(doc, from, to) {\n    var markers = null;\n    doc.iter(from.line, to.line + 1, function (line) {\n      if (line.markedSpans) { for (var i = 0; i < line.markedSpans.length; ++i) {\n        var mark = line.markedSpans[i].marker;\n        if (mark.readOnly && (!markers || indexOf(markers, mark) == -1))\n          { (markers || (markers = [])).push(mark); }\n      } }\n    });\n    if (!markers) { return null }\n    var parts = [{from: from, to: to}];\n    for (var i = 0; i < markers.length; ++i) {\n      var mk = markers[i], m = mk.find(0);\n      for (var j = 0; j < parts.length; ++j) {\n        var p = parts[j];\n        if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) { continue }\n        var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to);\n        if (dfrom < 0 || !mk.inclusiveLeft && !dfrom)\n          { newParts.push({from: p.from, to: m.from}); }\n        if (dto > 0 || !mk.inclusiveRight && !dto)\n          { newParts.push({from: m.to, to: p.to}); }\n        parts.splice.apply(parts, newParts);\n        j += newParts.length - 3;\n      }\n    }\n    return parts\n  }\n\n  // Connect or disconnect spans from a line.\n  function detachMarkedSpans(line) {\n    var spans = line.markedSpans;\n    if (!spans) { return }\n    for (var i = 0; i < spans.length; ++i)\n      { spans[i].marker.detachLine(line); }\n    line.markedSpans = null;\n  }\n  function attachMarkedSpans(line, spans) {\n    if (!spans) { return }\n    for (var i = 0; i < spans.length; ++i)\n      { spans[i].marker.attachLine(line); }\n    line.markedSpans = spans;\n  }\n\n  // Helpers used when computing which overlapping collapsed span\n  // counts as the larger one.\n  function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0 }\n  function extraRight(marker) { return marker.inclusiveRight ? 1 : 0 }\n\n  // Returns a number indicating which of two overlapping collapsed\n  // spans is larger (and thus includes the other). Falls back to\n  // comparing ids when the spans cover exactly the same range.\n  function compareCollapsedMarkers(a, b) {\n    var lenDiff = a.lines.length - b.lines.length;\n    if (lenDiff != 0) { return lenDiff }\n    var aPos = a.find(), bPos = b.find();\n    var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b);\n    if (fromCmp) { return -fromCmp }\n    var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b);\n    if (toCmp) { return toCmp }\n    return b.id - a.id\n  }\n\n  // Find out whether a line ends or starts in a collapsed span. If\n  // so, return the marker for that span.\n  function collapsedSpanAtSide(line, start) {\n    var sps = sawCollapsedSpans && line.markedSpans, found;\n    if (sps) { for (var sp = (void 0), i = 0; i < sps.length; ++i) {\n      sp = sps[i];\n      if (sp.marker.collapsed && (start ? sp.from : sp.to) == null &&\n          (!found || compareCollapsedMarkers(found, sp.marker) < 0))\n        { found = sp.marker; }\n    } }\n    return found\n  }\n  function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true) }\n  function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false) }\n\n  function collapsedSpanAround(line, ch) {\n    var sps = sawCollapsedSpans && line.markedSpans, found;\n    if (sps) { for (var i = 0; i < sps.length; ++i) {\n      var sp = sps[i];\n      if (sp.marker.collapsed && (sp.from == null || sp.from < ch) && (sp.to == null || sp.to > ch) &&\n          (!found || compareCollapsedMarkers(found, sp.marker) < 0)) { found = sp.marker; }\n    } }\n    return found\n  }\n\n  // Test whether there exists a collapsed span that partially\n  // overlaps (covers the start or end, but not both) of a new span.\n  // Such overlap is not allowed.\n  function conflictingCollapsedRange(doc, lineNo$$1, from, to, marker) {\n    var line = getLine(doc, lineNo$$1);\n    var sps = sawCollapsedSpans && line.markedSpans;\n    if (sps) { for (var i = 0; i < sps.length; ++i) {\n      var sp = sps[i];\n      if (!sp.marker.collapsed) { continue }\n      var found = sp.marker.find(0);\n      var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker);\n      var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker);\n      if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) { continue }\n      if (fromCmp <= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.to, from) >= 0 : cmp(found.to, from) > 0) ||\n          fromCmp >= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.from, to) <= 0 : cmp(found.from, to) < 0))\n        { return true }\n    } }\n  }\n\n  // A visual line is a line as drawn on the screen. Folding, for\n  // example, can cause multiple logical lines to appear on the same\n  // visual line. This finds the start of the visual line that the\n  // given line is part of (usually that is the line itself).\n  function visualLine(line) {\n    var merged;\n    while (merged = collapsedSpanAtStart(line))\n      { line = merged.find(-1, true).line; }\n    return line\n  }\n\n  function visualLineEnd(line) {\n    var merged;\n    while (merged = collapsedSpanAtEnd(line))\n      { line = merged.find(1, true).line; }\n    return line\n  }\n\n  // Returns an array of logical lines that continue the visual line\n  // started by the argument, or undefined if there are no such lines.\n  function visualLineContinued(line) {\n    var merged, lines;\n    while (merged = collapsedSpanAtEnd(line)) {\n      line = merged.find(1, true).line\n      ;(lines || (lines = [])).push(line);\n    }\n    return lines\n  }\n\n  // Get the line number of the start of the visual line that the\n  // given line number is part of.\n  function visualLineNo(doc, lineN) {\n    var line = getLine(doc, lineN), vis = visualLine(line);\n    if (line == vis) { return lineN }\n    return lineNo(vis)\n  }\n\n  // Get the line number of the start of the next visual line after\n  // the given line.\n  function visualLineEndNo(doc, lineN) {\n    if (lineN > doc.lastLine()) { return lineN }\n    var line = getLine(doc, lineN), merged;\n    if (!lineIsHidden(doc, line)) { return lineN }\n    while (merged = collapsedSpanAtEnd(line))\n      { line = merged.find(1, true).line; }\n    return lineNo(line) + 1\n  }\n\n  // Compute whether a line is hidden. Lines count as hidden when they\n  // are part of a visual line that starts with another line, or when\n  // they are entirely covered by collapsed, non-widget span.\n  function lineIsHidden(doc, line) {\n    var sps = sawCollapsedSpans && line.markedSpans;\n    if (sps) { for (var sp = (void 0), i = 0; i < sps.length; ++i) {\n      sp = sps[i];\n      if (!sp.marker.collapsed) { continue }\n      if (sp.from == null) { return true }\n      if (sp.marker.widgetNode) { continue }\n      if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp))\n        { return true }\n    } }\n  }\n  function lineIsHiddenInner(doc, line, span) {\n    if (span.to == null) {\n      var end = span.marker.find(1, true);\n      return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker))\n    }\n    if (span.marker.inclusiveRight && span.to == line.text.length)\n      { return true }\n    for (var sp = (void 0), i = 0; i < line.markedSpans.length; ++i) {\n      sp = line.markedSpans[i];\n      if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to &&\n          (sp.to == null || sp.to != span.from) &&\n          (sp.marker.inclusiveLeft || span.marker.inclusiveRight) &&\n          lineIsHiddenInner(doc, line, sp)) { return true }\n    }\n  }\n\n  // Find the height above the given line.\n  function heightAtLine(lineObj) {\n    lineObj = visualLine(lineObj);\n\n    var h = 0, chunk = lineObj.parent;\n    for (var i = 0; i < chunk.lines.length; ++i) {\n      var line = chunk.lines[i];\n      if (line == lineObj) { break }\n      else { h += line.height; }\n    }\n    for (var p = chunk.parent; p; chunk = p, p = chunk.parent) {\n      for (var i$1 = 0; i$1 < p.children.length; ++i$1) {\n        var cur = p.children[i$1];\n        if (cur == chunk) { break }\n        else { h += cur.height; }\n      }\n    }\n    return h\n  }\n\n  // Compute the character length of a line, taking into account\n  // collapsed ranges (see markText) that might hide parts, and join\n  // other lines onto it.\n  function lineLength(line) {\n    if (line.height == 0) { return 0 }\n    var len = line.text.length, merged, cur = line;\n    while (merged = collapsedSpanAtStart(cur)) {\n      var found = merged.find(0, true);\n      cur = found.from.line;\n      len += found.from.ch - found.to.ch;\n    }\n    cur = line;\n    while (merged = collapsedSpanAtEnd(cur)) {\n      var found$1 = merged.find(0, true);\n      len -= cur.text.length - found$1.from.ch;\n      cur = found$1.to.line;\n      len += cur.text.length - found$1.to.ch;\n    }\n    return len\n  }\n\n  // Find the longest line in the document.\n  function findMaxLine(cm) {\n    var d = cm.display, doc = cm.doc;\n    d.maxLine = getLine(doc, doc.first);\n    d.maxLineLength = lineLength(d.maxLine);\n    d.maxLineChanged = true;\n    doc.iter(function (line) {\n      var len = lineLength(line);\n      if (len > d.maxLineLength) {\n        d.maxLineLength = len;\n        d.maxLine = line;\n      }\n    });\n  }\n\n  // BIDI HELPERS\n\n  function iterateBidiSections(order, from, to, f) {\n    if (!order) { return f(from, to, \"ltr\", 0) }\n    var found = false;\n    for (var i = 0; i < order.length; ++i) {\n      var part = order[i];\n      if (part.from < to && part.to > from || from == to && part.to == from) {\n        f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? \"rtl\" : \"ltr\", i);\n        found = true;\n      }\n    }\n    if (!found) { f(from, to, \"ltr\"); }\n  }\n\n  var bidiOther = null;\n  function getBidiPartAt(order, ch, sticky) {\n    var found;\n    bidiOther = null;\n    for (var i = 0; i < order.length; ++i) {\n      var cur = order[i];\n      if (cur.from < ch && cur.to > ch) { return i }\n      if (cur.to == ch) {\n        if (cur.from != cur.to && sticky == \"before\") { found = i; }\n        else { bidiOther = i; }\n      }\n      if (cur.from == ch) {\n        if (cur.from != cur.to && sticky != \"before\") { found = i; }\n        else { bidiOther = i; }\n      }\n    }\n    return found != null ? found : bidiOther\n  }\n\n  // Bidirectional ordering algorithm\n  // See http://unicode.org/reports/tr9/tr9-13.html for the algorithm\n  // that this (partially) implements.\n\n  // One-char codes used for character types:\n  // L (L):   Left-to-Right\n  // R (R):   Right-to-Left\n  // r (AL):  Right-to-Left Arabic\n  // 1 (EN):  European Number\n  // + (ES):  European Number Separator\n  // % (ET):  European Number Terminator\n  // n (AN):  Arabic Number\n  // , (CS):  Common Number Separator\n  // m (NSM): Non-Spacing Mark\n  // b (BN):  Boundary Neutral\n  // s (B):   Paragraph Separator\n  // t (S):   Segment Separator\n  // w (WS):  Whitespace\n  // N (ON):  Other Neutrals\n\n  // Returns null if characters are ordered as they appear\n  // (left-to-right), or an array of sections ({from, to, level}\n  // objects) in the order in which they occur visually.\n  var bidiOrdering = (function() {\n    // Character types for codepoints 0 to 0xff\n    var lowTypes = \"bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN\";\n    // Character types for codepoints 0x600 to 0x6f9\n    var arabicTypes = \"nnnnnnNNr%%r,rNNmmmmmmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmmmnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmnNmmmmmmrrmmNmmmmrr1111111111\";\n    function charType(code) {\n      if (code <= 0xf7) { return lowTypes.charAt(code) }\n      else if (0x590 <= code && code <= 0x5f4) { return \"R\" }\n      else if (0x600 <= code && code <= 0x6f9) { return arabicTypes.charAt(code - 0x600) }\n      else if (0x6ee <= code && code <= 0x8ac) { return \"r\" }\n      else if (0x2000 <= code && code <= 0x200b) { return \"w\" }\n      else if (code == 0x200c) { return \"b\" }\n      else { return \"L\" }\n    }\n\n    var bidiRE = /[\\u0590-\\u05f4\\u0600-\\u06ff\\u0700-\\u08ac]/;\n    var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/;\n\n    function BidiSpan(level, from, to) {\n      this.level = level;\n      this.from = from; this.to = to;\n    }\n\n    return function(str, direction) {\n      var outerType = direction == \"ltr\" ? \"L\" : \"R\";\n\n      if (str.length == 0 || direction == \"ltr\" && !bidiRE.test(str)) { return false }\n      var len = str.length, types = [];\n      for (var i = 0; i < len; ++i)\n        { types.push(charType(str.charCodeAt(i))); }\n\n      // W1. Examine each non-spacing mark (NSM) in the level run, and\n      // change the type of the NSM to the type of the previous\n      // character. If the NSM is at the start of the level run, it will\n      // get the type of sor.\n      for (var i$1 = 0, prev = outerType; i$1 < len; ++i$1) {\n        var type = types[i$1];\n        if (type == \"m\") { types[i$1] = prev; }\n        else { prev = type; }\n      }\n\n      // W2. Search backwards from each instance of a European number\n      // until the first strong type (R, L, AL, or sor) is found. If an\n      // AL is found, change the type of the European number to Arabic\n      // number.\n      // W3. Change all ALs to R.\n      for (var i$2 = 0, cur = outerType; i$2 < len; ++i$2) {\n        var type$1 = types[i$2];\n        if (type$1 == \"1\" && cur == \"r\") { types[i$2] = \"n\"; }\n        else if (isStrong.test(type$1)) { cur = type$1; if (type$1 == \"r\") { types[i$2] = \"R\"; } }\n      }\n\n      // W4. A single European separator between two European numbers\n      // changes to a European number. A single common separator between\n      // two numbers of the same type changes to that type.\n      for (var i$3 = 1, prev$1 = types[0]; i$3 < len - 1; ++i$3) {\n        var type$2 = types[i$3];\n        if (type$2 == \"+\" && prev$1 == \"1\" && types[i$3+1] == \"1\") { types[i$3] = \"1\"; }\n        else if (type$2 == \",\" && prev$1 == types[i$3+1] &&\n                 (prev$1 == \"1\" || prev$1 == \"n\")) { types[i$3] = prev$1; }\n        prev$1 = type$2;\n      }\n\n      // W5. A sequence of European terminators adjacent to European\n      // numbers changes to all European numbers.\n      // W6. Otherwise, separators and terminators change to Other\n      // Neutral.\n      for (var i$4 = 0; i$4 < len; ++i$4) {\n        var type$3 = types[i$4];\n        if (type$3 == \",\") { types[i$4] = \"N\"; }\n        else if (type$3 == \"%\") {\n          var end = (void 0);\n          for (end = i$4 + 1; end < len && types[end] == \"%\"; ++end) {}\n          var replace = (i$4 && types[i$4-1] == \"!\") || (end < len && types[end] == \"1\") ? \"1\" : \"N\";\n          for (var j = i$4; j < end; ++j) { types[j] = replace; }\n          i$4 = end - 1;\n        }\n      }\n\n      // W7. Search backwards from each instance of a European number\n      // until the first strong type (R, L, or sor) is found. If an L is\n      // found, then change the type of the European number to L.\n      for (var i$5 = 0, cur$1 = outerType; i$5 < len; ++i$5) {\n        var type$4 = types[i$5];\n        if (cur$1 == \"L\" && type$4 == \"1\") { types[i$5] = \"L\"; }\n        else if (isStrong.test(type$4)) { cur$1 = type$4; }\n      }\n\n      // N1. A sequence of neutrals takes the direction of the\n      // surrounding strong text if the text on both sides has the same\n      // direction. European and Arabic numbers act as if they were R in\n      // terms of their influence on neutrals. Start-of-level-run (sor)\n      // and end-of-level-run (eor) are used at level run boundaries.\n      // N2. Any remaining neutrals take the embedding direction.\n      for (var i$6 = 0; i$6 < len; ++i$6) {\n        if (isNeutral.test(types[i$6])) {\n          var end$1 = (void 0);\n          for (end$1 = i$6 + 1; end$1 < len && isNeutral.test(types[end$1]); ++end$1) {}\n          var before = (i$6 ? types[i$6-1] : outerType) == \"L\";\n          var after = (end$1 < len ? types[end$1] : outerType) == \"L\";\n          var replace$1 = before == after ? (before ? \"L\" : \"R\") : outerType;\n          for (var j$1 = i$6; j$1 < end$1; ++j$1) { types[j$1] = replace$1; }\n          i$6 = end$1 - 1;\n        }\n      }\n\n      // Here we depart from the documented algorithm, in order to avoid\n      // building up an actual levels array. Since there are only three\n      // levels (0, 1, 2) in an implementation that doesn't take\n      // explicit embedding into account, we can build up the order on\n      // the fly, without following the level-based algorithm.\n      var order = [], m;\n      for (var i$7 = 0; i$7 < len;) {\n        if (countsAsLeft.test(types[i$7])) {\n          var start = i$7;\n          for (++i$7; i$7 < len && countsAsLeft.test(types[i$7]); ++i$7) {}\n          order.push(new BidiSpan(0, start, i$7));\n        } else {\n          var pos = i$7, at = order.length;\n          for (++i$7; i$7 < len && types[i$7] != \"L\"; ++i$7) {}\n          for (var j$2 = pos; j$2 < i$7;) {\n            if (countsAsNum.test(types[j$2])) {\n              if (pos < j$2) { order.splice(at, 0, new BidiSpan(1, pos, j$2)); }\n              var nstart = j$2;\n              for (++j$2; j$2 < i$7 && countsAsNum.test(types[j$2]); ++j$2) {}\n              order.splice(at, 0, new BidiSpan(2, nstart, j$2));\n              pos = j$2;\n            } else { ++j$2; }\n          }\n          if (pos < i$7) { order.splice(at, 0, new BidiSpan(1, pos, i$7)); }\n        }\n      }\n      if (direction == \"ltr\") {\n        if (order[0].level == 1 && (m = str.match(/^\\s+/))) {\n          order[0].from = m[0].length;\n          order.unshift(new BidiSpan(0, 0, m[0].length));\n        }\n        if (lst(order).level == 1 && (m = str.match(/\\s+$/))) {\n          lst(order).to -= m[0].length;\n          order.push(new BidiSpan(0, len - m[0].length, len));\n        }\n      }\n\n      return direction == \"rtl\" ? order.reverse() : order\n    }\n  })();\n\n  // Get the bidi ordering for the given line (and cache it). Returns\n  // false for lines that are fully left-to-right, and an array of\n  // BidiSpan objects otherwise.\n  function getOrder(line, direction) {\n    var order = line.order;\n    if (order == null) { order = line.order = bidiOrdering(line.text, direction); }\n    return order\n  }\n\n  // EVENT HANDLING\n\n  // Lightweight event framework. on/off also work on DOM nodes,\n  // registering native DOM handlers.\n\n  var noHandlers = [];\n\n  var on = function(emitter, type, f) {\n    if (emitter.addEventListener) {\n      emitter.addEventListener(type, f, false);\n    } else if (emitter.attachEvent) {\n      emitter.attachEvent(\"on\" + type, f);\n    } else {\n      var map$$1 = emitter._handlers || (emitter._handlers = {});\n      map$$1[type] = (map$$1[type] || noHandlers).concat(f);\n    }\n  };\n\n  function getHandlers(emitter, type) {\n    return emitter._handlers && emitter._handlers[type] || noHandlers\n  }\n\n  function off(emitter, type, f) {\n    if (emitter.removeEventListener) {\n      emitter.removeEventListener(type, f, false);\n    } else if (emitter.detachEvent) {\n      emitter.detachEvent(\"on\" + type, f);\n    } else {\n      var map$$1 = emitter._handlers, arr = map$$1 && map$$1[type];\n      if (arr) {\n        var index = indexOf(arr, f);\n        if (index > -1)\n          { map$$1[type] = arr.slice(0, index).concat(arr.slice(index + 1)); }\n      }\n    }\n  }\n\n  function signal(emitter, type /*, values...*/) {\n    var handlers = getHandlers(emitter, type);\n    if (!handlers.length) { return }\n    var args = Array.prototype.slice.call(arguments, 2);\n    for (var i = 0; i < handlers.length; ++i) { handlers[i].apply(null, args); }\n  }\n\n  // The DOM events that CodeMirror handles can be overridden by\n  // registering a (non-DOM) handler on the editor for the event name,\n  // and preventDefault-ing the event in that handler.\n  function signalDOMEvent(cm, e, override) {\n    if (typeof e == \"string\")\n      { e = {type: e, preventDefault: function() { this.defaultPrevented = true; }}; }\n    signal(cm, override || e.type, cm, e);\n    return e_defaultPrevented(e) || e.codemirrorIgnore\n  }\n\n  function signalCursorActivity(cm) {\n    var arr = cm._handlers && cm._handlers.cursorActivity;\n    if (!arr) { return }\n    var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []);\n    for (var i = 0; i < arr.length; ++i) { if (indexOf(set, arr[i]) == -1)\n      { set.push(arr[i]); } }\n  }\n\n  function hasHandler(emitter, type) {\n    return getHandlers(emitter, type).length > 0\n  }\n\n  // Add on and off methods to a constructor's prototype, to make\n  // registering events on such objects more convenient.\n  function eventMixin(ctor) {\n    ctor.prototype.on = function(type, f) {on(this, type, f);};\n    ctor.prototype.off = function(type, f) {off(this, type, f);};\n  }\n\n  // Due to the fact that we still support jurassic IE versions, some\n  // compatibility wrappers are needed.\n\n  function e_preventDefault(e) {\n    if (e.preventDefault) { e.preventDefault(); }\n    else { e.returnValue = false; }\n  }\n  function e_stopPropagation(e) {\n    if (e.stopPropagation) { e.stopPropagation(); }\n    else { e.cancelBubble = true; }\n  }\n  function e_defaultPrevented(e) {\n    return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false\n  }\n  function e_stop(e) {e_preventDefault(e); e_stopPropagation(e);}\n\n  function e_target(e) {return e.target || e.srcElement}\n  function e_button(e) {\n    var b = e.which;\n    if (b == null) {\n      if (e.button & 1) { b = 1; }\n      else if (e.button & 2) { b = 3; }\n      else if (e.button & 4) { b = 2; }\n    }\n    if (mac && e.ctrlKey && b == 1) { b = 3; }\n    return b\n  }\n\n  // Detect drag-and-drop\n  var dragAndDrop = function() {\n    // There is *some* kind of drag-and-drop support in IE6-8, but I\n    // couldn't get it to work yet.\n    if (ie && ie_version < 9) { return false }\n    var div = elt('div');\n    return \"draggable\" in div || \"dragDrop\" in div\n  }();\n\n  var zwspSupported;\n  function zeroWidthElement(measure) {\n    if (zwspSupported == null) {\n      var test = elt(\"span\", \"\\u200b\");\n      removeChildrenAndAdd(measure, elt(\"span\", [test, document.createTextNode(\"x\")]));\n      if (measure.firstChild.offsetHeight != 0)\n        { zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8); }\n    }\n    var node = zwspSupported ? elt(\"span\", \"\\u200b\") :\n      elt(\"span\", \"\\u00a0\", null, \"display: inline-block; width: 1px; margin-right: -1px\");\n    node.setAttribute(\"cm-text\", \"\");\n    return node\n  }\n\n  // Feature-detect IE's crummy client rect reporting for bidi text\n  var badBidiRects;\n  function hasBadBidiRects(measure) {\n    if (badBidiRects != null) { return badBidiRects }\n    var txt = removeChildrenAndAdd(measure, document.createTextNode(\"A\\u062eA\"));\n    var r0 = range(txt, 0, 1).getBoundingClientRect();\n    var r1 = range(txt, 1, 2).getBoundingClientRect();\n    removeChildren(measure);\n    if (!r0 || r0.left == r0.right) { return false } // Safari returns null in some cases (#2780)\n    return badBidiRects = (r1.right - r0.right < 3)\n  }\n\n  // See if \"\".split is the broken IE version, if so, provide an\n  // alternative way to split lines.\n  var splitLinesAuto = \"\\n\\nb\".split(/\\n/).length != 3 ? function (string) {\n    var pos = 0, result = [], l = string.length;\n    while (pos <= l) {\n      var nl = string.indexOf(\"\\n\", pos);\n      if (nl == -1) { nl = string.length; }\n      var line = string.slice(pos, string.charAt(nl - 1) == \"\\r\" ? nl - 1 : nl);\n      var rt = line.indexOf(\"\\r\");\n      if (rt != -1) {\n        result.push(line.slice(0, rt));\n        pos += rt + 1;\n      } else {\n        result.push(line);\n        pos = nl + 1;\n      }\n    }\n    return result\n  } : function (string) { return string.split(/\\r\\n?|\\n/); };\n\n  var hasSelection = window.getSelection ? function (te) {\n    try { return te.selectionStart != te.selectionEnd }\n    catch(e) { return false }\n  } : function (te) {\n    var range$$1;\n    try {range$$1 = te.ownerDocument.selection.createRange();}\n    catch(e) {}\n    if (!range$$1 || range$$1.parentElement() != te) { return false }\n    return range$$1.compareEndPoints(\"StartToEnd\", range$$1) != 0\n  };\n\n  var hasCopyEvent = (function () {\n    var e = elt(\"div\");\n    if (\"oncopy\" in e) { return true }\n    e.setAttribute(\"oncopy\", \"return;\");\n    return typeof e.oncopy == \"function\"\n  })();\n\n  var badZoomedRects = null;\n  function hasBadZoomedRects(measure) {\n    if (badZoomedRects != null) { return badZoomedRects }\n    var node = removeChildrenAndAdd(measure, elt(\"span\", \"x\"));\n    var normal = node.getBoundingClientRect();\n    var fromRange = range(node, 0, 1).getBoundingClientRect();\n    return badZoomedRects = Math.abs(normal.left - fromRange.left) > 1\n  }\n\n  // Known modes, by name and by MIME\n  var modes = {}, mimeModes = {};\n\n  // Extra arguments are stored as the mode's dependencies, which is\n  // used by (legacy) mechanisms like loadmode.js to automatically\n  // load a mode. (Preferred mechanism is the require/define calls.)\n  function defineMode(name, mode) {\n    if (arguments.length > 2)\n      { mode.dependencies = Array.prototype.slice.call(arguments, 2); }\n    modes[name] = mode;\n  }\n\n  function defineMIME(mime, spec) {\n    mimeModes[mime] = spec;\n  }\n\n  // Given a MIME type, a {name, ...options} config object, or a name\n  // string, return a mode config object.\n  function resolveMode(spec) {\n    if (typeof spec == \"string\" && mimeModes.hasOwnProperty(spec)) {\n      spec = mimeModes[spec];\n    } else if (spec && typeof spec.name == \"string\" && mimeModes.hasOwnProperty(spec.name)) {\n      var found = mimeModes[spec.name];\n      if (typeof found == \"string\") { found = {name: found}; }\n      spec = createObj(found, spec);\n      spec.name = found.name;\n    } else if (typeof spec == \"string\" && /^[\\w\\-]+\\/[\\w\\-]+\\+xml$/.test(spec)) {\n      return resolveMode(\"application/xml\")\n    } else if (typeof spec == \"string\" && /^[\\w\\-]+\\/[\\w\\-]+\\+json$/.test(spec)) {\n      return resolveMode(\"application/json\")\n    }\n    if (typeof spec == \"string\") { return {name: spec} }\n    else { return spec || {name: \"null\"} }\n  }\n\n  // Given a mode spec (anything that resolveMode accepts), find and\n  // initialize an actual mode object.\n  function getMode(options, spec) {\n    spec = resolveMode(spec);\n    var mfactory = modes[spec.name];\n    if (!mfactory) { return getMode(options, \"text/plain\") }\n    var modeObj = mfactory(options, spec);\n    if (modeExtensions.hasOwnProperty(spec.name)) {\n      var exts = modeExtensions[spec.name];\n      for (var prop in exts) {\n        if (!exts.hasOwnProperty(prop)) { continue }\n        if (modeObj.hasOwnProperty(prop)) { modeObj[\"_\" + prop] = modeObj[prop]; }\n        modeObj[prop] = exts[prop];\n      }\n    }\n    modeObj.name = spec.name;\n    if (spec.helperType) { modeObj.helperType = spec.helperType; }\n    if (spec.modeProps) { for (var prop$1 in spec.modeProps)\n      { modeObj[prop$1] = spec.modeProps[prop$1]; } }\n\n    return modeObj\n  }\n\n  // This can be used to attach properties to mode objects from\n  // outside the actual mode definition.\n  var modeExtensions = {};\n  function extendMode(mode, properties) {\n    var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {});\n    copyObj(properties, exts);\n  }\n\n  function copyState(mode, state) {\n    if (state === true) { return state }\n    if (mode.copyState) { return mode.copyState(state) }\n    var nstate = {};\n    for (var n in state) {\n      var val = state[n];\n      if (val instanceof Array) { val = val.concat([]); }\n      nstate[n] = val;\n    }\n    return nstate\n  }\n\n  // Given a mode and a state (for that mode), find the inner mode and\n  // state at the position that the state refers to.\n  function innerMode(mode, state) {\n    var info;\n    while (mode.innerMode) {\n      info = mode.innerMode(state);\n      if (!info || info.mode == mode) { break }\n      state = info.state;\n      mode = info.mode;\n    }\n    return info || {mode: mode, state: state}\n  }\n\n  function startState(mode, a1, a2) {\n    return mode.startState ? mode.startState(a1, a2) : true\n  }\n\n  // STRING STREAM\n\n  // Fed to the mode parsers, provides helper functions to make\n  // parsers more succinct.\n\n  var StringStream = function(string, tabSize, lineOracle) {\n    this.pos = this.start = 0;\n    this.string = string;\n    this.tabSize = tabSize || 8;\n    this.lastColumnPos = this.lastColumnValue = 0;\n    this.lineStart = 0;\n    this.lineOracle = lineOracle;\n  };\n\n  StringStream.prototype.eol = function () {return this.pos >= this.string.length};\n  StringStream.prototype.sol = function () {return this.pos == this.lineStart};\n  StringStream.prototype.peek = function () {return this.string.charAt(this.pos) || undefined};\n  StringStream.prototype.next = function () {\n    if (this.pos < this.string.length)\n      { return this.string.charAt(this.pos++) }\n  };\n  StringStream.prototype.eat = function (match) {\n    var ch = this.string.charAt(this.pos);\n    var ok;\n    if (typeof match == \"string\") { ok = ch == match; }\n    else { ok = ch && (match.test ? match.test(ch) : match(ch)); }\n    if (ok) {++this.pos; return ch}\n  };\n  StringStream.prototype.eatWhile = function (match) {\n    var start = this.pos;\n    while (this.eat(match)){}\n    return this.pos > start\n  };\n  StringStream.prototype.eatSpace = function () {\n      var this$1 = this;\n\n    var start = this.pos;\n    while (/[\\s\\u00a0]/.test(this.string.charAt(this.pos))) { ++this$1.pos; }\n    return this.pos > start\n  };\n  StringStream.prototype.skipToEnd = function () {this.pos = this.string.length;};\n  StringStream.prototype.skipTo = function (ch) {\n    var found = this.string.indexOf(ch, this.pos);\n    if (found > -1) {this.pos = found; return true}\n  };\n  StringStream.prototype.backUp = function (n) {this.pos -= n;};\n  StringStream.prototype.column = function () {\n    if (this.lastColumnPos < this.start) {\n      this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue);\n      this.lastColumnPos = this.start;\n    }\n    return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0)\n  };\n  StringStream.prototype.indentation = function () {\n    return countColumn(this.string, null, this.tabSize) -\n      (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0)\n  };\n  StringStream.prototype.match = function (pattern, consume, caseInsensitive) {\n    if (typeof pattern == \"string\") {\n      var cased = function (str) { return caseInsensitive ? str.toLowerCase() : str; };\n      var substr = this.string.substr(this.pos, pattern.length);\n      if (cased(substr) == cased(pattern)) {\n        if (consume !== false) { this.pos += pattern.length; }\n        return true\n      }\n    } else {\n      var match = this.string.slice(this.pos).match(pattern);\n      if (match && match.index > 0) { return null }\n      if (match && consume !== false) { this.pos += match[0].length; }\n      return match\n    }\n  };\n  StringStream.prototype.current = function (){return this.string.slice(this.start, this.pos)};\n  StringStream.prototype.hideFirstChars = function (n, inner) {\n    this.lineStart += n;\n    try { return inner() }\n    finally { this.lineStart -= n; }\n  };\n  StringStream.prototype.lookAhead = function (n) {\n    var oracle = this.lineOracle;\n    return oracle && oracle.lookAhead(n)\n  };\n  StringStream.prototype.baseToken = function () {\n    var oracle = this.lineOracle;\n    return oracle && oracle.baseToken(this.pos)\n  };\n\n  var SavedContext = function(state, lookAhead) {\n    this.state = state;\n    this.lookAhead = lookAhead;\n  };\n\n  var Context = function(doc, state, line, lookAhead) {\n    this.state = state;\n    this.doc = doc;\n    this.line = line;\n    this.maxLookAhead = lookAhead || 0;\n    this.baseTokens = null;\n    this.baseTokenPos = 1;\n  };\n\n  Context.prototype.lookAhead = function (n) {\n    var line = this.doc.getLine(this.line + n);\n    if (line != null && n > this.maxLookAhead) { this.maxLookAhead = n; }\n    return line\n  };\n\n  Context.prototype.baseToken = function (n) {\n      var this$1 = this;\n\n    if (!this.baseTokens) { return null }\n    while (this.baseTokens[this.baseTokenPos] <= n)\n      { this$1.baseTokenPos += 2; }\n    var type = this.baseTokens[this.baseTokenPos + 1];\n    return {type: type && type.replace(/( |^)overlay .*/, \"\"),\n            size: this.baseTokens[this.baseTokenPos] - n}\n  };\n\n  Context.prototype.nextLine = function () {\n    this.line++;\n    if (this.maxLookAhead > 0) { this.maxLookAhead--; }\n  };\n\n  Context.fromSaved = function (doc, saved, line) {\n    if (saved instanceof SavedContext)\n      { return new Context(doc, copyState(doc.mode, saved.state), line, saved.lookAhead) }\n    else\n      { return new Context(doc, copyState(doc.mode, saved), line) }\n  };\n\n  Context.prototype.save = function (copy) {\n    var state = copy !== false ? copyState(this.doc.mode, this.state) : this.state;\n    return this.maxLookAhead > 0 ? new SavedContext(state, this.maxLookAhead) : state\n  };\n\n\n  // Compute a style array (an array starting with a mode generation\n  // -- for invalidation -- followed by pairs of end positions and\n  // style strings), which is used to highlight the tokens on the\n  // line.\n  function highlightLine(cm, line, context, forceToEnd) {\n    // A styles array always starts with a number identifying the\n    // mode/overlays that it is based on (for easy invalidation).\n    var st = [cm.state.modeGen], lineClasses = {};\n    // Compute the base array of styles\n    runMode(cm, line.text, cm.doc.mode, context, function (end, style) { return st.push(end, style); },\n            lineClasses, forceToEnd);\n    var state = context.state;\n\n    // Run overlays, adjust style array.\n    var loop = function ( o ) {\n      context.baseTokens = st;\n      var overlay = cm.state.overlays[o], i = 1, at = 0;\n      context.state = true;\n      runMode(cm, line.text, overlay.mode, context, function (end, style) {\n        var start = i;\n        // Ensure there's a token end at the current position, and that i points at it\n        while (at < end) {\n          var i_end = st[i];\n          if (i_end > end)\n            { st.splice(i, 1, end, st[i+1], i_end); }\n          i += 2;\n          at = Math.min(end, i_end);\n        }\n        if (!style) { return }\n        if (overlay.opaque) {\n          st.splice(start, i - start, end, \"overlay \" + style);\n          i = start + 2;\n        } else {\n          for (; start < i; start += 2) {\n            var cur = st[start+1];\n            st[start+1] = (cur ? cur + \" \" : \"\") + \"overlay \" + style;\n          }\n        }\n      }, lineClasses);\n      context.state = state;\n      context.baseTokens = null;\n      context.baseTokenPos = 1;\n    };\n\n    for (var o = 0; o < cm.state.overlays.length; ++o) loop( o );\n\n    return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null}\n  }\n\n  function getLineStyles(cm, line, updateFrontier) {\n    if (!line.styles || line.styles[0] != cm.state.modeGen) {\n      var context = getContextBefore(cm, lineNo(line));\n      var resetState = line.text.length > cm.options.maxHighlightLength && copyState(cm.doc.mode, context.state);\n      var result = highlightLine(cm, line, context);\n      if (resetState) { context.state = resetState; }\n      line.stateAfter = context.save(!resetState);\n      line.styles = result.styles;\n      if (result.classes) { line.styleClasses = result.classes; }\n      else if (line.styleClasses) { line.styleClasses = null; }\n      if (updateFrontier === cm.doc.highlightFrontier)\n        { cm.doc.modeFrontier = Math.max(cm.doc.modeFrontier, ++cm.doc.highlightFrontier); }\n    }\n    return line.styles\n  }\n\n  function getContextBefore(cm, n, precise) {\n    var doc = cm.doc, display = cm.display;\n    if (!doc.mode.startState) { return new Context(doc, true, n) }\n    var start = findStartLine(cm, n, precise);\n    var saved = start > doc.first && getLine(doc, start - 1).stateAfter;\n    var context = saved ? Context.fromSaved(doc, saved, start) : new Context(doc, startState(doc.mode), start);\n\n    doc.iter(start, n, function (line) {\n      processLine(cm, line.text, context);\n      var pos = context.line;\n      line.stateAfter = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo ? context.save() : null;\n      context.nextLine();\n    });\n    if (precise) { doc.modeFrontier = context.line; }\n    return context\n  }\n\n  // Lightweight form of highlight -- proceed over this line and\n  // update state, but don't save a style array. Used for lines that\n  // aren't currently visible.\n  function processLine(cm, text, context, startAt) {\n    var mode = cm.doc.mode;\n    var stream = new StringStream(text, cm.options.tabSize, context);\n    stream.start = stream.pos = startAt || 0;\n    if (text == \"\") { callBlankLine(mode, context.state); }\n    while (!stream.eol()) {\n      readToken(mode, stream, context.state);\n      stream.start = stream.pos;\n    }\n  }\n\n  function callBlankLine(mode, state) {\n    if (mode.blankLine) { return mode.blankLine(state) }\n    if (!mode.innerMode) { return }\n    var inner = innerMode(mode, state);\n    if (inner.mode.blankLine) { return inner.mode.blankLine(inner.state) }\n  }\n\n  function readToken(mode, stream, state, inner) {\n    for (var i = 0; i < 10; i++) {\n      if (inner) { inner[0] = innerMode(mode, state).mode; }\n      var style = mode.token(stream, state);\n      if (stream.pos > stream.start) { return style }\n    }\n    throw new Error(\"Mode \" + mode.name + \" failed to advance stream.\")\n  }\n\n  var Token = function(stream, type, state) {\n    this.start = stream.start; this.end = stream.pos;\n    this.string = stream.current();\n    this.type = type || null;\n    this.state = state;\n  };\n\n  // Utility for getTokenAt and getLineTokens\n  function takeToken(cm, pos, precise, asArray) {\n    var doc = cm.doc, mode = doc.mode, style;\n    pos = clipPos(doc, pos);\n    var line = getLine(doc, pos.line), context = getContextBefore(cm, pos.line, precise);\n    var stream = new StringStream(line.text, cm.options.tabSize, context), tokens;\n    if (asArray) { tokens = []; }\n    while ((asArray || stream.pos < pos.ch) && !stream.eol()) {\n      stream.start = stream.pos;\n      style = readToken(mode, stream, context.state);\n      if (asArray) { tokens.push(new Token(stream, style, copyState(doc.mode, context.state))); }\n    }\n    return asArray ? tokens : new Token(stream, style, context.state)\n  }\n\n  function extractLineClasses(type, output) {\n    if (type) { for (;;) {\n      var lineClass = type.match(/(?:^|\\s+)line-(background-)?(\\S+)/);\n      if (!lineClass) { break }\n      type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length);\n      var prop = lineClass[1] ? \"bgClass\" : \"textClass\";\n      if (output[prop] == null)\n        { output[prop] = lineClass[2]; }\n      else if (!(new RegExp(\"(?:^|\\s)\" + lineClass[2] + \"(?:$|\\s)\")).test(output[prop]))\n        { output[prop] += \" \" + lineClass[2]; }\n    } }\n    return type\n  }\n\n  // Run the given mode's parser over a line, calling f for each token.\n  function runMode(cm, text, mode, context, f, lineClasses, forceToEnd) {\n    var flattenSpans = mode.flattenSpans;\n    if (flattenSpans == null) { flattenSpans = cm.options.flattenSpans; }\n    var curStart = 0, curStyle = null;\n    var stream = new StringStream(text, cm.options.tabSize, context), style;\n    var inner = cm.options.addModeClass && [null];\n    if (text == \"\") { extractLineClasses(callBlankLine(mode, context.state), lineClasses); }\n    while (!stream.eol()) {\n      if (stream.pos > cm.options.maxHighlightLength) {\n        flattenSpans = false;\n        if (forceToEnd) { processLine(cm, text, context, stream.pos); }\n        stream.pos = text.length;\n        style = null;\n      } else {\n        style = extractLineClasses(readToken(mode, stream, context.state, inner), lineClasses);\n      }\n      if (inner) {\n        var mName = inner[0].name;\n        if (mName) { style = \"m-\" + (style ? mName + \" \" + style : mName); }\n      }\n      if (!flattenSpans || curStyle != style) {\n        while (curStart < stream.start) {\n          curStart = Math.min(stream.start, curStart + 5000);\n          f(curStart, curStyle);\n        }\n        curStyle = style;\n      }\n      stream.start = stream.pos;\n    }\n    while (curStart < stream.pos) {\n      // Webkit seems to refuse to render text nodes longer than 57444\n      // characters, and returns inaccurate measurements in nodes\n      // starting around 5000 chars.\n      var pos = Math.min(stream.pos, curStart + 5000);\n      f(pos, curStyle);\n      curStart = pos;\n    }\n  }\n\n  // Finds the line to start with when starting a parse. Tries to\n  // find a line with a stateAfter, so that it can start with a\n  // valid state. If that fails, it returns the line with the\n  // smallest indentation, which tends to need the least context to\n  // parse correctly.\n  function findStartLine(cm, n, precise) {\n    var minindent, minline, doc = cm.doc;\n    var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100);\n    for (var search = n; search > lim; --search) {\n      if (search <= doc.first) { return doc.first }\n      var line = getLine(doc, search - 1), after = line.stateAfter;\n      if (after && (!precise || search + (after instanceof SavedContext ? after.lookAhead : 0) <= doc.modeFrontier))\n        { return search }\n      var indented = countColumn(line.text, null, cm.options.tabSize);\n      if (minline == null || minindent > indented) {\n        minline = search - 1;\n        minindent = indented;\n      }\n    }\n    return minline\n  }\n\n  function retreatFrontier(doc, n) {\n    doc.modeFrontier = Math.min(doc.modeFrontier, n);\n    if (doc.highlightFrontier < n - 10) { return }\n    var start = doc.first;\n    for (var line = n - 1; line > start; line--) {\n      var saved = getLine(doc, line).stateAfter;\n      // change is on 3\n      // state on line 1 looked ahead 2 -- so saw 3\n      // test 1 + 2 < 3 should cover this\n      if (saved && (!(saved instanceof SavedContext) || line + saved.lookAhead < n)) {\n        start = line + 1;\n        break\n      }\n    }\n    doc.highlightFrontier = Math.min(doc.highlightFrontier, start);\n  }\n\n  // LINE DATA STRUCTURE\n\n  // Line objects. These hold state related to a line, including\n  // highlighting info (the styles array).\n  var Line = function(text, markedSpans, estimateHeight) {\n    this.text = text;\n    attachMarkedSpans(this, markedSpans);\n    this.height = estimateHeight ? estimateHeight(this) : 1;\n  };\n\n  Line.prototype.lineNo = function () { return lineNo(this) };\n  eventMixin(Line);\n\n  // Change the content (text, markers) of a line. Automatically\n  // invalidates cached information and tries to re-estimate the\n  // line's height.\n  function updateLine(line, text, markedSpans, estimateHeight) {\n    line.text = text;\n    if (line.stateAfter) { line.stateAfter = null; }\n    if (line.styles) { line.styles = null; }\n    if (line.order != null) { line.order = null; }\n    detachMarkedSpans(line);\n    attachMarkedSpans(line, markedSpans);\n    var estHeight = estimateHeight ? estimateHeight(line) : 1;\n    if (estHeight != line.height) { updateLineHeight(line, estHeight); }\n  }\n\n  // Detach a line from the document tree and its markers.\n  function cleanUpLine(line) {\n    line.parent = null;\n    detachMarkedSpans(line);\n  }\n\n  // Convert a style as returned by a mode (either null, or a string\n  // containing one or more styles) to a CSS style. This is cached,\n  // and also looks for line-wide styles.\n  var styleToClassCache = {}, styleToClassCacheWithMode = {};\n  function interpretTokenStyle(style, options) {\n    if (!style || /^\\s*$/.test(style)) { return null }\n    var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache;\n    return cache[style] ||\n      (cache[style] = style.replace(/\\S+/g, \"cm-$&\"))\n  }\n\n  // Render the DOM representation of the text of a line. Also builds\n  // up a 'line map', which points at the DOM nodes that represent\n  // specific stretches of text, and is used by the measuring code.\n  // The returned object contains the DOM node, this map, and\n  // information about line-wide styles that were set by the mode.\n  function buildLineContent(cm, lineView) {\n    // The padding-right forces the element to have a 'border', which\n    // is needed on Webkit to be able to get line-level bounding\n    // rectangles for it (in measureChar).\n    var content = eltP(\"span\", null, null, webkit ? \"padding-right: .1px\" : null);\n    var builder = {pre: eltP(\"pre\", [content], \"CodeMirror-line\"), content: content,\n                   col: 0, pos: 0, cm: cm,\n                   trailingSpace: false,\n                   splitSpaces: cm.getOption(\"lineWrapping\")};\n    lineView.measure = {};\n\n    // Iterate over the logical lines that make up this visual line.\n    for (var i = 0; i <= (lineView.rest ? lineView.rest.length : 0); i++) {\n      var line = i ? lineView.rest[i - 1] : lineView.line, order = (void 0);\n      builder.pos = 0;\n      builder.addToken = buildToken;\n      // Optionally wire in some hacks into the token-rendering\n      // algorithm, to deal with browser quirks.\n      if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line, cm.doc.direction)))\n        { builder.addToken = buildTokenBadBidi(builder.addToken, order); }\n      builder.map = [];\n      var allowFrontierUpdate = lineView != cm.display.externalMeasured && lineNo(line);\n      insertLineContent(line, builder, getLineStyles(cm, line, allowFrontierUpdate));\n      if (line.styleClasses) {\n        if (line.styleClasses.bgClass)\n          { builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || \"\"); }\n        if (line.styleClasses.textClass)\n          { builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || \"\"); }\n      }\n\n      // Ensure at least a single node is present, for measuring.\n      if (builder.map.length == 0)\n        { builder.map.push(0, 0, builder.content.appendChild(zeroWidthElement(cm.display.measure))); }\n\n      // Store the map and a cache object for the current logical line\n      if (i == 0) {\n        lineView.measure.map = builder.map;\n        lineView.measure.cache = {};\n      } else {\n  (lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map)\n        ;(lineView.measure.caches || (lineView.measure.caches = [])).push({});\n      }\n    }\n\n    // See issue #2901\n    if (webkit) {\n      var last = builder.content.lastChild;\n      if (/\\bcm-tab\\b/.test(last.className) || (last.querySelector && last.querySelector(\".cm-tab\")))\n        { builder.content.className = \"cm-tab-wrap-hack\"; }\n    }\n\n    signal(cm, \"renderLine\", cm, lineView.line, builder.pre);\n    if (builder.pre.className)\n      { builder.textClass = joinClasses(builder.pre.className, builder.textClass || \"\"); }\n\n    return builder\n  }\n\n  function defaultSpecialCharPlaceholder(ch) {\n    var token = elt(\"span\", \"\\u2022\", \"cm-invalidchar\");\n    token.title = \"\\\\u\" + ch.charCodeAt(0).toString(16);\n    token.setAttribute(\"aria-label\", token.title);\n    return token\n  }\n\n  // Build up the DOM representation for a single token, and add it to\n  // the line map. Takes care to render special characters separately.\n  function buildToken(builder, text, style, startStyle, endStyle, title, css) {\n    if (!text) { return }\n    var displayText = builder.splitSpaces ? splitSpaces(text, builder.trailingSpace) : text;\n    var special = builder.cm.state.specialChars, mustWrap = false;\n    var content;\n    if (!special.test(text)) {\n      builder.col += text.length;\n      content = document.createTextNode(displayText);\n      builder.map.push(builder.pos, builder.pos + text.length, content);\n      if (ie && ie_version < 9) { mustWrap = true; }\n      builder.pos += text.length;\n    } else {\n      content = document.createDocumentFragment();\n      var pos = 0;\n      while (true) {\n        special.lastIndex = pos;\n        var m = special.exec(text);\n        var skipped = m ? m.index - pos : text.length - pos;\n        if (skipped) {\n          var txt = document.createTextNode(displayText.slice(pos, pos + skipped));\n          if (ie && ie_version < 9) { content.appendChild(elt(\"span\", [txt])); }\n          else { content.appendChild(txt); }\n          builder.map.push(builder.pos, builder.pos + skipped, txt);\n          builder.col += skipped;\n          builder.pos += skipped;\n        }\n        if (!m) { break }\n        pos += skipped + 1;\n        var txt$1 = (void 0);\n        if (m[0] == \"\\t\") {\n          var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize;\n          txt$1 = content.appendChild(elt(\"span\", spaceStr(tabWidth), \"cm-tab\"));\n          txt$1.setAttribute(\"role\", \"presentation\");\n          txt$1.setAttribute(\"cm-text\", \"\\t\");\n          builder.col += tabWidth;\n        } else if (m[0] == \"\\r\" || m[0] == \"\\n\") {\n          txt$1 = content.appendChild(elt(\"span\", m[0] == \"\\r\" ? \"\\u240d\" : \"\\u2424\", \"cm-invalidchar\"));\n          txt$1.setAttribute(\"cm-text\", m[0]);\n          builder.col += 1;\n        } else {\n          txt$1 = builder.cm.options.specialCharPlaceholder(m[0]);\n          txt$1.setAttribute(\"cm-text\", m[0]);\n          if (ie && ie_version < 9) { content.appendChild(elt(\"span\", [txt$1])); }\n          else { content.appendChild(txt$1); }\n          builder.col += 1;\n        }\n        builder.map.push(builder.pos, builder.pos + 1, txt$1);\n        builder.pos++;\n      }\n    }\n    builder.trailingSpace = displayText.charCodeAt(text.length - 1) == 32;\n    if (style || startStyle || endStyle || mustWrap || css) {\n      var fullStyle = style || \"\";\n      if (startStyle) { fullStyle += startStyle; }\n      if (endStyle) { fullStyle += endStyle; }\n      var token = elt(\"span\", [content], fullStyle, css);\n      if (title) { token.title = title; }\n      return builder.content.appendChild(token)\n    }\n    builder.content.appendChild(content);\n  }\n\n  // Change some spaces to NBSP to prevent the browser from collapsing\n  // trailing spaces at the end of a line when rendering text (issue #1362).\n  function splitSpaces(text, trailingBefore) {\n    if (text.length > 1 && !/  /.test(text)) { return text }\n    var spaceBefore = trailingBefore, result = \"\";\n    for (var i = 0; i < text.length; i++) {\n      var ch = text.charAt(i);\n      if (ch == \" \" && spaceBefore && (i == text.length - 1 || text.charCodeAt(i + 1) == 32))\n        { ch = \"\\u00a0\"; }\n      result += ch;\n      spaceBefore = ch == \" \";\n    }\n    return result\n  }\n\n  // Work around nonsense dimensions being reported for stretches of\n  // right-to-left text.\n  function buildTokenBadBidi(inner, order) {\n    return function (builder, text, style, startStyle, endStyle, title, css) {\n      style = style ? style + \" cm-force-border\" : \"cm-force-border\";\n      var start = builder.pos, end = start + text.length;\n      for (;;) {\n        // Find the part that overlaps with the start of this text\n        var part = (void 0);\n        for (var i = 0; i < order.length; i++) {\n          part = order[i];\n          if (part.to > start && part.from <= start) { break }\n        }\n        if (part.to >= end) { return inner(builder, text, style, startStyle, endStyle, title, css) }\n        inner(builder, text.slice(0, part.to - start), style, startStyle, null, title, css);\n        startStyle = null;\n        text = text.slice(part.to - start);\n        start = part.to;\n      }\n    }\n  }\n\n  function buildCollapsedSpan(builder, size, marker, ignoreWidget) {\n    var widget = !ignoreWidget && marker.widgetNode;\n    if (widget) { builder.map.push(builder.pos, builder.pos + size, widget); }\n    if (!ignoreWidget && builder.cm.display.input.needsContentAttribute) {\n      if (!widget)\n        { widget = builder.content.appendChild(document.createElement(\"span\")); }\n      widget.setAttribute(\"cm-marker\", marker.id);\n    }\n    if (widget) {\n      builder.cm.display.input.setUneditable(widget);\n      builder.content.appendChild(widget);\n    }\n    builder.pos += size;\n    builder.trailingSpace = false;\n  }\n\n  // Outputs a number of spans to make up a line, taking highlighting\n  // and marked text into account.\n  function insertLineContent(line, builder, styles) {\n    var spans = line.markedSpans, allText = line.text, at = 0;\n    if (!spans) {\n      for (var i$1 = 1; i$1 < styles.length; i$1+=2)\n        { builder.addToken(builder, allText.slice(at, at = styles[i$1]), interpretTokenStyle(styles[i$1+1], builder.cm.options)); }\n      return\n    }\n\n    var len = allText.length, pos = 0, i = 1, text = \"\", style, css;\n    var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed;\n    for (;;) {\n      if (nextChange == pos) { // Update current marker set\n        spanStyle = spanEndStyle = spanStartStyle = title = css = \"\";\n        collapsed = null; nextChange = Infinity;\n        var foundBookmarks = [], endStyles = (void 0);\n        for (var j = 0; j < spans.length; ++j) {\n          var sp = spans[j], m = sp.marker;\n          if (m.type == \"bookmark\" && sp.from == pos && m.widgetNode) {\n            foundBookmarks.push(m);\n          } else if (sp.from <= pos && (sp.to == null || sp.to > pos || m.collapsed && sp.to == pos && sp.from == pos)) {\n            if (sp.to != null && sp.to != pos && nextChange > sp.to) {\n              nextChange = sp.to;\n              spanEndStyle = \"\";\n            }\n            if (m.className) { spanStyle += \" \" + m.className; }\n            if (m.css) { css = (css ? css + \";\" : \"\") + m.css; }\n            if (m.startStyle && sp.from == pos) { spanStartStyle += \" \" + m.startStyle; }\n            if (m.endStyle && sp.to == nextChange) { (endStyles || (endStyles = [])).push(m.endStyle, sp.to); }\n            if (m.title && !title) { title = m.title; }\n            if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0))\n              { collapsed = sp; }\n          } else if (sp.from > pos && nextChange > sp.from) {\n            nextChange = sp.from;\n          }\n        }\n        if (endStyles) { for (var j$1 = 0; j$1 < endStyles.length; j$1 += 2)\n          { if (endStyles[j$1 + 1] == nextChange) { spanEndStyle += \" \" + endStyles[j$1]; } } }\n\n        if (!collapsed || collapsed.from == pos) { for (var j$2 = 0; j$2 < foundBookmarks.length; ++j$2)\n          { buildCollapsedSpan(builder, 0, foundBookmarks[j$2]); } }\n        if (collapsed && (collapsed.from || 0) == pos) {\n          buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos,\n                             collapsed.marker, collapsed.from == null);\n          if (collapsed.to == null) { return }\n          if (collapsed.to == pos) { collapsed = false; }\n        }\n      }\n      if (pos >= len) { break }\n\n      var upto = Math.min(len, nextChange);\n      while (true) {\n        if (text) {\n          var end = pos + text.length;\n          if (!collapsed) {\n            var tokenText = end > upto ? text.slice(0, upto - pos) : text;\n            builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle,\n                             spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : \"\", title, css);\n          }\n          if (end >= upto) {text = text.slice(upto - pos); pos = upto; break}\n          pos = end;\n          spanStartStyle = \"\";\n        }\n        text = allText.slice(at, at = styles[i++]);\n        style = interpretTokenStyle(styles[i++], builder.cm.options);\n      }\n    }\n  }\n\n\n  // These objects are used to represent the visible (currently drawn)\n  // part of the document. A LineView may correspond to multiple\n  // logical lines, if those are connected by collapsed ranges.\n  function LineView(doc, line, lineN) {\n    // The starting line\n    this.line = line;\n    // Continuing lines, if any\n    this.rest = visualLineContinued(line);\n    // Number of logical lines in this visual line\n    this.size = this.rest ? lineNo(lst(this.rest)) - lineN + 1 : 1;\n    this.node = this.text = null;\n    this.hidden = lineIsHidden(doc, line);\n  }\n\n  // Create a range of LineView objects for the given lines.\n  function buildViewArray(cm, from, to) {\n    var array = [], nextPos;\n    for (var pos = from; pos < to; pos = nextPos) {\n      var view = new LineView(cm.doc, getLine(cm.doc, pos), pos);\n      nextPos = pos + view.size;\n      array.push(view);\n    }\n    return array\n  }\n\n  var operationGroup = null;\n\n  function pushOperation(op) {\n    if (operationGroup) {\n      operationGroup.ops.push(op);\n    } else {\n      op.ownsGroup = operationGroup = {\n        ops: [op],\n        delayedCallbacks: []\n      };\n    }\n  }\n\n  function fireCallbacksForOps(group) {\n    // Calls delayed callbacks and cursorActivity handlers until no\n    // new ones appear\n    var callbacks = group.delayedCallbacks, i = 0;\n    do {\n      for (; i < callbacks.length; i++)\n        { callbacks[i].call(null); }\n      for (var j = 0; j < group.ops.length; j++) {\n        var op = group.ops[j];\n        if (op.cursorActivityHandlers)\n          { while (op.cursorActivityCalled < op.cursorActivityHandlers.length)\n            { op.cursorActivityHandlers[op.cursorActivityCalled++].call(null, op.cm); } }\n      }\n    } while (i < callbacks.length)\n  }\n\n  function finishOperation(op, endCb) {\n    var group = op.ownsGroup;\n    if (!group) { return }\n\n    try { fireCallbacksForOps(group); }\n    finally {\n      operationGroup = null;\n      endCb(group);\n    }\n  }\n\n  var orphanDelayedCallbacks = null;\n\n  // Often, we want to signal events at a point where we are in the\n  // middle of some work, but don't want the handler to start calling\n  // other methods on the editor, which might be in an inconsistent\n  // state or simply not expect any other events to happen.\n  // signalLater looks whether there are any handlers, and schedules\n  // them to be executed when the last operation ends, or, if no\n  // operation is active, when a timeout fires.\n  function signalLater(emitter, type /*, values...*/) {\n    var arr = getHandlers(emitter, type);\n    if (!arr.length) { return }\n    var args = Array.prototype.slice.call(arguments, 2), list;\n    if (operationGroup) {\n      list = operationGroup.delayedCallbacks;\n    } else if (orphanDelayedCallbacks) {\n      list = orphanDelayedCallbacks;\n    } else {\n      list = orphanDelayedCallbacks = [];\n      setTimeout(fireOrphanDelayed, 0);\n    }\n    var loop = function ( i ) {\n      list.push(function () { return arr[i].apply(null, args); });\n    };\n\n    for (var i = 0; i < arr.length; ++i)\n      loop( i );\n  }\n\n  function fireOrphanDelayed() {\n    var delayed = orphanDelayedCallbacks;\n    orphanDelayedCallbacks = null;\n    for (var i = 0; i < delayed.length; ++i) { delayed[i](); }\n  }\n\n  // When an aspect of a line changes, a string is added to\n  // lineView.changes. This updates the relevant part of the line's\n  // DOM structure.\n  function updateLineForChanges(cm, lineView, lineN, dims) {\n    for (var j = 0; j < lineView.changes.length; j++) {\n      var type = lineView.changes[j];\n      if (type == \"text\") { updateLineText(cm, lineView); }\n      else if (type == \"gutter\") { updateLineGutter(cm, lineView, lineN, dims); }\n      else if (type == \"class\") { updateLineClasses(cm, lineView); }\n      else if (type == \"widget\") { updateLineWidgets(cm, lineView, dims); }\n    }\n    lineView.changes = null;\n  }\n\n  // Lines with gutter elements, widgets or a background class need to\n  // be wrapped, and have the extra elements added to the wrapper div\n  function ensureLineWrapped(lineView) {\n    if (lineView.node == lineView.text) {\n      lineView.node = elt(\"div\", null, null, \"position: relative\");\n      if (lineView.text.parentNode)\n        { lineView.text.parentNode.replaceChild(lineView.node, lineView.text); }\n      lineView.node.appendChild(lineView.text);\n      if (ie && ie_version < 8) { lineView.node.style.zIndex = 2; }\n    }\n    return lineView.node\n  }\n\n  function updateLineBackground(cm, lineView) {\n    var cls = lineView.bgClass ? lineView.bgClass + \" \" + (lineView.line.bgClass || \"\") : lineView.line.bgClass;\n    if (cls) { cls += \" CodeMirror-linebackground\"; }\n    if (lineView.background) {\n      if (cls) { lineView.background.className = cls; }\n      else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null; }\n    } else if (cls) {\n      var wrap = ensureLineWrapped(lineView);\n      lineView.background = wrap.insertBefore(elt(\"div\", null, cls), wrap.firstChild);\n      cm.display.input.setUneditable(lineView.background);\n    }\n  }\n\n  // Wrapper around buildLineContent which will reuse the structure\n  // in display.externalMeasured when possible.\n  function getLineContent(cm, lineView) {\n    var ext = cm.display.externalMeasured;\n    if (ext && ext.line == lineView.line) {\n      cm.display.externalMeasured = null;\n      lineView.measure = ext.measure;\n      return ext.built\n    }\n    return buildLineContent(cm, lineView)\n  }\n\n  // Redraw the line's text. Interacts with the background and text\n  // classes because the mode may output tokens that influence these\n  // classes.\n  function updateLineText(cm, lineView) {\n    var cls = lineView.text.className;\n    var built = getLineContent(cm, lineView);\n    if (lineView.text == lineView.node) { lineView.node = built.pre; }\n    lineView.text.parentNode.replaceChild(built.pre, lineView.text);\n    lineView.text = built.pre;\n    if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) {\n      lineView.bgClass = built.bgClass;\n      lineView.textClass = built.textClass;\n      updateLineClasses(cm, lineView);\n    } else if (cls) {\n      lineView.text.className = cls;\n    }\n  }\n\n  function updateLineClasses(cm, lineView) {\n    updateLineBackground(cm, lineView);\n    if (lineView.line.wrapClass)\n      { ensureLineWrapped(lineView).className = lineView.line.wrapClass; }\n    else if (lineView.node != lineView.text)\n      { lineView.node.className = \"\"; }\n    var textClass = lineView.textClass ? lineView.textClass + \" \" + (lineView.line.textClass || \"\") : lineView.line.textClass;\n    lineView.text.className = textClass || \"\";\n  }\n\n  function updateLineGutter(cm, lineView, lineN, dims) {\n    if (lineView.gutter) {\n      lineView.node.removeChild(lineView.gutter);\n      lineView.gutter = null;\n    }\n    if (lineView.gutterBackground) {\n      lineView.node.removeChild(lineView.gutterBackground);\n      lineView.gutterBackground = null;\n    }\n    if (lineView.line.gutterClass) {\n      var wrap = ensureLineWrapped(lineView);\n      lineView.gutterBackground = elt(\"div\", null, \"CodeMirror-gutter-background \" + lineView.line.gutterClass,\n                                      (\"left: \" + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + \"px; width: \" + (dims.gutterTotalWidth) + \"px\"));\n      cm.display.input.setUneditable(lineView.gutterBackground);\n      wrap.insertBefore(lineView.gutterBackground, lineView.text);\n    }\n    var markers = lineView.line.gutterMarkers;\n    if (cm.options.lineNumbers || markers) {\n      var wrap$1 = ensureLineWrapped(lineView);\n      var gutterWrap = lineView.gutter = elt(\"div\", null, \"CodeMirror-gutter-wrapper\", (\"left: \" + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + \"px\"));\n      cm.display.input.setUneditable(gutterWrap);\n      wrap$1.insertBefore(gutterWrap, lineView.text);\n      if (lineView.line.gutterClass)\n        { gutterWrap.className += \" \" + lineView.line.gutterClass; }\n      if (cm.options.lineNumbers && (!markers || !markers[\"CodeMirror-linenumbers\"]))\n        { lineView.lineNumber = gutterWrap.appendChild(\n          elt(\"div\", lineNumberFor(cm.options, lineN),\n              \"CodeMirror-linenumber CodeMirror-gutter-elt\",\n              (\"left: \" + (dims.gutterLeft[\"CodeMirror-linenumbers\"]) + \"px; width: \" + (cm.display.lineNumInnerWidth) + \"px\"))); }\n      if (markers) { for (var k = 0; k < cm.options.gutters.length; ++k) {\n        var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id];\n        if (found)\n          { gutterWrap.appendChild(elt(\"div\", [found], \"CodeMirror-gutter-elt\",\n                                     (\"left: \" + (dims.gutterLeft[id]) + \"px; width: \" + (dims.gutterWidth[id]) + \"px\"))); }\n      } }\n    }\n  }\n\n  function updateLineWidgets(cm, lineView, dims) {\n    if (lineView.alignable) { lineView.alignable = null; }\n    for (var node = lineView.node.firstChild, next = (void 0); node; node = next) {\n      next = node.nextSibling;\n      if (node.className == \"CodeMirror-linewidget\")\n        { lineView.node.removeChild(node); }\n    }\n    insertLineWidgets(cm, lineView, dims);\n  }\n\n  // Build a line's DOM representation from scratch\n  function buildLineElement(cm, lineView, lineN, dims) {\n    var built = getLineContent(cm, lineView);\n    lineView.text = lineView.node = built.pre;\n    if (built.bgClass) { lineView.bgClass = built.bgClass; }\n    if (built.textClass) { lineView.textClass = built.textClass; }\n\n    updateLineClasses(cm, lineView);\n    updateLineGutter(cm, lineView, lineN, dims);\n    insertLineWidgets(cm, lineView, dims);\n    return lineView.node\n  }\n\n  // A lineView may contain multiple logical lines (when merged by\n  // collapsed spans). The widgets for all of them need to be drawn.\n  function insertLineWidgets(cm, lineView, dims) {\n    insertLineWidgetsFor(cm, lineView.line, lineView, dims, true);\n    if (lineView.rest) { for (var i = 0; i < lineView.rest.length; i++)\n      { insertLineWidgetsFor(cm, lineView.rest[i], lineView, dims, false); } }\n  }\n\n  function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) {\n    if (!line.widgets) { return }\n    var wrap = ensureLineWrapped(lineView);\n    for (var i = 0, ws = line.widgets; i < ws.length; ++i) {\n      var widget = ws[i], node = elt(\"div\", [widget.node], \"CodeMirror-linewidget\");\n      if (!widget.handleMouseEvents) { node.setAttribute(\"cm-ignore-events\", \"true\"); }\n      positionLineWidget(widget, node, lineView, dims);\n      cm.display.input.setUneditable(node);\n      if (allowAbove && widget.above)\n        { wrap.insertBefore(node, lineView.gutter || lineView.text); }\n      else\n        { wrap.appendChild(node); }\n      signalLater(widget, \"redraw\");\n    }\n  }\n\n  function positionLineWidget(widget, node, lineView, dims) {\n    if (widget.noHScroll) {\n  (lineView.alignable || (lineView.alignable = [])).push(node);\n      var width = dims.wrapperWidth;\n      node.style.left = dims.fixedPos + \"px\";\n      if (!widget.coverGutter) {\n        width -= dims.gutterTotalWidth;\n        node.style.paddingLeft = dims.gutterTotalWidth + \"px\";\n      }\n      node.style.width = width + \"px\";\n    }\n    if (widget.coverGutter) {\n      node.style.zIndex = 5;\n      node.style.position = \"relative\";\n      if (!widget.noHScroll) { node.style.marginLeft = -dims.gutterTotalWidth + \"px\"; }\n    }\n  }\n\n  function widgetHeight(widget) {\n    if (widget.height != null) { return widget.height }\n    var cm = widget.doc.cm;\n    if (!cm) { return 0 }\n    if (!contains(document.body, widget.node)) {\n      var parentStyle = \"position: relative;\";\n      if (widget.coverGutter)\n        { parentStyle += \"margin-left: -\" + cm.display.gutters.offsetWidth + \"px;\"; }\n      if (widget.noHScroll)\n        { parentStyle += \"width: \" + cm.display.wrapper.clientWidth + \"px;\"; }\n      removeChildrenAndAdd(cm.display.measure, elt(\"div\", [widget.node], null, parentStyle));\n    }\n    return widget.height = widget.node.parentNode.offsetHeight\n  }\n\n  // Return true when the given mouse event happened in a widget\n  function eventInWidget(display, e) {\n    for (var n = e_target(e); n != display.wrapper; n = n.parentNode) {\n      if (!n || (n.nodeType == 1 && n.getAttribute(\"cm-ignore-events\") == \"true\") ||\n          (n.parentNode == display.sizer && n != display.mover))\n        { return true }\n    }\n  }\n\n  // POSITION MEASUREMENT\n\n  function paddingTop(display) {return display.lineSpace.offsetTop}\n  function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight}\n  function paddingH(display) {\n    if (display.cachedPaddingH) { return display.cachedPaddingH }\n    var e = removeChildrenAndAdd(display.measure, elt(\"pre\", \"x\"));\n    var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle;\n    var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)};\n    if (!isNaN(data.left) && !isNaN(data.right)) { display.cachedPaddingH = data; }\n    return data\n  }\n\n  function scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth }\n  function displayWidth(cm) {\n    return cm.display.scroller.clientWidth - scrollGap(cm) - cm.display.barWidth\n  }\n  function displayHeight(cm) {\n    return cm.display.scroller.clientHeight - scrollGap(cm) - cm.display.barHeight\n  }\n\n  // Ensure the lineView.wrapping.heights array is populated. This is\n  // an array of bottom offsets for the lines that make up a drawn\n  // line. When lineWrapping is on, there might be more than one\n  // height.\n  function ensureLineHeights(cm, lineView, rect) {\n    var wrapping = cm.options.lineWrapping;\n    var curWidth = wrapping && displayWidth(cm);\n    if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) {\n      var heights = lineView.measure.heights = [];\n      if (wrapping) {\n        lineView.measure.width = curWidth;\n        var rects = lineView.text.firstChild.getClientRects();\n        for (var i = 0; i < rects.length - 1; i++) {\n          var cur = rects[i], next = rects[i + 1];\n          if (Math.abs(cur.bottom - next.bottom) > 2)\n            { heights.push((cur.bottom + next.top) / 2 - rect.top); }\n        }\n      }\n      heights.push(rect.bottom - rect.top);\n    }\n  }\n\n  // Find a line map (mapping character offsets to text nodes) and a\n  // measurement cache for the given line number. (A line view might\n  // contain multiple lines when collapsed ranges are present.)\n  function mapFromLineView(lineView, line, lineN) {\n    if (lineView.line == line)\n      { return {map: lineView.measure.map, cache: lineView.measure.cache} }\n    for (var i = 0; i < lineView.rest.length; i++)\n      { if (lineView.rest[i] == line)\n        { return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]} } }\n    for (var i$1 = 0; i$1 < lineView.rest.length; i$1++)\n      { if (lineNo(lineView.rest[i$1]) > lineN)\n        { return {map: lineView.measure.maps[i$1], cache: lineView.measure.caches[i$1], before: true} } }\n  }\n\n  // Render a line into the hidden node display.externalMeasured. Used\n  // when measurement is needed for a line that's not in the viewport.\n  function updateExternalMeasurement(cm, line) {\n    line = visualLine(line);\n    var lineN = lineNo(line);\n    var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN);\n    view.lineN = lineN;\n    var built = view.built = buildLineContent(cm, view);\n    view.text = built.pre;\n    removeChildrenAndAdd(cm.display.lineMeasure, built.pre);\n    return view\n  }\n\n  // Get a {top, bottom, left, right} box (in line-local coordinates)\n  // for a given character.\n  function measureChar(cm, line, ch, bias) {\n    return measureCharPrepared(cm, prepareMeasureForLine(cm, line), ch, bias)\n  }\n\n  // Find a line view that corresponds to the given line number.\n  function findViewForLine(cm, lineN) {\n    if (lineN >= cm.display.viewFrom && lineN < cm.display.viewTo)\n      { return cm.display.view[findViewIndex(cm, lineN)] }\n    var ext = cm.display.externalMeasured;\n    if (ext && lineN >= ext.lineN && lineN < ext.lineN + ext.size)\n      { return ext }\n  }\n\n  // Measurement can be split in two steps, the set-up work that\n  // applies to the whole line, and the measurement of the actual\n  // character. Functions like coordsChar, that need to do a lot of\n  // measurements in a row, can thus ensure that the set-up work is\n  // only done once.\n  function prepareMeasureForLine(cm, line) {\n    var lineN = lineNo(line);\n    var view = findViewForLine(cm, lineN);\n    if (view && !view.text) {\n      view = null;\n    } else if (view && view.changes) {\n      updateLineForChanges(cm, view, lineN, getDimensions(cm));\n      cm.curOp.forceUpdate = true;\n    }\n    if (!view)\n      { view = updateExternalMeasurement(cm, line); }\n\n    var info = mapFromLineView(view, line, lineN);\n    return {\n      line: line, view: view, rect: null,\n      map: info.map, cache: info.cache, before: info.before,\n      hasHeights: false\n    }\n  }\n\n  // Given a prepared measurement object, measures the position of an\n  // actual character (or fetches it from the cache).\n  function measureCharPrepared(cm, prepared, ch, bias, varHeight) {\n    if (prepared.before) { ch = -1; }\n    var key = ch + (bias || \"\"), found;\n    if (prepared.cache.hasOwnProperty(key)) {\n      found = prepared.cache[key];\n    } else {\n      if (!prepared.rect)\n        { prepared.rect = prepared.view.text.getBoundingClientRect(); }\n      if (!prepared.hasHeights) {\n        ensureLineHeights(cm, prepared.view, prepared.rect);\n        prepared.hasHeights = true;\n      }\n      found = measureCharInner(cm, prepared, ch, bias);\n      if (!found.bogus) { prepared.cache[key] = found; }\n    }\n    return {left: found.left, right: found.right,\n            top: varHeight ? found.rtop : found.top,\n            bottom: varHeight ? found.rbottom : found.bottom}\n  }\n\n  var nullRect = {left: 0, right: 0, top: 0, bottom: 0};\n\n  function nodeAndOffsetInLineMap(map$$1, ch, bias) {\n    var node, start, end, collapse, mStart, mEnd;\n    // First, search the line map for the text node corresponding to,\n    // or closest to, the target character.\n    for (var i = 0; i < map$$1.length; i += 3) {\n      mStart = map$$1[i];\n      mEnd = map$$1[i + 1];\n      if (ch < mStart) {\n        start = 0; end = 1;\n        collapse = \"left\";\n      } else if (ch < mEnd) {\n        start = ch - mStart;\n        end = start + 1;\n      } else if (i == map$$1.length - 3 || ch == mEnd && map$$1[i + 3] > ch) {\n        end = mEnd - mStart;\n        start = end - 1;\n        if (ch >= mEnd) { collapse = \"right\"; }\n      }\n      if (start != null) {\n        node = map$$1[i + 2];\n        if (mStart == mEnd && bias == (node.insertLeft ? \"left\" : \"right\"))\n          { collapse = bias; }\n        if (bias == \"left\" && start == 0)\n          { while (i && map$$1[i - 2] == map$$1[i - 3] && map$$1[i - 1].insertLeft) {\n            node = map$$1[(i -= 3) + 2];\n            collapse = \"left\";\n          } }\n        if (bias == \"right\" && start == mEnd - mStart)\n          { while (i < map$$1.length - 3 && map$$1[i + 3] == map$$1[i + 4] && !map$$1[i + 5].insertLeft) {\n            node = map$$1[(i += 3) + 2];\n            collapse = \"right\";\n          } }\n        break\n      }\n    }\n    return {node: node, start: start, end: end, collapse: collapse, coverStart: mStart, coverEnd: mEnd}\n  }\n\n  function getUsefulRect(rects, bias) {\n    var rect = nullRect;\n    if (bias == \"left\") { for (var i = 0; i < rects.length; i++) {\n      if ((rect = rects[i]).left != rect.right) { break }\n    } } else { for (var i$1 = rects.length - 1; i$1 >= 0; i$1--) {\n      if ((rect = rects[i$1]).left != rect.right) { break }\n    } }\n    return rect\n  }\n\n  function measureCharInner(cm, prepared, ch, bias) {\n    var place = nodeAndOffsetInLineMap(prepared.map, ch, bias);\n    var node = place.node, start = place.start, end = place.end, collapse = place.collapse;\n\n    var rect;\n    if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates.\n      for (var i$1 = 0; i$1 < 4; i$1++) { // Retry a maximum of 4 times when nonsense rectangles are returned\n        while (start && isExtendingChar(prepared.line.text.charAt(place.coverStart + start))) { --start; }\n        while (place.coverStart + end < place.coverEnd && isExtendingChar(prepared.line.text.charAt(place.coverStart + end))) { ++end; }\n        if (ie && ie_version < 9 && start == 0 && end == place.coverEnd - place.coverStart)\n          { rect = node.parentNode.getBoundingClientRect(); }\n        else\n          { rect = getUsefulRect(range(node, start, end).getClientRects(), bias); }\n        if (rect.left || rect.right || start == 0) { break }\n        end = start;\n        start = start - 1;\n        collapse = \"right\";\n      }\n      if (ie && ie_version < 11) { rect = maybeUpdateRectForZooming(cm.display.measure, rect); }\n    } else { // If it is a widget, simply get the box for the whole widget.\n      if (start > 0) { collapse = bias = \"right\"; }\n      var rects;\n      if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1)\n        { rect = rects[bias == \"right\" ? rects.length - 1 : 0]; }\n      else\n        { rect = node.getBoundingClientRect(); }\n    }\n    if (ie && ie_version < 9 && !start && (!rect || !rect.left && !rect.right)) {\n      var rSpan = node.parentNode.getClientRects()[0];\n      if (rSpan)\n        { rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom}; }\n      else\n        { rect = nullRect; }\n    }\n\n    var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top;\n    var mid = (rtop + rbot) / 2;\n    var heights = prepared.view.measure.heights;\n    var i = 0;\n    for (; i < heights.length - 1; i++)\n      { if (mid < heights[i]) { break } }\n    var top = i ? heights[i - 1] : 0, bot = heights[i];\n    var result = {left: (collapse == \"right\" ? rect.right : rect.left) - prepared.rect.left,\n                  right: (collapse == \"left\" ? rect.left : rect.right) - prepared.rect.left,\n                  top: top, bottom: bot};\n    if (!rect.left && !rect.right) { result.bogus = true; }\n    if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot; }\n\n    return result\n  }\n\n  // Work around problem with bounding client rects on ranges being\n  // returned incorrectly when zoomed on IE10 and below.\n  function maybeUpdateRectForZooming(measure, rect) {\n    if (!window.screen || screen.logicalXDPI == null ||\n        screen.logicalXDPI == screen.deviceXDPI || !hasBadZoomedRects(measure))\n      { return rect }\n    var scaleX = screen.logicalXDPI / screen.deviceXDPI;\n    var scaleY = screen.logicalYDPI / screen.deviceYDPI;\n    return {left: rect.left * scaleX, right: rect.right * scaleX,\n            top: rect.top * scaleY, bottom: rect.bottom * scaleY}\n  }\n\n  function clearLineMeasurementCacheFor(lineView) {\n    if (lineView.measure) {\n      lineView.measure.cache = {};\n      lineView.measure.heights = null;\n      if (lineView.rest) { for (var i = 0; i < lineView.rest.length; i++)\n        { lineView.measure.caches[i] = {}; } }\n    }\n  }\n\n  function clearLineMeasurementCache(cm) {\n    cm.display.externalMeasure = null;\n    removeChildren(cm.display.lineMeasure);\n    for (var i = 0; i < cm.display.view.length; i++)\n      { clearLineMeasurementCacheFor(cm.display.view[i]); }\n  }\n\n  function clearCaches(cm) {\n    clearLineMeasurementCache(cm);\n    cm.display.cachedCharWidth = cm.display.cachedTextHeight = cm.display.cachedPaddingH = null;\n    if (!cm.options.lineWrapping) { cm.display.maxLineChanged = true; }\n    cm.display.lineNumChars = null;\n  }\n\n  function pageScrollX() {\n    // Work around https://bugs.chromium.org/p/chromium/issues/detail?id=489206\n    // which causes page_Offset and bounding client rects to use\n    // different reference viewports and invalidate our calculations.\n    if (chrome && android) { return -(document.body.getBoundingClientRect().left - parseInt(getComputedStyle(document.body).marginLeft)) }\n    return window.pageXOffset || (document.documentElement || document.body).scrollLeft\n  }\n  function pageScrollY() {\n    if (chrome && android) { return -(document.body.getBoundingClientRect().top - parseInt(getComputedStyle(document.body).marginTop)) }\n    return window.pageYOffset || (document.documentElement || document.body).scrollTop\n  }\n\n  function widgetTopHeight(lineObj) {\n    var height = 0;\n    if (lineObj.widgets) { for (var i = 0; i < lineObj.widgets.length; ++i) { if (lineObj.widgets[i].above)\n      { height += widgetHeight(lineObj.widgets[i]); } } }\n    return height\n  }\n\n  // Converts a {top, bottom, left, right} box from line-local\n  // coordinates into another coordinate system. Context may be one of\n  // \"line\", \"div\" (display.lineDiv), \"local\"./null (editor), \"window\",\n  // or \"page\".\n  function intoCoordSystem(cm, lineObj, rect, context, includeWidgets) {\n    if (!includeWidgets) {\n      var height = widgetTopHeight(lineObj);\n      rect.top += height; rect.bottom += height;\n    }\n    if (context == \"line\") { return rect }\n    if (!context) { context = \"local\"; }\n    var yOff = heightAtLine(lineObj);\n    if (context == \"local\") { yOff += paddingTop(cm.display); }\n    else { yOff -= cm.display.viewOffset; }\n    if (context == \"page\" || context == \"window\") {\n      var lOff = cm.display.lineSpace.getBoundingClientRect();\n      yOff += lOff.top + (context == \"window\" ? 0 : pageScrollY());\n      var xOff = lOff.left + (context == \"window\" ? 0 : pageScrollX());\n      rect.left += xOff; rect.right += xOff;\n    }\n    rect.top += yOff; rect.bottom += yOff;\n    return rect\n  }\n\n  // Coverts a box from \"div\" coords to another coordinate system.\n  // Context may be \"window\", \"page\", \"div\", or \"local\"./null.\n  function fromCoordSystem(cm, coords, context) {\n    if (context == \"div\") { return coords }\n    var left = coords.left, top = coords.top;\n    // First move into \"page\" coordinate system\n    if (context == \"page\") {\n      left -= pageScrollX();\n      top -= pageScrollY();\n    } else if (context == \"local\" || !context) {\n      var localBox = cm.display.sizer.getBoundingClientRect();\n      left += localBox.left;\n      top += localBox.top;\n    }\n\n    var lineSpaceBox = cm.display.lineSpace.getBoundingClientRect();\n    return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top}\n  }\n\n  function charCoords(cm, pos, context, lineObj, bias) {\n    if (!lineObj) { lineObj = getLine(cm.doc, pos.line); }\n    return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context)\n  }\n\n  // Returns a box for a given cursor position, which may have an\n  // 'other' property containing the position of the secondary cursor\n  // on a bidi boundary.\n  // A cursor Pos(line, char, \"before\") is on the same visual line as `char - 1`\n  // and after `char - 1` in writing order of `char - 1`\n  // A cursor Pos(line, char, \"after\") is on the same visual line as `char`\n  // and before `char` in writing order of `char`\n  // Examples (upper-case letters are RTL, lower-case are LTR):\n  //     Pos(0, 1, ...)\n  //     before   after\n  // ab     a|b     a|b\n  // aB     a|B     aB|\n  // Ab     |Ab     A|b\n  // AB     B|A     B|A\n  // Every position after the last character on a line is considered to stick\n  // to the last character on the line.\n  function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeight) {\n    lineObj = lineObj || getLine(cm.doc, pos.line);\n    if (!preparedMeasure) { preparedMeasure = prepareMeasureForLine(cm, lineObj); }\n    function get(ch, right) {\n      var m = measureCharPrepared(cm, preparedMeasure, ch, right ? \"right\" : \"left\", varHeight);\n      if (right) { m.left = m.right; } else { m.right = m.left; }\n      return intoCoordSystem(cm, lineObj, m, context)\n    }\n    var order = getOrder(lineObj, cm.doc.direction), ch = pos.ch, sticky = pos.sticky;\n    if (ch >= lineObj.text.length) {\n      ch = lineObj.text.length;\n      sticky = \"before\";\n    } else if (ch <= 0) {\n      ch = 0;\n      sticky = \"after\";\n    }\n    if (!order) { return get(sticky == \"before\" ? ch - 1 : ch, sticky == \"before\") }\n\n    function getBidi(ch, partPos, invert) {\n      var part = order[partPos], right = part.level == 1;\n      return get(invert ? ch - 1 : ch, right != invert)\n    }\n    var partPos = getBidiPartAt(order, ch, sticky);\n    var other = bidiOther;\n    var val = getBidi(ch, partPos, sticky == \"before\");\n    if (other != null) { val.other = getBidi(ch, other, sticky != \"before\"); }\n    return val\n  }\n\n  // Used to cheaply estimate the coordinates for a position. Used for\n  // intermediate scroll updates.\n  function estimateCoords(cm, pos) {\n    var left = 0;\n    pos = clipPos(cm.doc, pos);\n    if (!cm.options.lineWrapping) { left = charWidth(cm.display) * pos.ch; }\n    var lineObj = getLine(cm.doc, pos.line);\n    var top = heightAtLine(lineObj) + paddingTop(cm.display);\n    return {left: left, right: left, top: top, bottom: top + lineObj.height}\n  }\n\n  // Positions returned by coordsChar contain some extra information.\n  // xRel is the relative x position of the input coordinates compared\n  // to the found position (so xRel > 0 means the coordinates are to\n  // the right of the character position, for example). When outside\n  // is true, that means the coordinates lie outside the line's\n  // vertical range.\n  function PosWithInfo(line, ch, sticky, outside, xRel) {\n    var pos = Pos(line, ch, sticky);\n    pos.xRel = xRel;\n    if (outside) { pos.outside = true; }\n    return pos\n  }\n\n  // Compute the character position closest to the given coordinates.\n  // Input must be lineSpace-local (\"div\" coordinate system).\n  function coordsChar(cm, x, y) {\n    var doc = cm.doc;\n    y += cm.display.viewOffset;\n    if (y < 0) { return PosWithInfo(doc.first, 0, null, true, -1) }\n    var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1;\n    if (lineN > last)\n      { return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, null, true, 1) }\n    if (x < 0) { x = 0; }\n\n    var lineObj = getLine(doc, lineN);\n    for (;;) {\n      var found = coordsCharInner(cm, lineObj, lineN, x, y);\n      var collapsed = collapsedSpanAround(lineObj, found.ch + (found.xRel > 0 ? 1 : 0));\n      if (!collapsed) { return found }\n      var rangeEnd = collapsed.find(1);\n      if (rangeEnd.line == lineN) { return rangeEnd }\n      lineObj = getLine(doc, lineN = rangeEnd.line);\n    }\n  }\n\n  function wrappedLineExtent(cm, lineObj, preparedMeasure, y) {\n    y -= widgetTopHeight(lineObj);\n    var end = lineObj.text.length;\n    var begin = findFirst(function (ch) { return measureCharPrepared(cm, preparedMeasure, ch - 1).bottom <= y; }, end, 0);\n    end = findFirst(function (ch) { return measureCharPrepared(cm, preparedMeasure, ch).top > y; }, begin, end);\n    return {begin: begin, end: end}\n  }\n\n  function wrappedLineExtentChar(cm, lineObj, preparedMeasure, target) {\n    if (!preparedMeasure) { preparedMeasure = prepareMeasureForLine(cm, lineObj); }\n    var targetTop = intoCoordSystem(cm, lineObj, measureCharPrepared(cm, preparedMeasure, target), \"line\").top;\n    return wrappedLineExtent(cm, lineObj, preparedMeasure, targetTop)\n  }\n\n  // Returns true if the given side of a box is after the given\n  // coordinates, in top-to-bottom, left-to-right order.\n  function boxIsAfter(box, x, y, left) {\n    return box.bottom <= y ? false : box.top > y ? true : (left ? box.left : box.right) > x\n  }\n\n  function coordsCharInner(cm, lineObj, lineNo$$1, x, y) {\n    // Move y into line-local coordinate space\n    y -= heightAtLine(lineObj);\n    var preparedMeasure = prepareMeasureForLine(cm, lineObj);\n    // When directly calling `measureCharPrepared`, we have to adjust\n    // for the widgets at this line.\n    var widgetHeight$$1 = widgetTopHeight(lineObj);\n    var begin = 0, end = lineObj.text.length, ltr = true;\n\n    var order = getOrder(lineObj, cm.doc.direction);\n    // If the line isn't plain left-to-right text, first figure out\n    // which bidi section the coordinates fall into.\n    if (order) {\n      var part = (cm.options.lineWrapping ? coordsBidiPartWrapped : coordsBidiPart)\n                   (cm, lineObj, lineNo$$1, preparedMeasure, order, x, y);\n      ltr = part.level != 1;\n      // The awkward -1 offsets are needed because findFirst (called\n      // on these below) will treat its first bound as inclusive,\n      // second as exclusive, but we want to actually address the\n      // characters in the part's range\n      begin = ltr ? part.from : part.to - 1;\n      end = ltr ? part.to : part.from - 1;\n    }\n\n    // A binary search to find the first character whose bounding box\n    // starts after the coordinates. If we run across any whose box wrap\n    // the coordinates, store that.\n    var chAround = null, boxAround = null;\n    var ch = findFirst(function (ch) {\n      var box = measureCharPrepared(cm, preparedMeasure, ch);\n      box.top += widgetHeight$$1; box.bottom += widgetHeight$$1;\n      if (!boxIsAfter(box, x, y, false)) { return false }\n      if (box.top <= y && box.left <= x) {\n        chAround = ch;\n        boxAround = box;\n      }\n      return true\n    }, begin, end);\n\n    var baseX, sticky, outside = false;\n    // If a box around the coordinates was found, use that\n    if (boxAround) {\n      // Distinguish coordinates nearer to the left or right side of the box\n      var atLeft = x - boxAround.left < boxAround.right - x, atStart = atLeft == ltr;\n      ch = chAround + (atStart ? 0 : 1);\n      sticky = atStart ? \"after\" : \"before\";\n      baseX = atLeft ? boxAround.left : boxAround.right;\n    } else {\n      // (Adjust for extended bound, if necessary.)\n      if (!ltr && (ch == end || ch == begin)) { ch++; }\n      // To determine which side to associate with, get the box to the\n      // left of the character and compare it's vertical position to the\n      // coordinates\n      sticky = ch == 0 ? \"after\" : ch == lineObj.text.length ? \"before\" :\n        (measureCharPrepared(cm, preparedMeasure, ch - (ltr ? 1 : 0)).bottom + widgetHeight$$1 <= y) == ltr ?\n        \"after\" : \"before\";\n      // Now get accurate coordinates for this place, in order to get a\n      // base X position\n      var coords = cursorCoords(cm, Pos(lineNo$$1, ch, sticky), \"line\", lineObj, preparedMeasure);\n      baseX = coords.left;\n      outside = y < coords.top || y >= coords.bottom;\n    }\n\n    ch = skipExtendingChars(lineObj.text, ch, 1);\n    return PosWithInfo(lineNo$$1, ch, sticky, outside, x - baseX)\n  }\n\n  function coordsBidiPart(cm, lineObj, lineNo$$1, preparedMeasure, order, x, y) {\n    // Bidi parts are sorted left-to-right, and in a non-line-wrapping\n    // situation, we can take this ordering to correspond to the visual\n    // ordering. This finds the first part whose end is after the given\n    // coordinates.\n    var index = findFirst(function (i) {\n      var part = order[i], ltr = part.level != 1;\n      return boxIsAfter(cursorCoords(cm, Pos(lineNo$$1, ltr ? part.to : part.from, ltr ? \"before\" : \"after\"),\n                                     \"line\", lineObj, preparedMeasure), x, y, true)\n    }, 0, order.length - 1);\n    var part = order[index];\n    // If this isn't the first part, the part's start is also after\n    // the coordinates, and the coordinates aren't on the same line as\n    // that start, move one part back.\n    if (index > 0) {\n      var ltr = part.level != 1;\n      var start = cursorCoords(cm, Pos(lineNo$$1, ltr ? part.from : part.to, ltr ? \"after\" : \"before\"),\n                               \"line\", lineObj, preparedMeasure);\n      if (boxIsAfter(start, x, y, true) && start.top > y)\n        { part = order[index - 1]; }\n    }\n    return part\n  }\n\n  function coordsBidiPartWrapped(cm, lineObj, _lineNo, preparedMeasure, order, x, y) {\n    // In a wrapped line, rtl text on wrapping boundaries can do things\n    // that don't correspond to the ordering in our `order` array at\n    // all, so a binary search doesn't work, and we want to return a\n    // part that only spans one line so that the binary search in\n    // coordsCharInner is safe. As such, we first find the extent of the\n    // wrapped line, and then do a flat search in which we discard any\n    // spans that aren't on the line.\n    var ref = wrappedLineExtent(cm, lineObj, preparedMeasure, y);\n    var begin = ref.begin;\n    var end = ref.end;\n    if (/\\s/.test(lineObj.text.charAt(end - 1))) { end--; }\n    var part = null, closestDist = null;\n    for (var i = 0; i < order.length; i++) {\n      var p = order[i];\n      if (p.from >= end || p.to <= begin) { continue }\n      var ltr = p.level != 1;\n      var endX = measureCharPrepared(cm, preparedMeasure, ltr ? Math.min(end, p.to) - 1 : Math.max(begin, p.from)).right;\n      // Weigh against spans ending before this, so that they are only\n      // picked if nothing ends after\n      var dist = endX < x ? x - endX + 1e9 : endX - x;\n      if (!part || closestDist > dist) {\n        part = p;\n        closestDist = dist;\n      }\n    }\n    if (!part) { part = order[order.length - 1]; }\n    // Clip the part to the wrapped line.\n    if (part.from < begin) { part = {from: begin, to: part.to, level: part.level}; }\n    if (part.to > end) { part = {from: part.from, to: end, level: part.level}; }\n    return part\n  }\n\n  var measureText;\n  // Compute the default text height.\n  function textHeight(display) {\n    if (display.cachedTextHeight != null) { return display.cachedTextHeight }\n    if (measureText == null) {\n      measureText = elt(\"pre\");\n      // Measure a bunch of lines, for browsers that compute\n      // fractional heights.\n      for (var i = 0; i < 49; ++i) {\n        measureText.appendChild(document.createTextNode(\"x\"));\n        measureText.appendChild(elt(\"br\"));\n      }\n      measureText.appendChild(document.createTextNode(\"x\"));\n    }\n    removeChildrenAndAdd(display.measure, measureText);\n    var height = measureText.offsetHeight / 50;\n    if (height > 3) { display.cachedTextHeight = height; }\n    removeChildren(display.measure);\n    return height || 1\n  }\n\n  // Compute the default character width.\n  function charWidth(display) {\n    if (display.cachedCharWidth != null) { return display.cachedCharWidth }\n    var anchor = elt(\"span\", \"xxxxxxxxxx\");\n    var pre = elt(\"pre\", [anchor]);\n    removeChildrenAndAdd(display.measure, pre);\n    var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10;\n    if (width > 2) { display.cachedCharWidth = width; }\n    return width || 10\n  }\n\n  // Do a bulk-read of the DOM positions and sizes needed to draw the\n  // view, so that we don't interleave reading and writing to the DOM.\n  function getDimensions(cm) {\n    var d = cm.display, left = {}, width = {};\n    var gutterLeft = d.gutters.clientLeft;\n    for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) {\n      left[cm.options.gutters[i]] = n.offsetLeft + n.clientLeft + gutterLeft;\n      width[cm.options.gutters[i]] = n.clientWidth;\n    }\n    return {fixedPos: compensateForHScroll(d),\n            gutterTotalWidth: d.gutters.offsetWidth,\n            gutterLeft: left,\n            gutterWidth: width,\n            wrapperWidth: d.wrapper.clientWidth}\n  }\n\n  // Computes display.scroller.scrollLeft + display.gutters.offsetWidth,\n  // but using getBoundingClientRect to get a sub-pixel-accurate\n  // result.\n  function compensateForHScroll(display) {\n    return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left\n  }\n\n  // Returns a function that estimates the height of a line, to use as\n  // first approximation until the line becomes visible (and is thus\n  // properly measurable).\n  function estimateHeight(cm) {\n    var th = textHeight(cm.display), wrapping = cm.options.lineWrapping;\n    var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3);\n    return function (line) {\n      if (lineIsHidden(cm.doc, line)) { return 0 }\n\n      var widgetsHeight = 0;\n      if (line.widgets) { for (var i = 0; i < line.widgets.length; i++) {\n        if (line.widgets[i].height) { widgetsHeight += line.widgets[i].height; }\n      } }\n\n      if (wrapping)\n        { return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * th }\n      else\n        { return widgetsHeight + th }\n    }\n  }\n\n  function estimateLineHeights(cm) {\n    var doc = cm.doc, est = estimateHeight(cm);\n    doc.iter(function (line) {\n      var estHeight = est(line);\n      if (estHeight != line.height) { updateLineHeight(line, estHeight); }\n    });\n  }\n\n  // Given a mouse event, find the corresponding position. If liberal\n  // is false, it checks whether a gutter or scrollbar was clicked,\n  // and returns null if it was. forRect is used by rectangular\n  // selections, and tries to estimate a character position even for\n  // coordinates beyond the right of the text.\n  function posFromMouse(cm, e, liberal, forRect) {\n    var display = cm.display;\n    if (!liberal && e_target(e).getAttribute(\"cm-not-content\") == \"true\") { return null }\n\n    var x, y, space = display.lineSpace.getBoundingClientRect();\n    // Fails unpredictably on IE[67] when mouse is dragged around quickly.\n    try { x = e.clientX - space.left; y = e.clientY - space.top; }\n    catch (e) { return null }\n    var coords = coordsChar(cm, x, y), line;\n    if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) {\n      var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length;\n      coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff));\n    }\n    return coords\n  }\n\n  // Find the view element corresponding to a given line. Return null\n  // when the line isn't visible.\n  function findViewIndex(cm, n) {\n    if (n >= cm.display.viewTo) { return null }\n    n -= cm.display.viewFrom;\n    if (n < 0) { return null }\n    var view = cm.display.view;\n    for (var i = 0; i < view.length; i++) {\n      n -= view[i].size;\n      if (n < 0) { return i }\n    }\n  }\n\n  function updateSelection(cm) {\n    cm.display.input.showSelection(cm.display.input.prepareSelection());\n  }\n\n  function prepareSelection(cm, primary) {\n    if ( primary === void 0 ) primary = true;\n\n    var doc = cm.doc, result = {};\n    var curFragment = result.cursors = document.createDocumentFragment();\n    var selFragment = result.selection = document.createDocumentFragment();\n\n    for (var i = 0; i < doc.sel.ranges.length; i++) {\n      if (!primary && i == doc.sel.primIndex) { continue }\n      var range$$1 = doc.sel.ranges[i];\n      if (range$$1.from().line >= cm.display.viewTo || range$$1.to().line < cm.display.viewFrom) { continue }\n      var collapsed = range$$1.empty();\n      if (collapsed || cm.options.showCursorWhenSelecting)\n        { drawSelectionCursor(cm, range$$1.head, curFragment); }\n      if (!collapsed)\n        { drawSelectionRange(cm, range$$1, selFragment); }\n    }\n    return result\n  }\n\n  // Draws a cursor for the given range\n  function drawSelectionCursor(cm, head, output) {\n    var pos = cursorCoords(cm, head, \"div\", null, null, !cm.options.singleCursorHeightPerLine);\n\n    var cursor = output.appendChild(elt(\"div\", \"\\u00a0\", \"CodeMirror-cursor\"));\n    cursor.style.left = pos.left + \"px\";\n    cursor.style.top = pos.top + \"px\";\n    cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + \"px\";\n\n    if (pos.other) {\n      // Secondary cursor, shown when on a 'jump' in bi-directional text\n      var otherCursor = output.appendChild(elt(\"div\", \"\\u00a0\", \"CodeMirror-cursor CodeMirror-secondarycursor\"));\n      otherCursor.style.display = \"\";\n      otherCursor.style.left = pos.other.left + \"px\";\n      otherCursor.style.top = pos.other.top + \"px\";\n      otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + \"px\";\n    }\n  }\n\n  function cmpCoords(a, b) { return a.top - b.top || a.left - b.left }\n\n  // Draws the given range as a highlighted selection\n  function drawSelectionRange(cm, range$$1, output) {\n    var display = cm.display, doc = cm.doc;\n    var fragment = document.createDocumentFragment();\n    var padding = paddingH(cm.display), leftSide = padding.left;\n    var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right;\n    var docLTR = doc.direction == \"ltr\";\n\n    function add(left, top, width, bottom) {\n      if (top < 0) { top = 0; }\n      top = Math.round(top);\n      bottom = Math.round(bottom);\n      fragment.appendChild(elt(\"div\", null, \"CodeMirror-selected\", (\"position: absolute; left: \" + left + \"px;\\n                             top: \" + top + \"px; width: \" + (width == null ? rightSide - left : width) + \"px;\\n                             height: \" + (bottom - top) + \"px\")));\n    }\n\n    function drawForLine(line, fromArg, toArg) {\n      var lineObj = getLine(doc, line);\n      var lineLen = lineObj.text.length;\n      var start, end;\n      function coords(ch, bias) {\n        return charCoords(cm, Pos(line, ch), \"div\", lineObj, bias)\n      }\n\n      function wrapX(pos, dir, side) {\n        var extent = wrappedLineExtentChar(cm, lineObj, null, pos);\n        var prop = (dir == \"ltr\") == (side == \"after\") ? \"left\" : \"right\";\n        var ch = side == \"after\" ? extent.begin : extent.end - (/\\s/.test(lineObj.text.charAt(extent.end - 1)) ? 2 : 1);\n        return coords(ch, prop)[prop]\n      }\n\n      var order = getOrder(lineObj, doc.direction);\n      iterateBidiSections(order, fromArg || 0, toArg == null ? lineLen : toArg, function (from, to, dir, i) {\n        var ltr = dir == \"ltr\";\n        var fromPos = coords(from, ltr ? \"left\" : \"right\");\n        var toPos = coords(to - 1, ltr ? \"right\" : \"left\");\n\n        var openStart = fromArg == null && from == 0, openEnd = toArg == null && to == lineLen;\n        var first = i == 0, last = !order || i == order.length - 1;\n        if (toPos.top - fromPos.top <= 3) { // Single line\n          var openLeft = (docLTR ? openStart : openEnd) && first;\n          var openRight = (docLTR ? openEnd : openStart) && last;\n          var left = openLeft ? leftSide : (ltr ? fromPos : toPos).left;\n          var right = openRight ? rightSide : (ltr ? toPos : fromPos).right;\n          add(left, fromPos.top, right - left, fromPos.bottom);\n        } else { // Multiple lines\n          var topLeft, topRight, botLeft, botRight;\n          if (ltr) {\n            topLeft = docLTR && openStart && first ? leftSide : fromPos.left;\n            topRight = docLTR ? rightSide : wrapX(from, dir, \"before\");\n            botLeft = docLTR ? leftSide : wrapX(to, dir, \"after\");\n            botRight = docLTR && openEnd && last ? rightSide : toPos.right;\n          } else {\n            topLeft = !docLTR ? leftSide : wrapX(from, dir, \"before\");\n            topRight = !docLTR && openStart && first ? rightSide : fromPos.right;\n            botLeft = !docLTR && openEnd && last ? leftSide : toPos.left;\n            botRight = !docLTR ? rightSide : wrapX(to, dir, \"after\");\n          }\n          add(topLeft, fromPos.top, topRight - topLeft, fromPos.bottom);\n          if (fromPos.bottom < toPos.top) { add(leftSide, fromPos.bottom, null, toPos.top); }\n          add(botLeft, toPos.top, botRight - botLeft, toPos.bottom);\n        }\n\n        if (!start || cmpCoords(fromPos, start) < 0) { start = fromPos; }\n        if (cmpCoords(toPos, start) < 0) { start = toPos; }\n        if (!end || cmpCoords(fromPos, end) < 0) { end = fromPos; }\n        if (cmpCoords(toPos, end) < 0) { end = toPos; }\n      });\n      return {start: start, end: end}\n    }\n\n    var sFrom = range$$1.from(), sTo = range$$1.to();\n    if (sFrom.line == sTo.line) {\n      drawForLine(sFrom.line, sFrom.ch, sTo.ch);\n    } else {\n      var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line);\n      var singleVLine = visualLine(fromLine) == visualLine(toLine);\n      var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end;\n      var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start;\n      if (singleVLine) {\n        if (leftEnd.top < rightStart.top - 2) {\n          add(leftEnd.right, leftEnd.top, null, leftEnd.bottom);\n          add(leftSide, rightStart.top, rightStart.left, rightStart.bottom);\n        } else {\n          add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom);\n        }\n      }\n      if (leftEnd.bottom < rightStart.top)\n        { add(leftSide, leftEnd.bottom, null, rightStart.top); }\n    }\n\n    output.appendChild(fragment);\n  }\n\n  // Cursor-blinking\n  function restartBlink(cm) {\n    if (!cm.state.focused) { return }\n    var display = cm.display;\n    clearInterval(display.blinker);\n    var on = true;\n    display.cursorDiv.style.visibility = \"\";\n    if (cm.options.cursorBlinkRate > 0)\n      { display.blinker = setInterval(function () { return display.cursorDiv.style.visibility = (on = !on) ? \"\" : \"hidden\"; },\n        cm.options.cursorBlinkRate); }\n    else if (cm.options.cursorBlinkRate < 0)\n      { display.cursorDiv.style.visibility = \"hidden\"; }\n  }\n\n  function ensureFocus(cm) {\n    if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm); }\n  }\n\n  function delayBlurEvent(cm) {\n    cm.state.delayingBlurEvent = true;\n    setTimeout(function () { if (cm.state.delayingBlurEvent) {\n      cm.state.delayingBlurEvent = false;\n      onBlur(cm);\n    } }, 100);\n  }\n\n  function onFocus(cm, e) {\n    if (cm.state.delayingBlurEvent) { cm.state.delayingBlurEvent = false; }\n\n    if (cm.options.readOnly == \"nocursor\") { return }\n    if (!cm.state.focused) {\n      signal(cm, \"focus\", cm, e);\n      cm.state.focused = true;\n      addClass(cm.display.wrapper, \"CodeMirror-focused\");\n      // This test prevents this from firing when a context\n      // menu is closed (since the input reset would kill the\n      // select-all detection hack)\n      if (!cm.curOp && cm.display.selForContextMenu != cm.doc.sel) {\n        cm.display.input.reset();\n        if (webkit) { setTimeout(function () { return cm.display.input.reset(true); }, 20); } // Issue #1730\n      }\n      cm.display.input.receivedFocus();\n    }\n    restartBlink(cm);\n  }\n  function onBlur(cm, e) {\n    if (cm.state.delayingBlurEvent) { return }\n\n    if (cm.state.focused) {\n      signal(cm, \"blur\", cm, e);\n      cm.state.focused = false;\n      rmClass(cm.display.wrapper, \"CodeMirror-focused\");\n    }\n    clearInterval(cm.display.blinker);\n    setTimeout(function () { if (!cm.state.focused) { cm.display.shift = false; } }, 150);\n  }\n\n  // Read the actual heights of the rendered lines, and update their\n  // stored heights to match.\n  function updateHeightsInViewport(cm) {\n    var display = cm.display;\n    var prevBottom = display.lineDiv.offsetTop;\n    for (var i = 0; i < display.view.length; i++) {\n      var cur = display.view[i], height = (void 0);\n      if (cur.hidden) { continue }\n      if (ie && ie_version < 8) {\n        var bot = cur.node.offsetTop + cur.node.offsetHeight;\n        height = bot - prevBottom;\n        prevBottom = bot;\n      } else {\n        var box = cur.node.getBoundingClientRect();\n        height = box.bottom - box.top;\n      }\n      var diff = cur.line.height - height;\n      if (height < 2) { height = textHeight(display); }\n      if (diff > .005 || diff < -.005) {\n        updateLineHeight(cur.line, height);\n        updateWidgetHeight(cur.line);\n        if (cur.rest) { for (var j = 0; j < cur.rest.length; j++)\n          { updateWidgetHeight(cur.rest[j]); } }\n      }\n    }\n  }\n\n  // Read and store the height of line widgets associated with the\n  // given line.\n  function updateWidgetHeight(line) {\n    if (line.widgets) { for (var i = 0; i < line.widgets.length; ++i) {\n      var w = line.widgets[i], parent = w.node.parentNode;\n      if (parent) { w.height = parent.offsetHeight; }\n    } }\n  }\n\n  // Compute the lines that are visible in a given viewport (defaults\n  // the the current scroll position). viewport may contain top,\n  // height, and ensure (see op.scrollToPos) properties.\n  function visibleLines(display, doc, viewport) {\n    var top = viewport && viewport.top != null ? Math.max(0, viewport.top) : display.scroller.scrollTop;\n    top = Math.floor(top - paddingTop(display));\n    var bottom = viewport && viewport.bottom != null ? viewport.bottom : top + display.wrapper.clientHeight;\n\n    var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom);\n    // Ensure is a {from: {line, ch}, to: {line, ch}} object, and\n    // forces those lines into the viewport (if possible).\n    if (viewport && viewport.ensure) {\n      var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line;\n      if (ensureFrom < from) {\n        from = ensureFrom;\n        to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight);\n      } else if (Math.min(ensureTo, doc.lastLine()) >= to) {\n        from = lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight);\n        to = ensureTo;\n      }\n    }\n    return {from: from, to: Math.max(to, from + 1)}\n  }\n\n  // Re-align line numbers and gutter marks to compensate for\n  // horizontal scrolling.\n  function alignHorizontally(cm) {\n    var display = cm.display, view = display.view;\n    if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) { return }\n    var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft;\n    var gutterW = display.gutters.offsetWidth, left = comp + \"px\";\n    for (var i = 0; i < view.length; i++) { if (!view[i].hidden) {\n      if (cm.options.fixedGutter) {\n        if (view[i].gutter)\n          { view[i].gutter.style.left = left; }\n        if (view[i].gutterBackground)\n          { view[i].gutterBackground.style.left = left; }\n      }\n      var align = view[i].alignable;\n      if (align) { for (var j = 0; j < align.length; j++)\n        { align[j].style.left = left; } }\n    } }\n    if (cm.options.fixedGutter)\n      { display.gutters.style.left = (comp + gutterW) + \"px\"; }\n  }\n\n  // Used to ensure that the line number gutter is still the right\n  // size for the current document size. Returns true when an update\n  // is needed.\n  function maybeUpdateLineNumberWidth(cm) {\n    if (!cm.options.lineNumbers) { return false }\n    var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display;\n    if (last.length != display.lineNumChars) {\n      var test = display.measure.appendChild(elt(\"div\", [elt(\"div\", last)],\n                                                 \"CodeMirror-linenumber CodeMirror-gutter-elt\"));\n      var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW;\n      display.lineGutter.style.width = \"\";\n      display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding) + 1;\n      display.lineNumWidth = display.lineNumInnerWidth + padding;\n      display.lineNumChars = display.lineNumInnerWidth ? last.length : -1;\n      display.lineGutter.style.width = display.lineNumWidth + \"px\";\n      updateGutterSpace(cm);\n      return true\n    }\n    return false\n  }\n\n  // SCROLLING THINGS INTO VIEW\n\n  // If an editor sits on the top or bottom of the window, partially\n  // scrolled out of view, this ensures that the cursor is visible.\n  function maybeScrollWindow(cm, rect) {\n    if (signalDOMEvent(cm, \"scrollCursorIntoView\")) { return }\n\n    var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null;\n    if (rect.top + box.top < 0) { doScroll = true; }\n    else if (rect.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) { doScroll = false; }\n    if (doScroll != null && !phantom) {\n      var scrollNode = elt(\"div\", \"\\u200b\", null, (\"position: absolute;\\n                         top: \" + (rect.top - display.viewOffset - paddingTop(cm.display)) + \"px;\\n                         height: \" + (rect.bottom - rect.top + scrollGap(cm) + display.barHeight) + \"px;\\n                         left: \" + (rect.left) + \"px; width: \" + (Math.max(2, rect.right - rect.left)) + \"px;\"));\n      cm.display.lineSpace.appendChild(scrollNode);\n      scrollNode.scrollIntoView(doScroll);\n      cm.display.lineSpace.removeChild(scrollNode);\n    }\n  }\n\n  // Scroll a given position into view (immediately), verifying that\n  // it actually became visible (as line heights are accurately\n  // measured, the position of something may 'drift' during drawing).\n  function scrollPosIntoView(cm, pos, end, margin) {\n    if (margin == null) { margin = 0; }\n    var rect;\n    if (!cm.options.lineWrapping && pos == end) {\n      // Set pos and end to the cursor positions around the character pos sticks to\n      // If pos.sticky == \"before\", that is around pos.ch - 1, otherwise around pos.ch\n      // If pos == Pos(_, 0, \"before\"), pos and end are unchanged\n      pos = pos.ch ? Pos(pos.line, pos.sticky == \"before\" ? pos.ch - 1 : pos.ch, \"after\") : pos;\n      end = pos.sticky == \"before\" ? Pos(pos.line, pos.ch + 1, \"before\") : pos;\n    }\n    for (var limit = 0; limit < 5; limit++) {\n      var changed = false;\n      var coords = cursorCoords(cm, pos);\n      var endCoords = !end || end == pos ? coords : cursorCoords(cm, end);\n      rect = {left: Math.min(coords.left, endCoords.left),\n              top: Math.min(coords.top, endCoords.top) - margin,\n              right: Math.max(coords.left, endCoords.left),\n              bottom: Math.max(coords.bottom, endCoords.bottom) + margin};\n      var scrollPos = calculateScrollPos(cm, rect);\n      var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft;\n      if (scrollPos.scrollTop != null) {\n        updateScrollTop(cm, scrollPos.scrollTop);\n        if (Math.abs(cm.doc.scrollTop - startTop) > 1) { changed = true; }\n      }\n      if (scrollPos.scrollLeft != null) {\n        setScrollLeft(cm, scrollPos.scrollLeft);\n        if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) { changed = true; }\n      }\n      if (!changed) { break }\n    }\n    return rect\n  }\n\n  // Scroll a given set of coordinates into view (immediately).\n  function scrollIntoView(cm, rect) {\n    var scrollPos = calculateScrollPos(cm, rect);\n    if (scrollPos.scrollTop != null) { updateScrollTop(cm, scrollPos.scrollTop); }\n    if (scrollPos.scrollLeft != null) { setScrollLeft(cm, scrollPos.scrollLeft); }\n  }\n\n  // Calculate a new scroll position needed to scroll the given\n  // rectangle into view. Returns an object with scrollTop and\n  // scrollLeft properties. When these are undefined, the\n  // vertical/horizontal position does not need to be adjusted.\n  function calculateScrollPos(cm, rect) {\n    var display = cm.display, snapMargin = textHeight(cm.display);\n    if (rect.top < 0) { rect.top = 0; }\n    var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop;\n    var screen = displayHeight(cm), result = {};\n    if (rect.bottom - rect.top > screen) { rect.bottom = rect.top + screen; }\n    var docBottom = cm.doc.height + paddingVert(display);\n    var atTop = rect.top < snapMargin, atBottom = rect.bottom > docBottom - snapMargin;\n    if (rect.top < screentop) {\n      result.scrollTop = atTop ? 0 : rect.top;\n    } else if (rect.bottom > screentop + screen) {\n      var newTop = Math.min(rect.top, (atBottom ? docBottom : rect.bottom) - screen);\n      if (newTop != screentop) { result.scrollTop = newTop; }\n    }\n\n    var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft;\n    var screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0);\n    var tooWide = rect.right - rect.left > screenw;\n    if (tooWide) { rect.right = rect.left + screenw; }\n    if (rect.left < 10)\n      { result.scrollLeft = 0; }\n    else if (rect.left < screenleft)\n      { result.scrollLeft = Math.max(0, rect.left - (tooWide ? 0 : 10)); }\n    else if (rect.right > screenw + screenleft - 3)\n      { result.scrollLeft = rect.right + (tooWide ? 0 : 10) - screenw; }\n    return result\n  }\n\n  // Store a relative adjustment to the scroll position in the current\n  // operation (to be applied when the operation finishes).\n  function addToScrollTop(cm, top) {\n    if (top == null) { return }\n    resolveScrollToPos(cm);\n    cm.curOp.scrollTop = (cm.curOp.scrollTop == null ? cm.doc.scrollTop : cm.curOp.scrollTop) + top;\n  }\n\n  // Make sure that at the end of the operation the current cursor is\n  // shown.\n  function ensureCursorVisible(cm) {\n    resolveScrollToPos(cm);\n    var cur = cm.getCursor();\n    cm.curOp.scrollToPos = {from: cur, to: cur, margin: cm.options.cursorScrollMargin};\n  }\n\n  function scrollToCoords(cm, x, y) {\n    if (x != null || y != null) { resolveScrollToPos(cm); }\n    if (x != null) { cm.curOp.scrollLeft = x; }\n    if (y != null) { cm.curOp.scrollTop = y; }\n  }\n\n  function scrollToRange(cm, range$$1) {\n    resolveScrollToPos(cm);\n    cm.curOp.scrollToPos = range$$1;\n  }\n\n  // When an operation has its scrollToPos property set, and another\n  // scroll action is applied before the end of the operation, this\n  // 'simulates' scrolling that position into view in a cheap way, so\n  // that the effect of intermediate scroll commands is not ignored.\n  function resolveScrollToPos(cm) {\n    var range$$1 = cm.curOp.scrollToPos;\n    if (range$$1) {\n      cm.curOp.scrollToPos = null;\n      var from = estimateCoords(cm, range$$1.from), to = estimateCoords(cm, range$$1.to);\n      scrollToCoordsRange(cm, from, to, range$$1.margin);\n    }\n  }\n\n  function scrollToCoordsRange(cm, from, to, margin) {\n    var sPos = calculateScrollPos(cm, {\n      left: Math.min(from.left, to.left),\n      top: Math.min(from.top, to.top) - margin,\n      right: Math.max(from.right, to.right),\n      bottom: Math.max(from.bottom, to.bottom) + margin\n    });\n    scrollToCoords(cm, sPos.scrollLeft, sPos.scrollTop);\n  }\n\n  // Sync the scrollable area and scrollbars, ensure the viewport\n  // covers the visible area.\n  function updateScrollTop(cm, val) {\n    if (Math.abs(cm.doc.scrollTop - val) < 2) { return }\n    if (!gecko) { updateDisplaySimple(cm, {top: val}); }\n    setScrollTop(cm, val, true);\n    if (gecko) { updateDisplaySimple(cm); }\n    startWorker(cm, 100);\n  }\n\n  function setScrollTop(cm, val, forceScroll) {\n    val = Math.min(cm.display.scroller.scrollHeight - cm.display.scroller.clientHeight, val);\n    if (cm.display.scroller.scrollTop == val && !forceScroll) { return }\n    cm.doc.scrollTop = val;\n    cm.display.scrollbars.setScrollTop(val);\n    if (cm.display.scroller.scrollTop != val) { cm.display.scroller.scrollTop = val; }\n  }\n\n  // Sync scroller and scrollbar, ensure the gutter elements are\n  // aligned.\n  function setScrollLeft(cm, val, isScroller, forceScroll) {\n    val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth);\n    if ((isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) && !forceScroll) { return }\n    cm.doc.scrollLeft = val;\n    alignHorizontally(cm);\n    if (cm.display.scroller.scrollLeft != val) { cm.display.scroller.scrollLeft = val; }\n    cm.display.scrollbars.setScrollLeft(val);\n  }\n\n  // SCROLLBARS\n\n  // Prepare DOM reads needed to update the scrollbars. Done in one\n  // shot to minimize update/measure roundtrips.\n  function measureForScrollbars(cm) {\n    var d = cm.display, gutterW = d.gutters.offsetWidth;\n    var docH = Math.round(cm.doc.height + paddingVert(cm.display));\n    return {\n      clientHeight: d.scroller.clientHeight,\n      viewHeight: d.wrapper.clientHeight,\n      scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth,\n      viewWidth: d.wrapper.clientWidth,\n      barLeft: cm.options.fixedGutter ? gutterW : 0,\n      docHeight: docH,\n      scrollHeight: docH + scrollGap(cm) + d.barHeight,\n      nativeBarWidth: d.nativeBarWidth,\n      gutterWidth: gutterW\n    }\n  }\n\n  var NativeScrollbars = function(place, scroll, cm) {\n    this.cm = cm;\n    var vert = this.vert = elt(\"div\", [elt(\"div\", null, null, \"min-width: 1px\")], \"CodeMirror-vscrollbar\");\n    var horiz = this.horiz = elt(\"div\", [elt(\"div\", null, null, \"height: 100%; min-height: 1px\")], \"CodeMirror-hscrollbar\");\n    vert.tabIndex = horiz.tabIndex = -1;\n    place(vert); place(horiz);\n\n    on(vert, \"scroll\", function () {\n      if (vert.clientHeight) { scroll(vert.scrollTop, \"vertical\"); }\n    });\n    on(horiz, \"scroll\", function () {\n      if (horiz.clientWidth) { scroll(horiz.scrollLeft, \"horizontal\"); }\n    });\n\n    this.checkedZeroWidth = false;\n    // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).\n    if (ie && ie_version < 8) { this.horiz.style.minHeight = this.vert.style.minWidth = \"18px\"; }\n  };\n\n  NativeScrollbars.prototype.update = function (measure) {\n    var needsH = measure.scrollWidth > measure.clientWidth + 1;\n    var needsV = measure.scrollHeight > measure.clientHeight + 1;\n    var sWidth = measure.nativeBarWidth;\n\n    if (needsV) {\n      this.vert.style.display = \"block\";\n      this.vert.style.bottom = needsH ? sWidth + \"px\" : \"0\";\n      var totalHeight = measure.viewHeight - (needsH ? sWidth : 0);\n      // A bug in IE8 can cause this value to be negative, so guard it.\n      this.vert.firstChild.style.height =\n        Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + \"px\";\n    } else {\n      this.vert.style.display = \"\";\n      this.vert.firstChild.style.height = \"0\";\n    }\n\n    if (needsH) {\n      this.horiz.style.display = \"block\";\n      this.horiz.style.right = needsV ? sWidth + \"px\" : \"0\";\n      this.horiz.style.left = measure.barLeft + \"px\";\n      var totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0);\n      this.horiz.firstChild.style.width =\n        Math.max(0, measure.scrollWidth - measure.clientWidth + totalWidth) + \"px\";\n    } else {\n      this.horiz.style.display = \"\";\n      this.horiz.firstChild.style.width = \"0\";\n    }\n\n    if (!this.checkedZeroWidth && measure.clientHeight > 0) {\n      if (sWidth == 0) { this.zeroWidthHack(); }\n      this.checkedZeroWidth = true;\n    }\n\n    return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0}\n  };\n\n  NativeScrollbars.prototype.setScrollLeft = function (pos) {\n    if (this.horiz.scrollLeft != pos) { this.horiz.scrollLeft = pos; }\n    if (this.disableHoriz) { this.enableZeroWidthBar(this.horiz, this.disableHoriz, \"horiz\"); }\n  };\n\n  NativeScrollbars.prototype.setScrollTop = function (pos) {\n    if (this.vert.scrollTop != pos) { this.vert.scrollTop = pos; }\n    if (this.disableVert) { this.enableZeroWidthBar(this.vert, this.disableVert, \"vert\"); }\n  };\n\n  NativeScrollbars.prototype.zeroWidthHack = function () {\n    var w = mac && !mac_geMountainLion ? \"12px\" : \"18px\";\n    this.horiz.style.height = this.vert.style.width = w;\n    this.horiz.style.pointerEvents = this.vert.style.pointerEvents = \"none\";\n    this.disableHoriz = new Delayed;\n    this.disableVert = new Delayed;\n  };\n\n  NativeScrollbars.prototype.enableZeroWidthBar = function (bar, delay, type) {\n    bar.style.pointerEvents = \"auto\";\n    function maybeDisable() {\n      // To find out whether the scrollbar is still visible, we\n      // check whether the element under the pixel in the bottom\n      // right corner of the scrollbar box is the scrollbar box\n      // itself (when the bar is still visible) or its filler child\n      // (when the bar is hidden). If it is still visible, we keep\n      // it enabled, if it's hidden, we disable pointer events.\n      var box = bar.getBoundingClientRect();\n      var elt$$1 = type == \"vert\" ? document.elementFromPoint(box.right - 1, (box.top + box.bottom) / 2)\n          : document.elementFromPoint((box.right + box.left) / 2, box.bottom - 1);\n      if (elt$$1 != bar) { bar.style.pointerEvents = \"none\"; }\n      else { delay.set(1000, maybeDisable); }\n    }\n    delay.set(1000, maybeDisable);\n  };\n\n  NativeScrollbars.prototype.clear = function () {\n    var parent = this.horiz.parentNode;\n    parent.removeChild(this.horiz);\n    parent.removeChild(this.vert);\n  };\n\n  var NullScrollbars = function () {};\n\n  NullScrollbars.prototype.update = function () { return {bottom: 0, right: 0} };\n  NullScrollbars.prototype.setScrollLeft = function () {};\n  NullScrollbars.prototype.setScrollTop = function () {};\n  NullScrollbars.prototype.clear = function () {};\n\n  function updateScrollbars(cm, measure) {\n    if (!measure) { measure = measureForScrollbars(cm); }\n    var startWidth = cm.display.barWidth, startHeight = cm.display.barHeight;\n    updateScrollbarsInner(cm, measure);\n    for (var i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) {\n      if (startWidth != cm.display.barWidth && cm.options.lineWrapping)\n        { updateHeightsInViewport(cm); }\n      updateScrollbarsInner(cm, measureForScrollbars(cm));\n      startWidth = cm.display.barWidth; startHeight = cm.display.barHeight;\n    }\n  }\n\n  // Re-synchronize the fake scrollbars with the actual size of the\n  // content.\n  function updateScrollbarsInner(cm, measure) {\n    var d = cm.display;\n    var sizes = d.scrollbars.update(measure);\n\n    d.sizer.style.paddingRight = (d.barWidth = sizes.right) + \"px\";\n    d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + \"px\";\n    d.heightForcer.style.borderBottom = sizes.bottom + \"px solid transparent\";\n\n    if (sizes.right && sizes.bottom) {\n      d.scrollbarFiller.style.display = \"block\";\n      d.scrollbarFiller.style.height = sizes.bottom + \"px\";\n      d.scrollbarFiller.style.width = sizes.right + \"px\";\n    } else { d.scrollbarFiller.style.display = \"\"; }\n    if (sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) {\n      d.gutterFiller.style.display = \"block\";\n      d.gutterFiller.style.height = sizes.bottom + \"px\";\n      d.gutterFiller.style.width = measure.gutterWidth + \"px\";\n    } else { d.gutterFiller.style.display = \"\"; }\n  }\n\n  var scrollbarModel = {\"native\": NativeScrollbars, \"null\": NullScrollbars};\n\n  function initScrollbars(cm) {\n    if (cm.display.scrollbars) {\n      cm.display.scrollbars.clear();\n      if (cm.display.scrollbars.addClass)\n        { rmClass(cm.display.wrapper, cm.display.scrollbars.addClass); }\n    }\n\n    cm.display.scrollbars = new scrollbarModel[cm.options.scrollbarStyle](function (node) {\n      cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller);\n      // Prevent clicks in the scrollbars from killing focus\n      on(node, \"mousedown\", function () {\n        if (cm.state.focused) { setTimeout(function () { return cm.display.input.focus(); }, 0); }\n      });\n      node.setAttribute(\"cm-not-content\", \"true\");\n    }, function (pos, axis) {\n      if (axis == \"horizontal\") { setScrollLeft(cm, pos); }\n      else { updateScrollTop(cm, pos); }\n    }, cm);\n    if (cm.display.scrollbars.addClass)\n      { addClass(cm.display.wrapper, cm.display.scrollbars.addClass); }\n  }\n\n  // Operations are used to wrap a series of changes to the editor\n  // state in such a way that each change won't have to update the\n  // cursor and display (which would be awkward, slow, and\n  // error-prone). Instead, display updates are batched and then all\n  // combined and executed at once.\n\n  var nextOpId = 0;\n  // Start a new operation.\n  function startOperation(cm) {\n    cm.curOp = {\n      cm: cm,\n      viewChanged: false,      // Flag that indicates that lines might need to be redrawn\n      startHeight: cm.doc.height, // Used to detect need to update scrollbar\n      forceUpdate: false,      // Used to force a redraw\n      updateInput: null,       // Whether to reset the input textarea\n      typing: false,           // Whether this reset should be careful to leave existing text (for compositing)\n      changeObjs: null,        // Accumulated changes, for firing change events\n      cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on\n      cursorActivityCalled: 0, // Tracks which cursorActivity handlers have been called already\n      selectionChanged: false, // Whether the selection needs to be redrawn\n      updateMaxLine: false,    // Set when the widest line needs to be determined anew\n      scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet\n      scrollToPos: null,       // Used to scroll to a specific position\n      focus: false,\n      id: ++nextOpId           // Unique ID\n    };\n    pushOperation(cm.curOp);\n  }\n\n  // Finish an operation, updating the display and signalling delayed events\n  function endOperation(cm) {\n    var op = cm.curOp;\n    if (op) { finishOperation(op, function (group) {\n      for (var i = 0; i < group.ops.length; i++)\n        { group.ops[i].cm.curOp = null; }\n      endOperations(group);\n    }); }\n  }\n\n  // The DOM updates done when an operation finishes are batched so\n  // that the minimum number of relayouts are required.\n  function endOperations(group) {\n    var ops = group.ops;\n    for (var i = 0; i < ops.length; i++) // Read DOM\n      { endOperation_R1(ops[i]); }\n    for (var i$1 = 0; i$1 < ops.length; i$1++) // Write DOM (maybe)\n      { endOperation_W1(ops[i$1]); }\n    for (var i$2 = 0; i$2 < ops.length; i$2++) // Read DOM\n      { endOperation_R2(ops[i$2]); }\n    for (var i$3 = 0; i$3 < ops.length; i$3++) // Write DOM (maybe)\n      { endOperation_W2(ops[i$3]); }\n    for (var i$4 = 0; i$4 < ops.length; i$4++) // Read DOM\n      { endOperation_finish(ops[i$4]); }\n  }\n\n  function endOperation_R1(op) {\n    var cm = op.cm, display = cm.display;\n    maybeClipScrollbars(cm);\n    if (op.updateMaxLine) { findMaxLine(cm); }\n\n    op.mustUpdate = op.viewChanged || op.forceUpdate || op.scrollTop != null ||\n      op.scrollToPos && (op.scrollToPos.from.line < display.viewFrom ||\n                         op.scrollToPos.to.line >= display.viewTo) ||\n      display.maxLineChanged && cm.options.lineWrapping;\n    op.update = op.mustUpdate &&\n      new DisplayUpdate(cm, op.mustUpdate && {top: op.scrollTop, ensure: op.scrollToPos}, op.forceUpdate);\n  }\n\n  function endOperation_W1(op) {\n    op.updatedDisplay = op.mustUpdate && updateDisplayIfNeeded(op.cm, op.update);\n  }\n\n  function endOperation_R2(op) {\n    var cm = op.cm, display = cm.display;\n    if (op.updatedDisplay) { updateHeightsInViewport(cm); }\n\n    op.barMeasure = measureForScrollbars(cm);\n\n    // If the max line changed since it was last measured, measure it,\n    // and ensure the document's width matches it.\n    // updateDisplay_W2 will use these properties to do the actual resizing\n    if (display.maxLineChanged && !cm.options.lineWrapping) {\n      op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3;\n      cm.display.sizerWidth = op.adjustWidthTo;\n      op.barMeasure.scrollWidth =\n        Math.max(display.scroller.clientWidth, display.sizer.offsetLeft + op.adjustWidthTo + scrollGap(cm) + cm.display.barWidth);\n      op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo - displayWidth(cm));\n    }\n\n    if (op.updatedDisplay || op.selectionChanged)\n      { op.preparedSelection = display.input.prepareSelection(); }\n  }\n\n  function endOperation_W2(op) {\n    var cm = op.cm;\n\n    if (op.adjustWidthTo != null) {\n      cm.display.sizer.style.minWidth = op.adjustWidthTo + \"px\";\n      if (op.maxScrollLeft < cm.doc.scrollLeft)\n        { setScrollLeft(cm, Math.min(cm.display.scroller.scrollLeft, op.maxScrollLeft), true); }\n      cm.display.maxLineChanged = false;\n    }\n\n    var takeFocus = op.focus && op.focus == activeElt();\n    if (op.preparedSelection)\n      { cm.display.input.showSelection(op.preparedSelection, takeFocus); }\n    if (op.updatedDisplay || op.startHeight != cm.doc.height)\n      { updateScrollbars(cm, op.barMeasure); }\n    if (op.updatedDisplay)\n      { setDocumentHeight(cm, op.barMeasure); }\n\n    if (op.selectionChanged) { restartBlink(cm); }\n\n    if (cm.state.focused && op.updateInput)\n      { cm.display.input.reset(op.typing); }\n    if (takeFocus) { ensureFocus(op.cm); }\n  }\n\n  function endOperation_finish(op) {\n    var cm = op.cm, display = cm.display, doc = cm.doc;\n\n    if (op.updatedDisplay) { postUpdateDisplay(cm, op.update); }\n\n    // Abort mouse wheel delta measurement, when scrolling explicitly\n    if (display.wheelStartX != null && (op.scrollTop != null || op.scrollLeft != null || op.scrollToPos))\n      { display.wheelStartX = display.wheelStartY = null; }\n\n    // Propagate the scroll position to the actual DOM scroller\n    if (op.scrollTop != null) { setScrollTop(cm, op.scrollTop, op.forceScroll); }\n\n    if (op.scrollLeft != null) { setScrollLeft(cm, op.scrollLeft, true, true); }\n    // If we need to scroll a specific position into view, do so.\n    if (op.scrollToPos) {\n      var rect = scrollPosIntoView(cm, clipPos(doc, op.scrollToPos.from),\n                                   clipPos(doc, op.scrollToPos.to), op.scrollToPos.margin);\n      maybeScrollWindow(cm, rect);\n    }\n\n    // Fire events for markers that are hidden/unidden by editing or\n    // undoing\n    var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers;\n    if (hidden) { for (var i = 0; i < hidden.length; ++i)\n      { if (!hidden[i].lines.length) { signal(hidden[i], \"hide\"); } } }\n    if (unhidden) { for (var i$1 = 0; i$1 < unhidden.length; ++i$1)\n      { if (unhidden[i$1].lines.length) { signal(unhidden[i$1], \"unhide\"); } } }\n\n    if (display.wrapper.offsetHeight)\n      { doc.scrollTop = cm.display.scroller.scrollTop; }\n\n    // Fire change events, and delayed event handlers\n    if (op.changeObjs)\n      { signal(cm, \"changes\", cm, op.changeObjs); }\n    if (op.update)\n      { op.update.finish(); }\n  }\n\n  // Run the given function in an operation\n  function runInOp(cm, f) {\n    if (cm.curOp) { return f() }\n    startOperation(cm);\n    try { return f() }\n    finally { endOperation(cm); }\n  }\n  // Wraps a function in an operation. Returns the wrapped function.\n  function operation(cm, f) {\n    return function() {\n      if (cm.curOp) { return f.apply(cm, arguments) }\n      startOperation(cm);\n      try { return f.apply(cm, arguments) }\n      finally { endOperation(cm); }\n    }\n  }\n  // Used to add methods to editor and doc instances, wrapping them in\n  // operations.\n  function methodOp(f) {\n    return function() {\n      if (this.curOp) { return f.apply(this, arguments) }\n      startOperation(this);\n      try { return f.apply(this, arguments) }\n      finally { endOperation(this); }\n    }\n  }\n  function docMethodOp(f) {\n    return function() {\n      var cm = this.cm;\n      if (!cm || cm.curOp) { return f.apply(this, arguments) }\n      startOperation(cm);\n      try { return f.apply(this, arguments) }\n      finally { endOperation(cm); }\n    }\n  }\n\n  // Updates the display.view data structure for a given change to the\n  // document. From and to are in pre-change coordinates. Lendiff is\n  // the amount of lines added or subtracted by the change. This is\n  // used for changes that span multiple lines, or change the way\n  // lines are divided into visual lines. regLineChange (below)\n  // registers single-line changes.\n  function regChange(cm, from, to, lendiff) {\n    if (from == null) { from = cm.doc.first; }\n    if (to == null) { to = cm.doc.first + cm.doc.size; }\n    if (!lendiff) { lendiff = 0; }\n\n    var display = cm.display;\n    if (lendiff && to < display.viewTo &&\n        (display.updateLineNumbers == null || display.updateLineNumbers > from))\n      { display.updateLineNumbers = from; }\n\n    cm.curOp.viewChanged = true;\n\n    if (from >= display.viewTo) { // Change after\n      if (sawCollapsedSpans && visualLineNo(cm.doc, from) < display.viewTo)\n        { resetView(cm); }\n    } else if (to <= display.viewFrom) { // Change before\n      if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + lendiff) > display.viewFrom) {\n        resetView(cm);\n      } else {\n        display.viewFrom += lendiff;\n        display.viewTo += lendiff;\n      }\n    } else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap\n      resetView(cm);\n    } else if (from <= display.viewFrom) { // Top overlap\n      var cut = viewCuttingPoint(cm, to, to + lendiff, 1);\n      if (cut) {\n        display.view = display.view.slice(cut.index);\n        display.viewFrom = cut.lineN;\n        display.viewTo += lendiff;\n      } else {\n        resetView(cm);\n      }\n    } else if (to >= display.viewTo) { // Bottom overlap\n      var cut$1 = viewCuttingPoint(cm, from, from, -1);\n      if (cut$1) {\n        display.view = display.view.slice(0, cut$1.index);\n        display.viewTo = cut$1.lineN;\n      } else {\n        resetView(cm);\n      }\n    } else { // Gap in the middle\n      var cutTop = viewCuttingPoint(cm, from, from, -1);\n      var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1);\n      if (cutTop && cutBot) {\n        display.view = display.view.slice(0, cutTop.index)\n          .concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN))\n          .concat(display.view.slice(cutBot.index));\n        display.viewTo += lendiff;\n      } else {\n        resetView(cm);\n      }\n    }\n\n    var ext = display.externalMeasured;\n    if (ext) {\n      if (to < ext.lineN)\n        { ext.lineN += lendiff; }\n      else if (from < ext.lineN + ext.size)\n        { display.externalMeasured = null; }\n    }\n  }\n\n  // Register a change to a single line. Type must be one of \"text\",\n  // \"gutter\", \"class\", \"widget\"\n  function regLineChange(cm, line, type) {\n    cm.curOp.viewChanged = true;\n    var display = cm.display, ext = cm.display.externalMeasured;\n    if (ext && line >= ext.lineN && line < ext.lineN + ext.size)\n      { display.externalMeasured = null; }\n\n    if (line < display.viewFrom || line >= display.viewTo) { return }\n    var lineView = display.view[findViewIndex(cm, line)];\n    if (lineView.node == null) { return }\n    var arr = lineView.changes || (lineView.changes = []);\n    if (indexOf(arr, type) == -1) { arr.push(type); }\n  }\n\n  // Clear the view.\n  function resetView(cm) {\n    cm.display.viewFrom = cm.display.viewTo = cm.doc.first;\n    cm.display.view = [];\n    cm.display.viewOffset = 0;\n  }\n\n  function viewCuttingPoint(cm, oldN, newN, dir) {\n    var index = findViewIndex(cm, oldN), diff, view = cm.display.view;\n    if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size)\n      { return {index: index, lineN: newN} }\n    var n = cm.display.viewFrom;\n    for (var i = 0; i < index; i++)\n      { n += view[i].size; }\n    if (n != oldN) {\n      if (dir > 0) {\n        if (index == view.length - 1) { return null }\n        diff = (n + view[index].size) - oldN;\n        index++;\n      } else {\n        diff = n - oldN;\n      }\n      oldN += diff; newN += diff;\n    }\n    while (visualLineNo(cm.doc, newN) != newN) {\n      if (index == (dir < 0 ? 0 : view.length - 1)) { return null }\n      newN += dir * view[index - (dir < 0 ? 1 : 0)].size;\n      index += dir;\n    }\n    return {index: index, lineN: newN}\n  }\n\n  // Force the view to cover a given range, adding empty view element\n  // or clipping off existing ones as needed.\n  function adjustView(cm, from, to) {\n    var display = cm.display, view = display.view;\n    if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) {\n      display.view = buildViewArray(cm, from, to);\n      display.viewFrom = from;\n    } else {\n      if (display.viewFrom > from)\n        { display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view); }\n      else if (display.viewFrom < from)\n        { display.view = display.view.slice(findViewIndex(cm, from)); }\n      display.viewFrom = from;\n      if (display.viewTo < to)\n        { display.view = display.view.concat(buildViewArray(cm, display.viewTo, to)); }\n      else if (display.viewTo > to)\n        { display.view = display.view.slice(0, findViewIndex(cm, to)); }\n    }\n    display.viewTo = to;\n  }\n\n  // Count the number of lines in the view whose DOM representation is\n  // out of date (or nonexistent).\n  function countDirtyView(cm) {\n    var view = cm.display.view, dirty = 0;\n    for (var i = 0; i < view.length; i++) {\n      var lineView = view[i];\n      if (!lineView.hidden && (!lineView.node || lineView.changes)) { ++dirty; }\n    }\n    return dirty\n  }\n\n  // HIGHLIGHT WORKER\n\n  function startWorker(cm, time) {\n    if (cm.doc.highlightFrontier < cm.display.viewTo)\n      { cm.state.highlight.set(time, bind(highlightWorker, cm)); }\n  }\n\n  function highlightWorker(cm) {\n    var doc = cm.doc;\n    if (doc.highlightFrontier >= cm.display.viewTo) { return }\n    var end = +new Date + cm.options.workTime;\n    var context = getContextBefore(cm, doc.highlightFrontier);\n    var changedLines = [];\n\n    doc.iter(context.line, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function (line) {\n      if (context.line >= cm.display.viewFrom) { // Visible\n        var oldStyles = line.styles;\n        var resetState = line.text.length > cm.options.maxHighlightLength ? copyState(doc.mode, context.state) : null;\n        var highlighted = highlightLine(cm, line, context, true);\n        if (resetState) { context.state = resetState; }\n        line.styles = highlighted.styles;\n        var oldCls = line.styleClasses, newCls = highlighted.classes;\n        if (newCls) { line.styleClasses = newCls; }\n        else if (oldCls) { line.styleClasses = null; }\n        var ischange = !oldStyles || oldStyles.length != line.styles.length ||\n          oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass);\n        for (var i = 0; !ischange && i < oldStyles.length; ++i) { ischange = oldStyles[i] != line.styles[i]; }\n        if (ischange) { changedLines.push(context.line); }\n        line.stateAfter = context.save();\n        context.nextLine();\n      } else {\n        if (line.text.length <= cm.options.maxHighlightLength)\n          { processLine(cm, line.text, context); }\n        line.stateAfter = context.line % 5 == 0 ? context.save() : null;\n        context.nextLine();\n      }\n      if (+new Date > end) {\n        startWorker(cm, cm.options.workDelay);\n        return true\n      }\n    });\n    doc.highlightFrontier = context.line;\n    doc.modeFrontier = Math.max(doc.modeFrontier, context.line);\n    if (changedLines.length) { runInOp(cm, function () {\n      for (var i = 0; i < changedLines.length; i++)\n        { regLineChange(cm, changedLines[i], \"text\"); }\n    }); }\n  }\n\n  // DISPLAY DRAWING\n\n  var DisplayUpdate = function(cm, viewport, force) {\n    var display = cm.display;\n\n    this.viewport = viewport;\n    // Store some values that we'll need later (but don't want to force a relayout for)\n    this.visible = visibleLines(display, cm.doc, viewport);\n    this.editorIsHidden = !display.wrapper.offsetWidth;\n    this.wrapperHeight = display.wrapper.clientHeight;\n    this.wrapperWidth = display.wrapper.clientWidth;\n    this.oldDisplayWidth = displayWidth(cm);\n    this.force = force;\n    this.dims = getDimensions(cm);\n    this.events = [];\n  };\n\n  DisplayUpdate.prototype.signal = function (emitter, type) {\n    if (hasHandler(emitter, type))\n      { this.events.push(arguments); }\n  };\n  DisplayUpdate.prototype.finish = function () {\n      var this$1 = this;\n\n    for (var i = 0; i < this.events.length; i++)\n      { signal.apply(null, this$1.events[i]); }\n  };\n\n  function maybeClipScrollbars(cm) {\n    var display = cm.display;\n    if (!display.scrollbarsClipped && display.scroller.offsetWidth) {\n      display.nativeBarWidth = display.scroller.offsetWidth - display.scroller.clientWidth;\n      display.heightForcer.style.height = scrollGap(cm) + \"px\";\n      display.sizer.style.marginBottom = -display.nativeBarWidth + \"px\";\n      display.sizer.style.borderRightWidth = scrollGap(cm) + \"px\";\n      display.scrollbarsClipped = true;\n    }\n  }\n\n  function selectionSnapshot(cm) {\n    if (cm.hasFocus()) { return null }\n    var active = activeElt();\n    if (!active || !contains(cm.display.lineDiv, active)) { return null }\n    var result = {activeElt: active};\n    if (window.getSelection) {\n      var sel = window.getSelection();\n      if (sel.anchorNode && sel.extend && contains(cm.display.lineDiv, sel.anchorNode)) {\n        result.anchorNode = sel.anchorNode;\n        result.anchorOffset = sel.anchorOffset;\n        result.focusNode = sel.focusNode;\n        result.focusOffset = sel.focusOffset;\n      }\n    }\n    return result\n  }\n\n  function restoreSelection(snapshot) {\n    if (!snapshot || !snapshot.activeElt || snapshot.activeElt == activeElt()) { return }\n    snapshot.activeElt.focus();\n    if (snapshot.anchorNode && contains(document.body, snapshot.anchorNode) && contains(document.body, snapshot.focusNode)) {\n      var sel = window.getSelection(), range$$1 = document.createRange();\n      range$$1.setEnd(snapshot.anchorNode, snapshot.anchorOffset);\n      range$$1.collapse(false);\n      sel.removeAllRanges();\n      sel.addRange(range$$1);\n      sel.extend(snapshot.focusNode, snapshot.focusOffset);\n    }\n  }\n\n  // Does the actual updating of the line display. Bails out\n  // (returning false) when there is nothing to be done and forced is\n  // false.\n  function updateDisplayIfNeeded(cm, update) {\n    var display = cm.display, doc = cm.doc;\n\n    if (update.editorIsHidden) {\n      resetView(cm);\n      return false\n    }\n\n    // Bail out if the visible area is already rendered and nothing changed.\n    if (!update.force &&\n        update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo &&\n        (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) &&\n        display.renderedView == display.view && countDirtyView(cm) == 0)\n      { return false }\n\n    if (maybeUpdateLineNumberWidth(cm)) {\n      resetView(cm);\n      update.dims = getDimensions(cm);\n    }\n\n    // Compute a suitable new viewport (from & to)\n    var end = doc.first + doc.size;\n    var from = Math.max(update.visible.from - cm.options.viewportMargin, doc.first);\n    var to = Math.min(end, update.visible.to + cm.options.viewportMargin);\n    if (display.viewFrom < from && from - display.viewFrom < 20) { from = Math.max(doc.first, display.viewFrom); }\n    if (display.viewTo > to && display.viewTo - to < 20) { to = Math.min(end, display.viewTo); }\n    if (sawCollapsedSpans) {\n      from = visualLineNo(cm.doc, from);\n      to = visualLineEndNo(cm.doc, to);\n    }\n\n    var different = from != display.viewFrom || to != display.viewTo ||\n      display.lastWrapHeight != update.wrapperHeight || display.lastWrapWidth != update.wrapperWidth;\n    adjustView(cm, from, to);\n\n    display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom));\n    // Position the mover div to align with the current scroll position\n    cm.display.mover.style.top = display.viewOffset + \"px\";\n\n    var toUpdate = countDirtyView(cm);\n    if (!different && toUpdate == 0 && !update.force && display.renderedView == display.view &&\n        (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo))\n      { return false }\n\n    // For big changes, we hide the enclosing element during the\n    // update, since that speeds up the operations on most browsers.\n    var selSnapshot = selectionSnapshot(cm);\n    if (toUpdate > 4) { display.lineDiv.style.display = \"none\"; }\n    patchDisplay(cm, display.updateLineNumbers, update.dims);\n    if (toUpdate > 4) { display.lineDiv.style.display = \"\"; }\n    display.renderedView = display.view;\n    // There might have been a widget with a focused element that got\n    // hidden or updated, if so re-focus it.\n    restoreSelection(selSnapshot);\n\n    // Prevent selection and cursors from interfering with the scroll\n    // width and height.\n    removeChildren(display.cursorDiv);\n    removeChildren(display.selectionDiv);\n    display.gutters.style.height = display.sizer.style.minHeight = 0;\n\n    if (different) {\n      display.lastWrapHeight = update.wrapperHeight;\n      display.lastWrapWidth = update.wrapperWidth;\n      startWorker(cm, 400);\n    }\n\n    display.updateLineNumbers = null;\n\n    return true\n  }\n\n  function postUpdateDisplay(cm, update) {\n    var viewport = update.viewport;\n\n    for (var first = true;; first = false) {\n      if (!first || !cm.options.lineWrapping || update.oldDisplayWidth == displayWidth(cm)) {\n        // Clip forced viewport to actual scrollable area.\n        if (viewport && viewport.top != null)\n          { viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - displayHeight(cm), viewport.top)}; }\n        // Updated line heights might result in the drawn area not\n        // actually covering the viewport. Keep looping until it does.\n        update.visible = visibleLines(cm.display, cm.doc, viewport);\n        if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo)\n          { break }\n      }\n      if (!updateDisplayIfNeeded(cm, update)) { break }\n      updateHeightsInViewport(cm);\n      var barMeasure = measureForScrollbars(cm);\n      updateSelection(cm);\n      updateScrollbars(cm, barMeasure);\n      setDocumentHeight(cm, barMeasure);\n      update.force = false;\n    }\n\n    update.signal(cm, \"update\", cm);\n    if (cm.display.viewFrom != cm.display.reportedViewFrom || cm.display.viewTo != cm.display.reportedViewTo) {\n      update.signal(cm, \"viewportChange\", cm, cm.display.viewFrom, cm.display.viewTo);\n      cm.display.reportedViewFrom = cm.display.viewFrom; cm.display.reportedViewTo = cm.display.viewTo;\n    }\n  }\n\n  function updateDisplaySimple(cm, viewport) {\n    var update = new DisplayUpdate(cm, viewport);\n    if (updateDisplayIfNeeded(cm, update)) {\n      updateHeightsInViewport(cm);\n      postUpdateDisplay(cm, update);\n      var barMeasure = measureForScrollbars(cm);\n      updateSelection(cm);\n      updateScrollbars(cm, barMeasure);\n      setDocumentHeight(cm, barMeasure);\n      update.finish();\n    }\n  }\n\n  // Sync the actual display DOM structure with display.view, removing\n  // nodes for lines that are no longer in view, and creating the ones\n  // that are not there yet, and updating the ones that are out of\n  // date.\n  function patchDisplay(cm, updateNumbersFrom, dims) {\n    var display = cm.display, lineNumbers = cm.options.lineNumbers;\n    var container = display.lineDiv, cur = container.firstChild;\n\n    function rm(node) {\n      var next = node.nextSibling;\n      // Works around a throw-scroll bug in OS X Webkit\n      if (webkit && mac && cm.display.currentWheelTarget == node)\n        { node.style.display = \"none\"; }\n      else\n        { node.parentNode.removeChild(node); }\n      return next\n    }\n\n    var view = display.view, lineN = display.viewFrom;\n    // Loop over the elements in the view, syncing cur (the DOM nodes\n    // in display.lineDiv) with the view as we go.\n    for (var i = 0; i < view.length; i++) {\n      var lineView = view[i];\n      if (lineView.hidden) ; else if (!lineView.node || lineView.node.parentNode != container) { // Not drawn yet\n        var node = buildLineElement(cm, lineView, lineN, dims);\n        container.insertBefore(node, cur);\n      } else { // Already drawn\n        while (cur != lineView.node) { cur = rm(cur); }\n        var updateNumber = lineNumbers && updateNumbersFrom != null &&\n          updateNumbersFrom <= lineN && lineView.lineNumber;\n        if (lineView.changes) {\n          if (indexOf(lineView.changes, \"gutter\") > -1) { updateNumber = false; }\n          updateLineForChanges(cm, lineView, lineN, dims);\n        }\n        if (updateNumber) {\n          removeChildren(lineView.lineNumber);\n          lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options, lineN)));\n        }\n        cur = lineView.node.nextSibling;\n      }\n      lineN += lineView.size;\n    }\n    while (cur) { cur = rm(cur); }\n  }\n\n  function updateGutterSpace(cm) {\n    var width = cm.display.gutters.offsetWidth;\n    cm.display.sizer.style.marginLeft = width + \"px\";\n  }\n\n  function setDocumentHeight(cm, measure) {\n    cm.display.sizer.style.minHeight = measure.docHeight + \"px\";\n    cm.display.heightForcer.style.top = measure.docHeight + \"px\";\n    cm.display.gutters.style.height = (measure.docHeight + cm.display.barHeight + scrollGap(cm)) + \"px\";\n  }\n\n  // Rebuild the gutter elements, ensure the margin to the left of the\n  // code matches their width.\n  function updateGutters(cm) {\n    var gutters = cm.display.gutters, specs = cm.options.gutters;\n    removeChildren(gutters);\n    var i = 0;\n    for (; i < specs.length; ++i) {\n      var gutterClass = specs[i];\n      var gElt = gutters.appendChild(elt(\"div\", null, \"CodeMirror-gutter \" + gutterClass));\n      if (gutterClass == \"CodeMirror-linenumbers\") {\n        cm.display.lineGutter = gElt;\n        gElt.style.width = (cm.display.lineNumWidth || 1) + \"px\";\n      }\n    }\n    gutters.style.display = i ? \"\" : \"none\";\n    updateGutterSpace(cm);\n  }\n\n  // Make sure the gutters options contains the element\n  // \"CodeMirror-linenumbers\" when the lineNumbers option is true.\n  function setGuttersForLineNumbers(options) {\n    var found = indexOf(options.gutters, \"CodeMirror-linenumbers\");\n    if (found == -1 && options.lineNumbers) {\n      options.gutters = options.gutters.concat([\"CodeMirror-linenumbers\"]);\n    } else if (found > -1 && !options.lineNumbers) {\n      options.gutters = options.gutters.slice(0);\n      options.gutters.splice(found, 1);\n    }\n  }\n\n  // Since the delta values reported on mouse wheel events are\n  // unstandardized between browsers and even browser versions, and\n  // generally horribly unpredictable, this code starts by measuring\n  // the scroll effect that the first few mouse wheel events have,\n  // and, from that, detects the way it can convert deltas to pixel\n  // offsets afterwards.\n  //\n  // The reason we want to know the amount a wheel event will scroll\n  // is that it gives us a chance to update the display before the\n  // actual scrolling happens, reducing flickering.\n\n  var wheelSamples = 0, wheelPixelsPerUnit = null;\n  // Fill in a browser-detected starting value on browsers where we\n  // know one. These don't have to be accurate -- the result of them\n  // being wrong would just be a slight flicker on the first wheel\n  // scroll (if it is large enough).\n  if (ie) { wheelPixelsPerUnit = -.53; }\n  else if (gecko) { wheelPixelsPerUnit = 15; }\n  else if (chrome) { wheelPixelsPerUnit = -.7; }\n  else if (safari) { wheelPixelsPerUnit = -1/3; }\n\n  function wheelEventDelta(e) {\n    var dx = e.wheelDeltaX, dy = e.wheelDeltaY;\n    if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) { dx = e.detail; }\n    if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) { dy = e.detail; }\n    else if (dy == null) { dy = e.wheelDelta; }\n    return {x: dx, y: dy}\n  }\n  function wheelEventPixels(e) {\n    var delta = wheelEventDelta(e);\n    delta.x *= wheelPixelsPerUnit;\n    delta.y *= wheelPixelsPerUnit;\n    return delta\n  }\n\n  function onScrollWheel(cm, e) {\n    var delta = wheelEventDelta(e), dx = delta.x, dy = delta.y;\n\n    var display = cm.display, scroll = display.scroller;\n    // Quit if there's nothing to scroll here\n    var canScrollX = scroll.scrollWidth > scroll.clientWidth;\n    var canScrollY = scroll.scrollHeight > scroll.clientHeight;\n    if (!(dx && canScrollX || dy && canScrollY)) { return }\n\n    // Webkit browsers on OS X abort momentum scrolls when the target\n    // of the scroll event is removed from the scrollable element.\n    // This hack (see related code in patchDisplay) makes sure the\n    // element is kept around.\n    if (dy && mac && webkit) {\n      outer: for (var cur = e.target, view = display.view; cur != scroll; cur = cur.parentNode) {\n        for (var i = 0; i < view.length; i++) {\n          if (view[i].node == cur) {\n            cm.display.currentWheelTarget = cur;\n            break outer\n          }\n        }\n      }\n    }\n\n    // On some browsers, horizontal scrolling will cause redraws to\n    // happen before the gutter has been realigned, causing it to\n    // wriggle around in a most unseemly way. When we have an\n    // estimated pixels/delta value, we just handle horizontal\n    // scrolling entirely here. It'll be slightly off from native, but\n    // better than glitching out.\n    if (dx && !gecko && !presto && wheelPixelsPerUnit != null) {\n      if (dy && canScrollY)\n        { updateScrollTop(cm, Math.max(0, scroll.scrollTop + dy * wheelPixelsPerUnit)); }\n      setScrollLeft(cm, Math.max(0, scroll.scrollLeft + dx * wheelPixelsPerUnit));\n      // Only prevent default scrolling if vertical scrolling is\n      // actually possible. Otherwise, it causes vertical scroll\n      // jitter on OSX trackpads when deltaX is small and deltaY\n      // is large (issue #3579)\n      if (!dy || (dy && canScrollY))\n        { e_preventDefault(e); }\n      display.wheelStartX = null; // Abort measurement, if in progress\n      return\n    }\n\n    // 'Project' the visible viewport to cover the area that is being\n    // scrolled into view (if we know enough to estimate it).\n    if (dy && wheelPixelsPerUnit != null) {\n      var pixels = dy * wheelPixelsPerUnit;\n      var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight;\n      if (pixels < 0) { top = Math.max(0, top + pixels - 50); }\n      else { bot = Math.min(cm.doc.height, bot + pixels + 50); }\n      updateDisplaySimple(cm, {top: top, bottom: bot});\n    }\n\n    if (wheelSamples < 20) {\n      if (display.wheelStartX == null) {\n        display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop;\n        display.wheelDX = dx; display.wheelDY = dy;\n        setTimeout(function () {\n          if (display.wheelStartX == null) { return }\n          var movedX = scroll.scrollLeft - display.wheelStartX;\n          var movedY = scroll.scrollTop - display.wheelStartY;\n          var sample = (movedY && display.wheelDY && movedY / display.wheelDY) ||\n            (movedX && display.wheelDX && movedX / display.wheelDX);\n          display.wheelStartX = display.wheelStartY = null;\n          if (!sample) { return }\n          wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1);\n          ++wheelSamples;\n        }, 200);\n      } else {\n        display.wheelDX += dx; display.wheelDY += dy;\n      }\n    }\n  }\n\n  // Selection objects are immutable. A new one is created every time\n  // the selection changes. A selection is one or more non-overlapping\n  // (and non-touching) ranges, sorted, and an integer that indicates\n  // which one is the primary selection (the one that's scrolled into\n  // view, that getCursor returns, etc).\n  var Selection = function(ranges, primIndex) {\n    this.ranges = ranges;\n    this.primIndex = primIndex;\n  };\n\n  Selection.prototype.primary = function () { return this.ranges[this.primIndex] };\n\n  Selection.prototype.equals = function (other) {\n      var this$1 = this;\n\n    if (other == this) { return true }\n    if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) { return false }\n    for (var i = 0; i < this.ranges.length; i++) {\n      var here = this$1.ranges[i], there = other.ranges[i];\n      if (!equalCursorPos(here.anchor, there.anchor) || !equalCursorPos(here.head, there.head)) { return false }\n    }\n    return true\n  };\n\n  Selection.prototype.deepCopy = function () {\n      var this$1 = this;\n\n    var out = [];\n    for (var i = 0; i < this.ranges.length; i++)\n      { out[i] = new Range(copyPos(this$1.ranges[i].anchor), copyPos(this$1.ranges[i].head)); }\n    return new Selection(out, this.primIndex)\n  };\n\n  Selection.prototype.somethingSelected = function () {\n      var this$1 = this;\n\n    for (var i = 0; i < this.ranges.length; i++)\n      { if (!this$1.ranges[i].empty()) { return true } }\n    return false\n  };\n\n  Selection.prototype.contains = function (pos, end) {\n      var this$1 = this;\n\n    if (!end) { end = pos; }\n    for (var i = 0; i < this.ranges.length; i++) {\n      var range = this$1.ranges[i];\n      if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0)\n        { return i }\n    }\n    return -1\n  };\n\n  var Range = function(anchor, head) {\n    this.anchor = anchor; this.head = head;\n  };\n\n  Range.prototype.from = function () { return minPos(this.anchor, this.head) };\n  Range.prototype.to = function () { return maxPos(this.anchor, this.head) };\n  Range.prototype.empty = function () { return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch };\n\n  // Take an unsorted, potentially overlapping set of ranges, and\n  // build a selection out of it. 'Consumes' ranges array (modifying\n  // it).\n  function normalizeSelection(cm, ranges, primIndex) {\n    var mayTouch = cm && cm.options.selectionsMayTouch;\n    var prim = ranges[primIndex];\n    ranges.sort(function (a, b) { return cmp(a.from(), b.from()); });\n    primIndex = indexOf(ranges, prim);\n    for (var i = 1; i < ranges.length; i++) {\n      var cur = ranges[i], prev = ranges[i - 1];\n      var diff = cmp(prev.to(), cur.from());\n      if (mayTouch && !cur.empty() ? diff > 0 : diff >= 0) {\n        var from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to());\n        var inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head;\n        if (i <= primIndex) { --primIndex; }\n        ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to));\n      }\n    }\n    return new Selection(ranges, primIndex)\n  }\n\n  function simpleSelection(anchor, head) {\n    return new Selection([new Range(anchor, head || anchor)], 0)\n  }\n\n  // Compute the position of the end of a change (its 'to' property\n  // refers to the pre-change end).\n  function changeEnd(change) {\n    if (!change.text) { return change.to }\n    return Pos(change.from.line + change.text.length - 1,\n               lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0))\n  }\n\n  // Adjust a position to refer to the post-change position of the\n  // same text, or the end of the change if the change covers it.\n  function adjustForChange(pos, change) {\n    if (cmp(pos, change.from) < 0) { return pos }\n    if (cmp(pos, change.to) <= 0) { return changeEnd(change) }\n\n    var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch;\n    if (pos.line == change.to.line) { ch += changeEnd(change).ch - change.to.ch; }\n    return Pos(line, ch)\n  }\n\n  function computeSelAfterChange(doc, change) {\n    var out = [];\n    for (var i = 0; i < doc.sel.ranges.length; i++) {\n      var range = doc.sel.ranges[i];\n      out.push(new Range(adjustForChange(range.anchor, change),\n                         adjustForChange(range.head, change)));\n    }\n    return normalizeSelection(doc.cm, out, doc.sel.primIndex)\n  }\n\n  function offsetPos(pos, old, nw) {\n    if (pos.line == old.line)\n      { return Pos(nw.line, pos.ch - old.ch + nw.ch) }\n    else\n      { return Pos(nw.line + (pos.line - old.line), pos.ch) }\n  }\n\n  // Used by replaceSelections to allow moving the selection to the\n  // start or around the replaced test. Hint may be \"start\" or \"around\".\n  function computeReplacedSel(doc, changes, hint) {\n    var out = [];\n    var oldPrev = Pos(doc.first, 0), newPrev = oldPrev;\n    for (var i = 0; i < changes.length; i++) {\n      var change = changes[i];\n      var from = offsetPos(change.from, oldPrev, newPrev);\n      var to = offsetPos(changeEnd(change), oldPrev, newPrev);\n      oldPrev = change.to;\n      newPrev = to;\n      if (hint == \"around\") {\n        var range = doc.sel.ranges[i], inv = cmp(range.head, range.anchor) < 0;\n        out[i] = new Range(inv ? to : from, inv ? from : to);\n      } else {\n        out[i] = new Range(from, from);\n      }\n    }\n    return new Selection(out, doc.sel.primIndex)\n  }\n\n  // Used to get the editor into a consistent state again when options change.\n\n  function loadMode(cm) {\n    cm.doc.mode = getMode(cm.options, cm.doc.modeOption);\n    resetModeState(cm);\n  }\n\n  function resetModeState(cm) {\n    cm.doc.iter(function (line) {\n      if (line.stateAfter) { line.stateAfter = null; }\n      if (line.styles) { line.styles = null; }\n    });\n    cm.doc.modeFrontier = cm.doc.highlightFrontier = cm.doc.first;\n    startWorker(cm, 100);\n    cm.state.modeGen++;\n    if (cm.curOp) { regChange(cm); }\n  }\n\n  // DOCUMENT DATA STRUCTURE\n\n  // By default, updates that start and end at the beginning of a line\n  // are treated specially, in order to make the association of line\n  // widgets and marker elements with the text behave more intuitive.\n  function isWholeLineUpdate(doc, change) {\n    return change.from.ch == 0 && change.to.ch == 0 && lst(change.text) == \"\" &&\n      (!doc.cm || doc.cm.options.wholeLineUpdateBefore)\n  }\n\n  // Perform a change on the document data structure.\n  function updateDoc(doc, change, markedSpans, estimateHeight$$1) {\n    function spansFor(n) {return markedSpans ? markedSpans[n] : null}\n    function update(line, text, spans) {\n      updateLine(line, text, spans, estimateHeight$$1);\n      signalLater(line, \"change\", line, change);\n    }\n    function linesFor(start, end) {\n      var result = [];\n      for (var i = start; i < end; ++i)\n        { result.push(new Line(text[i], spansFor(i), estimateHeight$$1)); }\n      return result\n    }\n\n    var from = change.from, to = change.to, text = change.text;\n    var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line);\n    var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line;\n\n    // Adjust the line structure\n    if (change.full) {\n      doc.insert(0, linesFor(0, text.length));\n      doc.remove(text.length, doc.size - text.length);\n    } else if (isWholeLineUpdate(doc, change)) {\n      // This is a whole-line replace. Treated specially to make\n      // sure line objects move the way they are supposed to.\n      var added = linesFor(0, text.length - 1);\n      update(lastLine, lastLine.text, lastSpans);\n      if (nlines) { doc.remove(from.line, nlines); }\n      if (added.length) { doc.insert(from.line, added); }\n    } else if (firstLine == lastLine) {\n      if (text.length == 1) {\n        update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans);\n      } else {\n        var added$1 = linesFor(1, text.length - 1);\n        added$1.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight$$1));\n        update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));\n        doc.insert(from.line + 1, added$1);\n      }\n    } else if (text.length == 1) {\n      update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0));\n      doc.remove(from.line + 1, nlines);\n    } else {\n      update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));\n      update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans);\n      var added$2 = linesFor(1, text.length - 1);\n      if (nlines > 1) { doc.remove(from.line + 1, nlines - 1); }\n      doc.insert(from.line + 1, added$2);\n    }\n\n    signalLater(doc, \"change\", doc, change);\n  }\n\n  // Call f for all linked documents.\n  function linkedDocs(doc, f, sharedHistOnly) {\n    function propagate(doc, skip, sharedHist) {\n      if (doc.linked) { for (var i = 0; i < doc.linked.length; ++i) {\n        var rel = doc.linked[i];\n        if (rel.doc == skip) { continue }\n        var shared = sharedHist && rel.sharedHist;\n        if (sharedHistOnly && !shared) { continue }\n        f(rel.doc, shared);\n        propagate(rel.doc, doc, shared);\n      } }\n    }\n    propagate(doc, null, true);\n  }\n\n  // Attach a document to an editor.\n  function attachDoc(cm, doc) {\n    if (doc.cm) { throw new Error(\"This document is already in use.\") }\n    cm.doc = doc;\n    doc.cm = cm;\n    estimateLineHeights(cm);\n    loadMode(cm);\n    setDirectionClass(cm);\n    if (!cm.options.lineWrapping) { findMaxLine(cm); }\n    cm.options.mode = doc.modeOption;\n    regChange(cm);\n  }\n\n  function setDirectionClass(cm) {\n  (cm.doc.direction == \"rtl\" ? addClass : rmClass)(cm.display.lineDiv, \"CodeMirror-rtl\");\n  }\n\n  function directionChanged(cm) {\n    runInOp(cm, function () {\n      setDirectionClass(cm);\n      regChange(cm);\n    });\n  }\n\n  function History(startGen) {\n    // Arrays of change events and selections. Doing something adds an\n    // event to done and clears undo. Undoing moves events from done\n    // to undone, redoing moves them in the other direction.\n    this.done = []; this.undone = [];\n    this.undoDepth = Infinity;\n    // Used to track when changes can be merged into a single undo\n    // event\n    this.lastModTime = this.lastSelTime = 0;\n    this.lastOp = this.lastSelOp = null;\n    this.lastOrigin = this.lastSelOrigin = null;\n    // Used by the isClean() method\n    this.generation = this.maxGeneration = startGen || 1;\n  }\n\n  // Create a history change event from an updateDoc-style change\n  // object.\n  function historyChangeFromChange(doc, change) {\n    var histChange = {from: copyPos(change.from), to: changeEnd(change), text: getBetween(doc, change.from, change.to)};\n    attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);\n    linkedDocs(doc, function (doc) { return attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1); }, true);\n    return histChange\n  }\n\n  // Pop all selection events off the end of a history array. Stop at\n  // a change event.\n  function clearSelectionEvents(array) {\n    while (array.length) {\n      var last = lst(array);\n      if (last.ranges) { array.pop(); }\n      else { break }\n    }\n  }\n\n  // Find the top change event in the history. Pop off selection\n  // events that are in the way.\n  function lastChangeEvent(hist, force) {\n    if (force) {\n      clearSelectionEvents(hist.done);\n      return lst(hist.done)\n    } else if (hist.done.length && !lst(hist.done).ranges) {\n      return lst(hist.done)\n    } else if (hist.done.length > 1 && !hist.done[hist.done.length - 2].ranges) {\n      hist.done.pop();\n      return lst(hist.done)\n    }\n  }\n\n  // Register a change in the history. Merges changes that are within\n  // a single operation, or are close together with an origin that\n  // allows merging (starting with \"+\") into a single event.\n  function addChangeToHistory(doc, change, selAfter, opId) {\n    var hist = doc.history;\n    hist.undone.length = 0;\n    var time = +new Date, cur;\n    var last;\n\n    if ((hist.lastOp == opId ||\n         hist.lastOrigin == change.origin && change.origin &&\n         ((change.origin.charAt(0) == \"+\" && hist.lastModTime > time - (doc.cm ? doc.cm.options.historyEventDelay : 500)) ||\n          change.origin.charAt(0) == \"*\")) &&\n        (cur = lastChangeEvent(hist, hist.lastOp == opId))) {\n      // Merge this change into the last event\n      last = lst(cur.changes);\n      if (cmp(change.from, change.to) == 0 && cmp(change.from, last.to) == 0) {\n        // Optimized case for simple insertion -- don't want to add\n        // new changesets for every character typed\n        last.to = changeEnd(change);\n      } else {\n        // Add new sub-event\n        cur.changes.push(historyChangeFromChange(doc, change));\n      }\n    } else {\n      // Can not be merged, start a new event.\n      var before = lst(hist.done);\n      if (!before || !before.ranges)\n        { pushSelectionToHistory(doc.sel, hist.done); }\n      cur = {changes: [historyChangeFromChange(doc, change)],\n             generation: hist.generation};\n      hist.done.push(cur);\n      while (hist.done.length > hist.undoDepth) {\n        hist.done.shift();\n        if (!hist.done[0].ranges) { hist.done.shift(); }\n      }\n    }\n    hist.done.push(selAfter);\n    hist.generation = ++hist.maxGeneration;\n    hist.lastModTime = hist.lastSelTime = time;\n    hist.lastOp = hist.lastSelOp = opId;\n    hist.lastOrigin = hist.lastSelOrigin = change.origin;\n\n    if (!last) { signal(doc, \"historyAdded\"); }\n  }\n\n  function selectionEventCanBeMerged(doc, origin, prev, sel) {\n    var ch = origin.charAt(0);\n    return ch == \"*\" ||\n      ch == \"+\" &&\n      prev.ranges.length == sel.ranges.length &&\n      prev.somethingSelected() == sel.somethingSelected() &&\n      new Date - doc.history.lastSelTime <= (doc.cm ? doc.cm.options.historyEventDelay : 500)\n  }\n\n  // Called whenever the selection changes, sets the new selection as\n  // the pending selection in the history, and pushes the old pending\n  // selection into the 'done' array when it was significantly\n  // different (in number of selected ranges, emptiness, or time).\n  function addSelectionToHistory(doc, sel, opId, options) {\n    var hist = doc.history, origin = options && options.origin;\n\n    // A new event is started when the previous origin does not match\n    // the current, or the origins don't allow matching. Origins\n    // starting with * are always merged, those starting with + are\n    // merged when similar and close together in time.\n    if (opId == hist.lastSelOp ||\n        (origin && hist.lastSelOrigin == origin &&\n         (hist.lastModTime == hist.lastSelTime && hist.lastOrigin == origin ||\n          selectionEventCanBeMerged(doc, origin, lst(hist.done), sel))))\n      { hist.done[hist.done.length - 1] = sel; }\n    else\n      { pushSelectionToHistory(sel, hist.done); }\n\n    hist.lastSelTime = +new Date;\n    hist.lastSelOrigin = origin;\n    hist.lastSelOp = opId;\n    if (options && options.clearRedo !== false)\n      { clearSelectionEvents(hist.undone); }\n  }\n\n  function pushSelectionToHistory(sel, dest) {\n    var top = lst(dest);\n    if (!(top && top.ranges && top.equals(sel)))\n      { dest.push(sel); }\n  }\n\n  // Used to store marked span information in the history.\n  function attachLocalSpans(doc, change, from, to) {\n    var existing = change[\"spans_\" + doc.id], n = 0;\n    doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function (line) {\n      if (line.markedSpans)\n        { (existing || (existing = change[\"spans_\" + doc.id] = {}))[n] = line.markedSpans; }\n      ++n;\n    });\n  }\n\n  // When un/re-doing restores text containing marked spans, those\n  // that have been explicitly cleared should not be restored.\n  function removeClearedSpans(spans) {\n    if (!spans) { return null }\n    var out;\n    for (var i = 0; i < spans.length; ++i) {\n      if (spans[i].marker.explicitlyCleared) { if (!out) { out = spans.slice(0, i); } }\n      else if (out) { out.push(spans[i]); }\n    }\n    return !out ? spans : out.length ? out : null\n  }\n\n  // Retrieve and filter the old marked spans stored in a change event.\n  function getOldSpans(doc, change) {\n    var found = change[\"spans_\" + doc.id];\n    if (!found) { return null }\n    var nw = [];\n    for (var i = 0; i < change.text.length; ++i)\n      { nw.push(removeClearedSpans(found[i])); }\n    return nw\n  }\n\n  // Used for un/re-doing changes from the history. Combines the\n  // result of computing the existing spans with the set of spans that\n  // existed in the history (so that deleting around a span and then\n  // undoing brings back the span).\n  function mergeOldSpans(doc, change) {\n    var old = getOldSpans(doc, change);\n    var stretched = stretchSpansOverChange(doc, change);\n    if (!old) { return stretched }\n    if (!stretched) { return old }\n\n    for (var i = 0; i < old.length; ++i) {\n      var oldCur = old[i], stretchCur = stretched[i];\n      if (oldCur && stretchCur) {\n        spans: for (var j = 0; j < stretchCur.length; ++j) {\n          var span = stretchCur[j];\n          for (var k = 0; k < oldCur.length; ++k)\n            { if (oldCur[k].marker == span.marker) { continue spans } }\n          oldCur.push(span);\n        }\n      } else if (stretchCur) {\n        old[i] = stretchCur;\n      }\n    }\n    return old\n  }\n\n  // Used both to provide a JSON-safe object in .getHistory, and, when\n  // detaching a document, to split the history in two\n  function copyHistoryArray(events, newGroup, instantiateSel) {\n    var copy = [];\n    for (var i = 0; i < events.length; ++i) {\n      var event = events[i];\n      if (event.ranges) {\n        copy.push(instantiateSel ? Selection.prototype.deepCopy.call(event) : event);\n        continue\n      }\n      var changes = event.changes, newChanges = [];\n      copy.push({changes: newChanges});\n      for (var j = 0; j < changes.length; ++j) {\n        var change = changes[j], m = (void 0);\n        newChanges.push({from: change.from, to: change.to, text: change.text});\n        if (newGroup) { for (var prop in change) { if (m = prop.match(/^spans_(\\d+)$/)) {\n          if (indexOf(newGroup, Number(m[1])) > -1) {\n            lst(newChanges)[prop] = change[prop];\n            delete change[prop];\n          }\n        } } }\n      }\n    }\n    return copy\n  }\n\n  // The 'scroll' parameter given to many of these indicated whether\n  // the new cursor position should be scrolled into view after\n  // modifying the selection.\n\n  // If shift is held or the extend flag is set, extends a range to\n  // include a given position (and optionally a second position).\n  // Otherwise, simply returns the range between the given positions.\n  // Used for cursor motion and such.\n  function extendRange(range, head, other, extend) {\n    if (extend) {\n      var anchor = range.anchor;\n      if (other) {\n        var posBefore = cmp(head, anchor) < 0;\n        if (posBefore != (cmp(other, anchor) < 0)) {\n          anchor = head;\n          head = other;\n        } else if (posBefore != (cmp(head, other) < 0)) {\n          head = other;\n        }\n      }\n      return new Range(anchor, head)\n    } else {\n      return new Range(other || head, head)\n    }\n  }\n\n  // Extend the primary selection range, discard the rest.\n  function extendSelection(doc, head, other, options, extend) {\n    if (extend == null) { extend = doc.cm && (doc.cm.display.shift || doc.extend); }\n    setSelection(doc, new Selection([extendRange(doc.sel.primary(), head, other, extend)], 0), options);\n  }\n\n  // Extend all selections (pos is an array of selections with length\n  // equal the number of selections)\n  function extendSelections(doc, heads, options) {\n    var out = [];\n    var extend = doc.cm && (doc.cm.display.shift || doc.extend);\n    for (var i = 0; i < doc.sel.ranges.length; i++)\n      { out[i] = extendRange(doc.sel.ranges[i], heads[i], null, extend); }\n    var newSel = normalizeSelection(doc.cm, out, doc.sel.primIndex);\n    setSelection(doc, newSel, options);\n  }\n\n  // Updates a single range in the selection.\n  function replaceOneSelection(doc, i, range, options) {\n    var ranges = doc.sel.ranges.slice(0);\n    ranges[i] = range;\n    setSelection(doc, normalizeSelection(doc.cm, ranges, doc.sel.primIndex), options);\n  }\n\n  // Reset the selection to a single range.\n  function setSimpleSelection(doc, anchor, head, options) {\n    setSelection(doc, simpleSelection(anchor, head), options);\n  }\n\n  // Give beforeSelectionChange handlers a change to influence a\n  // selection update.\n  function filterSelectionChange(doc, sel, options) {\n    var obj = {\n      ranges: sel.ranges,\n      update: function(ranges) {\n        var this$1 = this;\n\n        this.ranges = [];\n        for (var i = 0; i < ranges.length; i++)\n          { this$1.ranges[i] = new Range(clipPos(doc, ranges[i].anchor),\n                                     clipPos(doc, ranges[i].head)); }\n      },\n      origin: options && options.origin\n    };\n    signal(doc, \"beforeSelectionChange\", doc, obj);\n    if (doc.cm) { signal(doc.cm, \"beforeSelectionChange\", doc.cm, obj); }\n    if (obj.ranges != sel.ranges) { return normalizeSelection(doc.cm, obj.ranges, obj.ranges.length - 1) }\n    else { return sel }\n  }\n\n  function setSelectionReplaceHistory(doc, sel, options) {\n    var done = doc.history.done, last = lst(done);\n    if (last && last.ranges) {\n      done[done.length - 1] = sel;\n      setSelectionNoUndo(doc, sel, options);\n    } else {\n      setSelection(doc, sel, options);\n    }\n  }\n\n  // Set a new selection.\n  function setSelection(doc, sel, options) {\n    setSelectionNoUndo(doc, sel, options);\n    addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options);\n  }\n\n  function setSelectionNoUndo(doc, sel, options) {\n    if (hasHandler(doc, \"beforeSelectionChange\") || doc.cm && hasHandler(doc.cm, \"beforeSelectionChange\"))\n      { sel = filterSelectionChange(doc, sel, options); }\n\n    var bias = options && options.bias ||\n      (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1);\n    setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true));\n\n    if (!(options && options.scroll === false) && doc.cm)\n      { ensureCursorVisible(doc.cm); }\n  }\n\n  function setSelectionInner(doc, sel) {\n    if (sel.equals(doc.sel)) { return }\n\n    doc.sel = sel;\n\n    if (doc.cm) {\n      doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged = true;\n      signalCursorActivity(doc.cm);\n    }\n    signalLater(doc, \"cursorActivity\", doc);\n  }\n\n  // Verify that the selection does not partially select any atomic\n  // marked ranges.\n  function reCheckSelection(doc) {\n    setSelectionInner(doc, skipAtomicInSelection(doc, doc.sel, null, false));\n  }\n\n  // Return a selection that does not partially select any atomic\n  // ranges.\n  function skipAtomicInSelection(doc, sel, bias, mayClear) {\n    var out;\n    for (var i = 0; i < sel.ranges.length; i++) {\n      var range = sel.ranges[i];\n      var old = sel.ranges.length == doc.sel.ranges.length && doc.sel.ranges[i];\n      var newAnchor = skipAtomic(doc, range.anchor, old && old.anchor, bias, mayClear);\n      var newHead = skipAtomic(doc, range.head, old && old.head, bias, mayClear);\n      if (out || newAnchor != range.anchor || newHead != range.head) {\n        if (!out) { out = sel.ranges.slice(0, i); }\n        out[i] = new Range(newAnchor, newHead);\n      }\n    }\n    return out ? normalizeSelection(doc.cm, out, sel.primIndex) : sel\n  }\n\n  function skipAtomicInner(doc, pos, oldPos, dir, mayClear) {\n    var line = getLine(doc, pos.line);\n    if (line.markedSpans) { for (var i = 0; i < line.markedSpans.length; ++i) {\n      var sp = line.markedSpans[i], m = sp.marker;\n      if ((sp.from == null || (m.inclusiveLeft ? sp.from <= pos.ch : sp.from < pos.ch)) &&\n          (sp.to == null || (m.inclusiveRight ? sp.to >= pos.ch : sp.to > pos.ch))) {\n        if (mayClear) {\n          signal(m, \"beforeCursorEnter\");\n          if (m.explicitlyCleared) {\n            if (!line.markedSpans) { break }\n            else {--i; continue}\n          }\n        }\n        if (!m.atomic) { continue }\n\n        if (oldPos) {\n          var near = m.find(dir < 0 ? 1 : -1), diff = (void 0);\n          if (dir < 0 ? m.inclusiveRight : m.inclusiveLeft)\n            { near = movePos(doc, near, -dir, near && near.line == pos.line ? line : null); }\n          if (near && near.line == pos.line && (diff = cmp(near, oldPos)) && (dir < 0 ? diff < 0 : diff > 0))\n            { return skipAtomicInner(doc, near, pos, dir, mayClear) }\n        }\n\n        var far = m.find(dir < 0 ? -1 : 1);\n        if (dir < 0 ? m.inclusiveLeft : m.inclusiveRight)\n          { far = movePos(doc, far, dir, far.line == pos.line ? line : null); }\n        return far ? skipAtomicInner(doc, far, pos, dir, mayClear) : null\n      }\n    } }\n    return pos\n  }\n\n  // Ensure a given position is not inside an atomic range.\n  function skipAtomic(doc, pos, oldPos, bias, mayClear) {\n    var dir = bias || 1;\n    var found = skipAtomicInner(doc, pos, oldPos, dir, mayClear) ||\n        (!mayClear && skipAtomicInner(doc, pos, oldPos, dir, true)) ||\n        skipAtomicInner(doc, pos, oldPos, -dir, mayClear) ||\n        (!mayClear && skipAtomicInner(doc, pos, oldPos, -dir, true));\n    if (!found) {\n      doc.cantEdit = true;\n      return Pos(doc.first, 0)\n    }\n    return found\n  }\n\n  function movePos(doc, pos, dir, line) {\n    if (dir < 0 && pos.ch == 0) {\n      if (pos.line > doc.first) { return clipPos(doc, Pos(pos.line - 1)) }\n      else { return null }\n    } else if (dir > 0 && pos.ch == (line || getLine(doc, pos.line)).text.length) {\n      if (pos.line < doc.first + doc.size - 1) { return Pos(pos.line + 1, 0) }\n      else { return null }\n    } else {\n      return new Pos(pos.line, pos.ch + dir)\n    }\n  }\n\n  function selectAll(cm) {\n    cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()), sel_dontScroll);\n  }\n\n  // UPDATING\n\n  // Allow \"beforeChange\" event handlers to influence a change\n  function filterChange(doc, change, update) {\n    var obj = {\n      canceled: false,\n      from: change.from,\n      to: change.to,\n      text: change.text,\n      origin: change.origin,\n      cancel: function () { return obj.canceled = true; }\n    };\n    if (update) { obj.update = function (from, to, text, origin) {\n      if (from) { obj.from = clipPos(doc, from); }\n      if (to) { obj.to = clipPos(doc, to); }\n      if (text) { obj.text = text; }\n      if (origin !== undefined) { obj.origin = origin; }\n    }; }\n    signal(doc, \"beforeChange\", doc, obj);\n    if (doc.cm) { signal(doc.cm, \"beforeChange\", doc.cm, obj); }\n\n    if (obj.canceled) { return null }\n    return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin}\n  }\n\n  // Apply a change to a document, and add it to the document's\n  // history, and propagating it to all linked documents.\n  function makeChange(doc, change, ignoreReadOnly) {\n    if (doc.cm) {\n      if (!doc.cm.curOp) { return operation(doc.cm, makeChange)(doc, change, ignoreReadOnly) }\n      if (doc.cm.state.suppressEdits) { return }\n    }\n\n    if (hasHandler(doc, \"beforeChange\") || doc.cm && hasHandler(doc.cm, \"beforeChange\")) {\n      change = filterChange(doc, change, true);\n      if (!change) { return }\n    }\n\n    // Possibly split or suppress the update based on the presence\n    // of read-only spans in its range.\n    var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to);\n    if (split) {\n      for (var i = split.length - 1; i >= 0; --i)\n        { makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [\"\"] : change.text, origin: change.origin}); }\n    } else {\n      makeChangeInner(doc, change);\n    }\n  }\n\n  function makeChangeInner(doc, change) {\n    if (change.text.length == 1 && change.text[0] == \"\" && cmp(change.from, change.to) == 0) { return }\n    var selAfter = computeSelAfterChange(doc, change);\n    addChangeToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN);\n\n    makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change));\n    var rebased = [];\n\n    linkedDocs(doc, function (doc, sharedHist) {\n      if (!sharedHist && indexOf(rebased, doc.history) == -1) {\n        rebaseHist(doc.history, change);\n        rebased.push(doc.history);\n      }\n      makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change));\n    });\n  }\n\n  // Revert a change stored in a document's history.\n  function makeChangeFromHistory(doc, type, allowSelectionOnly) {\n    var suppress = doc.cm && doc.cm.state.suppressEdits;\n    if (suppress && !allowSelectionOnly) { return }\n\n    var hist = doc.history, event, selAfter = doc.sel;\n    var source = type == \"undo\" ? hist.done : hist.undone, dest = type == \"undo\" ? hist.undone : hist.done;\n\n    // Verify that there is a useable event (so that ctrl-z won't\n    // needlessly clear selection events)\n    var i = 0;\n    for (; i < source.length; i++) {\n      event = source[i];\n      if (allowSelectionOnly ? event.ranges && !event.equals(doc.sel) : !event.ranges)\n        { break }\n    }\n    if (i == source.length) { return }\n    hist.lastOrigin = hist.lastSelOrigin = null;\n\n    for (;;) {\n      event = source.pop();\n      if (event.ranges) {\n        pushSelectionToHistory(event, dest);\n        if (allowSelectionOnly && !event.equals(doc.sel)) {\n          setSelection(doc, event, {clearRedo: false});\n          return\n        }\n        selAfter = event;\n      } else if (suppress) {\n        source.push(event);\n        return\n      } else { break }\n    }\n\n    // Build up a reverse change object to add to the opposite history\n    // stack (redo when undoing, and vice versa).\n    var antiChanges = [];\n    pushSelectionToHistory(selAfter, dest);\n    dest.push({changes: antiChanges, generation: hist.generation});\n    hist.generation = event.generation || ++hist.maxGeneration;\n\n    var filter = hasHandler(doc, \"beforeChange\") || doc.cm && hasHandler(doc.cm, \"beforeChange\");\n\n    var loop = function ( i ) {\n      var change = event.changes[i];\n      change.origin = type;\n      if (filter && !filterChange(doc, change, false)) {\n        source.length = 0;\n        return {}\n      }\n\n      antiChanges.push(historyChangeFromChange(doc, change));\n\n      var after = i ? computeSelAfterChange(doc, change) : lst(source);\n      makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change));\n      if (!i && doc.cm) { doc.cm.scrollIntoView({from: change.from, to: changeEnd(change)}); }\n      var rebased = [];\n\n      // Propagate to the linked documents\n      linkedDocs(doc, function (doc, sharedHist) {\n        if (!sharedHist && indexOf(rebased, doc.history) == -1) {\n          rebaseHist(doc.history, change);\n          rebased.push(doc.history);\n        }\n        makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change));\n      });\n    };\n\n    for (var i$1 = event.changes.length - 1; i$1 >= 0; --i$1) {\n      var returned = loop( i$1 );\n\n      if ( returned ) return returned.v;\n    }\n  }\n\n  // Sub-views need their line numbers shifted when text is added\n  // above or below them in the parent document.\n  function shiftDoc(doc, distance) {\n    if (distance == 0) { return }\n    doc.first += distance;\n    doc.sel = new Selection(map(doc.sel.ranges, function (range) { return new Range(\n      Pos(range.anchor.line + distance, range.anchor.ch),\n      Pos(range.head.line + distance, range.head.ch)\n    ); }), doc.sel.primIndex);\n    if (doc.cm) {\n      regChange(doc.cm, doc.first, doc.first - distance, distance);\n      for (var d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++)\n        { regLineChange(doc.cm, l, \"gutter\"); }\n    }\n  }\n\n  // More lower-level change function, handling only a single document\n  // (not linked ones).\n  function makeChangeSingleDoc(doc, change, selAfter, spans) {\n    if (doc.cm && !doc.cm.curOp)\n      { return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans) }\n\n    if (change.to.line < doc.first) {\n      shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line));\n      return\n    }\n    if (change.from.line > doc.lastLine()) { return }\n\n    // Clip the change to the size of this doc\n    if (change.from.line < doc.first) {\n      var shift = change.text.length - 1 - (doc.first - change.from.line);\n      shiftDoc(doc, shift);\n      change = {from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch),\n                text: [lst(change.text)], origin: change.origin};\n    }\n    var last = doc.lastLine();\n    if (change.to.line > last) {\n      change = {from: change.from, to: Pos(last, getLine(doc, last).text.length),\n                text: [change.text[0]], origin: change.origin};\n    }\n\n    change.removed = getBetween(doc, change.from, change.to);\n\n    if (!selAfter) { selAfter = computeSelAfterChange(doc, change); }\n    if (doc.cm) { makeChangeSingleDocInEditor(doc.cm, change, spans); }\n    else { updateDoc(doc, change, spans); }\n    setSelectionNoUndo(doc, selAfter, sel_dontScroll);\n  }\n\n  // Handle the interaction of a change to a document with the editor\n  // that this document is part of.\n  function makeChangeSingleDocInEditor(cm, change, spans) {\n    var doc = cm.doc, display = cm.display, from = change.from, to = change.to;\n\n    var recomputeMaxLength = false, checkWidthStart = from.line;\n    if (!cm.options.lineWrapping) {\n      checkWidthStart = lineNo(visualLine(getLine(doc, from.line)));\n      doc.iter(checkWidthStart, to.line + 1, function (line) {\n        if (line == display.maxLine) {\n          recomputeMaxLength = true;\n          return true\n        }\n      });\n    }\n\n    if (doc.sel.contains(change.from, change.to) > -1)\n      { signalCursorActivity(cm); }\n\n    updateDoc(doc, change, spans, estimateHeight(cm));\n\n    if (!cm.options.lineWrapping) {\n      doc.iter(checkWidthStart, from.line + change.text.length, function (line) {\n        var len = lineLength(line);\n        if (len > display.maxLineLength) {\n          display.maxLine = line;\n          display.maxLineLength = len;\n          display.maxLineChanged = true;\n          recomputeMaxLength = false;\n        }\n      });\n      if (recomputeMaxLength) { cm.curOp.updateMaxLine = true; }\n    }\n\n    retreatFrontier(doc, from.line);\n    startWorker(cm, 400);\n\n    var lendiff = change.text.length - (to.line - from.line) - 1;\n    // Remember that these lines changed, for updating the display\n    if (change.full)\n      { regChange(cm); }\n    else if (from.line == to.line && change.text.length == 1 && !isWholeLineUpdate(cm.doc, change))\n      { regLineChange(cm, from.line, \"text\"); }\n    else\n      { regChange(cm, from.line, to.line + 1, lendiff); }\n\n    var changesHandler = hasHandler(cm, \"changes\"), changeHandler = hasHandler(cm, \"change\");\n    if (changeHandler || changesHandler) {\n      var obj = {\n        from: from, to: to,\n        text: change.text,\n        removed: change.removed,\n        origin: change.origin\n      };\n      if (changeHandler) { signalLater(cm, \"change\", cm, obj); }\n      if (changesHandler) { (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj); }\n    }\n    cm.display.selForContextMenu = null;\n  }\n\n  function replaceRange(doc, code, from, to, origin) {\n    var assign;\n\n    if (!to) { to = from; }\n    if (cmp(to, from) < 0) { (assign = [to, from], from = assign[0], to = assign[1]); }\n    if (typeof code == \"string\") { code = doc.splitLines(code); }\n    makeChange(doc, {from: from, to: to, text: code, origin: origin});\n  }\n\n  // Rebasing/resetting history to deal with externally-sourced changes\n\n  function rebaseHistSelSingle(pos, from, to, diff) {\n    if (to < pos.line) {\n      pos.line += diff;\n    } else if (from < pos.line) {\n      pos.line = from;\n      pos.ch = 0;\n    }\n  }\n\n  // Tries to rebase an array of history events given a change in the\n  // document. If the change touches the same lines as the event, the\n  // event, and everything 'behind' it, is discarded. If the change is\n  // before the event, the event's positions are updated. Uses a\n  // copy-on-write scheme for the positions, to avoid having to\n  // reallocate them all on every rebase, but also avoid problems with\n  // shared position objects being unsafely updated.\n  function rebaseHistArray(array, from, to, diff) {\n    for (var i = 0; i < array.length; ++i) {\n      var sub = array[i], ok = true;\n      if (sub.ranges) {\n        if (!sub.copied) { sub = array[i] = sub.deepCopy(); sub.copied = true; }\n        for (var j = 0; j < sub.ranges.length; j++) {\n          rebaseHistSelSingle(sub.ranges[j].anchor, from, to, diff);\n          rebaseHistSelSingle(sub.ranges[j].head, from, to, diff);\n        }\n        continue\n      }\n      for (var j$1 = 0; j$1 < sub.changes.length; ++j$1) {\n        var cur = sub.changes[j$1];\n        if (to < cur.from.line) {\n          cur.from = Pos(cur.from.line + diff, cur.from.ch);\n          cur.to = Pos(cur.to.line + diff, cur.to.ch);\n        } else if (from <= cur.to.line) {\n          ok = false;\n          break\n        }\n      }\n      if (!ok) {\n        array.splice(0, i + 1);\n        i = 0;\n      }\n    }\n  }\n\n  function rebaseHist(hist, change) {\n    var from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1;\n    rebaseHistArray(hist.done, from, to, diff);\n    rebaseHistArray(hist.undone, from, to, diff);\n  }\n\n  // Utility for applying a change to a line by handle or number,\n  // returning the number and optionally registering the line as\n  // changed.\n  function changeLine(doc, handle, changeType, op) {\n    var no = handle, line = handle;\n    if (typeof handle == \"number\") { line = getLine(doc, clipLine(doc, handle)); }\n    else { no = lineNo(handle); }\n    if (no == null) { return null }\n    if (op(line, no) && doc.cm) { regLineChange(doc.cm, no, changeType); }\n    return line\n  }\n\n  // The document is represented as a BTree consisting of leaves, with\n  // chunk of lines in them, and branches, with up to ten leaves or\n  // other branch nodes below them. The top node is always a branch\n  // node, and is the document object itself (meaning it has\n  // additional methods and properties).\n  //\n  // All nodes have parent links. The tree is used both to go from\n  // line numbers to line objects, and to go from objects to numbers.\n  // It also indexes by height, and is used to convert between height\n  // and line object, and to find the total height of the document.\n  //\n  // See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html\n\n  function LeafChunk(lines) {\n    var this$1 = this;\n\n    this.lines = lines;\n    this.parent = null;\n    var height = 0;\n    for (var i = 0; i < lines.length; ++i) {\n      lines[i].parent = this$1;\n      height += lines[i].height;\n    }\n    this.height = height;\n  }\n\n  LeafChunk.prototype = {\n    chunkSize: function() { return this.lines.length },\n\n    // Remove the n lines at offset 'at'.\n    removeInner: function(at, n) {\n      var this$1 = this;\n\n      for (var i = at, e = at + n; i < e; ++i) {\n        var line = this$1.lines[i];\n        this$1.height -= line.height;\n        cleanUpLine(line);\n        signalLater(line, \"delete\");\n      }\n      this.lines.splice(at, n);\n    },\n\n    // Helper used to collapse a small branch into a single leaf.\n    collapse: function(lines) {\n      lines.push.apply(lines, this.lines);\n    },\n\n    // Insert the given array of lines at offset 'at', count them as\n    // having the given height.\n    insertInner: function(at, lines, height) {\n      var this$1 = this;\n\n      this.height += height;\n      this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at));\n      for (var i = 0; i < lines.length; ++i) { lines[i].parent = this$1; }\n    },\n\n    // Used to iterate over a part of the tree.\n    iterN: function(at, n, op) {\n      var this$1 = this;\n\n      for (var e = at + n; at < e; ++at)\n        { if (op(this$1.lines[at])) { return true } }\n    }\n  };\n\n  function BranchChunk(children) {\n    var this$1 = this;\n\n    this.children = children;\n    var size = 0, height = 0;\n    for (var i = 0; i < children.length; ++i) {\n      var ch = children[i];\n      size += ch.chunkSize(); height += ch.height;\n      ch.parent = this$1;\n    }\n    this.size = size;\n    this.height = height;\n    this.parent = null;\n  }\n\n  BranchChunk.prototype = {\n    chunkSize: function() { return this.size },\n\n    removeInner: function(at, n) {\n      var this$1 = this;\n\n      this.size -= n;\n      for (var i = 0; i < this.children.length; ++i) {\n        var child = this$1.children[i], sz = child.chunkSize();\n        if (at < sz) {\n          var rm = Math.min(n, sz - at), oldHeight = child.height;\n          child.removeInner(at, rm);\n          this$1.height -= oldHeight - child.height;\n          if (sz == rm) { this$1.children.splice(i--, 1); child.parent = null; }\n          if ((n -= rm) == 0) { break }\n          at = 0;\n        } else { at -= sz; }\n      }\n      // If the result is smaller than 25 lines, ensure that it is a\n      // single leaf node.\n      if (this.size - n < 25 &&\n          (this.children.length > 1 || !(this.children[0] instanceof LeafChunk))) {\n        var lines = [];\n        this.collapse(lines);\n        this.children = [new LeafChunk(lines)];\n        this.children[0].parent = this;\n      }\n    },\n\n    collapse: function(lines) {\n      var this$1 = this;\n\n      for (var i = 0; i < this.children.length; ++i) { this$1.children[i].collapse(lines); }\n    },\n\n    insertInner: function(at, lines, height) {\n      var this$1 = this;\n\n      this.size += lines.length;\n      this.height += height;\n      for (var i = 0; i < this.children.length; ++i) {\n        var child = this$1.children[i], sz = child.chunkSize();\n        if (at <= sz) {\n          child.insertInner(at, lines, height);\n          if (child.lines && child.lines.length > 50) {\n            // To avoid memory thrashing when child.lines is huge (e.g. first view of a large file), it's never spliced.\n            // Instead, small slices are taken. They're taken in order because sequential memory accesses are fastest.\n            var remaining = child.lines.length % 25 + 25;\n            for (var pos = remaining; pos < child.lines.length;) {\n              var leaf = new LeafChunk(child.lines.slice(pos, pos += 25));\n              child.height -= leaf.height;\n              this$1.children.splice(++i, 0, leaf);\n              leaf.parent = this$1;\n            }\n            child.lines = child.lines.slice(0, remaining);\n            this$1.maybeSpill();\n          }\n          break\n        }\n        at -= sz;\n      }\n    },\n\n    // When a node has grown, check whether it should be split.\n    maybeSpill: function() {\n      if (this.children.length <= 10) { return }\n      var me = this;\n      do {\n        var spilled = me.children.splice(me.children.length - 5, 5);\n        var sibling = new BranchChunk(spilled);\n        if (!me.parent) { // Become the parent node\n          var copy = new BranchChunk(me.children);\n          copy.parent = me;\n          me.children = [copy, sibling];\n          me = copy;\n       } else {\n          me.size -= sibling.size;\n          me.height -= sibling.height;\n          var myIndex = indexOf(me.parent.children, me);\n          me.parent.children.splice(myIndex + 1, 0, sibling);\n        }\n        sibling.parent = me.parent;\n      } while (me.children.length > 10)\n      me.parent.maybeSpill();\n    },\n\n    iterN: function(at, n, op) {\n      var this$1 = this;\n\n      for (var i = 0; i < this.children.length; ++i) {\n        var child = this$1.children[i], sz = child.chunkSize();\n        if (at < sz) {\n          var used = Math.min(n, sz - at);\n          if (child.iterN(at, used, op)) { return true }\n          if ((n -= used) == 0) { break }\n          at = 0;\n        } else { at -= sz; }\n      }\n    }\n  };\n\n  // Line widgets are block elements displayed above or below a line.\n\n  var LineWidget = function(doc, node, options) {\n    var this$1 = this;\n\n    if (options) { for (var opt in options) { if (options.hasOwnProperty(opt))\n      { this$1[opt] = options[opt]; } } }\n    this.doc = doc;\n    this.node = node;\n  };\n\n  LineWidget.prototype.clear = function () {\n      var this$1 = this;\n\n    var cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line);\n    if (no == null || !ws) { return }\n    for (var i = 0; i < ws.length; ++i) { if (ws[i] == this$1) { ws.splice(i--, 1); } }\n    if (!ws.length) { line.widgets = null; }\n    var height = widgetHeight(this);\n    updateLineHeight(line, Math.max(0, line.height - height));\n    if (cm) {\n      runInOp(cm, function () {\n        adjustScrollWhenAboveVisible(cm, line, -height);\n        regLineChange(cm, no, \"widget\");\n      });\n      signalLater(cm, \"lineWidgetCleared\", cm, this, no);\n    }\n  };\n\n  LineWidget.prototype.changed = function () {\n      var this$1 = this;\n\n    var oldH = this.height, cm = this.doc.cm, line = this.line;\n    this.height = null;\n    var diff = widgetHeight(this) - oldH;\n    if (!diff) { return }\n    if (!lineIsHidden(this.doc, line)) { updateLineHeight(line, line.height + diff); }\n    if (cm) {\n      runInOp(cm, function () {\n        cm.curOp.forceUpdate = true;\n        adjustScrollWhenAboveVisible(cm, line, diff);\n        signalLater(cm, \"lineWidgetChanged\", cm, this$1, lineNo(line));\n      });\n    }\n  };\n  eventMixin(LineWidget);\n\n  function adjustScrollWhenAboveVisible(cm, line, diff) {\n    if (heightAtLine(line) < ((cm.curOp && cm.curOp.scrollTop) || cm.doc.scrollTop))\n      { addToScrollTop(cm, diff); }\n  }\n\n  function addLineWidget(doc, handle, node, options) {\n    var widget = new LineWidget(doc, node, options);\n    var cm = doc.cm;\n    if (cm && widget.noHScroll) { cm.display.alignWidgets = true; }\n    changeLine(doc, handle, \"widget\", function (line) {\n      var widgets = line.widgets || (line.widgets = []);\n      if (widget.insertAt == null) { widgets.push(widget); }\n      else { widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget); }\n      widget.line = line;\n      if (cm && !lineIsHidden(doc, line)) {\n        var aboveVisible = heightAtLine(line) < doc.scrollTop;\n        updateLineHeight(line, line.height + widgetHeight(widget));\n        if (aboveVisible) { addToScrollTop(cm, widget.height); }\n        cm.curOp.forceUpdate = true;\n      }\n      return true\n    });\n    if (cm) { signalLater(cm, \"lineWidgetAdded\", cm, widget, typeof handle == \"number\" ? handle : lineNo(handle)); }\n    return widget\n  }\n\n  // TEXTMARKERS\n\n  // Created with markText and setBookmark methods. A TextMarker is a\n  // handle that can be used to clear or find a marked position in the\n  // document. Line objects hold arrays (markedSpans) containing\n  // {from, to, marker} object pointing to such marker objects, and\n  // indicating that such a marker is present on that line. Multiple\n  // lines may point to the same marker when it spans across lines.\n  // The spans will have null for their from/to properties when the\n  // marker continues beyond the start/end of the line. Markers have\n  // links back to the lines they currently touch.\n\n  // Collapsed markers have unique ids, in order to be able to order\n  // them, which is needed for uniquely determining an outer marker\n  // when they overlap (they may nest, but not partially overlap).\n  var nextMarkerId = 0;\n\n  var TextMarker = function(doc, type) {\n    this.lines = [];\n    this.type = type;\n    this.doc = doc;\n    this.id = ++nextMarkerId;\n  };\n\n  // Clear the marker.\n  TextMarker.prototype.clear = function () {\n      var this$1 = this;\n\n    if (this.explicitlyCleared) { return }\n    var cm = this.doc.cm, withOp = cm && !cm.curOp;\n    if (withOp) { startOperation(cm); }\n    if (hasHandler(this, \"clear\")) {\n      var found = this.find();\n      if (found) { signalLater(this, \"clear\", found.from, found.to); }\n    }\n    var min = null, max = null;\n    for (var i = 0; i < this.lines.length; ++i) {\n      var line = this$1.lines[i];\n      var span = getMarkedSpanFor(line.markedSpans, this$1);\n      if (cm && !this$1.collapsed) { regLineChange(cm, lineNo(line), \"text\"); }\n      else if (cm) {\n        if (span.to != null) { max = lineNo(line); }\n        if (span.from != null) { min = lineNo(line); }\n      }\n      line.markedSpans = removeMarkedSpan(line.markedSpans, span);\n      if (span.from == null && this$1.collapsed && !lineIsHidden(this$1.doc, line) && cm)\n        { updateLineHeight(line, textHeight(cm.display)); }\n    }\n    if (cm && this.collapsed && !cm.options.lineWrapping) { for (var i$1 = 0; i$1 < this.lines.length; ++i$1) {\n      var visual = visualLine(this$1.lines[i$1]), len = lineLength(visual);\n      if (len > cm.display.maxLineLength) {\n        cm.display.maxLine = visual;\n        cm.display.maxLineLength = len;\n        cm.display.maxLineChanged = true;\n      }\n    } }\n\n    if (min != null && cm && this.collapsed) { regChange(cm, min, max + 1); }\n    this.lines.length = 0;\n    this.explicitlyCleared = true;\n    if (this.atomic && this.doc.cantEdit) {\n      this.doc.cantEdit = false;\n      if (cm) { reCheckSelection(cm.doc); }\n    }\n    if (cm) { signalLater(cm, \"markerCleared\", cm, this, min, max); }\n    if (withOp) { endOperation(cm); }\n    if (this.parent) { this.parent.clear(); }\n  };\n\n  // Find the position of the marker in the document. Returns a {from,\n  // to} object by default. Side can be passed to get a specific side\n  // -- 0 (both), -1 (left), or 1 (right). When lineObj is true, the\n  // Pos objects returned contain a line object, rather than a line\n  // number (used to prevent looking up the same line twice).\n  TextMarker.prototype.find = function (side, lineObj) {\n      var this$1 = this;\n\n    if (side == null && this.type == \"bookmark\") { side = 1; }\n    var from, to;\n    for (var i = 0; i < this.lines.length; ++i) {\n      var line = this$1.lines[i];\n      var span = getMarkedSpanFor(line.markedSpans, this$1);\n      if (span.from != null) {\n        from = Pos(lineObj ? line : lineNo(line), span.from);\n        if (side == -1) { return from }\n      }\n      if (span.to != null) {\n        to = Pos(lineObj ? line : lineNo(line), span.to);\n        if (side == 1) { return to }\n      }\n    }\n    return from && {from: from, to: to}\n  };\n\n  // Signals that the marker's widget changed, and surrounding layout\n  // should be recomputed.\n  TextMarker.prototype.changed = function () {\n      var this$1 = this;\n\n    var pos = this.find(-1, true), widget = this, cm = this.doc.cm;\n    if (!pos || !cm) { return }\n    runInOp(cm, function () {\n      var line = pos.line, lineN = lineNo(pos.line);\n      var view = findViewForLine(cm, lineN);\n      if (view) {\n        clearLineMeasurementCacheFor(view);\n        cm.curOp.selectionChanged = cm.curOp.forceUpdate = true;\n      }\n      cm.curOp.updateMaxLine = true;\n      if (!lineIsHidden(widget.doc, line) && widget.height != null) {\n        var oldHeight = widget.height;\n        widget.height = null;\n        var dHeight = widgetHeight(widget) - oldHeight;\n        if (dHeight)\n          { updateLineHeight(line, line.height + dHeight); }\n      }\n      signalLater(cm, \"markerChanged\", cm, this$1);\n    });\n  };\n\n  TextMarker.prototype.attachLine = function (line) {\n    if (!this.lines.length && this.doc.cm) {\n      var op = this.doc.cm.curOp;\n      if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1)\n        { (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this); }\n    }\n    this.lines.push(line);\n  };\n\n  TextMarker.prototype.detachLine = function (line) {\n    this.lines.splice(indexOf(this.lines, line), 1);\n    if (!this.lines.length && this.doc.cm) {\n      var op = this.doc.cm.curOp\n      ;(op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this);\n    }\n  };\n  eventMixin(TextMarker);\n\n  // Create a marker, wire it up to the right lines, and\n  function markText(doc, from, to, options, type) {\n    // Shared markers (across linked documents) are handled separately\n    // (markTextShared will call out to this again, once per\n    // document).\n    if (options && options.shared) { return markTextShared(doc, from, to, options, type) }\n    // Ensure we are in an operation.\n    if (doc.cm && !doc.cm.curOp) { return operation(doc.cm, markText)(doc, from, to, options, type) }\n\n    var marker = new TextMarker(doc, type), diff = cmp(from, to);\n    if (options) { copyObj(options, marker, false); }\n    // Don't connect empty markers unless clearWhenEmpty is false\n    if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false)\n      { return marker }\n    if (marker.replacedWith) {\n      // Showing up as a widget implies collapsed (widget replaces text)\n      marker.collapsed = true;\n      marker.widgetNode = eltP(\"span\", [marker.replacedWith], \"CodeMirror-widget\");\n      if (!options.handleMouseEvents) { marker.widgetNode.setAttribute(\"cm-ignore-events\", \"true\"); }\n      if (options.insertLeft) { marker.widgetNode.insertLeft = true; }\n    }\n    if (marker.collapsed) {\n      if (conflictingCollapsedRange(doc, from.line, from, to, marker) ||\n          from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker))\n        { throw new Error(\"Inserting collapsed marker partially overlapping an existing one\") }\n      seeCollapsedSpans();\n    }\n\n    if (marker.addToHistory)\n      { addChangeToHistory(doc, {from: from, to: to, origin: \"markText\"}, doc.sel, NaN); }\n\n    var curLine = from.line, cm = doc.cm, updateMaxLine;\n    doc.iter(curLine, to.line + 1, function (line) {\n      if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine)\n        { updateMaxLine = true; }\n      if (marker.collapsed && curLine != from.line) { updateLineHeight(line, 0); }\n      addMarkedSpan(line, new MarkedSpan(marker,\n                                         curLine == from.line ? from.ch : null,\n                                         curLine == to.line ? to.ch : null));\n      ++curLine;\n    });\n    // lineIsHidden depends on the presence of the spans, so needs a second pass\n    if (marker.collapsed) { doc.iter(from.line, to.line + 1, function (line) {\n      if (lineIsHidden(doc, line)) { updateLineHeight(line, 0); }\n    }); }\n\n    if (marker.clearOnEnter) { on(marker, \"beforeCursorEnter\", function () { return marker.clear(); }); }\n\n    if (marker.readOnly) {\n      seeReadOnlySpans();\n      if (doc.history.done.length || doc.history.undone.length)\n        { doc.clearHistory(); }\n    }\n    if (marker.collapsed) {\n      marker.id = ++nextMarkerId;\n      marker.atomic = true;\n    }\n    if (cm) {\n      // Sync editor state\n      if (updateMaxLine) { cm.curOp.updateMaxLine = true; }\n      if (marker.collapsed)\n        { regChange(cm, from.line, to.line + 1); }\n      else if (marker.className || marker.title || marker.startStyle || marker.endStyle || marker.css)\n        { for (var i = from.line; i <= to.line; i++) { regLineChange(cm, i, \"text\"); } }\n      if (marker.atomic) { reCheckSelection(cm.doc); }\n      signalLater(cm, \"markerAdded\", cm, marker);\n    }\n    return marker\n  }\n\n  // SHARED TEXTMARKERS\n\n  // A shared marker spans multiple linked documents. It is\n  // implemented as a meta-marker-object controlling multiple normal\n  // markers.\n  var SharedTextMarker = function(markers, primary) {\n    var this$1 = this;\n\n    this.markers = markers;\n    this.primary = primary;\n    for (var i = 0; i < markers.length; ++i)\n      { markers[i].parent = this$1; }\n  };\n\n  SharedTextMarker.prototype.clear = function () {\n      var this$1 = this;\n\n    if (this.explicitlyCleared) { return }\n    this.explicitlyCleared = true;\n    for (var i = 0; i < this.markers.length; ++i)\n      { this$1.markers[i].clear(); }\n    signalLater(this, \"clear\");\n  };\n\n  SharedTextMarker.prototype.find = function (side, lineObj) {\n    return this.primary.find(side, lineObj)\n  };\n  eventMixin(SharedTextMarker);\n\n  function markTextShared(doc, from, to, options, type) {\n    options = copyObj(options);\n    options.shared = false;\n    var markers = [markText(doc, from, to, options, type)], primary = markers[0];\n    var widget = options.widgetNode;\n    linkedDocs(doc, function (doc) {\n      if (widget) { options.widgetNode = widget.cloneNode(true); }\n      markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type));\n      for (var i = 0; i < doc.linked.length; ++i)\n        { if (doc.linked[i].isParent) { return } }\n      primary = lst(markers);\n    });\n    return new SharedTextMarker(markers, primary)\n  }\n\n  function findSharedMarkers(doc) {\n    return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())), function (m) { return m.parent; })\n  }\n\n  function copySharedMarkers(doc, markers) {\n    for (var i = 0; i < markers.length; i++) {\n      var marker = markers[i], pos = marker.find();\n      var mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to);\n      if (cmp(mFrom, mTo)) {\n        var subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type);\n        marker.markers.push(subMark);\n        subMark.parent = marker;\n      }\n    }\n  }\n\n  function detachSharedMarkers(markers) {\n    var loop = function ( i ) {\n      var marker = markers[i], linked = [marker.primary.doc];\n      linkedDocs(marker.primary.doc, function (d) { return linked.push(d); });\n      for (var j = 0; j < marker.markers.length; j++) {\n        var subMarker = marker.markers[j];\n        if (indexOf(linked, subMarker.doc) == -1) {\n          subMarker.parent = null;\n          marker.markers.splice(j--, 1);\n        }\n      }\n    };\n\n    for (var i = 0; i < markers.length; i++) loop( i );\n  }\n\n  var nextDocId = 0;\n  var Doc = function(text, mode, firstLine, lineSep, direction) {\n    if (!(this instanceof Doc)) { return new Doc(text, mode, firstLine, lineSep, direction) }\n    if (firstLine == null) { firstLine = 0; }\n\n    BranchChunk.call(this, [new LeafChunk([new Line(\"\", null)])]);\n    this.first = firstLine;\n    this.scrollTop = this.scrollLeft = 0;\n    this.cantEdit = false;\n    this.cleanGeneration = 1;\n    this.modeFrontier = this.highlightFrontier = firstLine;\n    var start = Pos(firstLine, 0);\n    this.sel = simpleSelection(start);\n    this.history = new History(null);\n    this.id = ++nextDocId;\n    this.modeOption = mode;\n    this.lineSep = lineSep;\n    this.direction = (direction == \"rtl\") ? \"rtl\" : \"ltr\";\n    this.extend = false;\n\n    if (typeof text == \"string\") { text = this.splitLines(text); }\n    updateDoc(this, {from: start, to: start, text: text});\n    setSelection(this, simpleSelection(start), sel_dontScroll);\n  };\n\n  Doc.prototype = createObj(BranchChunk.prototype, {\n    constructor: Doc,\n    // Iterate over the document. Supports two forms -- with only one\n    // argument, it calls that for each line in the document. With\n    // three, it iterates over the range given by the first two (with\n    // the second being non-inclusive).\n    iter: function(from, to, op) {\n      if (op) { this.iterN(from - this.first, to - from, op); }\n      else { this.iterN(this.first, this.first + this.size, from); }\n    },\n\n    // Non-public interface for adding and removing lines.\n    insert: function(at, lines) {\n      var height = 0;\n      for (var i = 0; i < lines.length; ++i) { height += lines[i].height; }\n      this.insertInner(at - this.first, lines, height);\n    },\n    remove: function(at, n) { this.removeInner(at - this.first, n); },\n\n    // From here, the methods are part of the public interface. Most\n    // are also available from CodeMirror (editor) instances.\n\n    getValue: function(lineSep) {\n      var lines = getLines(this, this.first, this.first + this.size);\n      if (lineSep === false) { return lines }\n      return lines.join(lineSep || this.lineSeparator())\n    },\n    setValue: docMethodOp(function(code) {\n      var top = Pos(this.first, 0), last = this.first + this.size - 1;\n      makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length),\n                        text: this.splitLines(code), origin: \"setValue\", full: true}, true);\n      if (this.cm) { scrollToCoords(this.cm, 0, 0); }\n      setSelection(this, simpleSelection(top), sel_dontScroll);\n    }),\n    replaceRange: function(code, from, to, origin) {\n      from = clipPos(this, from);\n      to = to ? clipPos(this, to) : from;\n      replaceRange(this, code, from, to, origin);\n    },\n    getRange: function(from, to, lineSep) {\n      var lines = getBetween(this, clipPos(this, from), clipPos(this, to));\n      if (lineSep === false) { return lines }\n      return lines.join(lineSep || this.lineSeparator())\n    },\n\n    getLine: function(line) {var l = this.getLineHandle(line); return l && l.text},\n\n    getLineHandle: function(line) {if (isLine(this, line)) { return getLine(this, line) }},\n    getLineNumber: function(line) {return lineNo(line)},\n\n    getLineHandleVisualStart: function(line) {\n      if (typeof line == \"number\") { line = getLine(this, line); }\n      return visualLine(line)\n    },\n\n    lineCount: function() {return this.size},\n    firstLine: function() {return this.first},\n    lastLine: function() {return this.first + this.size - 1},\n\n    clipPos: function(pos) {return clipPos(this, pos)},\n\n    getCursor: function(start) {\n      var range$$1 = this.sel.primary(), pos;\n      if (start == null || start == \"head\") { pos = range$$1.head; }\n      else if (start == \"anchor\") { pos = range$$1.anchor; }\n      else if (start == \"end\" || start == \"to\" || start === false) { pos = range$$1.to(); }\n      else { pos = range$$1.from(); }\n      return pos\n    },\n    listSelections: function() { return this.sel.ranges },\n    somethingSelected: function() {return this.sel.somethingSelected()},\n\n    setCursor: docMethodOp(function(line, ch, options) {\n      setSimpleSelection(this, clipPos(this, typeof line == \"number\" ? Pos(line, ch || 0) : line), null, options);\n    }),\n    setSelection: docMethodOp(function(anchor, head, options) {\n      setSimpleSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), options);\n    }),\n    extendSelection: docMethodOp(function(head, other, options) {\n      extendSelection(this, clipPos(this, head), other && clipPos(this, other), options);\n    }),\n    extendSelections: docMethodOp(function(heads, options) {\n      extendSelections(this, clipPosArray(this, heads), options);\n    }),\n    extendSelectionsBy: docMethodOp(function(f, options) {\n      var heads = map(this.sel.ranges, f);\n      extendSelections(this, clipPosArray(this, heads), options);\n    }),\n    setSelections: docMethodOp(function(ranges, primary, options) {\n      var this$1 = this;\n\n      if (!ranges.length) { return }\n      var out = [];\n      for (var i = 0; i < ranges.length; i++)\n        { out[i] = new Range(clipPos(this$1, ranges[i].anchor),\n                           clipPos(this$1, ranges[i].head)); }\n      if (primary == null) { primary = Math.min(ranges.length - 1, this.sel.primIndex); }\n      setSelection(this, normalizeSelection(this.cm, out, primary), options);\n    }),\n    addSelection: docMethodOp(function(anchor, head, options) {\n      var ranges = this.sel.ranges.slice(0);\n      ranges.push(new Range(clipPos(this, anchor), clipPos(this, head || anchor)));\n      setSelection(this, normalizeSelection(this.cm, ranges, ranges.length - 1), options);\n    }),\n\n    getSelection: function(lineSep) {\n      var this$1 = this;\n\n      var ranges = this.sel.ranges, lines;\n      for (var i = 0; i < ranges.length; i++) {\n        var sel = getBetween(this$1, ranges[i].from(), ranges[i].to());\n        lines = lines ? lines.concat(sel) : sel;\n      }\n      if (lineSep === false) { return lines }\n      else { return lines.join(lineSep || this.lineSeparator()) }\n    },\n    getSelections: function(lineSep) {\n      var this$1 = this;\n\n      var parts = [], ranges = this.sel.ranges;\n      for (var i = 0; i < ranges.length; i++) {\n        var sel = getBetween(this$1, ranges[i].from(), ranges[i].to());\n        if (lineSep !== false) { sel = sel.join(lineSep || this$1.lineSeparator()); }\n        parts[i] = sel;\n      }\n      return parts\n    },\n    replaceSelection: function(code, collapse, origin) {\n      var dup = [];\n      for (var i = 0; i < this.sel.ranges.length; i++)\n        { dup[i] = code; }\n      this.replaceSelections(dup, collapse, origin || \"+input\");\n    },\n    replaceSelections: docMethodOp(function(code, collapse, origin) {\n      var this$1 = this;\n\n      var changes = [], sel = this.sel;\n      for (var i = 0; i < sel.ranges.length; i++) {\n        var range$$1 = sel.ranges[i];\n        changes[i] = {from: range$$1.from(), to: range$$1.to(), text: this$1.splitLines(code[i]), origin: origin};\n      }\n      var newSel = collapse && collapse != \"end\" && computeReplacedSel(this, changes, collapse);\n      for (var i$1 = changes.length - 1; i$1 >= 0; i$1--)\n        { makeChange(this$1, changes[i$1]); }\n      if (newSel) { setSelectionReplaceHistory(this, newSel); }\n      else if (this.cm) { ensureCursorVisible(this.cm); }\n    }),\n    undo: docMethodOp(function() {makeChangeFromHistory(this, \"undo\");}),\n    redo: docMethodOp(function() {makeChangeFromHistory(this, \"redo\");}),\n    undoSelection: docMethodOp(function() {makeChangeFromHistory(this, \"undo\", true);}),\n    redoSelection: docMethodOp(function() {makeChangeFromHistory(this, \"redo\", true);}),\n\n    setExtending: function(val) {this.extend = val;},\n    getExtending: function() {return this.extend},\n\n    historySize: function() {\n      var hist = this.history, done = 0, undone = 0;\n      for (var i = 0; i < hist.done.length; i++) { if (!hist.done[i].ranges) { ++done; } }\n      for (var i$1 = 0; i$1 < hist.undone.length; i$1++) { if (!hist.undone[i$1].ranges) { ++undone; } }\n      return {undo: done, redo: undone}\n    },\n    clearHistory: function() {this.history = new History(this.history.maxGeneration);},\n\n    markClean: function() {\n      this.cleanGeneration = this.changeGeneration(true);\n    },\n    changeGeneration: function(forceSplit) {\n      if (forceSplit)\n        { this.history.lastOp = this.history.lastSelOp = this.history.lastOrigin = null; }\n      return this.history.generation\n    },\n    isClean: function (gen) {\n      return this.history.generation == (gen || this.cleanGeneration)\n    },\n\n    getHistory: function() {\n      return {done: copyHistoryArray(this.history.done),\n              undone: copyHistoryArray(this.history.undone)}\n    },\n    setHistory: function(histData) {\n      var hist = this.history = new History(this.history.maxGeneration);\n      hist.done = copyHistoryArray(histData.done.slice(0), null, true);\n      hist.undone = copyHistoryArray(histData.undone.slice(0), null, true);\n    },\n\n    setGutterMarker: docMethodOp(function(line, gutterID, value) {\n      return changeLine(this, line, \"gutter\", function (line) {\n        var markers = line.gutterMarkers || (line.gutterMarkers = {});\n        markers[gutterID] = value;\n        if (!value && isEmpty(markers)) { line.gutterMarkers = null; }\n        return true\n      })\n    }),\n\n    clearGutter: docMethodOp(function(gutterID) {\n      var this$1 = this;\n\n      this.iter(function (line) {\n        if (line.gutterMarkers && line.gutterMarkers[gutterID]) {\n          changeLine(this$1, line, \"gutter\", function () {\n            line.gutterMarkers[gutterID] = null;\n            if (isEmpty(line.gutterMarkers)) { line.gutterMarkers = null; }\n            return true\n          });\n        }\n      });\n    }),\n\n    lineInfo: function(line) {\n      var n;\n      if (typeof line == \"number\") {\n        if (!isLine(this, line)) { return null }\n        n = line;\n        line = getLine(this, line);\n        if (!line) { return null }\n      } else {\n        n = lineNo(line);\n        if (n == null) { return null }\n      }\n      return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers,\n              textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass,\n              widgets: line.widgets}\n    },\n\n    addLineClass: docMethodOp(function(handle, where, cls) {\n      return changeLine(this, handle, where == \"gutter\" ? \"gutter\" : \"class\", function (line) {\n        var prop = where == \"text\" ? \"textClass\"\n                 : where == \"background\" ? \"bgClass\"\n                 : where == \"gutter\" ? \"gutterClass\" : \"wrapClass\";\n        if (!line[prop]) { line[prop] = cls; }\n        else if (classTest(cls).test(line[prop])) { return false }\n        else { line[prop] += \" \" + cls; }\n        return true\n      })\n    }),\n    removeLineClass: docMethodOp(function(handle, where, cls) {\n      return changeLine(this, handle, where == \"gutter\" ? \"gutter\" : \"class\", function (line) {\n        var prop = where == \"text\" ? \"textClass\"\n                 : where == \"background\" ? \"bgClass\"\n                 : where == \"gutter\" ? \"gutterClass\" : \"wrapClass\";\n        var cur = line[prop];\n        if (!cur) { return false }\n        else if (cls == null) { line[prop] = null; }\n        else {\n          var found = cur.match(classTest(cls));\n          if (!found) { return false }\n          var end = found.index + found[0].length;\n          line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? \"\" : \" \") + cur.slice(end) || null;\n        }\n        return true\n      })\n    }),\n\n    addLineWidget: docMethodOp(function(handle, node, options) {\n      return addLineWidget(this, handle, node, options)\n    }),\n    removeLineWidget: function(widget) { widget.clear(); },\n\n    markText: function(from, to, options) {\n      return markText(this, clipPos(this, from), clipPos(this, to), options, options && options.type || \"range\")\n    },\n    setBookmark: function(pos, options) {\n      var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options),\n                      insertLeft: options && options.insertLeft,\n                      clearWhenEmpty: false, shared: options && options.shared,\n                      handleMouseEvents: options && options.handleMouseEvents};\n      pos = clipPos(this, pos);\n      return markText(this, pos, pos, realOpts, \"bookmark\")\n    },\n    findMarksAt: function(pos) {\n      pos = clipPos(this, pos);\n      var markers = [], spans = getLine(this, pos.line).markedSpans;\n      if (spans) { for (var i = 0; i < spans.length; ++i) {\n        var span = spans[i];\n        if ((span.from == null || span.from <= pos.ch) &&\n            (span.to == null || span.to >= pos.ch))\n          { markers.push(span.marker.parent || span.marker); }\n      } }\n      return markers\n    },\n    findMarks: function(from, to, filter) {\n      from = clipPos(this, from); to = clipPos(this, to);\n      var found = [], lineNo$$1 = from.line;\n      this.iter(from.line, to.line + 1, function (line) {\n        var spans = line.markedSpans;\n        if (spans) { for (var i = 0; i < spans.length; i++) {\n          var span = spans[i];\n          if (!(span.to != null && lineNo$$1 == from.line && from.ch >= span.to ||\n                span.from == null && lineNo$$1 != from.line ||\n                span.from != null && lineNo$$1 == to.line && span.from >= to.ch) &&\n              (!filter || filter(span.marker)))\n            { found.push(span.marker.parent || span.marker); }\n        } }\n        ++lineNo$$1;\n      });\n      return found\n    },\n    getAllMarks: function() {\n      var markers = [];\n      this.iter(function (line) {\n        var sps = line.markedSpans;\n        if (sps) { for (var i = 0; i < sps.length; ++i)\n          { if (sps[i].from != null) { markers.push(sps[i].marker); } } }\n      });\n      return markers\n    },\n\n    posFromIndex: function(off) {\n      var ch, lineNo$$1 = this.first, sepSize = this.lineSeparator().length;\n      this.iter(function (line) {\n        var sz = line.text.length + sepSize;\n        if (sz > off) { ch = off; return true }\n        off -= sz;\n        ++lineNo$$1;\n      });\n      return clipPos(this, Pos(lineNo$$1, ch))\n    },\n    indexFromPos: function (coords) {\n      coords = clipPos(this, coords);\n      var index = coords.ch;\n      if (coords.line < this.first || coords.ch < 0) { return 0 }\n      var sepSize = this.lineSeparator().length;\n      this.iter(this.first, coords.line, function (line) { // iter aborts when callback returns a truthy value\n        index += line.text.length + sepSize;\n      });\n      return index\n    },\n\n    copy: function(copyHistory) {\n      var doc = new Doc(getLines(this, this.first, this.first + this.size),\n                        this.modeOption, this.first, this.lineSep, this.direction);\n      doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft;\n      doc.sel = this.sel;\n      doc.extend = false;\n      if (copyHistory) {\n        doc.history.undoDepth = this.history.undoDepth;\n        doc.setHistory(this.getHistory());\n      }\n      return doc\n    },\n\n    linkedDoc: function(options) {\n      if (!options) { options = {}; }\n      var from = this.first, to = this.first + this.size;\n      if (options.from != null && options.from > from) { from = options.from; }\n      if (options.to != null && options.to < to) { to = options.to; }\n      var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from, this.lineSep, this.direction);\n      if (options.sharedHist) { copy.history = this.history\n      ; }(this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist});\n      copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}];\n      copySharedMarkers(copy, findSharedMarkers(this));\n      return copy\n    },\n    unlinkDoc: function(other) {\n      var this$1 = this;\n\n      if (other instanceof CodeMirror) { other = other.doc; }\n      if (this.linked) { for (var i = 0; i < this.linked.length; ++i) {\n        var link = this$1.linked[i];\n        if (link.doc != other) { continue }\n        this$1.linked.splice(i, 1);\n        other.unlinkDoc(this$1);\n        detachSharedMarkers(findSharedMarkers(this$1));\n        break\n      } }\n      // If the histories were shared, split them again\n      if (other.history == this.history) {\n        var splitIds = [other.id];\n        linkedDocs(other, function (doc) { return splitIds.push(doc.id); }, true);\n        other.history = new History(null);\n        other.history.done = copyHistoryArray(this.history.done, splitIds);\n        other.history.undone = copyHistoryArray(this.history.undone, splitIds);\n      }\n    },\n    iterLinkedDocs: function(f) {linkedDocs(this, f);},\n\n    getMode: function() {return this.mode},\n    getEditor: function() {return this.cm},\n\n    splitLines: function(str) {\n      if (this.lineSep) { return str.split(this.lineSep) }\n      return splitLinesAuto(str)\n    },\n    lineSeparator: function() { return this.lineSep || \"\\n\" },\n\n    setDirection: docMethodOp(function (dir) {\n      if (dir != \"rtl\") { dir = \"ltr\"; }\n      if (dir == this.direction) { return }\n      this.direction = dir;\n      this.iter(function (line) { return line.order = null; });\n      if (this.cm) { directionChanged(this.cm); }\n    })\n  });\n\n  // Public alias.\n  Doc.prototype.eachLine = Doc.prototype.iter;\n\n  // Kludge to work around strange IE behavior where it'll sometimes\n  // re-fire a series of drag-related events right after the drop (#1551)\n  var lastDrop = 0;\n\n  function onDrop(e) {\n    var cm = this;\n    clearDragCursor(cm);\n    if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e))\n      { return }\n    e_preventDefault(e);\n    if (ie) { lastDrop = +new Date; }\n    var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files;\n    if (!pos || cm.isReadOnly()) { return }\n    // Might be a file drop, in which case we simply extract the text\n    // and insert it.\n    if (files && files.length && window.FileReader && window.File) {\n      var n = files.length, text = Array(n), read = 0;\n      var loadFile = function (file, i) {\n        if (cm.options.allowDropFileTypes &&\n            indexOf(cm.options.allowDropFileTypes, file.type) == -1)\n          { return }\n\n        var reader = new FileReader;\n        reader.onload = operation(cm, function () {\n          var content = reader.result;\n          if (/[\\x00-\\x08\\x0e-\\x1f]{2}/.test(content)) { content = \"\"; }\n          text[i] = content;\n          if (++read == n) {\n            pos = clipPos(cm.doc, pos);\n            var change = {from: pos, to: pos,\n                          text: cm.doc.splitLines(text.join(cm.doc.lineSeparator())),\n                          origin: \"paste\"};\n            makeChange(cm.doc, change);\n            setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change)));\n          }\n        });\n        reader.readAsText(file);\n      };\n      for (var i = 0; i < n; ++i) { loadFile(files[i], i); }\n    } else { // Normal drop\n      // Don't do a replace if the drop happened inside of the selected text.\n      if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) {\n        cm.state.draggingText(e);\n        // Ensure the editor is re-focused\n        setTimeout(function () { return cm.display.input.focus(); }, 20);\n        return\n      }\n      try {\n        var text$1 = e.dataTransfer.getData(\"Text\");\n        if (text$1) {\n          var selected;\n          if (cm.state.draggingText && !cm.state.draggingText.copy)\n            { selected = cm.listSelections(); }\n          setSelectionNoUndo(cm.doc, simpleSelection(pos, pos));\n          if (selected) { for (var i$1 = 0; i$1 < selected.length; ++i$1)\n            { replaceRange(cm.doc, \"\", selected[i$1].anchor, selected[i$1].head, \"drag\"); } }\n          cm.replaceSelection(text$1, \"around\", \"paste\");\n          cm.display.input.focus();\n        }\n      }\n      catch(e){}\n    }\n  }\n\n  function onDragStart(cm, e) {\n    if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return }\n    if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) { return }\n\n    e.dataTransfer.setData(\"Text\", cm.getSelection());\n    e.dataTransfer.effectAllowed = \"copyMove\";\n\n    // Use dummy image instead of default browsers image.\n    // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there.\n    if (e.dataTransfer.setDragImage && !safari) {\n      var img = elt(\"img\", null, null, \"position: fixed; left: 0; top: 0;\");\n      img.src = \"data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\";\n      if (presto) {\n        img.width = img.height = 1;\n        cm.display.wrapper.appendChild(img);\n        // Force a relayout, or Opera won't use our image for some obscure reason\n        img._top = img.offsetTop;\n      }\n      e.dataTransfer.setDragImage(img, 0, 0);\n      if (presto) { img.parentNode.removeChild(img); }\n    }\n  }\n\n  function onDragOver(cm, e) {\n    var pos = posFromMouse(cm, e);\n    if (!pos) { return }\n    var frag = document.createDocumentFragment();\n    drawSelectionCursor(cm, pos, frag);\n    if (!cm.display.dragCursor) {\n      cm.display.dragCursor = elt(\"div\", null, \"CodeMirror-cursors CodeMirror-dragcursors\");\n      cm.display.lineSpace.insertBefore(cm.display.dragCursor, cm.display.cursorDiv);\n    }\n    removeChildrenAndAdd(cm.display.dragCursor, frag);\n  }\n\n  function clearDragCursor(cm) {\n    if (cm.display.dragCursor) {\n      cm.display.lineSpace.removeChild(cm.display.dragCursor);\n      cm.display.dragCursor = null;\n    }\n  }\n\n  // These must be handled carefully, because naively registering a\n  // handler for each editor will cause the editors to never be\n  // garbage collected.\n\n  function forEachCodeMirror(f) {\n    if (!document.getElementsByClassName) { return }\n    var byClass = document.getElementsByClassName(\"CodeMirror\");\n    for (var i = 0; i < byClass.length; i++) {\n      var cm = byClass[i].CodeMirror;\n      if (cm) { f(cm); }\n    }\n  }\n\n  var globalsRegistered = false;\n  function ensureGlobalHandlers() {\n    if (globalsRegistered) { return }\n    registerGlobalHandlers();\n    globalsRegistered = true;\n  }\n  function registerGlobalHandlers() {\n    // When the window resizes, we need to refresh active editors.\n    var resizeTimer;\n    on(window, \"resize\", function () {\n      if (resizeTimer == null) { resizeTimer = setTimeout(function () {\n        resizeTimer = null;\n        forEachCodeMirror(onResize);\n      }, 100); }\n    });\n    // When the window loses focus, we want to show the editor as blurred\n    on(window, \"blur\", function () { return forEachCodeMirror(onBlur); });\n  }\n  // Called when the window resizes\n  function onResize(cm) {\n    var d = cm.display;\n    // Might be a text scaling operation, clear size caches.\n    d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;\n    d.scrollbarsClipped = false;\n    cm.setSize();\n  }\n\n  var keyNames = {\n    3: \"Pause\", 8: \"Backspace\", 9: \"Tab\", 13: \"Enter\", 16: \"Shift\", 17: \"Ctrl\", 18: \"Alt\",\n    19: \"Pause\", 20: \"CapsLock\", 27: \"Esc\", 32: \"Space\", 33: \"PageUp\", 34: \"PageDown\", 35: \"End\",\n    36: \"Home\", 37: \"Left\", 38: \"Up\", 39: \"Right\", 40: \"Down\", 44: \"PrintScrn\", 45: \"Insert\",\n    46: \"Delete\", 59: \";\", 61: \"=\", 91: \"Mod\", 92: \"Mod\", 93: \"Mod\",\n    106: \"*\", 107: \"=\", 109: \"-\", 110: \".\", 111: \"/\", 127: \"Delete\", 145: \"ScrollLock\",\n    173: \"-\", 186: \";\", 187: \"=\", 188: \",\", 189: \"-\", 190: \".\", 191: \"/\", 192: \"`\", 219: \"[\", 220: \"\\\\\",\n    221: \"]\", 222: \"'\", 63232: \"Up\", 63233: \"Down\", 63234: \"Left\", 63235: \"Right\", 63272: \"Delete\",\n    63273: \"Home\", 63275: \"End\", 63276: \"PageUp\", 63277: \"PageDown\", 63302: \"Insert\"\n  };\n\n  // Number keys\n  for (var i = 0; i < 10; i++) { keyNames[i + 48] = keyNames[i + 96] = String(i); }\n  // Alphabetic keys\n  for (var i$1 = 65; i$1 <= 90; i$1++) { keyNames[i$1] = String.fromCharCode(i$1); }\n  // Function keys\n  for (var i$2 = 1; i$2 <= 12; i$2++) { keyNames[i$2 + 111] = keyNames[i$2 + 63235] = \"F\" + i$2; }\n\n  var keyMap = {};\n\n  keyMap.basic = {\n    \"Left\": \"goCharLeft\", \"Right\": \"goCharRight\", \"Up\": \"goLineUp\", \"Down\": \"goLineDown\",\n    \"End\": \"goLineEnd\", \"Home\": \"goLineStartSmart\", \"PageUp\": \"goPageUp\", \"PageDown\": \"goPageDown\",\n    \"Delete\": \"delCharAfter\", \"Backspace\": \"delCharBefore\", \"Shift-Backspace\": \"delCharBefore\",\n    \"Tab\": \"defaultTab\", \"Shift-Tab\": \"indentAuto\",\n    \"Enter\": \"newlineAndIndent\", \"Insert\": \"toggleOverwrite\",\n    \"Esc\": \"singleSelection\"\n  };\n  // Note that the save and find-related commands aren't defined by\n  // default. User code or addons can define them. Unknown commands\n  // are simply ignored.\n  keyMap.pcDefault = {\n    \"Ctrl-A\": \"selectAll\", \"Ctrl-D\": \"deleteLine\", \"Ctrl-Z\": \"undo\", \"Shift-Ctrl-Z\": \"redo\", \"Ctrl-Y\": \"redo\",\n    \"Ctrl-Home\": \"goDocStart\", \"Ctrl-End\": \"goDocEnd\", \"Ctrl-Up\": \"goLineUp\", \"Ctrl-Down\": \"goLineDown\",\n    \"Ctrl-Left\": \"goGroupLeft\", \"Ctrl-Right\": \"goGroupRight\", \"Alt-Left\": \"goLineStart\", \"Alt-Right\": \"goLineEnd\",\n    \"Ctrl-Backspace\": \"delGroupBefore\", \"Ctrl-Delete\": \"delGroupAfter\", \"Ctrl-S\": \"save\", \"Ctrl-F\": \"find\",\n    \"Ctrl-G\": \"findNext\", \"Shift-Ctrl-G\": \"findPrev\", \"Shift-Ctrl-F\": \"replace\", \"Shift-Ctrl-R\": \"replaceAll\",\n    \"Ctrl-[\": \"indentLess\", \"Ctrl-]\": \"indentMore\",\n    \"Ctrl-U\": \"undoSelection\", \"Shift-Ctrl-U\": \"redoSelection\", \"Alt-U\": \"redoSelection\",\n    \"fallthrough\": \"basic\"\n  };\n  // Very basic readline/emacs-style bindings, which are standard on Mac.\n  keyMap.emacsy = {\n    \"Ctrl-F\": \"goCharRight\", \"Ctrl-B\": \"goCharLeft\", \"Ctrl-P\": \"goLineUp\", \"Ctrl-N\": \"goLineDown\",\n    \"Alt-F\": \"goWordRight\", \"Alt-B\": \"goWordLeft\", \"Ctrl-A\": \"goLineStart\", \"Ctrl-E\": \"goLineEnd\",\n    \"Ctrl-V\": \"goPageDown\", \"Shift-Ctrl-V\": \"goPageUp\", \"Ctrl-D\": \"delCharAfter\", \"Ctrl-H\": \"delCharBefore\",\n    \"Alt-D\": \"delWordAfter\", \"Alt-Backspace\": \"delWordBefore\", \"Ctrl-K\": \"killLine\", \"Ctrl-T\": \"transposeChars\",\n    \"Ctrl-O\": \"openLine\"\n  };\n  keyMap.macDefault = {\n    \"Cmd-A\": \"selectAll\", \"Cmd-D\": \"deleteLine\", \"Cmd-Z\": \"undo\", \"Shift-Cmd-Z\": \"redo\", \"Cmd-Y\": \"redo\",\n    \"Cmd-Home\": \"goDocStart\", \"Cmd-Up\": \"goDocStart\", \"Cmd-End\": \"goDocEnd\", \"Cmd-Down\": \"goDocEnd\", \"Alt-Left\": \"goGroupLeft\",\n    \"Alt-Right\": \"goGroupRight\", \"Cmd-Left\": \"goLineLeft\", \"Cmd-Right\": \"goLineRight\", \"Alt-Backspace\": \"delGroupBefore\",\n    \"Ctrl-Alt-Backspace\": \"delGroupAfter\", \"Alt-Delete\": \"delGroupAfter\", \"Cmd-S\": \"save\", \"Cmd-F\": \"find\",\n    \"Cmd-G\": \"findNext\", \"Shift-Cmd-G\": \"findPrev\", \"Cmd-Alt-F\": \"replace\", \"Shift-Cmd-Alt-F\": \"replaceAll\",\n    \"Cmd-[\": \"indentLess\", \"Cmd-]\": \"indentMore\", \"Cmd-Backspace\": \"delWrappedLineLeft\", \"Cmd-Delete\": \"delWrappedLineRight\",\n    \"Cmd-U\": \"undoSelection\", \"Shift-Cmd-U\": \"redoSelection\", \"Ctrl-Up\": \"goDocStart\", \"Ctrl-Down\": \"goDocEnd\",\n    \"fallthrough\": [\"basic\", \"emacsy\"]\n  };\n  keyMap[\"default\"] = mac ? keyMap.macDefault : keyMap.pcDefault;\n\n  // KEYMAP DISPATCH\n\n  function normalizeKeyName(name) {\n    var parts = name.split(/-(?!$)/);\n    name = parts[parts.length - 1];\n    var alt, ctrl, shift, cmd;\n    for (var i = 0; i < parts.length - 1; i++) {\n      var mod = parts[i];\n      if (/^(cmd|meta|m)$/i.test(mod)) { cmd = true; }\n      else if (/^a(lt)?$/i.test(mod)) { alt = true; }\n      else if (/^(c|ctrl|control)$/i.test(mod)) { ctrl = true; }\n      else if (/^s(hift)?$/i.test(mod)) { shift = true; }\n      else { throw new Error(\"Unrecognized modifier name: \" + mod) }\n    }\n    if (alt) { name = \"Alt-\" + name; }\n    if (ctrl) { name = \"Ctrl-\" + name; }\n    if (cmd) { name = \"Cmd-\" + name; }\n    if (shift) { name = \"Shift-\" + name; }\n    return name\n  }\n\n  // This is a kludge to keep keymaps mostly working as raw objects\n  // (backwards compatibility) while at the same time support features\n  // like normalization and multi-stroke key bindings. It compiles a\n  // new normalized keymap, and then updates the old object to reflect\n  // this.\n  function normalizeKeyMap(keymap) {\n    var copy = {};\n    for (var keyname in keymap) { if (keymap.hasOwnProperty(keyname)) {\n      var value = keymap[keyname];\n      if (/^(name|fallthrough|(de|at)tach)$/.test(keyname)) { continue }\n      if (value == \"...\") { delete keymap[keyname]; continue }\n\n      var keys = map(keyname.split(\" \"), normalizeKeyName);\n      for (var i = 0; i < keys.length; i++) {\n        var val = (void 0), name = (void 0);\n        if (i == keys.length - 1) {\n          name = keys.join(\" \");\n          val = value;\n        } else {\n          name = keys.slice(0, i + 1).join(\" \");\n          val = \"...\";\n        }\n        var prev = copy[name];\n        if (!prev) { copy[name] = val; }\n        else if (prev != val) { throw new Error(\"Inconsistent bindings for \" + name) }\n      }\n      delete keymap[keyname];\n    } }\n    for (var prop in copy) { keymap[prop] = copy[prop]; }\n    return keymap\n  }\n\n  function lookupKey(key, map$$1, handle, context) {\n    map$$1 = getKeyMap(map$$1);\n    var found = map$$1.call ? map$$1.call(key, context) : map$$1[key];\n    if (found === false) { return \"nothing\" }\n    if (found === \"...\") { return \"multi\" }\n    if (found != null && handle(found)) { return \"handled\" }\n\n    if (map$$1.fallthrough) {\n      if (Object.prototype.toString.call(map$$1.fallthrough) != \"[object Array]\")\n        { return lookupKey(key, map$$1.fallthrough, handle, context) }\n      for (var i = 0; i < map$$1.fallthrough.length; i++) {\n        var result = lookupKey(key, map$$1.fallthrough[i], handle, context);\n        if (result) { return result }\n      }\n    }\n  }\n\n  // Modifier key presses don't count as 'real' key presses for the\n  // purpose of keymap fallthrough.\n  function isModifierKey(value) {\n    var name = typeof value == \"string\" ? value : keyNames[value.keyCode];\n    return name == \"Ctrl\" || name == \"Alt\" || name == \"Shift\" || name == \"Mod\"\n  }\n\n  function addModifierNames(name, event, noShift) {\n    var base = name;\n    if (event.altKey && base != \"Alt\") { name = \"Alt-\" + name; }\n    if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != \"Ctrl\") { name = \"Ctrl-\" + name; }\n    if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != \"Cmd\") { name = \"Cmd-\" + name; }\n    if (!noShift && event.shiftKey && base != \"Shift\") { name = \"Shift-\" + name; }\n    return name\n  }\n\n  // Look up the name of a key as indicated by an event object.\n  function keyName(event, noShift) {\n    if (presto && event.keyCode == 34 && event[\"char\"]) { return false }\n    var name = keyNames[event.keyCode];\n    if (name == null || event.altGraphKey) { return false }\n    // Ctrl-ScrollLock has keyCode 3, same as Ctrl-Pause,\n    // so we'll use event.code when available (Chrome 48+, FF 38+, Safari 10.1+)\n    if (event.keyCode == 3 && event.code) { name = event.code; }\n    return addModifierNames(name, event, noShift)\n  }\n\n  function getKeyMap(val) {\n    return typeof val == \"string\" ? keyMap[val] : val\n  }\n\n  // Helper for deleting text near the selection(s), used to implement\n  // backspace, delete, and similar functionality.\n  function deleteNearSelection(cm, compute) {\n    var ranges = cm.doc.sel.ranges, kill = [];\n    // Build up a set of ranges to kill first, merging overlapping\n    // ranges.\n    for (var i = 0; i < ranges.length; i++) {\n      var toKill = compute(ranges[i]);\n      while (kill.length && cmp(toKill.from, lst(kill).to) <= 0) {\n        var replaced = kill.pop();\n        if (cmp(replaced.from, toKill.from) < 0) {\n          toKill.from = replaced.from;\n          break\n        }\n      }\n      kill.push(toKill);\n    }\n    // Next, remove those actual ranges.\n    runInOp(cm, function () {\n      for (var i = kill.length - 1; i >= 0; i--)\n        { replaceRange(cm.doc, \"\", kill[i].from, kill[i].to, \"+delete\"); }\n      ensureCursorVisible(cm);\n    });\n  }\n\n  function moveCharLogically(line, ch, dir) {\n    var target = skipExtendingChars(line.text, ch + dir, dir);\n    return target < 0 || target > line.text.length ? null : target\n  }\n\n  function moveLogically(line, start, dir) {\n    var ch = moveCharLogically(line, start.ch, dir);\n    return ch == null ? null : new Pos(start.line, ch, dir < 0 ? \"after\" : \"before\")\n  }\n\n  function endOfLine(visually, cm, lineObj, lineNo, dir) {\n    if (visually) {\n      var order = getOrder(lineObj, cm.doc.direction);\n      if (order) {\n        var part = dir < 0 ? lst(order) : order[0];\n        var moveInStorageOrder = (dir < 0) == (part.level == 1);\n        var sticky = moveInStorageOrder ? \"after\" : \"before\";\n        var ch;\n        // With a wrapped rtl chunk (possibly spanning multiple bidi parts),\n        // it could be that the last bidi part is not on the last visual line,\n        // since visual lines contain content order-consecutive chunks.\n        // Thus, in rtl, we are looking for the first (content-order) character\n        // in the rtl chunk that is on the last line (that is, the same line\n        // as the last (content-order) character).\n        if (part.level > 0 || cm.doc.direction == \"rtl\") {\n          var prep = prepareMeasureForLine(cm, lineObj);\n          ch = dir < 0 ? lineObj.text.length - 1 : 0;\n          var targetTop = measureCharPrepared(cm, prep, ch).top;\n          ch = findFirst(function (ch) { return measureCharPrepared(cm, prep, ch).top == targetTop; }, (dir < 0) == (part.level == 1) ? part.from : part.to - 1, ch);\n          if (sticky == \"before\") { ch = moveCharLogically(lineObj, ch, 1); }\n        } else { ch = dir < 0 ? part.to : part.from; }\n        return new Pos(lineNo, ch, sticky)\n      }\n    }\n    return new Pos(lineNo, dir < 0 ? lineObj.text.length : 0, dir < 0 ? \"before\" : \"after\")\n  }\n\n  function moveVisually(cm, line, start, dir) {\n    var bidi = getOrder(line, cm.doc.direction);\n    if (!bidi) { return moveLogically(line, start, dir) }\n    if (start.ch >= line.text.length) {\n      start.ch = line.text.length;\n      start.sticky = \"before\";\n    } else if (start.ch <= 0) {\n      start.ch = 0;\n      start.sticky = \"after\";\n    }\n    var partPos = getBidiPartAt(bidi, start.ch, start.sticky), part = bidi[partPos];\n    if (cm.doc.direction == \"ltr\" && part.level % 2 == 0 && (dir > 0 ? part.to > start.ch : part.from < start.ch)) {\n      // Case 1: We move within an ltr part in an ltr editor. Even with wrapped lines,\n      // nothing interesting happens.\n      return moveLogically(line, start, dir)\n    }\n\n    var mv = function (pos, dir) { return moveCharLogically(line, pos instanceof Pos ? pos.ch : pos, dir); };\n    var prep;\n    var getWrappedLineExtent = function (ch) {\n      if (!cm.options.lineWrapping) { return {begin: 0, end: line.text.length} }\n      prep = prep || prepareMeasureForLine(cm, line);\n      return wrappedLineExtentChar(cm, line, prep, ch)\n    };\n    var wrappedLineExtent = getWrappedLineExtent(start.sticky == \"before\" ? mv(start, -1) : start.ch);\n\n    if (cm.doc.direction == \"rtl\" || part.level == 1) {\n      var moveInStorageOrder = (part.level == 1) == (dir < 0);\n      var ch = mv(start, moveInStorageOrder ? 1 : -1);\n      if (ch != null && (!moveInStorageOrder ? ch >= part.from && ch >= wrappedLineExtent.begin : ch <= part.to && ch <= wrappedLineExtent.end)) {\n        // Case 2: We move within an rtl part or in an rtl editor on the same visual line\n        var sticky = moveInStorageOrder ? \"before\" : \"after\";\n        return new Pos(start.line, ch, sticky)\n      }\n    }\n\n    // Case 3: Could not move within this bidi part in this visual line, so leave\n    // the current bidi part\n\n    var searchInVisualLine = function (partPos, dir, wrappedLineExtent) {\n      var getRes = function (ch, moveInStorageOrder) { return moveInStorageOrder\n        ? new Pos(start.line, mv(ch, 1), \"before\")\n        : new Pos(start.line, ch, \"after\"); };\n\n      for (; partPos >= 0 && partPos < bidi.length; partPos += dir) {\n        var part = bidi[partPos];\n        var moveInStorageOrder = (dir > 0) == (part.level != 1);\n        var ch = moveInStorageOrder ? wrappedLineExtent.begin : mv(wrappedLineExtent.end, -1);\n        if (part.from <= ch && ch < part.to) { return getRes(ch, moveInStorageOrder) }\n        ch = moveInStorageOrder ? part.from : mv(part.to, -1);\n        if (wrappedLineExtent.begin <= ch && ch < wrappedLineExtent.end) { return getRes(ch, moveInStorageOrder) }\n      }\n    };\n\n    // Case 3a: Look for other bidi parts on the same visual line\n    var res = searchInVisualLine(partPos + dir, dir, wrappedLineExtent);\n    if (res) { return res }\n\n    // Case 3b: Look for other bidi parts on the next visual line\n    var nextCh = dir > 0 ? wrappedLineExtent.end : mv(wrappedLineExtent.begin, -1);\n    if (nextCh != null && !(dir > 0 && nextCh == line.text.length)) {\n      res = searchInVisualLine(dir > 0 ? 0 : bidi.length - 1, dir, getWrappedLineExtent(nextCh));\n      if (res) { return res }\n    }\n\n    // Case 4: Nowhere to move\n    return null\n  }\n\n  // Commands are parameter-less actions that can be performed on an\n  // editor, mostly used for keybindings.\n  var commands = {\n    selectAll: selectAll,\n    singleSelection: function (cm) { return cm.setSelection(cm.getCursor(\"anchor\"), cm.getCursor(\"head\"), sel_dontScroll); },\n    killLine: function (cm) { return deleteNearSelection(cm, function (range) {\n      if (range.empty()) {\n        var len = getLine(cm.doc, range.head.line).text.length;\n        if (range.head.ch == len && range.head.line < cm.lastLine())\n          { return {from: range.head, to: Pos(range.head.line + 1, 0)} }\n        else\n          { return {from: range.head, to: Pos(range.head.line, len)} }\n      } else {\n        return {from: range.from(), to: range.to()}\n      }\n    }); },\n    deleteLine: function (cm) { return deleteNearSelection(cm, function (range) { return ({\n      from: Pos(range.from().line, 0),\n      to: clipPos(cm.doc, Pos(range.to().line + 1, 0))\n    }); }); },\n    delLineLeft: function (cm) { return deleteNearSelection(cm, function (range) { return ({\n      from: Pos(range.from().line, 0), to: range.from()\n    }); }); },\n    delWrappedLineLeft: function (cm) { return deleteNearSelection(cm, function (range) {\n      var top = cm.charCoords(range.head, \"div\").top + 5;\n      var leftPos = cm.coordsChar({left: 0, top: top}, \"div\");\n      return {from: leftPos, to: range.from()}\n    }); },\n    delWrappedLineRight: function (cm) { return deleteNearSelection(cm, function (range) {\n      var top = cm.charCoords(range.head, \"div\").top + 5;\n      var rightPos = cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, \"div\");\n      return {from: range.from(), to: rightPos }\n    }); },\n    undo: function (cm) { return cm.undo(); },\n    redo: function (cm) { return cm.redo(); },\n    undoSelection: function (cm) { return cm.undoSelection(); },\n    redoSelection: function (cm) { return cm.redoSelection(); },\n    goDocStart: function (cm) { return cm.extendSelection(Pos(cm.firstLine(), 0)); },\n    goDocEnd: function (cm) { return cm.extendSelection(Pos(cm.lastLine())); },\n    goLineStart: function (cm) { return cm.extendSelectionsBy(function (range) { return lineStart(cm, range.head.line); },\n      {origin: \"+move\", bias: 1}\n    ); },\n    goLineStartSmart: function (cm) { return cm.extendSelectionsBy(function (range) { return lineStartSmart(cm, range.head); },\n      {origin: \"+move\", bias: 1}\n    ); },\n    goLineEnd: function (cm) { return cm.extendSelectionsBy(function (range) { return lineEnd(cm, range.head.line); },\n      {origin: \"+move\", bias: -1}\n    ); },\n    goLineRight: function (cm) { return cm.extendSelectionsBy(function (range) {\n      var top = cm.cursorCoords(range.head, \"div\").top + 5;\n      return cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, \"div\")\n    }, sel_move); },\n    goLineLeft: function (cm) { return cm.extendSelectionsBy(function (range) {\n      var top = cm.cursorCoords(range.head, \"div\").top + 5;\n      return cm.coordsChar({left: 0, top: top}, \"div\")\n    }, sel_move); },\n    goLineLeftSmart: function (cm) { return cm.extendSelectionsBy(function (range) {\n      var top = cm.cursorCoords(range.head, \"div\").top + 5;\n      var pos = cm.coordsChar({left: 0, top: top}, \"div\");\n      if (pos.ch < cm.getLine(pos.line).search(/\\S/)) { return lineStartSmart(cm, range.head) }\n      return pos\n    }, sel_move); },\n    goLineUp: function (cm) { return cm.moveV(-1, \"line\"); },\n    goLineDown: function (cm) { return cm.moveV(1, \"line\"); },\n    goPageUp: function (cm) { return cm.moveV(-1, \"page\"); },\n    goPageDown: function (cm) { return cm.moveV(1, \"page\"); },\n    goCharLeft: function (cm) { return cm.moveH(-1, \"char\"); },\n    goCharRight: function (cm) { return cm.moveH(1, \"char\"); },\n    goColumnLeft: function (cm) { return cm.moveH(-1, \"column\"); },\n    goColumnRight: function (cm) { return cm.moveH(1, \"column\"); },\n    goWordLeft: function (cm) { return cm.moveH(-1, \"word\"); },\n    goGroupRight: function (cm) { return cm.moveH(1, \"group\"); },\n    goGroupLeft: function (cm) { return cm.moveH(-1, \"group\"); },\n    goWordRight: function (cm) { return cm.moveH(1, \"word\"); },\n    delCharBefore: function (cm) { return cm.deleteH(-1, \"char\"); },\n    delCharAfter: function (cm) { return cm.deleteH(1, \"char\"); },\n    delWordBefore: function (cm) { return cm.deleteH(-1, \"word\"); },\n    delWordAfter: function (cm) { return cm.deleteH(1, \"word\"); },\n    delGroupBefore: function (cm) { return cm.deleteH(-1, \"group\"); },\n    delGroupAfter: function (cm) { return cm.deleteH(1, \"group\"); },\n    indentAuto: function (cm) { return cm.indentSelection(\"smart\"); },\n    indentMore: function (cm) { return cm.indentSelection(\"add\"); },\n    indentLess: function (cm) { return cm.indentSelection(\"subtract\"); },\n    insertTab: function (cm) { return cm.replaceSelection(\"\\t\"); },\n    insertSoftTab: function (cm) {\n      var spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize;\n      for (var i = 0; i < ranges.length; i++) {\n        var pos = ranges[i].from();\n        var col = countColumn(cm.getLine(pos.line), pos.ch, tabSize);\n        spaces.push(spaceStr(tabSize - col % tabSize));\n      }\n      cm.replaceSelections(spaces);\n    },\n    defaultTab: function (cm) {\n      if (cm.somethingSelected()) { cm.indentSelection(\"add\"); }\n      else { cm.execCommand(\"insertTab\"); }\n    },\n    // Swap the two chars left and right of each selection's head.\n    // Move cursor behind the two swapped characters afterwards.\n    //\n    // Doesn't consider line feeds a character.\n    // Doesn't scan more than one line above to find a character.\n    // Doesn't do anything on an empty line.\n    // Doesn't do anything with non-empty selections.\n    transposeChars: function (cm) { return runInOp(cm, function () {\n      var ranges = cm.listSelections(), newSel = [];\n      for (var i = 0; i < ranges.length; i++) {\n        if (!ranges[i].empty()) { continue }\n        var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text;\n        if (line) {\n          if (cur.ch == line.length) { cur = new Pos(cur.line, cur.ch - 1); }\n          if (cur.ch > 0) {\n            cur = new Pos(cur.line, cur.ch + 1);\n            cm.replaceRange(line.charAt(cur.ch - 1) + line.charAt(cur.ch - 2),\n                            Pos(cur.line, cur.ch - 2), cur, \"+transpose\");\n          } else if (cur.line > cm.doc.first) {\n            var prev = getLine(cm.doc, cur.line - 1).text;\n            if (prev) {\n              cur = new Pos(cur.line, 1);\n              cm.replaceRange(line.charAt(0) + cm.doc.lineSeparator() +\n                              prev.charAt(prev.length - 1),\n                              Pos(cur.line - 1, prev.length - 1), cur, \"+transpose\");\n            }\n          }\n        }\n        newSel.push(new Range(cur, cur));\n      }\n      cm.setSelections(newSel);\n    }); },\n    newlineAndIndent: function (cm) { return runInOp(cm, function () {\n      var sels = cm.listSelections();\n      for (var i = sels.length - 1; i >= 0; i--)\n        { cm.replaceRange(cm.doc.lineSeparator(), sels[i].anchor, sels[i].head, \"+input\"); }\n      sels = cm.listSelections();\n      for (var i$1 = 0; i$1 < sels.length; i$1++)\n        { cm.indentLine(sels[i$1].from().line, null, true); }\n      ensureCursorVisible(cm);\n    }); },\n    openLine: function (cm) { return cm.replaceSelection(\"\\n\", \"start\"); },\n    toggleOverwrite: function (cm) { return cm.toggleOverwrite(); }\n  };\n\n\n  function lineStart(cm, lineN) {\n    var line = getLine(cm.doc, lineN);\n    var visual = visualLine(line);\n    if (visual != line) { lineN = lineNo(visual); }\n    return endOfLine(true, cm, visual, lineN, 1)\n  }\n  function lineEnd(cm, lineN) {\n    var line = getLine(cm.doc, lineN);\n    var visual = visualLineEnd(line);\n    if (visual != line) { lineN = lineNo(visual); }\n    return endOfLine(true, cm, line, lineN, -1)\n  }\n  function lineStartSmart(cm, pos) {\n    var start = lineStart(cm, pos.line);\n    var line = getLine(cm.doc, start.line);\n    var order = getOrder(line, cm.doc.direction);\n    if (!order || order[0].level == 0) {\n      var firstNonWS = Math.max(0, line.text.search(/\\S/));\n      var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch;\n      return Pos(start.line, inWS ? 0 : firstNonWS, start.sticky)\n    }\n    return start\n  }\n\n  // Run a handler that was bound to a key.\n  function doHandleBinding(cm, bound, dropShift) {\n    if (typeof bound == \"string\") {\n      bound = commands[bound];\n      if (!bound) { return false }\n    }\n    // Ensure previous input has been read, so that the handler sees a\n    // consistent view of the document\n    cm.display.input.ensurePolled();\n    var prevShift = cm.display.shift, done = false;\n    try {\n      if (cm.isReadOnly()) { cm.state.suppressEdits = true; }\n      if (dropShift) { cm.display.shift = false; }\n      done = bound(cm) != Pass;\n    } finally {\n      cm.display.shift = prevShift;\n      cm.state.suppressEdits = false;\n    }\n    return done\n  }\n\n  function lookupKeyForEditor(cm, name, handle) {\n    for (var i = 0; i < cm.state.keyMaps.length; i++) {\n      var result = lookupKey(name, cm.state.keyMaps[i], handle, cm);\n      if (result) { return result }\n    }\n    return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle, cm))\n      || lookupKey(name, cm.options.keyMap, handle, cm)\n  }\n\n  // Note that, despite the name, this function is also used to check\n  // for bound mouse clicks.\n\n  var stopSeq = new Delayed;\n\n  function dispatchKey(cm, name, e, handle) {\n    var seq = cm.state.keySeq;\n    if (seq) {\n      if (isModifierKey(name)) { return \"handled\" }\n      if (/\\'$/.test(name))\n        { cm.state.keySeq = null; }\n      else\n        { stopSeq.set(50, function () {\n          if (cm.state.keySeq == seq) {\n            cm.state.keySeq = null;\n            cm.display.input.reset();\n          }\n        }); }\n      if (dispatchKeyInner(cm, seq + \" \" + name, e, handle)) { return true }\n    }\n    return dispatchKeyInner(cm, name, e, handle)\n  }\n\n  function dispatchKeyInner(cm, name, e, handle) {\n    var result = lookupKeyForEditor(cm, name, handle);\n\n    if (result == \"multi\")\n      { cm.state.keySeq = name; }\n    if (result == \"handled\")\n      { signalLater(cm, \"keyHandled\", cm, name, e); }\n\n    if (result == \"handled\" || result == \"multi\") {\n      e_preventDefault(e);\n      restartBlink(cm);\n    }\n\n    return !!result\n  }\n\n  // Handle a key from the keydown event.\n  function handleKeyBinding(cm, e) {\n    var name = keyName(e, true);\n    if (!name) { return false }\n\n    if (e.shiftKey && !cm.state.keySeq) {\n      // First try to resolve full name (including 'Shift-'). Failing\n      // that, see if there is a cursor-motion command (starting with\n      // 'go') bound to the keyname without 'Shift-'.\n      return dispatchKey(cm, \"Shift-\" + name, e, function (b) { return doHandleBinding(cm, b, true); })\n          || dispatchKey(cm, name, e, function (b) {\n               if (typeof b == \"string\" ? /^go[A-Z]/.test(b) : b.motion)\n                 { return doHandleBinding(cm, b) }\n             })\n    } else {\n      return dispatchKey(cm, name, e, function (b) { return doHandleBinding(cm, b); })\n    }\n  }\n\n  // Handle a key from the keypress event\n  function handleCharBinding(cm, e, ch) {\n    return dispatchKey(cm, \"'\" + ch + \"'\", e, function (b) { return doHandleBinding(cm, b, true); })\n  }\n\n  var lastStoppedKey = null;\n  function onKeyDown(e) {\n    var cm = this;\n    cm.curOp.focus = activeElt();\n    if (signalDOMEvent(cm, e)) { return }\n    // IE does strange things with escape.\n    if (ie && ie_version < 11 && e.keyCode == 27) { e.returnValue = false; }\n    var code = e.keyCode;\n    cm.display.shift = code == 16 || e.shiftKey;\n    var handled = handleKeyBinding(cm, e);\n    if (presto) {\n      lastStoppedKey = handled ? code : null;\n      // Opera has no cut event... we try to at least catch the key combo\n      if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey))\n        { cm.replaceSelection(\"\", null, \"cut\"); }\n    }\n\n    // Turn mouse into crosshair when Alt is held on Mac.\n    if (code == 18 && !/\\bCodeMirror-crosshair\\b/.test(cm.display.lineDiv.className))\n      { showCrossHair(cm); }\n  }\n\n  function showCrossHair(cm) {\n    var lineDiv = cm.display.lineDiv;\n    addClass(lineDiv, \"CodeMirror-crosshair\");\n\n    function up(e) {\n      if (e.keyCode == 18 || !e.altKey) {\n        rmClass(lineDiv, \"CodeMirror-crosshair\");\n        off(document, \"keyup\", up);\n        off(document, \"mouseover\", up);\n      }\n    }\n    on(document, \"keyup\", up);\n    on(document, \"mouseover\", up);\n  }\n\n  function onKeyUp(e) {\n    if (e.keyCode == 16) { this.doc.sel.shift = false; }\n    signalDOMEvent(this, e);\n  }\n\n  function onKeyPress(e) {\n    var cm = this;\n    if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) { return }\n    var keyCode = e.keyCode, charCode = e.charCode;\n    if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return}\n    if ((presto && (!e.which || e.which < 10)) && handleKeyBinding(cm, e)) { return }\n    var ch = String.fromCharCode(charCode == null ? keyCode : charCode);\n    // Some browsers fire keypress events for backspace\n    if (ch == \"\\x08\") { return }\n    if (handleCharBinding(cm, e, ch)) { return }\n    cm.display.input.onKeyPress(e);\n  }\n\n  var DOUBLECLICK_DELAY = 400;\n\n  var PastClick = function(time, pos, button) {\n    this.time = time;\n    this.pos = pos;\n    this.button = button;\n  };\n\n  PastClick.prototype.compare = function (time, pos, button) {\n    return this.time + DOUBLECLICK_DELAY > time &&\n      cmp(pos, this.pos) == 0 && button == this.button\n  };\n\n  var lastClick, lastDoubleClick;\n  function clickRepeat(pos, button) {\n    var now = +new Date;\n    if (lastDoubleClick && lastDoubleClick.compare(now, pos, button)) {\n      lastClick = lastDoubleClick = null;\n      return \"triple\"\n    } else if (lastClick && lastClick.compare(now, pos, button)) {\n      lastDoubleClick = new PastClick(now, pos, button);\n      lastClick = null;\n      return \"double\"\n    } else {\n      lastClick = new PastClick(now, pos, button);\n      lastDoubleClick = null;\n      return \"single\"\n    }\n  }\n\n  // A mouse down can be a single click, double click, triple click,\n  // start of selection drag, start of text drag, new cursor\n  // (ctrl-click), rectangle drag (alt-drag), or xwin\n  // middle-click-paste. Or it might be a click on something we should\n  // not interfere with, such as a scrollbar or widget.\n  function onMouseDown(e) {\n    var cm = this, display = cm.display;\n    if (signalDOMEvent(cm, e) || display.activeTouch && display.input.supportsTouch()) { return }\n    display.input.ensurePolled();\n    display.shift = e.shiftKey;\n\n    if (eventInWidget(display, e)) {\n      if (!webkit) {\n        // Briefly turn off draggability, to allow widgets to do\n        // normal dragging things.\n        display.scroller.draggable = false;\n        setTimeout(function () { return display.scroller.draggable = true; }, 100);\n      }\n      return\n    }\n    if (clickInGutter(cm, e)) { return }\n    var pos = posFromMouse(cm, e), button = e_button(e), repeat = pos ? clickRepeat(pos, button) : \"single\";\n    window.focus();\n\n    // #3261: make sure, that we're not starting a second selection\n    if (button == 1 && cm.state.selectingText)\n      { cm.state.selectingText(e); }\n\n    if (pos && handleMappedButton(cm, button, pos, repeat, e)) { return }\n\n    if (button == 1) {\n      if (pos) { leftButtonDown(cm, pos, repeat, e); }\n      else if (e_target(e) == display.scroller) { e_preventDefault(e); }\n    } else if (button == 2) {\n      if (pos) { extendSelection(cm.doc, pos); }\n      setTimeout(function () { return display.input.focus(); }, 20);\n    } else if (button == 3) {\n      if (captureRightClick) { cm.display.input.onContextMenu(e); }\n      else { delayBlurEvent(cm); }\n    }\n  }\n\n  function handleMappedButton(cm, button, pos, repeat, event) {\n    var name = \"Click\";\n    if (repeat == \"double\") { name = \"Double\" + name; }\n    else if (repeat == \"triple\") { name = \"Triple\" + name; }\n    name = (button == 1 ? \"Left\" : button == 2 ? \"Middle\" : \"Right\") + name;\n\n    return dispatchKey(cm,  addModifierNames(name, event), event, function (bound) {\n      if (typeof bound == \"string\") { bound = commands[bound]; }\n      if (!bound) { return false }\n      var done = false;\n      try {\n        if (cm.isReadOnly()) { cm.state.suppressEdits = true; }\n        done = bound(cm, pos) != Pass;\n      } finally {\n        cm.state.suppressEdits = false;\n      }\n      return done\n    })\n  }\n\n  function configureMouse(cm, repeat, event) {\n    var option = cm.getOption(\"configureMouse\");\n    var value = option ? option(cm, repeat, event) : {};\n    if (value.unit == null) {\n      var rect = chromeOS ? event.shiftKey && event.metaKey : event.altKey;\n      value.unit = rect ? \"rectangle\" : repeat == \"single\" ? \"char\" : repeat == \"double\" ? \"word\" : \"line\";\n    }\n    if (value.extend == null || cm.doc.extend) { value.extend = cm.doc.extend || event.shiftKey; }\n    if (value.addNew == null) { value.addNew = mac ? event.metaKey : event.ctrlKey; }\n    if (value.moveOnDrag == null) { value.moveOnDrag = !(mac ? event.altKey : event.ctrlKey); }\n    return value\n  }\n\n  function leftButtonDown(cm, pos, repeat, event) {\n    if (ie) { setTimeout(bind(ensureFocus, cm), 0); }\n    else { cm.curOp.focus = activeElt(); }\n\n    var behavior = configureMouse(cm, repeat, event);\n\n    var sel = cm.doc.sel, contained;\n    if (cm.options.dragDrop && dragAndDrop && !cm.isReadOnly() &&\n        repeat == \"single\" && (contained = sel.contains(pos)) > -1 &&\n        (cmp((contained = sel.ranges[contained]).from(), pos) < 0 || pos.xRel > 0) &&\n        (cmp(contained.to(), pos) > 0 || pos.xRel < 0))\n      { leftButtonStartDrag(cm, event, pos, behavior); }\n    else\n      { leftButtonSelect(cm, event, pos, behavior); }\n  }\n\n  // Start a text drag. When it ends, see if any dragging actually\n  // happen, and treat as a click if it didn't.\n  function leftButtonStartDrag(cm, event, pos, behavior) {\n    var display = cm.display, moved = false;\n    var dragEnd = operation(cm, function (e) {\n      if (webkit) { display.scroller.draggable = false; }\n      cm.state.draggingText = false;\n      off(display.wrapper.ownerDocument, \"mouseup\", dragEnd);\n      off(display.wrapper.ownerDocument, \"mousemove\", mouseMove);\n      off(display.scroller, \"dragstart\", dragStart);\n      off(display.scroller, \"drop\", dragEnd);\n      if (!moved) {\n        e_preventDefault(e);\n        if (!behavior.addNew)\n          { extendSelection(cm.doc, pos, null, null, behavior.extend); }\n        // Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081)\n        if (webkit || ie && ie_version == 9)\n          { setTimeout(function () {display.wrapper.ownerDocument.body.focus(); display.input.focus();}, 20); }\n        else\n          { display.input.focus(); }\n      }\n    });\n    var mouseMove = function(e2) {\n      moved = moved || Math.abs(event.clientX - e2.clientX) + Math.abs(event.clientY - e2.clientY) >= 10;\n    };\n    var dragStart = function () { return moved = true; };\n    // Let the drag handler handle this.\n    if (webkit) { display.scroller.draggable = true; }\n    cm.state.draggingText = dragEnd;\n    dragEnd.copy = !behavior.moveOnDrag;\n    // IE's approach to draggable\n    if (display.scroller.dragDrop) { display.scroller.dragDrop(); }\n    on(display.wrapper.ownerDocument, \"mouseup\", dragEnd);\n    on(display.wrapper.ownerDocument, \"mousemove\", mouseMove);\n    on(display.scroller, \"dragstart\", dragStart);\n    on(display.scroller, \"drop\", dragEnd);\n\n    delayBlurEvent(cm);\n    setTimeout(function () { return display.input.focus(); }, 20);\n  }\n\n  function rangeForUnit(cm, pos, unit) {\n    if (unit == \"char\") { return new Range(pos, pos) }\n    if (unit == \"word\") { return cm.findWordAt(pos) }\n    if (unit == \"line\") { return new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0))) }\n    var result = unit(cm, pos);\n    return new Range(result.from, result.to)\n  }\n\n  // Normal selection, as opposed to text dragging.\n  function leftButtonSelect(cm, event, start, behavior) {\n    var display = cm.display, doc = cm.doc;\n    e_preventDefault(event);\n\n    var ourRange, ourIndex, startSel = doc.sel, ranges = startSel.ranges;\n    if (behavior.addNew && !behavior.extend) {\n      ourIndex = doc.sel.contains(start);\n      if (ourIndex > -1)\n        { ourRange = ranges[ourIndex]; }\n      else\n        { ourRange = new Range(start, start); }\n    } else {\n      ourRange = doc.sel.primary();\n      ourIndex = doc.sel.primIndex;\n    }\n\n    if (behavior.unit == \"rectangle\") {\n      if (!behavior.addNew) { ourRange = new Range(start, start); }\n      start = posFromMouse(cm, event, true, true);\n      ourIndex = -1;\n    } else {\n      var range$$1 = rangeForUnit(cm, start, behavior.unit);\n      if (behavior.extend)\n        { ourRange = extendRange(ourRange, range$$1.anchor, range$$1.head, behavior.extend); }\n      else\n        { ourRange = range$$1; }\n    }\n\n    if (!behavior.addNew) {\n      ourIndex = 0;\n      setSelection(doc, new Selection([ourRange], 0), sel_mouse);\n      startSel = doc.sel;\n    } else if (ourIndex == -1) {\n      ourIndex = ranges.length;\n      setSelection(doc, normalizeSelection(cm, ranges.concat([ourRange]), ourIndex),\n                   {scroll: false, origin: \"*mouse\"});\n    } else if (ranges.length > 1 && ranges[ourIndex].empty() && behavior.unit == \"char\" && !behavior.extend) {\n      setSelection(doc, normalizeSelection(cm, ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0),\n                   {scroll: false, origin: \"*mouse\"});\n      startSel = doc.sel;\n    } else {\n      replaceOneSelection(doc, ourIndex, ourRange, sel_mouse);\n    }\n\n    var lastPos = start;\n    function extendTo(pos) {\n      if (cmp(lastPos, pos) == 0) { return }\n      lastPos = pos;\n\n      if (behavior.unit == \"rectangle\") {\n        var ranges = [], tabSize = cm.options.tabSize;\n        var startCol = countColumn(getLine(doc, start.line).text, start.ch, tabSize);\n        var posCol = countColumn(getLine(doc, pos.line).text, pos.ch, tabSize);\n        var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol);\n        for (var line = Math.min(start.line, pos.line), end = Math.min(cm.lastLine(), Math.max(start.line, pos.line));\n             line <= end; line++) {\n          var text = getLine(doc, line).text, leftPos = findColumn(text, left, tabSize);\n          if (left == right)\n            { ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos))); }\n          else if (text.length > leftPos)\n            { ranges.push(new Range(Pos(line, leftPos), Pos(line, findColumn(text, right, tabSize)))); }\n        }\n        if (!ranges.length) { ranges.push(new Range(start, start)); }\n        setSelection(doc, normalizeSelection(cm, startSel.ranges.slice(0, ourIndex).concat(ranges), ourIndex),\n                     {origin: \"*mouse\", scroll: false});\n        cm.scrollIntoView(pos);\n      } else {\n        var oldRange = ourRange;\n        var range$$1 = rangeForUnit(cm, pos, behavior.unit);\n        var anchor = oldRange.anchor, head;\n        if (cmp(range$$1.anchor, anchor) > 0) {\n          head = range$$1.head;\n          anchor = minPos(oldRange.from(), range$$1.anchor);\n        } else {\n          head = range$$1.anchor;\n          anchor = maxPos(oldRange.to(), range$$1.head);\n        }\n        var ranges$1 = startSel.ranges.slice(0);\n        ranges$1[ourIndex] = bidiSimplify(cm, new Range(clipPos(doc, anchor), head));\n        setSelection(doc, normalizeSelection(cm, ranges$1, ourIndex), sel_mouse);\n      }\n    }\n\n    var editorSize = display.wrapper.getBoundingClientRect();\n    // Used to ensure timeout re-tries don't fire when another extend\n    // happened in the meantime (clearTimeout isn't reliable -- at\n    // least on Chrome, the timeouts still happen even when cleared,\n    // if the clear happens after their scheduled firing time).\n    var counter = 0;\n\n    function extend(e) {\n      var curCount = ++counter;\n      var cur = posFromMouse(cm, e, true, behavior.unit == \"rectangle\");\n      if (!cur) { return }\n      if (cmp(cur, lastPos) != 0) {\n        cm.curOp.focus = activeElt();\n        extendTo(cur);\n        var visible = visibleLines(display, doc);\n        if (cur.line >= visible.to || cur.line < visible.from)\n          { setTimeout(operation(cm, function () {if (counter == curCount) { extend(e); }}), 150); }\n      } else {\n        var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0;\n        if (outside) { setTimeout(operation(cm, function () {\n          if (counter != curCount) { return }\n          display.scroller.scrollTop += outside;\n          extend(e);\n        }), 50); }\n      }\n    }\n\n    function done(e) {\n      cm.state.selectingText = false;\n      counter = Infinity;\n      e_preventDefault(e);\n      display.input.focus();\n      off(display.wrapper.ownerDocument, \"mousemove\", move);\n      off(display.wrapper.ownerDocument, \"mouseup\", up);\n      doc.history.lastSelOrigin = null;\n    }\n\n    var move = operation(cm, function (e) {\n      if (e.buttons === 0 || !e_button(e)) { done(e); }\n      else { extend(e); }\n    });\n    var up = operation(cm, done);\n    cm.state.selectingText = up;\n    on(display.wrapper.ownerDocument, \"mousemove\", move);\n    on(display.wrapper.ownerDocument, \"mouseup\", up);\n  }\n\n  // Used when mouse-selecting to adjust the anchor to the proper side\n  // of a bidi jump depending on the visual position of the head.\n  function bidiSimplify(cm, range$$1) {\n    var anchor = range$$1.anchor;\n    var head = range$$1.head;\n    var anchorLine = getLine(cm.doc, anchor.line);\n    if (cmp(anchor, head) == 0 && anchor.sticky == head.sticky) { return range$$1 }\n    var order = getOrder(anchorLine);\n    if (!order) { return range$$1 }\n    var index = getBidiPartAt(order, anchor.ch, anchor.sticky), part = order[index];\n    if (part.from != anchor.ch && part.to != anchor.ch) { return range$$1 }\n    var boundary = index + ((part.from == anchor.ch) == (part.level != 1) ? 0 : 1);\n    if (boundary == 0 || boundary == order.length) { return range$$1 }\n\n    // Compute the relative visual position of the head compared to the\n    // anchor (<0 is to the left, >0 to the right)\n    var leftSide;\n    if (head.line != anchor.line) {\n      leftSide = (head.line - anchor.line) * (cm.doc.direction == \"ltr\" ? 1 : -1) > 0;\n    } else {\n      var headIndex = getBidiPartAt(order, head.ch, head.sticky);\n      var dir = headIndex - index || (head.ch - anchor.ch) * (part.level == 1 ? -1 : 1);\n      if (headIndex == boundary - 1 || headIndex == boundary)\n        { leftSide = dir < 0; }\n      else\n        { leftSide = dir > 0; }\n    }\n\n    var usePart = order[boundary + (leftSide ? -1 : 0)];\n    var from = leftSide == (usePart.level == 1);\n    var ch = from ? usePart.from : usePart.to, sticky = from ? \"after\" : \"before\";\n    return anchor.ch == ch && anchor.sticky == sticky ? range$$1 : new Range(new Pos(anchor.line, ch, sticky), head)\n  }\n\n\n  // Determines whether an event happened in the gutter, and fires the\n  // handlers for the corresponding event.\n  function gutterEvent(cm, e, type, prevent) {\n    var mX, mY;\n    if (e.touches) {\n      mX = e.touches[0].clientX;\n      mY = e.touches[0].clientY;\n    } else {\n      try { mX = e.clientX; mY = e.clientY; }\n      catch(e) { return false }\n    }\n    if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) { return false }\n    if (prevent) { e_preventDefault(e); }\n\n    var display = cm.display;\n    var lineBox = display.lineDiv.getBoundingClientRect();\n\n    if (mY > lineBox.bottom || !hasHandler(cm, type)) { return e_defaultPrevented(e) }\n    mY -= lineBox.top - display.viewOffset;\n\n    for (var i = 0; i < cm.options.gutters.length; ++i) {\n      var g = display.gutters.childNodes[i];\n      if (g && g.getBoundingClientRect().right >= mX) {\n        var line = lineAtHeight(cm.doc, mY);\n        var gutter = cm.options.gutters[i];\n        signal(cm, type, cm, line, gutter, e);\n        return e_defaultPrevented(e)\n      }\n    }\n  }\n\n  function clickInGutter(cm, e) {\n    return gutterEvent(cm, e, \"gutterClick\", true)\n  }\n\n  // CONTEXT MENU HANDLING\n\n  // To make the context menu work, we need to briefly unhide the\n  // textarea (making it as unobtrusive as possible) to let the\n  // right-click take effect on it.\n  function onContextMenu(cm, e) {\n    if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) { return }\n    if (signalDOMEvent(cm, e, \"contextmenu\")) { return }\n    if (!captureRightClick) { cm.display.input.onContextMenu(e); }\n  }\n\n  function contextMenuInGutter(cm, e) {\n    if (!hasHandler(cm, \"gutterContextMenu\")) { return false }\n    return gutterEvent(cm, e, \"gutterContextMenu\", false)\n  }\n\n  function themeChanged(cm) {\n    cm.display.wrapper.className = cm.display.wrapper.className.replace(/\\s*cm-s-\\S+/g, \"\") +\n      cm.options.theme.replace(/(^|\\s)\\s*/g, \" cm-s-\");\n    clearCaches(cm);\n  }\n\n  var Init = {toString: function(){return \"CodeMirror.Init\"}};\n\n  var defaults = {};\n  var optionHandlers = {};\n\n  function defineOptions(CodeMirror) {\n    var optionHandlers = CodeMirror.optionHandlers;\n\n    function option(name, deflt, handle, notOnInit) {\n      CodeMirror.defaults[name] = deflt;\n      if (handle) { optionHandlers[name] =\n        notOnInit ? function (cm, val, old) {if (old != Init) { handle(cm, val, old); }} : handle; }\n    }\n\n    CodeMirror.defineOption = option;\n\n    // Passed to option handlers when there is no old value.\n    CodeMirror.Init = Init;\n\n    // These two are, on init, called from the constructor because they\n    // have to be initialized before the editor can start at all.\n    option(\"value\", \"\", function (cm, val) { return cm.setValue(val); }, true);\n    option(\"mode\", null, function (cm, val) {\n      cm.doc.modeOption = val;\n      loadMode(cm);\n    }, true);\n\n    option(\"indentUnit\", 2, loadMode, true);\n    option(\"indentWithTabs\", false);\n    option(\"smartIndent\", true);\n    option(\"tabSize\", 4, function (cm) {\n      resetModeState(cm);\n      clearCaches(cm);\n      regChange(cm);\n    }, true);\n\n    option(\"lineSeparator\", null, function (cm, val) {\n      cm.doc.lineSep = val;\n      if (!val) { return }\n      var newBreaks = [], lineNo = cm.doc.first;\n      cm.doc.iter(function (line) {\n        for (var pos = 0;;) {\n          var found = line.text.indexOf(val, pos);\n          if (found == -1) { break }\n          pos = found + val.length;\n          newBreaks.push(Pos(lineNo, found));\n        }\n        lineNo++;\n      });\n      for (var i = newBreaks.length - 1; i >= 0; i--)\n        { replaceRange(cm.doc, val, newBreaks[i], Pos(newBreaks[i].line, newBreaks[i].ch + val.length)); }\n    });\n    option(\"specialChars\", /[\\u0000-\\u001f\\u007f-\\u009f\\u00ad\\u061c\\u200b-\\u200f\\u2028\\u2029\\ufeff]/g, function (cm, val, old) {\n      cm.state.specialChars = new RegExp(val.source + (val.test(\"\\t\") ? \"\" : \"|\\t\"), \"g\");\n      if (old != Init) { cm.refresh(); }\n    });\n    option(\"specialCharPlaceholder\", defaultSpecialCharPlaceholder, function (cm) { return cm.refresh(); }, true);\n    option(\"electricChars\", true);\n    option(\"inputStyle\", mobile ? \"contenteditable\" : \"textarea\", function () {\n      throw new Error(\"inputStyle can not (yet) be changed in a running editor\") // FIXME\n    }, true);\n    option(\"spellcheck\", false, function (cm, val) { return cm.getInputField().spellcheck = val; }, true);\n    option(\"rtlMoveVisually\", !windows);\n    option(\"wholeLineUpdateBefore\", true);\n\n    option(\"theme\", \"default\", function (cm) {\n      themeChanged(cm);\n      guttersChanged(cm);\n    }, true);\n    option(\"keyMap\", \"default\", function (cm, val, old) {\n      var next = getKeyMap(val);\n      var prev = old != Init && getKeyMap(old);\n      if (prev && prev.detach) { prev.detach(cm, next); }\n      if (next.attach) { next.attach(cm, prev || null); }\n    });\n    option(\"extraKeys\", null);\n    option(\"configureMouse\", null);\n\n    option(\"lineWrapping\", false, wrappingChanged, true);\n    option(\"gutters\", [], function (cm) {\n      setGuttersForLineNumbers(cm.options);\n      guttersChanged(cm);\n    }, true);\n    option(\"fixedGutter\", true, function (cm, val) {\n      cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + \"px\" : \"0\";\n      cm.refresh();\n    }, true);\n    option(\"coverGutterNextToScrollbar\", false, function (cm) { return updateScrollbars(cm); }, true);\n    option(\"scrollbarStyle\", \"native\", function (cm) {\n      initScrollbars(cm);\n      updateScrollbars(cm);\n      cm.display.scrollbars.setScrollTop(cm.doc.scrollTop);\n      cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft);\n    }, true);\n    option(\"lineNumbers\", false, function (cm) {\n      setGuttersForLineNumbers(cm.options);\n      guttersChanged(cm);\n    }, true);\n    option(\"firstLineNumber\", 1, guttersChanged, true);\n    option(\"lineNumberFormatter\", function (integer) { return integer; }, guttersChanged, true);\n    option(\"showCursorWhenSelecting\", false, updateSelection, true);\n\n    option(\"resetSelectionOnContextMenu\", true);\n    option(\"lineWiseCopyCut\", true);\n    option(\"pasteLinesPerSelection\", true);\n    option(\"selectionsMayTouch\", false);\n\n    option(\"readOnly\", false, function (cm, val) {\n      if (val == \"nocursor\") {\n        onBlur(cm);\n        cm.display.input.blur();\n      }\n      cm.display.input.readOnlyChanged(val);\n    });\n    option(\"disableInput\", false, function (cm, val) {if (!val) { cm.display.input.reset(); }}, true);\n    option(\"dragDrop\", true, dragDropChanged);\n    option(\"allowDropFileTypes\", null);\n\n    option(\"cursorBlinkRate\", 530);\n    option(\"cursorScrollMargin\", 0);\n    option(\"cursorHeight\", 1, updateSelection, true);\n    option(\"singleCursorHeightPerLine\", true, updateSelection, true);\n    option(\"workTime\", 100);\n    option(\"workDelay\", 100);\n    option(\"flattenSpans\", true, resetModeState, true);\n    option(\"addModeClass\", false, resetModeState, true);\n    option(\"pollInterval\", 100);\n    option(\"undoDepth\", 200, function (cm, val) { return cm.doc.history.undoDepth = val; });\n    option(\"historyEventDelay\", 1250);\n    option(\"viewportMargin\", 10, function (cm) { return cm.refresh(); }, true);\n    option(\"maxHighlightLength\", 10000, resetModeState, true);\n    option(\"moveInputWithCursor\", true, function (cm, val) {\n      if (!val) { cm.display.input.resetPosition(); }\n    });\n\n    option(\"tabindex\", null, function (cm, val) { return cm.display.input.getField().tabIndex = val || \"\"; });\n    option(\"autofocus\", null);\n    option(\"direction\", \"ltr\", function (cm, val) { return cm.doc.setDirection(val); }, true);\n    option(\"phrases\", null);\n  }\n\n  function guttersChanged(cm) {\n    updateGutters(cm);\n    regChange(cm);\n    alignHorizontally(cm);\n  }\n\n  function dragDropChanged(cm, value, old) {\n    var wasOn = old && old != Init;\n    if (!value != !wasOn) {\n      var funcs = cm.display.dragFunctions;\n      var toggle = value ? on : off;\n      toggle(cm.display.scroller, \"dragstart\", funcs.start);\n      toggle(cm.display.scroller, \"dragenter\", funcs.enter);\n      toggle(cm.display.scroller, \"dragover\", funcs.over);\n      toggle(cm.display.scroller, \"dragleave\", funcs.leave);\n      toggle(cm.display.scroller, \"drop\", funcs.drop);\n    }\n  }\n\n  function wrappingChanged(cm) {\n    if (cm.options.lineWrapping) {\n      addClass(cm.display.wrapper, \"CodeMirror-wrap\");\n      cm.display.sizer.style.minWidth = \"\";\n      cm.display.sizerWidth = null;\n    } else {\n      rmClass(cm.display.wrapper, \"CodeMirror-wrap\");\n      findMaxLine(cm);\n    }\n    estimateLineHeights(cm);\n    regChange(cm);\n    clearCaches(cm);\n    setTimeout(function () { return updateScrollbars(cm); }, 100);\n  }\n\n  // A CodeMirror instance represents an editor. This is the object\n  // that user code is usually dealing with.\n\n  function CodeMirror(place, options) {\n    var this$1 = this;\n\n    if (!(this instanceof CodeMirror)) { return new CodeMirror(place, options) }\n\n    this.options = options = options ? copyObj(options) : {};\n    // Determine effective options based on given values and defaults.\n    copyObj(defaults, options, false);\n    setGuttersForLineNumbers(options);\n\n    var doc = options.value;\n    if (typeof doc == \"string\") { doc = new Doc(doc, options.mode, null, options.lineSeparator, options.direction); }\n    else if (options.mode) { doc.modeOption = options.mode; }\n    this.doc = doc;\n\n    var input = new CodeMirror.inputStyles[options.inputStyle](this);\n    var display = this.display = new Display(place, doc, input);\n    display.wrapper.CodeMirror = this;\n    updateGutters(this);\n    themeChanged(this);\n    if (options.lineWrapping)\n      { this.display.wrapper.className += \" CodeMirror-wrap\"; }\n    initScrollbars(this);\n\n    this.state = {\n      keyMaps: [],  // stores maps added by addKeyMap\n      overlays: [], // highlighting overlays, as added by addOverlay\n      modeGen: 0,   // bumped when mode/overlay changes, used to invalidate highlighting info\n      overwrite: false,\n      delayingBlurEvent: false,\n      focused: false,\n      suppressEdits: false, // used to disable editing during key handlers when in readOnly mode\n      pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edits in input.poll\n      selectingText: false,\n      draggingText: false,\n      highlight: new Delayed(), // stores highlight worker timeout\n      keySeq: null,  // Unfinished key sequence\n      specialChars: null\n    };\n\n    if (options.autofocus && !mobile) { display.input.focus(); }\n\n    // Override magic textarea content restore that IE sometimes does\n    // on our hidden textarea on reload\n    if (ie && ie_version < 11) { setTimeout(function () { return this$1.display.input.reset(true); }, 20); }\n\n    registerEventHandlers(this);\n    ensureGlobalHandlers();\n\n    startOperation(this);\n    this.curOp.forceUpdate = true;\n    attachDoc(this, doc);\n\n    if ((options.autofocus && !mobile) || this.hasFocus())\n      { setTimeout(bind(onFocus, this), 20); }\n    else\n      { onBlur(this); }\n\n    for (var opt in optionHandlers) { if (optionHandlers.hasOwnProperty(opt))\n      { optionHandlers[opt](this$1, options[opt], Init); } }\n    maybeUpdateLineNumberWidth(this);\n    if (options.finishInit) { options.finishInit(this); }\n    for (var i = 0; i < initHooks.length; ++i) { initHooks[i](this$1); }\n    endOperation(this);\n    // Suppress optimizelegibility in Webkit, since it breaks text\n    // measuring on line wrapping boundaries.\n    if (webkit && options.lineWrapping &&\n        getComputedStyle(display.lineDiv).textRendering == \"optimizelegibility\")\n      { display.lineDiv.style.textRendering = \"auto\"; }\n  }\n\n  // The default configuration options.\n  CodeMirror.defaults = defaults;\n  // Functions to run when options are changed.\n  CodeMirror.optionHandlers = optionHandlers;\n\n  // Attach the necessary event handlers when initializing the editor\n  function registerEventHandlers(cm) {\n    var d = cm.display;\n    on(d.scroller, \"mousedown\", operation(cm, onMouseDown));\n    // Older IE's will not fire a second mousedown for a double click\n    if (ie && ie_version < 11)\n      { on(d.scroller, \"dblclick\", operation(cm, function (e) {\n        if (signalDOMEvent(cm, e)) { return }\n        var pos = posFromMouse(cm, e);\n        if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) { return }\n        e_preventDefault(e);\n        var word = cm.findWordAt(pos);\n        extendSelection(cm.doc, word.anchor, word.head);\n      })); }\n    else\n      { on(d.scroller, \"dblclick\", function (e) { return signalDOMEvent(cm, e) || e_preventDefault(e); }); }\n    // Some browsers fire contextmenu *after* opening the menu, at\n    // which point we can't mess with it anymore. Context menu is\n    // handled in onMouseDown for these browsers.\n    on(d.scroller, \"contextmenu\", function (e) { return onContextMenu(cm, e); });\n\n    // Used to suppress mouse event handling when a touch happens\n    var touchFinished, prevTouch = {end: 0};\n    function finishTouch() {\n      if (d.activeTouch) {\n        touchFinished = setTimeout(function () { return d.activeTouch = null; }, 1000);\n        prevTouch = d.activeTouch;\n        prevTouch.end = +new Date;\n      }\n    }\n    function isMouseLikeTouchEvent(e) {\n      if (e.touches.length != 1) { return false }\n      var touch = e.touches[0];\n      return touch.radiusX <= 1 && touch.radiusY <= 1\n    }\n    function farAway(touch, other) {\n      if (other.left == null) { return true }\n      var dx = other.left - touch.left, dy = other.top - touch.top;\n      return dx * dx + dy * dy > 20 * 20\n    }\n    on(d.scroller, \"touchstart\", function (e) {\n      if (!signalDOMEvent(cm, e) && !isMouseLikeTouchEvent(e) && !clickInGutter(cm, e)) {\n        d.input.ensurePolled();\n        clearTimeout(touchFinished);\n        var now = +new Date;\n        d.activeTouch = {start: now, moved: false,\n                         prev: now - prevTouch.end <= 300 ? prevTouch : null};\n        if (e.touches.length == 1) {\n          d.activeTouch.left = e.touches[0].pageX;\n          d.activeTouch.top = e.touches[0].pageY;\n        }\n      }\n    });\n    on(d.scroller, \"touchmove\", function () {\n      if (d.activeTouch) { d.activeTouch.moved = true; }\n    });\n    on(d.scroller, \"touchend\", function (e) {\n      var touch = d.activeTouch;\n      if (touch && !eventInWidget(d, e) && touch.left != null &&\n          !touch.moved && new Date - touch.start < 300) {\n        var pos = cm.coordsChar(d.activeTouch, \"page\"), range;\n        if (!touch.prev || farAway(touch, touch.prev)) // Single tap\n          { range = new Range(pos, pos); }\n        else if (!touch.prev.prev || farAway(touch, touch.prev.prev)) // Double tap\n          { range = cm.findWordAt(pos); }\n        else // Triple tap\n          { range = new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0))); }\n        cm.setSelection(range.anchor, range.head);\n        cm.focus();\n        e_preventDefault(e);\n      }\n      finishTouch();\n    });\n    on(d.scroller, \"touchcancel\", finishTouch);\n\n    // Sync scrolling between fake scrollbars and real scrollable\n    // area, ensure viewport is updated when scrolling.\n    on(d.scroller, \"scroll\", function () {\n      if (d.scroller.clientHeight) {\n        updateScrollTop(cm, d.scroller.scrollTop);\n        setScrollLeft(cm, d.scroller.scrollLeft, true);\n        signal(cm, \"scroll\", cm);\n      }\n    });\n\n    // Listen to wheel events in order to try and update the viewport on time.\n    on(d.scroller, \"mousewheel\", function (e) { return onScrollWheel(cm, e); });\n    on(d.scroller, \"DOMMouseScroll\", function (e) { return onScrollWheel(cm, e); });\n\n    // Prevent wrapper from ever scrolling\n    on(d.wrapper, \"scroll\", function () { return d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; });\n\n    d.dragFunctions = {\n      enter: function (e) {if (!signalDOMEvent(cm, e)) { e_stop(e); }},\n      over: function (e) {if (!signalDOMEvent(cm, e)) { onDragOver(cm, e); e_stop(e); }},\n      start: function (e) { return onDragStart(cm, e); },\n      drop: operation(cm, onDrop),\n      leave: function (e) {if (!signalDOMEvent(cm, e)) { clearDragCursor(cm); }}\n    };\n\n    var inp = d.input.getField();\n    on(inp, \"keyup\", function (e) { return onKeyUp.call(cm, e); });\n    on(inp, \"keydown\", operation(cm, onKeyDown));\n    on(inp, \"keypress\", operation(cm, onKeyPress));\n    on(inp, \"focus\", function (e) { return onFocus(cm, e); });\n    on(inp, \"blur\", function (e) { return onBlur(cm, e); });\n  }\n\n  var initHooks = [];\n  CodeMirror.defineInitHook = function (f) { return initHooks.push(f); };\n\n  // Indent the given line. The how parameter can be \"smart\",\n  // \"add\"/null, \"subtract\", or \"prev\". When aggressive is false\n  // (typically set to true for forced single-line indents), empty\n  // lines are not indented, and places where the mode returns Pass\n  // are left alone.\n  function indentLine(cm, n, how, aggressive) {\n    var doc = cm.doc, state;\n    if (how == null) { how = \"add\"; }\n    if (how == \"smart\") {\n      // Fall back to \"prev\" when the mode doesn't have an indentation\n      // method.\n      if (!doc.mode.indent) { how = \"prev\"; }\n      else { state = getContextBefore(cm, n).state; }\n    }\n\n    var tabSize = cm.options.tabSize;\n    var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize);\n    if (line.stateAfter) { line.stateAfter = null; }\n    var curSpaceString = line.text.match(/^\\s*/)[0], indentation;\n    if (!aggressive && !/\\S/.test(line.text)) {\n      indentation = 0;\n      how = \"not\";\n    } else if (how == \"smart\") {\n      indentation = doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text);\n      if (indentation == Pass || indentation > 150) {\n        if (!aggressive) { return }\n        how = \"prev\";\n      }\n    }\n    if (how == \"prev\") {\n      if (n > doc.first) { indentation = countColumn(getLine(doc, n-1).text, null, tabSize); }\n      else { indentation = 0; }\n    } else if (how == \"add\") {\n      indentation = curSpace + cm.options.indentUnit;\n    } else if (how == \"subtract\") {\n      indentation = curSpace - cm.options.indentUnit;\n    } else if (typeof how == \"number\") {\n      indentation = curSpace + how;\n    }\n    indentation = Math.max(0, indentation);\n\n    var indentString = \"\", pos = 0;\n    if (cm.options.indentWithTabs)\n      { for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += \"\\t\";} }\n    if (pos < indentation) { indentString += spaceStr(indentation - pos); }\n\n    if (indentString != curSpaceString) {\n      replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), \"+input\");\n      line.stateAfter = null;\n      return true\n    } else {\n      // Ensure that, if the cursor was in the whitespace at the start\n      // of the line, it is moved to the end of that space.\n      for (var i$1 = 0; i$1 < doc.sel.ranges.length; i$1++) {\n        var range = doc.sel.ranges[i$1];\n        if (range.head.line == n && range.head.ch < curSpaceString.length) {\n          var pos$1 = Pos(n, curSpaceString.length);\n          replaceOneSelection(doc, i$1, new Range(pos$1, pos$1));\n          break\n        }\n      }\n    }\n  }\n\n  // This will be set to a {lineWise: bool, text: [string]} object, so\n  // that, when pasting, we know what kind of selections the copied\n  // text was made out of.\n  var lastCopied = null;\n\n  function setLastCopied(newLastCopied) {\n    lastCopied = newLastCopied;\n  }\n\n  function applyTextInput(cm, inserted, deleted, sel, origin) {\n    var doc = cm.doc;\n    cm.display.shift = false;\n    if (!sel) { sel = doc.sel; }\n\n    var paste = cm.state.pasteIncoming || origin == \"paste\";\n    var textLines = splitLinesAuto(inserted), multiPaste = null;\n    // When pasting N lines into N selections, insert one line per selection\n    if (paste && sel.ranges.length > 1) {\n      if (lastCopied && lastCopied.text.join(\"\\n\") == inserted) {\n        if (sel.ranges.length % lastCopied.text.length == 0) {\n          multiPaste = [];\n          for (var i = 0; i < lastCopied.text.length; i++)\n            { multiPaste.push(doc.splitLines(lastCopied.text[i])); }\n        }\n      } else if (textLines.length == sel.ranges.length && cm.options.pasteLinesPerSelection) {\n        multiPaste = map(textLines, function (l) { return [l]; });\n      }\n    }\n\n    var updateInput;\n    // Normal behavior is to insert the new text into every selection\n    for (var i$1 = sel.ranges.length - 1; i$1 >= 0; i$1--) {\n      var range$$1 = sel.ranges[i$1];\n      var from = range$$1.from(), to = range$$1.to();\n      if (range$$1.empty()) {\n        if (deleted && deleted > 0) // Handle deletion\n          { from = Pos(from.line, from.ch - deleted); }\n        else if (cm.state.overwrite && !paste) // Handle overwrite\n          { to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length)); }\n        else if (paste && lastCopied && lastCopied.lineWise && lastCopied.text.join(\"\\n\") == inserted)\n          { from = to = Pos(from.line, 0); }\n      }\n      updateInput = cm.curOp.updateInput;\n      var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i$1 % multiPaste.length] : textLines,\n                         origin: origin || (paste ? \"paste\" : cm.state.cutIncoming ? \"cut\" : \"+input\")};\n      makeChange(cm.doc, changeEvent);\n      signalLater(cm, \"inputRead\", cm, changeEvent);\n    }\n    if (inserted && !paste)\n      { triggerElectric(cm, inserted); }\n\n    ensureCursorVisible(cm);\n    cm.curOp.updateInput = updateInput;\n    cm.curOp.typing = true;\n    cm.state.pasteIncoming = cm.state.cutIncoming = false;\n  }\n\n  function handlePaste(e, cm) {\n    var pasted = e.clipboardData && e.clipboardData.getData(\"Text\");\n    if (pasted) {\n      e.preventDefault();\n      if (!cm.isReadOnly() && !cm.options.disableInput)\n        { runInOp(cm, function () { return applyTextInput(cm, pasted, 0, null, \"paste\"); }); }\n      return true\n    }\n  }\n\n  function triggerElectric(cm, inserted) {\n    // When an 'electric' character is inserted, immediately trigger a reindent\n    if (!cm.options.electricChars || !cm.options.smartIndent) { return }\n    var sel = cm.doc.sel;\n\n    for (var i = sel.ranges.length - 1; i >= 0; i--) {\n      var range$$1 = sel.ranges[i];\n      if (range$$1.head.ch > 100 || (i && sel.ranges[i - 1].head.line == range$$1.head.line)) { continue }\n      var mode = cm.getModeAt(range$$1.head);\n      var indented = false;\n      if (mode.electricChars) {\n        for (var j = 0; j < mode.electricChars.length; j++)\n          { if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) {\n            indented = indentLine(cm, range$$1.head.line, \"smart\");\n            break\n          } }\n      } else if (mode.electricInput) {\n        if (mode.electricInput.test(getLine(cm.doc, range$$1.head.line).text.slice(0, range$$1.head.ch)))\n          { indented = indentLine(cm, range$$1.head.line, \"smart\"); }\n      }\n      if (indented) { signalLater(cm, \"electricInput\", cm, range$$1.head.line); }\n    }\n  }\n\n  function copyableRanges(cm) {\n    var text = [], ranges = [];\n    for (var i = 0; i < cm.doc.sel.ranges.length; i++) {\n      var line = cm.doc.sel.ranges[i].head.line;\n      var lineRange = {anchor: Pos(line, 0), head: Pos(line + 1, 0)};\n      ranges.push(lineRange);\n      text.push(cm.getRange(lineRange.anchor, lineRange.head));\n    }\n    return {text: text, ranges: ranges}\n  }\n\n  function disableBrowserMagic(field, spellcheck) {\n    field.setAttribute(\"autocorrect\", \"off\");\n    field.setAttribute(\"autocapitalize\", \"off\");\n    field.setAttribute(\"spellcheck\", !!spellcheck);\n  }\n\n  function hiddenTextarea() {\n    var te = elt(\"textarea\", null, null, \"position: absolute; bottom: -1em; padding: 0; width: 1px; height: 1em; outline: none\");\n    var div = elt(\"div\", [te], null, \"overflow: hidden; position: relative; width: 3px; height: 0px;\");\n    // The textarea is kept positioned near the cursor to prevent the\n    // fact that it'll be scrolled into view on input from scrolling\n    // our fake cursor out of view. On webkit, when wrap=off, paste is\n    // very slow. So make the area wide instead.\n    if (webkit) { te.style.width = \"1000px\"; }\n    else { te.setAttribute(\"wrap\", \"off\"); }\n    // If border: 0; -- iOS fails to open keyboard (issue #1287)\n    if (ios) { te.style.border = \"1px solid black\"; }\n    disableBrowserMagic(te);\n    return div\n  }\n\n  // The publicly visible API. Note that methodOp(f) means\n  // 'wrap f in an operation, performed on its `this` parameter'.\n\n  // This is not the complete set of editor methods. Most of the\n  // methods defined on the Doc type are also injected into\n  // CodeMirror.prototype, for backwards compatibility and\n  // convenience.\n\n  function addEditorMethods(CodeMirror) {\n    var optionHandlers = CodeMirror.optionHandlers;\n\n    var helpers = CodeMirror.helpers = {};\n\n    CodeMirror.prototype = {\n      constructor: CodeMirror,\n      focus: function(){window.focus(); this.display.input.focus();},\n\n      setOption: function(option, value) {\n        var options = this.options, old = options[option];\n        if (options[option] == value && option != \"mode\") { return }\n        options[option] = value;\n        if (optionHandlers.hasOwnProperty(option))\n          { operation(this, optionHandlers[option])(this, value, old); }\n        signal(this, \"optionChange\", this, option);\n      },\n\n      getOption: function(option) {return this.options[option]},\n      getDoc: function() {return this.doc},\n\n      addKeyMap: function(map$$1, bottom) {\n        this.state.keyMaps[bottom ? \"push\" : \"unshift\"](getKeyMap(map$$1));\n      },\n      removeKeyMap: function(map$$1) {\n        var maps = this.state.keyMaps;\n        for (var i = 0; i < maps.length; ++i)\n          { if (maps[i] == map$$1 || maps[i].name == map$$1) {\n            maps.splice(i, 1);\n            return true\n          } }\n      },\n\n      addOverlay: methodOp(function(spec, options) {\n        var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec);\n        if (mode.startState) { throw new Error(\"Overlays may not be stateful.\") }\n        insertSorted(this.state.overlays,\n                     {mode: mode, modeSpec: spec, opaque: options && options.opaque,\n                      priority: (options && options.priority) || 0},\n                     function (overlay) { return overlay.priority; });\n        this.state.modeGen++;\n        regChange(this);\n      }),\n      removeOverlay: methodOp(function(spec) {\n        var this$1 = this;\n\n        var overlays = this.state.overlays;\n        for (var i = 0; i < overlays.length; ++i) {\n          var cur = overlays[i].modeSpec;\n          if (cur == spec || typeof spec == \"string\" && cur.name == spec) {\n            overlays.splice(i, 1);\n            this$1.state.modeGen++;\n            regChange(this$1);\n            return\n          }\n        }\n      }),\n\n      indentLine: methodOp(function(n, dir, aggressive) {\n        if (typeof dir != \"string\" && typeof dir != \"number\") {\n          if (dir == null) { dir = this.options.smartIndent ? \"smart\" : \"prev\"; }\n          else { dir = dir ? \"add\" : \"subtract\"; }\n        }\n        if (isLine(this.doc, n)) { indentLine(this, n, dir, aggressive); }\n      }),\n      indentSelection: methodOp(function(how) {\n        var this$1 = this;\n\n        var ranges = this.doc.sel.ranges, end = -1;\n        for (var i = 0; i < ranges.length; i++) {\n          var range$$1 = ranges[i];\n          if (!range$$1.empty()) {\n            var from = range$$1.from(), to = range$$1.to();\n            var start = Math.max(end, from.line);\n            end = Math.min(this$1.lastLine(), to.line - (to.ch ? 0 : 1)) + 1;\n            for (var j = start; j < end; ++j)\n              { indentLine(this$1, j, how); }\n            var newRanges = this$1.doc.sel.ranges;\n            if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0)\n              { replaceOneSelection(this$1.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll); }\n          } else if (range$$1.head.line > end) {\n            indentLine(this$1, range$$1.head.line, how, true);\n            end = range$$1.head.line;\n            if (i == this$1.doc.sel.primIndex) { ensureCursorVisible(this$1); }\n          }\n        }\n      }),\n\n      // Fetch the parser token for a given character. Useful for hacks\n      // that want to inspect the mode state (say, for completion).\n      getTokenAt: function(pos, precise) {\n        return takeToken(this, pos, precise)\n      },\n\n      getLineTokens: function(line, precise) {\n        return takeToken(this, Pos(line), precise, true)\n      },\n\n      getTokenTypeAt: function(pos) {\n        pos = clipPos(this.doc, pos);\n        var styles = getLineStyles(this, getLine(this.doc, pos.line));\n        var before = 0, after = (styles.length - 1) / 2, ch = pos.ch;\n        var type;\n        if (ch == 0) { type = styles[2]; }\n        else { for (;;) {\n          var mid = (before + after) >> 1;\n          if ((mid ? styles[mid * 2 - 1] : 0) >= ch) { after = mid; }\n          else if (styles[mid * 2 + 1] < ch) { before = mid + 1; }\n          else { type = styles[mid * 2 + 2]; break }\n        } }\n        var cut = type ? type.indexOf(\"overlay \") : -1;\n        return cut < 0 ? type : cut == 0 ? null : type.slice(0, cut - 1)\n      },\n\n      getModeAt: function(pos) {\n        var mode = this.doc.mode;\n        if (!mode.innerMode) { return mode }\n        return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode\n      },\n\n      getHelper: function(pos, type) {\n        return this.getHelpers(pos, type)[0]\n      },\n\n      getHelpers: function(pos, type) {\n        var this$1 = this;\n\n        var found = [];\n        if (!helpers.hasOwnProperty(type)) { return found }\n        var help = helpers[type], mode = this.getModeAt(pos);\n        if (typeof mode[type] == \"string\") {\n          if (help[mode[type]]) { found.push(help[mode[type]]); }\n        } else if (mode[type]) {\n          for (var i = 0; i < mode[type].length; i++) {\n            var val = help[mode[type][i]];\n            if (val) { found.push(val); }\n          }\n        } else if (mode.helperType && help[mode.helperType]) {\n          found.push(help[mode.helperType]);\n        } else if (help[mode.name]) {\n          found.push(help[mode.name]);\n        }\n        for (var i$1 = 0; i$1 < help._global.length; i$1++) {\n          var cur = help._global[i$1];\n          if (cur.pred(mode, this$1) && indexOf(found, cur.val) == -1)\n            { found.push(cur.val); }\n        }\n        return found\n      },\n\n      getStateAfter: function(line, precise) {\n        var doc = this.doc;\n        line = clipLine(doc, line == null ? doc.first + doc.size - 1: line);\n        return getContextBefore(this, line + 1, precise).state\n      },\n\n      cursorCoords: function(start, mode) {\n        var pos, range$$1 = this.doc.sel.primary();\n        if (start == null) { pos = range$$1.head; }\n        else if (typeof start == \"object\") { pos = clipPos(this.doc, start); }\n        else { pos = start ? range$$1.from() : range$$1.to(); }\n        return cursorCoords(this, pos, mode || \"page\")\n      },\n\n      charCoords: function(pos, mode) {\n        return charCoords(this, clipPos(this.doc, pos), mode || \"page\")\n      },\n\n      coordsChar: function(coords, mode) {\n        coords = fromCoordSystem(this, coords, mode || \"page\");\n        return coordsChar(this, coords.left, coords.top)\n      },\n\n      lineAtHeight: function(height, mode) {\n        height = fromCoordSystem(this, {top: height, left: 0}, mode || \"page\").top;\n        return lineAtHeight(this.doc, height + this.display.viewOffset)\n      },\n      heightAtLine: function(line, mode, includeWidgets) {\n        var end = false, lineObj;\n        if (typeof line == \"number\") {\n          var last = this.doc.first + this.doc.size - 1;\n          if (line < this.doc.first) { line = this.doc.first; }\n          else if (line > last) { line = last; end = true; }\n          lineObj = getLine(this.doc, line);\n        } else {\n          lineObj = line;\n        }\n        return intoCoordSystem(this, lineObj, {top: 0, left: 0}, mode || \"page\", includeWidgets || end).top +\n          (end ? this.doc.height - heightAtLine(lineObj) : 0)\n      },\n\n      defaultTextHeight: function() { return textHeight(this.display) },\n      defaultCharWidth: function() { return charWidth(this.display) },\n\n      getViewport: function() { return {from: this.display.viewFrom, to: this.display.viewTo}},\n\n      addWidget: function(pos, node, scroll, vert, horiz) {\n        var display = this.display;\n        pos = cursorCoords(this, clipPos(this.doc, pos));\n        var top = pos.bottom, left = pos.left;\n        node.style.position = \"absolute\";\n        node.setAttribute(\"cm-ignore-events\", \"true\");\n        this.display.input.setUneditable(node);\n        display.sizer.appendChild(node);\n        if (vert == \"over\") {\n          top = pos.top;\n        } else if (vert == \"above\" || vert == \"near\") {\n          var vspace = Math.max(display.wrapper.clientHeight, this.doc.height),\n          hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth);\n          // Default to positioning above (if specified and possible); otherwise default to positioning below\n          if ((vert == 'above' || pos.bottom + node.offsetHeight > vspace) && pos.top > node.offsetHeight)\n            { top = pos.top - node.offsetHeight; }\n          else if (pos.bottom + node.offsetHeight <= vspace)\n            { top = pos.bottom; }\n          if (left + node.offsetWidth > hspace)\n            { left = hspace - node.offsetWidth; }\n        }\n        node.style.top = top + \"px\";\n        node.style.left = node.style.right = \"\";\n        if (horiz == \"right\") {\n          left = display.sizer.clientWidth - node.offsetWidth;\n          node.style.right = \"0px\";\n        } else {\n          if (horiz == \"left\") { left = 0; }\n          else if (horiz == \"middle\") { left = (display.sizer.clientWidth - node.offsetWidth) / 2; }\n          node.style.left = left + \"px\";\n        }\n        if (scroll)\n          { scrollIntoView(this, {left: left, top: top, right: left + node.offsetWidth, bottom: top + node.offsetHeight}); }\n      },\n\n      triggerOnKeyDown: methodOp(onKeyDown),\n      triggerOnKeyPress: methodOp(onKeyPress),\n      triggerOnKeyUp: onKeyUp,\n      triggerOnMouseDown: methodOp(onMouseDown),\n\n      execCommand: function(cmd) {\n        if (commands.hasOwnProperty(cmd))\n          { return commands[cmd].call(null, this) }\n      },\n\n      triggerElectric: methodOp(function(text) { triggerElectric(this, text); }),\n\n      findPosH: function(from, amount, unit, visually) {\n        var this$1 = this;\n\n        var dir = 1;\n        if (amount < 0) { dir = -1; amount = -amount; }\n        var cur = clipPos(this.doc, from);\n        for (var i = 0; i < amount; ++i) {\n          cur = findPosH(this$1.doc, cur, dir, unit, visually);\n          if (cur.hitSide) { break }\n        }\n        return cur\n      },\n\n      moveH: methodOp(function(dir, unit) {\n        var this$1 = this;\n\n        this.extendSelectionsBy(function (range$$1) {\n          if (this$1.display.shift || this$1.doc.extend || range$$1.empty())\n            { return findPosH(this$1.doc, range$$1.head, dir, unit, this$1.options.rtlMoveVisually) }\n          else\n            { return dir < 0 ? range$$1.from() : range$$1.to() }\n        }, sel_move);\n      }),\n\n      deleteH: methodOp(function(dir, unit) {\n        var sel = this.doc.sel, doc = this.doc;\n        if (sel.somethingSelected())\n          { doc.replaceSelection(\"\", null, \"+delete\"); }\n        else\n          { deleteNearSelection(this, function (range$$1) {\n            var other = findPosH(doc, range$$1.head, dir, unit, false);\n            return dir < 0 ? {from: other, to: range$$1.head} : {from: range$$1.head, to: other}\n          }); }\n      }),\n\n      findPosV: function(from, amount, unit, goalColumn) {\n        var this$1 = this;\n\n        var dir = 1, x = goalColumn;\n        if (amount < 0) { dir = -1; amount = -amount; }\n        var cur = clipPos(this.doc, from);\n        for (var i = 0; i < amount; ++i) {\n          var coords = cursorCoords(this$1, cur, \"div\");\n          if (x == null) { x = coords.left; }\n          else { coords.left = x; }\n          cur = findPosV(this$1, coords, dir, unit);\n          if (cur.hitSide) { break }\n        }\n        return cur\n      },\n\n      moveV: methodOp(function(dir, unit) {\n        var this$1 = this;\n\n        var doc = this.doc, goals = [];\n        var collapse = !this.display.shift && !doc.extend && doc.sel.somethingSelected();\n        doc.extendSelectionsBy(function (range$$1) {\n          if (collapse)\n            { return dir < 0 ? range$$1.from() : range$$1.to() }\n          var headPos = cursorCoords(this$1, range$$1.head, \"div\");\n          if (range$$1.goalColumn != null) { headPos.left = range$$1.goalColumn; }\n          goals.push(headPos.left);\n          var pos = findPosV(this$1, headPos, dir, unit);\n          if (unit == \"page\" && range$$1 == doc.sel.primary())\n            { addToScrollTop(this$1, charCoords(this$1, pos, \"div\").top - headPos.top); }\n          return pos\n        }, sel_move);\n        if (goals.length) { for (var i = 0; i < doc.sel.ranges.length; i++)\n          { doc.sel.ranges[i].goalColumn = goals[i]; } }\n      }),\n\n      // Find the word at the given position (as returned by coordsChar).\n      findWordAt: function(pos) {\n        var doc = this.doc, line = getLine(doc, pos.line).text;\n        var start = pos.ch, end = pos.ch;\n        if (line) {\n          var helper = this.getHelper(pos, \"wordChars\");\n          if ((pos.sticky == \"before\" || end == line.length) && start) { --start; } else { ++end; }\n          var startChar = line.charAt(start);\n          var check = isWordChar(startChar, helper)\n            ? function (ch) { return isWordChar(ch, helper); }\n            : /\\s/.test(startChar) ? function (ch) { return /\\s/.test(ch); }\n            : function (ch) { return (!/\\s/.test(ch) && !isWordChar(ch)); };\n          while (start > 0 && check(line.charAt(start - 1))) { --start; }\n          while (end < line.length && check(line.charAt(end))) { ++end; }\n        }\n        return new Range(Pos(pos.line, start), Pos(pos.line, end))\n      },\n\n      toggleOverwrite: function(value) {\n        if (value != null && value == this.state.overwrite) { return }\n        if (this.state.overwrite = !this.state.overwrite)\n          { addClass(this.display.cursorDiv, \"CodeMirror-overwrite\"); }\n        else\n          { rmClass(this.display.cursorDiv, \"CodeMirror-overwrite\"); }\n\n        signal(this, \"overwriteToggle\", this, this.state.overwrite);\n      },\n      hasFocus: function() { return this.display.input.getField() == activeElt() },\n      isReadOnly: function() { return !!(this.options.readOnly || this.doc.cantEdit) },\n\n      scrollTo: methodOp(function (x, y) { scrollToCoords(this, x, y); }),\n      getScrollInfo: function() {\n        var scroller = this.display.scroller;\n        return {left: scroller.scrollLeft, top: scroller.scrollTop,\n                height: scroller.scrollHeight - scrollGap(this) - this.display.barHeight,\n                width: scroller.scrollWidth - scrollGap(this) - this.display.barWidth,\n                clientHeight: displayHeight(this), clientWidth: displayWidth(this)}\n      },\n\n      scrollIntoView: methodOp(function(range$$1, margin) {\n        if (range$$1 == null) {\n          range$$1 = {from: this.doc.sel.primary().head, to: null};\n          if (margin == null) { margin = this.options.cursorScrollMargin; }\n        } else if (typeof range$$1 == \"number\") {\n          range$$1 = {from: Pos(range$$1, 0), to: null};\n        } else if (range$$1.from == null) {\n          range$$1 = {from: range$$1, to: null};\n        }\n        if (!range$$1.to) { range$$1.to = range$$1.from; }\n        range$$1.margin = margin || 0;\n\n        if (range$$1.from.line != null) {\n          scrollToRange(this, range$$1);\n        } else {\n          scrollToCoordsRange(this, range$$1.from, range$$1.to, range$$1.margin);\n        }\n      }),\n\n      setSize: methodOp(function(width, height) {\n        var this$1 = this;\n\n        var interpret = function (val) { return typeof val == \"number\" || /^\\d+$/.test(String(val)) ? val + \"px\" : val; };\n        if (width != null) { this.display.wrapper.style.width = interpret(width); }\n        if (height != null) { this.display.wrapper.style.height = interpret(height); }\n        if (this.options.lineWrapping) { clearLineMeasurementCache(this); }\n        var lineNo$$1 = this.display.viewFrom;\n        this.doc.iter(lineNo$$1, this.display.viewTo, function (line) {\n          if (line.widgets) { for (var i = 0; i < line.widgets.length; i++)\n            { if (line.widgets[i].noHScroll) { regLineChange(this$1, lineNo$$1, \"widget\"); break } } }\n          ++lineNo$$1;\n        });\n        this.curOp.forceUpdate = true;\n        signal(this, \"refresh\", this);\n      }),\n\n      operation: function(f){return runInOp(this, f)},\n      startOperation: function(){return startOperation(this)},\n      endOperation: function(){return endOperation(this)},\n\n      refresh: methodOp(function() {\n        var oldHeight = this.display.cachedTextHeight;\n        regChange(this);\n        this.curOp.forceUpdate = true;\n        clearCaches(this);\n        scrollToCoords(this, this.doc.scrollLeft, this.doc.scrollTop);\n        updateGutterSpace(this);\n        if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5)\n          { estimateLineHeights(this); }\n        signal(this, \"refresh\", this);\n      }),\n\n      swapDoc: methodOp(function(doc) {\n        var old = this.doc;\n        old.cm = null;\n        attachDoc(this, doc);\n        clearCaches(this);\n        this.display.input.reset();\n        scrollToCoords(this, doc.scrollLeft, doc.scrollTop);\n        this.curOp.forceScroll = true;\n        signalLater(this, \"swapDoc\", this, old);\n        return old\n      }),\n\n      phrase: function(phraseText) {\n        var phrases = this.options.phrases;\n        return phrases && Object.prototype.hasOwnProperty.call(phrases, phraseText) ? phrases[phraseText] : phraseText\n      },\n\n      getInputField: function(){return this.display.input.getField()},\n      getWrapperElement: function(){return this.display.wrapper},\n      getScrollerElement: function(){return this.display.scroller},\n      getGutterElement: function(){return this.display.gutters}\n    };\n    eventMixin(CodeMirror);\n\n    CodeMirror.registerHelper = function(type, name, value) {\n      if (!helpers.hasOwnProperty(type)) { helpers[type] = CodeMirror[type] = {_global: []}; }\n      helpers[type][name] = value;\n    };\n    CodeMirror.registerGlobalHelper = function(type, name, predicate, value) {\n      CodeMirror.registerHelper(type, name, value);\n      helpers[type]._global.push({pred: predicate, val: value});\n    };\n  }\n\n  // Used for horizontal relative motion. Dir is -1 or 1 (left or\n  // right), unit can be \"char\", \"column\" (like char, but doesn't\n  // cross line boundaries), \"word\" (across next word), or \"group\" (to\n  // the start of next group of word or non-word-non-whitespace\n  // chars). The visually param controls whether, in right-to-left\n  // text, direction 1 means to move towards the next index in the\n  // string, or towards the character to the right of the current\n  // position. The resulting position will have a hitSide=true\n  // property if it reached the end of the document.\n  function findPosH(doc, pos, dir, unit, visually) {\n    var oldPos = pos;\n    var origDir = dir;\n    var lineObj = getLine(doc, pos.line);\n    function findNextLine() {\n      var l = pos.line + dir;\n      if (l < doc.first || l >= doc.first + doc.size) { return false }\n      pos = new Pos(l, pos.ch, pos.sticky);\n      return lineObj = getLine(doc, l)\n    }\n    function moveOnce(boundToLine) {\n      var next;\n      if (visually) {\n        next = moveVisually(doc.cm, lineObj, pos, dir);\n      } else {\n        next = moveLogically(lineObj, pos, dir);\n      }\n      if (next == null) {\n        if (!boundToLine && findNextLine())\n          { pos = endOfLine(visually, doc.cm, lineObj, pos.line, dir); }\n        else\n          { return false }\n      } else {\n        pos = next;\n      }\n      return true\n    }\n\n    if (unit == \"char\") {\n      moveOnce();\n    } else if (unit == \"column\") {\n      moveOnce(true);\n    } else if (unit == \"word\" || unit == \"group\") {\n      var sawType = null, group = unit == \"group\";\n      var helper = doc.cm && doc.cm.getHelper(pos, \"wordChars\");\n      for (var first = true;; first = false) {\n        if (dir < 0 && !moveOnce(!first)) { break }\n        var cur = lineObj.text.charAt(pos.ch) || \"\\n\";\n        var type = isWordChar(cur, helper) ? \"w\"\n          : group && cur == \"\\n\" ? \"n\"\n          : !group || /\\s/.test(cur) ? null\n          : \"p\";\n        if (group && !first && !type) { type = \"s\"; }\n        if (sawType && sawType != type) {\n          if (dir < 0) {dir = 1; moveOnce(); pos.sticky = \"after\";}\n          break\n        }\n\n        if (type) { sawType = type; }\n        if (dir > 0 && !moveOnce(!first)) { break }\n      }\n    }\n    var result = skipAtomic(doc, pos, oldPos, origDir, true);\n    if (equalCursorPos(oldPos, result)) { result.hitSide = true; }\n    return result\n  }\n\n  // For relative vertical movement. Dir may be -1 or 1. Unit can be\n  // \"page\" or \"line\". The resulting position will have a hitSide=true\n  // property if it reached the end of the document.\n  function findPosV(cm, pos, dir, unit) {\n    var doc = cm.doc, x = pos.left, y;\n    if (unit == \"page\") {\n      var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight);\n      var moveAmount = Math.max(pageSize - .5 * textHeight(cm.display), 3);\n      y = (dir > 0 ? pos.bottom : pos.top) + dir * moveAmount;\n\n    } else if (unit == \"line\") {\n      y = dir > 0 ? pos.bottom + 3 : pos.top - 3;\n    }\n    var target;\n    for (;;) {\n      target = coordsChar(cm, x, y);\n      if (!target.outside) { break }\n      if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break }\n      y += dir * 5;\n    }\n    return target\n  }\n\n  // CONTENTEDITABLE INPUT STYLE\n\n  var ContentEditableInput = function(cm) {\n    this.cm = cm;\n    this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null;\n    this.polling = new Delayed();\n    this.composing = null;\n    this.gracePeriod = false;\n    this.readDOMTimeout = null;\n  };\n\n  ContentEditableInput.prototype.init = function (display) {\n      var this$1 = this;\n\n    var input = this, cm = input.cm;\n    var div = input.div = display.lineDiv;\n    disableBrowserMagic(div, cm.options.spellcheck);\n\n    on(div, \"paste\", function (e) {\n      if (signalDOMEvent(cm, e) || handlePaste(e, cm)) { return }\n      // IE doesn't fire input events, so we schedule a read for the pasted content in this way\n      if (ie_version <= 11) { setTimeout(operation(cm, function () { return this$1.updateFromDOM(); }), 20); }\n    });\n\n    on(div, \"compositionstart\", function (e) {\n      this$1.composing = {data: e.data, done: false};\n    });\n    on(div, \"compositionupdate\", function (e) {\n      if (!this$1.composing) { this$1.composing = {data: e.data, done: false}; }\n    });\n    on(div, \"compositionend\", function (e) {\n      if (this$1.composing) {\n        if (e.data != this$1.composing.data) { this$1.readFromDOMSoon(); }\n        this$1.composing.done = true;\n      }\n    });\n\n    on(div, \"touchstart\", function () { return input.forceCompositionEnd(); });\n\n    on(div, \"input\", function () {\n      if (!this$1.composing) { this$1.readFromDOMSoon(); }\n    });\n\n    function onCopyCut(e) {\n      if (signalDOMEvent(cm, e)) { return }\n      if (cm.somethingSelected()) {\n        setLastCopied({lineWise: false, text: cm.getSelections()});\n        if (e.type == \"cut\") { cm.replaceSelection(\"\", null, \"cut\"); }\n      } else if (!cm.options.lineWiseCopyCut) {\n        return\n      } else {\n        var ranges = copyableRanges(cm);\n        setLastCopied({lineWise: true, text: ranges.text});\n        if (e.type == \"cut\") {\n          cm.operation(function () {\n            cm.setSelections(ranges.ranges, 0, sel_dontScroll);\n            cm.replaceSelection(\"\", null, \"cut\");\n          });\n        }\n      }\n      if (e.clipboardData) {\n        e.clipboardData.clearData();\n        var content = lastCopied.text.join(\"\\n\");\n        // iOS exposes the clipboard API, but seems to discard content inserted into it\n        e.clipboardData.setData(\"Text\", content);\n        if (e.clipboardData.getData(\"Text\") == content) {\n          e.preventDefault();\n          return\n        }\n      }\n      // Old-fashioned briefly-focus-a-textarea hack\n      var kludge = hiddenTextarea(), te = kludge.firstChild;\n      cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild);\n      te.value = lastCopied.text.join(\"\\n\");\n      var hadFocus = document.activeElement;\n      selectInput(te);\n      setTimeout(function () {\n        cm.display.lineSpace.removeChild(kludge);\n        hadFocus.focus();\n        if (hadFocus == div) { input.showPrimarySelection(); }\n      }, 50);\n    }\n    on(div, \"copy\", onCopyCut);\n    on(div, \"cut\", onCopyCut);\n  };\n\n  ContentEditableInput.prototype.prepareSelection = function () {\n    var result = prepareSelection(this.cm, false);\n    result.focus = this.cm.state.focused;\n    return result\n  };\n\n  ContentEditableInput.prototype.showSelection = function (info, takeFocus) {\n    if (!info || !this.cm.display.view.length) { return }\n    if (info.focus || takeFocus) { this.showPrimarySelection(); }\n    this.showMultipleSelections(info);\n  };\n\n  ContentEditableInput.prototype.getSelection = function () {\n    return this.cm.display.wrapper.ownerDocument.getSelection()\n  };\n\n  ContentEditableInput.prototype.showPrimarySelection = function () {\n    var sel = this.getSelection(), cm = this.cm, prim = cm.doc.sel.primary();\n    var from = prim.from(), to = prim.to();\n\n    if (cm.display.viewTo == cm.display.viewFrom || from.line >= cm.display.viewTo || to.line < cm.display.viewFrom) {\n      sel.removeAllRanges();\n      return\n    }\n\n    var curAnchor = domToPos(cm, sel.anchorNode, sel.anchorOffset);\n    var curFocus = domToPos(cm, sel.focusNode, sel.focusOffset);\n    if (curAnchor && !curAnchor.bad && curFocus && !curFocus.bad &&\n        cmp(minPos(curAnchor, curFocus), from) == 0 &&\n        cmp(maxPos(curAnchor, curFocus), to) == 0)\n      { return }\n\n    var view = cm.display.view;\n    var start = (from.line >= cm.display.viewFrom && posToDOM(cm, from)) ||\n        {node: view[0].measure.map[2], offset: 0};\n    var end = to.line < cm.display.viewTo && posToDOM(cm, to);\n    if (!end) {\n      var measure = view[view.length - 1].measure;\n      var map$$1 = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map;\n      end = {node: map$$1[map$$1.length - 1], offset: map$$1[map$$1.length - 2] - map$$1[map$$1.length - 3]};\n    }\n\n    if (!start || !end) {\n      sel.removeAllRanges();\n      return\n    }\n\n    var old = sel.rangeCount && sel.getRangeAt(0), rng;\n    try { rng = range(start.node, start.offset, end.offset, end.node); }\n    catch(e) {} // Our model of the DOM might be outdated, in which case the range we try to set can be impossible\n    if (rng) {\n      if (!gecko && cm.state.focused) {\n        sel.collapse(start.node, start.offset);\n        if (!rng.collapsed) {\n          sel.removeAllRanges();\n          sel.addRange(rng);\n        }\n      } else {\n        sel.removeAllRanges();\n        sel.addRange(rng);\n      }\n      if (old && sel.anchorNode == null) { sel.addRange(old); }\n      else if (gecko) { this.startGracePeriod(); }\n    }\n    this.rememberSelection();\n  };\n\n  ContentEditableInput.prototype.startGracePeriod = function () {\n      var this$1 = this;\n\n    clearTimeout(this.gracePeriod);\n    this.gracePeriod = setTimeout(function () {\n      this$1.gracePeriod = false;\n      if (this$1.selectionChanged())\n        { this$1.cm.operation(function () { return this$1.cm.curOp.selectionChanged = true; }); }\n    }, 20);\n  };\n\n  ContentEditableInput.prototype.showMultipleSelections = function (info) {\n    removeChildrenAndAdd(this.cm.display.cursorDiv, info.cursors);\n    removeChildrenAndAdd(this.cm.display.selectionDiv, info.selection);\n  };\n\n  ContentEditableInput.prototype.rememberSelection = function () {\n    var sel = this.getSelection();\n    this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset;\n    this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset;\n  };\n\n  ContentEditableInput.prototype.selectionInEditor = function () {\n    var sel = this.getSelection();\n    if (!sel.rangeCount) { return false }\n    var node = sel.getRangeAt(0).commonAncestorContainer;\n    return contains(this.div, node)\n  };\n\n  ContentEditableInput.prototype.focus = function () {\n    if (this.cm.options.readOnly != \"nocursor\") {\n      if (!this.selectionInEditor())\n        { this.showSelection(this.prepareSelection(), true); }\n      this.div.focus();\n    }\n  };\n  ContentEditableInput.prototype.blur = function () { this.div.blur(); };\n  ContentEditableInput.prototype.getField = function () { return this.div };\n\n  ContentEditableInput.prototype.supportsTouch = function () { return true };\n\n  ContentEditableInput.prototype.receivedFocus = function () {\n    var input = this;\n    if (this.selectionInEditor())\n      { this.pollSelection(); }\n    else\n      { runInOp(this.cm, function () { return input.cm.curOp.selectionChanged = true; }); }\n\n    function poll() {\n      if (input.cm.state.focused) {\n        input.pollSelection();\n        input.polling.set(input.cm.options.pollInterval, poll);\n      }\n    }\n    this.polling.set(this.cm.options.pollInterval, poll);\n  };\n\n  ContentEditableInput.prototype.selectionChanged = function () {\n    var sel = this.getSelection();\n    return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset ||\n      sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset\n  };\n\n  ContentEditableInput.prototype.pollSelection = function () {\n    if (this.readDOMTimeout != null || this.gracePeriod || !this.selectionChanged()) { return }\n    var sel = this.getSelection(), cm = this.cm;\n    // On Android Chrome (version 56, at least), backspacing into an\n    // uneditable block element will put the cursor in that element,\n    // and then, because it's not editable, hide the virtual keyboard.\n    // Because Android doesn't allow us to actually detect backspace\n    // presses in a sane way, this code checks for when that happens\n    // and simulates a backspace press in this case.\n    if (android && chrome && this.cm.options.gutters.length && isInGutter(sel.anchorNode)) {\n      this.cm.triggerOnKeyDown({type: \"keydown\", keyCode: 8, preventDefault: Math.abs});\n      this.blur();\n      this.focus();\n      return\n    }\n    if (this.composing) { return }\n    this.rememberSelection();\n    var anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset);\n    var head = domToPos(cm, sel.focusNode, sel.focusOffset);\n    if (anchor && head) { runInOp(cm, function () {\n      setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll);\n      if (anchor.bad || head.bad) { cm.curOp.selectionChanged = true; }\n    }); }\n  };\n\n  ContentEditableInput.prototype.pollContent = function () {\n    if (this.readDOMTimeout != null) {\n      clearTimeout(this.readDOMTimeout);\n      this.readDOMTimeout = null;\n    }\n\n    var cm = this.cm, display = cm.display, sel = cm.doc.sel.primary();\n    var from = sel.from(), to = sel.to();\n    if (from.ch == 0 && from.line > cm.firstLine())\n      { from = Pos(from.line - 1, getLine(cm.doc, from.line - 1).length); }\n    if (to.ch == getLine(cm.doc, to.line).text.length && to.line < cm.lastLine())\n      { to = Pos(to.line + 1, 0); }\n    if (from.line < display.viewFrom || to.line > display.viewTo - 1) { return false }\n\n    var fromIndex, fromLine, fromNode;\n    if (from.line == display.viewFrom || (fromIndex = findViewIndex(cm, from.line)) == 0) {\n      fromLine = lineNo(display.view[0].line);\n      fromNode = display.view[0].node;\n    } else {\n      fromLine = lineNo(display.view[fromIndex].line);\n      fromNode = display.view[fromIndex - 1].node.nextSibling;\n    }\n    var toIndex = findViewIndex(cm, to.line);\n    var toLine, toNode;\n    if (toIndex == display.view.length - 1) {\n      toLine = display.viewTo - 1;\n      toNode = display.lineDiv.lastChild;\n    } else {\n      toLine = lineNo(display.view[toIndex + 1].line) - 1;\n      toNode = display.view[toIndex + 1].node.previousSibling;\n    }\n\n    if (!fromNode) { return false }\n    var newText = cm.doc.splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine));\n    var oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length));\n    while (newText.length > 1 && oldText.length > 1) {\n      if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine--; }\n      else if (newText[0] == oldText[0]) { newText.shift(); oldText.shift(); fromLine++; }\n      else { break }\n    }\n\n    var cutFront = 0, cutEnd = 0;\n    var newTop = newText[0], oldTop = oldText[0], maxCutFront = Math.min(newTop.length, oldTop.length);\n    while (cutFront < maxCutFront && newTop.charCodeAt(cutFront) == oldTop.charCodeAt(cutFront))\n      { ++cutFront; }\n    var newBot = lst(newText), oldBot = lst(oldText);\n    var maxCutEnd = Math.min(newBot.length - (newText.length == 1 ? cutFront : 0),\n                             oldBot.length - (oldText.length == 1 ? cutFront : 0));\n    while (cutEnd < maxCutEnd &&\n           newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1))\n      { ++cutEnd; }\n    // Try to move start of change to start of selection if ambiguous\n    if (newText.length == 1 && oldText.length == 1 && fromLine == from.line) {\n      while (cutFront && cutFront > from.ch &&\n             newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1)) {\n        cutFront--;\n        cutEnd++;\n      }\n    }\n\n    newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd).replace(/^\\u200b+/, \"\");\n    newText[0] = newText[0].slice(cutFront).replace(/\\u200b+$/, \"\");\n\n    var chFrom = Pos(fromLine, cutFront);\n    var chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0);\n    if (newText.length > 1 || newText[0] || cmp(chFrom, chTo)) {\n      replaceRange(cm.doc, newText, chFrom, chTo, \"+input\");\n      return true\n    }\n  };\n\n  ContentEditableInput.prototype.ensurePolled = function () {\n    this.forceCompositionEnd();\n  };\n  ContentEditableInput.prototype.reset = function () {\n    this.forceCompositionEnd();\n  };\n  ContentEditableInput.prototype.forceCompositionEnd = function () {\n    if (!this.composing) { return }\n    clearTimeout(this.readDOMTimeout);\n    this.composing = null;\n    this.updateFromDOM();\n    this.div.blur();\n    this.div.focus();\n  };\n  ContentEditableInput.prototype.readFromDOMSoon = function () {\n      var this$1 = this;\n\n    if (this.readDOMTimeout != null) { return }\n    this.readDOMTimeout = setTimeout(function () {\n      this$1.readDOMTimeout = null;\n      if (this$1.composing) {\n        if (this$1.composing.done) { this$1.composing = null; }\n        else { return }\n      }\n      this$1.updateFromDOM();\n    }, 80);\n  };\n\n  ContentEditableInput.prototype.updateFromDOM = function () {\n      var this$1 = this;\n\n    if (this.cm.isReadOnly() || !this.pollContent())\n      { runInOp(this.cm, function () { return regChange(this$1.cm); }); }\n  };\n\n  ContentEditableInput.prototype.setUneditable = function (node) {\n    node.contentEditable = \"false\";\n  };\n\n  ContentEditableInput.prototype.onKeyPress = function (e) {\n    if (e.charCode == 0 || this.composing) { return }\n    e.preventDefault();\n    if (!this.cm.isReadOnly())\n      { operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0); }\n  };\n\n  ContentEditableInput.prototype.readOnlyChanged = function (val) {\n    this.div.contentEditable = String(val != \"nocursor\");\n  };\n\n  ContentEditableInput.prototype.onContextMenu = function () {};\n  ContentEditableInput.prototype.resetPosition = function () {};\n\n  ContentEditableInput.prototype.needsContentAttribute = true;\n\n  function posToDOM(cm, pos) {\n    var view = findViewForLine(cm, pos.line);\n    if (!view || view.hidden) { return null }\n    var line = getLine(cm.doc, pos.line);\n    var info = mapFromLineView(view, line, pos.line);\n\n    var order = getOrder(line, cm.doc.direction), side = \"left\";\n    if (order) {\n      var partPos = getBidiPartAt(order, pos.ch);\n      side = partPos % 2 ? \"right\" : \"left\";\n    }\n    var result = nodeAndOffsetInLineMap(info.map, pos.ch, side);\n    result.offset = result.collapse == \"right\" ? result.end : result.start;\n    return result\n  }\n\n  function isInGutter(node) {\n    for (var scan = node; scan; scan = scan.parentNode)\n      { if (/CodeMirror-gutter-wrapper/.test(scan.className)) { return true } }\n    return false\n  }\n\n  function badPos(pos, bad) { if (bad) { pos.bad = true; } return pos }\n\n  function domTextBetween(cm, from, to, fromLine, toLine) {\n    var text = \"\", closing = false, lineSep = cm.doc.lineSeparator(), extraLinebreak = false;\n    function recognizeMarker(id) { return function (marker) { return marker.id == id; } }\n    function close() {\n      if (closing) {\n        text += lineSep;\n        if (extraLinebreak) { text += lineSep; }\n        closing = extraLinebreak = false;\n      }\n    }\n    function addText(str) {\n      if (str) {\n        close();\n        text += str;\n      }\n    }\n    function walk(node) {\n      if (node.nodeType == 1) {\n        var cmText = node.getAttribute(\"cm-text\");\n        if (cmText) {\n          addText(cmText);\n          return\n        }\n        var markerID = node.getAttribute(\"cm-marker\"), range$$1;\n        if (markerID) {\n          var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID));\n          if (found.length && (range$$1 = found[0].find(0)))\n            { addText(getBetween(cm.doc, range$$1.from, range$$1.to).join(lineSep)); }\n          return\n        }\n        if (node.getAttribute(\"contenteditable\") == \"false\") { return }\n        var isBlock = /^(pre|div|p|li|table|br)$/i.test(node.nodeName);\n        if (!/^br$/i.test(node.nodeName) && node.textContent.length == 0) { return }\n\n        if (isBlock) { close(); }\n        for (var i = 0; i < node.childNodes.length; i++)\n          { walk(node.childNodes[i]); }\n\n        if (/^(pre|p)$/i.test(node.nodeName)) { extraLinebreak = true; }\n        if (isBlock) { closing = true; }\n      } else if (node.nodeType == 3) {\n        addText(node.nodeValue.replace(/\\u200b/g, \"\").replace(/\\u00a0/g, \" \"));\n      }\n    }\n    for (;;) {\n      walk(from);\n      if (from == to) { break }\n      from = from.nextSibling;\n      extraLinebreak = false;\n    }\n    return text\n  }\n\n  function domToPos(cm, node, offset) {\n    var lineNode;\n    if (node == cm.display.lineDiv) {\n      lineNode = cm.display.lineDiv.childNodes[offset];\n      if (!lineNode) { return badPos(cm.clipPos(Pos(cm.display.viewTo - 1)), true) }\n      node = null; offset = 0;\n    } else {\n      for (lineNode = node;; lineNode = lineNode.parentNode) {\n        if (!lineNode || lineNode == cm.display.lineDiv) { return null }\n        if (lineNode.parentNode && lineNode.parentNode == cm.display.lineDiv) { break }\n      }\n    }\n    for (var i = 0; i < cm.display.view.length; i++) {\n      var lineView = cm.display.view[i];\n      if (lineView.node == lineNode)\n        { return locateNodeInLineView(lineView, node, offset) }\n    }\n  }\n\n  function locateNodeInLineView(lineView, node, offset) {\n    var wrapper = lineView.text.firstChild, bad = false;\n    if (!node || !contains(wrapper, node)) { return badPos(Pos(lineNo(lineView.line), 0), true) }\n    if (node == wrapper) {\n      bad = true;\n      node = wrapper.childNodes[offset];\n      offset = 0;\n      if (!node) {\n        var line = lineView.rest ? lst(lineView.rest) : lineView.line;\n        return badPos(Pos(lineNo(line), line.text.length), bad)\n      }\n    }\n\n    var textNode = node.nodeType == 3 ? node : null, topNode = node;\n    if (!textNode && node.childNodes.length == 1 && node.firstChild.nodeType == 3) {\n      textNode = node.firstChild;\n      if (offset) { offset = textNode.nodeValue.length; }\n    }\n    while (topNode.parentNode != wrapper) { topNode = topNode.parentNode; }\n    var measure = lineView.measure, maps = measure.maps;\n\n    function find(textNode, topNode, offset) {\n      for (var i = -1; i < (maps ? maps.length : 0); i++) {\n        var map$$1 = i < 0 ? measure.map : maps[i];\n        for (var j = 0; j < map$$1.length; j += 3) {\n          var curNode = map$$1[j + 2];\n          if (curNode == textNode || curNode == topNode) {\n            var line = lineNo(i < 0 ? lineView.line : lineView.rest[i]);\n            var ch = map$$1[j] + offset;\n            if (offset < 0 || curNode != textNode) { ch = map$$1[j + (offset ? 1 : 0)]; }\n            return Pos(line, ch)\n          }\n        }\n      }\n    }\n    var found = find(textNode, topNode, offset);\n    if (found) { return badPos(found, bad) }\n\n    // FIXME this is all really shaky. might handle the few cases it needs to handle, but likely to cause problems\n    for (var after = topNode.nextSibling, dist = textNode ? textNode.nodeValue.length - offset : 0; after; after = after.nextSibling) {\n      found = find(after, after.firstChild, 0);\n      if (found)\n        { return badPos(Pos(found.line, found.ch - dist), bad) }\n      else\n        { dist += after.textContent.length; }\n    }\n    for (var before = topNode.previousSibling, dist$1 = offset; before; before = before.previousSibling) {\n      found = find(before, before.firstChild, -1);\n      if (found)\n        { return badPos(Pos(found.line, found.ch + dist$1), bad) }\n      else\n        { dist$1 += before.textContent.length; }\n    }\n  }\n\n  // TEXTAREA INPUT STYLE\n\n  var TextareaInput = function(cm) {\n    this.cm = cm;\n    // See input.poll and input.reset\n    this.prevInput = \"\";\n\n    // Flag that indicates whether we expect input to appear real soon\n    // now (after some event like 'keypress' or 'input') and are\n    // polling intensively.\n    this.pollingFast = false;\n    // Self-resetting timeout for the poller\n    this.polling = new Delayed();\n    // Used to work around IE issue with selection being forgotten when focus moves away from textarea\n    this.hasSelection = false;\n    this.composing = null;\n  };\n\n  TextareaInput.prototype.init = function (display) {\n      var this$1 = this;\n\n    var input = this, cm = this.cm;\n    this.createField(display);\n    var te = this.textarea;\n\n    display.wrapper.insertBefore(this.wrapper, display.wrapper.firstChild);\n\n    // Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore)\n    if (ios) { te.style.width = \"0px\"; }\n\n    on(te, \"input\", function () {\n      if (ie && ie_version >= 9 && this$1.hasSelection) { this$1.hasSelection = null; }\n      input.poll();\n    });\n\n    on(te, \"paste\", function (e) {\n      if (signalDOMEvent(cm, e) || handlePaste(e, cm)) { return }\n\n      cm.state.pasteIncoming = true;\n      input.fastPoll();\n    });\n\n    function prepareCopyCut(e) {\n      if (signalDOMEvent(cm, e)) { return }\n      if (cm.somethingSelected()) {\n        setLastCopied({lineWise: false, text: cm.getSelections()});\n      } else if (!cm.options.lineWiseCopyCut) {\n        return\n      } else {\n        var ranges = copyableRanges(cm);\n        setLastCopied({lineWise: true, text: ranges.text});\n        if (e.type == \"cut\") {\n          cm.setSelections(ranges.ranges, null, sel_dontScroll);\n        } else {\n          input.prevInput = \"\";\n          te.value = ranges.text.join(\"\\n\");\n          selectInput(te);\n        }\n      }\n      if (e.type == \"cut\") { cm.state.cutIncoming = true; }\n    }\n    on(te, \"cut\", prepareCopyCut);\n    on(te, \"copy\", prepareCopyCut);\n\n    on(display.scroller, \"paste\", function (e) {\n      if (eventInWidget(display, e) || signalDOMEvent(cm, e)) { return }\n      cm.state.pasteIncoming = true;\n      input.focus();\n    });\n\n    // Prevent normal selection in the editor (we handle our own)\n    on(display.lineSpace, \"selectstart\", function (e) {\n      if (!eventInWidget(display, e)) { e_preventDefault(e); }\n    });\n\n    on(te, \"compositionstart\", function () {\n      var start = cm.getCursor(\"from\");\n      if (input.composing) { input.composing.range.clear(); }\n      input.composing = {\n        start: start,\n        range: cm.markText(start, cm.getCursor(\"to\"), {className: \"CodeMirror-composing\"})\n      };\n    });\n    on(te, \"compositionend\", function () {\n      if (input.composing) {\n        input.poll();\n        input.composing.range.clear();\n        input.composing = null;\n      }\n    });\n  };\n\n  TextareaInput.prototype.createField = function (_display) {\n    // Wraps and hides input textarea\n    this.wrapper = hiddenTextarea();\n    // The semihidden textarea that is focused when the editor is\n    // focused, and receives input.\n    this.textarea = this.wrapper.firstChild;\n  };\n\n  TextareaInput.prototype.prepareSelection = function () {\n    // Redraw the selection and/or cursor\n    var cm = this.cm, display = cm.display, doc = cm.doc;\n    var result = prepareSelection(cm);\n\n    // Move the hidden textarea near the cursor to prevent scrolling artifacts\n    if (cm.options.moveInputWithCursor) {\n      var headPos = cursorCoords(cm, doc.sel.primary().head, \"div\");\n      var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect();\n      result.teTop = Math.max(0, Math.min(display.wrapper.clientHeight - 10,\n                                          headPos.top + lineOff.top - wrapOff.top));\n      result.teLeft = Math.max(0, Math.min(display.wrapper.clientWidth - 10,\n                                           headPos.left + lineOff.left - wrapOff.left));\n    }\n\n    return result\n  };\n\n  TextareaInput.prototype.showSelection = function (drawn) {\n    var cm = this.cm, display = cm.display;\n    removeChildrenAndAdd(display.cursorDiv, drawn.cursors);\n    removeChildrenAndAdd(display.selectionDiv, drawn.selection);\n    if (drawn.teTop != null) {\n      this.wrapper.style.top = drawn.teTop + \"px\";\n      this.wrapper.style.left = drawn.teLeft + \"px\";\n    }\n  };\n\n  // Reset the input to correspond to the selection (or to be empty,\n  // when not typing and nothing is selected)\n  TextareaInput.prototype.reset = function (typing) {\n    if (this.contextMenuPending || this.composing) { return }\n    var cm = this.cm;\n    if (cm.somethingSelected()) {\n      this.prevInput = \"\";\n      var content = cm.getSelection();\n      this.textarea.value = content;\n      if (cm.state.focused) { selectInput(this.textarea); }\n      if (ie && ie_version >= 9) { this.hasSelection = content; }\n    } else if (!typing) {\n      this.prevInput = this.textarea.value = \"\";\n      if (ie && ie_version >= 9) { this.hasSelection = null; }\n    }\n  };\n\n  TextareaInput.prototype.getField = function () { return this.textarea };\n\n  TextareaInput.prototype.supportsTouch = function () { return false };\n\n  TextareaInput.prototype.focus = function () {\n    if (this.cm.options.readOnly != \"nocursor\" && (!mobile || activeElt() != this.textarea)) {\n      try { this.textarea.focus(); }\n      catch (e) {} // IE8 will throw if the textarea is display: none or not in DOM\n    }\n  };\n\n  TextareaInput.prototype.blur = function () { this.textarea.blur(); };\n\n  TextareaInput.prototype.resetPosition = function () {\n    this.wrapper.style.top = this.wrapper.style.left = 0;\n  };\n\n  TextareaInput.prototype.receivedFocus = function () { this.slowPoll(); };\n\n  // Poll for input changes, using the normal rate of polling. This\n  // runs as long as the editor is focused.\n  TextareaInput.prototype.slowPoll = function () {\n      var this$1 = this;\n\n    if (this.pollingFast) { return }\n    this.polling.set(this.cm.options.pollInterval, function () {\n      this$1.poll();\n      if (this$1.cm.state.focused) { this$1.slowPoll(); }\n    });\n  };\n\n  // When an event has just come in that is likely to add or change\n  // something in the input textarea, we poll faster, to ensure that\n  // the change appears on the screen quickly.\n  TextareaInput.prototype.fastPoll = function () {\n    var missed = false, input = this;\n    input.pollingFast = true;\n    function p() {\n      var changed = input.poll();\n      if (!changed && !missed) {missed = true; input.polling.set(60, p);}\n      else {input.pollingFast = false; input.slowPoll();}\n    }\n    input.polling.set(20, p);\n  };\n\n  // Read input from the textarea, and update the document to match.\n  // When something is selected, it is present in the textarea, and\n  // selected (unless it is huge, in which case a placeholder is\n  // used). When nothing is selected, the cursor sits after previously\n  // seen text (can be empty), which is stored in prevInput (we must\n  // not reset the textarea when typing, because that breaks IME).\n  TextareaInput.prototype.poll = function () {\n      var this$1 = this;\n\n    var cm = this.cm, input = this.textarea, prevInput = this.prevInput;\n    // Since this is called a *lot*, try to bail out as cheaply as\n    // possible when it is clear that nothing happened. hasSelection\n    // will be the case when there is a lot of text in the textarea,\n    // in which case reading its value would be expensive.\n    if (this.contextMenuPending || !cm.state.focused ||\n        (hasSelection(input) && !prevInput && !this.composing) ||\n        cm.isReadOnly() || cm.options.disableInput || cm.state.keySeq)\n      { return false }\n\n    var text = input.value;\n    // If nothing changed, bail.\n    if (text == prevInput && !cm.somethingSelected()) { return false }\n    // Work around nonsensical selection resetting in IE9/10, and\n    // inexplicable appearance of private area unicode characters on\n    // some key combos in Mac (#2689).\n    if (ie && ie_version >= 9 && this.hasSelection === text ||\n        mac && /[\\uf700-\\uf7ff]/.test(text)) {\n      cm.display.input.reset();\n      return false\n    }\n\n    if (cm.doc.sel == cm.display.selForContextMenu) {\n      var first = text.charCodeAt(0);\n      if (first == 0x200b && !prevInput) { prevInput = \"\\u200b\"; }\n      if (first == 0x21da) { this.reset(); return this.cm.execCommand(\"undo\") }\n    }\n    // Find the part of the input that is actually new\n    var same = 0, l = Math.min(prevInput.length, text.length);\n    while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) { ++same; }\n\n    runInOp(cm, function () {\n      applyTextInput(cm, text.slice(same), prevInput.length - same,\n                     null, this$1.composing ? \"*compose\" : null);\n\n      // Don't leave long text in the textarea, since it makes further polling slow\n      if (text.length > 1000 || text.indexOf(\"\\n\") > -1) { input.value = this$1.prevInput = \"\"; }\n      else { this$1.prevInput = text; }\n\n      if (this$1.composing) {\n        this$1.composing.range.clear();\n        this$1.composing.range = cm.markText(this$1.composing.start, cm.getCursor(\"to\"),\n                                           {className: \"CodeMirror-composing\"});\n      }\n    });\n    return true\n  };\n\n  TextareaInput.prototype.ensurePolled = function () {\n    if (this.pollingFast && this.poll()) { this.pollingFast = false; }\n  };\n\n  TextareaInput.prototype.onKeyPress = function () {\n    if (ie && ie_version >= 9) { this.hasSelection = null; }\n    this.fastPoll();\n  };\n\n  TextareaInput.prototype.onContextMenu = function (e) {\n    var input = this, cm = input.cm, display = cm.display, te = input.textarea;\n    var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop;\n    if (!pos || presto) { return } // Opera is difficult.\n\n    // Reset the current text selection only if the click is done outside of the selection\n    // and 'resetSelectionOnContextMenu' option is true.\n    var reset = cm.options.resetSelectionOnContextMenu;\n    if (reset && cm.doc.sel.contains(pos) == -1)\n      { operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll); }\n\n    var oldCSS = te.style.cssText, oldWrapperCSS = input.wrapper.style.cssText;\n    input.wrapper.style.cssText = \"position: absolute\";\n    var wrapperBox = input.wrapper.getBoundingClientRect();\n    te.style.cssText = \"position: absolute; width: 30px; height: 30px;\\n      top: \" + (e.clientY - wrapperBox.top - 5) + \"px; left: \" + (e.clientX - wrapperBox.left - 5) + \"px;\\n      z-index: 1000; background: \" + (ie ? \"rgba(255, 255, 255, .05)\" : \"transparent\") + \";\\n      outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);\";\n    var oldScrollY;\n    if (webkit) { oldScrollY = window.scrollY; } // Work around Chrome issue (#2712)\n    display.input.focus();\n    if (webkit) { window.scrollTo(null, oldScrollY); }\n    display.input.reset();\n    // Adds \"Select all\" to context menu in FF\n    if (!cm.somethingSelected()) { te.value = input.prevInput = \" \"; }\n    input.contextMenuPending = true;\n    display.selForContextMenu = cm.doc.sel;\n    clearTimeout(display.detectingSelectAll);\n\n    // Select-all will be greyed out if there's nothing to select, so\n    // this adds a zero-width space so that we can later check whether\n    // it got selected.\n    function prepareSelectAllHack() {\n      if (te.selectionStart != null) {\n        var selected = cm.somethingSelected();\n        var extval = \"\\u200b\" + (selected ? te.value : \"\");\n        te.value = \"\\u21da\"; // Used to catch context-menu undo\n        te.value = extval;\n        input.prevInput = selected ? \"\" : \"\\u200b\";\n        te.selectionStart = 1; te.selectionEnd = extval.length;\n        // Re-set this, in case some other handler touched the\n        // selection in the meantime.\n        display.selForContextMenu = cm.doc.sel;\n      }\n    }\n    function rehide() {\n      input.contextMenuPending = false;\n      input.wrapper.style.cssText = oldWrapperCSS;\n      te.style.cssText = oldCSS;\n      if (ie && ie_version < 9) { display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos); }\n\n      // Try to detect the user choosing select-all\n      if (te.selectionStart != null) {\n        if (!ie || (ie && ie_version < 9)) { prepareSelectAllHack(); }\n        var i = 0, poll = function () {\n          if (display.selForContextMenu == cm.doc.sel && te.selectionStart == 0 &&\n              te.selectionEnd > 0 && input.prevInput == \"\\u200b\") {\n            operation(cm, selectAll)(cm);\n          } else if (i++ < 10) {\n            display.detectingSelectAll = setTimeout(poll, 500);\n          } else {\n            display.selForContextMenu = null;\n            display.input.reset();\n          }\n        };\n        display.detectingSelectAll = setTimeout(poll, 200);\n      }\n    }\n\n    if (ie && ie_version >= 9) { prepareSelectAllHack(); }\n    if (captureRightClick) {\n      e_stop(e);\n      var mouseup = function () {\n        off(window, \"mouseup\", mouseup);\n        setTimeout(rehide, 20);\n      };\n      on(window, \"mouseup\", mouseup);\n    } else {\n      setTimeout(rehide, 50);\n    }\n  };\n\n  TextareaInput.prototype.readOnlyChanged = function (val) {\n    if (!val) { this.reset(); }\n    this.textarea.disabled = val == \"nocursor\";\n  };\n\n  TextareaInput.prototype.setUneditable = function () {};\n\n  TextareaInput.prototype.needsContentAttribute = false;\n\n  function fromTextArea(textarea, options) {\n    options = options ? copyObj(options) : {};\n    options.value = textarea.value;\n    if (!options.tabindex && textarea.tabIndex)\n      { options.tabindex = textarea.tabIndex; }\n    if (!options.placeholder && textarea.placeholder)\n      { options.placeholder = textarea.placeholder; }\n    // Set autofocus to true if this textarea is focused, or if it has\n    // autofocus and no other element is focused.\n    if (options.autofocus == null) {\n      var hasFocus = activeElt();\n      options.autofocus = hasFocus == textarea ||\n        textarea.getAttribute(\"autofocus\") != null && hasFocus == document.body;\n    }\n\n    function save() {textarea.value = cm.getValue();}\n\n    var realSubmit;\n    if (textarea.form) {\n      on(textarea.form, \"submit\", save);\n      // Deplorable hack to make the submit method do the right thing.\n      if (!options.leaveSubmitMethodAlone) {\n        var form = textarea.form;\n        realSubmit = form.submit;\n        try {\n          var wrappedSubmit = form.submit = function () {\n            save();\n            form.submit = realSubmit;\n            form.submit();\n            form.submit = wrappedSubmit;\n          };\n        } catch(e) {}\n      }\n    }\n\n    options.finishInit = function (cm) {\n      cm.save = save;\n      cm.getTextArea = function () { return textarea; };\n      cm.toTextArea = function () {\n        cm.toTextArea = isNaN; // Prevent this from being ran twice\n        save();\n        textarea.parentNode.removeChild(cm.getWrapperElement());\n        textarea.style.display = \"\";\n        if (textarea.form) {\n          off(textarea.form, \"submit\", save);\n          if (typeof textarea.form.submit == \"function\")\n            { textarea.form.submit = realSubmit; }\n        }\n      };\n    };\n\n    textarea.style.display = \"none\";\n    var cm = CodeMirror(function (node) { return textarea.parentNode.insertBefore(node, textarea.nextSibling); },\n      options);\n    return cm\n  }\n\n  function addLegacyProps(CodeMirror) {\n    CodeMirror.off = off;\n    CodeMirror.on = on;\n    CodeMirror.wheelEventPixels = wheelEventPixels;\n    CodeMirror.Doc = Doc;\n    CodeMirror.splitLines = splitLinesAuto;\n    CodeMirror.countColumn = countColumn;\n    CodeMirror.findColumn = findColumn;\n    CodeMirror.isWordChar = isWordCharBasic;\n    CodeMirror.Pass = Pass;\n    CodeMirror.signal = signal;\n    CodeMirror.Line = Line;\n    CodeMirror.changeEnd = changeEnd;\n    CodeMirror.scrollbarModel = scrollbarModel;\n    CodeMirror.Pos = Pos;\n    CodeMirror.cmpPos = cmp;\n    CodeMirror.modes = modes;\n    CodeMirror.mimeModes = mimeModes;\n    CodeMirror.resolveMode = resolveMode;\n    CodeMirror.getMode = getMode;\n    CodeMirror.modeExtensions = modeExtensions;\n    CodeMirror.extendMode = extendMode;\n    CodeMirror.copyState = copyState;\n    CodeMirror.startState = startState;\n    CodeMirror.innerMode = innerMode;\n    CodeMirror.commands = commands;\n    CodeMirror.keyMap = keyMap;\n    CodeMirror.keyName = keyName;\n    CodeMirror.isModifierKey = isModifierKey;\n    CodeMirror.lookupKey = lookupKey;\n    CodeMirror.normalizeKeyMap = normalizeKeyMap;\n    CodeMirror.StringStream = StringStream;\n    CodeMirror.SharedTextMarker = SharedTextMarker;\n    CodeMirror.TextMarker = TextMarker;\n    CodeMirror.LineWidget = LineWidget;\n    CodeMirror.e_preventDefault = e_preventDefault;\n    CodeMirror.e_stopPropagation = e_stopPropagation;\n    CodeMirror.e_stop = e_stop;\n    CodeMirror.addClass = addClass;\n    CodeMirror.contains = contains;\n    CodeMirror.rmClass = rmClass;\n    CodeMirror.keyNames = keyNames;\n  }\n\n  // EDITOR CONSTRUCTOR\n\n  defineOptions(CodeMirror);\n\n  addEditorMethods(CodeMirror);\n\n  // Set up methods on CodeMirror's prototype to redirect to the editor's document.\n  var dontDelegate = \"iter insert remove copy getEditor constructor\".split(\" \");\n  for (var prop in Doc.prototype) { if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0)\n    { CodeMirror.prototype[prop] = (function(method) {\n      return function() {return method.apply(this.doc, arguments)}\n    })(Doc.prototype[prop]); } }\n\n  eventMixin(Doc);\n  CodeMirror.inputStyles = {\"textarea\": TextareaInput, \"contenteditable\": ContentEditableInput};\n\n  // Extra arguments are stored as the mode's dependencies, which is\n  // used by (legacy) mechanisms like loadmode.js to automatically\n  // load a mode. (Preferred mechanism is the require/define calls.)\n  CodeMirror.defineMode = function(name/*, mode, …*/) {\n    if (!CodeMirror.defaults.mode && name != \"null\") { CodeMirror.defaults.mode = name; }\n    defineMode.apply(this, arguments);\n  };\n\n  CodeMirror.defineMIME = defineMIME;\n\n  // Minimal default mode.\n  CodeMirror.defineMode(\"null\", function () { return ({token: function (stream) { return stream.skipToEnd(); }}); });\n  CodeMirror.defineMIME(\"text/plain\", \"null\");\n\n  // EXTENSIONS\n\n  CodeMirror.defineExtension = function (name, func) {\n    CodeMirror.prototype[name] = func;\n  };\n  CodeMirror.defineDocExtension = function (name, func) {\n    Doc.prototype[name] = func;\n  };\n\n  CodeMirror.fromTextArea = fromTextArea;\n\n  addLegacyProps(CodeMirror);\n\n  CodeMirror.version = \"5.41.0\";\n\n  return CodeMirror;\n\n})));\n"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/plugins/codemirror/mode/clike/clike.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: https://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nfunction Context(indented, column, type, info, align, prev) {\n  this.indented = indented;\n  this.column = column;\n  this.type = type;\n  this.info = info;\n  this.align = align;\n  this.prev = prev;\n}\nfunction pushContext(state, col, type, info) {\n  var indent = state.indented;\n  if (state.context && state.context.type == \"statement\" && type != \"statement\")\n    indent = state.context.indented;\n  return state.context = new Context(indent, col, type, info, null, state.context);\n}\nfunction popContext(state) {\n  var t = state.context.type;\n  if (t == \")\" || t == \"]\" || t == \"}\")\n    state.indented = state.context.indented;\n  return state.context = state.context.prev;\n}\n\nfunction typeBefore(stream, state, pos) {\n  if (state.prevToken == \"variable\" || state.prevToken == \"type\") return true;\n  if (/\\S(?:[^- ]>|[*\\]])\\s*$|\\*$/.test(stream.string.slice(0, pos))) return true;\n  if (state.typeAtEndOfLine && stream.column() == stream.indentation()) return true;\n}\n\nfunction isTopScope(context) {\n  for (;;) {\n    if (!context || context.type == \"top\") return true;\n    if (context.type == \"}\" && context.prev.info != \"namespace\") return false;\n    context = context.prev;\n  }\n}\n\nCodeMirror.defineMode(\"clike\", function(config, parserConfig) {\n  var indentUnit = config.indentUnit,\n      statementIndentUnit = parserConfig.statementIndentUnit || indentUnit,\n      dontAlignCalls = parserConfig.dontAlignCalls,\n      keywords = parserConfig.keywords || {},\n      types = parserConfig.types || {},\n      builtin = parserConfig.builtin || {},\n      blockKeywords = parserConfig.blockKeywords || {},\n      defKeywords = parserConfig.defKeywords || {},\n      atoms = parserConfig.atoms || {},\n      hooks = parserConfig.hooks || {},\n      multiLineStrings = parserConfig.multiLineStrings,\n      indentStatements = parserConfig.indentStatements !== false,\n      indentSwitch = parserConfig.indentSwitch !== false,\n      namespaceSeparator = parserConfig.namespaceSeparator,\n      isPunctuationChar = parserConfig.isPunctuationChar || /[\\[\\]{}\\(\\),;\\:\\.]/,\n      numberStart = parserConfig.numberStart || /[\\d\\.]/,\n      number = parserConfig.number || /^(?:0x[a-f\\d]+|0b[01]+|(?:\\d+\\.?\\d*|\\.\\d+)(?:e[-+]?\\d+)?)(u|ll?|l|f)?/i,\n      isOperatorChar = parserConfig.isOperatorChar || /[+\\-*&%=<>!?|\\/]/,\n      isIdentifierChar = parserConfig.isIdentifierChar || /[\\w\\$_\\xa1-\\uffff]/,\n      // An optional function that takes a {string} token and returns true if it\n      // should be treated as a builtin.\n      isReservedIdentifier = parserConfig.isReservedIdentifier || false;\n\n  var curPunc, isDefKeyword;\n\n  function tokenBase(stream, state) {\n    var ch = stream.next();\n    if (hooks[ch]) {\n      var result = hooks[ch](stream, state);\n      if (result !== false) return result;\n    }\n    if (ch == '\"' || ch == \"'\") {\n      state.tokenize = tokenString(ch);\n      return state.tokenize(stream, state);\n    }\n    if (isPunctuationChar.test(ch)) {\n      curPunc = ch;\n      return null;\n    }\n    if (numberStart.test(ch)) {\n      stream.backUp(1)\n      if (stream.match(number)) return \"number\"\n      stream.next()\n    }\n    if (ch == \"/\") {\n      if (stream.eat(\"*\")) {\n        state.tokenize = tokenComment;\n        return tokenComment(stream, state);\n      }\n      if (stream.eat(\"/\")) {\n        stream.skipToEnd();\n        return \"comment\";\n      }\n    }\n    if (isOperatorChar.test(ch)) {\n      while (!stream.match(/^\\/[\\/*]/, false) && stream.eat(isOperatorChar)) {}\n      return \"operator\";\n    }\n    stream.eatWhile(isIdentifierChar);\n    if (namespaceSeparator) while (stream.match(namespaceSeparator))\n      stream.eatWhile(isIdentifierChar);\n\n    var cur = stream.current();\n    if (contains(keywords, cur)) {\n      if (contains(blockKeywords, cur)) curPunc = \"newstatement\";\n      if (contains(defKeywords, cur)) isDefKeyword = true;\n      return \"keyword\";\n    }\n    if (contains(types, cur)) return \"type\";\n    if (contains(builtin, cur)\n        || (isReservedIdentifier && isReservedIdentifier(cur))) {\n      if (contains(blockKeywords, cur)) curPunc = \"newstatement\";\n      return \"builtin\";\n    }\n    if (contains(atoms, cur)) return \"atom\";\n    return \"variable\";\n  }\n\n  function tokenString(quote) {\n    return function(stream, state) {\n      var escaped = false, next, end = false;\n      while ((next = stream.next()) != null) {\n        if (next == quote && !escaped) {end = true; break;}\n        escaped = !escaped && next == \"\\\\\";\n      }\n      if (end || !(escaped || multiLineStrings))\n        state.tokenize = null;\n      return \"string\";\n    };\n  }\n\n  function tokenComment(stream, state) {\n    var maybeEnd = false, ch;\n    while (ch = stream.next()) {\n      if (ch == \"/\" && maybeEnd) {\n        state.tokenize = null;\n        break;\n      }\n      maybeEnd = (ch == \"*\");\n    }\n    return \"comment\";\n  }\n\n  function maybeEOL(stream, state) {\n    if (parserConfig.typeFirstDefinitions && stream.eol() && isTopScope(state.context))\n      state.typeAtEndOfLine = typeBefore(stream, state, stream.pos)\n  }\n\n  // Interface\n\n  return {\n    startState: function(basecolumn) {\n      return {\n        tokenize: null,\n        context: new Context((basecolumn || 0) - indentUnit, 0, \"top\", null, false),\n        indented: 0,\n        startOfLine: true,\n        prevToken: null\n      };\n    },\n\n    token: function(stream, state) {\n      var ctx = state.context;\n      if (stream.sol()) {\n        if (ctx.align == null) ctx.align = false;\n        state.indented = stream.indentation();\n        state.startOfLine = true;\n      }\n      if (stream.eatSpace()) { maybeEOL(stream, state); return null; }\n      curPunc = isDefKeyword = null;\n      var style = (state.tokenize || tokenBase)(stream, state);\n      if (style == \"comment\" || style == \"meta\") return style;\n      if (ctx.align == null) ctx.align = true;\n\n      if (curPunc == \";\" || curPunc == \":\" || (curPunc == \",\" && stream.match(/^\\s*(?:\\/\\/.*)?$/, false)))\n        while (state.context.type == \"statement\") popContext(state);\n      else if (curPunc == \"{\") pushContext(state, stream.column(), \"}\");\n      else if (curPunc == \"[\") pushContext(state, stream.column(), \"]\");\n      else if (curPunc == \"(\") pushContext(state, stream.column(), \")\");\n      else if (curPunc == \"}\") {\n        while (ctx.type == \"statement\") ctx = popContext(state);\n        if (ctx.type == \"}\") ctx = popContext(state);\n        while (ctx.type == \"statement\") ctx = popContext(state);\n      }\n      else if (curPunc == ctx.type) popContext(state);\n      else if (indentStatements &&\n               (((ctx.type == \"}\" || ctx.type == \"top\") && curPunc != \";\") ||\n                (ctx.type == \"statement\" && curPunc == \"newstatement\"))) {\n        pushContext(state, stream.column(), \"statement\", stream.current());\n      }\n\n      if (style == \"variable\" &&\n          ((state.prevToken == \"def\" ||\n            (parserConfig.typeFirstDefinitions && typeBefore(stream, state, stream.start) &&\n             isTopScope(state.context) && stream.match(/^\\s*\\(/, false)))))\n        style = \"def\";\n\n      if (hooks.token) {\n        var result = hooks.token(stream, state, style);\n        if (result !== undefined) style = result;\n      }\n\n      if (style == \"def\" && parserConfig.styleDefs === false) style = \"variable\";\n\n      state.startOfLine = false;\n      state.prevToken = isDefKeyword ? \"def\" : style || curPunc;\n      maybeEOL(stream, state);\n      return style;\n    },\n\n    indent: function(state, textAfter) {\n      if (state.tokenize != tokenBase && state.tokenize != null || state.typeAtEndOfLine) return CodeMirror.Pass;\n      var ctx = state.context, firstChar = textAfter && textAfter.charAt(0);\n      var closing = firstChar == ctx.type;\n      if (ctx.type == \"statement\" && firstChar == \"}\") ctx = ctx.prev;\n      if (parserConfig.dontIndentStatements)\n        while (ctx.type == \"statement\" && parserConfig.dontIndentStatements.test(ctx.info))\n          ctx = ctx.prev\n      if (hooks.indent) {\n        var hook = hooks.indent(state, ctx, textAfter, indentUnit);\n        if (typeof hook == \"number\") return hook\n      }\n      var switchBlock = ctx.prev && ctx.prev.info == \"switch\";\n      if (parserConfig.allmanIndentation && /[{(]/.test(firstChar)) {\n        while (ctx.type != \"top\" && ctx.type != \"}\") ctx = ctx.prev\n        return ctx.indented\n      }\n      if (ctx.type == \"statement\")\n        return ctx.indented + (firstChar == \"{\" ? 0 : statementIndentUnit);\n      if (ctx.align && (!dontAlignCalls || ctx.type != \")\"))\n        return ctx.column + (closing ? 0 : 1);\n      if (ctx.type == \")\" && !closing)\n        return ctx.indented + statementIndentUnit;\n\n      return ctx.indented + (closing ? 0 : indentUnit) +\n        (!closing && switchBlock && !/^(?:case|default)\\b/.test(textAfter) ? indentUnit : 0);\n    },\n\n    electricInput: indentSwitch ? /^\\s*(?:case .*?:|default:|\\{\\}?|\\})$/ : /^\\s*[{}]$/,\n    blockCommentStart: \"/*\",\n    blockCommentEnd: \"*/\",\n    blockCommentContinue: \" * \",\n    lineComment: \"//\",\n    fold: \"brace\"\n  };\n});\n\n  function words(str) {\n    var obj = {}, words = str.split(\" \");\n    for (var i = 0; i < words.length; ++i) obj[words[i]] = true;\n    return obj;\n  }\n  function contains(words, word) {\n    if (typeof words === \"function\") {\n      return words(word);\n    } else {\n      return words.propertyIsEnumerable(word);\n    }\n  }\n  var cKeywords = \"auto if break case register continue return default do sizeof \" +\n    \"static else struct switch extern typedef union for goto while enum const \" +\n    \"volatile inline restrict asm fortran\";\n\n  // Do not use this. Use the cTypes function below. This is global just to avoid\n  // excessive calls when cTypes is being called multiple times during a parse.\n  var basicCTypes = words(\"int long char short double float unsigned signed \" +\n    \"void bool\");\n\n  // Do not use this. Use the objCTypes function below. This is global just to avoid\n  // excessive calls when objCTypes is being called multiple times during a parse.\n  var basicObjCTypes = words(\"SEL instancetype id Class Protocol BOOL\");\n\n  // Returns true if identifier is a \"C\" type.\n  // C type is defined as those that are reserved by the compiler (basicTypes),\n  // and those that end in _t (Reserved by POSIX for types)\n  // http://www.gnu.org/software/libc/manual/html_node/Reserved-Names.html\n  function cTypes(identifier) {\n    return contains(basicCTypes, identifier) || /.+_t/.test(identifier);\n  }\n\n  // Returns true if identifier is a \"Objective C\" type.\n  function objCTypes(identifier) {\n    return cTypes(identifier) || contains(basicObjCTypes, identifier);\n  }\n\n  var cBlockKeywords = \"case do else for if switch while struct enum union\";\n  var cDefKeywords = \"struct enum union\";\n\n  function cppHook(stream, state) {\n    if (!state.startOfLine) return false\n    for (var ch, next = null; ch = stream.peek();) {\n      if (ch == \"\\\\\" && stream.match(/^.$/)) {\n        next = cppHook\n        break\n      } else if (ch == \"/\" && stream.match(/^\\/[\\/\\*]/, false)) {\n        break\n      }\n      stream.next()\n    }\n    state.tokenize = next\n    return \"meta\"\n  }\n\n  function pointerHook(_stream, state) {\n    if (state.prevToken == \"type\") return \"type\";\n    return false;\n  }\n\n  // For C and C++ (and ObjC): identifiers starting with __\n  // or _ followed by a capital letter are reserved for the compiler.\n  function cIsReservedIdentifier(token) {\n    if (!token || token.length < 2) return false;\n    if (token[0] != '_') return false;\n    return (token[1] == '_') || (token[1] !== token[1].toLowerCase());\n  }\n\n  function cpp14Literal(stream) {\n    stream.eatWhile(/[\\w\\.']/);\n    return \"number\";\n  }\n\n  function cpp11StringHook(stream, state) {\n    stream.backUp(1);\n    // Raw strings.\n    if (stream.match(/(R|u8R|uR|UR|LR)/)) {\n      var match = stream.match(/\"([^\\s\\\\()]{0,16})\\(/);\n      if (!match) {\n        return false;\n      }\n      state.cpp11RawStringDelim = match[1];\n      state.tokenize = tokenRawString;\n      return tokenRawString(stream, state);\n    }\n    // Unicode strings/chars.\n    if (stream.match(/(u8|u|U|L)/)) {\n      if (stream.match(/[\"']/, /* eat */ false)) {\n        return \"string\";\n      }\n      return false;\n    }\n    // Ignore this hook.\n    stream.next();\n    return false;\n  }\n\n  function cppLooksLikeConstructor(word) {\n    var lastTwo = /(\\w+)::~?(\\w+)$/.exec(word);\n    return lastTwo && lastTwo[1] == lastTwo[2];\n  }\n\n  // C#-style strings where \"\" escapes a quote.\n  function tokenAtString(stream, state) {\n    var next;\n    while ((next = stream.next()) != null) {\n      if (next == '\"' && !stream.eat('\"')) {\n        state.tokenize = null;\n        break;\n      }\n    }\n    return \"string\";\n  }\n\n  // C++11 raw string literal is <prefix>\"<delim>( anything )<delim>\", where\n  // <delim> can be a string up to 16 characters long.\n  function tokenRawString(stream, state) {\n    // Escape characters that have special regex meanings.\n    var delim = state.cpp11RawStringDelim.replace(/[^\\w\\s]/g, '\\\\$&');\n    var match = stream.match(new RegExp(\".*?\\\\)\" + delim + '\"'));\n    if (match)\n      state.tokenize = null;\n    else\n      stream.skipToEnd();\n    return \"string\";\n  }\n\n  function def(mimes, mode) {\n    if (typeof mimes == \"string\") mimes = [mimes];\n    var words = [];\n    function add(obj) {\n      if (obj) for (var prop in obj) if (obj.hasOwnProperty(prop))\n        words.push(prop);\n    }\n    add(mode.keywords);\n    add(mode.types);\n    add(mode.builtin);\n    add(mode.atoms);\n    if (words.length) {\n      mode.helperType = mimes[0];\n      CodeMirror.registerHelper(\"hintWords\", mimes[0], words);\n    }\n\n    for (var i = 0; i < mimes.length; ++i)\n      CodeMirror.defineMIME(mimes[i], mode);\n  }\n\n  def([\"text/x-csrc\", \"text/x-c\", \"text/x-chdr\"], {\n    name: \"clike\",\n    keywords: words(cKeywords),\n    types: cTypes,\n    blockKeywords: words(cBlockKeywords),\n    defKeywords: words(cDefKeywords),\n    typeFirstDefinitions: true,\n    atoms: words(\"NULL true false\"),\n    isReservedIdentifier: cIsReservedIdentifier,\n    hooks: {\n      \"#\": cppHook,\n      \"*\": pointerHook,\n    },\n    modeProps: {fold: [\"brace\", \"include\"]}\n  });\n\n  def([\"text/x-c++src\", \"text/x-c++hdr\"], {\n    name: \"clike\",\n    keywords: words(cKeywords + \" dynamic_cast namespace reinterpret_cast try explicit new \" +\n                    \"static_cast typeid catch operator template typename class friend private \" +\n                    \"this using const_cast public throw virtual delete mutable protected \" +\n                    \"alignas alignof constexpr decltype nullptr noexcept thread_local final \" +\n                    \"static_assert override\"),\n    types: cTypes,\n    blockKeywords: words(cBlockKeywords +\" class try catch finally\"),\n    defKeywords: words(cDefKeywords + \" class namespace\"),\n    typeFirstDefinitions: true,\n    atoms: words(\"true false NULL\"),\n    dontIndentStatements: /^template$/,\n    isIdentifierChar: /[\\w\\$_~\\xa1-\\uffff]/,\n    isReservedIdentifier: cIsReservedIdentifier,\n    hooks: {\n      \"#\": cppHook,\n      \"*\": pointerHook,\n      \"u\": cpp11StringHook,\n      \"U\": cpp11StringHook,\n      \"L\": cpp11StringHook,\n      \"R\": cpp11StringHook,\n      \"0\": cpp14Literal,\n      \"1\": cpp14Literal,\n      \"2\": cpp14Literal,\n      \"3\": cpp14Literal,\n      \"4\": cpp14Literal,\n      \"5\": cpp14Literal,\n      \"6\": cpp14Literal,\n      \"7\": cpp14Literal,\n      \"8\": cpp14Literal,\n      \"9\": cpp14Literal,\n      token: function(stream, state, style) {\n        if (style == \"variable\" && stream.peek() == \"(\" &&\n            (state.prevToken == \";\" || state.prevToken == null ||\n             state.prevToken == \"}\") &&\n            cppLooksLikeConstructor(stream.current()))\n          return \"def\";\n      }\n    },\n    namespaceSeparator: \"::\",\n    modeProps: {fold: [\"brace\", \"include\"]}\n  });\n\n  def(\"text/x-java\", {\n    name: \"clike\",\n    keywords: words(\"abstract assert break case catch class const continue default \" +\n                    \"do else enum extends final finally float for goto if implements import \" +\n                    \"instanceof interface native new package private protected public \" +\n                    \"return static strictfp super switch synchronized this throw throws transient \" +\n                    \"try volatile while @interface\"),\n    types: words(\"byte short int long float double boolean char void Boolean Byte Character Double Float \" +\n                 \"Integer Long Number Object Short String StringBuffer StringBuilder Void\"),\n    blockKeywords: words(\"catch class do else finally for if switch try while\"),\n    defKeywords: words(\"class interface enum @interface\"),\n    typeFirstDefinitions: true,\n    atoms: words(\"true false null\"),\n    number: /^(?:0x[a-f\\d_]+|0b[01_]+|(?:[\\d_]+\\.?\\d*|\\.\\d+)(?:e[-+]?[\\d_]+)?)(u|ll?|l|f)?/i,\n    hooks: {\n      \"@\": function(stream) {\n        // Don't match the @interface keyword.\n        if (stream.match('interface', false)) return false;\n\n        stream.eatWhile(/[\\w\\$_]/);\n        return \"meta\";\n      }\n    },\n    modeProps: {fold: [\"brace\", \"import\"]}\n  });\n\n  def(\"text/x-csharp\", {\n    name: \"clike\",\n    keywords: words(\"abstract as async await base break case catch checked class const continue\" +\n                    \" default delegate do else enum event explicit extern finally fixed for\" +\n                    \" foreach goto if implicit in interface internal is lock namespace new\" +\n                    \" operator out override params private protected public readonly ref return sealed\" +\n                    \" sizeof stackalloc static struct switch this throw try typeof unchecked\" +\n                    \" unsafe using virtual void volatile while add alias ascending descending dynamic from get\" +\n                    \" global group into join let orderby partial remove select set value var yield\"),\n    types: words(\"Action Boolean Byte Char DateTime DateTimeOffset Decimal Double Func\" +\n                 \" Guid Int16 Int32 Int64 Object SByte Single String Task TimeSpan UInt16 UInt32\" +\n                 \" UInt64 bool byte char decimal double short int long object\"  +\n                 \" sbyte float string ushort uint ulong\"),\n    blockKeywords: words(\"catch class do else finally for foreach if struct switch try while\"),\n    defKeywords: words(\"class interface namespace struct var\"),\n    typeFirstDefinitions: true,\n    atoms: words(\"true false null\"),\n    hooks: {\n      \"@\": function(stream, state) {\n        if (stream.eat('\"')) {\n          state.tokenize = tokenAtString;\n          return tokenAtString(stream, state);\n        }\n        stream.eatWhile(/[\\w\\$_]/);\n        return \"meta\";\n      }\n    }\n  });\n\n  function tokenTripleString(stream, state) {\n    var escaped = false;\n    while (!stream.eol()) {\n      if (!escaped && stream.match('\"\"\"')) {\n        state.tokenize = null;\n        break;\n      }\n      escaped = stream.next() == \"\\\\\" && !escaped;\n    }\n    return \"string\";\n  }\n\n  function tokenNestedComment(depth) {\n    return function (stream, state) {\n      var ch\n      while (ch = stream.next()) {\n        if (ch == \"*\" && stream.eat(\"/\")) {\n          if (depth == 1) {\n            state.tokenize = null\n            break\n          } else {\n            state.tokenize = tokenNestedComment(depth - 1)\n            return state.tokenize(stream, state)\n          }\n        } else if (ch == \"/\" && stream.eat(\"*\")) {\n          state.tokenize = tokenNestedComment(depth + 1)\n          return state.tokenize(stream, state)\n        }\n      }\n      return \"comment\"\n    }\n  }\n\n  def(\"text/x-scala\", {\n    name: \"clike\",\n    keywords: words(\n      /* scala */\n      \"abstract case catch class def do else extends final finally for forSome if \" +\n      \"implicit import lazy match new null object override package private protected return \" +\n      \"sealed super this throw trait try type val var while with yield _ \" +\n\n      /* package scala */\n      \"assert assume require print println printf readLine readBoolean readByte readShort \" +\n      \"readChar readInt readLong readFloat readDouble\"\n    ),\n    types: words(\n      \"AnyVal App Application Array BufferedIterator BigDecimal BigInt Char Console Either \" +\n      \"Enumeration Equiv Error Exception Fractional Function IndexedSeq Int Integral Iterable \" +\n      \"Iterator List Map Numeric Nil NotNull Option Ordered Ordering PartialFunction PartialOrdering \" +\n      \"Product Proxy Range Responder Seq Serializable Set Specializable Stream StringBuilder \" +\n      \"StringContext Symbol Throwable Traversable TraversableOnce Tuple Unit Vector \" +\n\n      /* package java.lang */\n      \"Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable \" +\n      \"Compiler Double Exception Float Integer Long Math Number Object Package Pair Process \" +\n      \"Runtime Runnable SecurityManager Short StackTraceElement StrictMath String \" +\n      \"StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void\"\n    ),\n    multiLineStrings: true,\n    blockKeywords: words(\"catch class enum do else finally for forSome if match switch try while\"),\n    defKeywords: words(\"class enum def object package trait type val var\"),\n    atoms: words(\"true false null\"),\n    indentStatements: false,\n    indentSwitch: false,\n    isOperatorChar: /[+\\-*&%=<>!?|\\/#:@]/,\n    hooks: {\n      \"@\": function(stream) {\n        stream.eatWhile(/[\\w\\$_]/);\n        return \"meta\";\n      },\n      '\"': function(stream, state) {\n        if (!stream.match('\"\"')) return false;\n        state.tokenize = tokenTripleString;\n        return state.tokenize(stream, state);\n      },\n      \"'\": function(stream) {\n        stream.eatWhile(/[\\w\\$_\\xa1-\\uffff]/);\n        return \"atom\";\n      },\n      \"=\": function(stream, state) {\n        var cx = state.context\n        if (cx.type == \"}\" && cx.align && stream.eat(\">\")) {\n          state.context = new Context(cx.indented, cx.column, cx.type, cx.info, null, cx.prev)\n          return \"operator\"\n        } else {\n          return false\n        }\n      },\n\n      \"/\": function(stream, state) {\n        if (!stream.eat(\"*\")) return false\n        state.tokenize = tokenNestedComment(1)\n        return state.tokenize(stream, state)\n      }\n    },\n    modeProps: {closeBrackets: {pairs: '()[]{}\"\"', triples: '\"'}}\n  });\n\n  function tokenKotlinString(tripleString){\n    return function (stream, state) {\n      var escaped = false, next, end = false;\n      while (!stream.eol()) {\n        if (!tripleString && !escaped && stream.match('\"') ) {end = true; break;}\n        if (tripleString && stream.match('\"\"\"')) {end = true; break;}\n        next = stream.next();\n        if(!escaped && next == \"$\" && stream.match('{'))\n          stream.skipTo(\"}\");\n        escaped = !escaped && next == \"\\\\\" && !tripleString;\n      }\n      if (end || !tripleString)\n        state.tokenize = null;\n      return \"string\";\n    }\n  }\n\n  def(\"text/x-kotlin\", {\n    name: \"clike\",\n    keywords: words(\n      /*keywords*/\n      \"package as typealias class interface this super val operator \" +\n      \"var fun for is in This throw return annotation \" +\n      \"break continue object if else while do try when !in !is as? \" +\n\n      /*soft keywords*/\n      \"file import where by get set abstract enum open inner override private public internal \" +\n      \"protected catch finally out final vararg reified dynamic companion constructor init \" +\n      \"sealed field property receiver param sparam lateinit data inline noinline tailrec \" +\n      \"external annotation crossinline const operator infix suspend actual expect setparam\"\n    ),\n    types: words(\n      /* package java.lang */\n      \"Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable \" +\n      \"Compiler Double Exception Float Integer Long Math Number Object Package Pair Process \" +\n      \"Runtime Runnable SecurityManager Short StackTraceElement StrictMath String \" +\n      \"StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void Annotation Any BooleanArray \" +\n      \"ByteArray Char CharArray DeprecationLevel DoubleArray Enum FloatArray Function Int IntArray Lazy \" +\n      \"LazyThreadSafetyMode LongArray Nothing ShortArray Unit\"\n    ),\n    intendSwitch: false,\n    indentStatements: false,\n    multiLineStrings: true,\n    number: /^(?:0x[a-f\\d_]+|0b[01_]+|(?:[\\d_]+(\\.\\d+)?|\\.\\d+)(?:e[-+]?[\\d_]+)?)(u|ll?|l|f)?/i,\n    blockKeywords: words(\"catch class do else finally for if where try while enum\"),\n    defKeywords: words(\"class val var object interface fun\"),\n    atoms: words(\"true false null this\"),\n    hooks: {\n      \"@\": function(stream) {\n        stream.eatWhile(/[\\w\\$_]/);\n        return \"meta\";\n      },\n      '\"': function(stream, state) {\n        state.tokenize = tokenKotlinString(stream.match('\"\"'));\n        return state.tokenize(stream, state);\n      },\n      indent: function(state, ctx, textAfter, indentUnit) {\n        var firstChar = textAfter && textAfter.charAt(0);\n        if ((state.prevToken == \"}\" || state.prevToken == \")\") && textAfter == \"\")\n          return state.indented;\n        if (state.prevToken == \"operator\" && textAfter != \"}\" ||\n          state.prevToken == \"variable\" && firstChar == \".\" ||\n          (state.prevToken == \"}\" || state.prevToken == \")\") && firstChar == \".\")\n          return indentUnit * 2 + ctx.indented;\n        if (ctx.align && ctx.type == \"}\")\n          return ctx.indented + (state.context.type == (textAfter || \"\").charAt(0) ? 0 : indentUnit);\n      }\n    },\n    modeProps: {closeBrackets: {triples: '\"'}}\n  });\n\n  def([\"x-shader/x-vertex\", \"x-shader/x-fragment\"], {\n    name: \"clike\",\n    keywords: words(\"sampler1D sampler2D sampler3D samplerCube \" +\n                    \"sampler1DShadow sampler2DShadow \" +\n                    \"const attribute uniform varying \" +\n                    \"break continue discard return \" +\n                    \"for while do if else struct \" +\n                    \"in out inout\"),\n    types: words(\"float int bool void \" +\n                 \"vec2 vec3 vec4 ivec2 ivec3 ivec4 bvec2 bvec3 bvec4 \" +\n                 \"mat2 mat3 mat4\"),\n    blockKeywords: words(\"for while do if else struct\"),\n    builtin: words(\"radians degrees sin cos tan asin acos atan \" +\n                    \"pow exp log exp2 sqrt inversesqrt \" +\n                    \"abs sign floor ceil fract mod min max clamp mix step smoothstep \" +\n                    \"length distance dot cross normalize ftransform faceforward \" +\n                    \"reflect refract matrixCompMult \" +\n                    \"lessThan lessThanEqual greaterThan greaterThanEqual \" +\n                    \"equal notEqual any all not \" +\n                    \"texture1D texture1DProj texture1DLod texture1DProjLod \" +\n                    \"texture2D texture2DProj texture2DLod texture2DProjLod \" +\n                    \"texture3D texture3DProj texture3DLod texture3DProjLod \" +\n                    \"textureCube textureCubeLod \" +\n                    \"shadow1D shadow2D shadow1DProj shadow2DProj \" +\n                    \"shadow1DLod shadow2DLod shadow1DProjLod shadow2DProjLod \" +\n                    \"dFdx dFdy fwidth \" +\n                    \"noise1 noise2 noise3 noise4\"),\n    atoms: words(\"true false \" +\n                \"gl_FragColor gl_SecondaryColor gl_Normal gl_Vertex \" +\n                \"gl_MultiTexCoord0 gl_MultiTexCoord1 gl_MultiTexCoord2 gl_MultiTexCoord3 \" +\n                \"gl_MultiTexCoord4 gl_MultiTexCoord5 gl_MultiTexCoord6 gl_MultiTexCoord7 \" +\n                \"gl_FogCoord gl_PointCoord \" +\n                \"gl_Position gl_PointSize gl_ClipVertex \" +\n                \"gl_FrontColor gl_BackColor gl_FrontSecondaryColor gl_BackSecondaryColor \" +\n                \"gl_TexCoord gl_FogFragCoord \" +\n                \"gl_FragCoord gl_FrontFacing \" +\n                \"gl_FragData gl_FragDepth \" +\n                \"gl_ModelViewMatrix gl_ProjectionMatrix gl_ModelViewProjectionMatrix \" +\n                \"gl_TextureMatrix gl_NormalMatrix gl_ModelViewMatrixInverse \" +\n                \"gl_ProjectionMatrixInverse gl_ModelViewProjectionMatrixInverse \" +\n                \"gl_TexureMatrixTranspose gl_ModelViewMatrixInverseTranspose \" +\n                \"gl_ProjectionMatrixInverseTranspose \" +\n                \"gl_ModelViewProjectionMatrixInverseTranspose \" +\n                \"gl_TextureMatrixInverseTranspose \" +\n                \"gl_NormalScale gl_DepthRange gl_ClipPlane \" +\n                \"gl_Point gl_FrontMaterial gl_BackMaterial gl_LightSource gl_LightModel \" +\n                \"gl_FrontLightModelProduct gl_BackLightModelProduct \" +\n                \"gl_TextureColor gl_EyePlaneS gl_EyePlaneT gl_EyePlaneR gl_EyePlaneQ \" +\n                \"gl_FogParameters \" +\n                \"gl_MaxLights gl_MaxClipPlanes gl_MaxTextureUnits gl_MaxTextureCoords \" +\n                \"gl_MaxVertexAttribs gl_MaxVertexUniformComponents gl_MaxVaryingFloats \" +\n                \"gl_MaxVertexTextureImageUnits gl_MaxTextureImageUnits \" +\n                \"gl_MaxFragmentUniformComponents gl_MaxCombineTextureImageUnits \" +\n                \"gl_MaxDrawBuffers\"),\n    indentSwitch: false,\n    hooks: {\"#\": cppHook},\n    modeProps: {fold: [\"brace\", \"include\"]}\n  });\n\n  def(\"text/x-nesc\", {\n    name: \"clike\",\n    keywords: words(cKeywords + \" as atomic async call command component components configuration event generic \" +\n                    \"implementation includes interface module new norace nx_struct nx_union post provides \" +\n                    \"signal task uses abstract extends\"),\n    types: cTypes,\n    blockKeywords: words(cBlockKeywords),\n    atoms: words(\"null true false\"),\n    hooks: {\"#\": cppHook},\n    modeProps: {fold: [\"brace\", \"include\"]}\n  });\n\n  def(\"text/x-objectivec\", {\n    name: \"clike\",\n    keywords: words(cKeywords + \" bycopy byref in inout oneway out self super atomic nonatomic retain copy \" +\n                    \"readwrite readonly strong weak assign typeof nullable nonnull null_resettable _cmd \" +\n                    \"@interface @implementation @end @protocol @encode @property @synthesize @dynamic @class \" +\n                    \"@public @package @private @protected @required @optional @try @catch @finally @import \" +\n                    \"@selector @encode @defs @synchronized @autoreleasepool @compatibility_alias @available\"),\n    types: objCTypes,\n    builtin: words(\"FOUNDATION_EXPORT FOUNDATION_EXTERN NS_INLINE NS_FORMAT_FUNCTION NS_RETURNS_RETAINED \" +\n                   \"NS_ERROR_ENUM NS_RETURNS_NOT_RETAINED NS_RETURNS_INNER_POINTER NS_DESIGNATED_INITIALIZER \" +\n                   \"NS_ENUM NS_OPTIONS NS_REQUIRES_NIL_TERMINATION NS_ASSUME_NONNULL_BEGIN \" +\n                   \"NS_ASSUME_NONNULL_END NS_SWIFT_NAME NS_REFINED_FOR_SWIFT\"),\n    blockKeywords: words(cBlockKeywords + \" @synthesize @try @catch @finally @autoreleasepool @synchronized\"),\n    defKeywords: words(cDefKeywords + \" @interface @implementation @protocol @class\"),\n    dontIndentStatements: /^@.*$/,\n    typeFirstDefinitions: true,\n    atoms: words(\"YES NO NULL Nil nil true false nullptr\"),\n    isReservedIdentifier: cIsReservedIdentifier,\n    hooks: {\n      \"#\": cppHook,\n      \"*\": pointerHook,\n    },\n    modeProps: {fold: [\"brace\", \"include\"]}\n  });\n\n  def(\"text/x-squirrel\", {\n    name: \"clike\",\n    keywords: words(\"base break clone continue const default delete enum extends function in class\" +\n                    \" foreach local resume return this throw typeof yield constructor instanceof static\"),\n    types: cTypes,\n    blockKeywords: words(\"case catch class else for foreach if switch try while\"),\n    defKeywords: words(\"function local class\"),\n    typeFirstDefinitions: true,\n    atoms: words(\"true false null\"),\n    hooks: {\"#\": cppHook},\n    modeProps: {fold: [\"brace\", \"include\"]}\n  });\n\n  // Ceylon Strings need to deal with interpolation\n  var stringTokenizer = null;\n  function tokenCeylonString(type) {\n    return function(stream, state) {\n      var escaped = false, next, end = false;\n      while (!stream.eol()) {\n        if (!escaped && stream.match('\"') &&\n              (type == \"single\" || stream.match('\"\"'))) {\n          end = true;\n          break;\n        }\n        if (!escaped && stream.match('``')) {\n          stringTokenizer = tokenCeylonString(type);\n          end = true;\n          break;\n        }\n        next = stream.next();\n        escaped = type == \"single\" && !escaped && next == \"\\\\\";\n      }\n      if (end)\n          state.tokenize = null;\n      return \"string\";\n    }\n  }\n\n  def(\"text/x-ceylon\", {\n    name: \"clike\",\n    keywords: words(\"abstracts alias assembly assert assign break case catch class continue dynamic else\" +\n                    \" exists extends finally for function given if import in interface is let module new\" +\n                    \" nonempty object of out outer package return satisfies super switch then this throw\" +\n                    \" try value void while\"),\n    types: function(word) {\n        // In Ceylon all identifiers that start with an uppercase are types\n        var first = word.charAt(0);\n        return (first === first.toUpperCase() && first !== first.toLowerCase());\n    },\n    blockKeywords: words(\"case catch class dynamic else finally for function if interface module new object switch try while\"),\n    defKeywords: words(\"class dynamic function interface module object package value\"),\n    builtin: words(\"abstract actual aliased annotation by default deprecated doc final formal late license\" +\n                   \" native optional sealed see serializable shared suppressWarnings tagged throws variable\"),\n    isPunctuationChar: /[\\[\\]{}\\(\\),;\\:\\.`]/,\n    isOperatorChar: /[+\\-*&%=<>!?|^~:\\/]/,\n    numberStart: /[\\d#$]/,\n    number: /^(?:#[\\da-fA-F_]+|\\$[01_]+|[\\d_]+[kMGTPmunpf]?|[\\d_]+\\.[\\d_]+(?:[eE][-+]?\\d+|[kMGTPmunpf]|)|)/i,\n    multiLineStrings: true,\n    typeFirstDefinitions: true,\n    atoms: words(\"true false null larger smaller equal empty finished\"),\n    indentSwitch: false,\n    styleDefs: false,\n    hooks: {\n      \"@\": function(stream) {\n        stream.eatWhile(/[\\w\\$_]/);\n        return \"meta\";\n      },\n      '\"': function(stream, state) {\n          state.tokenize = tokenCeylonString(stream.match('\"\"') ? \"triple\" : \"single\");\n          return state.tokenize(stream, state);\n        },\n      '`': function(stream, state) {\n          if (!stringTokenizer || !stream.match('`')) return false;\n          state.tokenize = stringTokenizer;\n          stringTokenizer = null;\n          return state.tokenize(stream, state);\n        },\n      \"'\": function(stream) {\n        stream.eatWhile(/[\\w\\$_\\xa1-\\uffff]/);\n        return \"atom\";\n      },\n      token: function(_stream, state, style) {\n          if ((style == \"variable\" || style == \"type\") &&\n              state.prevToken == \".\") {\n            return \"variable-2\";\n          }\n        }\n    },\n    modeProps: {\n        fold: [\"brace\", \"import\"],\n        closeBrackets: {triples: '\"'}\n    }\n  });\n\n});\n"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/plugins/codemirror/mode/javascript/javascript.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: https://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"javascript\", function(config, parserConfig) {\n  var indentUnit = config.indentUnit;\n  var statementIndent = parserConfig.statementIndent;\n  var jsonldMode = parserConfig.jsonld;\n  var jsonMode = parserConfig.json || jsonldMode;\n  var isTS = parserConfig.typescript;\n  var wordRE = parserConfig.wordCharacters || /[\\w$\\xa1-\\uffff]/;\n\n  // Tokenizer\n\n  var keywords = function(){\n    function kw(type) {return {type: type, style: \"keyword\"};}\n    var A = kw(\"keyword a\"), B = kw(\"keyword b\"), C = kw(\"keyword c\"), D = kw(\"keyword d\");\n    var operator = kw(\"operator\"), atom = {type: \"atom\", style: \"atom\"};\n\n    return {\n      \"if\": kw(\"if\"), \"while\": A, \"with\": A, \"else\": B, \"do\": B, \"try\": B, \"finally\": B,\n      \"return\": D, \"break\": D, \"continue\": D, \"new\": kw(\"new\"), \"delete\": C, \"void\": C, \"throw\": C,\n      \"debugger\": kw(\"debugger\"), \"var\": kw(\"var\"), \"const\": kw(\"var\"), \"let\": kw(\"var\"),\n      \"function\": kw(\"function\"), \"catch\": kw(\"catch\"),\n      \"for\": kw(\"for\"), \"switch\": kw(\"switch\"), \"case\": kw(\"case\"), \"default\": kw(\"default\"),\n      \"in\": operator, \"typeof\": operator, \"instanceof\": operator,\n      \"true\": atom, \"false\": atom, \"null\": atom, \"undefined\": atom, \"NaN\": atom, \"Infinity\": atom,\n      \"this\": kw(\"this\"), \"class\": kw(\"class\"), \"super\": kw(\"atom\"),\n      \"yield\": C, \"export\": kw(\"export\"), \"import\": kw(\"import\"), \"extends\": C,\n      \"await\": C\n    };\n  }();\n\n  var isOperatorChar = /[+\\-*&%=<>!?|~^@]/;\n  var isJsonldKeyword = /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)\"/;\n\n  function readRegexp(stream) {\n    var escaped = false, next, inSet = false;\n    while ((next = stream.next()) != null) {\n      if (!escaped) {\n        if (next == \"/\" && !inSet) return;\n        if (next == \"[\") inSet = true;\n        else if (inSet && next == \"]\") inSet = false;\n      }\n      escaped = !escaped && next == \"\\\\\";\n    }\n  }\n\n  // Used as scratch variables to communicate multiple values without\n  // consing up tons of objects.\n  var type, content;\n  function ret(tp, style, cont) {\n    type = tp; content = cont;\n    return style;\n  }\n  function tokenBase(stream, state) {\n    var ch = stream.next();\n    if (ch == '\"' || ch == \"'\") {\n      state.tokenize = tokenString(ch);\n      return state.tokenize(stream, state);\n    } else if (ch == \".\" && stream.match(/^\\d+(?:[eE][+\\-]?\\d+)?/)) {\n      return ret(\"number\", \"number\");\n    } else if (ch == \".\" && stream.match(\"..\")) {\n      return ret(\"spread\", \"meta\");\n    } else if (/[\\[\\]{}\\(\\),;\\:\\.]/.test(ch)) {\n      return ret(ch);\n    } else if (ch == \"=\" && stream.eat(\">\")) {\n      return ret(\"=>\", \"operator\");\n    } else if (ch == \"0\" && stream.match(/^(?:x[\\da-f]+|o[0-7]+|b[01]+)n?/i)) {\n      return ret(\"number\", \"number\");\n    } else if (/\\d/.test(ch)) {\n      stream.match(/^\\d*(?:n|(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?)?/);\n      return ret(\"number\", \"number\");\n    } else if (ch == \"/\") {\n      if (stream.eat(\"*\")) {\n        state.tokenize = tokenComment;\n        return tokenComment(stream, state);\n      } else if (stream.eat(\"/\")) {\n        stream.skipToEnd();\n        return ret(\"comment\", \"comment\");\n      } else if (expressionAllowed(stream, state, 1)) {\n        readRegexp(stream);\n        stream.match(/^\\b(([gimyus])(?![gimyus]*\\2))+\\b/);\n        return ret(\"regexp\", \"string-2\");\n      } else {\n        stream.eat(\"=\");\n        return ret(\"operator\", \"operator\", stream.current());\n      }\n    } else if (ch == \"`\") {\n      state.tokenize = tokenQuasi;\n      return tokenQuasi(stream, state);\n    } else if (ch == \"#\") {\n      stream.skipToEnd();\n      return ret(\"error\", \"error\");\n    } else if (isOperatorChar.test(ch)) {\n      if (ch != \">\" || !state.lexical || state.lexical.type != \">\") {\n        if (stream.eat(\"=\")) {\n          if (ch == \"!\" || ch == \"=\") stream.eat(\"=\")\n        } else if (/[<>*+\\-]/.test(ch)) {\n          stream.eat(ch)\n          if (ch == \">\") stream.eat(ch)\n        }\n      }\n      return ret(\"operator\", \"operator\", stream.current());\n    } else if (wordRE.test(ch)) {\n      stream.eatWhile(wordRE);\n      var word = stream.current()\n      if (state.lastType != \".\") {\n        if (keywords.propertyIsEnumerable(word)) {\n          var kw = keywords[word]\n          return ret(kw.type, kw.style, word)\n        }\n        if (word == \"async\" && stream.match(/^(\\s|\\/\\*.*?\\*\\/)*[\\[\\(\\w]/, false))\n          return ret(\"async\", \"keyword\", word)\n      }\n      return ret(\"variable\", \"variable\", word)\n    }\n  }\n\n  function tokenString(quote) {\n    return function(stream, state) {\n      var escaped = false, next;\n      if (jsonldMode && stream.peek() == \"@\" && stream.match(isJsonldKeyword)){\n        state.tokenize = tokenBase;\n        return ret(\"jsonld-keyword\", \"meta\");\n      }\n      while ((next = stream.next()) != null) {\n        if (next == quote && !escaped) break;\n        escaped = !escaped && next == \"\\\\\";\n      }\n      if (!escaped) state.tokenize = tokenBase;\n      return ret(\"string\", \"string\");\n    };\n  }\n\n  function tokenComment(stream, state) {\n    var maybeEnd = false, ch;\n    while (ch = stream.next()) {\n      if (ch == \"/\" && maybeEnd) {\n        state.tokenize = tokenBase;\n        break;\n      }\n      maybeEnd = (ch == \"*\");\n    }\n    return ret(\"comment\", \"comment\");\n  }\n\n  function tokenQuasi(stream, state) {\n    var escaped = false, next;\n    while ((next = stream.next()) != null) {\n      if (!escaped && (next == \"`\" || next == \"$\" && stream.eat(\"{\"))) {\n        state.tokenize = tokenBase;\n        break;\n      }\n      escaped = !escaped && next == \"\\\\\";\n    }\n    return ret(\"quasi\", \"string-2\", stream.current());\n  }\n\n  var brackets = \"([{}])\";\n  // This is a crude lookahead trick to try and notice that we're\n  // parsing the argument patterns for a fat-arrow function before we\n  // actually hit the arrow token. It only works if the arrow is on\n  // the same line as the arguments and there's no strange noise\n  // (comments) in between. Fallback is to only notice when we hit the\n  // arrow, and not declare the arguments as locals for the arrow\n  // body.\n  function findFatArrow(stream, state) {\n    if (state.fatArrowAt) state.fatArrowAt = null;\n    var arrow = stream.string.indexOf(\"=>\", stream.start);\n    if (arrow < 0) return;\n\n    if (isTS) { // Try to skip TypeScript return type declarations after the arguments\n      var m = /:\\s*(?:\\w+(?:<[^>]*>|\\[\\])?|\\{[^}]*\\})\\s*$/.exec(stream.string.slice(stream.start, arrow))\n      if (m) arrow = m.index\n    }\n\n    var depth = 0, sawSomething = false;\n    for (var pos = arrow - 1; pos >= 0; --pos) {\n      var ch = stream.string.charAt(pos);\n      var bracket = brackets.indexOf(ch);\n      if (bracket >= 0 && bracket < 3) {\n        if (!depth) { ++pos; break; }\n        if (--depth == 0) { if (ch == \"(\") sawSomething = true; break; }\n      } else if (bracket >= 3 && bracket < 6) {\n        ++depth;\n      } else if (wordRE.test(ch)) {\n        sawSomething = true;\n      } else if (/[\"'\\/]/.test(ch)) {\n        return;\n      } else if (sawSomething && !depth) {\n        ++pos;\n        break;\n      }\n    }\n    if (sawSomething && !depth) state.fatArrowAt = pos;\n  }\n\n  // Parser\n\n  var atomicTypes = {\"atom\": true, \"number\": true, \"variable\": true, \"string\": true, \"regexp\": true, \"this\": true, \"jsonld-keyword\": true};\n\n  function JSLexical(indented, column, type, align, prev, info) {\n    this.indented = indented;\n    this.column = column;\n    this.type = type;\n    this.prev = prev;\n    this.info = info;\n    if (align != null) this.align = align;\n  }\n\n  function inScope(state, varname) {\n    for (var v = state.localVars; v; v = v.next)\n      if (v.name == varname) return true;\n    for (var cx = state.context; cx; cx = cx.prev) {\n      for (var v = cx.vars; v; v = v.next)\n        if (v.name == varname) return true;\n    }\n  }\n\n  function parseJS(state, style, type, content, stream) {\n    var cc = state.cc;\n    // Communicate our context to the combinators.\n    // (Less wasteful than consing up a hundred closures on every call.)\n    cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; cx.style = style;\n\n    if (!state.lexical.hasOwnProperty(\"align\"))\n      state.lexical.align = true;\n\n    while(true) {\n      var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement;\n      if (combinator(type, content)) {\n        while(cc.length && cc[cc.length - 1].lex)\n          cc.pop()();\n        if (cx.marked) return cx.marked;\n        if (type == \"variable\" && inScope(state, content)) return \"variable-2\";\n        return style;\n      }\n    }\n  }\n\n  // Combinator utils\n\n  var cx = {state: null, column: null, marked: null, cc: null};\n  function pass() {\n    for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]);\n  }\n  function cont() {\n    pass.apply(null, arguments);\n    return true;\n  }\n  function inList(name, list) {\n    for (var v = list; v; v = v.next) if (v.name == name) return true\n    return false;\n  }\n  function register(varname) {\n    var state = cx.state;\n    cx.marked = \"def\";\n    if (state.context) {\n      if (state.lexical.info == \"var\" && state.context && state.context.block) {\n        // FIXME function decls are also not block scoped\n        var newContext = registerVarScoped(varname, state.context)\n        if (newContext != null) {\n          state.context = newContext\n          return\n        }\n      } else if (!inList(varname, state.localVars)) {\n        state.localVars = new Var(varname, state.localVars)\n        return\n      }\n    }\n    // Fall through means this is global\n    if (parserConfig.globalVars && !inList(varname, state.globalVars))\n      state.globalVars = new Var(varname, state.globalVars)\n  }\n  function registerVarScoped(varname, context) {\n    if (!context) {\n      return null\n    } else if (context.block) {\n      var inner = registerVarScoped(varname, context.prev)\n      if (!inner) return null\n      if (inner == context.prev) return context\n      return new Context(inner, context.vars, true)\n    } else if (inList(varname, context.vars)) {\n      return context\n    } else {\n      return new Context(context.prev, new Var(varname, context.vars), false)\n    }\n  }\n\n  function isModifier(name) {\n    return name == \"public\" || name == \"private\" || name == \"protected\" || name == \"abstract\" || name == \"readonly\"\n  }\n\n  // Combinators\n\n  function Context(prev, vars, block) { this.prev = prev; this.vars = vars; this.block = block }\n  function Var(name, next) { this.name = name; this.next = next }\n\n  var defaultVars = new Var(\"this\", new Var(\"arguments\", null))\n  function pushcontext() {\n    cx.state.context = new Context(cx.state.context, cx.state.localVars, false)\n    cx.state.localVars = defaultVars\n  }\n  function pushblockcontext() {\n    cx.state.context = new Context(cx.state.context, cx.state.localVars, true)\n    cx.state.localVars = null\n  }\n  function popcontext() {\n    cx.state.localVars = cx.state.context.vars\n    cx.state.context = cx.state.context.prev\n  }\n  popcontext.lex = true\n  function pushlex(type, info) {\n    var result = function() {\n      var state = cx.state, indent = state.indented;\n      if (state.lexical.type == \"stat\") indent = state.lexical.indented;\n      else for (var outer = state.lexical; outer && outer.type == \")\" && outer.align; outer = outer.prev)\n        indent = outer.indented;\n      state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info);\n    };\n    result.lex = true;\n    return result;\n  }\n  function poplex() {\n    var state = cx.state;\n    if (state.lexical.prev) {\n      if (state.lexical.type == \")\")\n        state.indented = state.lexical.indented;\n      state.lexical = state.lexical.prev;\n    }\n  }\n  poplex.lex = true;\n\n  function expect(wanted) {\n    function exp(type) {\n      if (type == wanted) return cont();\n      else if (wanted == \";\" || type == \"}\" || type == \")\" || type == \"]\") return pass();\n      else return cont(exp);\n    };\n    return exp;\n  }\n\n  function statement(type, value) {\n    if (type == \"var\") return cont(pushlex(\"vardef\", value), vardef, expect(\";\"), poplex);\n    if (type == \"keyword a\") return cont(pushlex(\"form\"), parenExpr, statement, poplex);\n    if (type == \"keyword b\") return cont(pushlex(\"form\"), statement, poplex);\n    if (type == \"keyword d\") return cx.stream.match(/^\\s*$/, false) ? cont() : cont(pushlex(\"stat\"), maybeexpression, expect(\";\"), poplex);\n    if (type == \"debugger\") return cont(expect(\";\"));\n    if (type == \"{\") return cont(pushlex(\"}\"), pushblockcontext, block, poplex, popcontext);\n    if (type == \";\") return cont();\n    if (type == \"if\") {\n      if (cx.state.lexical.info == \"else\" && cx.state.cc[cx.state.cc.length - 1] == poplex)\n        cx.state.cc.pop()();\n      return cont(pushlex(\"form\"), parenExpr, statement, poplex, maybeelse);\n    }\n    if (type == \"function\") return cont(functiondef);\n    if (type == \"for\") return cont(pushlex(\"form\"), forspec, statement, poplex);\n    if (type == \"class\" || (isTS && value == \"interface\")) { cx.marked = \"keyword\"; return cont(pushlex(\"form\"), className, poplex); }\n    if (type == \"variable\") {\n      if (isTS && value == \"declare\") {\n        cx.marked = \"keyword\"\n        return cont(statement)\n      } else if (isTS && (value == \"module\" || value == \"enum\" || value == \"type\") && cx.stream.match(/^\\s*\\w/, false)) {\n        cx.marked = \"keyword\"\n        if (value == \"enum\") return cont(enumdef);\n        else if (value == \"type\") return cont(typeexpr, expect(\"operator\"), typeexpr, expect(\";\"));\n        else return cont(pushlex(\"form\"), pattern, expect(\"{\"), pushlex(\"}\"), block, poplex, poplex)\n      } else if (isTS && value == \"namespace\") {\n        cx.marked = \"keyword\"\n        return cont(pushlex(\"form\"), expression, block, poplex)\n      } else if (isTS && value == \"abstract\") {\n        cx.marked = \"keyword\"\n        return cont(statement)\n      } else {\n        return cont(pushlex(\"stat\"), maybelabel);\n      }\n    }\n    if (type == \"switch\") return cont(pushlex(\"form\"), parenExpr, expect(\"{\"), pushlex(\"}\", \"switch\"), pushblockcontext,\n                                      block, poplex, poplex, popcontext);\n    if (type == \"case\") return cont(expression, expect(\":\"));\n    if (type == \"default\") return cont(expect(\":\"));\n    if (type == \"catch\") return cont(pushlex(\"form\"), pushcontext, maybeCatchBinding, statement, poplex, popcontext);\n    if (type == \"export\") return cont(pushlex(\"stat\"), afterExport, poplex);\n    if (type == \"import\") return cont(pushlex(\"stat\"), afterImport, poplex);\n    if (type == \"async\") return cont(statement)\n    if (value == \"@\") return cont(expression, statement)\n    return pass(pushlex(\"stat\"), expression, expect(\";\"), poplex);\n  }\n  function maybeCatchBinding(type) {\n    if (type == \"(\") return cont(funarg, expect(\")\"))\n  }\n  function expression(type, value) {\n    return expressionInner(type, value, false);\n  }\n  function expressionNoComma(type, value) {\n    return expressionInner(type, value, true);\n  }\n  function parenExpr(type) {\n    if (type != \"(\") return pass()\n    return cont(pushlex(\")\"), expression, expect(\")\"), poplex)\n  }\n  function expressionInner(type, value, noComma) {\n    if (cx.state.fatArrowAt == cx.stream.start) {\n      var body = noComma ? arrowBodyNoComma : arrowBody;\n      if (type == \"(\") return cont(pushcontext, pushlex(\")\"), commasep(funarg, \")\"), poplex, expect(\"=>\"), body, popcontext);\n      else if (type == \"variable\") return pass(pushcontext, pattern, expect(\"=>\"), body, popcontext);\n    }\n\n    var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma;\n    if (atomicTypes.hasOwnProperty(type)) return cont(maybeop);\n    if (type == \"function\") return cont(functiondef, maybeop);\n    if (type == \"class\" || (isTS && value == \"interface\")) { cx.marked = \"keyword\"; return cont(pushlex(\"form\"), classExpression, poplex); }\n    if (type == \"keyword c\" || type == \"async\") return cont(noComma ? expressionNoComma : expression);\n    if (type == \"(\") return cont(pushlex(\")\"), maybeexpression, expect(\")\"), poplex, maybeop);\n    if (type == \"operator\" || type == \"spread\") return cont(noComma ? expressionNoComma : expression);\n    if (type == \"[\") return cont(pushlex(\"]\"), arrayLiteral, poplex, maybeop);\n    if (type == \"{\") return contCommasep(objprop, \"}\", null, maybeop);\n    if (type == \"quasi\") return pass(quasi, maybeop);\n    if (type == \"new\") return cont(maybeTarget(noComma));\n    if (type == \"import\") return cont(expression);\n    return cont();\n  }\n  function maybeexpression(type) {\n    if (type.match(/[;\\}\\)\\],]/)) return pass();\n    return pass(expression);\n  }\n\n  function maybeoperatorComma(type, value) {\n    if (type == \",\") return cont(expression);\n    return maybeoperatorNoComma(type, value, false);\n  }\n  function maybeoperatorNoComma(type, value, noComma) {\n    var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma;\n    var expr = noComma == false ? expression : expressionNoComma;\n    if (type == \"=>\") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext);\n    if (type == \"operator\") {\n      if (/\\+\\+|--/.test(value) || isTS && value == \"!\") return cont(me);\n      if (isTS && value == \"<\" && cx.stream.match(/^([^>]|<.*?>)*>\\s*\\(/, false))\n        return cont(pushlex(\">\"), commasep(typeexpr, \">\"), poplex, me);\n      if (value == \"?\") return cont(expression, expect(\":\"), expr);\n      return cont(expr);\n    }\n    if (type == \"quasi\") { return pass(quasi, me); }\n    if (type == \";\") return;\n    if (type == \"(\") return contCommasep(expressionNoComma, \")\", \"call\", me);\n    if (type == \".\") return cont(property, me);\n    if (type == \"[\") return cont(pushlex(\"]\"), maybeexpression, expect(\"]\"), poplex, me);\n    if (isTS && value == \"as\") { cx.marked = \"keyword\"; return cont(typeexpr, me) }\n    if (type == \"regexp\") {\n      cx.state.lastType = cx.marked = \"operator\"\n      cx.stream.backUp(cx.stream.pos - cx.stream.start - 1)\n      return cont(expr)\n    }\n  }\n  function quasi(type, value) {\n    if (type != \"quasi\") return pass();\n    if (value.slice(value.length - 2) != \"${\") return cont(quasi);\n    return cont(expression, continueQuasi);\n  }\n  function continueQuasi(type) {\n    if (type == \"}\") {\n      cx.marked = \"string-2\";\n      cx.state.tokenize = tokenQuasi;\n      return cont(quasi);\n    }\n  }\n  function arrowBody(type) {\n    findFatArrow(cx.stream, cx.state);\n    return pass(type == \"{\" ? statement : expression);\n  }\n  function arrowBodyNoComma(type) {\n    findFatArrow(cx.stream, cx.state);\n    return pass(type == \"{\" ? statement : expressionNoComma);\n  }\n  function maybeTarget(noComma) {\n    return function(type) {\n      if (type == \".\") return cont(noComma ? targetNoComma : target);\n      else if (type == \"variable\" && isTS) return cont(maybeTypeArgs, noComma ? maybeoperatorNoComma : maybeoperatorComma)\n      else return pass(noComma ? expressionNoComma : expression);\n    };\n  }\n  function target(_, value) {\n    if (value == \"target\") { cx.marked = \"keyword\"; return cont(maybeoperatorComma); }\n  }\n  function targetNoComma(_, value) {\n    if (value == \"target\") { cx.marked = \"keyword\"; return cont(maybeoperatorNoComma); }\n  }\n  function maybelabel(type) {\n    if (type == \":\") return cont(poplex, statement);\n    return pass(maybeoperatorComma, expect(\";\"), poplex);\n  }\n  function property(type) {\n    if (type == \"variable\") {cx.marked = \"property\"; return cont();}\n  }\n  function objprop(type, value) {\n    if (type == \"async\") {\n      cx.marked = \"property\";\n      return cont(objprop);\n    } else if (type == \"variable\" || cx.style == \"keyword\") {\n      cx.marked = \"property\";\n      if (value == \"get\" || value == \"set\") return cont(getterSetter);\n      var m // Work around fat-arrow-detection complication for detecting typescript typed arrow params\n      if (isTS && cx.state.fatArrowAt == cx.stream.start && (m = cx.stream.match(/^\\s*:\\s*/, false)))\n        cx.state.fatArrowAt = cx.stream.pos + m[0].length\n      return cont(afterprop);\n    } else if (type == \"number\" || type == \"string\") {\n      cx.marked = jsonldMode ? \"property\" : (cx.style + \" property\");\n      return cont(afterprop);\n    } else if (type == \"jsonld-keyword\") {\n      return cont(afterprop);\n    } else if (isTS && isModifier(value)) {\n      cx.marked = \"keyword\"\n      return cont(objprop)\n    } else if (type == \"[\") {\n      return cont(expression, maybetype, expect(\"]\"), afterprop);\n    } else if (type == \"spread\") {\n      return cont(expressionNoComma, afterprop);\n    } else if (value == \"*\") {\n      cx.marked = \"keyword\";\n      return cont(objprop);\n    } else if (type == \":\") {\n      return pass(afterprop)\n    }\n  }\n  function getterSetter(type) {\n    if (type != \"variable\") return pass(afterprop);\n    cx.marked = \"property\";\n    return cont(functiondef);\n  }\n  function afterprop(type) {\n    if (type == \":\") return cont(expressionNoComma);\n    if (type == \"(\") return pass(functiondef);\n  }\n  function commasep(what, end, sep) {\n    function proceed(type, value) {\n      if (sep ? sep.indexOf(type) > -1 : type == \",\") {\n        var lex = cx.state.lexical;\n        if (lex.info == \"call\") lex.pos = (lex.pos || 0) + 1;\n        return cont(function(type, value) {\n          if (type == end || value == end) return pass()\n          return pass(what)\n        }, proceed);\n      }\n      if (type == end || value == end) return cont();\n      return cont(expect(end));\n    }\n    return function(type, value) {\n      if (type == end || value == end) return cont();\n      return pass(what, proceed);\n    };\n  }\n  function contCommasep(what, end, info) {\n    for (var i = 3; i < arguments.length; i++)\n      cx.cc.push(arguments[i]);\n    return cont(pushlex(end, info), commasep(what, end), poplex);\n  }\n  function block(type) {\n    if (type == \"}\") return cont();\n    return pass(statement, block);\n  }\n  function maybetype(type, value) {\n    if (isTS) {\n      if (type == \":\") return cont(typeexpr);\n      if (value == \"?\") return cont(maybetype);\n    }\n  }\n  function mayberettype(type) {\n    if (isTS && type == \":\") {\n      if (cx.stream.match(/^\\s*\\w+\\s+is\\b/, false)) return cont(expression, isKW, typeexpr)\n      else return cont(typeexpr)\n    }\n  }\n  function isKW(_, value) {\n    if (value == \"is\") {\n      cx.marked = \"keyword\"\n      return cont()\n    }\n  }\n  function typeexpr(type, value) {\n    if (value == \"keyof\" || value == \"typeof\") {\n      cx.marked = \"keyword\"\n      return cont(value == \"keyof\" ? typeexpr : expressionNoComma)\n    }\n    if (type == \"variable\" || value == \"void\") {\n      cx.marked = \"type\"\n      return cont(afterType)\n    }\n    if (type == \"string\" || type == \"number\" || type == \"atom\") return cont(afterType);\n    if (type == \"[\") return cont(pushlex(\"]\"), commasep(typeexpr, \"]\", \",\"), poplex, afterType)\n    if (type == \"{\") return cont(pushlex(\"}\"), commasep(typeprop, \"}\", \",;\"), poplex, afterType)\n    if (type == \"(\") return cont(commasep(typearg, \")\"), maybeReturnType)\n    if (type == \"<\") return cont(commasep(typeexpr, \">\"), typeexpr)\n  }\n  function maybeReturnType(type) {\n    if (type == \"=>\") return cont(typeexpr)\n  }\n  function typeprop(type, value) {\n    if (type == \"variable\" || cx.style == \"keyword\") {\n      cx.marked = \"property\"\n      return cont(typeprop)\n    } else if (value == \"?\") {\n      return cont(typeprop)\n    } else if (type == \":\") {\n      return cont(typeexpr)\n    } else if (type == \"[\") {\n      return cont(expression, maybetype, expect(\"]\"), typeprop)\n    }\n  }\n  function typearg(type, value) {\n    if (type == \"variable\" && cx.stream.match(/^\\s*[?:]/, false) || value == \"?\") return cont(typearg)\n    if (type == \":\") return cont(typeexpr)\n    return pass(typeexpr)\n  }\n  function afterType(type, value) {\n    if (value == \"<\") return cont(pushlex(\">\"), commasep(typeexpr, \">\"), poplex, afterType)\n    if (value == \"|\" || type == \".\" || value == \"&\") return cont(typeexpr)\n    if (type == \"[\") return cont(expect(\"]\"), afterType)\n    if (value == \"extends\" || value == \"implements\") { cx.marked = \"keyword\"; return cont(typeexpr) }\n  }\n  function maybeTypeArgs(_, value) {\n    if (value == \"<\") return cont(pushlex(\">\"), commasep(typeexpr, \">\"), poplex, afterType)\n  }\n  function typeparam() {\n    return pass(typeexpr, maybeTypeDefault)\n  }\n  function maybeTypeDefault(_, value) {\n    if (value == \"=\") return cont(typeexpr)\n  }\n  function vardef(_, value) {\n    if (value == \"enum\") {cx.marked = \"keyword\"; return cont(enumdef)}\n    return pass(pattern, maybetype, maybeAssign, vardefCont);\n  }\n  function pattern(type, value) {\n    if (isTS && isModifier(value)) { cx.marked = \"keyword\"; return cont(pattern) }\n    if (type == \"variable\") { register(value); return cont(); }\n    if (type == \"spread\") return cont(pattern);\n    if (type == \"[\") return contCommasep(eltpattern, \"]\");\n    if (type == \"{\") return contCommasep(proppattern, \"}\");\n  }\n  function proppattern(type, value) {\n    if (type == \"variable\" && !cx.stream.match(/^\\s*:/, false)) {\n      register(value);\n      return cont(maybeAssign);\n    }\n    if (type == \"variable\") cx.marked = \"property\";\n    if (type == \"spread\") return cont(pattern);\n    if (type == \"}\") return pass();\n    return cont(expect(\":\"), pattern, maybeAssign);\n  }\n  function eltpattern() {\n    return pass(pattern, maybeAssign)\n  }\n  function maybeAssign(_type, value) {\n    if (value == \"=\") return cont(expressionNoComma);\n  }\n  function vardefCont(type) {\n    if (type == \",\") return cont(vardef);\n  }\n  function maybeelse(type, value) {\n    if (type == \"keyword b\" && value == \"else\") return cont(pushlex(\"form\", \"else\"), statement, poplex);\n  }\n  function forspec(type, value) {\n    if (value == \"await\") return cont(forspec);\n    if (type == \"(\") return cont(pushlex(\")\"), forspec1, expect(\")\"), poplex);\n  }\n  function forspec1(type) {\n    if (type == \"var\") return cont(vardef, expect(\";\"), forspec2);\n    if (type == \";\") return cont(forspec2);\n    if (type == \"variable\") return cont(formaybeinof);\n    return pass(expression, expect(\";\"), forspec2);\n  }\n  function formaybeinof(_type, value) {\n    if (value == \"in\" || value == \"of\") { cx.marked = \"keyword\"; return cont(expression); }\n    return cont(maybeoperatorComma, forspec2);\n  }\n  function forspec2(type, value) {\n    if (type == \";\") return cont(forspec3);\n    if (value == \"in\" || value == \"of\") { cx.marked = \"keyword\"; return cont(expression); }\n    return pass(expression, expect(\";\"), forspec3);\n  }\n  function forspec3(type) {\n    if (type != \")\") cont(expression);\n  }\n  function functiondef(type, value) {\n    if (value == \"*\") {cx.marked = \"keyword\"; return cont(functiondef);}\n    if (type == \"variable\") {register(value); return cont(functiondef);}\n    if (type == \"(\") return cont(pushcontext, pushlex(\")\"), commasep(funarg, \")\"), poplex, mayberettype, statement, popcontext);\n    if (isTS && value == \"<\") return cont(pushlex(\">\"), commasep(typeparam, \">\"), poplex, functiondef)\n  }\n  function funarg(type, value) {\n    if (value == \"@\") cont(expression, funarg)\n    if (type == \"spread\") return cont(funarg);\n    if (isTS && isModifier(value)) { cx.marked = \"keyword\"; return cont(funarg); }\n    return pass(pattern, maybetype, maybeAssign);\n  }\n  function classExpression(type, value) {\n    // Class expressions may have an optional name.\n    if (type == \"variable\") return className(type, value);\n    return classNameAfter(type, value);\n  }\n  function className(type, value) {\n    if (type == \"variable\") {register(value); return cont(classNameAfter);}\n  }\n  function classNameAfter(type, value) {\n    if (value == \"<\") return cont(pushlex(\">\"), commasep(typeparam, \">\"), poplex, classNameAfter)\n    if (value == \"extends\" || value == \"implements\" || (isTS && type == \",\")) {\n      if (value == \"implements\") cx.marked = \"keyword\";\n      return cont(isTS ? typeexpr : expression, classNameAfter);\n    }\n    if (type == \"{\") return cont(pushlex(\"}\"), classBody, poplex);\n  }\n  function classBody(type, value) {\n    if (type == \"async\" ||\n        (type == \"variable\" &&\n         (value == \"static\" || value == \"get\" || value == \"set\" || (isTS && isModifier(value))) &&\n         cx.stream.match(/^\\s+[\\w$\\xa1-\\uffff]/, false))) {\n      cx.marked = \"keyword\";\n      return cont(classBody);\n    }\n    if (type == \"variable\" || cx.style == \"keyword\") {\n      cx.marked = \"property\";\n      return cont(isTS ? classfield : functiondef, classBody);\n    }\n    if (type == \"[\")\n      return cont(expression, maybetype, expect(\"]\"), isTS ? classfield : functiondef, classBody)\n    if (value == \"*\") {\n      cx.marked = \"keyword\";\n      return cont(classBody);\n    }\n    if (type == \";\") return cont(classBody);\n    if (type == \"}\") return cont();\n    if (value == \"@\") return cont(expression, classBody)\n  }\n  function classfield(type, value) {\n    if (value == \"?\") return cont(classfield)\n    if (type == \":\") return cont(typeexpr, maybeAssign)\n    if (value == \"=\") return cont(expressionNoComma)\n    return pass(functiondef)\n  }\n  function afterExport(type, value) {\n    if (value == \"*\") { cx.marked = \"keyword\"; return cont(maybeFrom, expect(\";\")); }\n    if (value == \"default\") { cx.marked = \"keyword\"; return cont(expression, expect(\";\")); }\n    if (type == \"{\") return cont(commasep(exportField, \"}\"), maybeFrom, expect(\";\"));\n    return pass(statement);\n  }\n  function exportField(type, value) {\n    if (value == \"as\") { cx.marked = \"keyword\"; return cont(expect(\"variable\")); }\n    if (type == \"variable\") return pass(expressionNoComma, exportField);\n  }\n  function afterImport(type) {\n    if (type == \"string\") return cont();\n    if (type == \"(\") return pass(expression);\n    return pass(importSpec, maybeMoreImports, maybeFrom);\n  }\n  function importSpec(type, value) {\n    if (type == \"{\") return contCommasep(importSpec, \"}\");\n    if (type == \"variable\") register(value);\n    if (value == \"*\") cx.marked = \"keyword\";\n    return cont(maybeAs);\n  }\n  function maybeMoreImports(type) {\n    if (type == \",\") return cont(importSpec, maybeMoreImports)\n  }\n  function maybeAs(_type, value) {\n    if (value == \"as\") { cx.marked = \"keyword\"; return cont(importSpec); }\n  }\n  function maybeFrom(_type, value) {\n    if (value == \"from\") { cx.marked = \"keyword\"; return cont(expression); }\n  }\n  function arrayLiteral(type) {\n    if (type == \"]\") return cont();\n    return pass(commasep(expressionNoComma, \"]\"));\n  }\n  function enumdef() {\n    return pass(pushlex(\"form\"), pattern, expect(\"{\"), pushlex(\"}\"), commasep(enummember, \"}\"), poplex, poplex)\n  }\n  function enummember() {\n    return pass(pattern, maybeAssign);\n  }\n\n  function isContinuedStatement(state, textAfter) {\n    return state.lastType == \"operator\" || state.lastType == \",\" ||\n      isOperatorChar.test(textAfter.charAt(0)) ||\n      /[,.]/.test(textAfter.charAt(0));\n  }\n\n  function expressionAllowed(stream, state, backUp) {\n    return state.tokenize == tokenBase &&\n      /^(?:operator|sof|keyword [bcd]|case|new|export|default|spread|[\\[{}\\(,;:]|=>)$/.test(state.lastType) ||\n      (state.lastType == \"quasi\" && /\\{\\s*$/.test(stream.string.slice(0, stream.pos - (backUp || 0))))\n  }\n\n  // Interface\n\n  return {\n    startState: function(basecolumn) {\n      var state = {\n        tokenize: tokenBase,\n        lastType: \"sof\",\n        cc: [],\n        lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, \"block\", false),\n        localVars: parserConfig.localVars,\n        context: parserConfig.localVars && new Context(null, null, false),\n        indented: basecolumn || 0\n      };\n      if (parserConfig.globalVars && typeof parserConfig.globalVars == \"object\")\n        state.globalVars = parserConfig.globalVars;\n      return state;\n    },\n\n    token: function(stream, state) {\n      if (stream.sol()) {\n        if (!state.lexical.hasOwnProperty(\"align\"))\n          state.lexical.align = false;\n        state.indented = stream.indentation();\n        findFatArrow(stream, state);\n      }\n      if (state.tokenize != tokenComment && stream.eatSpace()) return null;\n      var style = state.tokenize(stream, state);\n      if (type == \"comment\") return style;\n      state.lastType = type == \"operator\" && (content == \"++\" || content == \"--\") ? \"incdec\" : type;\n      return parseJS(state, style, type, content, stream);\n    },\n\n    indent: function(state, textAfter) {\n      if (state.tokenize == tokenComment) return CodeMirror.Pass;\n      if (state.tokenize != tokenBase) return 0;\n      var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical, top\n      // Kludge to prevent 'maybelse' from blocking lexical scope pops\n      if (!/^\\s*else\\b/.test(textAfter)) for (var i = state.cc.length - 1; i >= 0; --i) {\n        var c = state.cc[i];\n        if (c == poplex) lexical = lexical.prev;\n        else if (c != maybeelse) break;\n      }\n      while ((lexical.type == \"stat\" || lexical.type == \"form\") &&\n             (firstChar == \"}\" || ((top = state.cc[state.cc.length - 1]) &&\n                                   (top == maybeoperatorComma || top == maybeoperatorNoComma) &&\n                                   !/^[,\\.=+\\-*:?[\\(]/.test(textAfter))))\n        lexical = lexical.prev;\n      if (statementIndent && lexical.type == \")\" && lexical.prev.type == \"stat\")\n        lexical = lexical.prev;\n      var type = lexical.type, closing = firstChar == type;\n\n      if (type == \"vardef\") return lexical.indented + (state.lastType == \"operator\" || state.lastType == \",\" ? lexical.info.length + 1 : 0);\n      else if (type == \"form\" && firstChar == \"{\") return lexical.indented;\n      else if (type == \"form\") return lexical.indented + indentUnit;\n      else if (type == \"stat\")\n        return lexical.indented + (isContinuedStatement(state, textAfter) ? statementIndent || indentUnit : 0);\n      else if (lexical.info == \"switch\" && !closing && parserConfig.doubleIndentSwitch != false)\n        return lexical.indented + (/^(?:case|default)\\b/.test(textAfter) ? indentUnit : 2 * indentUnit);\n      else if (lexical.align) return lexical.column + (closing ? 0 : 1);\n      else return lexical.indented + (closing ? 0 : indentUnit);\n    },\n\n    electricInput: /^\\s*(?:case .*?:|default:|\\{|\\})$/,\n    blockCommentStart: jsonMode ? null : \"/*\",\n    blockCommentEnd: jsonMode ? null : \"*/\",\n    blockCommentContinue: jsonMode ? null : \" * \",\n    lineComment: jsonMode ? null : \"//\",\n    fold: \"brace\",\n    closeBrackets: \"()[]{}''\\\"\\\"``\",\n\n    helperType: jsonMode ? \"json\" : \"javascript\",\n    jsonldMode: jsonldMode,\n    jsonMode: jsonMode,\n\n    expressionAllowed: expressionAllowed,\n\n    skipExpression: function(state) {\n      var top = state.cc[state.cc.length - 1]\n      if (top == expression || top == expressionNoComma) state.cc.pop()\n    }\n  };\n});\n\nCodeMirror.registerHelper(\"wordChars\", \"javascript\", /[\\w$]/);\n\nCodeMirror.defineMIME(\"text/javascript\", \"javascript\");\nCodeMirror.defineMIME(\"text/ecmascript\", \"javascript\");\nCodeMirror.defineMIME(\"application/javascript\", \"javascript\");\nCodeMirror.defineMIME(\"application/x-javascript\", \"javascript\");\nCodeMirror.defineMIME(\"application/ecmascript\", \"javascript\");\nCodeMirror.defineMIME(\"application/json\", {name: \"javascript\", json: true});\nCodeMirror.defineMIME(\"application/x-json\", {name: \"javascript\", json: true});\nCodeMirror.defineMIME(\"application/ld+json\", {name: \"javascript\", jsonld: true});\nCodeMirror.defineMIME(\"text/typescript\", { name: \"javascript\", typescript: true });\nCodeMirror.defineMIME(\"application/typescript\", { name: \"javascript\", typescript: true });\n\n});\n"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/plugins/codemirror/mode/php/php.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: https://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"), require(\"../htmlmixed/htmlmixed\"), require(\"../clike/clike\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\", \"../htmlmixed/htmlmixed\", \"../clike/clike\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n\n  function keywords(str) {\n    var obj = {}, words = str.split(\" \");\n    for (var i = 0; i < words.length; ++i) obj[words[i]] = true;\n    return obj;\n  }\n\n  // Helper for phpString\n  function matchSequence(list, end, escapes) {\n    if (list.length == 0) return phpString(end);\n    return function (stream, state) {\n      var patterns = list[0];\n      for (var i = 0; i < patterns.length; i++) if (stream.match(patterns[i][0])) {\n        state.tokenize = matchSequence(list.slice(1), end);\n        return patterns[i][1];\n      }\n      state.tokenize = phpString(end, escapes);\n      return \"string\";\n    };\n  }\n  function phpString(closing, escapes) {\n    return function(stream, state) { return phpString_(stream, state, closing, escapes); };\n  }\n  function phpString_(stream, state, closing, escapes) {\n    // \"Complex\" syntax\n    if (escapes !== false && stream.match(\"${\", false) || stream.match(\"{$\", false)) {\n      state.tokenize = null;\n      return \"string\";\n    }\n\n    // Simple syntax\n    if (escapes !== false && stream.match(/^\\$[a-zA-Z_][a-zA-Z0-9_]*/)) {\n      // After the variable name there may appear array or object operator.\n      if (stream.match(\"[\", false)) {\n        // Match array operator\n        state.tokenize = matchSequence([\n          [[\"[\", null]],\n          [[/\\d[\\w\\.]*/, \"number\"],\n           [/\\$[a-zA-Z_][a-zA-Z0-9_]*/, \"variable-2\"],\n           [/[\\w\\$]+/, \"variable\"]],\n          [[\"]\", null]]\n        ], closing, escapes);\n      }\n      if (stream.match(/\\-\\>\\w/, false)) {\n        // Match object operator\n        state.tokenize = matchSequence([\n          [[\"->\", null]],\n          [[/[\\w]+/, \"variable\"]]\n        ], closing, escapes);\n      }\n      return \"variable-2\";\n    }\n\n    var escaped = false;\n    // Normal string\n    while (!stream.eol() &&\n           (escaped || escapes === false ||\n            (!stream.match(\"{$\", false) &&\n             !stream.match(/^(\\$[a-zA-Z_][a-zA-Z0-9_]*|\\$\\{)/, false)))) {\n      if (!escaped && stream.match(closing)) {\n        state.tokenize = null;\n        state.tokStack.pop(); state.tokStack.pop();\n        break;\n      }\n      escaped = stream.next() == \"\\\\\" && !escaped;\n    }\n    return \"string\";\n  }\n\n  var phpKeywords = \"abstract and array as break case catch class clone const continue declare default \" +\n    \"do else elseif enddeclare endfor endforeach endif endswitch endwhile extends final \" +\n    \"for foreach function global goto if implements interface instanceof namespace \" +\n    \"new or private protected public static switch throw trait try use var while xor \" +\n    \"die echo empty exit eval include include_once isset list require require_once return \" +\n    \"print unset __halt_compiler self static parent yield insteadof finally\";\n  var phpAtoms = \"true false null TRUE FALSE NULL __CLASS__ __DIR__ __FILE__ __LINE__ __METHOD__ __FUNCTION__ __NAMESPACE__ __TRAIT__\";\n  var phpBuiltin = \"func_num_args func_get_arg func_get_args strlen strcmp strncmp strcasecmp strncasecmp each error_reporting define defined trigger_error user_error set_error_handler restore_error_handler get_declared_classes get_loaded_extensions extension_loaded get_extension_funcs debug_backtrace constant bin2hex hex2bin sleep usleep time mktime gmmktime strftime gmstrftime strtotime date gmdate getdate localtime checkdate flush wordwrap htmlspecialchars htmlentities html_entity_decode md5 md5_file crc32 getimagesize image_type_to_mime_type phpinfo phpversion phpcredits strnatcmp strnatcasecmp substr_count strspn strcspn strtok strtoupper strtolower strpos strrpos strrev hebrev hebrevc nl2br basename dirname pathinfo stripslashes stripcslashes strstr stristr strrchr str_shuffle str_word_count strcoll substr substr_replace quotemeta ucfirst ucwords strtr addslashes addcslashes rtrim str_replace str_repeat count_chars chunk_split trim ltrim strip_tags similar_text explode implode setlocale localeconv parse_str str_pad chop strchr sprintf printf vprintf vsprintf sscanf fscanf parse_url urlencode urldecode rawurlencode rawurldecode readlink linkinfo link unlink exec system escapeshellcmd escapeshellarg passthru shell_exec proc_open proc_close rand srand getrandmax mt_rand mt_srand mt_getrandmax base64_decode base64_encode abs ceil floor round is_finite is_nan is_infinite bindec hexdec octdec decbin decoct dechex base_convert number_format fmod ip2long long2ip getenv putenv getopt microtime gettimeofday getrusage uniqid quoted_printable_decode set_time_limit get_cfg_var magic_quotes_runtime set_magic_quotes_runtime get_magic_quotes_gpc get_magic_quotes_runtime import_request_variables error_log serialize unserialize memory_get_usage var_dump var_export debug_zval_dump print_r highlight_file show_source highlight_string ini_get ini_get_all ini_set ini_alter ini_restore get_include_path set_include_path restore_include_path setcookie header headers_sent connection_aborted connection_status ignore_user_abort parse_ini_file is_uploaded_file move_uploaded_file intval floatval doubleval strval gettype settype is_null is_resource is_bool is_long is_float is_int is_integer is_double is_real is_numeric is_string is_array is_object is_scalar ereg ereg_replace eregi eregi_replace split spliti join sql_regcase dl pclose popen readfile rewind rmdir umask fclose feof fgetc fgets fgetss fread fopen fpassthru ftruncate fstat fseek ftell fflush fwrite fputs mkdir rename copy tempnam tmpfile file file_get_contents file_put_contents stream_select stream_context_create stream_context_set_params stream_context_set_option stream_context_get_options stream_filter_prepend stream_filter_append fgetcsv flock get_meta_tags stream_set_write_buffer set_file_buffer set_socket_blocking stream_set_blocking socket_set_blocking stream_get_meta_data stream_register_wrapper stream_wrapper_register stream_set_timeout socket_set_timeout socket_get_status realpath fnmatch fsockopen pfsockopen pack unpack get_browser crypt opendir closedir chdir getcwd rewinddir readdir dir glob fileatime filectime filegroup fileinode filemtime fileowner fileperms filesize filetype file_exists is_writable is_writeable is_readable is_executable is_file is_dir is_link stat lstat chown touch clearstatcache mail ob_start ob_flush ob_clean ob_end_flush ob_end_clean ob_get_flush ob_get_clean ob_get_length ob_get_level ob_get_status ob_get_contents ob_implicit_flush ob_list_handlers ksort krsort natsort natcasesort asort arsort sort rsort usort uasort uksort shuffle array_walk count end prev next reset current key min max in_array array_search extract compact array_fill range array_multisort array_push array_pop array_shift array_unshift array_splice array_slice array_merge array_merge_recursive array_keys array_values array_count_values array_reverse array_reduce array_pad array_flip array_change_key_case array_rand array_unique array_intersect array_intersect_assoc array_diff array_diff_assoc array_sum array_filter array_map array_chunk array_key_exists array_intersect_key array_combine array_column pos sizeof key_exists assert assert_options version_compare ftok str_rot13 aggregate session_name session_module_name session_save_path session_id session_regenerate_id session_decode session_register session_unregister session_is_registered session_encode session_start session_destroy session_unset session_set_save_handler session_cache_limiter session_cache_expire session_set_cookie_params session_get_cookie_params session_write_close preg_match preg_match_all preg_replace preg_replace_callback preg_split preg_quote preg_grep overload ctype_alnum ctype_alpha ctype_cntrl ctype_digit ctype_lower ctype_graph ctype_print ctype_punct ctype_space ctype_upper ctype_xdigit virtual apache_request_headers apache_note apache_lookup_uri apache_child_terminate apache_setenv apache_response_headers apache_get_version getallheaders mysql_connect mysql_pconnect mysql_close mysql_select_db mysql_create_db mysql_drop_db mysql_query mysql_unbuffered_query mysql_db_query mysql_list_dbs mysql_list_tables mysql_list_fields mysql_list_processes mysql_error mysql_errno mysql_affected_rows mysql_insert_id mysql_result mysql_num_rows mysql_num_fields mysql_fetch_row mysql_fetch_array mysql_fetch_assoc mysql_fetch_object mysql_data_seek mysql_fetch_lengths mysql_fetch_field mysql_field_seek mysql_free_result mysql_field_name mysql_field_table mysql_field_len mysql_field_type mysql_field_flags mysql_escape_string mysql_real_escape_string mysql_stat mysql_thread_id mysql_client_encoding mysql_get_client_info mysql_get_host_info mysql_get_proto_info mysql_get_server_info mysql_info mysql mysql_fieldname mysql_fieldtable mysql_fieldlen mysql_fieldtype mysql_fieldflags mysql_selectdb mysql_createdb mysql_dropdb mysql_freeresult mysql_numfields mysql_numrows mysql_listdbs mysql_listtables mysql_listfields mysql_db_name mysql_dbname mysql_tablename mysql_table_name pg_connect pg_pconnect pg_close pg_connection_status pg_connection_busy pg_connection_reset pg_host pg_dbname pg_port pg_tty pg_options pg_ping pg_query pg_send_query pg_cancel_query pg_fetch_result pg_fetch_row pg_fetch_assoc pg_fetch_array pg_fetch_object pg_fetch_all pg_affected_rows pg_get_result pg_result_seek pg_result_status pg_free_result pg_last_oid pg_num_rows pg_num_fields pg_field_name pg_field_num pg_field_size pg_field_type pg_field_prtlen pg_field_is_null pg_get_notify pg_get_pid pg_result_error pg_last_error pg_last_notice pg_put_line pg_end_copy pg_copy_to pg_copy_from pg_trace pg_untrace pg_lo_create pg_lo_unlink pg_lo_open pg_lo_close pg_lo_read pg_lo_write pg_lo_read_all pg_lo_import pg_lo_export pg_lo_seek pg_lo_tell pg_escape_string pg_escape_bytea pg_unescape_bytea pg_client_encoding pg_set_client_encoding pg_meta_data pg_convert pg_insert pg_update pg_delete pg_select pg_exec pg_getlastoid pg_cmdtuples pg_errormessage pg_numrows pg_numfields pg_fieldname pg_fieldsize pg_fieldtype pg_fieldnum pg_fieldprtlen pg_fieldisnull pg_freeresult pg_result pg_loreadall pg_locreate pg_lounlink pg_loopen pg_loclose pg_loread pg_lowrite pg_loimport pg_loexport http_response_code get_declared_traits getimagesizefromstring socket_import_stream stream_set_chunk_size trait_exists header_register_callback class_uses session_status session_register_shutdown echo print global static exit array empty eval isset unset die include require include_once require_once json_decode json_encode json_last_error json_last_error_msg curl_close curl_copy_handle curl_errno curl_error curl_escape curl_exec curl_file_create curl_getinfo curl_init curl_multi_add_handle curl_multi_close curl_multi_exec curl_multi_getcontent curl_multi_info_read curl_multi_init curl_multi_remove_handle curl_multi_select curl_multi_setopt curl_multi_strerror curl_pause curl_reset curl_setopt_array curl_setopt curl_share_close curl_share_init curl_share_setopt curl_strerror curl_unescape curl_version mysqli_affected_rows mysqli_autocommit mysqli_change_user mysqli_character_set_name mysqli_close mysqli_commit mysqli_connect_errno mysqli_connect_error mysqli_connect mysqli_data_seek mysqli_debug mysqli_dump_debug_info mysqli_errno mysqli_error_list mysqli_error mysqli_fetch_all mysqli_fetch_array mysqli_fetch_assoc mysqli_fetch_field_direct mysqli_fetch_field mysqli_fetch_fields mysqli_fetch_lengths mysqli_fetch_object mysqli_fetch_row mysqli_field_count mysqli_field_seek mysqli_field_tell mysqli_free_result mysqli_get_charset mysqli_get_client_info mysqli_get_client_stats mysqli_get_client_version mysqli_get_connection_stats mysqli_get_host_info mysqli_get_proto_info mysqli_get_server_info mysqli_get_server_version mysqli_info mysqli_init mysqli_insert_id mysqli_kill mysqli_more_results mysqli_multi_query mysqli_next_result mysqli_num_fields mysqli_num_rows mysqli_options mysqli_ping mysqli_prepare mysqli_query mysqli_real_connect mysqli_real_escape_string mysqli_real_query mysqli_reap_async_query mysqli_refresh mysqli_rollback mysqli_select_db mysqli_set_charset mysqli_set_local_infile_default mysqli_set_local_infile_handler mysqli_sqlstate mysqli_ssl_set mysqli_stat mysqli_stmt_init mysqli_store_result mysqli_thread_id mysqli_thread_safe mysqli_use_result mysqli_warning_count\";\n  CodeMirror.registerHelper(\"hintWords\", \"php\", [phpKeywords, phpAtoms, phpBuiltin].join(\" \").split(\" \"));\n  CodeMirror.registerHelper(\"wordChars\", \"php\", /[\\w$]/);\n\n  var phpConfig = {\n    name: \"clike\",\n    helperType: \"php\",\n    keywords: keywords(phpKeywords),\n    blockKeywords: keywords(\"catch do else elseif for foreach if switch try while finally\"),\n    defKeywords: keywords(\"class function interface namespace trait\"),\n    atoms: keywords(phpAtoms),\n    builtin: keywords(phpBuiltin),\n    multiLineStrings: true,\n    hooks: {\n      \"$\": function(stream) {\n        stream.eatWhile(/[\\w\\$_]/);\n        return \"variable-2\";\n      },\n      \"<\": function(stream, state) {\n        var before;\n        if (before = stream.match(/<<\\s*/)) {\n          var quoted = stream.eat(/['\"]/);\n          stream.eatWhile(/[\\w\\.]/);\n          var delim = stream.current().slice(before[0].length + (quoted ? 2 : 1));\n          if (quoted) stream.eat(quoted);\n          if (delim) {\n            (state.tokStack || (state.tokStack = [])).push(delim, 0);\n            state.tokenize = phpString(delim, quoted != \"'\");\n            return \"string\";\n          }\n        }\n        return false;\n      },\n      \"#\": function(stream) {\n        while (!stream.eol() && !stream.match(\"?>\", false)) stream.next();\n        return \"comment\";\n      },\n      \"/\": function(stream) {\n        if (stream.eat(\"/\")) {\n          while (!stream.eol() && !stream.match(\"?>\", false)) stream.next();\n          return \"comment\";\n        }\n        return false;\n      },\n      '\"': function(_stream, state) {\n        (state.tokStack || (state.tokStack = [])).push('\"', 0);\n        state.tokenize = phpString('\"');\n        return \"string\";\n      },\n      \"{\": function(_stream, state) {\n        if (state.tokStack && state.tokStack.length)\n          state.tokStack[state.tokStack.length - 1]++;\n        return false;\n      },\n      \"}\": function(_stream, state) {\n        if (state.tokStack && state.tokStack.length > 0 &&\n            !--state.tokStack[state.tokStack.length - 1]) {\n          state.tokenize = phpString(state.tokStack[state.tokStack.length - 2]);\n        }\n        return false;\n      }\n    }\n  };\n\n  CodeMirror.defineMode(\"php\", function(config, parserConfig) {\n    var htmlMode = CodeMirror.getMode(config, (parserConfig && parserConfig.htmlMode) || \"text/html\");\n    var phpMode = CodeMirror.getMode(config, phpConfig);\n\n    function dispatch(stream, state) {\n      var isPHP = state.curMode == phpMode;\n      if (stream.sol() && state.pending && state.pending != '\"' && state.pending != \"'\") state.pending = null;\n      if (!isPHP) {\n        if (stream.match(/^<\\?\\w*/)) {\n          state.curMode = phpMode;\n          if (!state.php) state.php = CodeMirror.startState(phpMode, htmlMode.indent(state.html, \"\"))\n          state.curState = state.php;\n          return \"meta\";\n        }\n        if (state.pending == '\"' || state.pending == \"'\") {\n          while (!stream.eol() && stream.next() != state.pending) {}\n          var style = \"string\";\n        } else if (state.pending && stream.pos < state.pending.end) {\n          stream.pos = state.pending.end;\n          var style = state.pending.style;\n        } else {\n          var style = htmlMode.token(stream, state.curState);\n        }\n        if (state.pending) state.pending = null;\n        var cur = stream.current(), openPHP = cur.search(/<\\?/), m;\n        if (openPHP != -1) {\n          if (style == \"string\" && (m = cur.match(/[\\'\\\"]$/)) && !/\\?>/.test(cur)) state.pending = m[0];\n          else state.pending = {end: stream.pos, style: style};\n          stream.backUp(cur.length - openPHP);\n        }\n        return style;\n      } else if (isPHP && state.php.tokenize == null && stream.match(\"?>\")) {\n        state.curMode = htmlMode;\n        state.curState = state.html;\n        if (!state.php.context.prev) state.php = null;\n        return \"meta\";\n      } else {\n        return phpMode.token(stream, state.curState);\n      }\n    }\n\n    return {\n      startState: function() {\n        var html = CodeMirror.startState(htmlMode)\n        var php = parserConfig.startOpen ? CodeMirror.startState(phpMode) : null\n        return {html: html,\n                php: php,\n                curMode: parserConfig.startOpen ? phpMode : htmlMode,\n                curState: parserConfig.startOpen ? php : html,\n                pending: null};\n      },\n\n      copyState: function(state) {\n        var html = state.html, htmlNew = CodeMirror.copyState(htmlMode, html),\n            php = state.php, phpNew = php && CodeMirror.copyState(phpMode, php), cur;\n        if (state.curMode == htmlMode) cur = htmlNew;\n        else cur = phpNew;\n        return {html: htmlNew, php: phpNew, curMode: state.curMode, curState: cur,\n                pending: state.pending};\n      },\n\n      token: dispatch,\n\n      indent: function(state, textAfter) {\n        if ((state.curMode != phpMode && /^\\s*<\\//.test(textAfter)) ||\n            (state.curMode == phpMode && /^\\?>/.test(textAfter)))\n          return htmlMode.indent(state.html, textAfter);\n        return state.curMode.indent(state.curState, textAfter);\n      },\n\n      blockCommentStart: \"/*\",\n      blockCommentEnd: \"*/\",\n      lineComment: \"//\",\n\n      innerMode: function(state) { return {state: state.curState, mode: state.curMode}; }\n    };\n  }, \"htmlmixed\", \"clike\");\n\n  CodeMirror.defineMIME(\"application/x-httpd-php\", \"php\");\n  CodeMirror.defineMIME(\"application/x-httpd-php-open\", {name: \"php\", startOpen: true});\n  CodeMirror.defineMIME(\"text/x-php\", phpConfig);\n});\n"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/plugins/codemirror/mode/powershell/powershell.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: https://codemirror.net/LICENSE\n\n(function(mod) {\n  'use strict';\n  if (typeof exports == 'object' && typeof module == 'object') // CommonJS\n    mod(require('../../lib/codemirror'));\n  else if (typeof define == 'function' && define.amd) // AMD\n    define(['../../lib/codemirror'], mod);\n  else // Plain browser env\n    mod(window.CodeMirror);\n})(function(CodeMirror) {\n'use strict';\n\nCodeMirror.defineMode('powershell', function() {\n  function buildRegexp(patterns, options) {\n    options = options || {};\n    var prefix = options.prefix !== undefined ? options.prefix : '^';\n    var suffix = options.suffix !== undefined ? options.suffix : '\\\\b';\n\n    for (var i = 0; i < patterns.length; i++) {\n      if (patterns[i] instanceof RegExp) {\n        patterns[i] = patterns[i].source;\n      }\n      else {\n        patterns[i] = patterns[i].replace(/[-\\/\\\\^$*+?.()|[\\]{}]/g, '\\\\$&');\n      }\n    }\n\n    return new RegExp(prefix + '(' + patterns.join('|') + ')' + suffix, 'i');\n  }\n\n  var notCharacterOrDash = '(?=[^A-Za-z\\\\d\\\\-_]|$)';\n  var varNames = /[\\w\\-:]/\n  var keywords = buildRegexp([\n    /begin|break|catch|continue|data|default|do|dynamicparam/,\n    /else|elseif|end|exit|filter|finally|for|foreach|from|function|if|in/,\n    /param|process|return|switch|throw|trap|try|until|where|while/\n  ], { suffix: notCharacterOrDash });\n\n  var punctuation = /[\\[\\]{},;`\\.]|@[({]/;\n  var wordOperators = buildRegexp([\n    'f',\n    /b?not/,\n    /[ic]?split/, 'join',\n    /is(not)?/, 'as',\n    /[ic]?(eq|ne|[gl][te])/,\n    /[ic]?(not)?(like|match|contains)/,\n    /[ic]?replace/,\n    /b?(and|or|xor)/\n  ], { prefix: '-' });\n  var symbolOperators = /[+\\-*\\/%]=|\\+\\+|--|\\.\\.|[+\\-*&^%:=!|\\/]|<(?!#)|(?!#)>/;\n  var operators = buildRegexp([wordOperators, symbolOperators], { suffix: '' });\n\n  var numbers = /^((0x[\\da-f]+)|((\\d+\\.\\d+|\\d\\.|\\.\\d+|\\d+)(e[\\+\\-]?\\d+)?))[ld]?([kmgtp]b)?/i;\n\n  var identifiers = /^[A-Za-z\\_][A-Za-z\\-\\_\\d]*\\b/;\n\n  var symbolBuiltins = /[A-Z]:|%|\\?/i;\n  var namedBuiltins = buildRegexp([\n    /Add-(Computer|Content|History|Member|PSSnapin|Type)/,\n    /Checkpoint-Computer/,\n    /Clear-(Content|EventLog|History|Host|Item(Property)?|Variable)/,\n    /Compare-Object/,\n    /Complete-Transaction/,\n    /Connect-PSSession/,\n    /ConvertFrom-(Csv|Json|SecureString|StringData)/,\n    /Convert-Path/,\n    /ConvertTo-(Csv|Html|Json|SecureString|Xml)/,\n    /Copy-Item(Property)?/,\n    /Debug-Process/,\n    /Disable-(ComputerRestore|PSBreakpoint|PSRemoting|PSSessionConfiguration)/,\n    /Disconnect-PSSession/,\n    /Enable-(ComputerRestore|PSBreakpoint|PSRemoting|PSSessionConfiguration)/,\n    /(Enter|Exit)-PSSession/,\n    /Export-(Alias|Clixml|Console|Counter|Csv|FormatData|ModuleMember|PSSession)/,\n    /ForEach-Object/,\n    /Format-(Custom|List|Table|Wide)/,\n    new RegExp('Get-(Acl|Alias|AuthenticodeSignature|ChildItem|Command|ComputerRestorePoint|Content|ControlPanelItem|Counter|Credential'\n      + '|Culture|Date|Event|EventLog|EventSubscriber|ExecutionPolicy|FormatData|Help|History|Host|HotFix|Item|ItemProperty|Job'\n      + '|Location|Member|Module|PfxCertificate|Process|PSBreakpoint|PSCallStack|PSDrive|PSProvider|PSSession|PSSessionConfiguration'\n      + '|PSSnapin|Random|Service|TraceSource|Transaction|TypeData|UICulture|Unique|Variable|Verb|WinEvent|WmiObject)'),\n    /Group-Object/,\n    /Import-(Alias|Clixml|Counter|Csv|LocalizedData|Module|PSSession)/,\n    /ImportSystemModules/,\n    /Invoke-(Command|Expression|History|Item|RestMethod|WebRequest|WmiMethod)/,\n    /Join-Path/,\n    /Limit-EventLog/,\n    /Measure-(Command|Object)/,\n    /Move-Item(Property)?/,\n    new RegExp('New-(Alias|Event|EventLog|Item(Property)?|Module|ModuleManifest|Object|PSDrive|PSSession|PSSessionConfigurationFile'\n      + '|PSSessionOption|PSTransportOption|Service|TimeSpan|Variable|WebServiceProxy|WinEvent)'),\n    /Out-(Default|File|GridView|Host|Null|Printer|String)/,\n    /Pause/,\n    /(Pop|Push)-Location/,\n    /Read-Host/,\n    /Receive-(Job|PSSession)/,\n    /Register-(EngineEvent|ObjectEvent|PSSessionConfiguration|WmiEvent)/,\n    /Remove-(Computer|Event|EventLog|Item(Property)?|Job|Module|PSBreakpoint|PSDrive|PSSession|PSSnapin|TypeData|Variable|WmiObject)/,\n    /Rename-(Computer|Item(Property)?)/,\n    /Reset-ComputerMachinePassword/,\n    /Resolve-Path/,\n    /Restart-(Computer|Service)/,\n    /Restore-Computer/,\n    /Resume-(Job|Service)/,\n    /Save-Help/,\n    /Select-(Object|String|Xml)/,\n    /Send-MailMessage/,\n    new RegExp('Set-(Acl|Alias|AuthenticodeSignature|Content|Date|ExecutionPolicy|Item(Property)?|Location|PSBreakpoint|PSDebug' +\n               '|PSSessionConfiguration|Service|StrictMode|TraceSource|Variable|WmiInstance)'),\n    /Show-(Command|ControlPanelItem|EventLog)/,\n    /Sort-Object/,\n    /Split-Path/,\n    /Start-(Job|Process|Service|Sleep|Transaction|Transcript)/,\n    /Stop-(Computer|Job|Process|Service|Transcript)/,\n    /Suspend-(Job|Service)/,\n    /TabExpansion2/,\n    /Tee-Object/,\n    /Test-(ComputerSecureChannel|Connection|ModuleManifest|Path|PSSessionConfigurationFile)/,\n    /Trace-Command/,\n    /Unblock-File/,\n    /Undo-Transaction/,\n    /Unregister-(Event|PSSessionConfiguration)/,\n    /Update-(FormatData|Help|List|TypeData)/,\n    /Use-Transaction/,\n    /Wait-(Event|Job|Process)/,\n    /Where-Object/,\n    /Write-(Debug|Error|EventLog|Host|Output|Progress|Verbose|Warning)/,\n    /cd|help|mkdir|more|oss|prompt/,\n    /ac|asnp|cat|cd|chdir|clc|clear|clhy|cli|clp|cls|clv|cnsn|compare|copy|cp|cpi|cpp|cvpa|dbp|del|diff|dir|dnsn|ebp/,\n    /echo|epal|epcsv|epsn|erase|etsn|exsn|fc|fl|foreach|ft|fw|gal|gbp|gc|gci|gcm|gcs|gdr|ghy|gi|gjb|gl|gm|gmo|gp|gps/,\n    /group|gsn|gsnp|gsv|gu|gv|gwmi|h|history|icm|iex|ihy|ii|ipal|ipcsv|ipmo|ipsn|irm|ise|iwmi|iwr|kill|lp|ls|man|md/,\n    /measure|mi|mount|move|mp|mv|nal|ndr|ni|nmo|npssc|nsn|nv|ogv|oh|popd|ps|pushd|pwd|r|rbp|rcjb|rcsn|rd|rdr|ren|ri/,\n    /rjb|rm|rmdir|rmo|rni|rnp|rp|rsn|rsnp|rujb|rv|rvpa|rwmi|sajb|sal|saps|sasv|sbp|sc|select|set|shcm|si|sl|sleep|sls/,\n    /sort|sp|spjb|spps|spsv|start|sujb|sv|swmi|tee|trcm|type|where|wjb|write/\n  ], { prefix: '', suffix: '' });\n  var variableBuiltins = buildRegexp([\n    /[$?^_]|Args|ConfirmPreference|ConsoleFileName|DebugPreference|Error|ErrorActionPreference|ErrorView|ExecutionContext/,\n    /FormatEnumerationLimit|Home|Host|Input|MaximumAliasCount|MaximumDriveCount|MaximumErrorCount|MaximumFunctionCount/,\n    /MaximumHistoryCount|MaximumVariableCount|MyInvocation|NestedPromptLevel|OutputEncoding|Pid|Profile|ProgressPreference/,\n    /PSBoundParameters|PSCommandPath|PSCulture|PSDefaultParameterValues|PSEmailServer|PSHome|PSScriptRoot|PSSessionApplicationName/,\n    /PSSessionConfigurationName|PSSessionOption|PSUICulture|PSVersionTable|Pwd|ShellId|StackTrace|VerbosePreference/,\n    /WarningPreference|WhatIfPreference/,\n\n    /Event|EventArgs|EventSubscriber|Sender/,\n    /Matches|Ofs|ForEach|LastExitCode|PSCmdlet|PSItem|PSSenderInfo|This/,\n    /true|false|null/\n  ], { prefix: '\\\\$', suffix: '' });\n\n  var builtins = buildRegexp([symbolBuiltins, namedBuiltins, variableBuiltins], { suffix: notCharacterOrDash });\n\n  var grammar = {\n    keyword: keywords,\n    number: numbers,\n    operator: operators,\n    builtin: builtins,\n    punctuation: punctuation,\n    identifier: identifiers\n  };\n\n  // tokenizers\n  function tokenBase(stream, state) {\n    // Handle Comments\n    //var ch = stream.peek();\n\n    var parent = state.returnStack[state.returnStack.length - 1];\n    if (parent && parent.shouldReturnFrom(state)) {\n      state.tokenize = parent.tokenize;\n      state.returnStack.pop();\n      return state.tokenize(stream, state);\n    }\n\n    if (stream.eatSpace()) {\n      return null;\n    }\n\n    if (stream.eat('(')) {\n      state.bracketNesting += 1;\n      return 'punctuation';\n    }\n\n    if (stream.eat(')')) {\n      state.bracketNesting -= 1;\n      return 'punctuation';\n    }\n\n    for (var key in grammar) {\n      if (stream.match(grammar[key])) {\n        return key;\n      }\n    }\n\n    var ch = stream.next();\n\n    // single-quote string\n    if (ch === \"'\") {\n      return tokenSingleQuoteString(stream, state);\n    }\n\n    if (ch === '$') {\n      return tokenVariable(stream, state);\n    }\n\n    // double-quote string\n    if (ch === '\"') {\n      return tokenDoubleQuoteString(stream, state);\n    }\n\n    if (ch === '<' && stream.eat('#')) {\n      state.tokenize = tokenComment;\n      return tokenComment(stream, state);\n    }\n\n    if (ch === '#') {\n      stream.skipToEnd();\n      return 'comment';\n    }\n\n    if (ch === '@') {\n      var quoteMatch = stream.eat(/[\"']/);\n      if (quoteMatch && stream.eol()) {\n        state.tokenize = tokenMultiString;\n        state.startQuote = quoteMatch[0];\n        return tokenMultiString(stream, state);\n      } else if (stream.eol()) {\n        return 'error';\n      } else if (stream.peek().match(/[({]/)) {\n        return 'punctuation';\n      } else if (stream.peek().match(varNames)) {\n        // splatted variable\n        return tokenVariable(stream, state);\n      }\n    }\n    return 'error';\n  }\n\n  function tokenSingleQuoteString(stream, state) {\n    var ch;\n    while ((ch = stream.peek()) != null) {\n      stream.next();\n\n      if (ch === \"'\" && !stream.eat(\"'\")) {\n        state.tokenize = tokenBase;\n        return 'string';\n      }\n    }\n\n    return 'error';\n  }\n\n  function tokenDoubleQuoteString(stream, state) {\n    var ch;\n    while ((ch = stream.peek()) != null) {\n      if (ch === '$') {\n        state.tokenize = tokenStringInterpolation;\n        return 'string';\n      }\n\n      stream.next();\n      if (ch === '`') {\n        stream.next();\n        continue;\n      }\n\n      if (ch === '\"' && !stream.eat('\"')) {\n        state.tokenize = tokenBase;\n        return 'string';\n      }\n    }\n\n    return 'error';\n  }\n\n  function tokenStringInterpolation(stream, state) {\n    return tokenInterpolation(stream, state, tokenDoubleQuoteString);\n  }\n\n  function tokenMultiStringReturn(stream, state) {\n    state.tokenize = tokenMultiString;\n    state.startQuote = '\"'\n    return tokenMultiString(stream, state);\n  }\n\n  function tokenHereStringInterpolation(stream, state) {\n    return tokenInterpolation(stream, state, tokenMultiStringReturn);\n  }\n\n  function tokenInterpolation(stream, state, parentTokenize) {\n    if (stream.match('$(')) {\n      var savedBracketNesting = state.bracketNesting;\n      state.returnStack.push({\n        /*jshint loopfunc:true */\n        shouldReturnFrom: function(state) {\n          return state.bracketNesting === savedBracketNesting;\n        },\n        tokenize: parentTokenize\n      });\n      state.tokenize = tokenBase;\n      state.bracketNesting += 1;\n      return 'punctuation';\n    } else {\n      stream.next();\n      state.returnStack.push({\n        shouldReturnFrom: function() { return true; },\n        tokenize: parentTokenize\n      });\n      state.tokenize = tokenVariable;\n      return state.tokenize(stream, state);\n    }\n  }\n\n  function tokenComment(stream, state) {\n    var maybeEnd = false, ch;\n    while ((ch = stream.next()) != null) {\n      if (maybeEnd && ch == '>') {\n          state.tokenize = tokenBase;\n          break;\n      }\n      maybeEnd = (ch === '#');\n    }\n    return 'comment';\n  }\n\n  function tokenVariable(stream, state) {\n    var ch = stream.peek();\n    if (stream.eat('{')) {\n      state.tokenize = tokenVariableWithBraces;\n      return tokenVariableWithBraces(stream, state);\n    } else if (ch != undefined && ch.match(varNames)) {\n      stream.eatWhile(varNames);\n      state.tokenize = tokenBase;\n      return 'variable-2';\n    } else {\n      state.tokenize = tokenBase;\n      return 'error';\n    }\n  }\n\n  function tokenVariableWithBraces(stream, state) {\n    var ch;\n    while ((ch = stream.next()) != null) {\n      if (ch === '}') {\n        state.tokenize = tokenBase;\n        break;\n      }\n    }\n    return 'variable-2';\n  }\n\n  function tokenMultiString(stream, state) {\n    var quote = state.startQuote;\n    if (stream.sol() && stream.match(new RegExp(quote + '@'))) {\n      state.tokenize = tokenBase;\n    }\n    else if (quote === '\"') {\n      while (!stream.eol()) {\n        var ch = stream.peek();\n        if (ch === '$') {\n          state.tokenize = tokenHereStringInterpolation;\n          return 'string';\n        }\n\n        stream.next();\n        if (ch === '`') {\n          stream.next();\n        }\n      }\n    }\n    else {\n      stream.skipToEnd();\n    }\n\n    return 'string';\n  }\n\n  var external = {\n    startState: function() {\n      return {\n        returnStack: [],\n        bracketNesting: 0,\n        tokenize: tokenBase\n      };\n    },\n\n    token: function(stream, state) {\n      return state.tokenize(stream, state);\n    },\n\n    blockCommentStart: '<#',\n    blockCommentEnd: '#>',\n    lineComment: '#',\n    fold: 'brace'\n  };\n  return external;\n});\n\nCodeMirror.defineMIME('application/x-powershell', 'powershell');\n});\n"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/plugins/codemirror/mode/python/python.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: https://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n\n  function wordRegexp(words) {\n    return new RegExp(\"^((\" + words.join(\")|(\") + \"))\\\\b\");\n  }\n\n  var wordOperators = wordRegexp([\"and\", \"or\", \"not\", \"is\"]);\n  var commonKeywords = [\"as\", \"assert\", \"break\", \"class\", \"continue\",\n                        \"def\", \"del\", \"elif\", \"else\", \"except\", \"finally\",\n                        \"for\", \"from\", \"global\", \"if\", \"import\",\n                        \"lambda\", \"pass\", \"raise\", \"return\",\n                        \"try\", \"while\", \"with\", \"yield\", \"in\"];\n  var commonBuiltins = [\"abs\", \"all\", \"any\", \"bin\", \"bool\", \"bytearray\", \"callable\", \"chr\",\n                        \"classmethod\", \"compile\", \"complex\", \"delattr\", \"dict\", \"dir\", \"divmod\",\n                        \"enumerate\", \"eval\", \"filter\", \"float\", \"format\", \"frozenset\",\n                        \"getattr\", \"globals\", \"hasattr\", \"hash\", \"help\", \"hex\", \"id\",\n                        \"input\", \"int\", \"isinstance\", \"issubclass\", \"iter\", \"len\",\n                        \"list\", \"locals\", \"map\", \"max\", \"memoryview\", \"min\", \"next\",\n                        \"object\", \"oct\", \"open\", \"ord\", \"pow\", \"property\", \"range\",\n                        \"repr\", \"reversed\", \"round\", \"set\", \"setattr\", \"slice\",\n                        \"sorted\", \"staticmethod\", \"str\", \"sum\", \"super\", \"tuple\",\n                        \"type\", \"vars\", \"zip\", \"__import__\", \"NotImplemented\",\n                        \"Ellipsis\", \"__debug__\"];\n  CodeMirror.registerHelper(\"hintWords\", \"python\", commonKeywords.concat(commonBuiltins));\n\n  function top(state) {\n    return state.scopes[state.scopes.length - 1];\n  }\n\n  CodeMirror.defineMode(\"python\", function(conf, parserConf) {\n    var ERRORCLASS = \"error\";\n\n    var delimiters = parserConf.delimiters || parserConf.singleDelimiters || /^[\\(\\)\\[\\]\\{\\}@,:`=;\\.\\\\]/;\n    //               (Backwards-compatiblity with old, cumbersome config system)\n    var operators = [parserConf.singleOperators, parserConf.doubleOperators, parserConf.doubleDelimiters, parserConf.tripleDelimiters,\n                     parserConf.operators || /^([-+*/%\\/&|^]=?|[<>=]+|\\/\\/=?|\\*\\*=?|!=|[~!@])/]\n    for (var i = 0; i < operators.length; i++) if (!operators[i]) operators.splice(i--, 1)\n\n    var hangingIndent = parserConf.hangingIndent || conf.indentUnit;\n\n    var myKeywords = commonKeywords, myBuiltins = commonBuiltins;\n    if (parserConf.extra_keywords != undefined)\n      myKeywords = myKeywords.concat(parserConf.extra_keywords);\n\n    if (parserConf.extra_builtins != undefined)\n      myBuiltins = myBuiltins.concat(parserConf.extra_builtins);\n\n    var py3 = !(parserConf.version && Number(parserConf.version) < 3)\n    if (py3) {\n      // since http://legacy.python.org/dev/peps/pep-0465/ @ is also an operator\n      var identifiers = parserConf.identifiers|| /^[_A-Za-z\\u00A1-\\uFFFF][_A-Za-z0-9\\u00A1-\\uFFFF]*/;\n      myKeywords = myKeywords.concat([\"nonlocal\", \"False\", \"True\", \"None\", \"async\", \"await\"]);\n      myBuiltins = myBuiltins.concat([\"ascii\", \"bytes\", \"exec\", \"print\"]);\n      var stringPrefixes = new RegExp(\"^(([rbuf]|(br)|(fr))?('{3}|\\\"{3}|['\\\"]))\", \"i\");\n    } else {\n      var identifiers = parserConf.identifiers|| /^[_A-Za-z][_A-Za-z0-9]*/;\n      myKeywords = myKeywords.concat([\"exec\", \"print\"]);\n      myBuiltins = myBuiltins.concat([\"apply\", \"basestring\", \"buffer\", \"cmp\", \"coerce\", \"execfile\",\n                                      \"file\", \"intern\", \"long\", \"raw_input\", \"reduce\", \"reload\",\n                                      \"unichr\", \"unicode\", \"xrange\", \"False\", \"True\", \"None\"]);\n      var stringPrefixes = new RegExp(\"^(([rubf]|(ur)|(br))?('{3}|\\\"{3}|['\\\"]))\", \"i\");\n    }\n    var keywords = wordRegexp(myKeywords);\n    var builtins = wordRegexp(myBuiltins);\n\n    // tokenizers\n    function tokenBase(stream, state) {\n      var sol = stream.sol() && state.lastToken != \"\\\\\"\n      if (sol) state.indent = stream.indentation()\n      // Handle scope changes\n      if (sol && top(state).type == \"py\") {\n        var scopeOffset = top(state).offset;\n        if (stream.eatSpace()) {\n          var lineOffset = stream.indentation();\n          if (lineOffset > scopeOffset)\n            pushPyScope(state);\n          else if (lineOffset < scopeOffset && dedent(stream, state) && stream.peek() != \"#\")\n            state.errorToken = true;\n          return null;\n        } else {\n          var style = tokenBaseInner(stream, state);\n          if (scopeOffset > 0 && dedent(stream, state))\n            style += \" \" + ERRORCLASS;\n          return style;\n        }\n      }\n      return tokenBaseInner(stream, state);\n    }\n\n    function tokenBaseInner(stream, state) {\n      if (stream.eatSpace()) return null;\n\n      // Handle Comments\n      if (stream.match(/^#.*/)) return \"comment\";\n\n      // Handle Number Literals\n      if (stream.match(/^[0-9\\.]/, false)) {\n        var floatLiteral = false;\n        // Floats\n        if (stream.match(/^[\\d_]*\\.\\d+(e[\\+\\-]?\\d+)?/i)) { floatLiteral = true; }\n        if (stream.match(/^[\\d_]+\\.\\d*/)) { floatLiteral = true; }\n        if (stream.match(/^\\.\\d+/)) { floatLiteral = true; }\n        if (floatLiteral) {\n          // Float literals may be \"imaginary\"\n          stream.eat(/J/i);\n          return \"number\";\n        }\n        // Integers\n        var intLiteral = false;\n        // Hex\n        if (stream.match(/^0x[0-9a-f_]+/i)) intLiteral = true;\n        // Binary\n        if (stream.match(/^0b[01_]+/i)) intLiteral = true;\n        // Octal\n        if (stream.match(/^0o[0-7_]+/i)) intLiteral = true;\n        // Decimal\n        if (stream.match(/^[1-9][\\d_]*(e[\\+\\-]?[\\d_]+)?/)) {\n          // Decimal literals may be \"imaginary\"\n          stream.eat(/J/i);\n          // TODO - Can you have imaginary longs?\n          intLiteral = true;\n        }\n        // Zero by itself with no other piece of number.\n        if (stream.match(/^0(?![\\dx])/i)) intLiteral = true;\n        if (intLiteral) {\n          // Integer literals may be \"long\"\n          stream.eat(/L/i);\n          return \"number\";\n        }\n      }\n\n      // Handle Strings\n      if (stream.match(stringPrefixes)) {\n        var isFmtString = stream.current().toLowerCase().indexOf('f') !== -1;\n        if (!isFmtString) {\n          state.tokenize = tokenStringFactory(stream.current());\n          return state.tokenize(stream, state);\n        } else {\n          state.tokenize = formatStringFactory(stream.current(), state.tokenize);\n          return state.tokenize(stream, state);\n        }\n      }\n\n      for (var i = 0; i < operators.length; i++)\n        if (stream.match(operators[i])) return \"operator\"\n\n      if (stream.match(delimiters)) return \"punctuation\";\n\n      if (state.lastToken == \".\" && stream.match(identifiers))\n        return \"property\";\n\n      if (stream.match(keywords) || stream.match(wordOperators))\n        return \"keyword\";\n\n      if (stream.match(builtins))\n        return \"builtin\";\n\n      if (stream.match(/^(self|cls)\\b/))\n        return \"variable-2\";\n\n      if (stream.match(identifiers)) {\n        if (state.lastToken == \"def\" || state.lastToken == \"class\")\n          return \"def\";\n        return \"variable\";\n      }\n\n      // Handle non-detected items\n      stream.next();\n      return ERRORCLASS;\n    }\n\n    function formatStringFactory(delimiter, tokenOuter) {\n      while (\"rubf\".indexOf(delimiter.charAt(0).toLowerCase()) >= 0)\n        delimiter = delimiter.substr(1);\n\n      var singleline = delimiter.length == 1;\n      var OUTCLASS = \"string\";\n\n      function tokenFString(stream, state) {\n        // inside f-str Expression\n        if (stream.match(delimiter)) {\n          // expression ends pre-maturally, but very common in editing\n          // Could show error to remind users to close brace here\n          state.tokenize = tokenString\n          return OUTCLASS;\n        } else if (stream.match('{')) {\n          // starting brace, if not eaten below\n          return \"punctuation\";\n        } else if (stream.match('}')) {\n          // return to regular inside string state\n          state.tokenize = tokenString\n          return \"punctuation\";\n        } else {\n          // use tokenBaseInner to parse the expression\n          return tokenBaseInner(stream, state);\n        }\n      }\n\n      function tokenString(stream, state) {\n        while (!stream.eol()) {\n          stream.eatWhile(/[^'\"\\{\\}\\\\]/);\n          if (stream.eat(\"\\\\\")) {\n            stream.next();\n            if (singleline && stream.eol())\n              return OUTCLASS;\n          } else if (stream.match(delimiter)) {\n            state.tokenize = tokenOuter;\n            return OUTCLASS;\n          } else if (stream.match('{{')) {\n            // ignore {{ in f-str\n            return OUTCLASS;\n          } else if (stream.match('{', false)) {\n            // switch to nested mode\n            state.tokenize = tokenFString\n            if (stream.current()) {\n              return OUTCLASS;\n            } else {\n              // need to return something, so eat the starting {\n              stream.next();\n              return \"punctuation\";\n            }\n          } else if (stream.match('}}')) {\n            return OUTCLASS;\n          } else if (stream.match('}')) {\n            // single } in f-string is an error\n            return ERRORCLASS;\n          } else {\n            stream.eat(/['\"]/);\n          }\n        }\n        if (singleline) {\n          if (parserConf.singleLineStringErrors)\n            return ERRORCLASS;\n          else\n            state.tokenize = tokenOuter;\n        }\n        return OUTCLASS;\n      }\n      tokenString.isString = true;\n      return tokenString;\n    }\n\n    function tokenStringFactory(delimiter) {\n      while (\"rubf\".indexOf(delimiter.charAt(0).toLowerCase()) >= 0)\n        delimiter = delimiter.substr(1);\n\n      var singleline = delimiter.length == 1;\n      var OUTCLASS = \"string\";\n\n      function tokenString(stream, state) {\n        while (!stream.eol()) {\n          stream.eatWhile(/[^'\"\\\\]/);\n          if (stream.eat(\"\\\\\")) {\n            stream.next();\n            if (singleline && stream.eol())\n              return OUTCLASS;\n          } else if (stream.match(delimiter)) {\n            state.tokenize = tokenBase;\n            return OUTCLASS;\n          } else {\n            stream.eat(/['\"]/);\n          }\n        }\n        if (singleline) {\n          if (parserConf.singleLineStringErrors)\n            return ERRORCLASS;\n          else\n            state.tokenize = tokenBase;\n        }\n        return OUTCLASS;\n      }\n      tokenString.isString = true;\n      return tokenString;\n    }\n\n    function pushPyScope(state) {\n      while (top(state).type != \"py\") state.scopes.pop()\n      state.scopes.push({offset: top(state).offset + conf.indentUnit,\n                         type: \"py\",\n                         align: null})\n    }\n\n    function pushBracketScope(stream, state, type) {\n      var align = stream.match(/^([\\s\\[\\{\\(]|#.*)*$/, false) ? null : stream.column() + 1\n      state.scopes.push({offset: state.indent + hangingIndent,\n                         type: type,\n                         align: align})\n    }\n\n    function dedent(stream, state) {\n      var indented = stream.indentation();\n      while (state.scopes.length > 1 && top(state).offset > indented) {\n        if (top(state).type != \"py\") return true;\n        state.scopes.pop();\n      }\n      return top(state).offset != indented;\n    }\n\n    function tokenLexer(stream, state) {\n      if (stream.sol()) state.beginningOfLine = true;\n\n      var style = state.tokenize(stream, state);\n      var current = stream.current();\n\n      // Handle decorators\n      if (state.beginningOfLine && current == \"@\")\n        return stream.match(identifiers, false) ? \"meta\" : py3 ? \"operator\" : ERRORCLASS;\n\n      if (/\\S/.test(current)) state.beginningOfLine = false;\n\n      if ((style == \"variable\" || style == \"builtin\")\n          && state.lastToken == \"meta\")\n        style = \"meta\";\n\n      // Handle scope changes.\n      if (current == \"pass\" || current == \"return\")\n        state.dedent += 1;\n\n      if (current == \"lambda\") state.lambda = true;\n      if (current == \":\" && !state.lambda && top(state).type == \"py\")\n        pushPyScope(state);\n\n      if (current.length == 1 && !/string|comment/.test(style)) {\n        var delimiter_index = \"[({\".indexOf(current);\n        if (delimiter_index != -1)\n          pushBracketScope(stream, state, \"])}\".slice(delimiter_index, delimiter_index+1));\n\n        delimiter_index = \"])}\".indexOf(current);\n        if (delimiter_index != -1) {\n          if (top(state).type == current) state.indent = state.scopes.pop().offset - hangingIndent\n          else return ERRORCLASS;\n        }\n      }\n      if (state.dedent > 0 && stream.eol() && top(state).type == \"py\") {\n        if (state.scopes.length > 1) state.scopes.pop();\n        state.dedent -= 1;\n      }\n\n      return style;\n    }\n\n    var external = {\n      startState: function(basecolumn) {\n        return {\n          tokenize: tokenBase,\n          scopes: [{offset: basecolumn || 0, type: \"py\", align: null}],\n          indent: basecolumn || 0,\n          lastToken: null,\n          lambda: false,\n          dedent: 0\n        };\n      },\n\n      token: function(stream, state) {\n        var addErr = state.errorToken;\n        if (addErr) state.errorToken = false;\n        var style = tokenLexer(stream, state);\n\n        if (style && style != \"comment\")\n          state.lastToken = (style == \"keyword\" || style == \"punctuation\") ? stream.current() : style;\n        if (style == \"punctuation\") style = null;\n\n        if (stream.eol() && state.lambda)\n          state.lambda = false;\n        return addErr ? style + \" \" + ERRORCLASS : style;\n      },\n\n      indent: function(state, textAfter) {\n        if (state.tokenize != tokenBase)\n          return state.tokenize.isString ? CodeMirror.Pass : 0;\n\n        var scope = top(state), closing = scope.type == textAfter.charAt(0)\n        if (scope.align != null)\n          return scope.align - (closing ? 1 : 0)\n        else\n          return scope.offset - (closing ? hangingIndent : 0)\n      },\n\n      electricInput: /^\\s*[\\}\\]\\)]$/,\n      closeBrackets: {triples: \"'\\\"\"},\n      lineComment: \"#\",\n      fold: \"indent\"\n    };\n    return external;\n  });\n\n  CodeMirror.defineMIME(\"text/x-python\", \"python\");\n\n  var words = function(str) { return str.split(\" \"); };\n\n  CodeMirror.defineMIME(\"text/x-cython\", {\n    name: \"python\",\n    extra_keywords: words(\"by cdef cimport cpdef ctypedef enum except \"+\n                          \"extern gil include nogil property public \"+\n                          \"readonly struct union DEF IF ELIF ELSE\")\n  });\n\n});\n"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/plugins/codemirror/mode/shell/shell.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: https://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode('shell', function() {\n\n  var words = {};\n  function define(style, dict) {\n    for(var i = 0; i < dict.length; i++) {\n      words[dict[i]] = style;\n    }\n  };\n\n  var commonAtoms = [\"true\", \"false\"];\n  var commonKeywords = [\"if\", \"then\", \"do\", \"else\", \"elif\", \"while\", \"until\", \"for\", \"in\", \"esac\", \"fi\",\n    \"fin\", \"fil\", \"done\", \"exit\", \"set\", \"unset\", \"export\", \"function\"];\n  var commonCommands = [\"ab\", \"awk\", \"bash\", \"beep\", \"cat\", \"cc\", \"cd\", \"chown\", \"chmod\", \"chroot\", \"clear\",\n    \"cp\", \"curl\", \"cut\", \"diff\", \"echo\", \"find\", \"gawk\", \"gcc\", \"get\", \"git\", \"grep\", \"hg\", \"kill\", \"killall\",\n    \"ln\", \"ls\", \"make\", \"mkdir\", \"openssl\", \"mv\", \"nc\", \"nl\", \"node\", \"npm\", \"ping\", \"ps\", \"restart\", \"rm\",\n    \"rmdir\", \"sed\", \"service\", \"sh\", \"shopt\", \"shred\", \"source\", \"sort\", \"sleep\", \"ssh\", \"start\", \"stop\",\n    \"su\", \"sudo\", \"svn\", \"tee\", \"telnet\", \"top\", \"touch\", \"vi\", \"vim\", \"wall\", \"wc\", \"wget\", \"who\", \"write\",\n    \"yes\", \"zsh\"];\n\n  CodeMirror.registerHelper(\"hintWords\", \"shell\", commonAtoms.concat(commonKeywords, commonCommands));\n\n  define('atom', commonAtoms);\n  define('keyword', commonKeywords);\n  define('builtin', commonCommands);\n\n  function tokenBase(stream, state) {\n    if (stream.eatSpace()) return null;\n\n    var sol = stream.sol();\n    var ch = stream.next();\n\n    if (ch === '\\\\') {\n      stream.next();\n      return null;\n    }\n    if (ch === '\\'' || ch === '\"' || ch === '`') {\n      state.tokens.unshift(tokenString(ch, ch === \"`\" ? \"quote\" : \"string\"));\n      return tokenize(stream, state);\n    }\n    if (ch === '#') {\n      if (sol && stream.eat('!')) {\n        stream.skipToEnd();\n        return 'meta'; // 'comment'?\n      }\n      stream.skipToEnd();\n      return 'comment';\n    }\n    if (ch === '$') {\n      state.tokens.unshift(tokenDollar);\n      return tokenize(stream, state);\n    }\n    if (ch === '+' || ch === '=') {\n      return 'operator';\n    }\n    if (ch === '-') {\n      stream.eat('-');\n      stream.eatWhile(/\\w/);\n      return 'attribute';\n    }\n    if (/\\d/.test(ch)) {\n      stream.eatWhile(/\\d/);\n      if(stream.eol() || !/\\w/.test(stream.peek())) {\n        return 'number';\n      }\n    }\n    stream.eatWhile(/[\\w-]/);\n    var cur = stream.current();\n    if (stream.peek() === '=' && /\\w+/.test(cur)) return 'def';\n    return words.hasOwnProperty(cur) ? words[cur] : null;\n  }\n\n  function tokenString(quote, style) {\n    var close = quote == \"(\" ? \")\" : quote == \"{\" ? \"}\" : quote\n    return function(stream, state) {\n      var next, escaped = false;\n      while ((next = stream.next()) != null) {\n        if (next === close && !escaped) {\n          state.tokens.shift();\n          break;\n        } else if (next === '$' && !escaped && quote !== \"'\" && stream.peek() != close) {\n          escaped = true;\n          stream.backUp(1);\n          state.tokens.unshift(tokenDollar);\n          break;\n        } else if (!escaped && quote !== close && next === quote) {\n          state.tokens.unshift(tokenString(quote, style))\n          return tokenize(stream, state)\n        } else if (!escaped && /['\"]/.test(next) && !/['\"]/.test(quote)) {\n          state.tokens.unshift(tokenStringStart(next, \"string\"));\n          stream.backUp(1);\n          break;\n        }\n        escaped = !escaped && next === '\\\\';\n      }\n      return style;\n    };\n  };\n\n  function tokenStringStart(quote, style) {\n    return function(stream, state) {\n      state.tokens[0] = tokenString(quote, style)\n      stream.next()\n      return tokenize(stream, state)\n    }\n  }\n\n  var tokenDollar = function(stream, state) {\n    if (state.tokens.length > 1) stream.eat('$');\n    var ch = stream.next()\n    if (/['\"({]/.test(ch)) {\n      state.tokens[0] = tokenString(ch, ch == \"(\" ? \"quote\" : ch == \"{\" ? \"def\" : \"string\");\n      return tokenize(stream, state);\n    }\n    if (!/\\d/.test(ch)) stream.eatWhile(/\\w/);\n    state.tokens.shift();\n    return 'def';\n  };\n\n  function tokenize(stream, state) {\n    return (state.tokens[0] || tokenBase) (stream, state);\n  };\n\n  return {\n    startState: function() {return {tokens:[]};},\n    token: function(stream, state) {\n      return tokenize(stream, state);\n    },\n    closeBrackets: \"()[]{}''\\\"\\\"``\",\n    lineComment: '#',\n    fold: \"brace\"\n  };\n});\n\nCodeMirror.defineMIME('text/x-sh', 'shell');\n// Apache uses a slightly different Media Type for Shell scripts\n// http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types\nCodeMirror.defineMIME('application/x-sh', 'shell');\n\n});\n"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/plugins/cronGen/cronGen.js",
    "content": "﻿(function ($) {\n    // var resultsName = \"\";\n    var inputElement;\n    var displayElement;\n    $.fn.extend({\n        cronGen: function (options) {\n            if (options == null) {\n              options = {};\n            }\n            options = $.extend({}, $.fn.cronGen.defaultOptions, options);\n            //create top menu\n            var cronContainer = $(\"<div/>\", { id: \"CronContainer\", style: \"display:none;width:300px;height:300px;\" });\n            var mainDiv = $(\"<div/>\", { id: \"CronGenMainDiv\", style: \"width:410px;height:420px;\" });\n            var topMenu = $(\"<ul/>\", { \"class\": \"nav nav-tabs\", id: \"CronGenTabs\" });\n            $('<li/>', { 'class': 'active' }).html($('<a id=\"SecondlyTab\" href=\"#Secondly\">秒</a>')).appendTo(topMenu);\n            $('<li/>').html($('<a id=\"MinutesTab\" href=\"#Minutes\">分钟</a>')).appendTo(topMenu);\n            $('<li/>').html($('<a id=\"HourlyTab\" href=\"#Hourly\">小时</a>')).appendTo(topMenu);\n            $('<li/>').html($('<a id=\"DailyTab\" href=\"#Daily\">日</a>')).appendTo(topMenu);\n            $('<li/>').html($('<a id=\"MonthlyTab\" href=\"#Monthly\">月</a>')).appendTo(topMenu);\n            $('<li/>').html($('<a id=\"WeeklyTab\" href=\"#Weekly\">周</a>')).appendTo(topMenu);\n            $('<li/>').html($('<a id=\"YearlyTab\" href=\"#Yearly\">年</a>')).appendTo(topMenu);\n            $(topMenu).appendTo(mainDiv);\n\n            //create what's inside the tabs\n            var container = $(\"<div/>\", { \"class\": \"container-fluid\", \"style\": \"margin-top: 30px;margin-left: -14px;\" });\n            var row = $(\"<div/>\", { \"class\": \"row-fluid\" });\n            var span12 = $(\"<div/>\", { \"class\": \"span12\" });\n            var tabContent = $(\"<div/>\", { \"class\": \"tab-content\", \"style\": \"border:0px; margin-top:-20px;\" });\n\n\n            //creating the secondsTab\n            var secondsTab = $(\"<div/>\", { \"class\": \"tab-pane active\", id: \"Secondly\" });\n            var seconds1 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"1\", name : \"second\"}).appendTo(seconds1);\n            $(seconds1).append(\"每秒 允许的通配符[, - * /]\");\n            $(seconds1).appendTo(secondsTab);\n\n            var seconds2 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"2\", name : \"second\"}).appendTo(seconds2);\n            $(seconds2).append(\"周期 从\");\n            $(\"<input/>\",{type : \"text\", id : \"secondStart_0\", value : \"1\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(seconds2);\n            $(seconds2).append(\"-\");\n            $(\"<input/>\",{type : \"text\", id : \"secondEnd_0\", value : \"2\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(seconds2);\n            $(seconds2).append(\"秒\");\n            $(seconds2).appendTo(secondsTab);\n\n            var seconds3 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"3\", name : \"second\"}).appendTo(seconds3);\n            $(seconds3).append(\"从\");\n            $(\"<input/>\",{type : \"text\", id : \"secondStart_1\", value : \"0\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(seconds3);\n            $(seconds3).append(\"秒开始,每\");\n            $(\"<input/>\",{type : \"text\", id : \"secondEnd_1\", value : \"1\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(seconds3);\n            $(seconds3).append(\"秒执行一次\");\n            $(seconds3).appendTo(secondsTab);\n\n            var seconds4 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"4\", name : \"second\", id: \"sencond_appoint\"}).appendTo(seconds4);\n            $(seconds4).append(\"指定\");\n            $(seconds4).appendTo(secondsTab);\n\n            $(secondsTab).append('<div class=\"imp secondList\"><input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"0\">00<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"1\">01<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"2\">02<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"3\">03<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"4\">04<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"5\">05<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"6\">06<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"7\">07<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"8\">08<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"9\">09</div>');\n            $(secondsTab).append('<div class=\"imp secondList\"><input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"10\">10<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"11\">11<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"12\">12<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"13\">13<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"14\">14<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"15\">15<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"16\">16<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"17\">17<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"18\">18<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"19\">19</div>');\n            $(secondsTab).append('<div class=\"imp secondList\"><input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"20\">20<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"21\">21<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"22\">22<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"23\">23<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"24\">24<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"25\">25<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"26\">26<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"27\">27<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"28\">28<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"29\">29</div>');\n            $(secondsTab).append('<div class=\"imp secondList\"><input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"30\">30<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"31\">31<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"32\">32<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"33\">33<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"34\">34<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"35\">35<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"36\">36<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"37\">37<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"38\">38<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"39\">39</div>');\n            $(secondsTab).append('<div class=\"imp secondList\"><input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"40\">40<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"41\">41<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"42\">42<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"43\">43<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"44\">44<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"45\">45<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"46\">46<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"47\">47<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"48\">48<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"49\">49</div>');\n            $(secondsTab).append('<div class=\"imp secondList\"><input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"50\">50<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"51\">51<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"52\">52<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"53\">53<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"54\">54<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"55\">55<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"56\">56<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"57\">57<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"58\">58<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"59\">59</div>');\n            $(\"<input/>\",{type : \"hidden\", id : \"secondHidden\"}).appendTo(secondsTab);\n            $(secondsTab).appendTo(tabContent);\n\n            //creating the minutesTab\n            var minutesTab = $(\"<div/>\", { \"class\": \"tab-pane\", id: \"Minutes\" });\n\n            var minutes1 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"1\", name : \"min\"}).appendTo(minutes1);\n            $(minutes1).append(\"每分钟 允许的通配符[, - * /]\");\n            $(minutes1).appendTo(minutesTab);\n\n            var minutes2 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"2\", name : \"min\"}).appendTo(minutes2);\n            $(minutes2).append(\"周期 从\");\n            $(\"<input/>\",{type : \"text\", id : \"minStart_0\", value : \"1\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(minutes2);\n            $(minutes2).append(\"-\");\n            $(\"<input/>\",{type : \"text\", id : \"minEnd_0\", value : \"2\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(minutes2);\n            $(minutes2).append(\"分钟\");\n            $(minutes2).appendTo(minutesTab);\n\n            var minutes3 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"3\", name : \"min\"}).appendTo(minutes3);\n            $(minutes3).append(\"从\");\n            $(\"<input/>\",{type : \"text\", id : \"minStart_1\", value : \"0\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(minutes3);\n            $(minutes3).append(\"分钟开始,每\");\n            $(\"<input/>\",{type : \"text\", id : \"minEnd_1\", value : \"1\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(minutes3);\n            $(minutes3).append(\"分钟执行一次\");\n            $(minutes3).appendTo(minutesTab);\n\n            var minutes4 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"4\", name : \"min\", id: \"min_appoint\"}).appendTo(minutes4);\n            $(minutes4).append(\"指定\");\n            $(minutes4).appendTo(minutesTab);\n\n            $(minutesTab).append('<div class=\"imp minList\"><input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"0\">00<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"1\">01<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"2\">02<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"3\">03<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"4\">04<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"5\">05<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"6\">06<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"7\">07<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"8\">08<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"9\">09</div>');\n            $(minutesTab).append('<div class=\"imp minList\"><input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"10\">10<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"11\">11<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"12\">12<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"13\">13<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"14\">14<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"15\">15<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"16\">16<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"17\">17<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"18\">18<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"19\">19</div>');\n            $(minutesTab).append('<div class=\"imp minList\"><input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"20\">20<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"21\">21<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"22\">22<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"23\">23<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"24\">24<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"25\">25<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"26\">26<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"27\">27<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"28\">28<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"29\">29</div>');\n            $(minutesTab).append('<div class=\"imp minList\"><input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"30\">30<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"31\">31<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"32\">32<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"33\">33<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"34\">34<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"35\">35<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"36\">36<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"37\">37<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"38\">38<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"39\">39</div>');\n            $(minutesTab).append('<div class=\"imp minList\"><input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"40\">40<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"41\">41<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"42\">42<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"43\">43<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"44\">44<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"45\">45<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"46\">46<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"47\">47<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"48\">48<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"49\">49</div>');\n            $(minutesTab).append('<div class=\"imp minList\"><input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"50\">50<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"51\">51<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"52\">52<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"53\">53<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"54\">54<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"55\">55<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"56\">56<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"57\">57<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"58\">58<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"59\">59</div>');\n            $(\"<input/>\",{type : \"hidden\", id : \"minHidden\"}).appendTo(minutesTab);\n            $(minutesTab).appendTo(tabContent);\n\n            //creating the hourlyTab\n            var hourlyTab = $(\"<div/>\", { \"class\": \"tab-pane\", id: \"Hourly\" });\n\n            var hourly1 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"1\", name : \"hour\"}).appendTo(hourly1);\n            $(hourly1).append(\"每小时 允许的通配符[, - * /]\");\n            $(hourly1).appendTo(hourlyTab);\n\n            var hourly2 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"2\", name : \"hour\"}).appendTo(hourly2);\n            $(hourly2).append(\"周期 从\");\n            $(\"<input/>\",{type : \"text\", id : \"hourStart_0\", value : \"1\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(hourly2);\n            $(hourly2).append(\"-\");\n            $(\"<input/>\",{type : \"text\", id : \"hourEnd_0\", value : \"2\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(hourly2);\n            $(hourly2).append(\"小时\");\n            $(hourly2).appendTo(hourlyTab);\n\n            var hourly3 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"3\", name : \"hour\"}).appendTo(hourly3);\n            $(hourly3).append(\"从\");\n            $(\"<input/>\",{type : \"text\", id : \"hourStart_1\", value : \"0\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(hourly3);\n            $(hourly3).append(\"小时开始,每\");\n            $(\"<input/>\",{type : \"text\", id : \"hourEnd_1\", value : \"1\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(hourly3);\n            $(hourly3).append(\"小时执行一次\");\n            $(hourly3).appendTo(hourlyTab);\n\n            var hourly4 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"4\", name : \"hour\", id: \"hour_appoint\"}).appendTo(hourly4);\n            $(hourly4).append(\"指定\");\n            $(hourly4).appendTo(hourlyTab);\n\n            $(hourlyTab).append('<div class=\"imp hourList\"><input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"0\">00<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"1\">01<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"2\">02<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"3\">03<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"4\">04<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"5\">05</div>');\n            $(hourlyTab).append('<div class=\"imp hourList\"><input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"6\">06<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"7\">07<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"8\">08<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"9\">09<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"10\">10<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"11\">11</div>');\n            $(hourlyTab).append('<div class=\"imp hourList\"><input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"12\">12<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"13\">13<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"14\">14<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"15\">15<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"16\">16<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"17\">17</div>');\n            $(hourlyTab).append('<div class=\"imp hourList\"><input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"18\">18<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"19\">19<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"20\">20<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"21\">21<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"22\">22<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"23\">23</div>');\n            $(\"<input/>\",{type : \"hidden\", id : \"hourHidden\"}).appendTo(hourlyTab);\n            $(hourlyTab).appendTo(tabContent);\n\n\n            //creating the dailyTab\n            var dailyTab = $(\"<div/>\", { \"class\": \"tab-pane\", id: \"Daily\" });\n\n            var daily1 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"1\", name : \"day\"}).appendTo(daily1);\n            $(daily1).append(\"每天 允许的通配符[, - * / L W]\");\n            $(daily1).appendTo(dailyTab);\n\n            var daily5 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"2\", name : \"day\"}).appendTo(daily5);\n            $(daily5).append(\"不指定\");\n            $(daily5).appendTo(dailyTab);\n\n            var daily2 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"3\", name : \"day\"}).appendTo(daily2);\n            $(daily2).append(\"周期 从\");\n            $(\"<input/>\",{type : \"text\", id : \"dayStart_0\", value : \"1\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(daily2);\n            $(daily2).append(\"-\");\n            $(\"<input/>\",{type : \"text\", id : \"dayEnd_0\", value : \"2\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(daily2);\n            $(daily2).append(\"日\");\n            $(daily2).appendTo(dailyTab);\n\n            var daily3 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"4\", name : \"day\"}).appendTo(daily3);\n            $(daily3).append(\"从\");\n            $(\"<input/>\",{type : \"text\", id : \"dayStart_1\", value : \"1\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(daily3);\n            $(daily3).append(\"日开始,每\");\n            $(\"<input/>\",{type : \"text\", id : \"dayEnd_1\", value : \"1\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(daily3);\n            $(daily3).append(\"天执行一次\");\n            $(daily3).appendTo(dailyTab);\n\n            var daily6 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"5\", name : \"day\"}).appendTo(daily6);\n            $(daily6).append(\"每月\");\n            $(\"<input/>\",{type : \"text\", id : \"dayStart_2\", value : \"1\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(daily6);\n            $(daily6).append(\"号最近的那个工作日\");\n            $(daily6).appendTo(dailyTab);\n\n            var daily7 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"6\", name : \"day\"}).appendTo(daily7);\n            $(daily7).append(\"本月最后一天\");\n            $(daily7).appendTo(dailyTab);\n\n            var daily4 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"7\", name : \"day\", id: \"day_appoint\"}).appendTo(daily4);\n            $(daily4).append(\"指定\");\n            $(daily4).appendTo(dailyTab);\n\n            $(dailyTab).append('<div class=\"imp dayList\"><input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"1\">01<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"2\">02<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"3\">03<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"4\">04<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"5\">05<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"6\">06<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"7\">07<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"8\">08<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"9\">09<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"10\">10</div>');\n            $(dailyTab).append('<div class=\"imp dayList\"><input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"11\">11<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"12\">12<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"13\">13<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"14\">14<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"15\">15<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"16\">16<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"17\">17<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"18\">18<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"19\">19<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"20\">20</div>');\n            $(dailyTab).append('<div class=\"imp dayList\"><input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"21\">21<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"22\">22<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"23\">23<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"24\">24<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"25\">25<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"26\">26<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"27\">27<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"28\">28<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"29\">29<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"30\">30</div>');\n            $(dailyTab).append('<div class=\"imp dayList\"><input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"31\">31</div>');\n            $(\"<input/>\",{type : \"hidden\", id : \"dayHidden\"}).appendTo(dailyTab);\n            $(dailyTab).appendTo(tabContent);\n\n\n            //creating the monthlyTab\n            var monthlyTab = $(\"<div/>\", { \"class\": \"tab-pane\", id: \"Monthly\" });\n\n            var monthly1 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"1\", name : \"month\"}).appendTo(monthly1);\n            $(monthly1).append(\"每月 允许的通配符[, - * /]\");\n            $(monthly1).appendTo(monthlyTab);\n\n            var monthly2 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"2\", name : \"month\"}).appendTo(monthly2);\n            $(monthly2).append(\"不指定\");\n            $(monthly2).appendTo(monthlyTab);\n\n            var monthly3 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"3\", name : \"month\"}).appendTo(monthly3);\n            $(monthly3).append(\"周期 从\");\n            $(\"<input/>\",{type : \"text\", id : \"monthStart_0\", value : \"1\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(monthly3);\n            $(monthly3).append(\"-\");\n            $(\"<input/>\",{type : \"text\", id : \"monthEnd_0\", value : \"2\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(monthly3);\n            $(monthly3).append(\"月\");\n            $(monthly3).appendTo(monthlyTab);\n\n            var monthly4 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"4\", name : \"month\"}).appendTo(monthly4);\n            $(monthly4).append(\"从\");\n            $(\"<input/>\",{type : \"text\", id : \"monthStart_1\", value : \"1\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(monthly4);\n            $(monthly4).append(\"月开始,每\");\n            $(\"<input/>\",{type : \"text\", id : \"monthEnd_1\", value : \"1\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(monthly4);\n            $(monthly4).append(\"月执行一次\");\n            $(monthly4).appendTo(monthlyTab);\n\n            var monthly5 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"5\", name : \"month\", id: \"month_appoint\"}).appendTo(monthly5);\n            $(monthly5).append(\"指定\");\n            $(monthly5).appendTo(monthlyTab);\n\n            $(monthlyTab).append('<div class=\"imp monthList\"><input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"1\">01<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"2\">02<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"3\">03<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"4\">04<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"5\">05<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"6\">06</div>');\n            $(monthlyTab).append('<div class=\"imp monthList\"><input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"7\">07<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"8\">08<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"9\">09<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"10\">10<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"11\">11<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"12\">12</div>');\n            $(\"<input/>\",{type : \"hidden\", id : \"monthHidden\"}).appendTo(monthlyTab);\n            $(monthlyTab).appendTo(tabContent);\n\n            //creating the weeklyTab\n            var weeklyTab = $(\"<div/>\", { \"class\": \"tab-pane\", id: \"Weekly\" });\n\n            var weekly1 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"1\", name : \"week\"}).appendTo(weekly1);\n            $(weekly1).append(\"每周 允许的通配符[, - * / L #]\");\n            $(weekly1).appendTo(weeklyTab);\n\n            var weekly2 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"2\", name : \"week\"}).appendTo(weekly2);\n            $(weekly2).append(\"不指定\");\n            $(weekly2).appendTo(weeklyTab);\n\n            var weekly3 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"3\", name : \"week\"}).appendTo(weekly3);\n            $(weekly3).append(\"周期 每周第\");\n            $(\"<input/>\",{type : \"text\", id : \"weekStart_0\", value : \"1\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(weekly3);\n            $(weekly3).append(\"天-第\");\n            $(\"<input/>\",{type : \"text\", id : \"weekEnd_0\", value : \"2\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(weekly3);\n            $(weekly3).append(\"天\");\n            $(weekly3).appendTo(weeklyTab);\n\n            var weekly4 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"4\", name : \"week\"}).appendTo(weekly4);\n            $(weekly4).append(\"从第\");\n            $(\"<input/>\",{type : \"text\", id : \"weekStart_1\", value : \"1\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(weekly4);\n            $(weekly4).append(\"天开始，间隔\");\n            $(\"<input/>\",{type : \"text\", id : \"weekEnd_1\", value : \"1\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(weekly4);\n            $(weekly4).append(\"天执行一次\");\n            $(weekly4).appendTo(weeklyTab);\n\n            var weekly5 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"5\", name : \"week\"}).appendTo(weekly5);\n            $(weekly5).append(\"本月最后一周的第\");\n            $(\"<input/>\",{type : \"text\", id : \"weekStart_2\", value : \"1\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(weekly5);\n            $(weekly5).append(\"天\");\n            $(weekly5).appendTo(weeklyTab);\n\n            var weekly6 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"6\", name : \"week\", id: \"week_appoint\"}).appendTo(weekly6);\n            $(weekly6).append(\"指定\");\n            $(weekly6).appendTo(weeklyTab);\n\n            $(weeklyTab).append('<div class=\"imp weekList\"><input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"1\">周日<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"2\">周一<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"3\">周二<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"4\">周三<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"5\">周四<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"6\">周五<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"7\">周六</div>');\n\n            $(\"<input/>\",{type : \"hidden\", id : \"weekHidden\"}).appendTo(weeklyTab);\n            $(weeklyTab).appendTo(tabContent);\n\n            //creating the yearlyTab\n            var yearlyTab = $(\"<div/>\", { \"class\": \"tab-pane\", id: \"Yearly\" });\n\n            var yearly1 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"1\", name : \"year\"}).appendTo(yearly1);\n            $(yearly1).append(\"不指定 允许的通配符[, - * /] 非必填\");\n            $(yearly1).appendTo(yearlyTab);\n\n            var yearly3 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"2\", name : \"year\"}).appendTo(yearly3);\n            $(yearly3).append(\"每年\");\n            $(yearly3).appendTo(yearlyTab);\n\n            var yearly2 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"3\", name : \"year\"}).appendTo(yearly2);\n            $(yearly2).append(\"周期从\");\n            $(\"<input/>\",{type : \"text\", id : \"yearStart_0\", value : \"2016\", style:\"width:45px; height:20px;\"}).appendTo(yearly2);\n            $(yearly2).append(\"-\");\n            $(\"<input/>\",{type : \"text\", id : \"yearEnd_0\", value : \"2017\", style:\"width:45px; height:20px;\"}).appendTo(yearly2);\n            $(yearly2).append(\"年\");\n            $(yearly2).appendTo(yearlyTab);\n            $(\"<input/>\",{type : \"hidden\", id : \"yearHidden\"}).appendTo(yearlyTab);\n            $(yearlyTab).appendTo(tabContent);\n\n            $(tabContent).appendTo(span12);\n\n            //creating the button and results input\n            // resultsName = $(this).prop(\"id\");\n            // $(this).prop(\"name\", resultsName);\n\n            var runTime = '<br style=\"padding-top: 10px\"><label>最近运行时间: </label></br><textarea id=\"runTime\" rows=\"6\" style=\"width: 90%;resize: none;background: none;border: none;outline: none;\" readonly = readonly></textarea></div>';\n\n            $(span12).appendTo(row);\n            $(row).appendTo(container);\n            $(container).appendTo(mainDiv);\n            $(runTime).appendTo(mainDiv);\n            $(cronContainer).append(mainDiv);\n\n            var that = $(this);\n\n            // Hide the original input\n            that.hide();\n\n            // Replace the input with an input group\n            var $g = $(\"<div>\").addClass(\"input-group\");\n            // Add an input\n            var $i = $(\"<input>\", { type: 'text', placeholder: 'cron表达式...', name: 'cronGen_display' }).addClass(\"form-control\").val($(that).val());\n            $i.appendTo($g);\n            // Add the button\n            var $b = $(\"<button class=\\\"btn btn-default\\\"><i class=\\\"fa fa-edit\\\"></i></button>\");\n            // Put button inside span\n            var $s = $(\"<span>\").addClass(\"input-group-btn\");\n            $b.appendTo($s);\n            $s.appendTo($g);\n\n            $(this).before($g);\n\n            inputElement = that;\n            displayElement = $i;\n\n            $b.popover({\n                html: true,\n                content: function () {\n                    return $(cronContainer).html();\n                },\n                template: '<div class=\"popover\" style=\"max-width:500px !important; width:425px;left:-341.656px;\"><div class=\"arrow\"></div><div class=\"popover-inner\"><h3 class=\"popover-title\"></h3><div class=\"popover-content\"><p></p></div></div></div>',\n                sanitize:false,\n                placement: options.direction\n\n            }).on('click', function (e) {\n                if (inputElement.val().trim() !== '') {\n                    refreshRunTime();\n                }\n                e.preventDefault();\n\n                //fillDataOfMinutesAndHoursSelectOptions();\n                //fillDayWeekInMonth();\n                //fillInWeekDays();\n                //fillInMonths();\n\n                $.fn.cronGen.tools.cronParse(inputElement.val());\n\n                //绑定指定事件\n                $.fn.cronGen.tools.initChangeEvent();\n\n\n                $('#CronGenTabs a').click(function (e) {\n                    e.preventDefault();\n                    $(this).tab('show');\n                    //generate();\n                });\n                $(\"#CronGenMainDiv select,input\").change(function (e) {\n                    generate();\n                    refreshRunTime();\n                });\n                $(\"#CronGenMainDiv input\").focus(function (e) {\n                    generate();\n                });\n                //generate();\n            });\n            return;\n        }\n    });\n\n\n    var fillInMonths = function () {\n        var days = [\n            { text: \"一月\", val: \"1\" },\n            { text: \"二月\", val: \"2\" },\n            { text: \"三月\", val: \"3\" },\n            { text: \"四月\", val: \"4\" },\n            { text: \"五月\", val: \"5\" },\n            { text: \"六月\", val: \"6\" },\n            { text: \"七月\", val: \"7\" },\n            { text: \"八月\", val: \"8\" },\n            { text: \"九月\", val: \"9\" },\n            { text: \"十月\", val: \"10\" },\n            { text: \"十一月\", val: \"11\" },\n            { text: \"十二月\", val: \"12\" }\n        ];\n        $(\".months\").each(function () {\n            fillOptions(this, days);\n        });\n    };\n\n    var fillOptions = function (elements, options) {\n        for (var i = 0; i < options.length; i++)\n            $(elements).append(\"<option value='\" + options[i].val + \"'>\" + options[i].text + \"</option>\");\n    };\n    var fillDataOfMinutesAndHoursSelectOptions = function () {\n        for (var i = 0; i < 60; i++) {\n            if (i < 24) {\n                $(\".hours\").each(function () { $(this).append(timeSelectOption(i)); });\n            }\n            $(\".minutes\").each(function () { $(this).append(timeSelectOption(i)); });\n        }\n    };\n    var fillInWeekDays = function () {\n        var days = [\n            { text: \"周一\", val: \"2\" },\n            { text: \"周二\", val: \"3\" },\n            { text: \"周三\", val: \"4\" },\n            { text: \"周四\", val: \"5\" },\n            { text: \"周五\", val: \"6\" },\n            { text: \"周六\", val: \"7\" },\n            { text: \"周天\", val: \"1\" }\n        ];\n        $(\".week-days\").each(function () {\n            fillOptions(this, days);\n        });\n\n    };\n    var fillDayWeekInMonth = function () {\n        var days = [\n            { text: \"第一个\", val: \"1\" },\n            { text: \"第二个\", val: \"2\" },\n            { text: \"第三个\", val: \"3\" },\n            { text: \"第四个\", val: \"4\" }\n        ];\n        $(\".day-order-in-month\").each(function () {\n            fillOptions(this, days);\n        });\n    };\n    var displayTimeUnit = function (unit) {\n        if (unit.toString().length == 1)\n            return \"0\" + unit;\n        return unit;\n    };\n    var timeSelectOption = function (i) {\n        return \"<option id='\" + i + \"'>\" + displayTimeUnit(i) + \"</option>\";\n    };\n\n    var generate = function () {\n\n        var activeTab = $(\"ul#CronGenTabs li.active a\").prop(\"id\");\n        if (activeTab == undefined) {\n            return;\n        }\n        var results = \"\";\n        switch (activeTab) {\n            case \"SecondlyTab\":\n                switch ($(\"input:radio[name=second]:checked\").val()) {\n                    case \"1\":\n                        $.fn.cronGen.tools.everyTime(\"second\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"2\":\n                        $.fn.cronGen.tools.cycle(\"second\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"3\":\n                        $.fn.cronGen.tools.startOn(\"second\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"4\":\n                    \t$.fn.cronGen.tools.initCheckBox(\"second\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                }\n                break;\n            case \"MinutesTab\":\n                switch ($(\"input:radio[name=min]:checked\").val()) {\n                    case \"1\":\n                        $.fn.cronGen.tools.everyTime(\"min\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"2\":\n                        $.fn.cronGen.tools.cycle(\"min\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"3\":\n                        $.fn.cronGen.tools.startOn(\"min\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"4\":\n                    \t$.fn.cronGen.tools.initCheckBox(\"min\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                }\n                break;\n            case \"HourlyTab\":\n                switch ($(\"input:radio[name=hour]:checked\").val()) {\n                    case \"1\":\n                       $.fn.cronGen.tools.everyTime(\"hour\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"2\":\n                       $.fn.cronGen.tools.cycle(\"hour\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"3\":\n                        $.fn.cronGen.tools.startOn(\"hour\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"4\":\n                    \t$.fn.cronGen.tools.initCheckBox(\"hour\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                }\n                break;\n            case \"DailyTab\":\n                switch ($(\"input:radio[name=day]:checked\").val()) {\n                    case \"1\":\n                        $.fn.cronGen.tools.everyTime(\"day\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"2\":\n                        $.fn.cronGen.tools.unAppoint(\"day\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"3\":\n                        $.fn.cronGen.tools.cycle(\"day\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"4\":\n                        $.fn.cronGen.tools.startOn(\"day\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"5\":\n                        $.fn.cronGen.tools.workDay(\"day\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"6\":\n                        $.fn.cronGen.tools.lastDay(\"day\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"7\":\n                    \t$.fn.cronGen.tools.initCheckBox(\"day\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                }\n                break;\n            case \"WeeklyTab\":\n                switch ($(\"input:radio[name=week]:checked\").val()) {\n                    case \"1\":\n                        $.fn.cronGen.tools.everyTime(\"week\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"2\":\n                        $.fn.cronGen.tools.unAppoint(\"week\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"3\":\n                        $.fn.cronGen.tools.cycle(\"week\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"4\":\n                        $.fn.cronGen.tools.startOn(\"week\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"5\":\n                        $.fn.cronGen.tools.lastWeek(\"week\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"6\":\n                    \t$.fn.cronGen.tools.initCheckBox(\"week\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                }\n                break;\n            case \"MonthlyTab\":\n                switch ($(\"input:radio[name=month]:checked\").val()) {\n                    case \"1\":\n                        $.fn.cronGen.tools.everyTime(\"month\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"2\":\n                        $.fn.cronGen.tools.unAppoint(\"month\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"3\":\n                        $.fn.cronGen.tools.cycle(\"month\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"4\":\n                        $.fn.cronGen.tools.startOn(\"month\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"5\":\n                    \t$.fn.cronGen.tools.initCheckBox(\"month\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                }\n                break;\n            case \"YearlyTab\":\n                switch ($(\"input:radio[name=year]:checked\").val()) {\n                    case \"1\":\n                        $.fn.cronGen.tools.unAppoint(\"year\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"2\":\n                        $.fn.cronGen.tools.everyTime(\"year\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"3\":\n                        $.fn.cronGen.tools.cycle(\"year\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                }\n                break;\n        }\n\n        // Update original control\n        inputElement.val(results);\n        // Update display\n        displayElement.val(results);\n    };\n\n    var refreshRunTime = function () {\n        $.ajax({\n            type : 'GET',\n            url : base_url + \"/jobinfo/nextTriggerTime\",\n            data : {\n                \"scheduleType\" : 'CRON',\n                \"scheduleConf\" : inputElement.val()\n            },\n            dataType : \"json\",\n            success : function(data){\n                if (data.code === 200) {\n                    $('#runTime').val(data.data.join(\"\\n\"));\n                } else {\n                    $('#runTime').val(data.msg);\n                }\n            }\n        });\n    };\n\n})(jQuery);\n\n(function($) {\n    $.fn.cronGen.defaultOptions = {\n        direction : 'bottom'\n    };\n    $.fn.cronGen.tools = {\n        /**\n         * 每周期\n         */\n        everyTime : function(dom){\n            $(\"#\"+dom+\"Hidden\").val(\"*\");\n            $.fn.cronGen.tools.clearCheckbox(dom);\n        },\n        /**\n         * 不指定\n         */\n        unAppoint : function(dom){\n            var val = \"?\";\n            if (dom == \"year\")\n            {\n                val = \"\";\n            }\n            $(\"#\"+dom+\"Hidden\").val(val);\n            $.fn.cronGen.tools.clearCheckbox(dom);\n        },\n        /**\n         * 周期\n         */\n        cycle : function(dom){\n            var start = $(\"#\"+dom+\"Start_0\").val();\n            var end = $(\"#\"+dom+\"End_0\").val();\n            $(\"#\"+dom+\"Hidden\").val(start + \"-\" + end);\n            $.fn.cronGen.tools.clearCheckbox(dom);\n        },\n        /**\n         * 从开始\n         */\n        startOn : function(dom) {\n            var start = $(\"#\"+dom+\"Start_1\").val();\n            var end = $(\"#\"+dom+\"End_1\").val();\n            $(\"#\"+dom+\"Hidden\").val(start + \"/\" + end);\n            $.fn.cronGen.tools.clearCheckbox(dom);\n        },\n        /**\n         * 最后一天\n         */\n        lastDay : function(dom){\n            $(\"#\"+dom+\"Hidden\").val(\"L\");\n            $.fn.cronGen.tools.clearCheckbox(dom);\n        },\n        /**\n         * 每周的某一天\n         */\n        weekOfDay : function(dom){\n            var start = $(\"#\"+dom+\"Start_0\").val();\n            var end = $(\"#\"+dom+\"End_0\").val();\n            $(\"#\"+dom+\"Hidden\").val(start + \"#\" + end);\n            $.fn.cronGen.tools.clearCheckbox(dom);\n        },\n        /**\n         * 最后一周\n         */\n        lastWeek : function(dom){\n            var start = $(\"#\"+dom+\"Start_2\").val();\n            $(\"#\"+dom+\"Hidden\").val(start+\"L\");\n            $.fn.cronGen.tools.clearCheckbox(dom);\n        },\n        /**\n         * 工作日\n         */\n        workDay : function(dom) {\n            var start = $(\"#\"+dom+\"Start_2\").val();\n            $(\"#\"+dom+\"Hidden\").val(start + \"W\");\n            $.fn.cronGen.tools.clearCheckbox(dom);\n        },\n        initChangeEvent : function(){\n            var secondList = $(\".secondList\").children();\n            $(\"#sencond_appoint\").click(function(){\n                if (this.checked) {\n                    if ($(secondList).filter(\":checked\").length == 0) {\n                        $(secondList.eq(0)).attr(\"checked\", true);\n                    }\n                    secondList.eq(0).change();\n                }\n            });\n\n            secondList.change(function() {\n                var sencond_appoint = $(\"#sencond_appoint\").prop(\"checked\");\n                if (sencond_appoint) {\n                    var vals = [];\n                    secondList.each(function() {\n                        if (this.checked) {\n                            vals.push(this.value);\n                        }\n                    });\n                    var val = \"?\";\n                    if (vals.length > 0 && vals.length < 59) {\n                        val = vals.join(\",\");\n                    }else if(vals.length == 59){\n                        val = \"*\";\n                    }\n                    $(\"#secondHidden\").val(val);\n                }\n            });\n\n            var minList = $(\".minList\").children();\n            $(\"#min_appoint\").click(function(){\n                if (this.checked) {\n                    if ($(minList).filter(\":checked\").length == 0) {\n                        $(minList.eq(0)).attr(\"checked\", true);\n                    }\n                    minList.eq(0).change();\n                }\n            });\n\n            minList.change(function() {\n                var min_appoint = $(\"#min_appoint\").prop(\"checked\");\n                if (min_appoint) {\n                    var vals = [];\n                    minList.each(function() {\n                        if (this.checked) {\n                            vals.push(this.value);\n                        }\n                    });\n                    var val = \"?\";\n                    if (vals.length > 0 && vals.length < 59) {\n                        val = vals.join(\",\");\n                    }else if(vals.length == 59){\n                        val = \"*\";\n                    }\n                    $(\"#minHidden\").val(val);\n                }\n            });\n\n            var hourList = $(\".hourList\").children();\n            $(\"#hour_appoint\").click(function(){\n                if (this.checked) {\n                    if ($(hourList).filter(\":checked\").length == 0) {\n                        $(hourList.eq(0)).attr(\"checked\", true);\n                    }\n                    hourList.eq(0).change();\n                }\n            });\n\n            hourList.change(function() {\n                var hour_appoint = $(\"#hour_appoint\").prop(\"checked\");\n                if (hour_appoint) {\n                    var vals = [];\n                    hourList.each(function() {\n                        if (this.checked) {\n                            vals.push(this.value);\n                        }\n                    });\n                    var val = \"?\";\n                    if (vals.length > 0 && vals.length < 24) {\n                        val = vals.join(\",\");\n                    }else if(vals.length == 24){\n                        val = \"*\";\n                    }\n                    $(\"#hourHidden\").val(val);\n                }\n            });\n\n            var dayList = $(\".dayList\").children();\n            $(\"#day_appoint\").click(function(){\n                if (this.checked) {\n                    if ($(dayList).filter(\":checked\").length == 0) {\n                        $(dayList.eq(0)).attr(\"checked\", true);\n                    }\n                    dayList.eq(0).change();\n                }\n            });\n\n            dayList.change(function() {\n                var day_appoint = $(\"#day_appoint\").prop(\"checked\");\n                if (day_appoint) {\n                    var vals = [];\n                    dayList.each(function() {\n                        if (this.checked) {\n                            vals.push(this.value);\n                        }\n                    });\n                    var val = \"?\";\n                    if (vals.length > 0 && vals.length < 31) {\n                        val = vals.join(\",\");\n                    }else if(vals.length == 31){\n                        val = \"*\";\n                    }\n                   $(\"#dayHidden\").val(val);\n                }\n            });\n\n            var monthList = $(\".monthList\").children();\n            $(\"#month_appoint\").click(function(){\n                if (this.checked) {\n                    if ($(monthList).filter(\":checked\").length == 0) {\n                        $(monthList.eq(0)).attr(\"checked\", true);\n                    }\n                    monthList.eq(0).change();\n                }\n            });\n\n            monthList.change(function() {\n                var month_appoint = $(\"#month_appoint\").prop(\"checked\");\n                if (month_appoint) {\n                    var vals = [];\n                    monthList.each(function() {\n                        if (this.checked) {\n                            vals.push(this.value);\n                        }\n                    });\n                    var val = \"?\";\n                    if (vals.length > 0 && vals.length < 12) {\n                        val = vals.join(\",\");\n                    }else if(vals.length == 12){\n                        val = \"*\";\n                    }\n                    $(\"#monthHidden\").val(val);\n                }\n            });\n\n            var weekList = $(\".weekList\").children();\n            $(\"#week_appoint\").click(function(){\n                if (this.checked) {\n                    if ($(weekList).filter(\":checked\").length == 0) {\n                        $(weekList.eq(0)).attr(\"checked\", true);\n                    }\n                    weekList.eq(0).change();\n                }\n            });\n\n            weekList.change(function() {\n                var week_appoint = $(\"#week_appoint\").prop(\"checked\");\n                if (week_appoint) {\n                    var vals = [];\n                    weekList.each(function() {\n                        if (this.checked) {\n                            vals.push(this.value);\n                        }\n                    });\n                    var val = \"?\";\n                    if (vals.length > 0 && vals.length < 7) {\n                        val = vals.join(\",\");\n                    }else if(vals.length == 7){\n                        val = \"*\";\n                    }\n                   $(\"#weekHidden\").val(val);\n                }\n            });\n        },\n        initObj : function(strVal, strid){\n            var ary = null;\n            var objRadio = $(\"input[name='\" + strid + \"'\");\n            if (strVal == \"*\") {\n                objRadio.eq(0).attr(\"checked\", \"checked\");\n            } else if (strVal.split('-').length > 1) {\n                ary = strVal.split('-');\n                objRadio.eq(1).attr(\"checked\", \"checked\");\n                $(\"#\" + strid + \"Start_0\").val(ary[0]);\n                $(\"#\" + strid + \"End_0\").val(ary[1]);\n            } else if (strVal.split('/').length > 1) {\n                ary = strVal.split('/');\n                objRadio.eq(2).attr(\"checked\", \"checked\");\n                $(\"#\" + strid + \"Start_1\").val(ary[0]);\n                $(\"#\" + strid + \"End_1\").val(ary[1]);\n            } else {\n                objRadio.eq(3).attr(\"checked\", \"checked\");\n                if (strVal != \"?\") {\n                    ary = strVal.split(\",\");\n                    for (var i = 0; i < ary.length; i++) {\n                        $(\".\" + strid + \"List input[value='\" + ary[i] + \"']\").attr(\"checked\", \"checked\");\n                    }\n                    $.fn.cronGen.tools.initCheckBox(strid);\n                }\n            }\n        },\n        initDay : function(strVal) {\n            var ary = null;\n            var objRadio = $(\"input[name='day'\");\n            if (strVal == \"*\") {\n                objRadio.eq(0).attr(\"checked\", \"checked\");\n            } else if (strVal == \"?\") {\n                objRadio.eq(1).attr(\"checked\", \"checked\");\n            } else if (strVal.split('-').length > 1) {\n                ary = strVal.split('-');\n                objRadio.eq(2).attr(\"checked\", \"checked\");\n                $(\"#dayStart_0\").val(ary[0]);\n                $(\"#dayEnd_0\").val(ary[1]);\n            } else if (strVal.split('/').length > 1) {\n                ary = strVal.split('/');\n                objRadio.eq(3).attr(\"checked\", \"checked\");\n                $(\"#dayStart_1\").val(ary[0]);\n                $(\"#dayEnd_1\").val(ary[1]);\n            } else if (strVal.split('W').length > 1) {\n                ary = strVal.split('W');\n                objRadio.eq(4).attr(\"checked\", \"checked\");\n                $(\"#dayStart_2\").val(ary[0]);\n            } else if (strVal == \"L\") {\n                objRadio.eq(5).attr(\"checked\", \"checked\");\n            } else {\n                objRadio.eq(6).attr(\"checked\", \"checked\");\n                ary = strVal.split(\",\");\n                for (var i = 0; i < ary.length; i++) {\n                    $(\".dayList input[value='\" + ary[i] + \"']\").attr(\"checked\", \"checked\");\n                }\n                $.fn.cronGen.tools.initCheckBox(\"day\");\n            }\n        },\n        initMonth : function(strVal) {\n            var ary = null;\n            var objRadio = $(\"input[name='month'\");\n            if (strVal == \"*\") {\n                objRadio.eq(0).attr(\"checked\", \"checked\");\n            } else if (strVal == \"?\") {\n                objRadio.eq(1).attr(\"checked\", \"checked\");\n            } else if (strVal.split('-').length > 1) {\n                ary = strVal.split('-');\n                objRadio.eq(2).attr(\"checked\", \"checked\");\n                $(\"#monthStart_0\").val(ary[0]);\n                $(\"#monthEnd_0\").val(ary[1]);\n            } else if (strVal.split('/').length > 1) {\n                ary = strVal.split('/');\n                objRadio.eq(3).attr(\"checked\", \"checked\");\n                $(\"#monthStart_1\").val(ary[0]);\n                $(\"#monthEnd_1\").val(ary[1]);\n\n            } else {\n                objRadio.eq(4).attr(\"checked\", \"checked\");\n\n                ary = strVal.split(\",\");\n                for (var i = 0; i < ary.length; i++) {\n                    $(\".monthList input[value='\" + ary[i] + \"']\").attr(\"checked\", \"checked\");\n                }\n                $.fn.cronGen.tools.initCheckBox(\"month\");\n            }\n        },\n        initWeek : function(strVal) {\n            var ary = null;\n            var objRadio = $(\"input[name='week'\");\n            if (strVal == \"*\") {\n                objRadio.eq(0).attr(\"checked\", \"checked\");\n            } else if (strVal == \"?\") {\n                objRadio.eq(1).attr(\"checked\", \"checked\");\n            } else if (strVal.split('/').length > 1) {\n                ary = strVal.split('/');\n                objRadio.eq(2).attr(\"checked\", \"checked\");\n                $(\"#weekStart_0\").val(ary[0]);\n                $(\"#weekEnd_0\").val(ary[1]);\n            } else if (strVal.split('-').length > 1) {\n                ary = strVal.split('-');\n                objRadio.eq(3).attr(\"checked\", \"checked\");\n                $(\"#weekStart_1\").val(ary[0]);\n                $(\"#weekEnd_1\").val(ary[1]);\n            } else if (strVal.split('L').length > 1) {\n                ary = strVal.split('L');\n                objRadio.eq(4).attr(\"checked\", \"checked\");\n                $(\"#weekStart_2\").val(ary[0]);\n            } else {\n                objRadio.eq(5).attr(\"checked\", \"checked\");\n                ary = strVal.split(\",\");\n                for (var i = 0; i < ary.length; i++) {\n                    $(\".weekList input[value='\" + ary[i] + \"']\").attr(\"checked\", \"checked\");\n                }\n                $.fn.cronGen.tools.initCheckBox(\"week\");\n            }\n        },\n        initYear : function(strVal) {\n            var ary = null;\n            var objRadio = $(\"input[name='year'\");\n            if (strVal == \"*\") {\n                objRadio.eq(1).attr(\"checked\", \"checked\");\n            } else if (strVal.split('-').length > 1) {\n                ary = strVal.split('-');\n                objRadio.eq(2).attr(\"checked\", \"checked\");\n                $(\"#yearStart_0\").val(ary[0]);\n                $(\"#yearEnd_0\").val(ary[1]);\n            }\n        },\n        cronParse : function(cronExpress) {\n            //获取参数中表达式的值\n            if (cronExpress) {\n                var regs = cronExpress.split(' ');\n                $(\"#secondHidden\").val(regs[0]);\n                $(\"#minHidden\").val(regs[1]);\n                $(\"#hourHidden\").val(regs[2]);\n                $(\"#dayHidden\").val(regs[3]);\n                $(\"#monthHidden\").val(regs[4]);\n                $(\"#weekHidden\").val(regs[5]);\n\n                $.fn.cronGen.tools.initObj(regs[0], \"second\");\n                $.fn.cronGen.tools.initObj(regs[1], \"min\");\n                $.fn.cronGen.tools.initObj(regs[2], \"hour\");\n                $.fn.cronGen.tools.initDay(regs[3]);\n                $.fn.cronGen.tools.initMonth(regs[4]);\n                $.fn.cronGen.tools.initWeek(regs[5]);\n\n                if (regs.length > 6) {\n                    $(\"input[name=yearHidden]\").val(regs[6]);\n                    $.fn.cronGen.tools.initYear(regs[6]);\n                }\n            }\n    \t},\n        cronResult : function() {\n            var result;\n            var second = $(\"#secondHidden\").val();\n            second = second== \"\" ? \"*\":second;\n            var minute = $(\"#minHidden\").val();\n            minute = minute== \"\" ? \"*\":minute;\n            var hour = $(\"#hourHidden\").val();\n            hour = hour== \"\" ? \"*\":hour;\n            var day = $(\"#dayHidden\").val();\n            day = day== \"\" ? \"*\":day;\n            var month = $(\"#monthHidden\").val();\n            month = month== \"\" ? \"*\":month;\n            var week = $(\"#weekHidden\").val();\n            week = week== \"\" ? \"?\":week;\n            var year = $(\"#yearHidden\").val();\n            if(year!=\"\")\n            {\n                result = second+\" \"+minute+\" \"+hour+\" \"+day+\" \"+month+\" \"+week+\" \"+year;\n            }else\n            {\n                result = second+\" \"+minute+\" \"+hour+\" \"+day+\" \"+month+\" \"+week;\n            }\n            return result;\n        },\n        clearCheckbox : function(dom){\n        \t//清除选中的checkbox\n            var list = $(\".\"+dom+\"List\").children().filter(\":checked\");\n            if ($(list).length > 0) {\n            \t$.each(list, function(index){\n            \t\t$(this).attr(\"checked\", false);\n            \t\t$(this).attr(\"disabled\", \"disabled\");\n            \t\t$(this).change();\n            \t});\n            }\n        },\n        initCheckBox : function(dom) {\n        \t//移除checkbox禁用\n            var list = $(\".\"+dom+\"List\").children();\n            if ($(list).length > 0) {\n            \t$.each(list, function(index){\n            \t\t$(this).removeAttr(\"disabled\");\n            \t});\n            }\n        }\n    };\n})(jQuery);\n"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/plugins/cronGen/cronGen_en.js",
    "content": "﻿(function ($) {\n    // var resultsName = \"\";\n    var inputElement;\n    var displayElement;\n    $.fn.extend({\n        cronGen: function (options) {\n            if (options == null) {\n              options = {};\n            }\n            options = $.extend({}, $.fn.cronGen.defaultOptions, options);\n            //create top menu\n            var cronContainer = $(\"<div/>\", { id: \"CronContainer\", style: \"display:none;width:300px;height:300px;\" });\n            var mainDiv = $(\"<div/>\", { id: \"CronGenMainDiv\", style: \"width:410px;height:420px;\" });\n            var topMenu = $(\"<ul/>\", { \"class\": \"nav nav-tabs\", id: \"CronGenTabs\" });\n            $('<li/>', { 'class': 'active' }).html($('<a id=\"SecondlyTab\" href=\"#Secondly\">秒</a>')).appendTo(topMenu);\n            $('<li/>').html($('<a id=\"MinutesTab\" href=\"#Minutes\">Minute</a>')).appendTo(topMenu);\n            $('<li/>').html($('<a id=\"HourlyTab\" href=\"#Hourly\">Hour</a>')).appendTo(topMenu);\n            $('<li/>').html($('<a id=\"DailyTab\" href=\"#Daily\">Day</a>')).appendTo(topMenu);\n            $('<li/>').html($('<a id=\"MonthlyTab\" href=\"#Monthly\">Month</a>')).appendTo(topMenu);\n            $('<li/>').html($('<a id=\"WeeklyTab\" href=\"#Weekly\">Week</a>')).appendTo(topMenu);\n            $('<li/>').html($('<a id=\"YearlyTab\" href=\"#Yearly\">Year</a>')).appendTo(topMenu);\n            $(topMenu).appendTo(mainDiv);\n\n            //create what's inside the tabs\n            var container = $(\"<div/>\", { \"class\": \"container-fluid\", \"style\": \"margin-top: 30px;margin-left: -14px;\" });\n            var row = $(\"<div/>\", { \"class\": \"row-fluid\" });\n            var span12 = $(\"<div/>\", { \"class\": \"span12\" });\n            var tabContent = $(\"<div/>\", { \"class\": \"tab-content\", \"style\": \"border:0px; margin-top:-20px;\" });\n\n\n            //creating the secondsTab\n            var secondsTab = $(\"<div/>\", { \"class\": \"tab-pane active\", id: \"Secondly\" });\n            var seconds1 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"1\", name : \"second\"}).appendTo(seconds1);\n            $(seconds1).append(\"Per second, allowed wildcard[, - * /]\");\n            $(seconds1).appendTo(secondsTab);\n\n            var seconds2 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"2\", name : \"second\"}).appendTo(seconds2);\n            $(seconds2).append(\"Cycle, from\");\n            $(\"<input/>\",{type : \"text\", id : \"secondStart_0\", value : \"1\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(seconds2);\n            $(seconds2).append(\"-\");\n            $(\"<input/>\",{type : \"text\", id : \"secondEnd_0\", value : \"2\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(seconds2);\n            $(seconds2).append(\"second\");\n            $(seconds2).appendTo(secondsTab);\n\n            var seconds3 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"3\", name : \"second\"}).appendTo(seconds3);\n            $(seconds3).append(\"from\");\n            $(\"<input/>\",{type : \"text\", id : \"secondStart_1\", value : \"0\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(seconds3);\n            $(seconds3).append(\"seconds start, per\");\n            $(\"<input/>\",{type : \"text\", id : \"secondEnd_1\", value : \"1\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(seconds3);\n            $(seconds3).append(\"second execute once\");\n            $(seconds3).appendTo(secondsTab);\n\n            var seconds4 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"4\", name : \"second\", id: \"sencond_appoint\"}).appendTo(seconds4);\n            $(seconds4).append(\"specify\");\n            $(seconds4).appendTo(secondsTab);\n\n            $(secondsTab).append('<div class=\"imp secondList\"><input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"0\">00<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"1\">01<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"2\">02<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"3\">03<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"4\">04<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"5\">05<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"6\">06<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"7\">07<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"8\">08<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"9\">09</div>');\n            $(secondsTab).append('<div class=\"imp secondList\"><input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"10\">10<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"11\">11<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"12\">12<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"13\">13<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"14\">14<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"15\">15<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"16\">16<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"17\">17<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"18\">18<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"19\">19</div>');\n            $(secondsTab).append('<div class=\"imp secondList\"><input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"20\">20<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"21\">21<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"22\">22<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"23\">23<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"24\">24<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"25\">25<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"26\">26<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"27\">27<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"28\">28<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"29\">29</div>');\n            $(secondsTab).append('<div class=\"imp secondList\"><input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"30\">30<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"31\">31<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"32\">32<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"33\">33<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"34\">34<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"35\">35<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"36\">36<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"37\">37<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"38\">38<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"39\">39</div>');\n            $(secondsTab).append('<div class=\"imp secondList\"><input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"40\">40<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"41\">41<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"42\">42<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"43\">43<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"44\">44<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"45\">45<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"46\">46<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"47\">47<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"48\">48<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"49\">49</div>');\n            $(secondsTab).append('<div class=\"imp secondList\"><input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"50\">50<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"51\">51<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"52\">52<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"53\">53<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"54\">54<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"55\">55<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"56\">56<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"57\">57<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"58\">58<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"59\">59</div>');\n            $(\"<input/>\",{type : \"hidden\", id : \"secondHidden\"}).appendTo(secondsTab);\n            $(secondsTab).appendTo(tabContent);\n\n            //creating the minutesTab\n            var minutesTab = $(\"<div/>\", { \"class\": \"tab-pane\", id: \"Minutes\" });\n\n            var minutes1 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"1\", name : \"min\"}).appendTo(minutes1);\n            $(minutes1).append(\"Per minute, allowed wildcard[, - * /]\");\n            $(minutes1).appendTo(minutesTab);\n\n            var minutes2 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"2\", name : \"min\"}).appendTo(minutes2);\n            $(minutes2).append(\"Cycle, from\");\n            $(\"<input/>\",{type : \"text\", id : \"minStart_0\", value : \"1\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(minutes2);\n            $(minutes2).append(\"-\");\n            $(\"<input/>\",{type : \"text\", id : \"minEnd_0\", value : \"2\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(minutes2);\n            $(minutes2).append(\"minute\");\n            $(minutes2).appendTo(minutesTab);\n\n            var minutes3 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"3\", name : \"min\"}).appendTo(minutes3);\n            $(minutes3).append(\"from\");\n            $(\"<input/>\",{type : \"text\", id : \"minStart_1\", value : \"0\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(minutes3);\n            $(minutes3).append(\"seconds start, per\");\n            $(\"<input/>\",{type : \"text\", id : \"minEnd_1\", value : \"1\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(minutes3);\n            $(minutes3).append(\"second execute once\");\n            $(minutes3).appendTo(minutesTab);\n\n            var minutes4 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"4\", name : \"min\", id: \"min_appoint\"}).appendTo(minutes4);\n            $(minutes4).append(\"specify\");\n            $(minutes4).appendTo(minutesTab);\n\n            $(minutesTab).append('<div class=\"imp minList\"><input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"0\">00<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"1\">01<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"2\">02<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"3\">03<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"4\">04<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"5\">05<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"6\">06<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"7\">07<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"8\">08<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"9\">09</div>');\n            $(minutesTab).append('<div class=\"imp minList\"><input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"10\">10<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"11\">11<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"12\">12<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"13\">13<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"14\">14<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"15\">15<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"16\">16<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"17\">17<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"18\">18<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"19\">19</div>');\n            $(minutesTab).append('<div class=\"imp minList\"><input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"20\">20<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"21\">21<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"22\">22<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"23\">23<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"24\">24<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"25\">25<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"26\">26<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"27\">27<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"28\">28<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"29\">29</div>');\n            $(minutesTab).append('<div class=\"imp minList\"><input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"30\">30<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"31\">31<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"32\">32<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"33\">33<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"34\">34<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"35\">35<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"36\">36<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"37\">37<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"38\">38<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"39\">39</div>');\n            $(minutesTab).append('<div class=\"imp minList\"><input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"40\">40<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"41\">41<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"42\">42<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"43\">43<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"44\">44<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"45\">45<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"46\">46<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"47\">47<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"48\">48<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"49\">49</div>');\n            $(minutesTab).append('<div class=\"imp minList\"><input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"50\">50<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"51\">51<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"52\">52<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"53\">53<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"54\">54<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"55\">55<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"56\">56<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"57\">57<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"58\">58<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"59\">59</div>');\n            $(\"<input/>\",{type : \"hidden\", id : \"minHidden\"}).appendTo(minutesTab);\n            $(minutesTab).appendTo(tabContent);\n\n            //creating the hourlyTab\n            var hourlyTab = $(\"<div/>\", { \"class\": \"tab-pane\", id: \"Hourly\" });\n\n            var hourly1 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"1\", name : \"hour\"}).appendTo(hourly1);\n            $(hourly1).append(\"Per hour, allowed wildcard[, - * /]\");\n            $(hourly1).appendTo(hourlyTab);\n\n            var hourly2 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"2\", name : \"hour\"}).appendTo(hourly2);\n            $(hourly2).append(\"Cycle, from\");\n            $(\"<input/>\",{type : \"text\", id : \"hourStart_0\", value : \"1\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(hourly2);\n            $(hourly2).append(\"-\");\n            $(\"<input/>\",{type : \"text\", id : \"hourEnd_0\", value : \"2\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(hourly2);\n            $(hourly2).append(\"hour\");\n            $(hourly2).appendTo(hourlyTab);\n\n            var hourly3 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"3\", name : \"hour\"}).appendTo(hourly3);\n            $(hourly3).append(\"from\");\n            $(\"<input/>\",{type : \"text\", id : \"hourStart_1\", value : \"0\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(hourly3);\n            $(hourly3).append(\"hour start, per\");\n            $(\"<input/>\",{type : \"text\", id : \"hourEnd_1\", value : \"1\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(hourly3);\n            $(hourly3).append(\"hour execute once\");\n            $(hourly3).appendTo(hourlyTab);\n\n            var hourly4 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"4\", name : \"hour\", id: \"hour_appoint\"}).appendTo(hourly4);\n            $(hourly4).append(\"specify\");\n            $(hourly4).appendTo(hourlyTab);\n\n            $(hourlyTab).append('<div class=\"imp hourList\"><input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"0\">00<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"1\">01<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"2\">02<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"3\">03<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"4\">04<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"5\">05</div>');\n            $(hourlyTab).append('<div class=\"imp hourList\"><input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"6\">06<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"7\">07<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"8\">08<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"9\">09<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"10\">10<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"11\">11</div>');\n            $(hourlyTab).append('<div class=\"imp hourList\"><input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"12\">12<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"13\">13<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"14\">14<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"15\">15<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"16\">16<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"17\">17</div>');\n            $(hourlyTab).append('<div class=\"imp hourList\"><input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"18\">18<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"19\">19<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"20\">20<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"21\">21<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"22\">22<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"23\">23</div>');\n            $(\"<input/>\",{type : \"hidden\", id : \"hourHidden\"}).appendTo(hourlyTab);\n            $(hourlyTab).appendTo(tabContent);\n\n\n            //creating the dailyTab\n            var dailyTab = $(\"<div/>\", { \"class\": \"tab-pane\", id: \"Daily\" });\n\n            var daily1 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"1\", name : \"day\"}).appendTo(daily1);\n            $(daily1).append(\"Per day, allowed wildcard[, - * / L W]\");\n            $(daily1).appendTo(dailyTab);\n\n            var daily5 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"2\", name : \"day\"}).appendTo(daily5);\n            $(daily5).append(\"not specify\");\n            $(daily5).appendTo(dailyTab);\n\n            var daily2 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"3\", name : \"day\"}).appendTo(daily2);\n            $(daily2).append(\"Cycle, from\");\n            $(\"<input/>\",{type : \"text\", id : \"dayStart_0\", value : \"1\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(daily2);\n            $(daily2).append(\"-\");\n            $(\"<input/>\",{type : \"text\", id : \"dayEnd_0\", value : \"2\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(daily2);\n            $(daily2).append(\"day\");\n            $(daily2).appendTo(dailyTab);\n\n            var daily3 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"4\", name : \"day\"}).appendTo(daily3);\n            $(daily3).append(\"from\");\n            $(\"<input/>\",{type : \"text\", id : \"dayStart_1\", value : \"1\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(daily3);\n            $(daily3).append(\"day start, per\");\n            $(\"<input/>\",{type : \"text\", id : \"dayEnd_1\", value : \"1\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(daily3);\n            $(daily3).append(\"day execute once\");\n            $(daily3).appendTo(dailyTab);\n\n            var daily6 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"5\", name : \"day\"}).appendTo(daily6);\n            $(daily6).append(\"The most recent working day on the 1\");\n            $(\"<input/>\",{type : \"text\", id : \"dayStart_2\", value : \"1\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(daily6);\n            $(daily6).append(\" of each month\");\n            $(daily6).appendTo(dailyTab);\n\n            var daily7 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"6\", name : \"day\"}).appendTo(daily7);\n            $(daily7).append(\"The last day of the month\");\n            $(daily7).appendTo(dailyTab);\n\n            var daily4 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"7\", name : \"day\", id: \"day_appoint\"}).appendTo(daily4);\n            $(daily4).append(\"specify\");\n            $(daily4).appendTo(dailyTab);\n\n            $(dailyTab).append('<div class=\"imp dayList\"><input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"1\">01<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"2\">02<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"3\">03<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"4\">04<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"5\">05<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"6\">06<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"7\">07<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"8\">08<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"9\">09<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"10\">10</div>');\n            $(dailyTab).append('<div class=\"imp dayList\"><input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"11\">11<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"12\">12<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"13\">13<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"14\">14<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"15\">15<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"16\">16<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"17\">17<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"18\">18<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"19\">19<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"20\">20</div>');\n            $(dailyTab).append('<div class=\"imp dayList\"><input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"21\">21<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"22\">22<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"23\">23<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"24\">24<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"25\">25<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"26\">26<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"27\">27<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"28\">28<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"29\">29<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"30\">30</div>');\n            $(dailyTab).append('<div class=\"imp dayList\"><input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"31\">31</div>');\n            $(\"<input/>\",{type : \"hidden\", id : \"dayHidden\"}).appendTo(dailyTab);\n            $(dailyTab).appendTo(tabContent);\n\n\n            //creating the monthlyTab\n            var monthlyTab = $(\"<div/>\", { \"class\": \"tab-pane\", id: \"Monthly\" });\n\n            var monthly1 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"1\", name : \"month\"}).appendTo(monthly1);\n            $(monthly1).append(\"Per month, allowed wildcard[, - * /]\");\n            $(monthly1).appendTo(monthlyTab);\n\n            var monthly2 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"2\", name : \"month\"}).appendTo(monthly2);\n            $(monthly2).append(\"not specify\");\n            $(monthly2).appendTo(monthlyTab);\n\n            var monthly3 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"3\", name : \"month\"}).appendTo(monthly3);\n            $(monthly3).append(\"Cycle, from\");\n            $(\"<input/>\",{type : \"text\", id : \"monthStart_0\", value : \"1\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(monthly3);\n            $(monthly3).append(\"-\");\n            $(\"<input/>\",{type : \"text\", id : \"monthEnd_0\", value : \"2\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(monthly3);\n            $(monthly3).append(\"month\");\n            $(monthly3).appendTo(monthlyTab);\n\n            var monthly4 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"4\", name : \"month\"}).appendTo(monthly4);\n            $(monthly4).append(\"Starting from \");\n            $(\"<input/>\",{type : \"text\", id : \"monthStart_1\", value : \"1\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(monthly4);\n            $(monthly4).append(\"day, once every\");\n            $(\"<input/>\",{type : \"text\", id : \"monthEnd_1\", value : \"1\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(monthly4);\n            $(monthly4).append(\"month\");\n            $(monthly4).appendTo(monthlyTab);\n\n            var monthly5 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"5\", name : \"month\", id: \"month_appoint\"}).appendTo(monthly5);\n            $(monthly5).append(\"specify\");\n            $(monthly5).appendTo(monthlyTab);\n\n            $(monthlyTab).append('<div class=\"imp monthList\"><input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"1\">01<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"2\">02<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"3\">03<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"4\">04<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"5\">05<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"6\">06</div>');\n            $(monthlyTab).append('<div class=\"imp monthList\"><input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"7\">07<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"8\">08<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"9\">09<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"10\">10<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"11\">11<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"12\">12</div>');\n            $(\"<input/>\",{type : \"hidden\", id : \"monthHidden\"}).appendTo(monthlyTab);\n            $(monthlyTab).appendTo(tabContent);\n\n            //creating the weeklyTab\n            var weeklyTab = $(\"<div/>\", { \"class\": \"tab-pane\", id: \"Weekly\" });\n\n            var weekly1 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"1\", name : \"week\"}).appendTo(weekly1);\n            $(weekly1).append(\"Per week, allowed wildcard[, - * / L #]\");\n            $(weekly1).appendTo(weeklyTab);\n\n            var weekly2 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"2\", name : \"week\"}).appendTo(weekly2);\n            $(weekly2).append(\"not specify\");\n            $(weekly2).appendTo(weeklyTab);\n\n            var weekly3 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"3\", name : \"week\"}).appendTo(weekly3);\n            $(weekly3).append(\"Cycle, from week\");\n            $(\"<input/>\",{type : \"text\", id : \"weekStart_0\", value : \"1\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(weekly3);\n            $(weekly3).append(\"-\");\n            $(\"<input/>\",{type : \"text\", id : \"weekEnd_0\", value : \"2\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(weekly3);\n            $(weekly3).appendTo(weeklyTab);\n\n            var weekly4 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"4\", name : \"week\"}).appendTo(weekly4);\n            $(weekly4).append(\"The\");\n            $(\"<input/>\",{type : \"text\", id : \"weekStart_1\", value : \"1\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(weekly4);\n            $(weekly4).append(\"th week, once every \");\n            $(\"<input/>\",{type : \"text\", id : \"weekEnd_1\", value : \"1\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(weekly4);\n            $(weekly4).appendTo(weeklyTab);\n\n            var weekly5 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"5\", name : \"week\"}).appendTo(weekly5);\n            $(weekly5).append(\"Last week of the month\");\n            $(\"<input/>\",{type : \"text\", id : \"weekStart_2\", value : \"1\", style:\"width:35px; height:20px; text-align: center; margin: 0 3px;\"}).appendTo(weekly5);\n            $(weekly5).appendTo(weeklyTab);\n\n            var weekly6 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"6\", name : \"week\", id: \"week_appoint\"}).appendTo(weekly6);\n            $(weekly6).append(\"specify\");\n            $(weekly6).appendTo(weeklyTab);\n\n            $(weeklyTab).append('<div class=\"imp weekList\"><input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"1\">SUN<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"2\">MON<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"3\">TUE<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"4\">WED<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"5\">THU<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"6\">FRI<input type=\"checkbox\" disabled=\"disabled\" style=\"margin-left: 5px\"  value=\"7\">SAT</div>');\n\n            $(\"<input/>\",{type : \"hidden\", id : \"weekHidden\"}).appendTo(weeklyTab);\n            $(weeklyTab).appendTo(tabContent);\n\n            //creating the yearlyTab\n            var yearlyTab = $(\"<div/>\", { \"class\": \"tab-pane\", id: \"Yearly\" });\n\n            var yearly1 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"1\", name : \"year\"}).appendTo(yearly1);\n            $(yearly1).append(\"not specify allowed wildcard[, - * /] not required\");\n            $(yearly1).appendTo(yearlyTab);\n\n            var yearly3 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"2\", name : \"year\"}).appendTo(yearly3);\n            $(yearly3).append(\"Per year\");\n            $(yearly3).appendTo(yearlyTab);\n\n            var yearly2 = $(\"<div/>\",{\"class\":\"line\"});\n            $(\"<input/>\",{type : \"radio\", value : \"3\", name : \"year\"}).appendTo(yearly2);\n            $(yearly2).append(\"Cycle, from \");\n            $(\"<input/>\",{type : \"text\", id : \"yearStart_0\", value : \"2016\", style:\"width:45px; height:20px;\"}).appendTo(yearly2);\n            $(yearly2).append(\"-\");\n            $(\"<input/>\",{type : \"text\", id : \"yearEnd_0\", value : \"2017\", style:\"width:45px; height:20px;\"}).appendTo(yearly2);\n            $(yearly2).append(\"year\");\n            $(yearly2).appendTo(yearlyTab);\n            $(\"<input/>\",{type : \"hidden\", id : \"yearHidden\"}).appendTo(yearlyTab);\n            $(yearlyTab).appendTo(tabContent);\n\n            $(tabContent).appendTo(span12);\n\n            //creating the button and results input\n            // resultsName = $(this).prop(\"id\");\n            // $(this).prop(\"name\", resultsName);\n\n            var runTime = '<br style=\"padding-top: 10px\"><label>Recent Run Time: </label></br><textarea id=\"runTime\" rows=\"6\" style=\"width: 90%;resize: none;background: none;border: none;outline: none;\" readonly = readonly></textarea></div>';\n\n            $(span12).appendTo(row);\n            $(row).appendTo(container);\n            $(container).appendTo(mainDiv);\n            $(runTime).appendTo(mainDiv);\n            $(cronContainer).append(mainDiv);\n\n            var that = $(this);\n\n            // Hide the original input\n            that.hide();\n\n            // Replace the input with an input group\n            var $g = $(\"<div>\").addClass(\"input-group\");\n            // Add an input\n            var $i = $(\"<input>\", { type: 'text', placeholder: 'cron expression...', name: 'cronGen_display' }).addClass(\"form-control\").val($(that).val());\n            $i.appendTo($g);\n            // Add the button\n            var $b = $(\"<button class=\\\"btn btn-default\\\"><i class=\\\"fa fa-edit\\\"></i></button>\");\n            // Put button inside span\n            var $s = $(\"<span>\").addClass(\"input-group-btn\");\n            $b.appendTo($s);\n            $s.appendTo($g);\n\n            $(this).before($g);\n\n            inputElement = that;\n            displayElement = $i;\n\n            $b.popover({\n                html: true,\n                content: function () {\n                    return $(cronContainer).html();\n                },\n                template: '<div class=\"popover\" style=\"max-width:500px !important; width:425px;left:-341.656px;\"><div class=\"arrow\"></div><div class=\"popover-inner\"><h3 class=\"popover-title\"></h3><div class=\"popover-content\"><p></p></div></div></div>',\n                sanitize:false,\n                placement: options.direction\n\n            }).on('click', function (e) {\n                if (inputElement.val().trim() !== '') {\n                    refreshRunTime();\n                }\n                e.preventDefault();\n\n                //fillDataOfMinutesAndHoursSelectOptions();\n                //fillDayWeekInMonth();\n                //fillInWeekDays();\n                //fillInMonths();\n\n                $.fn.cronGen.tools.cronParse(inputElement.val());\n\n                //绑定指定事件\n                $.fn.cronGen.tools.initChangeEvent();\n\n\n                $('#CronGenTabs a').click(function (e) {\n                    e.preventDefault();\n                    $(this).tab('show');\n                    //generate();\n                });\n                $(\"#CronGenMainDiv select,input\").change(function (e) {\n                    generate();\n                    refreshRunTime();\n                });\n                $(\"#CronGenMainDiv input\").focus(function (e) {\n                    generate();\n                });\n                //generate();\n            });\n            return;\n        }\n    });\n\n\n    var fillInMonths = function () {\n        var days = [\n            { text: \"January\", val: \"1\" },\n            { text: \"February\", val: \"2\" },\n            { text: \"March\", val: \"3\" },\n            { text: \"April\", val: \"4\" },\n            { text: \"May\", val: \"5\" },\n            { text: \"June\", val: \"6\" },\n            { text: \"July\", val: \"7\" },\n            { text: \"August\", val: \"8\" },\n            { text: \"September\", val: \"9\" },\n            { text: \"October\", val: \"10\" },\n            { text: \"November\", val: \"11\" },\n            { text: \"December\", val: \"12\" }\n        ];\n        $(\".months\").each(function () {\n            fillOptions(this, days);\n        });\n    };\n\n    var fillOptions = function (elements, options) {\n        for (var i = 0; i < options.length; i++)\n            $(elements).append(\"<option value='\" + options[i].val + \"'>\" + options[i].text + \"</option>\");\n    };\n    var fillDataOfMinutesAndHoursSelectOptions = function () {\n        for (var i = 0; i < 60; i++) {\n            if (i < 24) {\n                $(\".hours\").each(function () { $(this).append(timeSelectOption(i)); });\n            }\n            $(\".minutes\").each(function () { $(this).append(timeSelectOption(i)); });\n        }\n    };\n    var fillInWeekDays = function () {\n        var days = [\n            { text: \"Tuesday\", val: \"2\" },\n            { text: \"Wednesday\", val: \"3\" },\n            { text: \"Thursday\", val: \"4\" },\n            { text: \"Friday\", val: \"5\" },\n            { text: \"Saturday\", val: \"6\" },\n            { text: \"Sunday\", val: \"7\" },\n            { text: \"Monday\", val: \"1\" }\n        ];\n        $(\".week-days\").each(function () {\n            fillOptions(this, days);\n        });\n\n    };\n    var fillDayWeekInMonth = function () {\n        var days = [\n            { text: \"First\", val: \"1\" },\n            { text: \"Second\", val: \"2\" },\n            { text: \"Third\", val: \"3\" },\n            { text: \"Fourth\", val: \"4\" }\n        ];\n        $(\".day-order-in-month\").each(function () {\n            fillOptions(this, days);\n        });\n    };\n    var displayTimeUnit = function (unit) {\n        if (unit.toString().length == 1)\n            return \"0\" + unit;\n        return unit;\n    };\n    var timeSelectOption = function (i) {\n        return \"<option id='\" + i + \"'>\" + displayTimeUnit(i) + \"</option>\";\n    };\n\n    var generate = function () {\n\n        var activeTab = $(\"ul#CronGenTabs li.active a\").prop(\"id\");\n        if (activeTab == undefined) {\n            return;\n        }\n        var results = \"\";\n        switch (activeTab) {\n            case \"SecondlyTab\":\n                switch ($(\"input:radio[name=second]:checked\").val()) {\n                    case \"1\":\n                        $.fn.cronGen.tools.everyTime(\"second\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"2\":\n                        $.fn.cronGen.tools.cycle(\"second\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"3\":\n                        $.fn.cronGen.tools.startOn(\"second\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"4\":\n                    \t$.fn.cronGen.tools.initCheckBox(\"second\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                }\n                break;\n            case \"MinutesTab\":\n                switch ($(\"input:radio[name=min]:checked\").val()) {\n                    case \"1\":\n                        $.fn.cronGen.tools.everyTime(\"min\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"2\":\n                        $.fn.cronGen.tools.cycle(\"min\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"3\":\n                        $.fn.cronGen.tools.startOn(\"min\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"4\":\n                    \t$.fn.cronGen.tools.initCheckBox(\"min\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                }\n                break;\n            case \"HourlyTab\":\n                switch ($(\"input:radio[name=hour]:checked\").val()) {\n                    case \"1\":\n                       $.fn.cronGen.tools.everyTime(\"hour\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"2\":\n                       $.fn.cronGen.tools.cycle(\"hour\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"3\":\n                        $.fn.cronGen.tools.startOn(\"hour\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"4\":\n                    \t$.fn.cronGen.tools.initCheckBox(\"hour\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                }\n                break;\n            case \"DailyTab\":\n                switch ($(\"input:radio[name=day]:checked\").val()) {\n                    case \"1\":\n                        $.fn.cronGen.tools.everyTime(\"day\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"2\":\n                        $.fn.cronGen.tools.unAppoint(\"day\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"3\":\n                        $.fn.cronGen.tools.cycle(\"day\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"4\":\n                        $.fn.cronGen.tools.startOn(\"day\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"5\":\n                        $.fn.cronGen.tools.workDay(\"day\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"6\":\n                        $.fn.cronGen.tools.lastDay(\"day\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"7\":\n                    \t$.fn.cronGen.tools.initCheckBox(\"day\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                }\n                break;\n            case \"WeeklyTab\":\n                switch ($(\"input:radio[name=week]:checked\").val()) {\n                    case \"1\":\n                        $.fn.cronGen.tools.everyTime(\"week\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"2\":\n                        $.fn.cronGen.tools.unAppoint(\"week\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"3\":\n                        $.fn.cronGen.tools.cycle(\"week\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"4\":\n                        $.fn.cronGen.tools.startOn(\"week\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"5\":\n                        $.fn.cronGen.tools.lastWeek(\"week\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"6\":\n                    \t$.fn.cronGen.tools.initCheckBox(\"week\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                }\n                break;\n            case \"MonthlyTab\":\n                switch ($(\"input:radio[name=month]:checked\").val()) {\n                    case \"1\":\n                        $.fn.cronGen.tools.everyTime(\"month\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"2\":\n                        $.fn.cronGen.tools.unAppoint(\"month\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"3\":\n                        $.fn.cronGen.tools.cycle(\"month\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"4\":\n                        $.fn.cronGen.tools.startOn(\"month\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"5\":\n                    \t$.fn.cronGen.tools.initCheckBox(\"month\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                }\n                break;\n            case \"YearlyTab\":\n                switch ($(\"input:radio[name=year]:checked\").val()) {\n                    case \"1\":\n                        $.fn.cronGen.tools.unAppoint(\"year\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"2\":\n                        $.fn.cronGen.tools.everyTime(\"year\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                    case \"3\":\n                        $.fn.cronGen.tools.cycle(\"year\");\n                        results = $.fn.cronGen.tools.cronResult();\n                        break;\n                }\n                break;\n        }\n\n        // Update original control\n        inputElement.val(results);\n        // Update display\n        displayElement.val(results);\n    };\n\n    var refreshRunTime = function () {\n        $.ajax({\n            type : 'GET',\n            url : base_url + \"/jobinfo/nextTriggerTime\",\n            data : {\n                \"scheduleType\" : 'CRON',\n                \"scheduleConf\" : inputElement.val()\n            },\n            dataType : \"json\",\n            success : function(data){\n                if (data.code === 200) {\n                    $('#runTime').val(data.data.join(\"\\n\"));\n                } else {\n                    $('#runTime').val(data.msg);\n                }\n            }\n        });\n    };\n\n})(jQuery);\n\n(function($) {\n    $.fn.cronGen.defaultOptions = {\n        direction : 'bottom'\n    };\n    $.fn.cronGen.tools = {\n        /**\n         * 每周期\n         */\n        everyTime : function(dom){\n            $(\"#\"+dom+\"Hidden\").val(\"*\");\n            $.fn.cronGen.tools.clearCheckbox(dom);\n        },\n        /**\n         * 不指定\n         */\n        unAppoint : function(dom){\n            var val = \"?\";\n            if (dom == \"year\")\n            {\n                val = \"\";\n            }\n            $(\"#\"+dom+\"Hidden\").val(val);\n            $.fn.cronGen.tools.clearCheckbox(dom);\n        },\n        /**\n         * 周期\n         */\n        cycle : function(dom){\n            var start = $(\"#\"+dom+\"Start_0\").val();\n            var end = $(\"#\"+dom+\"End_0\").val();\n            $(\"#\"+dom+\"Hidden\").val(start + \"-\" + end);\n            $.fn.cronGen.tools.clearCheckbox(dom);\n        },\n        /**\n         * 从开始\n         */\n        startOn : function(dom) {\n            var start = $(\"#\"+dom+\"Start_1\").val();\n            var end = $(\"#\"+dom+\"End_1\").val();\n            $(\"#\"+dom+\"Hidden\").val(start + \"/\" + end);\n            $.fn.cronGen.tools.clearCheckbox(dom);\n        },\n        /**\n         * 最后一天\n         */\n        lastDay : function(dom){\n            $(\"#\"+dom+\"Hidden\").val(\"L\");\n            $.fn.cronGen.tools.clearCheckbox(dom);\n        },\n        /**\n         * 每周的某一天\n         */\n        weekOfDay : function(dom){\n            var start = $(\"#\"+dom+\"Start_0\").val();\n            var end = $(\"#\"+dom+\"End_0\").val();\n            $(\"#\"+dom+\"Hidden\").val(start + \"#\" + end);\n            $.fn.cronGen.tools.clearCheckbox(dom);\n        },\n        /**\n         * 最后一周\n         */\n        lastWeek : function(dom){\n            var start = $(\"#\"+dom+\"Start_2\").val();\n            $(\"#\"+dom+\"Hidden\").val(start+\"L\");\n            $.fn.cronGen.tools.clearCheckbox(dom);\n        },\n        /**\n         * 工作日\n         */\n        workDay : function(dom) {\n            var start = $(\"#\"+dom+\"Start_2\").val();\n            $(\"#\"+dom+\"Hidden\").val(start + \"W\");\n            $.fn.cronGen.tools.clearCheckbox(dom);\n        },\n        initChangeEvent : function(){\n            var secondList = $(\".secondList\").children();\n            $(\"#sencond_appoint\").click(function(){\n                if (this.checked) {\n                    if ($(secondList).filter(\":checked\").length == 0) {\n                        $(secondList.eq(0)).attr(\"checked\", true);\n                    }\n                    secondList.eq(0).change();\n                }\n            });\n\n            secondList.change(function() {\n                var sencond_appoint = $(\"#sencond_appoint\").prop(\"checked\");\n                if (sencond_appoint) {\n                    var vals = [];\n                    secondList.each(function() {\n                        if (this.checked) {\n                            vals.push(this.value);\n                        }\n                    });\n                    var val = \"?\";\n                    if (vals.length > 0 && vals.length < 59) {\n                        val = vals.join(\",\");\n                    }else if(vals.length == 59){\n                        val = \"*\";\n                    }\n                    $(\"#secondHidden\").val(val);\n                }\n            });\n\n            var minList = $(\".minList\").children();\n            $(\"#min_appoint\").click(function(){\n                if (this.checked) {\n                    if ($(minList).filter(\":checked\").length == 0) {\n                        $(minList.eq(0)).attr(\"checked\", true);\n                    }\n                    minList.eq(0).change();\n                }\n            });\n\n            minList.change(function() {\n                var min_appoint = $(\"#min_appoint\").prop(\"checked\");\n                if (min_appoint) {\n                    var vals = [];\n                    minList.each(function() {\n                        if (this.checked) {\n                            vals.push(this.value);\n                        }\n                    });\n                    var val = \"?\";\n                    if (vals.length > 0 && vals.length < 59) {\n                        val = vals.join(\",\");\n                    }else if(vals.length == 59){\n                        val = \"*\";\n                    }\n                    $(\"#minHidden\").val(val);\n                }\n            });\n\n            var hourList = $(\".hourList\").children();\n            $(\"#hour_appoint\").click(function(){\n                if (this.checked) {\n                    if ($(hourList).filter(\":checked\").length == 0) {\n                        $(hourList.eq(0)).attr(\"checked\", true);\n                    }\n                    hourList.eq(0).change();\n                }\n            });\n\n            hourList.change(function() {\n                var hour_appoint = $(\"#hour_appoint\").prop(\"checked\");\n                if (hour_appoint) {\n                    var vals = [];\n                    hourList.each(function() {\n                        if (this.checked) {\n                            vals.push(this.value);\n                        }\n                    });\n                    var val = \"?\";\n                    if (vals.length > 0 && vals.length < 24) {\n                        val = vals.join(\",\");\n                    }else if(vals.length == 24){\n                        val = \"*\";\n                    }\n                    $(\"#hourHidden\").val(val);\n                }\n            });\n\n            var dayList = $(\".dayList\").children();\n            $(\"#day_appoint\").click(function(){\n                if (this.checked) {\n                    if ($(dayList).filter(\":checked\").length == 0) {\n                        $(dayList.eq(0)).attr(\"checked\", true);\n                    }\n                    dayList.eq(0).change();\n                }\n            });\n\n            dayList.change(function() {\n                var day_appoint = $(\"#day_appoint\").prop(\"checked\");\n                if (day_appoint) {\n                    var vals = [];\n                    dayList.each(function() {\n                        if (this.checked) {\n                            vals.push(this.value);\n                        }\n                    });\n                    var val = \"?\";\n                    if (vals.length > 0 && vals.length < 31) {\n                        val = vals.join(\",\");\n                    }else if(vals.length == 31){\n                        val = \"*\";\n                    }\n                   $(\"#dayHidden\").val(val);\n                }\n            });\n\n            var monthList = $(\".monthList\").children();\n            $(\"#month_appoint\").click(function(){\n                if (this.checked) {\n                    if ($(monthList).filter(\":checked\").length == 0) {\n                        $(monthList.eq(0)).attr(\"checked\", true);\n                    }\n                    monthList.eq(0).change();\n                }\n            });\n\n            monthList.change(function() {\n                var month_appoint = $(\"#month_appoint\").prop(\"checked\");\n                if (month_appoint) {\n                    var vals = [];\n                    monthList.each(function() {\n                        if (this.checked) {\n                            vals.push(this.value);\n                        }\n                    });\n                    var val = \"?\";\n                    if (vals.length > 0 && vals.length < 12) {\n                        val = vals.join(\",\");\n                    }else if(vals.length == 12){\n                        val = \"*\";\n                    }\n                    $(\"#monthHidden\").val(val);\n                }\n            });\n\n            var weekList = $(\".weekList\").children();\n            $(\"#week_appoint\").click(function(){\n                if (this.checked) {\n                    if ($(weekList).filter(\":checked\").length == 0) {\n                        $(weekList.eq(0)).attr(\"checked\", true);\n                    }\n                    weekList.eq(0).change();\n                }\n            });\n\n            weekList.change(function() {\n                var week_appoint = $(\"#week_appoint\").prop(\"checked\");\n                if (week_appoint) {\n                    var vals = [];\n                    weekList.each(function() {\n                        if (this.checked) {\n                            vals.push(this.value);\n                        }\n                    });\n                    var val = \"?\";\n                    if (vals.length > 0 && vals.length < 7) {\n                        val = vals.join(\",\");\n                    }else if(vals.length == 7){\n                        val = \"*\";\n                    }\n                   $(\"#weekHidden\").val(val);\n                }\n            });\n        },\n        initObj : function(strVal, strid){\n            var ary = null;\n            var objRadio = $(\"input[name='\" + strid + \"'\");\n            if (strVal == \"*\") {\n                objRadio.eq(0).attr(\"checked\", \"checked\");\n            } else if (strVal.split('-').length > 1) {\n                ary = strVal.split('-');\n                objRadio.eq(1).attr(\"checked\", \"checked\");\n                $(\"#\" + strid + \"Start_0\").val(ary[0]);\n                $(\"#\" + strid + \"End_0\").val(ary[1]);\n            } else if (strVal.split('/').length > 1) {\n                ary = strVal.split('/');\n                objRadio.eq(2).attr(\"checked\", \"checked\");\n                $(\"#\" + strid + \"Start_1\").val(ary[0]);\n                $(\"#\" + strid + \"End_1\").val(ary[1]);\n            } else {\n                objRadio.eq(3).attr(\"checked\", \"checked\");\n                if (strVal != \"?\") {\n                    ary = strVal.split(\",\");\n                    for (var i = 0; i < ary.length; i++) {\n                        $(\".\" + strid + \"List input[value='\" + ary[i] + \"']\").attr(\"checked\", \"checked\");\n                    }\n                    $.fn.cronGen.tools.initCheckBox(strid);\n                }\n            }\n        },\n        initDay : function(strVal) {\n            var ary = null;\n            var objRadio = $(\"input[name='day'\");\n            if (strVal == \"*\") {\n                objRadio.eq(0).attr(\"checked\", \"checked\");\n            } else if (strVal == \"?\") {\n                objRadio.eq(1).attr(\"checked\", \"checked\");\n            } else if (strVal.split('-').length > 1) {\n                ary = strVal.split('-');\n                objRadio.eq(2).attr(\"checked\", \"checked\");\n                $(\"#dayStart_0\").val(ary[0]);\n                $(\"#dayEnd_0\").val(ary[1]);\n            } else if (strVal.split('/').length > 1) {\n                ary = strVal.split('/');\n                objRadio.eq(3).attr(\"checked\", \"checked\");\n                $(\"#dayStart_1\").val(ary[0]);\n                $(\"#dayEnd_1\").val(ary[1]);\n            } else if (strVal.split('W').length > 1) {\n                ary = strVal.split('W');\n                objRadio.eq(4).attr(\"checked\", \"checked\");\n                $(\"#dayStart_2\").val(ary[0]);\n            } else if (strVal == \"L\") {\n                objRadio.eq(5).attr(\"checked\", \"checked\");\n            } else {\n                objRadio.eq(6).attr(\"checked\", \"checked\");\n                ary = strVal.split(\",\");\n                for (var i = 0; i < ary.length; i++) {\n                    $(\".dayList input[value='\" + ary[i] + \"']\").attr(\"checked\", \"checked\");\n                }\n                $.fn.cronGen.tools.initCheckBox(\"day\");\n            }\n        },\n        initMonth : function(strVal) {\n            var ary = null;\n            var objRadio = $(\"input[name='month'\");\n            if (strVal == \"*\") {\n                objRadio.eq(0).attr(\"checked\", \"checked\");\n            } else if (strVal == \"?\") {\n                objRadio.eq(1).attr(\"checked\", \"checked\");\n            } else if (strVal.split('-').length > 1) {\n                ary = strVal.split('-');\n                objRadio.eq(2).attr(\"checked\", \"checked\");\n                $(\"#monthStart_0\").val(ary[0]);\n                $(\"#monthEnd_0\").val(ary[1]);\n            } else if (strVal.split('/').length > 1) {\n                ary = strVal.split('/');\n                objRadio.eq(3).attr(\"checked\", \"checked\");\n                $(\"#monthStart_1\").val(ary[0]);\n                $(\"#monthEnd_1\").val(ary[1]);\n\n            } else {\n                objRadio.eq(4).attr(\"checked\", \"checked\");\n\n                ary = strVal.split(\",\");\n                for (var i = 0; i < ary.length; i++) {\n                    $(\".monthList input[value='\" + ary[i] + \"']\").attr(\"checked\", \"checked\");\n                }\n                $.fn.cronGen.tools.initCheckBox(\"month\");\n            }\n        },\n        initWeek : function(strVal) {\n            var ary = null;\n            var objRadio = $(\"input[name='week'\");\n            if (strVal == \"*\") {\n                objRadio.eq(0).attr(\"checked\", \"checked\");\n            } else if (strVal == \"?\") {\n                objRadio.eq(1).attr(\"checked\", \"checked\");\n            } else if (strVal.split('/').length > 1) {\n                ary = strVal.split('/');\n                objRadio.eq(2).attr(\"checked\", \"checked\");\n                $(\"#weekStart_0\").val(ary[0]);\n                $(\"#weekEnd_0\").val(ary[1]);\n            } else if (strVal.split('-').length > 1) {\n                ary = strVal.split('-');\n                objRadio.eq(3).attr(\"checked\", \"checked\");\n                $(\"#weekStart_1\").val(ary[0]);\n                $(\"#weekEnd_1\").val(ary[1]);\n            } else if (strVal.split('L').length > 1) {\n                ary = strVal.split('L');\n                objRadio.eq(4).attr(\"checked\", \"checked\");\n                $(\"#weekStart_2\").val(ary[0]);\n            } else {\n                objRadio.eq(5).attr(\"checked\", \"checked\");\n                ary = strVal.split(\",\");\n                for (var i = 0; i < ary.length; i++) {\n                    $(\".weekList input[value='\" + ary[i] + \"']\").attr(\"checked\", \"checked\");\n                }\n                $.fn.cronGen.tools.initCheckBox(\"week\");\n            }\n        },\n        initYear : function(strVal) {\n            var ary = null;\n            var objRadio = $(\"input[name='year'\");\n            if (strVal == \"*\") {\n                objRadio.eq(1).attr(\"checked\", \"checked\");\n            } else if (strVal.split('-').length > 1) {\n                ary = strVal.split('-');\n                objRadio.eq(2).attr(\"checked\", \"checked\");\n                $(\"#yearStart_0\").val(ary[0]);\n                $(\"#yearEnd_0\").val(ary[1]);\n            }\n        },\n        cronParse : function(cronExpress) {\n            //获取参数中表达式的值\n            if (cronExpress) {\n                var regs = cronExpress.split(' ');\n                $(\"#secondHidden\").val(regs[0]);\n                $(\"#minHidden\").val(regs[1]);\n                $(\"#hourHidden\").val(regs[2]);\n                $(\"#dayHidden\").val(regs[3]);\n                $(\"#monthHidden\").val(regs[4]);\n                $(\"#weekHidden\").val(regs[5]);\n\n                $.fn.cronGen.tools.initObj(regs[0], \"second\");\n                $.fn.cronGen.tools.initObj(regs[1], \"min\");\n                $.fn.cronGen.tools.initObj(regs[2], \"hour\");\n                $.fn.cronGen.tools.initDay(regs[3]);\n                $.fn.cronGen.tools.initMonth(regs[4]);\n                $.fn.cronGen.tools.initWeek(regs[5]);\n\n                if (regs.length > 6) {\n                    $(\"input[name=yearHidden]\").val(regs[6]);\n                    $.fn.cronGen.tools.initYear(regs[6]);\n                }\n            }\n    \t},\n        cronResult : function() {\n            var result;\n            var second = $(\"#secondHidden\").val();\n            second = second== \"\" ? \"*\":second;\n            var minute = $(\"#minHidden\").val();\n            minute = minute== \"\" ? \"*\":minute;\n            var hour = $(\"#hourHidden\").val();\n            hour = hour== \"\" ? \"*\":hour;\n            var day = $(\"#dayHidden\").val();\n            day = day== \"\" ? \"*\":day;\n            var month = $(\"#monthHidden\").val();\n            month = month== \"\" ? \"*\":month;\n            var week = $(\"#weekHidden\").val();\n            week = week== \"\" ? \"?\":week;\n            var year = $(\"#yearHidden\").val();\n            if(year!=\"\")\n            {\n                result = second+\" \"+minute+\" \"+hour+\" \"+day+\" \"+month+\" \"+week+\" \"+year;\n            }else\n            {\n                result = second+\" \"+minute+\" \"+hour+\" \"+day+\" \"+month+\" \"+week;\n            }\n            return result;\n        },\n        clearCheckbox : function(dom){\n        \t//清除选中的checkbox\n            var list = $(\".\"+dom+\"List\").children().filter(\":checked\");\n            if ($(list).length > 0) {\n            \t$.each(list, function(index){\n            \t\t$(this).attr(\"checked\", false);\n            \t\t$(this).attr(\"disabled\", \"disabled\");\n            \t\t$(this).change();\n            \t});\n            }\n        },\n        initCheckBox : function(dom) {\n        \t//移除checkbox禁用\n            var list = $(\".\"+dom+\"List\").children();\n            if ($(list).length > 0) {\n            \t$.each(list, function(index){\n            \t\t$(this).removeAttr(\"disabled\");\n            \t});\n            }\n        }\n    };\n})(jQuery);\n"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/plugins/fullscreen/jquery.fullscreen.js",
    "content": "/**\n * modify base jQuery FullScreen, support IE\n */\n(function(jQuery) {\n    \n    /**\n     * Sets or gets the fullscreen state.\n     * \n     * @param {boolean=} state\n     *            True to enable fullscreen mode, false to disable it. If not\n     *            specified then the current fullscreen state is returned.\n     * @return {boolean|Element|jQuery|null}\n     *            When querying the fullscreen state then the current fullscreen\n     *            element (or true if browser doesn't support it) is returned\n     *            when browser is currently in full screen mode. False is returned\n     *            if browser is not in full screen mode. Null is returned if \n     *            browser doesn't support fullscreen mode at all. When setting \n     *            the fullscreen state then the current jQuery selection is \n     *            returned for chaining.\n     * @this {jQuery}\n     */\n    function fullScreen(state)\n    {\n        var e, func, doc;\n        \n        // Do nothing when nothing was selected\n        if (!this.length) return this;\n        \n        // We only use the first selected element because it doesn't make sense\n        // to fullscreen multiple elements.\n        e = (/** @type {Element} */ this[0]);\n        \n        // Find the real element and the document (Depends on whether the\n        // document itself or a HTML element was selected)\n        if (e.ownerDocument)\n        {\n            doc = e.ownerDocument;\n        }\n        else\n        {\n            doc = e;\n            e = doc.documentElement;\n        }\n        \n        // When no state was specified then return the current state.\n        if (state == null)\n        {\n            // When fullscreen mode is not supported then return null\n            if (!((/** @type {?Function} */ doc[\"exitFullscreen\"])\n                || (/** @type {?Function} */ doc[\"webkitExitFullscreen\"])\n                || (/** @type {?Function} */ doc[\"webkitCancelFullScreen\"])\n                || (/** @type {?Function} */ doc[\"msExitFullscreen\"])\n                || (/** @type {?Function} */ doc[\"mozCancelFullScreen\"])))\n            {\n                return null;\n            }\n            \n            // Check fullscreen state\n            state = !!doc[\"fullscreenElement\"]\n                || !!doc[\"msFullscreenElement\"]\n                || !!doc[\"webkitIsFullScreen\"]\n                || !!doc[\"mozFullScreen\"];\n            if (!state) return state;\n            \n            // Return current fullscreen element or \"true\" if browser doesn't\n            // support this\n            return (/** @type {?Element} */ doc[\"fullscreenElement\"])\n                || (/** @type {?Element} */ doc[\"webkitFullscreenElement\"])\n                || (/** @type {?Element} */ doc[\"webkitCurrentFullScreenElement\"])\n                || (/** @type {?Element} */ doc[\"msFullscreenElement\"])\n                || (/** @type {?Element} */ doc[\"mozFullScreenElement\"])\n                || state;\n        }\n        \n        // When state was specified then enter or exit fullscreen mode.\n        if (state)\n        {\n            // Enter fullscreen\n            func = (/** @type {?Function} */ e[\"requestFullscreen\"])\n                || (/** @type {?Function} */ e[\"webkitRequestFullscreen\"])\n                || (/** @type {?Function} */ e[\"webkitRequestFullScreen\"])\n                || (/** @type {?Function} */ e[\"msRequestFullscreen\"])\n                || (/** @type {?Function} */ e[\"mozRequestFullScreen\"]);\n            if (func) \n            {\n                func.call(e);\n            }\n            return this;\n        }\n        else\n        {\n            // Exit fullscreen\n            func = (/** @type {?Function} */ doc[\"exitFullscreen\"])\n                || (/** @type {?Function} */ doc[\"webkitExitFullscreen\"])\n                || (/** @type {?Function} */ doc[\"webkitCancelFullScreen\"])\n                || (/** @type {?Function} */ doc[\"msExitFullscreen\"])\n                || (/** @type {?Function} */ doc[\"mozCancelFullScreen\"]);\n            if (func) func.call(doc);\n            return this;\n        }\n    }\n    \n    /**\n     * Toggles the fullscreen mode.\n     * \n     * @return {!jQuery}\n     *            The jQuery selection for chaining.\n     * @this {jQuery}\n     */\n    function toggleFullScreen()\n    {\n        return (/** @type {!jQuery} */ fullScreen.call(this, \n            !fullScreen.call(this)));\n    }\n    \n    /**\n     * Handles the browser-specific fullscreenchange event and triggers\n     * a jquery event for it.\n     *\n     * @param {?Event} event\n     *            The fullscreenchange event.\n     */\n    function fullScreenChangeHandler(event)\n    {\n        jQuery(document).trigger(new jQuery.Event(\"fullscreenchange\"));\n    }\n    \n    /**\n     * Handles the browser-specific fullscreenerror event and triggers\n     * a jquery event for it.\n     *\n     * @param {?Event} event\n     *            The fullscreenerror event.\n     */\n    function fullScreenErrorHandler(event)\n    {\n        jQuery(document).trigger(new jQuery.Event(\"fullscreenerror\"));\n    }\n    \n    /**\n     * Installs the fullscreenchange event handler.\n     */\n    function installFullScreenHandlers()\n    {\n        var e, change, error;\n        \n        // Determine event name\n        e = document;\n        if (e[\"webkitCancelFullScreen\"])\n        {\n            change = \"webkitfullscreenchange\";\n            error = \"webkitfullscreenerror\";\n        }\n        else if (e[\"msExitFullscreen\"])\n        {\n            change = \"MSFullscreenChange\";\n            error = \"MSFullscreenError\";\n        }\n        else if (e[\"mozCancelFullScreen\"])\n        {\n            change = \"mozfullscreenchange\";\n            error = \"mozfullscreenerror\";\n        }\n        else \n        {\n            change = \"fullscreenchange\";\n            error = \"fullscreenerror\";\n        }\n    \n        // Install the event handlers\n        jQuery(document).bind(change, fullScreenChangeHandler);\n        jQuery(document).bind(error, fullScreenErrorHandler);\n    }\n    \n    jQuery.fn[\"fullScreen\"] = fullScreen;\n    jQuery.fn[\"toggleFullScreen\"] = toggleFullScreen;\n    installFullScreenHandlers();\n    \n    })(jQuery);\n    "
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/plugins/jquery-treegrid/jquery.treegrid.css",
    "content": ".treegrid-indent {width:16px; height: 16px; display: inline-block; position: relative;}\n\n.treegrid-expander {width:16px; height: 16px; display: inline-block; position: relative; cursor: pointer;}\n\n.treegrid-expander-expanded{background-image: url(./img/collapse.png); }\n.treegrid-expander-collapsed{background-image: url(./img/expand.png);}\n"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/plugins/layer/layer.js",
    "content": "/*! layer-v3.1.1 Web弹层组件 MIT License  http://layer.layui.com/  By 贤心 */\n ;!function(e,t){\"use strict\";var i,n,a=e.layui&&layui.define,o={getPath:function(){var e=document.currentScript?document.currentScript.src:function(){for(var e,t=document.scripts,i=t.length-1,n=i;n>0;n--)if(\"interactive\"===t[n].readyState){e=t[n].src;break}return e||t[i].src}();return e.substring(0,e.lastIndexOf(\"/\")+1)}(),config:{},end:{},minIndex:0,minLeft:[],btn:[\"&#x786E;&#x5B9A;\",\"&#x53D6;&#x6D88;\"],type:[\"dialog\",\"page\",\"iframe\",\"loading\",\"tips\"],getStyle:function(t,i){var n=t.currentStyle?t.currentStyle:e.getComputedStyle(t,null);return n[n.getPropertyValue?\"getPropertyValue\":\"getAttribute\"](i)},link:function(t,i,n){if(r.path){var a=document.getElementsByTagName(\"head\")[0],s=document.createElement(\"link\");\"string\"==typeof i&&(n=i);var l=(n||t).replace(/\\.|\\//g,\"\"),f=\"layuicss-\"+l,c=0;s.rel=\"stylesheet\",s.href=r.path+t,s.id=f,document.getElementById(f)||a.appendChild(s),\"function\"==typeof i&&!function u(){return++c>80?e.console&&console.error(\"layer.css: Invalid\"):void(1989===parseInt(o.getStyle(document.getElementById(f),\"width\"))?i():setTimeout(u,100))}()}}},r={v:\"3.1.1\",ie:function(){var t=navigator.userAgent.toLowerCase();return!!(e.ActiveXObject||\"ActiveXObject\"in e)&&((t.match(/msie\\s(\\d+)/)||[])[1]||\"11\")}(),index:e.layer&&e.layer.v?1e5:0,path:o.getPath,config:function(e,t){return e=e||{},r.cache=o.config=i.extend({},o.config,e),r.path=o.config.path||r.path,\"string\"==typeof e.extend&&(e.extend=[e.extend]),o.config.path&&r.ready(),e.extend?(a?layui.addcss(\"modules/layer/\"+e.extend):o.link(\"theme/\"+e.extend),this):this},ready:function(e){var t=\"layer\",i=\"\",n=(a?\"modules/layer/\":\"theme/\")+\"default/layer.css?v=\"+r.v+i;return a?layui.addcss(n,e,t):o.link(n,e,t),this},alert:function(e,t,n){var a=\"function\"==typeof t;return a&&(n=t),r.open(i.extend({content:e,yes:n},a?{}:t))},confirm:function(e,t,n,a){var s=\"function\"==typeof t;return s&&(a=n,n=t),r.open(i.extend({content:e,btn:o.btn,yes:n,btn2:a},s?{}:t))},msg:function(e,n,a){var s=\"function\"==typeof n,f=o.config.skin,c=(f?f+\" \"+f+\"-msg\":\"\")||\"layui-layer-msg\",u=l.anim.length-1;return s&&(a=n),r.open(i.extend({content:e,time:3e3,shade:!1,skin:c,title:!1,closeBtn:!1,btn:!1,resize:!1,end:a},s&&!o.config.skin?{skin:c+\" layui-layer-hui\",anim:u}:function(){return n=n||{},(n.icon===-1||n.icon===t&&!o.config.skin)&&(n.skin=c+\" \"+(n.skin||\"layui-layer-hui\")),n}()))},load:function(e,t){return r.open(i.extend({type:3,icon:e||0,resize:!1,shade:.01},t))},tips:function(e,t,n){return r.open(i.extend({type:4,content:[e,t],closeBtn:!1,time:3e3,shade:!1,resize:!1,fixed:!1,maxWidth:210},n))}},s=function(e){var t=this;t.index=++r.index,t.config=i.extend({},t.config,o.config,e),document.body?t.creat():setTimeout(function(){t.creat()},30)};s.pt=s.prototype;var l=[\"layui-layer\",\".layui-layer-title\",\".layui-layer-main\",\".layui-layer-dialog\",\"layui-layer-iframe\",\"layui-layer-content\",\"layui-layer-btn\",\"layui-layer-close\"];l.anim=[\"layer-anim-00\",\"layer-anim-01\",\"layer-anim-02\",\"layer-anim-03\",\"layer-anim-04\",\"layer-anim-05\",\"layer-anim-06\"],s.pt.config={type:0,shade:.3,fixed:!0,move:l[1],title:\"&#x4FE1;&#x606F;\",offset:\"auto\",area:\"auto\",closeBtn:1,time:0,zIndex:19891014,maxWidth:360,anim:0,isOutAnim:!0,icon:-1,moveType:1,resize:!0,scrollbar:!0,tips:2},s.pt.vessel=function(e,t){var n=this,a=n.index,r=n.config,s=r.zIndex+a,f=\"object\"==typeof r.title,c=r.maxmin&&(1===r.type||2===r.type),u=r.title?'<div class=\"layui-layer-title\" style=\"'+(f?r.title[1]:\"\")+'\">'+(f?r.title[0]:r.title)+\"</div>\":\"\";return r.zIndex=s,t([r.shade?'<div class=\"layui-layer-shade\" id=\"layui-layer-shade'+a+'\" times=\"'+a+'\" style=\"'+(\"z-index:\"+(s-1)+\"; \")+'\"></div>':\"\",'<div class=\"'+l[0]+(\" layui-layer-\"+o.type[r.type])+(0!=r.type&&2!=r.type||r.shade?\"\":\" layui-layer-border\")+\" \"+(r.skin||\"\")+'\" id=\"'+l[0]+a+'\" type=\"'+o.type[r.type]+'\" times=\"'+a+'\" showtime=\"'+r.time+'\" conType=\"'+(e?\"object\":\"string\")+'\" style=\"z-index: '+s+\"; width:\"+r.area[0]+\";height:\"+r.area[1]+(r.fixed?\"\":\";position:absolute;\")+'\">'+(e&&2!=r.type?\"\":u)+'<div id=\"'+(r.id||\"\")+'\" class=\"layui-layer-content'+(0==r.type&&r.icon!==-1?\" layui-layer-padding\":\"\")+(3==r.type?\" layui-layer-loading\"+r.icon:\"\")+'\">'+(0==r.type&&r.icon!==-1?'<i class=\"layui-layer-ico layui-layer-ico'+r.icon+'\"></i>':\"\")+(1==r.type&&e?\"\":r.content||\"\")+'</div><span class=\"layui-layer-setwin\">'+function(){var e=c?'<a class=\"layui-layer-min\" href=\"javascript:;\"><cite></cite></a><a class=\"layui-layer-ico layui-layer-max\" href=\"javascript:;\"></a>':\"\";return r.closeBtn&&(e+='<a class=\"layui-layer-ico '+l[7]+\" \"+l[7]+(r.title?r.closeBtn:4==r.type?\"1\":\"2\")+'\" href=\"javascript:;\"></a>'),e}()+\"</span>\"+(r.btn?function(){var e=\"\";\"string\"==typeof r.btn&&(r.btn=[r.btn]);for(var t=0,i=r.btn.length;t<i;t++)e+='<a class=\"'+l[6]+t+'\">'+r.btn[t]+\"</a>\";return'<div class=\"'+l[6]+\" layui-layer-btn-\"+(r.btnAlign||\"\")+'\">'+e+\"</div>\"}():\"\")+(r.resize?'<span class=\"layui-layer-resize\"></span>':\"\")+\"</div>\"],u,i('<div class=\"layui-layer-move\"></div>')),n},s.pt.creat=function(){var e=this,t=e.config,a=e.index,s=t.content,f=\"object\"==typeof s,c=i(\"body\");if(!t.id||!i(\"#\"+t.id)[0]){switch(\"string\"==typeof t.area&&(t.area=\"auto\"===t.area?[\"\",\"\"]:[t.area,\"\"]),t.shift&&(t.anim=t.shift),6==r.ie&&(t.fixed=!1),t.type){case 0:t.btn=\"btn\"in t?t.btn:o.btn[0],r.closeAll(\"dialog\");break;case 2:var s=t.content=f?t.content:[t.content||\"http://layer.layui.com\",\"auto\"];t.content='<iframe scrolling=\"'+(t.content[1]||\"auto\")+'\" allowtransparency=\"true\" id=\"'+l[4]+a+'\" name=\"'+l[4]+a+'\" onload=\"this.className=\\'\\';\" class=\"layui-layer-load\" frameborder=\"0\" src=\"'+t.content[0]+'\"></iframe>';break;case 3:delete t.title,delete t.closeBtn,t.icon===-1&&0===t.icon,r.closeAll(\"loading\");break;case 4:f||(t.content=[t.content,\"body\"]),t.follow=t.content[1],t.content=t.content[0]+'<i class=\"layui-layer-TipsG\"></i>',delete t.title,t.tips=\"object\"==typeof t.tips?t.tips:[t.tips,!0],t.tipsMore||r.closeAll(\"tips\")}if(e.vessel(f,function(n,r,u){c.append(n[0]),f?function(){2==t.type||4==t.type?function(){i(\"body\").append(n[1])}():function(){s.parents(\".\"+l[0])[0]||(s.data(\"display\",s.css(\"display\")).show().addClass(\"layui-layer-wrap\").wrap(n[1]),i(\"#\"+l[0]+a).find(\".\"+l[5]).before(r))}()}():c.append(n[1]),i(\".layui-layer-move\")[0]||c.append(o.moveElem=u),e.layero=i(\"#\"+l[0]+a),t.scrollbar||l.html.css(\"overflow\",\"hidden\").attr(\"layer-full\",a)}).auto(a),i(\"#layui-layer-shade\"+e.index).css({\"background-color\":t.shade[1]||\"#000\",opacity:t.shade[0]||t.shade}),2==t.type&&6==r.ie&&e.layero.find(\"iframe\").attr(\"src\",s[0]),4==t.type?e.tips():e.offset(),t.fixed&&n.on(\"resize\",function(){e.offset(),(/^\\d+%$/.test(t.area[0])||/^\\d+%$/.test(t.area[1]))&&e.auto(a),4==t.type&&e.tips()}),t.time<=0||setTimeout(function(){r.close(e.index)},t.time),e.move().callback(),l.anim[t.anim]){var u=\"layer-anim \"+l.anim[t.anim];e.layero.addClass(u).one(\"webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend\",function(){i(this).removeClass(u)})}t.isOutAnim&&e.layero.data(\"isOutAnim\",!0)}},s.pt.auto=function(e){var t=this,a=t.config,o=i(\"#\"+l[0]+e);\"\"===a.area[0]&&a.maxWidth>0&&(r.ie&&r.ie<8&&a.btn&&o.width(o.innerWidth()),o.outerWidth()>a.maxWidth&&o.width(a.maxWidth));var s=[o.innerWidth(),o.innerHeight()],f=o.find(l[1]).outerHeight()||0,c=o.find(\".\"+l[6]).outerHeight()||0,u=function(e){e=o.find(e),e.height(s[1]-f-c-2*(0|parseFloat(e.css(\"padding-top\"))))};switch(a.type){case 2:u(\"iframe\");break;default:\"\"===a.area[1]?a.maxHeight>0&&o.outerHeight()>a.maxHeight?(s[1]=a.maxHeight,u(\".\"+l[5])):a.fixed&&s[1]>=n.height()&&(s[1]=n.height(),u(\".\"+l[5])):u(\".\"+l[5])}return t},s.pt.offset=function(){var e=this,t=e.config,i=e.layero,a=[i.outerWidth(),i.outerHeight()],o=\"object\"==typeof t.offset;e.offsetTop=(n.height()-a[1])/2,e.offsetLeft=(n.width()-a[0])/2,o?(e.offsetTop=t.offset[0],e.offsetLeft=t.offset[1]||e.offsetLeft):\"auto\"!==t.offset&&(\"t\"===t.offset?e.offsetTop=0:\"r\"===t.offset?e.offsetLeft=n.width()-a[0]:\"b\"===t.offset?e.offsetTop=n.height()-a[1]:\"l\"===t.offset?e.offsetLeft=0:\"lt\"===t.offset?(e.offsetTop=0,e.offsetLeft=0):\"lb\"===t.offset?(e.offsetTop=n.height()-a[1],e.offsetLeft=0):\"rt\"===t.offset?(e.offsetTop=0,e.offsetLeft=n.width()-a[0]):\"rb\"===t.offset?(e.offsetTop=n.height()-a[1],e.offsetLeft=n.width()-a[0]):e.offsetTop=t.offset),t.fixed||(e.offsetTop=/%$/.test(e.offsetTop)?n.height()*parseFloat(e.offsetTop)/100:parseFloat(e.offsetTop),e.offsetLeft=/%$/.test(e.offsetLeft)?n.width()*parseFloat(e.offsetLeft)/100:parseFloat(e.offsetLeft),e.offsetTop+=n.scrollTop(),e.offsetLeft+=n.scrollLeft()),i.attr(\"minLeft\")&&(e.offsetTop=n.height()-(i.find(l[1]).outerHeight()||0),e.offsetLeft=i.css(\"left\")),i.css({top:e.offsetTop,left:e.offsetLeft})},s.pt.tips=function(){var e=this,t=e.config,a=e.layero,o=[a.outerWidth(),a.outerHeight()],r=i(t.follow);r[0]||(r=i(\"body\"));var s={width:r.outerWidth(),height:r.outerHeight(),top:r.offset().top,left:r.offset().left},f=a.find(\".layui-layer-TipsG\"),c=t.tips[0];t.tips[1]||f.remove(),s.autoLeft=function(){s.left+o[0]-n.width()>0?(s.tipLeft=s.left+s.width-o[0],f.css({right:12,left:\"auto\"})):s.tipLeft=s.left},s.where=[function(){s.autoLeft(),s.tipTop=s.top-o[1]-10,f.removeClass(\"layui-layer-TipsB\").addClass(\"layui-layer-TipsT\").css(\"border-right-color\",t.tips[1])},function(){s.tipLeft=s.left+s.width+10,s.tipTop=s.top,f.removeClass(\"layui-layer-TipsL\").addClass(\"layui-layer-TipsR\").css(\"border-bottom-color\",t.tips[1])},function(){s.autoLeft(),s.tipTop=s.top+s.height+10,f.removeClass(\"layui-layer-TipsT\").addClass(\"layui-layer-TipsB\").css(\"border-right-color\",t.tips[1])},function(){s.tipLeft=s.left-o[0]-10,s.tipTop=s.top,f.removeClass(\"layui-layer-TipsR\").addClass(\"layui-layer-TipsL\").css(\"border-bottom-color\",t.tips[1])}],s.where[c-1](),1===c?s.top-(n.scrollTop()+o[1]+16)<0&&s.where[2]():2===c?n.width()-(s.left+s.width+o[0]+16)>0||s.where[3]():3===c?s.top-n.scrollTop()+s.height+o[1]+16-n.height()>0&&s.where[0]():4===c&&o[0]+16-s.left>0&&s.where[1](),a.find(\".\"+l[5]).css({\"background-color\":t.tips[1],\"padding-right\":t.closeBtn?\"30px\":\"\"}),a.css({left:s.tipLeft-(t.fixed?n.scrollLeft():0),top:s.tipTop-(t.fixed?n.scrollTop():0)})},s.pt.move=function(){var e=this,t=e.config,a=i(document),s=e.layero,l=s.find(t.move),f=s.find(\".layui-layer-resize\"),c={};return t.move&&l.css(\"cursor\",\"move\"),l.on(\"mousedown\",function(e){e.preventDefault(),t.move&&(c.moveStart=!0,c.offset=[e.clientX-parseFloat(s.css(\"left\")),e.clientY-parseFloat(s.css(\"top\"))],o.moveElem.css(\"cursor\",\"move\").show())}),f.on(\"mousedown\",function(e){e.preventDefault(),c.resizeStart=!0,c.offset=[e.clientX,e.clientY],c.area=[s.outerWidth(),s.outerHeight()],o.moveElem.css(\"cursor\",\"se-resize\").show()}),a.on(\"mousemove\",function(i){if(c.moveStart){var a=i.clientX-c.offset[0],o=i.clientY-c.offset[1],l=\"fixed\"===s.css(\"position\");if(i.preventDefault(),c.stX=l?0:n.scrollLeft(),c.stY=l?0:n.scrollTop(),!t.moveOut){var f=n.width()-s.outerWidth()+c.stX,u=n.height()-s.outerHeight()+c.stY;a<c.stX&&(a=c.stX),a>f&&(a=f),o<c.stY&&(o=c.stY),o>u&&(o=u)}s.css({left:a,top:o})}if(t.resize&&c.resizeStart){var a=i.clientX-c.offset[0],o=i.clientY-c.offset[1];i.preventDefault(),r.style(e.index,{width:c.area[0]+a,height:c.area[1]+o}),c.isResize=!0,t.resizing&&t.resizing(s)}}).on(\"mouseup\",function(e){c.moveStart&&(delete c.moveStart,o.moveElem.hide(),t.moveEnd&&t.moveEnd(s)),c.resizeStart&&(delete c.resizeStart,o.moveElem.hide())}),e},s.pt.callback=function(){function e(){var e=a.cancel&&a.cancel(t.index,n);e===!1||r.close(t.index)}var t=this,n=t.layero,a=t.config;t.openLayer(),a.success&&(2==a.type?n.find(\"iframe\").on(\"load\",function(){a.success(n,t.index)}):a.success(n,t.index)),6==r.ie&&t.IE6(n),n.find(\".\"+l[6]).children(\"a\").on(\"click\",function(){var e=i(this).index();if(0===e)a.yes?a.yes(t.index,n):a.btn1?a.btn1(t.index,n):r.close(t.index);else{var o=a[\"btn\"+(e+1)]&&a[\"btn\"+(e+1)](t.index,n);o===!1||r.close(t.index)}}),n.find(\".\"+l[7]).on(\"click\",e),a.shadeClose&&i(\"#layui-layer-shade\"+t.index).on(\"click\",function(){r.close(t.index)}),n.find(\".layui-layer-min\").on(\"click\",function(){var e=a.min&&a.min(n);e===!1||r.min(t.index,a)}),n.find(\".layui-layer-max\").on(\"click\",function(){i(this).hasClass(\"layui-layer-maxmin\")?(r.restore(t.index),a.restore&&a.restore(n)):(r.full(t.index,a),setTimeout(function(){a.full&&a.full(n)},100))}),a.end&&(o.end[t.index]=a.end)},o.reselect=function(){i.each(i(\"select\"),function(e,t){var n=i(this);n.parents(\".\"+l[0])[0]||1==n.attr(\"layer\")&&i(\".\"+l[0]).length<1&&n.removeAttr(\"layer\").show(),n=null})},s.pt.IE6=function(e){i(\"select\").each(function(e,t){var n=i(this);n.parents(\".\"+l[0])[0]||\"none\"===n.css(\"display\")||n.attr({layer:\"1\"}).hide(),n=null})},s.pt.openLayer=function(){var e=this;r.zIndex=e.config.zIndex,r.setTop=function(e){var t=function(){r.zIndex++,e.css(\"z-index\",r.zIndex+1)};return r.zIndex=parseInt(e[0].style.zIndex),e.on(\"mousedown\",t),r.zIndex}},o.record=function(e){var t=[e.width(),e.height(),e.position().top,e.position().left+parseFloat(e.css(\"margin-left\"))];e.find(\".layui-layer-max\").addClass(\"layui-layer-maxmin\"),e.attr({area:t})},o.rescollbar=function(e){l.html.attr(\"layer-full\")==e&&(l.html[0].style.removeProperty?l.html[0].style.removeProperty(\"overflow\"):l.html[0].style.removeAttribute(\"overflow\"),l.html.removeAttr(\"layer-full\"))},e.layer=r,r.getChildFrame=function(e,t){return t=t||i(\".\"+l[4]).attr(\"times\"),i(\"#\"+l[0]+t).find(\"iframe\").contents().find(e)},r.getFrameIndex=function(e){return i(\"#\"+e).parents(\".\"+l[4]).attr(\"times\")},r.iframeAuto=function(e){if(e){var t=r.getChildFrame(\"html\",e).outerHeight(),n=i(\"#\"+l[0]+e),a=n.find(l[1]).outerHeight()||0,o=n.find(\".\"+l[6]).outerHeight()||0;n.css({height:t+a+o}),n.find(\"iframe\").css({height:t})}},r.iframeSrc=function(e,t){i(\"#\"+l[0]+e).find(\"iframe\").attr(\"src\",t)},r.style=function(e,t,n){var a=i(\"#\"+l[0]+e),r=a.find(\".layui-layer-content\"),s=a.attr(\"type\"),f=a.find(l[1]).outerHeight()||0,c=a.find(\".\"+l[6]).outerHeight()||0;a.attr(\"minLeft\");s!==o.type[3]&&s!==o.type[4]&&(n||(parseFloat(t.width)<=260&&(t.width=260),parseFloat(t.height)-f-c<=64&&(t.height=64+f+c)),a.css(t),c=a.find(\".\"+l[6]).outerHeight(),s===o.type[2]?a.find(\"iframe\").css({height:parseFloat(t.height)-f-c}):r.css({height:parseFloat(t.height)-f-c-parseFloat(r.css(\"padding-top\"))-parseFloat(r.css(\"padding-bottom\"))}))},r.min=function(e,t){var a=i(\"#\"+l[0]+e),s=a.find(l[1]).outerHeight()||0,f=a.attr(\"minLeft\")||181*o.minIndex+\"px\",c=a.css(\"position\");o.record(a),o.minLeft[0]&&(f=o.minLeft[0],o.minLeft.shift()),a.attr(\"position\",c),r.style(e,{width:180,height:s,left:f,top:n.height()-s,position:\"fixed\",overflow:\"hidden\"},!0),a.find(\".layui-layer-min\").hide(),\"page\"===a.attr(\"type\")&&a.find(l[4]).hide(),o.rescollbar(e),a.attr(\"minLeft\")||o.minIndex++,a.attr(\"minLeft\",f)},r.restore=function(e){var t=i(\"#\"+l[0]+e),n=t.attr(\"area\").split(\",\");t.attr(\"type\");r.style(e,{width:parseFloat(n[0]),height:parseFloat(n[1]),top:parseFloat(n[2]),left:parseFloat(n[3]),position:t.attr(\"position\"),overflow:\"visible\"},!0),t.find(\".layui-layer-max\").removeClass(\"layui-layer-maxmin\"),t.find(\".layui-layer-min\").show(),\"page\"===t.attr(\"type\")&&t.find(l[4]).show(),o.rescollbar(e)},r.full=function(e){var t,a=i(\"#\"+l[0]+e);o.record(a),l.html.attr(\"layer-full\")||l.html.css(\"overflow\",\"hidden\").attr(\"layer-full\",e),clearTimeout(t),t=setTimeout(function(){var t=\"fixed\"===a.css(\"position\");r.style(e,{top:t?0:n.scrollTop(),left:t?0:n.scrollLeft(),width:n.width(),height:n.height()},!0),a.find(\".layui-layer-min\").hide()},100)},r.title=function(e,t){var n=i(\"#\"+l[0]+(t||r.index)).find(l[1]);n.html(e)},r.close=function(e){var t=i(\"#\"+l[0]+e),n=t.attr(\"type\"),a=\"layer-anim-close\";if(t[0]){var s=\"layui-layer-wrap\",f=function(){if(n===o.type[1]&&\"object\"===t.attr(\"conType\")){t.children(\":not(.\"+l[5]+\")\").remove();for(var a=t.find(\".\"+s),r=0;r<2;r++)a.unwrap();a.css(\"display\",a.data(\"display\")).removeClass(s)}else{if(n===o.type[2])try{var f=i(\"#\"+l[4]+e)[0];f.contentWindow.document.write(\"\"),f.contentWindow.close(),t.find(\".\"+l[5])[0].removeChild(f)}catch(c){}t[0].innerHTML=\"\",t.remove()}\"function\"==typeof o.end[e]&&o.end[e](),delete o.end[e]};t.data(\"isOutAnim\")&&t.addClass(\"layer-anim \"+a),i(\"#layui-layer-moves, #layui-layer-shade\"+e).remove(),6==r.ie&&o.reselect(),o.rescollbar(e),t.attr(\"minLeft\")&&(o.minIndex--,o.minLeft.push(t.attr(\"minLeft\"))),r.ie&&r.ie<10||!t.data(\"isOutAnim\")?f():setTimeout(function(){f()},200)}},r.closeAll=function(e){i.each(i(\".\"+l[0]),function(){var t=i(this),n=e?t.attr(\"type\")===e:1;n&&r.close(t.attr(\"times\")),n=null})};var f=r.cache||{},c=function(e){return f.skin?\" \"+f.skin+\" \"+f.skin+\"-\"+e:\"\"};r.prompt=function(e,t){var a=\"\";if(e=e||{},\"function\"==typeof e&&(t=e),e.area){var o=e.area;a='style=\"width: '+o[0]+\"; height: \"+o[1]+';\"',delete e.area}var s,l=2==e.formType?'<textarea class=\"layui-layer-input\"'+a+\">\"+(e.value||\"\")+\"</textarea>\":function(){return'<input type=\"'+(1==e.formType?\"password\":\"text\")+'\" class=\"layui-layer-input\" value=\"'+(e.value||\"\")+'\">'}(),f=e.success;return delete e.success,r.open(i.extend({type:1,btn:[\"&#x786E;&#x5B9A;\",\"&#x53D6;&#x6D88;\"],content:l,skin:\"layui-layer-prompt\"+c(\"prompt\"),maxWidth:n.width(),success:function(e){s=e.find(\".layui-layer-input\"),s.focus(),\"function\"==typeof f&&f(e)},resize:!1,yes:function(i){var n=s.val();\"\"===n?s.focus():n.length>(e.maxlength||500)?r.tips(\"&#x6700;&#x591A;&#x8F93;&#x5165;\"+(e.maxlength||500)+\"&#x4E2A;&#x5B57;&#x6570;\",s,{tips:1}):t&&t(n,i,s)}},e))},r.tab=function(e){e=e||{};var t=e.tab||{},n=\"layui-this\",a=e.success;return delete e.success,r.open(i.extend({type:1,skin:\"layui-layer-tab\"+c(\"tab\"),resize:!1,title:function(){var e=t.length,i=1,a=\"\";if(e>0)for(a='<span class=\"'+n+'\">'+t[0].title+\"</span>\";i<e;i++)a+=\"<span>\"+t[i].title+\"</span>\";return a}(),content:'<ul class=\"layui-layer-tabmain\">'+function(){var e=t.length,i=1,a=\"\";if(e>0)for(a='<li class=\"layui-layer-tabli '+n+'\">'+(t[0].content||\"no content\")+\"</li>\";i<e;i++)a+='<li class=\"layui-layer-tabli\">'+(t[i].content||\"no  content\")+\"</li>\";return a}()+\"</ul>\",success:function(t){var o=t.find(\".layui-layer-title\").children(),r=t.find(\".layui-layer-tabmain\").children();o.on(\"mousedown\",function(t){t.stopPropagation?t.stopPropagation():t.cancelBubble=!0;var a=i(this),o=a.index();a.addClass(n).siblings().removeClass(n),r.eq(o).show().siblings().hide(),\"function\"==typeof e.change&&e.change(o)}),\"function\"==typeof a&&a(t)}},e))},r.photos=function(t,n,a){function o(e,t,i){var n=new Image;return n.src=e,n.complete?t(n):(n.onload=function(){n.onload=null,t(n)},void(n.onerror=function(e){n.onerror=null,i(e)}))}var s={};if(t=t||{},t.photos){var l=t.photos.constructor===Object,f=l?t.photos:{},u=f.data||[],d=f.start||0;s.imgIndex=(0|d)+1,t.img=t.img||\"img\";var y=t.success;if(delete t.success,l){if(0===u.length)return r.msg(\"&#x6CA1;&#x6709;&#x56FE;&#x7247;\")}else{var p=i(t.photos),h=function(){u=[],p.find(t.img).each(function(e){var t=i(this);t.attr(\"layer-index\",e),u.push({alt:t.attr(\"alt\"),pid:t.attr(\"layer-pid\"),src:t.attr(\"layer-src\")||t.attr(\"src\"),thumb:t.attr(\"src\")})})};if(h(),0===u.length)return;if(n||p.on(\"click\",t.img,function(){var e=i(this),n=e.attr(\"layer-index\");r.photos(i.extend(t,{photos:{start:n,data:u,tab:t.tab},full:t.full}),!0),h()}),!n)return}s.imgprev=function(e){s.imgIndex--,s.imgIndex<1&&(s.imgIndex=u.length),s.tabimg(e)},s.imgnext=function(e,t){s.imgIndex++,s.imgIndex>u.length&&(s.imgIndex=1,t)||s.tabimg(e)},s.keyup=function(e){if(!s.end){var t=e.keyCode;e.preventDefault(),37===t?s.imgprev(!0):39===t?s.imgnext(!0):27===t&&r.close(s.index)}},s.tabimg=function(e){if(!(u.length<=1))return f.start=s.imgIndex-1,r.close(s.index),r.photos(t,!0,e)},s.event=function(){s.bigimg.hover(function(){s.imgsee.show()},function(){s.imgsee.hide()}),s.bigimg.find(\".layui-layer-imgprev\").on(\"click\",function(e){e.preventDefault(),s.imgprev()}),s.bigimg.find(\".layui-layer-imgnext\").on(\"click\",function(e){e.preventDefault(),s.imgnext()}),i(document).on(\"keyup\",s.keyup)},s.loadi=r.load(1,{shade:!(\"shade\"in t)&&.9,scrollbar:!1}),o(u[d].src,function(n){r.close(s.loadi),s.index=r.open(i.extend({type:1,id:\"layui-layer-photos\",area:function(){var a=[n.width,n.height],o=[i(e).width()-100,i(e).height()-100];if(!t.full&&(a[0]>o[0]||a[1]>o[1])){var r=[a[0]/o[0],a[1]/o[1]];r[0]>r[1]?(a[0]=a[0]/r[0],a[1]=a[1]/r[0]):r[0]<r[1]&&(a[0]=a[0]/r[1],a[1]=a[1]/r[1])}return[a[0]+\"px\",a[1]+\"px\"]}(),title:!1,shade:.9,shadeClose:!0,closeBtn:!1,move:\".layui-layer-phimg img\",moveType:1,scrollbar:!1,moveOut:!0,isOutAnim:!1,skin:\"layui-layer-photos\"+c(\"photos\"),content:'<div class=\"layui-layer-phimg\"><img src=\"'+u[d].src+'\" alt=\"'+(u[d].alt||\"\")+'\" layer-pid=\"'+u[d].pid+'\"><div class=\"layui-layer-imgsee\">'+(u.length>1?'<span class=\"layui-layer-imguide\"><a href=\"javascript:;\" class=\"layui-layer-iconext layui-layer-imgprev\"></a><a href=\"javascript:;\" class=\"layui-layer-iconext layui-layer-imgnext\"></a></span>':\"\")+'<div class=\"layui-layer-imgbar\" style=\"display:'+(a?\"block\":\"\")+'\"><span class=\"layui-layer-imgtit\"><a href=\"javascript:;\">'+(u[d].alt||\"\")+\"</a><em>\"+s.imgIndex+\"/\"+u.length+\"</em></span></div></div></div>\",success:function(e,i){s.bigimg=e.find(\".layui-layer-phimg\"),s.imgsee=e.find(\".layui-layer-imguide,.layui-layer-imgbar\"),s.event(e),t.tab&&t.tab(u[d],e),\"function\"==typeof y&&y(e)},end:function(){s.end=!0,i(document).off(\"keyup\",s.keyup)}},t))},function(){r.close(s.loadi),r.msg(\"&#x5F53;&#x524D;&#x56FE;&#x7247;&#x5730;&#x5740;&#x5F02;&#x5E38;<br>&#x662F;&#x5426;&#x7EE7;&#x7EED;&#x67E5;&#x770B;&#x4E0B;&#x4E00;&#x5F20;&#xFF1F;\",{time:3e4,btn:[\"&#x4E0B;&#x4E00;&#x5F20;\",\"&#x4E0D;&#x770B;&#x4E86;\"],yes:function(){u.length>1&&s.imgnext(!0,!0)}})})}},o.run=function(t){i=t,n=i(e),l.html=i(\"html\"),r.open=function(e){var t=new s(e);return t.index}},e.layui&&layui.define?(r.ready(),layui.define(\"jquery\",function(t){r.path=layui.cache.dir,o.run(layui.$),e.layer=r,t(\"layer\",r)})):\"function\"==typeof define&&define.amd?define([\"jquery\"],function(){return o.run(e.jQuery),r}):function(){o.run(e.jQuery),r.ready()}()}(window);"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/plugins/layer/theme/default/layer.css",
    "content": ".layui-layer-imgbar,.layui-layer-imgtit a,.layui-layer-tab .layui-layer-title span,.layui-layer-title{text-overflow:ellipsis;white-space:nowrap}html #layuicss-layer{display:none;position:absolute;width:1989px}.layui-layer,.layui-layer-shade{position:fixed;_position:absolute;pointer-events:auto}.layui-layer-shade{top:0;left:0;width:100%;height:100%;_height:expression(document.body.offsetHeight+\"px\")}.layui-layer{-webkit-overflow-scrolling:touch;top:150px;left:0;margin:0;padding:0;background-color:#fff;-webkit-background-clip:content;border-radius:2px;box-shadow:1px 1px 50px rgba(0,0,0,.3)}.layui-layer-close{position:absolute}.layui-layer-content{position:relative}.layui-layer-border{border:1px solid #B2B2B2;border:1px solid rgba(0,0,0,.1);box-shadow:1px 1px 5px rgba(0,0,0,.2)}.layui-layer-load{background:url(loading-1.gif) center center no-repeat #eee}.layui-layer-ico{background:url(icon.png) no-repeat}.layui-layer-btn a,.layui-layer-dialog .layui-layer-ico,.layui-layer-setwin a{display:inline-block;*display:inline;*zoom:1;vertical-align:top}.layui-layer-move{display:none;position:fixed;*position:absolute;left:0;top:0;width:100%;height:100%;cursor:move;opacity:0;filter:alpha(opacity=0);background-color:#fff;z-index:2147483647}.layui-layer-resize{position:absolute;width:15px;height:15px;right:0;bottom:0;cursor:se-resize}.layer-anim{-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-duration:.3s;animation-duration:.3s}@-webkit-keyframes layer-bounceIn{0%{opacity:0;-webkit-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}}@keyframes layer-bounceIn{0%{opacity:0;-webkit-transform:scale(.5);-ms-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}}.layer-anim-00{-webkit-animation-name:layer-bounceIn;animation-name:layer-bounceIn}@-webkit-keyframes layer-zoomInDown{0%{opacity:0;-webkit-transform:scale(.1) translateY(-2000px);transform:scale(.1) translateY(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateY(60px);transform:scale(.475) translateY(60px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}@keyframes layer-zoomInDown{0%{opacity:0;-webkit-transform:scale(.1) translateY(-2000px);-ms-transform:scale(.1) translateY(-2000px);transform:scale(.1) translateY(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateY(60px);-ms-transform:scale(.475) translateY(60px);transform:scale(.475) translateY(60px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}.layer-anim-01{-webkit-animation-name:layer-zoomInDown;animation-name:layer-zoomInDown}@-webkit-keyframes layer-fadeInUpBig{0%{opacity:0;-webkit-transform:translateY(2000px);transform:translateY(2000px)}100%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes layer-fadeInUpBig{0%{opacity:0;-webkit-transform:translateY(2000px);-ms-transform:translateY(2000px);transform:translateY(2000px)}100%{opacity:1;-webkit-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}}.layer-anim-02{-webkit-animation-name:layer-fadeInUpBig;animation-name:layer-fadeInUpBig}@-webkit-keyframes layer-zoomInLeft{0%{opacity:0;-webkit-transform:scale(.1) translateX(-2000px);transform:scale(.1) translateX(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateX(48px);transform:scale(.475) translateX(48px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}@keyframes layer-zoomInLeft{0%{opacity:0;-webkit-transform:scale(.1) translateX(-2000px);-ms-transform:scale(.1) translateX(-2000px);transform:scale(.1) translateX(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateX(48px);-ms-transform:scale(.475) translateX(48px);transform:scale(.475) translateX(48px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}.layer-anim-03{-webkit-animation-name:layer-zoomInLeft;animation-name:layer-zoomInLeft}@-webkit-keyframes layer-rollIn{0%{opacity:0;-webkit-transform:translateX(-100%) rotate(-120deg);transform:translateX(-100%) rotate(-120deg)}100%{opacity:1;-webkit-transform:translateX(0) rotate(0);transform:translateX(0) rotate(0)}}@keyframes layer-rollIn{0%{opacity:0;-webkit-transform:translateX(-100%) rotate(-120deg);-ms-transform:translateX(-100%) rotate(-120deg);transform:translateX(-100%) rotate(-120deg)}100%{opacity:1;-webkit-transform:translateX(0) rotate(0);-ms-transform:translateX(0) rotate(0);transform:translateX(0) rotate(0)}}.layer-anim-04{-webkit-animation-name:layer-rollIn;animation-name:layer-rollIn}@keyframes layer-fadeIn{0%{opacity:0}100%{opacity:1}}.layer-anim-05{-webkit-animation-name:layer-fadeIn;animation-name:layer-fadeIn}@-webkit-keyframes layer-shake{0%,100%{-webkit-transform:translateX(0);transform:translateX(0)}10%,30%,50%,70%,90%{-webkit-transform:translateX(-10px);transform:translateX(-10px)}20%,40%,60%,80%{-webkit-transform:translateX(10px);transform:translateX(10px)}}@keyframes layer-shake{0%,100%{-webkit-transform:translateX(0);-ms-transform:translateX(0);transform:translateX(0)}10%,30%,50%,70%,90%{-webkit-transform:translateX(-10px);-ms-transform:translateX(-10px);transform:translateX(-10px)}20%,40%,60%,80%{-webkit-transform:translateX(10px);-ms-transform:translateX(10px);transform:translateX(10px)}}.layer-anim-06{-webkit-animation-name:layer-shake;animation-name:layer-shake}@-webkit-keyframes fadeIn{0%{opacity:0}100%{opacity:1}}.layui-layer-title{padding:0 80px 0 20px;height:42px;line-height:42px;border-bottom:1px solid #eee;font-size:14px;color:#333;overflow:hidden;background-color:#F8F8F8;border-radius:2px 2px 0 0}.layui-layer-setwin{position:absolute;right:15px;*right:0;top:15px;font-size:0;line-height:initial}.layui-layer-setwin a{position:relative;width:16px;height:16px;margin-left:10px;font-size:12px;_overflow:hidden}.layui-layer-setwin .layui-layer-min cite{position:absolute;width:14px;height:2px;left:0;top:50%;margin-top:-1px;background-color:#2E2D3C;cursor:pointer;_overflow:hidden}.layui-layer-setwin .layui-layer-min:hover cite{background-color:#2D93CA}.layui-layer-setwin .layui-layer-max{background-position:-32px -40px}.layui-layer-setwin .layui-layer-max:hover{background-position:-16px -40px}.layui-layer-setwin .layui-layer-maxmin{background-position:-65px -40px}.layui-layer-setwin .layui-layer-maxmin:hover{background-position:-49px -40px}.layui-layer-setwin .layui-layer-close1{background-position:1px -40px;cursor:pointer}.layui-layer-setwin .layui-layer-close1:hover{opacity:.7}.layui-layer-setwin .layui-layer-close2{position:absolute;right:-28px;top:-28px;width:30px;height:30px;margin-left:0;background-position:-149px -31px;*right:-18px;_display:none}.layui-layer-setwin .layui-layer-close2:hover{background-position:-180px -31px}.layui-layer-btn{text-align:right;padding:0 15px 12px;pointer-events:auto;user-select:none;-webkit-user-select:none}.layui-layer-btn a{height:28px;line-height:28px;margin:5px 5px 0;padding:0 15px;border:1px solid #dedede;background-color:#fff;color:#333;border-radius:2px;font-weight:400;cursor:pointer;text-decoration:none}.layui-layer-btn a:hover{opacity:.9;text-decoration:none}.layui-layer-btn a:active{opacity:.8}.layui-layer-btn .layui-layer-btn0{border-color:#1E9FFF;background-color:#1E9FFF;color:#fff}.layui-layer-btn-l{text-align:left}.layui-layer-btn-c{text-align:center}.layui-layer-dialog{min-width:260px}.layui-layer-dialog .layui-layer-content{position:relative;padding:20px;line-height:24px;word-break:break-all;overflow:hidden;font-size:14px;overflow-x:hidden;overflow-y:auto}.layui-layer-dialog .layui-layer-content .layui-layer-ico{position:absolute;top:16px;left:15px;_left:-40px;width:30px;height:30px}.layui-layer-ico1{background-position:-30px 0}.layui-layer-ico2{background-position:-60px 0}.layui-layer-ico3{background-position:-90px 0}.layui-layer-ico4{background-position:-120px 0}.layui-layer-ico5{background-position:-150px 0}.layui-layer-ico6{background-position:-180px 0}.layui-layer-rim{border:6px solid #8D8D8D;border:6px solid rgba(0,0,0,.3);border-radius:5px;box-shadow:none}.layui-layer-msg{min-width:180px;border:1px solid #D3D4D3;box-shadow:none}.layui-layer-hui{min-width:100px;background-color:#000;filter:alpha(opacity=60);background-color:rgba(0,0,0,.6);color:#fff;border:none}.layui-layer-hui .layui-layer-content{padding:12px 25px;text-align:center}.layui-layer-dialog .layui-layer-padding{padding:20px 20px 20px 55px;text-align:left}.layui-layer-page .layui-layer-content{position:relative;overflow:auto}.layui-layer-iframe .layui-layer-btn,.layui-layer-page .layui-layer-btn{padding-top:10px}.layui-layer-nobg{background:0 0}.layui-layer-iframe iframe{display:block;width:100%}.layui-layer-loading{border-radius:100%;background:0 0;box-shadow:none;border:none}.layui-layer-loading .layui-layer-content{width:60px;height:24px;background:url(loading-0.gif) no-repeat}.layui-layer-loading .layui-layer-loading1{width:37px;height:37px;background:url(loading-1.gif) no-repeat}.layui-layer-ico16,.layui-layer-loading .layui-layer-loading2{width:32px;height:32px;background:url(loading-2.gif) no-repeat}.layui-layer-tips{background:0 0;box-shadow:none;border:none}.layui-layer-tips .layui-layer-content{position:relative;line-height:22px;min-width:12px;padding:8px 15px;font-size:12px;_float:left;border-radius:2px;box-shadow:1px 1px 3px rgba(0,0,0,.2);background-color:#000;color:#fff}.layui-layer-tips .layui-layer-close{right:-2px;top:-1px}.layui-layer-tips i.layui-layer-TipsG{position:absolute;width:0;height:0;border-width:8px;border-color:transparent;border-style:dashed;*overflow:hidden}.layui-layer-tips i.layui-layer-TipsB,.layui-layer-tips i.layui-layer-TipsT{left:5px;border-right-style:solid;border-right-color:#000}.layui-layer-tips i.layui-layer-TipsT{bottom:-8px}.layui-layer-tips i.layui-layer-TipsB{top:-8px}.layui-layer-tips i.layui-layer-TipsL,.layui-layer-tips i.layui-layer-TipsR{top:5px;border-bottom-style:solid;border-bottom-color:#000}.layui-layer-tips i.layui-layer-TipsR{left:-8px}.layui-layer-tips i.layui-layer-TipsL{right:-8px}.layui-layer-lan[type=dialog]{min-width:280px}.layui-layer-lan .layui-layer-title{background:#4476A7;color:#fff;border:none}.layui-layer-lan .layui-layer-btn{padding:5px 10px 10px;text-align:right;border-top:1px solid #E9E7E7}.layui-layer-lan .layui-layer-btn a{background:#fff;border-color:#E9E7E7;color:#333}.layui-layer-lan .layui-layer-btn .layui-layer-btn1{background:#C9C5C5}.layui-layer-molv .layui-layer-title{background:#009f95;color:#fff;border:none}.layui-layer-molv .layui-layer-btn a{background:#009f95;border-color:#009f95}.layui-layer-molv .layui-layer-btn .layui-layer-btn1{background:#92B8B1}.layui-layer-iconext{background:url(icon-ext.png) no-repeat}.layui-layer-prompt .layui-layer-input{display:block;width:230px;height:36px;margin:0 auto;line-height:30px;padding-left:10px;border:1px solid #e6e6e6;color:#333}.layui-layer-prompt textarea.layui-layer-input{width:300px;height:100px;line-height:20px;padding:6px 10px}.layui-layer-prompt .layui-layer-content{padding:20px}.layui-layer-prompt .layui-layer-btn{padding-top:0}.layui-layer-tab{box-shadow:1px 1px 50px rgba(0,0,0,.4)}.layui-layer-tab .layui-layer-title{padding-left:0;overflow:visible}.layui-layer-tab .layui-layer-title span{position:relative;float:left;min-width:80px;max-width:260px;padding:0 20px;text-align:center;overflow:hidden;cursor:pointer}.layui-layer-tab .layui-layer-title span.layui-this{height:43px;border-left:1px solid #eee;border-right:1px solid #eee;background-color:#fff;z-index:10}.layui-layer-tab .layui-layer-title span:first-child{border-left:none}.layui-layer-tabmain{line-height:24px;clear:both}.layui-layer-tabmain .layui-layer-tabli{display:none}.layui-layer-tabmain .layui-layer-tabli.layui-this{display:block}.layui-layer-photos{-webkit-animation-duration:.8s;animation-duration:.8s}.layui-layer-photos .layui-layer-content{overflow:hidden;text-align:center}.layui-layer-photos .layui-layer-phimg img{position:relative;width:100%;display:inline-block;*display:inline;*zoom:1;vertical-align:top}.layui-layer-imgbar,.layui-layer-imguide{display:none}.layui-layer-imgnext,.layui-layer-imgprev{position:absolute;top:50%;width:27px;_width:44px;height:44px;margin-top:-22px;outline:0;blr:expression(this.onFocus=this.blur())}.layui-layer-imgprev{left:10px;background-position:-5px -5px;_background-position:-70px -5px}.layui-layer-imgprev:hover{background-position:-33px -5px;_background-position:-120px -5px}.layui-layer-imgnext{right:10px;_right:8px;background-position:-5px -50px;_background-position:-70px -50px}.layui-layer-imgnext:hover{background-position:-33px -50px;_background-position:-120px -50px}.layui-layer-imgbar{position:absolute;left:0;bottom:0;width:100%;height:32px;line-height:32px;background-color:rgba(0,0,0,.8);background-color:#000\\9;filter:Alpha(opacity=80);color:#fff;overflow:hidden;font-size:0}.layui-layer-imgtit *{display:inline-block;*display:inline;*zoom:1;vertical-align:top;font-size:12px}.layui-layer-imgtit a{max-width:65%;overflow:hidden;color:#fff}.layui-layer-imgtit a:hover{color:#fff;text-decoration:underline}.layui-layer-imgtit em{padding-left:10px;font-style:normal}@-webkit-keyframes layer-bounceOut{100%{opacity:0;-webkit-transform:scale(.7);transform:scale(.7)}30%{-webkit-transform:scale(1.05);transform:scale(1.05)}0%{-webkit-transform:scale(1);transform:scale(1)}}@keyframes layer-bounceOut{100%{opacity:0;-webkit-transform:scale(.7);-ms-transform:scale(.7);transform:scale(.7)}30%{-webkit-transform:scale(1.05);-ms-transform:scale(1.05);transform:scale(1.05)}0%{-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}}.layer-anim-close{-webkit-animation-name:layer-bounceOut;animation-name:layer-bounceOut;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-duration:.2s;animation-duration:.2s}@media screen and (max-width:1100px){.layui-layer-iframe{overflow-y:auto;-webkit-overflow-scrolling:touch}}"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/plugins/nprogress/nprogress.css",
    "content": "/* Make clicks pass-through */\n#nprogress {\n  pointer-events: none;\n}\n\n#nprogress .bar {\n  background: #29d;\n\n  position: fixed;\n  z-index: 1031;\n  top: 0;\n  left: 0;\n\n  width: 100%;\n  height: 2px;\n}\n\n/* Fancy blur effect */\n#nprogress .peg {\n  display: block;\n  position: absolute;\n  right: 0px;\n  width: 100px;\n  height: 100%;\n  box-shadow: 0 0 10px #29d, 0 0 5px #29d;\n  opacity: 1.0;\n\n  -webkit-transform: rotate(3deg) translate(0px, -4px);\n      -ms-transform: rotate(3deg) translate(0px, -4px);\n          transform: rotate(3deg) translate(0px, -4px);\n}\n\n/* Remove these to get rid of the spinner */\n#nprogress .spinner {\n  display: block;\n  position: fixed;\n  z-index: 1031;\n  top: 15px;\n  right: 15px;\n}\n\n#nprogress .spinner-icon {\n  width: 18px;\n  height: 18px;\n  box-sizing: border-box;\n\n  border: solid 2px transparent;\n  border-top-color: #29d;\n  border-left-color: #29d;\n  border-radius: 50%;\n\n  -webkit-animation: nprogress-spinner 400ms linear infinite;\n          animation: nprogress-spinner 400ms linear infinite;\n}\n\n.nprogress-custom-parent {\n  overflow: hidden;\n  position: relative;\n}\n\n.nprogress-custom-parent #nprogress .spinner,\n.nprogress-custom-parent #nprogress .bar {\n  position: absolute;\n}\n\n@-webkit-keyframes nprogress-spinner {\n  0%   { -webkit-transform: rotate(0deg); }\n  100% { -webkit-transform: rotate(360deg); }\n}\n@keyframes nprogress-spinner {\n  0%   { transform: rotate(0deg); }\n  100% { transform: rotate(360deg); }\n}\n\n"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/plugins/nprogress/nprogress.js",
    "content": "/* NProgress, (c) 2013, 2014 Rico Sta. Cruz - http://ricostacruz.com/nprogress\n * @license MIT */\n\n;(function(root, factory) {\n\n  if (typeof define === 'function' && define.amd) {\n    define(factory);\n  } else if (typeof exports === 'object') {\n    module.exports = factory();\n  } else {\n    root.NProgress = factory();\n  }\n\n})(this, function() {\n  var NProgress = {};\n\n  NProgress.version = '0.2.0';\n\n  var Settings = NProgress.settings = {\n    minimum: 0.08,\n    easing: 'ease',\n    positionUsing: '',\n    speed: 200,\n    trickle: true,\n    trickleRate: 0.02,\n    trickleSpeed: 800,\n    showSpinner: true,\n    barSelector: '[role=\"bar\"]',\n    spinnerSelector: '[role=\"spinner\"]',\n    parent: 'body',\n    template: '<div class=\"bar\" role=\"bar\"><div class=\"peg\"></div></div><div class=\"spinner\" role=\"spinner\"><div class=\"spinner-icon\"></div></div>'\n  };\n\n  /**\n   * Updates configuration.\n   *\n   *     NProgress.configure({\n   *       minimum: 0.1\n   *     });\n   */\n  NProgress.configure = function(options) {\n    var key, value;\n    for (key in options) {\n      value = options[key];\n      if (value !== undefined && options.hasOwnProperty(key)) Settings[key] = value;\n    }\n\n    return this;\n  };\n\n  /**\n   * Last number.\n   */\n\n  NProgress.status = null;\n\n  /**\n   * Sets the progress bar status, where `n` is a number from `0.0` to `1.0`.\n   *\n   *     NProgress.set(0.4);\n   *     NProgress.set(1.0);\n   */\n\n  NProgress.set = function(n) {\n    var started = NProgress.isStarted();\n\n    n = clamp(n, Settings.minimum, 1);\n    NProgress.status = (n === 1 ? null : n);\n\n    var progress = NProgress.render(!started),\n        bar      = progress.querySelector(Settings.barSelector),\n        speed    = Settings.speed,\n        ease     = Settings.easing;\n\n    progress.offsetWidth; /* Repaint */\n\n    queue(function(next) {\n      // Set positionUsing if it hasn't already been set\n      if (Settings.positionUsing === '') Settings.positionUsing = NProgress.getPositioningCSS();\n\n      // Add transition\n      css(bar, barPositionCSS(n, speed, ease));\n\n      if (n === 1) {\n        // Fade out\n        css(progress, { \n          transition: 'none', \n          opacity: 1 \n        });\n        progress.offsetWidth; /* Repaint */\n\n        setTimeout(function() {\n          css(progress, { \n            transition: 'all ' + speed + 'ms linear', \n            opacity: 0 \n          });\n          setTimeout(function() {\n            NProgress.remove();\n            next();\n          }, speed);\n        }, speed);\n      } else {\n        setTimeout(next, speed);\n      }\n    });\n\n    return this;\n  };\n\n  NProgress.isStarted = function() {\n    return typeof NProgress.status === 'number';\n  };\n\n  /**\n   * Shows the progress bar.\n   * This is the same as setting the status to 0%, except that it doesn't go backwards.\n   *\n   *     NProgress.start();\n   *\n   */\n  NProgress.start = function() {\n    if (!NProgress.status) NProgress.set(0);\n\n    var work = function() {\n      setTimeout(function() {\n        if (!NProgress.status) return;\n        NProgress.trickle();\n        work();\n      }, Settings.trickleSpeed);\n    };\n\n    if (Settings.trickle) work();\n\n    return this;\n  };\n\n  /**\n   * Hides the progress bar.\n   * This is the *sort of* the same as setting the status to 100%, with the\n   * difference being `done()` makes some placebo effect of some realistic motion.\n   *\n   *     NProgress.done();\n   *\n   * If `true` is passed, it will show the progress bar even if its hidden.\n   *\n   *     NProgress.done(true);\n   */\n\n  NProgress.done = function(force) {\n    if (!force && !NProgress.status) return this;\n\n    return NProgress.inc(0.3 + 0.5 * Math.random()).set(1);\n  };\n\n  /**\n   * Increments by a random amount.\n   */\n\n  NProgress.inc = function(amount) {\n    var n = NProgress.status;\n\n    if (!n) {\n      return NProgress.start();\n    } else {\n      if (typeof amount !== 'number') {\n        amount = (1 - n) * clamp(Math.random() * n, 0.1, 0.95);\n      }\n\n      n = clamp(n + amount, 0, 0.994);\n      return NProgress.set(n);\n    }\n  };\n\n  NProgress.trickle = function() {\n    return NProgress.inc(Math.random() * Settings.trickleRate);\n  };\n\n  /**\n   * Waits for all supplied jQuery promises and\n   * increases the progress as the promises resolve.\n   *\n   * @param $promise jQUery Promise\n   */\n  (function() {\n    var initial = 0, current = 0;\n\n    NProgress.promise = function($promise) {\n      if (!$promise || $promise.state() === \"resolved\") {\n        return this;\n      }\n\n      if (current === 0) {\n        NProgress.start();\n      }\n\n      initial++;\n      current++;\n\n      $promise.always(function() {\n        current--;\n        if (current === 0) {\n            initial = 0;\n            NProgress.done();\n        } else {\n            NProgress.set((initial - current) / initial);\n        }\n      });\n\n      return this;\n    };\n\n  })();\n\n  /**\n   * (Internal) renders the progress bar markup based on the `template`\n   * setting.\n   */\n\n  NProgress.render = function(fromStart) {\n    if (NProgress.isRendered()) return document.getElementById('nprogress');\n\n    addClass(document.documentElement, 'nprogress-busy');\n    \n    var progress = document.createElement('div');\n    progress.id = 'nprogress';\n    progress.innerHTML = Settings.template;\n\n    var bar      = progress.querySelector(Settings.barSelector),\n        perc     = fromStart ? '-100' : toBarPerc(NProgress.status || 0),\n        parent   = document.querySelector(Settings.parent),\n        spinner;\n    \n    css(bar, {\n      transition: 'all 0 linear',\n      transform: 'translate3d(' + perc + '%,0,0)'\n    });\n\n    if (!Settings.showSpinner) {\n      spinner = progress.querySelector(Settings.spinnerSelector);\n      spinner && removeElement(spinner);\n    }\n\n    if (parent != document.body) {\n      addClass(parent, 'nprogress-custom-parent');\n    }\n\n    parent.appendChild(progress);\n    return progress;\n  };\n\n  /**\n   * Removes the element. Opposite of render().\n   */\n\n  NProgress.remove = function() {\n    removeClass(document.documentElement, 'nprogress-busy');\n    removeClass(document.querySelector(Settings.parent), 'nprogress-custom-parent');\n    var progress = document.getElementById('nprogress');\n    progress && removeElement(progress);\n  };\n\n  /**\n   * Checks if the progress bar is rendered.\n   */\n\n  NProgress.isRendered = function() {\n    return !!document.getElementById('nprogress');\n  };\n\n  /**\n   * Determine which positioning CSS rule to use.\n   */\n\n  NProgress.getPositioningCSS = function() {\n    // Sniff on document.body.style\n    var bodyStyle = document.body.style;\n\n    // Sniff prefixes\n    var vendorPrefix = ('WebkitTransform' in bodyStyle) ? 'Webkit' :\n                       ('MozTransform' in bodyStyle) ? 'Moz' :\n                       ('msTransform' in bodyStyle) ? 'ms' :\n                       ('OTransform' in bodyStyle) ? 'O' : '';\n\n    if (vendorPrefix + 'Perspective' in bodyStyle) {\n      // Modern browsers with 3D support, e.g. Webkit, IE10\n      return 'translate3d';\n    } else if (vendorPrefix + 'Transform' in bodyStyle) {\n      // Browsers without 3D support, e.g. IE9\n      return 'translate';\n    } else {\n      // Browsers without translate() support, e.g. IE7-8\n      return 'margin';\n    }\n  };\n\n  /**\n   * Helpers\n   */\n\n  function clamp(n, min, max) {\n    if (n < min) return min;\n    if (n > max) return max;\n    return n;\n  }\n\n  /**\n   * (Internal) converts a percentage (`0..1`) to a bar translateX\n   * percentage (`-100%..0%`).\n   */\n\n  function toBarPerc(n) {\n    return (-1 + n) * 100;\n  }\n\n\n  /**\n   * (Internal) returns the correct CSS for changing the bar's\n   * position given an n percentage, and speed and ease from Settings\n   */\n\n  function barPositionCSS(n, speed, ease) {\n    var barCSS;\n\n    if (Settings.positionUsing === 'translate3d') {\n      barCSS = { transform: 'translate3d('+toBarPerc(n)+'%,0,0)' };\n    } else if (Settings.positionUsing === 'translate') {\n      barCSS = { transform: 'translate('+toBarPerc(n)+'%,0)' };\n    } else {\n      barCSS = { 'margin-left': toBarPerc(n)+'%' };\n    }\n\n    barCSS.transition = 'all '+speed+'ms '+ease;\n\n    return barCSS;\n  }\n\n  /**\n   * (Internal) Queues a function to be executed.\n   */\n\n  var queue = (function() {\n    var pending = [];\n    \n    function next() {\n      var fn = pending.shift();\n      if (fn) {\n        fn(next);\n      }\n    }\n\n    return function(fn) {\n      pending.push(fn);\n      if (pending.length == 1) next();\n    };\n  })();\n\n  /**\n   * (Internal) Applies css properties to an element, similar to the jQuery \n   * css method.\n   *\n   * While this helper does assist with vendor prefixed property names, it \n   * does not perform any manipulation of values prior to setting styles.\n   */\n\n  var css = (function() {\n    var cssPrefixes = [ 'Webkit', 'O', 'Moz', 'ms' ],\n        cssProps    = {};\n\n    function camelCase(string) {\n      return string.replace(/^-ms-/, 'ms-').replace(/-([\\da-z])/gi, function(match, letter) {\n        return letter.toUpperCase();\n      });\n    }\n\n    function getVendorProp(name) {\n      var style = document.body.style;\n      if (name in style) return name;\n\n      var i = cssPrefixes.length,\n          capName = name.charAt(0).toUpperCase() + name.slice(1),\n          vendorName;\n      while (i--) {\n        vendorName = cssPrefixes[i] + capName;\n        if (vendorName in style) return vendorName;\n      }\n\n      return name;\n    }\n\n    function getStyleProp(name) {\n      name = camelCase(name);\n      return cssProps[name] || (cssProps[name] = getVendorProp(name));\n    }\n\n    function applyCss(element, prop, value) {\n      prop = getStyleProp(prop);\n      element.style[prop] = value;\n    }\n\n    return function(element, properties) {\n      var args = arguments,\n          prop, \n          value;\n\n      if (args.length == 2) {\n        for (prop in properties) {\n          value = properties[prop];\n          if (value !== undefined && properties.hasOwnProperty(prop)) applyCss(element, prop, value);\n        }\n      } else {\n        applyCss(element, args[1], args[2]);\n      }\n    }\n  })();\n\n  /**\n   * (Internal) Determines if an element or space separated list of class names contains a class name.\n   */\n\n  function hasClass(element, name) {\n    var list = typeof element == 'string' ? element : classList(element);\n    return list.indexOf(' ' + name + ' ') >= 0;\n  }\n\n  /**\n   * (Internal) Adds a class to an element.\n   */\n\n  function addClass(element, name) {\n    var oldList = classList(element),\n        newList = oldList + name;\n\n    if (hasClass(oldList, name)) return; \n\n    // Trim the opening space.\n    element.className = newList.substring(1);\n  }\n\n  /**\n   * (Internal) Removes a class from an element.\n   */\n\n  function removeClass(element, name) {\n    var oldList = classList(element),\n        newList;\n\n    if (!hasClass(element, name)) return;\n\n    // Replace the class name.\n    newList = oldList.replace(' ' + name + ' ', ' ');\n\n    // Trim the opening and closing spaces.\n    element.className = newList.substring(1, newList.length - 1);\n  }\n\n  /**\n   * (Internal) Gets a space separated list of the class names on the element. \n   * The list is wrapped with a single space on each end to facilitate finding \n   * matches within the list.\n   */\n\n  function classList(element) {\n    return (' ' + (element.className || '') + ' ').replace(/\\s+/gi, ' ');\n  }\n\n  /**\n   * (Internal) Removes an element from the DOM.\n   */\n\n  function removeElement(element) {\n    element && element.parentNode && element.parentNode.removeChild(element);\n  }\n\n  return NProgress;\n});\n\n"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/plugins/zTree/css/metroStyle/metroStyle.css",
    "content": "/*-------------------------------------\nzTree Style\n\nversion:    3.4\nauthor:     Hunter.z\nemail:      hunter.z@263.net\nwebsite:    http://code.google.com/p/jquerytree/\n\n-------------------------------------*/\n\n.ztree * {padding:0; margin:0; font-size:12px; font-family: Verdana, Arial, Helvetica, AppleGothic, sans-serif}\n.ztree {margin:0; padding:5px; color:#333}\n.ztree li{padding:0; margin:0; list-style:none; line-height:17px; text-align:left; white-space:nowrap; outline:0}\n.ztree li ul{ margin:0; padding:0 0 0 18px}\n.ztree li ul.line{ background:url(./img/line_conn.png) 0 0 repeat-y;}\n\n.ztree li a {padding-right:3px; margin:0; cursor:pointer; height:21px; color:#333; background-color: transparent; text-decoration:none; vertical-align:top; display: inline-block}\n.ztree li a:hover {text-decoration:underline}\n.ztree li a.curSelectedNode {padding-top:0px; background-color:#e5e5e5; color:black; height:21px; opacity:0.8;}\n.ztree li a.curSelectedNode_Edit {padding-top:0px; background-color:#e5e5e5; color:black; height:21px; border:1px #666 solid; opacity:0.8;}\n.ztree li a.tmpTargetNode_inner {padding-top:0px; background-color:#aaa; color:white; height:21px; border:1px #666 solid;\n  opacity:0.8; filter:alpha(opacity=80)}\n.ztree li a.tmpTargetNode_prev {}\n.ztree li a.tmpTargetNode_next {}\n.ztree li a input.rename {height:14px; width:80px; padding:0; margin:0;\n  font-size:12px; border:1px #585956 solid; *border:0px}\n.ztree li span {line-height:21px; margin-right:2px}\n.ztree li span.button {line-height:0; margin:0; padding: 0; width:21px; height:21px; display: inline-block; vertical-align:middle;\n  border:0 none; cursor: pointer;outline:none;\n  background-color:transparent; background-repeat:no-repeat; background-attachment: scroll;\n  background-image:url(\"./img/metro.png\"); *background-image:url(\"./img/metro.gif\")}\n\n.ztree li span.button.chk {width:13px; height:13px; margin:0 2px; cursor: auto}\n.ztree li span.button.chk.checkbox_false_full {background-position: -5px -5px;}\n.ztree li span.button.chk.checkbox_false_full_focus {background-position: -5px -26px;}\n.ztree li span.button.chk.checkbox_false_part {background-position: -5px -48px;}\n.ztree li span.button.chk.checkbox_false_part_focus {background-position: -5px -68px;}\n.ztree li span.button.chk.checkbox_false_disable {background-position: -5px -89px;}\n.ztree li span.button.chk.checkbox_true_full {background-position: -26px -5px;}\n.ztree li span.button.chk.checkbox_true_full_focus {background-position: -26px -26px;}\n.ztree li span.button.chk.checkbox_true_part {background-position: -26px -48px;}\n.ztree li span.button.chk.checkbox_true_part_focus {background-position: -26px -68px;}\n.ztree li span.button.chk.checkbox_true_disable {background-position: -26px -89px;}\n.ztree li span.button.chk.radio_false_full {background-position: -47px -5px;}\n.ztree li span.button.chk.radio_false_full_focus {background-position: -47px -26px;}\n.ztree li span.button.chk.radio_false_part {background-position: -47px -47px;}\n.ztree li span.button.chk.radio_false_part_focus {background-position: -47px -68px;}\n.ztree li span.button.chk.radio_false_disable {background-position: -47px -89px;}\n.ztree li span.button.chk.radio_true_full {background-position: -68px -5px;}\n.ztree li span.button.chk.radio_true_full_focus {background-position: -68px -26px;}\n.ztree li span.button.chk.radio_true_part {background-position: -68px -47px;}\n.ztree li span.button.chk.radio_true_part_focus {background-position: -68px -68px;}\n.ztree li span.button.chk.radio_true_disable {background-position: -68px -89px;}\n\n.ztree li span.button.switch {width:21px; height:21px}\n.ztree li span.button.root_open{background-position:-105px -63px}\n.ztree li span.button.root_close{background-position:-126px -63px}\n.ztree li span.button.roots_open{background-position: -105px 0;}\n.ztree li span.button.roots_close{background-position: -126px 0;}\n.ztree li span.button.center_open{background-position: -105px -21px;}\n.ztree li span.button.center_close{background-position: -126px -21px;}\n.ztree li span.button.bottom_open{background-position: -105px -42px;}\n.ztree li span.button.bottom_close{background-position: -126px -42px;}\n.ztree li span.button.noline_open{background-position: -105px -84px;}\n.ztree li span.button.noline_close{background-position: -126px -84px;}\n.ztree li span.button.root_docu{ background:none;}\n.ztree li span.button.roots_docu{background-position: -84px 0;}\n.ztree li span.button.center_docu{background-position: -84px -21px;}\n.ztree li span.button.bottom_docu{background-position: -84px -42px;}\n.ztree li span.button.noline_docu{ background:none;}\n\n.ztree li span.button.ico_open{margin-right:2px; background-position: -147px -21px; vertical-align:top; *vertical-align:middle}\n.ztree li span.button.ico_close{margin-right:2px; margin-right:2px; background-position: -147px 0; vertical-align:top; *vertical-align:middle}\n.ztree li span.button.ico_docu{margin-right:2px; background-position: -147px -42px; vertical-align:top; *vertical-align:middle}\n.ztree li span.button.edit {margin-left:2px; margin-right: -1px; background-position: -189px -21px; vertical-align:top; *vertical-align:middle}\n.ztree li span.button.edit:hover {\n  background-position: -168px -21px;\n}\n.ztree li span.button.remove {margin-left:2px; margin-right: -1px; background-position: -189px -42px; vertical-align:top; *vertical-align:middle}\n.ztree li span.button.remove:hover {\n  background-position: -168px -42px;\n}\n.ztree li span.button.add {margin-left:2px; margin-right: -1px; background-position: -189px 0; vertical-align:top; *vertical-align:middle}\n.ztree li span.button.add:hover {\n  background-position: -168px 0;\n}\n.ztree li span.button.ico_loading{margin-right:2px; background:url(./img/loading.gif) no-repeat scroll 0 0 transparent; vertical-align:top; *vertical-align:middle}\n\nul.tmpTargetzTree {background-color:#FFE6B0; opacity:0.8; filter:alpha(opacity=80)}\n\nspan.tmpzTreeMove_arrow {width:16px; height:21px; display: inline-block; padding:0; margin:2px 0 0 1px; border:0 none; position:absolute;\n    background-color:transparent; background-repeat:no-repeat; background-attachment: scroll;\n    background-position:-168px -84px; background-image:url(\"./img/metro.png\"); *background-image:url(\"./img/metro.gif\")}\n\nul.ztree.zTreeDragUL {margin:0; padding:0; position:absolute; width:auto; height:auto;overflow:hidden; background-color:#cfcfcf; border:1px #00B83F dotted; opacity:0.8; filter:alpha(opacity=80)}\n.ztreeMask {z-index:10000; background-color:#cfcfcf; opacity:0.0; filter:alpha(opacity=0); position:absolute}\n"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/plugins/zTree/js/jquery.ztree.core.js",
    "content": "/*\n * JQuery zTree core\n * v3.5.48\n * http://treejs.cn/\n *\n * Copyright (c) 2010 Hunter.z\n *\n * Licensed same as jquery - MIT License\n * http://www.opensource.org/licenses/mit-license.php\n *\n * Date: 2020-11-21\n */\n\n(function ($) {\n  var settings = {}, roots = {}, caches = {},\n    //default consts of core\n    _consts = {\n      className: {\n        BUTTON: \"button\",\n        LEVEL: \"level\",\n        ICO_LOADING: \"ico_loading\",\n        SWITCH: \"switch\",\n        NAME: 'node_name'\n      },\n      event: {\n        NODECREATED: \"ztree_nodeCreated\",\n        CLICK: \"ztree_click\",\n        EXPAND: \"ztree_expand\",\n        COLLAPSE: \"ztree_collapse\",\n        ASYNC_SUCCESS: \"ztree_async_success\",\n        ASYNC_ERROR: \"ztree_async_error\",\n        REMOVE: \"ztree_remove\",\n        SELECTED: \"ztree_selected\",\n        UNSELECTED: \"ztree_unselected\"\n      },\n      id: {\n        A: \"_a\",\n        ICON: \"_ico\",\n        SPAN: \"_span\",\n        SWITCH: \"_switch\",\n        UL: \"_ul\"\n      },\n      line: {\n        ROOT: \"root\",\n        ROOTS: \"roots\",\n        CENTER: \"center\",\n        BOTTOM: \"bottom\",\n        NOLINE: \"noline\",\n        LINE: \"line\"\n      },\n      folder: {\n        OPEN: \"open\",\n        CLOSE: \"close\",\n        DOCU: \"docu\"\n      },\n      node: {\n        CURSELECTED: \"curSelectedNode\"\n      }\n    },\n    //default setting of core\n    _setting = {\n      treeId: \"\",\n      treeObj: null,\n      view: {\n        addDiyDom: null,\n        autoCancelSelected: true,\n        dblClickExpand: true,\n        expandSpeed: \"fast\",\n        fontCss: {},\n        nodeClasses: {},\n        nameIsHTML: false,\n        selectedMulti: true,\n        showIcon: true,\n        showLine: true,\n        showTitle: true,\n        txtSelectedEnable: false\n      },\n      data: {\n        key: {\n          isParent: \"isParent\",\n          children: \"children\",\n          name: \"name\",\n          title: \"\",\n          url: \"url\",\n          icon: \"icon\"\n        },\n        render: {\n          name: null,\n          title: null,\n        },\n        simpleData: {\n          enable: false,\n          idKey: \"id\",\n          pIdKey: \"pId\",\n          rootPId: null\n        },\n        keep: {\n          parent: false,\n          leaf: false\n        }\n      },\n      async: {\n        enable: false,\n        contentType: \"application/x-www-form-urlencoded\",\n        type: \"post\",\n        dataType: \"text\",\n        headers: {},\n        xhrFields: {},\n        url: \"\",\n        autoParam: [],\n        otherParam: [],\n        dataFilter: null\n      },\n      callback: {\n        beforeAsync: null,\n        beforeClick: null,\n        beforeDblClick: null,\n        beforeRightClick: null,\n        beforeMouseDown: null,\n        beforeMouseUp: null,\n        beforeExpand: null,\n        beforeCollapse: null,\n        beforeRemove: null,\n\n        onAsyncError: null,\n        onAsyncSuccess: null,\n        onNodeCreated: null,\n        onClick: null,\n        onDblClick: null,\n        onRightClick: null,\n        onMouseDown: null,\n        onMouseUp: null,\n        onExpand: null,\n        onCollapse: null,\n        onRemove: null\n      }\n    },\n    //default root of core\n    //zTree use root to save full data\n    _initRoot = function (setting) {\n      var r = data.getRoot(setting);\n      if (!r) {\n        r = {};\n        data.setRoot(setting, r);\n      }\n      data.nodeChildren(setting, r, []);\n      r.expandTriggerFlag = false;\n      r.curSelectedList = [];\n      r.noSelection = true;\n      r.createdNodes = [];\n      r.zId = 0;\n      r._ver = (new Date()).getTime();\n    },\n    //default cache of core\n    _initCache = function (setting) {\n      var c = data.getCache(setting);\n      if (!c) {\n        c = {};\n        data.setCache(setting, c);\n      }\n      c.nodes = [];\n      c.doms = [];\n    },\n    //default bindEvent of core\n    _bindEvent = function (setting) {\n      var o = setting.treeObj,\n        c = consts.event;\n      o.bind(c.NODECREATED, function (event, treeId, node) {\n        tools.apply(setting.callback.onNodeCreated, [event, treeId, node]);\n      });\n\n      o.bind(c.CLICK, function (event, srcEvent, treeId, node, clickFlag) {\n        tools.apply(setting.callback.onClick, [srcEvent, treeId, node, clickFlag]);\n      });\n\n      o.bind(c.EXPAND, function (event, treeId, node) {\n        tools.apply(setting.callback.onExpand, [event, treeId, node]);\n      });\n\n      o.bind(c.COLLAPSE, function (event, treeId, node) {\n        tools.apply(setting.callback.onCollapse, [event, treeId, node]);\n      });\n\n      o.bind(c.ASYNC_SUCCESS, function (event, treeId, node, msg) {\n        tools.apply(setting.callback.onAsyncSuccess, [event, treeId, node, msg]);\n      });\n\n      o.bind(c.ASYNC_ERROR, function (event, treeId, node, XMLHttpRequest, textStatus, errorThrown) {\n        tools.apply(setting.callback.onAsyncError, [event, treeId, node, XMLHttpRequest, textStatus, errorThrown]);\n      });\n\n      o.bind(c.REMOVE, function (event, treeId, treeNode) {\n        tools.apply(setting.callback.onRemove, [event, treeId, treeNode]);\n      });\n\n      o.bind(c.SELECTED, function (event, treeId, node) {\n        tools.apply(setting.callback.onSelected, [treeId, node]);\n      });\n      o.bind(c.UNSELECTED, function (event, treeId, node) {\n        tools.apply(setting.callback.onUnSelected, [treeId, node]);\n      });\n    },\n    _unbindEvent = function (setting) {\n      var o = setting.treeObj,\n        c = consts.event;\n      o.unbind(c.NODECREATED)\n        .unbind(c.CLICK)\n        .unbind(c.EXPAND)\n        .unbind(c.COLLAPSE)\n        .unbind(c.ASYNC_SUCCESS)\n        .unbind(c.ASYNC_ERROR)\n        .unbind(c.REMOVE)\n        .unbind(c.SELECTED)\n        .unbind(c.UNSELECTED);\n    },\n    //default event proxy of core\n    _eventProxy = function (event) {\n      var target = event.target,\n        setting = data.getSetting(event.data.treeId),\n        tId = \"\", node = null,\n        nodeEventType = \"\", treeEventType = \"\",\n        nodeEventCallback = null, treeEventCallback = null,\n        tmp = null;\n\n      if (tools.eqs(event.type, \"mousedown\")) {\n        treeEventType = \"mousedown\";\n      } else if (tools.eqs(event.type, \"mouseup\")) {\n        treeEventType = \"mouseup\";\n      } else if (tools.eqs(event.type, \"contextmenu\")) {\n        treeEventType = \"contextmenu\";\n      } else if (tools.eqs(event.type, \"click\")) {\n        if (tools.eqs(target.tagName, \"span\") && target.getAttribute(\"treeNode\" + consts.id.SWITCH) !== null) {\n          tId = tools.getNodeMainDom(target).id;\n          nodeEventType = \"switchNode\";\n        } else {\n          tmp = tools.getMDom(setting, target, [{tagName: \"a\", attrName: \"treeNode\" + consts.id.A}]);\n          if (tmp) {\n            tId = tools.getNodeMainDom(tmp).id;\n            nodeEventType = \"clickNode\";\n          }\n        }\n      } else if (tools.eqs(event.type, \"dblclick\")) {\n        treeEventType = \"dblclick\";\n        tmp = tools.getMDom(setting, target, [{tagName: \"a\", attrName: \"treeNode\" + consts.id.A}]);\n        if (tmp) {\n          tId = tools.getNodeMainDom(tmp).id;\n          nodeEventType = \"switchNode\";\n        }\n      }\n      if (treeEventType.length > 0 && tId.length == 0) {\n        tmp = tools.getMDom(setting, target, [{tagName: \"a\", attrName: \"treeNode\" + consts.id.A}]);\n        if (tmp) {\n          tId = tools.getNodeMainDom(tmp).id;\n        }\n      }\n      // event to node\n      if (tId.length > 0) {\n        node = data.getNodeCache(setting, tId);\n        switch (nodeEventType) {\n          case \"switchNode\" :\n            var isParent = data.nodeIsParent(setting, node);\n            if (!isParent) {\n              nodeEventType = \"\";\n            } else if (tools.eqs(event.type, \"click\")\n              || (tools.eqs(event.type, \"dblclick\") && tools.apply(setting.view.dblClickExpand, [setting.treeId, node], setting.view.dblClickExpand))) {\n              nodeEventCallback = handler.onSwitchNode;\n            } else {\n              nodeEventType = \"\";\n            }\n            break;\n          case \"clickNode\" :\n            nodeEventCallback = handler.onClickNode;\n            break;\n        }\n      }\n      // event to zTree\n      switch (treeEventType) {\n        case \"mousedown\" :\n          treeEventCallback = handler.onZTreeMousedown;\n          break;\n        case \"mouseup\" :\n          treeEventCallback = handler.onZTreeMouseup;\n          break;\n        case \"dblclick\" :\n          treeEventCallback = handler.onZTreeDblclick;\n          break;\n        case \"contextmenu\" :\n          treeEventCallback = handler.onZTreeContextmenu;\n          break;\n      }\n      var proxyResult = {\n        stop: false,\n        node: node,\n        nodeEventType: nodeEventType,\n        nodeEventCallback: nodeEventCallback,\n        treeEventType: treeEventType,\n        treeEventCallback: treeEventCallback\n      };\n      return proxyResult\n    },\n    //default init node of core\n    _initNode = function (setting, level, n, parentNode, isFirstNode, isLastNode, openFlag) {\n      if (!n) return;\n      var r = data.getRoot(setting),\n        children = data.nodeChildren(setting, n);\n      n.level = level;\n      n.tId = setting.treeId + \"_\" + (++r.zId);\n      n.parentTId = parentNode ? parentNode.tId : null;\n      n.open = (typeof n.open == \"string\") ? tools.eqs(n.open, \"true\") : !!n.open;\n      var isParent = data.nodeIsParent(setting, n);\n      if (tools.isArray(children)) {\n        data.nodeIsParent(setting, n, true);\n        n.zAsync = true;\n      } else {\n        isParent = data.nodeIsParent(setting, n, isParent);\n        n.open = (isParent && !setting.async.enable) ? n.open : false;\n        n.zAsync = !isParent;\n      }\n      n.isFirstNode = isFirstNode;\n      n.isLastNode = isLastNode;\n      n.getParentNode = function () {\n        return data.getNodeCache(setting, n.parentTId);\n      };\n      n.getPreNode = function () {\n        return data.getPreNode(setting, n);\n      };\n      n.getNextNode = function () {\n        return data.getNextNode(setting, n);\n      };\n      n.getIndex = function () {\n        return data.getNodeIndex(setting, n);\n      };\n      n.getPath = function () {\n        return data.getNodePath(setting, n);\n      };\n      n.isAjaxing = false;\n      data.fixPIdKeyValue(setting, n);\n    },\n    _init = {\n      bind: [_bindEvent],\n      unbind: [_unbindEvent],\n      caches: [_initCache],\n      nodes: [_initNode],\n      proxys: [_eventProxy],\n      roots: [_initRoot],\n      beforeA: [],\n      afterA: [],\n      innerBeforeA: [],\n      innerAfterA: [],\n      zTreeTools: []\n    },\n    //method of operate data\n    data = {\n      addNodeCache: function (setting, node) {\n        data.getCache(setting).nodes[data.getNodeCacheId(node.tId)] = node;\n      },\n      getNodeCacheId: function (tId) {\n        return tId.substring(tId.lastIndexOf(\"_\") + 1);\n      },\n      addAfterA: function (afterA) {\n        _init.afterA.push(afterA);\n      },\n      addBeforeA: function (beforeA) {\n        _init.beforeA.push(beforeA);\n      },\n      addInnerAfterA: function (innerAfterA) {\n        _init.innerAfterA.push(innerAfterA);\n      },\n      addInnerBeforeA: function (innerBeforeA) {\n        _init.innerBeforeA.push(innerBeforeA);\n      },\n      addInitBind: function (bindEvent) {\n        _init.bind.push(bindEvent);\n      },\n      addInitUnBind: function (unbindEvent) {\n        _init.unbind.push(unbindEvent);\n      },\n      addInitCache: function (initCache) {\n        _init.caches.push(initCache);\n      },\n      addInitNode: function (initNode) {\n        _init.nodes.push(initNode);\n      },\n      addInitProxy: function (initProxy, isFirst) {\n        if (!!isFirst) {\n          _init.proxys.splice(0, 0, initProxy);\n        } else {\n          _init.proxys.push(initProxy);\n        }\n      },\n      addInitRoot: function (initRoot) {\n        _init.roots.push(initRoot);\n      },\n      addNodesData: function (setting, parentNode, index, nodes) {\n        var children = data.nodeChildren(setting, parentNode), params;\n        if (!children) {\n          children = data.nodeChildren(setting, parentNode, []);\n          index = -1;\n        } else if (index >= children.length) {\n          index = -1;\n        }\n\n        if (children.length > 0 && index === 0) {\n          children[0].isFirstNode = false;\n          view.setNodeLineIcos(setting, children[0]);\n        } else if (children.length > 0 && index < 0) {\n          children[children.length - 1].isLastNode = false;\n          view.setNodeLineIcos(setting, children[children.length - 1]);\n        }\n        data.nodeIsParent(setting, parentNode, true);\n\n        if (index < 0) {\n          data.nodeChildren(setting, parentNode, children.concat(nodes));\n        } else {\n          params = [index, 0].concat(nodes);\n          children.splice.apply(children, params);\n        }\n      },\n      addSelectedNode: function (setting, node) {\n        var root = data.getRoot(setting);\n        if (!data.isSelectedNode(setting, node)) {\n          root.curSelectedList.push(node);\n        }\n      },\n      addCreatedNode: function (setting, node) {\n        if (!!setting.callback.onNodeCreated || !!setting.view.addDiyDom) {\n          var root = data.getRoot(setting);\n          root.createdNodes.push(node);\n        }\n      },\n      addZTreeTools: function (zTreeTools) {\n        _init.zTreeTools.push(zTreeTools);\n      },\n      exSetting: function (s) {\n        $.extend(true, _setting, s);\n      },\n      fixPIdKeyValue: function (setting, node) {\n        if (setting.data.simpleData.enable) {\n          node[setting.data.simpleData.pIdKey] = node.parentTId ? node.getParentNode()[setting.data.simpleData.idKey] : setting.data.simpleData.rootPId;\n        }\n      },\n      getAfterA: function (setting, node, array) {\n        for (var i = 0, j = _init.afterA.length; i < j; i++) {\n          _init.afterA[i].apply(this, arguments);\n        }\n      },\n      getBeforeA: function (setting, node, array) {\n        for (var i = 0, j = _init.beforeA.length; i < j; i++) {\n          _init.beforeA[i].apply(this, arguments);\n        }\n      },\n      getInnerAfterA: function (setting, node, array) {\n        for (var i = 0, j = _init.innerAfterA.length; i < j; i++) {\n          _init.innerAfterA[i].apply(this, arguments);\n        }\n      },\n      getInnerBeforeA: function (setting, node, array) {\n        for (var i = 0, j = _init.innerBeforeA.length; i < j; i++) {\n          _init.innerBeforeA[i].apply(this, arguments);\n        }\n      },\n      getCache: function (setting) {\n        return caches[setting.treeId];\n      },\n      getNodeIndex: function (setting, node) {\n        if (!node) return null;\n        var p = node.parentTId ? node.getParentNode() : data.getRoot(setting),\n          children = data.nodeChildren(setting, p);\n        for (var i = 0, l = children.length - 1; i <= l; i++) {\n          if (children[i] === node) {\n            return i;\n          }\n        }\n        return -1;\n      },\n      getNextNode: function (setting, node) {\n        if (!node) return null;\n        var p = node.parentTId ? node.getParentNode() : data.getRoot(setting),\n          children = data.nodeChildren(setting, p);\n        for (var i = 0, l = children.length - 1; i <= l; i++) {\n          if (children[i] === node) {\n            return (i == l ? null : children[i + 1]);\n          }\n        }\n        return null;\n      },\n      getNodeByParam: function (setting, nodes, key, value) {\n        if (!nodes || !key) return null;\n        for (var i = 0, l = nodes.length; i < l; i++) {\n          var node = nodes[i];\n          if (node[key] == value) {\n            return nodes[i];\n          }\n          var children = data.nodeChildren(setting, node);\n          var tmp = data.getNodeByParam(setting, children, key, value);\n          if (tmp) return tmp;\n        }\n        return null;\n      },\n      getNodeCache: function (setting, tId) {\n        if (!tId) return null;\n        var n = caches[setting.treeId].nodes[data.getNodeCacheId(tId)];\n        return n ? n : null;\n      },\n      getNodePath: function (setting, node) {\n        if (!node) return null;\n\n        var path;\n        if (node.parentTId) {\n          path = node.getParentNode().getPath();\n        } else {\n          path = [];\n        }\n\n        if (path) {\n          path.push(node);\n        }\n\n        return path;\n      },\n      getNodes: function (setting) {\n        return data.nodeChildren(setting, data.getRoot(setting));\n      },\n      getNodesByParam: function (setting, nodes, key, value) {\n        if (!nodes || !key) return [];\n        var result = [];\n        for (var i = 0, l = nodes.length; i < l; i++) {\n          var node = nodes[i];\n          if (node[key] == value) {\n            result.push(node);\n          }\n          var children = data.nodeChildren(setting, node);\n          result = result.concat(data.getNodesByParam(setting, children, key, value));\n        }\n        return result;\n      },\n      getNodesByParamFuzzy: function (setting, nodes, key, value) {\n        if (!nodes || !key) return [];\n        var result = [];\n        value = value.toLowerCase();\n        for (var i = 0, l = nodes.length; i < l; i++) {\n          var node = nodes[i];\n          if (typeof node[key] == \"string\" && nodes[i][key].toLowerCase().indexOf(value) > -1) {\n            result.push(node);\n          }\n          var children = data.nodeChildren(setting, node);\n          result = result.concat(data.getNodesByParamFuzzy(setting, children, key, value));\n        }\n        return result;\n      },\n      getNodesByFilter: function (setting, nodes, filter, isSingle, invokeParam) {\n        if (!nodes) return (isSingle ? null : []);\n        var result = isSingle ? null : [];\n        for (var i = 0, l = nodes.length; i < l; i++) {\n          var node = nodes[i];\n          if (tools.apply(filter, [node, invokeParam], false)) {\n            if (isSingle) {\n              return node;\n            }\n            result.push(node);\n          }\n          var children = data.nodeChildren(setting, node);\n          var tmpResult = data.getNodesByFilter(setting, children, filter, isSingle, invokeParam);\n          if (isSingle && !!tmpResult) {\n            return tmpResult;\n          }\n          result = isSingle ? tmpResult : result.concat(tmpResult);\n        }\n        return result;\n      },\n      getPreNode: function (setting, node) {\n        if (!node) return null;\n        var p = node.parentTId ? node.getParentNode() : data.getRoot(setting),\n          children = data.nodeChildren(setting, p);\n        for (var i = 0, l = children.length; i < l; i++) {\n          if (children[i] === node) {\n            return (i == 0 ? null : children[i - 1]);\n          }\n        }\n        return null;\n      },\n      getRoot: function (setting) {\n        return setting ? roots[setting.treeId] : null;\n      },\n      getRoots: function () {\n        return roots;\n      },\n      getSetting: function (treeId) {\n        return settings[treeId];\n      },\n      getSettings: function () {\n        return settings;\n      },\n      getZTreeTools: function (treeId) {\n        var r = this.getRoot(this.getSetting(treeId));\n        return r ? r.treeTools : null;\n      },\n      initCache: function (setting) {\n        for (var i = 0, j = _init.caches.length; i < j; i++) {\n          _init.caches[i].apply(this, arguments);\n        }\n      },\n      initNode: function (setting, level, node, parentNode, preNode, nextNode) {\n        for (var i = 0, j = _init.nodes.length; i < j; i++) {\n          _init.nodes[i].apply(this, arguments);\n        }\n      },\n      initRoot: function (setting) {\n        for (var i = 0, j = _init.roots.length; i < j; i++) {\n          _init.roots[i].apply(this, arguments);\n        }\n      },\n      isSelectedNode: function (setting, node) {\n        var root = data.getRoot(setting);\n        for (var i = 0, j = root.curSelectedList.length; i < j; i++) {\n          if (node === root.curSelectedList[i]) return true;\n        }\n        return false;\n      },\n      nodeChildren: function (setting, node, newChildren) {\n        if (!node) {\n          return null;\n        }\n        var key = setting.data.key.children;\n        if (typeof newChildren !== 'undefined') {\n          node[key] = newChildren;\n        }\n        return node[key];\n      },\n      nodeIsParent: function (setting, node, newIsParent) {\n        if (!node) {\n          return false;\n        }\n        var key = setting.data.key.isParent;\n        if (typeof newIsParent !== 'undefined') {\n          if (typeof newIsParent === \"string\") {\n            newIsParent = tools.eqs(newIsParent, \"true\");\n          }\n          newIsParent = !!newIsParent;\n          node[key] = newIsParent;\n        } else if (typeof node[key] == \"string\"){\n          node[key] = tools.eqs(node[key], \"true\");\n        } else {\n          node[key] = !!node[key];\n        }\n        return node[key];\n      },\n      nodeName: function (setting, node, newName) {\n        var key = setting.data.key.name;\n        if (typeof newName !== 'undefined') {\n          node[key] = newName;\n        }\n        var rawName = \"\" + node[key];\n        if(typeof setting.data.render.name === 'function') {\n          return setting.data.render.name.call(this,rawName,node);\n        }\n        return rawName;\n      },\n      nodeTitle: function (setting, node) {\n        var t = setting.data.key.title === \"\" ? setting.data.key.name : setting.data.key.title;\n        var rawTitle = \"\" + node[t];\n        if(typeof setting.data.render.title === 'function') {\n          return setting.data.render.title.call(this,rawTitle,node);\n        }\n        return rawTitle;\n      },\n      removeNodeCache: function (setting, node) {\n        var children = data.nodeChildren(setting, node);\n        if (children) {\n          for (var i = 0, l = children.length; i < l; i++) {\n            data.removeNodeCache(setting, children[i]);\n          }\n        }\n        data.getCache(setting).nodes[data.getNodeCacheId(node.tId)] = null;\n      },\n      removeSelectedNode: function (setting, node) {\n        var root = data.getRoot(setting);\n        for (var i = 0, j = root.curSelectedList.length; i < j; i++) {\n          if (node === root.curSelectedList[i] || !data.getNodeCache(setting, root.curSelectedList[i].tId)) {\n            root.curSelectedList.splice(i, 1);\n            setting.treeObj.trigger(consts.event.UNSELECTED, [setting.treeId, node]);\n            i--;\n            j--;\n          }\n        }\n      },\n      setCache: function (setting, cache) {\n        caches[setting.treeId] = cache;\n      },\n      setRoot: function (setting, root) {\n        roots[setting.treeId] = root;\n      },\n      setZTreeTools: function (setting, zTreeTools) {\n        for (var i = 0, j = _init.zTreeTools.length; i < j; i++) {\n          _init.zTreeTools[i].apply(this, arguments);\n        }\n      },\n      transformToArrayFormat: function (setting, nodes) {\n        if (!nodes) return [];\n        var r = [];\n        if (tools.isArray(nodes)) {\n          for (var i = 0, l = nodes.length; i < l; i++) {\n            var node = nodes[i];\n            _do(node);\n          }\n        } else {\n          _do(nodes);\n        }\n        return r;\n\n        function _do(_node) {\n          r.push(_node);\n          var children = data.nodeChildren(setting, _node);\n          if (children) {\n            r = r.concat(data.transformToArrayFormat(setting, children));\n          }\n        }\n      },\n      transformTozTreeFormat: function (setting, sNodes) {\n        var i, l,\n          key = setting.data.simpleData.idKey,\n          parentKey = setting.data.simpleData.pIdKey;\n        if (!key || key == \"\" || !sNodes) return [];\n\n        if (tools.isArray(sNodes)) {\n          var r = [];\n          var tmpMap = {};\n          for (i = 0, l = sNodes.length; i < l; i++) {\n            tmpMap[sNodes[i][key]] = sNodes[i];\n          }\n          for (i = 0, l = sNodes.length; i < l; i++) {\n            var p = tmpMap[sNodes[i][parentKey]];\n            if (p && sNodes[i][key] != sNodes[i][parentKey]) {\n              var children = data.nodeChildren(setting, p);\n              if (!children) {\n                children = data.nodeChildren(setting, p, []);\n              }\n              children.push(sNodes[i]);\n            } else {\n              r.push(sNodes[i]);\n            }\n          }\n          return r;\n        } else {\n          return [sNodes];\n        }\n      }\n    },\n    //method of event proxy\n    event = {\n      bindEvent: function (setting) {\n        for (var i = 0, j = _init.bind.length; i < j; i++) {\n          _init.bind[i].apply(this, arguments);\n        }\n      },\n      unbindEvent: function (setting) {\n        for (var i = 0, j = _init.unbind.length; i < j; i++) {\n          _init.unbind[i].apply(this, arguments);\n        }\n      },\n      bindTree: function (setting) {\n        var eventParam = {\n            treeId: setting.treeId\n          },\n          o = setting.treeObj;\n        if (!setting.view.txtSelectedEnable) {\n          // for can't select text\n          o.bind('selectstart', handler.onSelectStart).css({\n            \"-moz-user-select\": \"-moz-none\"\n          });\n        }\n        o.bind('click', eventParam, event.proxy);\n        o.bind('dblclick', eventParam, event.proxy);\n        o.bind('mouseover', eventParam, event.proxy);\n        o.bind('mouseout', eventParam, event.proxy);\n        o.bind('mousedown', eventParam, event.proxy);\n        o.bind('mouseup', eventParam, event.proxy);\n        o.bind('contextmenu', eventParam, event.proxy);\n      },\n      unbindTree: function (setting) {\n        var o = setting.treeObj;\n        o.unbind('selectstart', handler.onSelectStart)\n          .unbind('click', event.proxy)\n          .unbind('dblclick', event.proxy)\n          .unbind('mouseover', event.proxy)\n          .unbind('mouseout', event.proxy)\n          .unbind('mousedown', event.proxy)\n          .unbind('mouseup', event.proxy)\n          .unbind('contextmenu', event.proxy);\n      },\n      doProxy: function (e) {\n        var results = [];\n        for (var i = 0, j = _init.proxys.length; i < j; i++) {\n          var proxyResult = _init.proxys[i].apply(this, arguments);\n          results.push(proxyResult);\n          if (proxyResult.stop) {\n            break;\n          }\n        }\n        return results;\n      },\n      proxy: function (e) {\n        var setting = data.getSetting(e.data.treeId);\n        if (!tools.uCanDo(setting, e)) return true;\n        var results = event.doProxy(e),\n          r = true, x = false;\n        for (var i = 0, l = results.length; i < l; i++) {\n          var proxyResult = results[i];\n          if (proxyResult.nodeEventCallback) {\n            x = true;\n            r = proxyResult.nodeEventCallback.apply(proxyResult, [e, proxyResult.node]) && r;\n          }\n          if (proxyResult.treeEventCallback) {\n            x = true;\n            r = proxyResult.treeEventCallback.apply(proxyResult, [e, proxyResult.node]) && r;\n          }\n        }\n        return r;\n      }\n    },\n    //method of event handler\n    handler = {\n      onSwitchNode: function (event, node) {\n        var setting = data.getSetting(event.data.treeId);\n        if (node.open) {\n          if (tools.apply(setting.callback.beforeCollapse, [setting.treeId, node], true) == false) return true;\n          data.getRoot(setting).expandTriggerFlag = true;\n          view.switchNode(setting, node);\n        } else {\n          if (tools.apply(setting.callback.beforeExpand, [setting.treeId, node], true) == false) return true;\n          data.getRoot(setting).expandTriggerFlag = true;\n          view.switchNode(setting, node);\n        }\n        return true;\n      },\n      onClickNode: function (event, node) {\n        var setting = data.getSetting(event.data.treeId),\n          clickFlag = ((setting.view.autoCancelSelected && (event.ctrlKey || event.metaKey)) && data.isSelectedNode(setting, node)) ? 0 : (setting.view.autoCancelSelected && (event.ctrlKey || event.metaKey) && setting.view.selectedMulti) ? 2 : 1;\n        if (tools.apply(setting.callback.beforeClick, [setting.treeId, node, clickFlag], true) == false) return true;\n        if (clickFlag === 0) {\n          view.cancelPreSelectedNode(setting, node);\n        } else {\n          view.selectNode(setting, node, clickFlag === 2);\n        }\n        setting.treeObj.trigger(consts.event.CLICK, [event, setting.treeId, node, clickFlag]);\n        return true;\n      },\n      onZTreeMousedown: function (event, node) {\n        var setting = data.getSetting(event.data.treeId);\n        if (tools.apply(setting.callback.beforeMouseDown, [setting.treeId, node], true)) {\n          tools.apply(setting.callback.onMouseDown, [event, setting.treeId, node]);\n        }\n        return true;\n      },\n      onZTreeMouseup: function (event, node) {\n        var setting = data.getSetting(event.data.treeId);\n        if (tools.apply(setting.callback.beforeMouseUp, [setting.treeId, node], true)) {\n          tools.apply(setting.callback.onMouseUp, [event, setting.treeId, node]);\n        }\n        return true;\n      },\n      onZTreeDblclick: function (event, node) {\n        var setting = data.getSetting(event.data.treeId);\n        if (tools.apply(setting.callback.beforeDblClick, [setting.treeId, node], true)) {\n          tools.apply(setting.callback.onDblClick, [event, setting.treeId, node]);\n        }\n        return true;\n      },\n      onZTreeContextmenu: function (event, node) {\n        var setting = data.getSetting(event.data.treeId);\n        if (tools.apply(setting.callback.beforeRightClick, [setting.treeId, node], true)) {\n          tools.apply(setting.callback.onRightClick, [event, setting.treeId, node]);\n        }\n        return (typeof setting.callback.onRightClick) != \"function\";\n      },\n      onSelectStart: function (e) {\n        var n = e.originalEvent.srcElement.nodeName.toLowerCase();\n        return (n === \"input\" || n === \"textarea\");\n      }\n    },\n    //method of tools for zTree\n    tools = {\n      apply: function (fun, param, defaultValue) {\n        if ((typeof fun) == \"function\") {\n          return fun.apply(zt, param ? param : []);\n        }\n        return defaultValue;\n      },\n      canAsync: function (setting, node) {\n        var children = data.nodeChildren(setting, node);\n        var isParent = data.nodeIsParent(setting, node);\n        return (setting.async.enable && node && isParent && !(node.zAsync || (children && children.length > 0)));\n      },\n      clone: function (obj) {\n        if (obj === null) return null;\n        var o = tools.isArray(obj) ? [] : {};\n        for (var i in obj) {\n          o[i] = (obj[i] instanceof Date) ? new Date(obj[i].getTime()) : (typeof obj[i] === \"object\" ? tools.clone(obj[i]) : obj[i]);\n        }\n        return o;\n      },\n      eqs: function (str1, str2) {\n        return str1.toLowerCase() === str2.toLowerCase();\n      },\n      isArray: function (arr) {\n        return Object.prototype.toString.apply(arr) === \"[object Array]\";\n      },\n      isElement: function (o) {\n        return (\n          typeof HTMLElement === \"object\" ? o instanceof HTMLElement : //DOM2\n            o && typeof o === \"object\" && o !== null && o.nodeType === 1 && typeof o.nodeName === \"string\"\n        );\n      },\n      $: function (node, exp, setting) {\n        if (!!exp && typeof exp != \"string\") {\n          setting = exp;\n          exp = \"\";\n        }\n        if (typeof node == \"string\") {\n          return $(node, setting ? setting.treeObj.get(0).ownerDocument : null);\n        } else {\n          return $(\"#\" + node.tId + exp, setting ? setting.treeObj : null);\n        }\n      },\n      getMDom: function (setting, curDom, targetExpr) {\n        if (!curDom) return null;\n        while (curDom && curDom.id !== setting.treeId) {\n          for (var i = 0, l = targetExpr.length; curDom.tagName && i < l; i++) {\n            if (tools.eqs(curDom.tagName, targetExpr[i].tagName) && curDom.getAttribute(targetExpr[i].attrName) !== null) {\n              return curDom;\n            }\n          }\n          curDom = curDom.parentNode;\n        }\n        return null;\n      },\n      getNodeMainDom: function (target) {\n        return ($(target).parent(\"li\").get(0) || $(target).parentsUntil(\"li\").parent().get(0));\n      },\n      isChildOrSelf: function (dom, parentId) {\n        return ($(dom).closest(\"#\" + parentId).length > 0);\n      },\n      uCanDo: function (setting, e) {\n        return true;\n      }\n    },\n    //method of operate ztree dom\n    view = {\n      addNodes: function (setting, parentNode, index, newNodes, isSilent) {\n        var isParent = data.nodeIsParent(setting, parentNode);\n        if (setting.data.keep.leaf && parentNode && !isParent) {\n          return;\n        }\n        if (!tools.isArray(newNodes)) {\n          newNodes = [newNodes];\n        }\n        if (setting.data.simpleData.enable) {\n          newNodes = data.transformTozTreeFormat(setting, newNodes);\n        }\n        if (parentNode) {\n          var target_switchObj = $$(parentNode, consts.id.SWITCH, setting),\n            target_icoObj = $$(parentNode, consts.id.ICON, setting),\n            target_ulObj = $$(parentNode, consts.id.UL, setting);\n\n          if (!parentNode.open) {\n            view.replaceSwitchClass(parentNode, target_switchObj, consts.folder.CLOSE);\n            view.replaceIcoClass(parentNode, target_icoObj, consts.folder.CLOSE);\n            parentNode.open = false;\n            target_ulObj.css({\n              \"display\": \"none\"\n            });\n          }\n\n          data.addNodesData(setting, parentNode, index, newNodes);\n          view.createNodes(setting, parentNode.level + 1, newNodes, parentNode, index);\n          if (!isSilent) {\n            view.expandCollapseParentNode(setting, parentNode, true);\n          }\n        } else {\n          data.addNodesData(setting, data.getRoot(setting), index, newNodes);\n          view.createNodes(setting, 0, newNodes, null, index);\n        }\n      },\n      appendNodes: function (setting, level, nodes, parentNode, index, initFlag, openFlag) {\n        if (!nodes) return [];\n        var html = [];\n\n        var tmpPNode = (parentNode) ? parentNode : data.getRoot(setting),\n          tmpPChild = data.nodeChildren(setting, tmpPNode),\n          isFirstNode, isLastNode;\n\n        if (!tmpPChild || index >= tmpPChild.length - nodes.length) {\n          index = -1;\n        }\n\n        for (var i = 0, l = nodes.length; i < l; i++) {\n          var node = nodes[i];\n          if (initFlag) {\n            isFirstNode = ((index === 0 || tmpPChild.length == nodes.length) && (i == 0));\n            isLastNode = (index < 0 && i == (nodes.length - 1));\n            data.initNode(setting, level, node, parentNode, isFirstNode, isLastNode, openFlag);\n            data.addNodeCache(setting, node);\n          }\n          var isParent = data.nodeIsParent(setting, node);\n\n          var childHtml = [];\n          var children = data.nodeChildren(setting, node);\n          if (children && children.length > 0) {\n            //make child html first, because checkType\n            childHtml = view.appendNodes(setting, level + 1, children, node, -1, initFlag, openFlag && node.open);\n          }\n          if (openFlag) {\n            view.makeDOMNodeMainBefore(html, setting, node);\n            view.makeDOMNodeLine(html, setting, node);\n            data.getBeforeA(setting, node, html);\n            view.makeDOMNodeNameBefore(html, setting, node);\n            data.getInnerBeforeA(setting, node, html);\n            view.makeDOMNodeIcon(html, setting, node);\n            data.getInnerAfterA(setting, node, html);\n            view.makeDOMNodeNameAfter(html, setting, node);\n            data.getAfterA(setting, node, html);\n            if (isParent && node.open) {\n              view.makeUlHtml(setting, node, html, childHtml.join(''));\n            }\n            view.makeDOMNodeMainAfter(html, setting, node);\n            data.addCreatedNode(setting, node);\n          }\n        }\n        return html;\n      },\n      appendParentULDom: function (setting, node) {\n        var html = [],\n          nObj = $$(node, setting);\n        if (!nObj.get(0) && !!node.parentTId) {\n          view.appendParentULDom(setting, node.getParentNode());\n          nObj = $$(node, setting);\n        }\n        var ulObj = $$(node, consts.id.UL, setting);\n        if (ulObj.get(0)) {\n          ulObj.remove();\n        }\n        var children = data.nodeChildren(setting, node),\n          childHtml = view.appendNodes(setting, node.level + 1, children, node, -1, false, true);\n        view.makeUlHtml(setting, node, html, childHtml.join(''));\n        nObj.append(html.join(''));\n      },\n      asyncNode: function (setting, node, isSilent, callback) {\n        var i, l;\n        var isParent = data.nodeIsParent(setting, node);\n        if (node && !isParent) {\n          tools.apply(callback);\n          return false;\n        } else if (node && node.isAjaxing) {\n          return false;\n        } else if (tools.apply(setting.callback.beforeAsync, [setting.treeId, node], true) == false) {\n          tools.apply(callback);\n          return false;\n        }\n        if (node) {\n          node.isAjaxing = true;\n          var icoObj = $$(node, consts.id.ICON, setting);\n          icoObj.attr({\"style\": \"\", \"class\": consts.className.BUTTON + \" \" + consts.className.ICO_LOADING});\n        }\n\n        var tmpParam = {};\n        var autoParam = tools.apply(setting.async.autoParam, [setting.treeId, node], setting.async.autoParam);\n        for (i = 0, l = autoParam.length; node && i < l; i++) {\n          var pKey = autoParam[i].split(\"=\"), spKey = pKey;\n          if (pKey.length > 1) {\n            spKey = pKey[1];\n            pKey = pKey[0];\n          }\n          tmpParam[spKey] = node[pKey];\n        }\n        var otherParam = tools.apply(setting.async.otherParam, [setting.treeId, node], setting.async.otherParam);\n        if (tools.isArray(otherParam)) {\n          for (i = 0, l = otherParam.length; i < l; i += 2) {\n            tmpParam[otherParam[i]] = otherParam[i + 1];\n          }\n        } else {\n          for (var p in otherParam) {\n            tmpParam[p] = otherParam[p];\n          }\n        }\n\n        var _tmpV = data.getRoot(setting)._ver;\n        $.ajax({\n          contentType: setting.async.contentType,\n          cache: false,\n          type: setting.async.type,\n          url: tools.apply(setting.async.url, [setting.treeId, node], setting.async.url),\n          data: setting.async.contentType.indexOf('application/json') > -1 ? JSON.stringify(tmpParam) : tmpParam,\n          dataType: setting.async.dataType,\n          headers: setting.async.headers,\n          xhrFields: setting.async.xhrFields,\n          success: function (msg) {\n            if (_tmpV != data.getRoot(setting)._ver) {\n              return;\n            }\n            var newNodes = [];\n            try {\n              if (!msg || msg.length == 0) {\n                newNodes = [];\n              } else if (typeof msg == \"string\") {\n                newNodes = eval(\"(\" + msg + \")\");\n              } else {\n                newNodes = msg;\n              }\n            } catch (err) {\n              newNodes = msg;\n            }\n\n            if (node) {\n              node.isAjaxing = null;\n              node.zAsync = true;\n            }\n            view.setNodeLineIcos(setting, node);\n            if (newNodes && newNodes !== \"\") {\n              newNodes = tools.apply(setting.async.dataFilter, [setting.treeId, node, newNodes], newNodes);\n              view.addNodes(setting, node, -1, !!newNodes ? tools.clone(newNodes) : [], !!isSilent);\n            } else {\n              view.addNodes(setting, node, -1, [], !!isSilent);\n            }\n            setting.treeObj.trigger(consts.event.ASYNC_SUCCESS, [setting.treeId, node, msg]);\n            tools.apply(callback);\n          },\n          error: function (XMLHttpRequest, textStatus, errorThrown) {\n            if (_tmpV != data.getRoot(setting)._ver) {\n              return;\n            }\n            if (node) node.isAjaxing = null;\n            view.setNodeLineIcos(setting, node);\n            setting.treeObj.trigger(consts.event.ASYNC_ERROR, [setting.treeId, node, XMLHttpRequest, textStatus, errorThrown]);\n          }\n        });\n        return true;\n      },\n      cancelPreSelectedNode: function (setting, node, excludeNode) {\n        var list = data.getRoot(setting).curSelectedList,\n          i, n;\n        for (i = list.length - 1; i >= 0; i--) {\n          n = list[i];\n          if (node === n || (!node && (!excludeNode || excludeNode !== n))) {\n            $$(n, consts.id.A, setting).removeClass(consts.node.CURSELECTED);\n            if (node) {\n              data.removeSelectedNode(setting, node);\n              break;\n            } else {\n              list.splice(i, 1);\n              setting.treeObj.trigger(consts.event.UNSELECTED, [setting.treeId, n]);\n            }\n          }\n        }\n      },\n      createNodeCallback: function (setting) {\n        if (!!setting.callback.onNodeCreated || !!setting.view.addDiyDom) {\n          var root = data.getRoot(setting);\n          while (root.createdNodes.length > 0) {\n            var node = root.createdNodes.shift();\n            tools.apply(setting.view.addDiyDom, [setting.treeId, node]);\n            if (!!setting.callback.onNodeCreated) {\n              setting.treeObj.trigger(consts.event.NODECREATED, [setting.treeId, node]);\n            }\n          }\n        }\n      },\n      createNodes: function (setting, level, nodes, parentNode, index) {\n        if (!nodes || nodes.length == 0) return;\n        var root = data.getRoot(setting),\n          openFlag = !parentNode || parentNode.open || !!$$(data.nodeChildren(setting, parentNode)[0], setting).get(0);\n        root.createdNodes = [];\n        var zTreeHtml = view.appendNodes(setting, level, nodes, parentNode, index, true, openFlag),\n          parentObj, nextObj;\n\n        if (!parentNode) {\n          parentObj = setting.treeObj;\n          //setting.treeObj.append(zTreeHtml.join(''));\n        } else {\n          var ulObj = $$(parentNode, consts.id.UL, setting);\n          if (ulObj.get(0)) {\n            parentObj = ulObj;\n            //ulObj.append(zTreeHtml.join(''));\n          }\n        }\n        if (parentObj) {\n          if (index >= 0) {\n            nextObj = parentObj.children()[index];\n          }\n          if (index >= 0 && nextObj) {\n            $(nextObj).before(zTreeHtml.join(''));\n          } else {\n            parentObj.append(zTreeHtml.join(''));\n          }\n        }\n\n        view.createNodeCallback(setting);\n      },\n      destroy: function (setting) {\n        if (!setting) return;\n        data.initCache(setting);\n        data.initRoot(setting);\n        event.unbindTree(setting);\n        event.unbindEvent(setting);\n        setting.treeObj.empty();\n        delete settings[setting.treeId];\n      },\n      expandCollapseNode: function (setting, node, expandFlag, animateFlag, callback) {\n        var root = data.getRoot(setting);\n        var tmpCb, _callback;\n        if (!node) {\n          tools.apply(callback, []);\n          return;\n        }\n        var children = data.nodeChildren(setting, node);\n        var isParent = data.nodeIsParent(setting, node);\n        if (root.expandTriggerFlag) {\n          _callback = callback;\n          tmpCb = function () {\n            if (_callback) _callback();\n            if (node.open) {\n              setting.treeObj.trigger(consts.event.EXPAND, [setting.treeId, node]);\n            } else {\n              setting.treeObj.trigger(consts.event.COLLAPSE, [setting.treeId, node]);\n            }\n          };\n          callback = tmpCb;\n          root.expandTriggerFlag = false;\n        }\n        if (!node.open && isParent && ((!$$(node, consts.id.UL, setting).get(0)) || (children && children.length > 0 && !$$(children[0], setting).get(0)))) {\n          view.appendParentULDom(setting, node);\n          view.createNodeCallback(setting);\n        }\n        if (node.open == expandFlag) {\n          tools.apply(callback, []);\n          return;\n        }\n        var ulObj = $$(node, consts.id.UL, setting),\n          switchObj = $$(node, consts.id.SWITCH, setting),\n          icoObj = $$(node, consts.id.ICON, setting);\n\n        if (isParent) {\n          node.open = !node.open;\n          if (node.iconOpen && node.iconClose) {\n            icoObj.attr(\"style\", view.makeNodeIcoStyle(setting, node));\n          }\n\n          if (node.open) {\n            view.replaceSwitchClass(node, switchObj, consts.folder.OPEN);\n            view.replaceIcoClass(node, icoObj, consts.folder.OPEN);\n            if (animateFlag == false || setting.view.expandSpeed == \"\") {\n              ulObj.show();\n              tools.apply(callback, []);\n            } else {\n              if (children && children.length > 0) {\n                ulObj.slideDown(setting.view.expandSpeed, callback);\n              } else {\n                ulObj.show();\n                tools.apply(callback, []);\n              }\n            }\n          } else {\n            view.replaceSwitchClass(node, switchObj, consts.folder.CLOSE);\n            view.replaceIcoClass(node, icoObj, consts.folder.CLOSE);\n            if (animateFlag == false || setting.view.expandSpeed == \"\" || !(children && children.length > 0)) {\n              ulObj.hide();\n              tools.apply(callback, []);\n            } else {\n              ulObj.slideUp(setting.view.expandSpeed, callback);\n            }\n          }\n        } else {\n          tools.apply(callback, []);\n        }\n      },\n      expandCollapseParentNode: function (setting, node, expandFlag, animateFlag, callback) {\n        if (!node) return;\n        if (!node.parentTId) {\n          view.expandCollapseNode(setting, node, expandFlag, animateFlag, callback);\n          return;\n        } else {\n          view.expandCollapseNode(setting, node, expandFlag, animateFlag);\n        }\n        if (node.parentTId) {\n          view.expandCollapseParentNode(setting, node.getParentNode(), expandFlag, animateFlag, callback);\n        }\n      },\n      expandCollapseSonNode: function (setting, node, expandFlag, animateFlag, callback) {\n        var root = data.getRoot(setting),\n          treeNodes = (node) ? data.nodeChildren(setting, node) : data.nodeChildren(setting, root),\n          selfAnimateSign = (node) ? false : animateFlag,\n          expandTriggerFlag = data.getRoot(setting).expandTriggerFlag;\n        data.getRoot(setting).expandTriggerFlag = false;\n        if (treeNodes) {\n          for (var i = 0, l = treeNodes.length; i < l; i++) {\n            if (treeNodes[i]) view.expandCollapseSonNode(setting, treeNodes[i], expandFlag, selfAnimateSign);\n          }\n        }\n        data.getRoot(setting).expandTriggerFlag = expandTriggerFlag;\n        view.expandCollapseNode(setting, node, expandFlag, animateFlag, callback);\n      },\n      isSelectedNode: function (setting, node) {\n        if (!node) {\n          return false;\n        }\n        var list = data.getRoot(setting).curSelectedList,\n          i;\n        for (i = list.length - 1; i >= 0; i--) {\n          if (node === list[i]) {\n            return true;\n          }\n        }\n        return false;\n      },\n      makeDOMNodeIcon: function (html, setting, node) {\n        var nameStr = data.nodeName(setting, node),\n          name = setting.view.nameIsHTML ? nameStr : nameStr.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n        html.push(\"<span id='\", node.tId, consts.id.ICON,\n          \"' title='' treeNode\", consts.id.ICON, \" class='\", view.makeNodeIcoClass(setting, node),\n          \"' style='\", view.makeNodeIcoStyle(setting, node), \"'></span><span id='\", node.tId, consts.id.SPAN,\n          \"' class='\", consts.className.NAME,\n          \"'>\", name, \"</span>\");\n      },\n      makeDOMNodeLine: function (html, setting, node) {\n        html.push(\"<span id='\", node.tId, consts.id.SWITCH, \"' title='' class='\", view.makeNodeLineClass(setting, node), \"' treeNode\", consts.id.SWITCH, \"></span>\");\n      },\n      makeDOMNodeMainAfter: function (html, setting, node) {\n        html.push(\"</li>\");\n      },\n      makeDOMNodeMainBefore: function (html, setting, node) {\n        html.push(\"<li id='\", node.tId, \"' class='\", consts.className.LEVEL, node.level, \"' tabindex='0' hidefocus='true' treenode>\");\n      },\n      makeDOMNodeNameAfter: function (html, setting, node) {\n        html.push(\"</a>\");\n      },\n      makeDOMNodeNameBefore: function (html, setting, node) {\n        var title = data.nodeTitle(setting, node),\n          url = view.makeNodeUrl(setting, node),\n          fontcss = view.makeNodeFontCss(setting, node),\n          nodeClasses = view.makeNodeClasses(setting, node),\n          fontStyle = [];\n        for (var f in fontcss) {\n          fontStyle.push(f, \":\", fontcss[f], \";\");\n        }\n        html.push(\"<a id='\", node.tId, consts.id.A, \"' class='\", consts.className.LEVEL, node.level,\n          nodeClasses.add ? ' ' + nodeClasses.add.join(' ') : '', \n          \"' treeNode\", consts.id.A,\n          node.click ? \" onclick=\\\"\" + node.click + \"\\\"\" : \"\",\n          ((url != null && url.length > 0) ? \" href='\" + url + \"'\" : \"\"), \" target='\", view.makeNodeTarget(node), \"' style='\", fontStyle.join(''),\n          \"'\");\n        if (tools.apply(setting.view.showTitle, [setting.treeId, node], setting.view.showTitle) && title) {\n          html.push(\"title='\", title.replace(/'/g, \"&#39;\").replace(/</g, '&lt;').replace(/>/g, '&gt;'), \"'\");\n        }\n        html.push(\">\");\n      },\n      makeNodeFontCss: function (setting, node) {\n        var fontCss = tools.apply(setting.view.fontCss, [setting.treeId, node], setting.view.fontCss);\n        return (fontCss && ((typeof fontCss) != \"function\")) ? fontCss : {};\n      },\n      makeNodeClasses: function (setting, node) {\n        var classes = tools.apply(setting.view.nodeClasses, [setting.treeId, node], setting.view.nodeClasses);\n        return (classes && (typeof classes !== \"function\")) ? classes : {add:[], remove:[]};\n      },\n      makeNodeIcoClass: function (setting, node) {\n        var icoCss = [\"ico\"];\n        if (!node.isAjaxing) {\n          var isParent = data.nodeIsParent(setting, node);\n          icoCss[0] = (node.iconSkin ? node.iconSkin + \"_\" : \"\") + icoCss[0];\n          if (isParent) {\n            icoCss.push(node.open ? consts.folder.OPEN : consts.folder.CLOSE);\n          } else {\n            icoCss.push(consts.folder.DOCU);\n          }\n        }\n        return consts.className.BUTTON + \" \" + icoCss.join('_');\n      },\n      makeNodeIcoStyle: function (setting, node) {\n        var icoStyle = [];\n        if (!node.isAjaxing) {\n          var isParent = data.nodeIsParent(setting, node);\n          var icon = (isParent && node.iconOpen && node.iconClose) ? (node.open ? node.iconOpen : node.iconClose) : node[setting.data.key.icon];\n          if (icon) icoStyle.push(\"background:url(\", icon, \") 0 0 no-repeat;\");\n          if (setting.view.showIcon == false || !tools.apply(setting.view.showIcon, [setting.treeId, node], true)) {\n            icoStyle.push(\"display:none;\");\n          }\n        }\n        return icoStyle.join('');\n      },\n      makeNodeLineClass: function (setting, node) {\n        var lineClass = [];\n        if (setting.view.showLine) {\n          if (node.level == 0 && node.isFirstNode && node.isLastNode) {\n            lineClass.push(consts.line.ROOT);\n          } else if (node.level == 0 && node.isFirstNode) {\n            lineClass.push(consts.line.ROOTS);\n          } else if (node.isLastNode) {\n            lineClass.push(consts.line.BOTTOM);\n          } else {\n            lineClass.push(consts.line.CENTER);\n          }\n        } else {\n          lineClass.push(consts.line.NOLINE);\n        }\n        if (data.nodeIsParent(setting, node)) {\n          lineClass.push(node.open ? consts.folder.OPEN : consts.folder.CLOSE);\n        } else {\n          lineClass.push(consts.folder.DOCU);\n        }\n        return view.makeNodeLineClassEx(node) + lineClass.join('_');\n      },\n      makeNodeLineClassEx: function (node) {\n        return consts.className.BUTTON + \" \" + consts.className.LEVEL + node.level + \" \" + consts.className.SWITCH + \" \";\n      },\n      makeNodeTarget: function (node) {\n        return (node.target || \"_blank\");\n      },\n      makeNodeUrl: function (setting, node) {\n        var urlKey = setting.data.key.url;\n        return node[urlKey] ? node[urlKey] : null;\n      },\n      makeUlHtml: function (setting, node, html, content) {\n        html.push(\"<ul id='\", node.tId, consts.id.UL, \"' class='\", consts.className.LEVEL, node.level, \" \", view.makeUlLineClass(setting, node), \"' style='display:\", (node.open ? \"block\" : \"none\"), \"'>\");\n        html.push(content);\n        html.push(\"</ul>\");\n      },\n      makeUlLineClass: function (setting, node) {\n        return ((setting.view.showLine && !node.isLastNode) ? consts.line.LINE : \"\");\n      },\n      removeChildNodes: function (setting, node) {\n        if (!node) return;\n        var nodes = data.nodeChildren(setting, node);\n        if (!nodes) return;\n\n        for (var i = 0, l = nodes.length; i < l; i++) {\n          data.removeNodeCache(setting, nodes[i]);\n        }\n        data.removeSelectedNode(setting);\n        delete node[setting.data.key.children];\n\n        if (!setting.data.keep.parent) {\n          data.nodeIsParent(setting, node, false);\n          node.open = false;\n          var tmp_switchObj = $$(node, consts.id.SWITCH, setting),\n            tmp_icoObj = $$(node, consts.id.ICON, setting);\n          view.replaceSwitchClass(node, tmp_switchObj, consts.folder.DOCU);\n          view.replaceIcoClass(node, tmp_icoObj, consts.folder.DOCU);\n          $$(node, consts.id.UL, setting).remove();\n        } else {\n          $$(node, consts.id.UL, setting).empty();\n        }\n      },\n      scrollIntoView: function (setting, dom) {\n        if (!dom) {\n          return;\n        }\n        // support IE 7 / 8\n        if (typeof Element === 'undefined' || typeof HTMLElement === 'undefined') {\n          var contRect = setting.treeObj.get(0).getBoundingClientRect(),\n            findMeRect = dom.getBoundingClientRect();\n          if (findMeRect.top < contRect.top || findMeRect.bottom > contRect.bottom\n            || findMeRect.right > contRect.right || findMeRect.left < contRect.left) {\n            dom.scrollIntoView();\n          }\n          return;\n        }\n        // CC-BY jocki84@googlemail.com, https://gist.github.com/jocki84/6ffafd003387179a988e\n        if (!Element.prototype.scrollIntoViewIfNeeded) {\n          Element.prototype.scrollIntoViewIfNeeded = function (centerIfNeeded) {\n            \"use strict\";\n\n            function makeRange(start, length) {\n              return {\"start\": start, \"length\": length, \"end\": start + length};\n            }\n\n            function coverRange(inner, outer) {\n              if (\n                false === centerIfNeeded ||\n                (outer.start < inner.end && inner.start < outer.end)\n              ) {\n                return Math.max(\n                  inner.end - outer.length,\n                  Math.min(outer.start, inner.start)\n                );\n              }\n              return (inner.start + inner.end - outer.length) / 2;\n            }\n\n            function makePoint(x, y) {\n              return {\n                \"x\": x,\n                \"y\": y,\n                \"translate\": function translate(dX, dY) {\n                  return makePoint(x + dX, y + dY);\n                }\n              };\n            }\n\n            function absolute(elem, pt) {\n              while (elem) {\n                pt = pt.translate(elem.offsetLeft, elem.offsetTop);\n                elem = elem.offsetParent;\n              }\n              return pt;\n            }\n\n            var target = absolute(this, makePoint(0, 0)),\n              extent = makePoint(this.offsetWidth, this.offsetHeight),\n              elem = this.parentNode,\n              origin;\n\n            while (elem instanceof HTMLElement) {\n              // Apply desired scroll amount.\n              origin = absolute(elem, makePoint(elem.clientLeft, elem.clientTop));\n              elem.scrollLeft = coverRange(\n                makeRange(target.x - origin.x, extent.x),\n                makeRange(elem.scrollLeft, elem.clientWidth)\n              );\n              elem.scrollTop = coverRange(\n                makeRange(target.y - origin.y, extent.y),\n                makeRange(elem.scrollTop, elem.clientHeight)\n              );\n\n              // Determine actual scroll amount by reading back scroll properties.\n              target = target.translate(-elem.scrollLeft, -elem.scrollTop);\n              elem = elem.parentNode;\n            }\n          };\n        }\n        dom.scrollIntoViewIfNeeded();\n      },\n      setFirstNode: function (setting, parentNode) {\n        var children = data.nodeChildren(setting, parentNode);\n        if (children.length > 0) {\n          children[0].isFirstNode = true;\n        }\n      },\n      setLastNode: function (setting, parentNode) {\n        var children = data.nodeChildren(setting, parentNode);\n        if (children.length > 0) {\n          children[children.length - 1].isLastNode = true;\n        }\n      },\n      removeNode: function (setting, node) {\n        var root = data.getRoot(setting),\n          parentNode = (node.parentTId) ? node.getParentNode() : root;\n\n        node.isFirstNode = false;\n        node.isLastNode = false;\n        node.getPreNode = function () {\n          return null;\n        };\n        node.getNextNode = function () {\n          return null;\n        };\n\n        if (!data.getNodeCache(setting, node.tId)) {\n          return;\n        }\n\n        $$(node, setting).remove();\n        data.removeNodeCache(setting, node);\n        data.removeSelectedNode(setting, node);\n\n        var children = data.nodeChildren(setting, parentNode);\n        for (var i = 0, l = children.length; i < l; i++) {\n          if (children[i].tId == node.tId) {\n            children.splice(i, 1);\n            break;\n          }\n        }\n        view.setFirstNode(setting, parentNode);\n        view.setLastNode(setting, parentNode);\n\n        var tmp_ulObj, tmp_switchObj, tmp_icoObj,\n          childLength = children.length;\n\n        //repair nodes old parent\n        if (!setting.data.keep.parent && childLength == 0) {\n          //old parentNode has no child nodes\n          data.nodeIsParent(setting, parentNode, false);\n          parentNode.open = false;\n          delete parentNode[setting.data.key.children];\n          tmp_ulObj = $$(parentNode, consts.id.UL, setting);\n          tmp_switchObj = $$(parentNode, consts.id.SWITCH, setting);\n          tmp_icoObj = $$(parentNode, consts.id.ICON, setting);\n          view.replaceSwitchClass(parentNode, tmp_switchObj, consts.folder.DOCU);\n          view.replaceIcoClass(parentNode, tmp_icoObj, consts.folder.DOCU);\n          tmp_ulObj.css(\"display\", \"none\");\n\n        } else if (setting.view.showLine && childLength > 0) {\n          //old parentNode has child nodes\n          var newLast = children[childLength - 1];\n          tmp_ulObj = $$(newLast, consts.id.UL, setting);\n          tmp_switchObj = $$(newLast, consts.id.SWITCH, setting);\n          tmp_icoObj = $$(newLast, consts.id.ICON, setting);\n          if (parentNode == root) {\n            if (children.length == 1) {\n              //node was root, and ztree has only one root after move node\n              view.replaceSwitchClass(newLast, tmp_switchObj, consts.line.ROOT);\n            } else {\n              var tmp_first_switchObj = $$(children[0], consts.id.SWITCH, setting);\n              view.replaceSwitchClass(children[0], tmp_first_switchObj, consts.line.ROOTS);\n              view.replaceSwitchClass(newLast, tmp_switchObj, consts.line.BOTTOM);\n            }\n          } else {\n            view.replaceSwitchClass(newLast, tmp_switchObj, consts.line.BOTTOM);\n          }\n          tmp_ulObj.removeClass(consts.line.LINE);\n        }\n      },\n      replaceIcoClass: function (node, obj, newName) {\n        if (!obj || node.isAjaxing) return;\n        var tmpName = obj.attr(\"class\");\n        if (tmpName == undefined) return;\n        var tmpList = tmpName.split(\"_\");\n        switch (newName) {\n          case consts.folder.OPEN:\n          case consts.folder.CLOSE:\n          case consts.folder.DOCU:\n            tmpList[tmpList.length - 1] = newName;\n            break;\n        }\n        obj.attr(\"class\", tmpList.join(\"_\"));\n      },\n      replaceSwitchClass: function (node, obj, newName) {\n        if (!obj) return;\n        var tmpName = obj.attr(\"class\");\n        if (tmpName == undefined) return;\n        var tmpList = tmpName.split(\"_\");\n        switch (newName) {\n          case consts.line.ROOT:\n          case consts.line.ROOTS:\n          case consts.line.CENTER:\n          case consts.line.BOTTOM:\n          case consts.line.NOLINE:\n            tmpList[0] = view.makeNodeLineClassEx(node) + newName;\n            break;\n          case consts.folder.OPEN:\n          case consts.folder.CLOSE:\n          case consts.folder.DOCU:\n            tmpList[1] = newName;\n            break;\n        }\n        obj.attr(\"class\", tmpList.join(\"_\"));\n        if (newName !== consts.folder.DOCU) {\n          obj.removeAttr(\"disabled\");\n        } else {\n          obj.attr(\"disabled\", \"disabled\");\n        }\n      },\n      selectNode: function (setting, node, addFlag) {\n        if (!addFlag) {\n          view.cancelPreSelectedNode(setting, null, node);\n        }\n        $$(node, consts.id.A, setting).addClass(consts.node.CURSELECTED);\n        data.addSelectedNode(setting, node);\n        setting.treeObj.trigger(consts.event.SELECTED, [setting.treeId, node]);\n      },\n      setNodeFontCss: function (setting, treeNode) {\n        var aObj = $$(treeNode, consts.id.A, setting),\n          fontCss = view.makeNodeFontCss(setting, treeNode);\n        if (fontCss) {\n          aObj.css(fontCss);\n        }\n      },\n      setNodeClasses: function (setting, treeNode) {\n        var aObj = $$(treeNode, consts.id.A, setting),\n          classes = view.makeNodeClasses(setting, treeNode);\n        if ('add' in classes && classes.add.length) {\n          aObj.addClass(classes.add.join(' '));\n        }\n        if ('remove' in classes && classes.remove.length) {\n          aObj.removeClass(classes.remove.join(' '));\n        }\n      },\n      setNodeLineIcos: function (setting, node) {\n        if (!node) return;\n        var switchObj = $$(node, consts.id.SWITCH, setting),\n          ulObj = $$(node, consts.id.UL, setting),\n          icoObj = $$(node, consts.id.ICON, setting),\n          ulLine = view.makeUlLineClass(setting, node);\n        if (ulLine.length == 0) {\n          ulObj.removeClass(consts.line.LINE);\n        } else {\n          ulObj.addClass(ulLine);\n        }\n        switchObj.attr(\"class\", view.makeNodeLineClass(setting, node));\n        if (data.nodeIsParent(setting, node)) {\n          switchObj.removeAttr(\"disabled\");\n        } else {\n          switchObj.attr(\"disabled\", \"disabled\");\n        }\n        icoObj.removeAttr(\"style\");\n        icoObj.attr(\"style\", view.makeNodeIcoStyle(setting, node));\n        icoObj.attr(\"class\", view.makeNodeIcoClass(setting, node));\n      },\n      setNodeName: function (setting, node) {\n        var title = data.nodeTitle(setting, node),\n          nObj = $$(node, consts.id.SPAN, setting);\n        nObj.empty();\n        if (setting.view.nameIsHTML) {\n          nObj.html(data.nodeName(setting, node));\n        } else {\n          nObj.text(data.nodeName(setting, node));\n        }\n        if (tools.apply(setting.view.showTitle, [setting.treeId, node], setting.view.showTitle)) {\n          var aObj = $$(node, consts.id.A, setting);\n          aObj.attr(\"title\", !title ? \"\" : title);\n        }\n      },\n      setNodeTarget: function (setting, node) {\n        var aObj = $$(node, consts.id.A, setting);\n        aObj.attr(\"target\", view.makeNodeTarget(node));\n      },\n      setNodeUrl: function (setting, node) {\n        var aObj = $$(node, consts.id.A, setting),\n          url = view.makeNodeUrl(setting, node);\n        if (url == null || url.length == 0) {\n          aObj.removeAttr(\"href\");\n        } else {\n          aObj.attr(\"href\", url);\n        }\n      },\n      switchNode: function (setting, node) {\n        if (node.open || !tools.canAsync(setting, node)) {\n          view.expandCollapseNode(setting, node, !node.open);\n        } else if (setting.async.enable) {\n          if (!view.asyncNode(setting, node)) {\n            view.expandCollapseNode(setting, node, !node.open);\n            return;\n          }\n        } else if (node) {\n          view.expandCollapseNode(setting, node, !node.open);\n        }\n      }\n    };\n  // zTree defind\n  $.fn.zTree = {\n    consts: _consts,\n    _z: {\n      tools: tools,\n      view: view,\n      event: event,\n      data: data\n    },\n    getZTreeObj: function (treeId) {\n      var o = data.getZTreeTools(treeId);\n      return o ? o : null;\n    },\n    destroy: function (treeId) {\n      if (!!treeId && treeId.length > 0) {\n        view.destroy(data.getSetting(treeId));\n      } else {\n        for (var s in settings) {\n          view.destroy(settings[s]);\n        }\n      }\n    },\n    init: function (obj, zSetting, zNodes) {\n      var setting = tools.clone(_setting);\n      $.extend(true, setting, zSetting);\n      setting.treeId = obj.attr(\"id\");\n      setting.treeObj = obj;\n      setting.treeObj.empty();\n      settings[setting.treeId] = setting;\n      //For some older browser,(e.g., ie6)\n      if (typeof document.body.style.maxHeight === \"undefined\") {\n        setting.view.expandSpeed = \"\";\n      }\n      data.initRoot(setting);\n      var root = data.getRoot(setting);\n      zNodes = zNodes ? tools.clone(tools.isArray(zNodes) ? zNodes : [zNodes]) : [];\n      if (setting.data.simpleData.enable) {\n        data.nodeChildren(setting, root, data.transformTozTreeFormat(setting, zNodes));\n      } else {\n        data.nodeChildren(setting, root, zNodes);\n      }\n\n      data.initCache(setting);\n      event.unbindTree(setting);\n      event.bindTree(setting);\n      event.unbindEvent(setting);\n      event.bindEvent(setting);\n\n      var zTreeTools = {\n        setting: setting,\n        addNodes: function (parentNode, index, newNodes, isSilent) {\n          if (!parentNode) parentNode = null;\n          var isParent = data.nodeIsParent(setting, parentNode);\n          if (parentNode && !isParent && setting.data.keep.leaf) return null;\n\n          var i = parseInt(index, 10);\n          if (isNaN(i)) {\n            isSilent = !!newNodes;\n            newNodes = index;\n            index = -1;\n          } else {\n            index = i;\n          }\n          if (!newNodes) return null;\n\n\n          var xNewNodes = tools.clone(tools.isArray(newNodes) ? newNodes : [newNodes]);\n\n          function addCallback() {\n            view.addNodes(setting, parentNode, index, xNewNodes, (isSilent == true));\n          }\n\n          if (tools.canAsync(setting, parentNode)) {\n            view.asyncNode(setting, parentNode, isSilent, addCallback);\n          } else {\n            addCallback();\n          }\n          return xNewNodes;\n        },\n        cancelSelectedNode: function (node) {\n          view.cancelPreSelectedNode(setting, node);\n        },\n        destroy: function () {\n          view.destroy(setting);\n        },\n        expandAll: function (expandFlag) {\n          expandFlag = !!expandFlag;\n          view.expandCollapseSonNode(setting, null, expandFlag, true);\n          return expandFlag;\n        },\n        expandNode: function (node, expandFlag, sonSign, focus, callbackFlag) {\n          if (!node || !data.nodeIsParent(setting, node)) return null;\n          if (expandFlag !== true && expandFlag !== false) {\n            expandFlag = !node.open;\n          }\n          callbackFlag = !!callbackFlag;\n\n          if (callbackFlag && expandFlag && (tools.apply(setting.callback.beforeExpand, [setting.treeId, node], true) == false)) {\n            return null;\n          } else if (callbackFlag && !expandFlag && (tools.apply(setting.callback.beforeCollapse, [setting.treeId, node], true) == false)) {\n            return null;\n          }\n          if (expandFlag && node.parentTId) {\n            view.expandCollapseParentNode(setting, node.getParentNode(), expandFlag, false);\n          }\n          if (expandFlag === node.open && !sonSign) {\n            return null;\n          }\n\n          data.getRoot(setting).expandTriggerFlag = callbackFlag;\n          if (!tools.canAsync(setting, node) && sonSign) {\n            view.expandCollapseSonNode(setting, node, expandFlag, true, showNodeFocus);\n          } else {\n            node.open = !expandFlag;\n            view.switchNode(this.setting, node);\n            showNodeFocus();\n          }\n          return expandFlag;\n\n          function showNodeFocus() {\n            var a = $$(node, consts.id.A, setting).get(0);\n            if (a && focus !== false) {\n              view.scrollIntoView(setting, a);\n            }\n          }\n        },\n        getNodes: function () {\n          return data.getNodes(setting);\n        },\n        getNodeByParam: function (key, value, parentNode) {\n          if (!key) return null;\n          return data.getNodeByParam(setting, parentNode ? data.nodeChildren(setting, parentNode) : data.getNodes(setting), key, value);\n        },\n        getNodeByTId: function (tId) {\n          return data.getNodeCache(setting, tId);\n        },\n        getNodesByParam: function (key, value, parentNode) {\n          if (!key) return null;\n          return data.getNodesByParam(setting, parentNode ? data.nodeChildren(setting, parentNode) : data.getNodes(setting), key, value);\n        },\n        getNodesByParamFuzzy: function (key, value, parentNode) {\n          if (!key) return null;\n          return data.getNodesByParamFuzzy(setting, parentNode ? data.nodeChildren(setting, parentNode) : data.getNodes(setting), key, value);\n        },\n        getNodesByFilter: function (filter, isSingle, parentNode, invokeParam) {\n          isSingle = !!isSingle;\n          if (!filter || (typeof filter != \"function\")) return (isSingle ? null : []);\n          return data.getNodesByFilter(setting, parentNode ? data.nodeChildren(setting, parentNode) : data.getNodes(setting), filter, isSingle, invokeParam);\n        },\n        getNodeIndex: function (node) {\n          if (!node) return null;\n          var parentNode = (node.parentTId) ? node.getParentNode() : data.getRoot(setting);\n          var children = data.nodeChildren(setting, parentNode);\n          for (var i = 0, l = children.length; i < l; i++) {\n            if (children[i] == node) return i;\n          }\n          return -1;\n        },\n        getSelectedNodes: function () {\n          var r = [], list = data.getRoot(setting).curSelectedList;\n          for (var i = 0, l = list.length; i < l; i++) {\n            r.push(list[i]);\n          }\n          return r;\n        },\n        isSelectedNode: function (node) {\n          return data.isSelectedNode(setting, node);\n        },\n        reAsyncChildNodesPromise: function (parentNode, reloadType, isSilent) {\n          var promise = new Promise(function (resolve, reject) {\n            try {\n              zTreeTools.reAsyncChildNodes(parentNode, reloadType, isSilent, function () {\n                resolve(parentNode);\n              });\n            } catch (e) {\n              reject(e);\n            }\n          });\n          return promise;\n        },\n        reAsyncChildNodes: function (parentNode, reloadType, isSilent, callback) {\n          if (!this.setting.async.enable) return;\n          var isRoot = !parentNode;\n          if (isRoot) {\n            parentNode = data.getRoot(setting);\n          }\n          if (reloadType == \"refresh\") {\n            var children = data.nodeChildren(setting, parentNode);\n            for (var i = 0, l = children ? children.length : 0; i < l; i++) {\n              data.removeNodeCache(setting, children[i]);\n            }\n            data.removeSelectedNode(setting);\n            data.nodeChildren(setting, parentNode, []);\n            if (isRoot) {\n              this.setting.treeObj.empty();\n            } else {\n              var ulObj = $$(parentNode, consts.id.UL, setting);\n              ulObj.empty();\n            }\n          }\n          view.asyncNode(this.setting, isRoot ? null : parentNode, !!isSilent, callback);\n        },\n        refresh: function () {\n          this.setting.treeObj.empty();\n          var root = data.getRoot(setting),\n            nodes = data.nodeChildren(setting, root);\n          data.initRoot(setting);\n          data.nodeChildren(setting, root, nodes);\n          data.initCache(setting);\n          view.createNodes(setting, 0, data.nodeChildren(setting, root), null, -1);\n        },\n        removeChildNodes: function (node) {\n          if (!node) return null;\n          var nodes = data.nodeChildren(setting, node);\n          view.removeChildNodes(setting, node);\n          return nodes ? nodes : null;\n        },\n        removeNode: function (node, callbackFlag) {\n          if (!node) return;\n          callbackFlag = !!callbackFlag;\n          if (callbackFlag && tools.apply(setting.callback.beforeRemove, [setting.treeId, node], true) == false) return;\n          view.removeNode(setting, node);\n          if (callbackFlag) {\n            this.setting.treeObj.trigger(consts.event.REMOVE, [setting.treeId, node]);\n          }\n        },\n        selectNode: function (node, addFlag, isSilent) {\n          if (!node) return;\n          if (tools.uCanDo(setting)) {\n            addFlag = setting.view.selectedMulti && addFlag;\n            if (node.parentTId) {\n              view.expandCollapseParentNode(setting, node.getParentNode(), true, false, showNodeFocus);\n            } else if (!isSilent) {\n              try {\n                $$(node, setting).focus().blur();\n              } catch (e) {\n              }\n            }\n            view.selectNode(setting, node, addFlag);\n          }\n\n          function showNodeFocus() {\n            if (isSilent) {\n              return;\n            }\n            var a = $$(node, setting).get(0);\n            view.scrollIntoView(setting, a);\n          }\n        },\n        transformTozTreeNodes: function (simpleNodes) {\n          return data.transformTozTreeFormat(setting, simpleNodes);\n        },\n        transformToArray: function (nodes) {\n          return data.transformToArrayFormat(setting, nodes);\n        },\n        updateNode: function (node, checkTypeFlag) {\n          if (!node) return;\n          var nObj = $$(node, setting);\n          if (nObj.get(0) && tools.uCanDo(setting)) {\n            view.setNodeName(setting, node);\n            view.setNodeTarget(setting, node);\n            view.setNodeUrl(setting, node);\n            view.setNodeLineIcos(setting, node);\n            view.setNodeFontCss(setting, node);\n            view.setNodeClasses(setting, node);\n          }\n        }\n      };\n      root.treeTools = zTreeTools;\n      data.setZTreeTools(setting, zTreeTools);\n      var children = data.nodeChildren(setting, root);\n      if (children && children.length > 0) {\n        view.createNodes(setting, 0, children, null, -1);\n      } else if (setting.async.enable && setting.async.url && setting.async.url !== '') {\n        view.asyncNode(setting);\n      }\n      return zTreeTools;\n    }\n  };\n\n  var zt = $.fn.zTree,\n    $$ = tools.$,\n    consts = zt.consts;\n})(jQuery);"
  },
  {
    "path": "xxl-job-admin/src/main/resources/static/plugins/zTree/js/jquery.ztree.excheck.js",
    "content": "/*\n * JQuery zTree excheck\n * v3.5.42\n * http://treejs.cn/\n *\n * Copyright (c) 2010 Hunter.z\n *\n * Licensed same as jquery - MIT License\n * http://www.opensource.org/licenses/mit-license.php\n *\n * Date: 2020-01-19\n */\n\n(function ($) {\n  //default consts of excheck\n  var _consts = {\n      event: {\n        CHECK: \"ztree_check\"\n      },\n      id: {\n        CHECK: \"_check\"\n      },\n      checkbox: {\n        STYLE: \"checkbox\",\n        DEFAULT: \"chk\",\n        DISABLED: \"disable\",\n        FALSE: \"false\",\n        TRUE: \"true\",\n        FULL: \"full\",\n        PART: \"part\",\n        FOCUS: \"focus\"\n      },\n      radio: {\n        STYLE: \"radio\",\n        TYPE_ALL: \"all\",\n        TYPE_LEVEL: \"level\"\n      }\n    },\n    //default setting of excheck\n    _setting = {\n      check: {\n        enable: false,\n        autoCheckTrigger: false,\n        chkStyle: _consts.checkbox.STYLE,\n        nocheckInherit: false,\n        chkDisabledInherit: false,\n        radioType: _consts.radio.TYPE_LEVEL,\n        chkboxType: {\n          \"Y\": \"ps\",\n          \"N\": \"ps\"\n        }\n      },\n      data: {\n        key: {\n          checked: \"checked\"\n        }\n      },\n      callback: {\n        beforeCheck: null,\n        onCheck: null\n      }\n    },\n    //default root of excheck\n    _initRoot = function (setting) {\n      var r = data.getRoot(setting);\n      r.radioCheckedList = [];\n    },\n    //default cache of excheck\n    _initCache = function (treeId) {\n    },\n    //default bind event of excheck\n    _bindEvent = function (setting) {\n      var o = setting.treeObj,\n        c = consts.event;\n      o.bind(c.CHECK, function (event, srcEvent, treeId, node) {\n        event.srcEvent = srcEvent;\n        tools.apply(setting.callback.onCheck, [event, treeId, node]);\n      });\n    },\n    _unbindEvent = function (setting) {\n      var o = setting.treeObj,\n        c = consts.event;\n      o.unbind(c.CHECK);\n    },\n    //default event proxy of excheck\n    _eventProxy = function (e) {\n      var target = e.target,\n        setting = data.getSetting(e.data.treeId),\n        tId = \"\", node = null,\n        nodeEventType = \"\", treeEventType = \"\",\n        nodeEventCallback = null, treeEventCallback = null;\n\n      if (tools.eqs(e.type, \"mouseover\")) {\n        if (setting.check.enable && tools.eqs(target.tagName, \"span\") && target.getAttribute(\"treeNode\" + consts.id.CHECK) !== null) {\n          tId = tools.getNodeMainDom(target).id;\n          nodeEventType = \"mouseoverCheck\";\n        }\n      } else if (tools.eqs(e.type, \"mouseout\")) {\n        if (setting.check.enable && tools.eqs(target.tagName, \"span\") && target.getAttribute(\"treeNode\" + consts.id.CHECK) !== null) {\n          tId = tools.getNodeMainDom(target).id;\n          nodeEventType = \"mouseoutCheck\";\n        }\n      } else if (tools.eqs(e.type, \"click\")) {\n        if (setting.check.enable && tools.eqs(target.tagName, \"span\") && target.getAttribute(\"treeNode\" + consts.id.CHECK) !== null) {\n          tId = tools.getNodeMainDom(target).id;\n          nodeEventType = \"checkNode\";\n        }\n      }\n      if (tId.length > 0) {\n        node = data.getNodeCache(setting, tId);\n        switch (nodeEventType) {\n          case \"checkNode\" :\n            nodeEventCallback = _handler.onCheckNode;\n            break;\n          case \"mouseoverCheck\" :\n            nodeEventCallback = _handler.onMouseoverCheck;\n            break;\n          case \"mouseoutCheck\" :\n            nodeEventCallback = _handler.onMouseoutCheck;\n            break;\n        }\n      }\n      var proxyResult = {\n        stop: nodeEventType === \"checkNode\",\n        node: node,\n        nodeEventType: nodeEventType,\n        nodeEventCallback: nodeEventCallback,\n        treeEventType: treeEventType,\n        treeEventCallback: treeEventCallback\n      };\n      return proxyResult\n    },\n    //default init node of excheck\n    _initNode = function (setting, level, n, parentNode, isFirstNode, isLastNode, openFlag) {\n      if (!n) return;\n      var checked = data.nodeChecked(setting, n);\n      n.checkedOld = checked;\n      if (typeof n.nocheck == \"string\") n.nocheck = tools.eqs(n.nocheck, \"true\");\n      n.nocheck = !!n.nocheck || (setting.check.nocheckInherit && parentNode && !!parentNode.nocheck);\n      if (typeof n.chkDisabled == \"string\") n.chkDisabled = tools.eqs(n.chkDisabled, \"true\");\n      n.chkDisabled = !!n.chkDisabled || (setting.check.chkDisabledInherit && parentNode && !!parentNode.chkDisabled);\n      if (typeof n.halfCheck == \"string\") n.halfCheck = tools.eqs(n.halfCheck, \"true\");\n      n.halfCheck = !!n.halfCheck;\n      n.check_Child_State = -1;\n      n.check_Focus = false;\n      n.getCheckStatus = function () {\n        return data.getCheckStatus(setting, n);\n      };\n\n      if (setting.check.chkStyle == consts.radio.STYLE && setting.check.radioType == consts.radio.TYPE_ALL && checked) {\n        var r = data.getRoot(setting);\n        r.radioCheckedList.push(n);\n      }\n    },\n    //add dom for check\n    _beforeA = function (setting, node, html) {\n      if (setting.check.enable) {\n        data.makeChkFlag(setting, node);\n        html.push(\"<span ID='\", node.tId, consts.id.CHECK, \"' class='\", view.makeChkClass(setting, node), \"' treeNode\", consts.id.CHECK, (node.nocheck === true ? \" style='display:none;'\" : \"\"), \"></span>\");\n      }\n    },\n    //update zTreeObj, add method of check\n    _zTreeTools = function (setting, zTreeTools) {\n      zTreeTools.checkNode = function (node, checked, checkTypeFlag, callbackFlag) {\n        var nodeChecked = data.nodeChecked(setting, node);\n        if (node.chkDisabled === true) return;\n        if (checked !== true && checked !== false) {\n          checked = !nodeChecked;\n        }\n        callbackFlag = !!callbackFlag;\n\n        if (nodeChecked === checked && !checkTypeFlag) {\n          return;\n        } else if (callbackFlag && tools.apply(this.setting.callback.beforeCheck, [this.setting.treeId, node], true) == false) {\n          return;\n        }\n        if (tools.uCanDo(this.setting) && this.setting.check.enable && node.nocheck !== true) {\n          data.nodeChecked(setting, node, checked);\n          var checkObj = $$(node, consts.id.CHECK, this.setting);\n          if (checkTypeFlag || this.setting.check.chkStyle === consts.radio.STYLE) view.checkNodeRelation(this.setting, node);\n          view.setChkClass(this.setting, checkObj, node);\n          view.repairParentChkClassWithSelf(this.setting, node);\n          if (callbackFlag) {\n            this.setting.treeObj.trigger(consts.event.CHECK, [null, this.setting.treeId, node]);\n          }\n        }\n      }\n\n      zTreeTools.checkAllNodes = function (checked) {\n        view.repairAllChk(this.setting, !!checked);\n      }\n\n      zTreeTools.getCheckedNodes = function (checked) {\n        checked = (checked !== false);\n        var children = data.nodeChildren(setting, data.getRoot(this.setting));\n        return data.getTreeCheckedNodes(this.setting, children, checked);\n      }\n\n      zTreeTools.getChangeCheckedNodes = function () {\n        var children = data.nodeChildren(setting, data.getRoot(this.setting));\n        return data.getTreeChangeCheckedNodes(this.setting, children);\n      }\n\n      zTreeTools.setChkDisabled = function (node, disabled, inheritParent, inheritChildren) {\n        disabled = !!disabled;\n        inheritParent = !!inheritParent;\n        inheritChildren = !!inheritChildren;\n        view.repairSonChkDisabled(this.setting, node, disabled, inheritChildren);\n        view.repairParentChkDisabled(this.setting, node.getParentNode(), disabled, inheritParent);\n      }\n\n      var _updateNode = zTreeTools.updateNode;\n      zTreeTools.updateNode = function (node, checkTypeFlag) {\n        if (_updateNode) _updateNode.apply(zTreeTools, arguments);\n        if (!node || !this.setting.check.enable) return;\n        var nObj = $$(node, this.setting);\n        if (nObj.get(0) && tools.uCanDo(this.setting)) {\n          var checkObj = $$(node, consts.id.CHECK, this.setting);\n          if (checkTypeFlag == true || this.setting.check.chkStyle === consts.radio.STYLE) view.checkNodeRelation(this.setting, node);\n          view.setChkClass(this.setting, checkObj, node);\n          view.repairParentChkClassWithSelf(this.setting, node);\n        }\n      }\n    },\n    //method of operate data\n    _data = {\n      getRadioCheckedList: function (setting) {\n        var checkedList = data.getRoot(setting).radioCheckedList;\n        for (var i = 0, j = checkedList.length; i < j; i++) {\n          if (!data.getNodeCache(setting, checkedList[i].tId)) {\n            checkedList.splice(i, 1);\n            i--;\n            j--;\n          }\n        }\n        return checkedList;\n      },\n      getCheckStatus: function (setting, node) {\n        if (!setting.check.enable || node.nocheck || node.chkDisabled) return null;\n        var checked = data.nodeChecked(setting, node),\n          r = {\n            checked: checked,\n            half: node.halfCheck ? node.halfCheck : (setting.check.chkStyle == consts.radio.STYLE ? (node.check_Child_State === 2) : (checked ? (node.check_Child_State > -1 && node.check_Child_State < 2) : (node.check_Child_State > 0)))\n          };\n        return r;\n      },\n      getTreeCheckedNodes: function (setting, nodes, checked, results) {\n        if (!nodes) return [];\n        var onlyOne = (checked && setting.check.chkStyle == consts.radio.STYLE && setting.check.radioType == consts.radio.TYPE_ALL);\n        results = !results ? [] : results;\n        for (var i = 0, l = nodes.length; i < l; i++) {\n          var node = nodes[i];\n          var children = data.nodeChildren(setting, node);\n          var nodeChecked = data.nodeChecked(setting, node);\n          if (node.nocheck !== true && node.chkDisabled !== true && nodeChecked == checked) {\n            results.push(node);\n            if (onlyOne) {\n              break;\n            }\n          }\n          data.getTreeCheckedNodes(setting, children, checked, results);\n          if (onlyOne && results.length > 0) {\n            break;\n          }\n        }\n        return results;\n      },\n      getTreeChangeCheckedNodes: function (setting, nodes, results) {\n        if (!nodes) return [];\n        results = !results ? [] : results;\n        for (var i = 0, l = nodes.length; i < l; i++) {\n          var node = nodes[i];\n          var children = data.nodeChildren(setting, node);\n          var nodeChecked = data.nodeChecked(setting, node);\n          if (node.nocheck !== true && node.chkDisabled !== true && nodeChecked != node.checkedOld) {\n            results.push(node);\n          }\n          data.getTreeChangeCheckedNodes(setting, children, results);\n        }\n        return results;\n      },\n      makeChkFlag: function (setting, node) {\n        if (!node) return;\n        var chkFlag = -1;\n        var children = data.nodeChildren(setting, node);\n        if (children) {\n          for (var i = 0, l = children.length; i < l; i++) {\n            var cNode = children[i];\n            var nodeChecked = data.nodeChecked(setting, cNode);\n            var tmp = -1;\n            if (setting.check.chkStyle == consts.radio.STYLE) {\n              if (cNode.nocheck === true || cNode.chkDisabled === true) {\n                tmp = cNode.check_Child_State;\n              } else if (cNode.halfCheck === true) {\n                tmp = 2;\n              } else if (nodeChecked) {\n                tmp = 2;\n              } else {\n                tmp = cNode.check_Child_State > 0 ? 2 : 0;\n              }\n              if (tmp == 2) {\n                chkFlag = 2;\n                break;\n              } else if (tmp == 0) {\n                chkFlag = 0;\n              }\n            } else if (setting.check.chkStyle == consts.checkbox.STYLE) {\n              if (cNode.nocheck === true || cNode.chkDisabled === true) {\n                tmp = cNode.check_Child_State;\n              } else if (cNode.halfCheck === true) {\n                tmp = 1;\n              } else if (nodeChecked) {\n                tmp = (cNode.check_Child_State === -1 || cNode.check_Child_State === 2) ? 2 : 1;\n              } else {\n                tmp = (cNode.check_Child_State > 0) ? 1 : 0;\n              }\n              if (tmp === 1) {\n                chkFlag = 1;\n                break;\n              } else if (tmp === 2 && chkFlag > -1 && i > 0 && tmp !== chkFlag) {\n                chkFlag = 1;\n                break;\n              } else if (chkFlag === 2 && tmp > -1 && tmp < 2) {\n                chkFlag = 1;\n                break;\n              } else if (tmp > -1) {\n                chkFlag = tmp;\n              }\n            }\n          }\n        }\n        node.check_Child_State = chkFlag;\n      }\n    },\n    //method of event proxy\n    _event = {},\n    //method of event handler\n    _handler = {\n      onCheckNode: function (event, node) {\n        if (node.chkDisabled === true) return false;\n        var setting = data.getSetting(event.data.treeId);\n        if (tools.apply(setting.callback.beforeCheck, [setting.treeId, node], true) == false) return true;\n        var nodeChecked = data.nodeChecked(setting, node);\n        data.nodeChecked(setting, node, !nodeChecked);\n        view.checkNodeRelation(setting, node);\n        var checkObj = $$(node, consts.id.CHECK, setting);\n        view.setChkClass(setting, checkObj, node);\n        view.repairParentChkClassWithSelf(setting, node);\n        setting.treeObj.trigger(consts.event.CHECK, [event, setting.treeId, node]);\n        return true;\n      },\n      onMouseoverCheck: function (event, node) {\n        if (node.chkDisabled === true) return false;\n        var setting = data.getSetting(event.data.treeId),\n          checkObj = $$(node, consts.id.CHECK, setting);\n        node.check_Focus = true;\n        view.setChkClass(setting, checkObj, node);\n        return true;\n      },\n      onMouseoutCheck: function (event, node) {\n        if (node.chkDisabled === true) return false;\n        var setting = data.getSetting(event.data.treeId),\n          checkObj = $$(node, consts.id.CHECK, setting);\n        node.check_Focus = false;\n        view.setChkClass(setting, checkObj, node);\n        return true;\n      }\n    },\n    //method of tools for zTree\n    _tools = {},\n    //method of operate ztree dom\n    _view = {\n      checkNodeRelation: function (setting, node) {\n        var pNode, i, l,\n          r = consts.radio;\n        var nodeChecked = data.nodeChecked(setting, node);\n        if (setting.check.chkStyle == r.STYLE) {\n          var checkedList = data.getRadioCheckedList(setting);\n          if (nodeChecked) {\n            if (setting.check.radioType == r.TYPE_ALL) {\n              for (i = checkedList.length - 1; i >= 0; i--) {\n                pNode = checkedList[i];\n                var pNodeChecked = data.nodeChecked(setting, pNode);\n                if (pNodeChecked && pNode != node) {\n                  data.nodeChecked(setting, pNode, false);\n                  checkedList.splice(i, 1);\n\n                  view.setChkClass(setting, $$(pNode, consts.id.CHECK, setting), pNode);\n                  if (pNode.parentTId != node.parentTId) {\n                    view.repairParentChkClassWithSelf(setting, pNode);\n                  }\n                }\n              }\n              checkedList.push(node);\n            } else {\n              var parentNode = (node.parentTId) ? node.getParentNode() : data.getRoot(setting);\n              var children = data.nodeChildren(setting, parentNode);\n              for (i = 0, l = children.length; i < l; i++) {\n                pNode = children[i];\n                var pNodeChecked = data.nodeChecked(setting, pNode);\n                if (pNodeChecked && pNode != node) {\n                  data.nodeChecked(setting, pNode, false);\n                  view.setChkClass(setting, $$(pNode, consts.id.CHECK, setting), pNode);\n                }\n              }\n            }\n          } else if (setting.check.radioType == r.TYPE_ALL) {\n            for (i = 0, l = checkedList.length; i < l; i++) {\n              if (node == checkedList[i]) {\n                checkedList.splice(i, 1);\n                break;\n              }\n            }\n          }\n\n        } else {\n          var children = data.nodeChildren(setting, node);\n          if (nodeChecked && (!children || children.length == 0 || setting.check.chkboxType.Y.indexOf(\"s\") > -1)) {\n            view.setSonNodeCheckBox(setting, node, true);\n          }\n          if (!nodeChecked && (!children || children.length == 0 || setting.check.chkboxType.N.indexOf(\"s\") > -1)) {\n            view.setSonNodeCheckBox(setting, node, false);\n          }\n          if (nodeChecked && setting.check.chkboxType.Y.indexOf(\"p\") > -1) {\n            view.setParentNodeCheckBox(setting, node, true);\n          }\n          if (!nodeChecked && setting.check.chkboxType.N.indexOf(\"p\") > -1) {\n            view.setParentNodeCheckBox(setting, node, false);\n          }\n        }\n      },\n      makeChkClass: function (setting, node) {\n        var c = consts.checkbox, r = consts.radio,\n          fullStyle = \"\";\n        var nodeChecked = data.nodeChecked(setting, node);\n        if (node.chkDisabled === true) {\n          fullStyle = c.DISABLED;\n        } else if (node.halfCheck) {\n          fullStyle = c.PART;\n        } else if (setting.check.chkStyle == r.STYLE) {\n          fullStyle = (node.check_Child_State < 1) ? c.FULL : c.PART;\n        } else {\n          fullStyle = nodeChecked ? ((node.check_Child_State === 2 || node.check_Child_State === -1) ? c.FULL : c.PART) : ((node.check_Child_State < 1) ? c.FULL : c.PART);\n        }\n        var chkName = setting.check.chkStyle + \"_\" + (nodeChecked ? c.TRUE : c.FALSE) + \"_\" + fullStyle;\n        chkName = (node.check_Focus && node.chkDisabled !== true) ? chkName + \"_\" + c.FOCUS : chkName;\n        return consts.className.BUTTON + \" \" + c.DEFAULT + \" \" + chkName;\n      },\n      repairAllChk: function (setting, checked) {\n        if (setting.check.enable && setting.check.chkStyle === consts.checkbox.STYLE) {\n          var root = data.getRoot(setting);\n          var children = data.nodeChildren(setting, root);\n          for (var i = 0, l = children.length; i < l; i++) {\n            var node = children[i];\n            if (node.nocheck !== true && node.chkDisabled !== true) {\n              data.nodeChecked(setting, node, checked);\n            }\n            view.setSonNodeCheckBox(setting, node, checked);\n          }\n        }\n      },\n      repairChkClass: function (setting, node) {\n        if (!node) return;\n        data.makeChkFlag(setting, node);\n        if (node.nocheck !== true) {\n          var checkObj = $$(node, consts.id.CHECK, setting);\n          view.setChkClass(setting, checkObj, node);\n        }\n      },\n      repairParentChkClass: function (setting, node) {\n        if (!node || !node.parentTId) return;\n        var pNode = node.getParentNode();\n        view.repairChkClass(setting, pNode);\n        view.repairParentChkClass(setting, pNode);\n      },\n      repairParentChkClassWithSelf: function (setting, node) {\n        if (!node) return;\n        var children = data.nodeChildren(setting, node);\n        if (children && children.length > 0) {\n          view.repairParentChkClass(setting, children[0]);\n        } else {\n          view.repairParentChkClass(setting, node);\n        }\n      },\n      repairSonChkDisabled: function (setting, node, chkDisabled, inherit) {\n        if (!node) return;\n        if (node.chkDisabled != chkDisabled) {\n          node.chkDisabled = chkDisabled;\n        }\n        view.repairChkClass(setting, node);\n        var children = data.nodeChildren(setting, node);\n        if (children && inherit) {\n          for (var i = 0, l = children.length; i < l; i++) {\n            var sNode = children[i];\n            view.repairSonChkDisabled(setting, sNode, chkDisabled, inherit);\n          }\n        }\n      },\n      repairParentChkDisabled: function (setting, node, chkDisabled, inherit) {\n        if (!node) return;\n        if (node.chkDisabled != chkDisabled && inherit) {\n          node.chkDisabled = chkDisabled;\n        }\n        view.repairChkClass(setting, node);\n        view.repairParentChkDisabled(setting, node.getParentNode(), chkDisabled, inherit);\n      },\n      setChkClass: function (setting, obj, node) {\n        if (!obj) return;\n        if (node.nocheck === true) {\n          obj.hide();\n        } else {\n          obj.show();\n        }\n        obj.attr('class', view.makeChkClass(setting, node));\n      },\n      setParentNodeCheckBox: function (setting, node, value, srcNode) {\n        var checkObj = $$(node, consts.id.CHECK, setting);\n        if (!srcNode) srcNode = node;\n        data.makeChkFlag(setting, node);\n        if (node.nocheck !== true && node.chkDisabled !== true) {\n          data.nodeChecked(setting, node, value);\n          view.setChkClass(setting, checkObj, node);\n          if (setting.check.autoCheckTrigger && node != srcNode) {\n            setting.treeObj.trigger(consts.event.CHECK, [null, setting.treeId, node]);\n          }\n        }\n        if (node.parentTId) {\n          var pSign = true;\n          if (!value) {\n            var pNodes = data.nodeChildren(setting, node.getParentNode());\n            for (var i = 0, l = pNodes.length; i < l; i++) {\n              var pNode = pNodes[i];\n              var nodeChecked = data.nodeChecked(setting, pNode);\n              if ((pNode.nocheck !== true && pNode.chkDisabled !== true && nodeChecked)\n                || ((pNode.nocheck === true || pNode.chkDisabled === true) && pNode.check_Child_State > 0)) {\n                pSign = false;\n                break;\n              }\n            }\n          }\n          if (pSign) {\n            view.setParentNodeCheckBox(setting, node.getParentNode(), value, srcNode);\n          }\n        }\n      },\n      setSonNodeCheckBox: function (setting, node, value, srcNode) {\n        if (!node) return;\n        var checkObj = $$(node, consts.id.CHECK, setting);\n        if (!srcNode) srcNode = node;\n\n        var hasDisable = false;\n        var children = data.nodeChildren(setting, node);\n        if (children) {\n          for (var i = 0, l = children.length; i < l; i++) {\n            var sNode = children[i];\n            view.setSonNodeCheckBox(setting, sNode, value, srcNode);\n            if (sNode.chkDisabled === true) hasDisable = true;\n          }\n        }\n\n        if (node != data.getRoot(setting) && node.chkDisabled !== true) {\n          if (hasDisable && node.nocheck !== true) {\n            data.makeChkFlag(setting, node);\n          }\n          if (node.nocheck !== true && node.chkDisabled !== true) {\n            data.nodeChecked(setting, node, value);\n            if (!hasDisable) node.check_Child_State = (children && children.length > 0) ? (value ? 2 : 0) : -1;\n          } else {\n            node.check_Child_State = -1;\n          }\n          view.setChkClass(setting, checkObj, node);\n          if (setting.check.autoCheckTrigger && node != srcNode && node.nocheck !== true && node.chkDisabled !== true) {\n            setting.treeObj.trigger(consts.event.CHECK, [null, setting.treeId, node]);\n          }\n        }\n\n      }\n    },\n\n    _z = {\n      tools: _tools,\n      view: _view,\n      event: _event,\n      data: _data\n    };\n  $.extend(true, $.fn.zTree.consts, _consts);\n  $.extend(true, $.fn.zTree._z, _z);\n\n  var zt = $.fn.zTree,\n    tools = zt._z.tools,\n    consts = zt.consts,\n    view = zt._z.view,\n    data = zt._z.data,\n    event = zt._z.event,\n    $$ = tools.$;\n\n  data.nodeChecked = function (setting, node, newChecked) {\n    if (!node) {\n      return false;\n    }\n    var key = setting.data.key.checked;\n    if (typeof newChecked !== 'undefined') {\n      if (typeof newChecked === \"string\") {\n        newChecked = tools.eqs(newChecked, \"true\");\n      }\n      newChecked = !!newChecked;\n      node[key] = newChecked;\n    } else if (typeof node[key] == \"string\"){\n      node[key] = tools.eqs(node[key], \"true\");\n    } else {\n      node[key] = !!node[key];\n    }\n    return node[key];\n  };\n\n  data.exSetting(_setting);\n  data.addInitBind(_bindEvent);\n  data.addInitUnBind(_unbindEvent);\n  data.addInitCache(_initCache);\n  data.addInitNode(_initNode);\n  data.addInitProxy(_eventProxy, true);\n  data.addInitRoot(_initRoot);\n  data.addBeforeA(_beforeA);\n  data.addZTreeTools(_zTreeTools);\n\n  var _createNodes = view.createNodes;\n  view.createNodes = function (setting, level, nodes, parentNode, index) {\n    if (_createNodes) _createNodes.apply(view, arguments);\n    if (!nodes) return;\n    view.repairParentChkClassWithSelf(setting, parentNode);\n  }\n  var _removeNode = view.removeNode;\n  view.removeNode = function (setting, node) {\n    var parentNode = node.getParentNode();\n    if (_removeNode) _removeNode.apply(view, arguments);\n    if (!node || !parentNode) return;\n    view.repairChkClass(setting, parentNode);\n    view.repairParentChkClass(setting, parentNode);\n  }\n\n  var _appendNodes = view.appendNodes;\n  view.appendNodes = function (setting, level, nodes, parentNode, index, initFlag, openFlag) {\n    var html = \"\";\n    if (_appendNodes) {\n      html = _appendNodes.apply(view, arguments);\n    }\n    if (parentNode) {\n      data.makeChkFlag(setting, parentNode);\n    }\n    return html;\n  }\n})(jQuery);"
  },
  {
    "path": "xxl-job-admin/src/main/resources/templates/base/dashboard.ftl",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n    <#-- import macro -->\n    <#import \"../common/common.macro.ftl\" as netCommon>\n\n    <!-- 1-style start -->\n    <@netCommon.commonStyle />\n    <link rel=\"stylesheet\" href=\"${request.contextPath}/static/adminlte/bower_components/bootstrap-daterangepicker/daterangepicker.css\">\n    <!-- 1-style end -->\n\n</head>\n<body class=\"hold-transition\" style=\"background-color: #ecf0f5;\">\n<div class=\"wrapper\">\n    <section class=\"content\">\n\n        <#-- 2-biz start -->\n\n        <!-- 任务信息 -->\n        <div class=\"row\">\n\n            <#-- 任务信息 -->\n            <div class=\"col-md-4 col-sm-6 col-xs-12\">\n                <div class=\"info-box bg-aqua\">\n                    <span class=\"info-box-icon\"><i class=\"fa fa-flag-o\"></i></span>\n\n                    <div class=\"info-box-content\">\n                        <span class=\"info-box-text\">${I18n.job_dashboard_job_num}</span>\n                        <span class=\"info-box-number\">${jobInfoCount}</span>\n\n                        <div class=\"progress\">\n                            <div class=\"progress-bar\" style=\"width: 100%\"></div>\n                        </div>\n                        <span class=\"progress-description\">${I18n.job_dashboard_job_num_tip}</span>\n                    </div>\n                </div>\n            </div>\n\n            <#-- 调度信息 -->\n            <div class=\"col-md-4 col-sm-6 col-xs-12\" >\n                <div class=\"info-box bg-yellow\">\n                    <span class=\"info-box-icon\"><i class=\"fa fa-calendar\"></i></span>\n\n                    <div class=\"info-box-content\">\n                        <span class=\"info-box-text\">${I18n.job_dashboard_trigger_num}</span>\n                        <span class=\"info-box-number\">${jobLogCount}</span>\n\n                        <div class=\"progress\">\n                            <div class=\"progress-bar\" style=\"width: 100%\" ></div>\n                        </div>\n                        <span class=\"progress-description\">\n                                ${I18n.job_dashboard_trigger_num_tip}\n                            <#--<#if jobLogCount gt 0>\n                                调度成功率：${(jobLogSuccessCount*100/jobLogCount)?string(\"0.00\")}<small>%</small>\n                            </#if>-->\n                            </span>\n                    </div>\n                </div>\n            </div>\n\n            <#-- 执行器 -->\n            <div class=\"col-md-4 col-sm-6 col-xs-12\">\n                <div class=\"info-box bg-green\">\n                    <span class=\"info-box-icon\"><i class=\"fa ion-ios-settings-strong\"></i></span>\n\n                    <div class=\"info-box-content\">\n                        <span class=\"info-box-text\">${I18n.job_dashboard_jobgroup_num}</span>\n                        <span class=\"info-box-number\">${executorCount}</span>\n\n                        <div class=\"progress\">\n                            <div class=\"progress-bar\" style=\"width: 100%\"></div>\n                        </div>\n                        <span class=\"progress-description\">${I18n.job_dashboard_jobgroup_num_tip}</span>\n                    </div>\n                </div>\n            </div>\n\n        </div>\n\n        <#-- 调度报表：时间区间筛选，左侧折线图 + 右侧饼图 -->\n        <div class=\"row\">\n            <div class=\"col-md-12\">\n                <div class=\"box\">\n                    <div class=\"box-header with-border\">\n                        <h3 class=\"box-title\">${I18n.job_dashboard_report}</h3>\n                        <#--<input type=\"text\" class=\"form-control\" id=\"filterTime\" readonly >-->\n\n                        <!-- tools box -->\n                        <div class=\"pull-right box-tools\">\n                            <button type=\"button\" class=\"btn btn-primary btn-sm daterange pull-right\" data-toggle=\"tooltip\" id=\"filterTime\" >\n                                <i class=\"fa fa-calendar\"></i>\n                            </button>\n                            <#--<button type=\"button\" class=\"btn btn-primary btn-sm pull-right\" data-widget=\"collapse\" data-toggle=\"tooltip\" title=\"\" style=\"margin-right: 5px;\" data-original-title=\"Collapse\">\n                                <i class=\"fa fa-minus\"></i>\n                            </button>-->\n                        </div>\n                        <!-- /. tools -->\n\n                    </div>\n                    <div class=\"box-body\">\n                        <div class=\"row\">\n                            <#-- 左侧折线图 -->\n                            <div class=\"col-md-8\">\n                                <div id=\"lineChart\" style=\"height: 350px;\"></div>\n                            </div>\n                            <#-- 右侧饼图 -->\n                            <div class=\"col-md-4\">\n                                <div id=\"pieChart\" style=\"height: 350px;\"></div>\n                            </div>\n                        </div>\n                    </div>\n                </div>\n            </div>\n        </div>\n\n        <#-- 2-biz end -->\n\n    </section>\n</div>\n\n<!-- 3-script start -->\n<@netCommon.commonScript />\n<!-- daterangepicker -->\n<script src=\"${request.contextPath}/static/adminlte/bower_components/moment/moment.min.js\"></script>\n<script src=\"${request.contextPath}/static/adminlte/bower_components/bootstrap-daterangepicker/daterangepicker.js\"></script>\n<!-- echarts -->\n<script src=\"${request.contextPath}/static/plugins/echarts/echarts.common.min.js\"></script>\n<script>\n$(function () {\n\n    // filter Time\n    var rangesConf = {};\n    rangesConf[I18n.daterangepicker_ranges_today] = [moment().startOf('day'), moment().endOf('day')];\n    rangesConf[I18n.daterangepicker_ranges_yesterday] = [moment().subtract(1, 'days').startOf('day'), moment().subtract(1, 'days').endOf('day')];\n    rangesConf[I18n.daterangepicker_ranges_this_month] = [moment().startOf('month'), moment().endOf('month')];\n    rangesConf[I18n.daterangepicker_ranges_last_month] = [moment().subtract(1, 'months').startOf('month'), moment().subtract(1, 'months').endOf('month')];\n    rangesConf[I18n.daterangepicker_ranges_recent_week] = [moment().subtract(1, 'weeks').startOf('day'), moment().endOf('day')];\n    rangesConf[I18n.daterangepicker_ranges_recent_month] = [moment().subtract(1, 'months').startOf('day'), moment().endOf('day')];\n\n    $('#filterTime').daterangepicker({\n        autoApply:false,\n        singleDatePicker:false,\n        showDropdowns:false,        // 是否显示年月选择条件\n        timePicker: true, \t\t\t// 是否显示小时和分钟选择条件\n        timePickerIncrement: 10, \t// 时间的增量，单位为分钟\n        timePicker24Hour : true,\n        opens : 'left', //日期选择框的弹出位置\n        ranges: rangesConf,\n        locale : {\n            format: 'YYYY-MM-DD HH:mm:ss',\n            separator : ' - ',\n            customRangeLabel : I18n.daterangepicker_custom_name ,\n            applyLabel : I18n.system_ok ,\n            cancelLabel : I18n.system_cancel ,\n            fromLabel : I18n.daterangepicker_custom_starttime ,\n            toLabel : I18n.daterangepicker_custom_endtime ,\n            daysOfWeek : I18n.daterangepicker_custom_daysofweek.split(',') ,        // '日', '一', '二', '三', '四', '五', '六'\n            monthNames : I18n.daterangepicker_custom_monthnames.split(',') ,        // '一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'\n            firstDay : 1\n        },\n        startDate: rangesConf[I18n.daterangepicker_ranges_recent_week][0] ,\n        endDate: rangesConf[I18n.daterangepicker_ranges_recent_week][1]\n    }, function (start, end, label) {\n        freshChartDate(start, end);\n    });\n    freshChartDate(rangesConf[I18n.daterangepicker_ranges_recent_week][0], rangesConf[I18n.daterangepicker_ranges_recent_week][1]);\n\n    /**\n     * fresh Chart Date\n     *\n     * @param startDate\n     * @param endDate\n     */\n    function freshChartDate(startDate, endDate) {\n        $.ajax({\n            type : 'POST',\n            url : base_url + '/chartInfo',\n            data : {\n                'startDate':startDate.format('YYYY-MM-DD HH:mm:ss'),\n                'endDate':endDate.format('YYYY-MM-DD HH:mm:ss')\n            },\n            dataType : \"json\",\n            success : function(data){\n                if (data.code == 200) {\n                    lineChartInit(data.data)\n                    pieChartInit(data.data);\n                } else {\n                    layer.open({\n                        title: I18n.system_tips ,\n                        btn: [ I18n.system_ok ],\n                        content: (data.msg || I18n.job_dashboard_report_loaddata_fail ),\n                        icon: '2'\n                    });\n                }\n            }\n        });\n    }\n\n    /**\n     * line Chart Init\n     */\n    function lineChartInit(data) {\n        var option = {\n            title: {\n                text: I18n.job_dashboard_date_report\n            },\n            tooltip : {\n                trigger: 'axis',\n                axisPointer: {\n                    type: 'cross',\n                    label: {\n                        backgroundColor: '#6a7985'\n                    }\n                }\n            },\n            legend: {\n                data:[I18n.joblog_status_suc, I18n.joblog_status_fail, I18n.joblog_status_running]\n            },\n            toolbox: {\n                feature: {\n                    /*saveAsImage: {}*/\n                }\n            },\n            grid: {\n                left: '3%',\n                right: '4%',\n                bottom: '3%',\n                containLabel: true\n            },\n            xAxis : [\n                {\n                    type : 'category',\n                    boundaryGap : false,\n                    data : data.triggerDayList\n                }\n            ],\n            yAxis : [\n                {\n                    type : 'value'\n                }\n            ],\n            series : [\n                {\n                    name:I18n.joblog_status_suc,\n                    type:'line',\n                    stack: 'Total',\n                    areaStyle: {normal: {}},\n                    data: data.triggerDayCountSucList\n                },\n                {\n                    name:I18n.joblog_status_fail,\n                    type:'line',\n                    stack: 'Total',\n                    label: {\n                        normal: {\n                            show: true,\n                            position: 'top'\n                        }\n                    },\n                    areaStyle: {normal: {}},\n                    data: data.triggerDayCountFailList\n                },\n                {\n                    name:I18n.joblog_status_running,\n                    type:'line',\n                    stack: 'Total',\n                    areaStyle: {normal: {}},\n                    data: data.triggerDayCountRunningList\n                }\n            ],\n            color:['#00A65A', '#c23632', '#F39C12']\n        };\n\n        var lineChart = echarts.init(document.getElementById('lineChart'));\n        lineChart.setOption(option);\n    }\n\n    /**\n     * pie Chart Init\n     */\n    function pieChartInit(data) {\n        var option = {\n            title : {\n                text: I18n.job_dashboard_rate_report ,\n                /*subtext: 'subtext',*/\n                x:'center'\n            },\n            tooltip : {\n                trigger: 'item',\n                formatter: \"{b} : {c} ({d}%)\"\n            },\n            legend: {\n                orient: 'vertical',\n                left: 'left',\n                data: [I18n.joblog_status_suc, I18n.joblog_status_fail, I18n.joblog_status_running ]\n            },\n            series : [\n                {\n                    //name: '分布比例',\n                    type: 'pie',\n                    radius : '55%',\n                    center: ['50%', '60%'],\n                    data:[\n                        {\n                            name:I18n.joblog_status_suc,\n                            value:data.triggerCountSucTotal\n                        },\n                        {\n                            name:I18n.joblog_status_fail,\n                            value:data.triggerCountFailTotal\n                        },\n                        {\n                            name:I18n.joblog_status_running,\n                            value:data.triggerCountRunningTotal\n                        }\n                    ],\n                    itemStyle: {\n                        emphasis: {\n                            shadowBlur: 10,\n                            shadowOffsetX: 0,\n                            shadowColor: 'rgba(0, 0, 0, 0.5)'\n                        }\n                    }\n                }\n            ],\n            color:['#00A65A', '#c23632', '#F39C12']\n        };\n        var pieChart = echarts.init(document.getElementById('pieChart'));\n        pieChart.setOption(option);\n    }\n\n});\n</script>\n<!-- 3-script end -->\n\n</body>\n</html>"
  },
  {
    "path": "xxl-job-admin/src/main/resources/templates/base/help.ftl",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n\t<#-- import macro -->\n\t<#import \"../common/common.macro.ftl\" as netCommon>\n\n\t<!-- 1-style start -->\n\t<@netCommon.commonStyle />\n\t<!-- 1-style end -->\n\n</head>\n<body class=\"hold-transition\" style=\"background-color: #ecf0f5;\">\n<div class=\"wrapper\">\n\t<section class=\"content\">\n\n\t\t<#-- 2-biz start -->\n\t\t<div class=\"callout callout-info\">\n\t\t\t<h4>${I18n.admin_name_full}</h4>\n\t\t\t<br>\n\t\t\t<p>\n\n\t\t\t\t<a target=\"_blank\" href=\"https://github.com/xuxueli/xxl-job\">Github</a>&nbsp;&nbsp;&nbsp;&nbsp;\n\t\t\t\t<iframe src=\"https://ghbtns.com/github-btn.html?user=xuxueli&repo=xxl-job&type=star&count=true\" frameborder=\"0\" scrolling=\"0\" width=\"170px\" height=\"20px\" style=\"margin-bottom:-5px;\"></iframe>\n\t\t\t\t<br><br>\n\t\t\t\t<a target=\"_blank\" href=\"https://www.xuxueli.com/xxl-job/\">${I18n.admin_help_document}</a>\n\t\t\t\t<br><br>\n\n\t\t\t</p>\n\t\t\t<p></p>\n\t\t</div>\n\t\t<#-- 2-biz end -->\n\n\t</section>\n</div>\n\n<!-- 3-script start -->\n<@netCommon.commonScript />\n<!-- 3-script end -->\n\n</body>\n</html>"
  },
  {
    "path": "xxl-job-admin/src/main/resources/templates/base/index.ftl",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n    <#-- import macro -->\n    <#import \"../common/common.macro.ftl\" as netCommon>\n\n    <!-- 1-style start -->\n    <@netCommon.commonStyle />\n    <link rel=\"stylesheet\" href=\"${request.contextPath}/static/biz/common/admin.tab.css?v=${I18n.admin_version}\">\n    <!-- 1-style end -->\n\n</head>\n<body class=\"hold-transition skin-blue sidebar-mini fixed\" >\n<div class=\"wrapper\" >\n\n    <!-- 2-header start -->\n    <header class=\"main-header\">\n        <!-- header logo -->\n        <a href=\"${request.contextPath}/\" class=\"logo\">\n            <span class=\"logo-mini\"><b>XXL</b></span>\n            <span class=\"logo-lg\"><b>${I18n.admin_name}</b></span>\n        </a>\n        <nav class=\"navbar navbar-static-top\" role=\"navigation\">\n            <!--header left -->\n            <a href=\"#\" class=\"sidebar-toggle\" data-toggle=\"push-menu\" role=\"button\">\n                <span class=\"sr-only\">Toggle navigation</span>\n                <span class=\"icon-bar\"></span>\n                <span class=\"icon-bar\"></span>\n                <span class=\"icon-bar\"></span>\n            </a>\n            <!--header right -->\n            <div class=\"navbar-custom-menu\">\n                <ul class=\"nav navbar-nav\">\n\n                    <#-- login user -->\n                    <li class=\"dropdown\">\n                        <a href=\"javascript:\" class=\"dropdown-toggle\" data-toggle=\"dropdown\" aria-expanded=\"false\" style=\"font-weight: bold;\">\n                            ${I18n.system_welcome}：${xxl_sso_user.userName!}\n                            <span class=\"caret\"></span>\n                        </a>\n                        <ul class=\"dropdown-menu\" role=\"menu\">\n                            <li id=\"updatePwd\" >\n                                <a href=\"javascript:\" style=\"height: 30px;padding: 3px 25px;color: #777;\" ><i class=\"fa fa-key\"></i> ${I18n.change_pwd}</a>\n                            </li>\n                            <li id=\"changeSkin\" >\n                                <a href=\"javascript:\" style=\"height: 30px;padding: 3px 25px;color: #777;\" ><i class=\"fa fa-key\"></i> ${I18n.change_skin}</a>\n                            </li>\n                            <li id=\"logoutBtn\" >\n                                <a href=\"javascript:\" style=\"height: 30px;padding: 3px 25px;color: #777;\" ><i class=\"fa fa-sign-out\"></i> ${I18n.logout_btn}</a>\n                            </li>\n                        </ul>\n\n                    </li>\n                </ul>\n            </div>\n\n        </nav>\n    </header>\n    <!-- 2-header end -->\n\n    <!-- 3-left start -->\n    <aside class=\"main-sidebar\">\n        <section class=\"sidebar\" style=\"height: auto;\" >\n            <!-- sidebar menu -->\n            <ul class=\"sidebar-menu\" data-widget=\"tree\" >\n                <li class=\"header\">${I18n.system_nav}</li>\n                <#if resourceList?? && resourceList?size gt 0>\n                    <@renderMenu resourceList />\n                </#if>\n            </ul>\n            <#-- render menu -->\n            <#macro renderMenu resourceList >\n                <#list resourceList as resource>\n                    <#if resource.type ==0>\n                    <#-- catalog -->\n                        <li class=\"treeview\" style=\"height: auto;\"  >\n                            <a href=\"javascript:void(0);\">\n                                <i class=\"fa ${resource.icon}\"></i>\n                                <span>${resource.name}</span>\n                                <span class=\"pull-right-container\">\n                                    <i class=\"fa fa-angle-left pull-right\"></i>\n                                </span>\n                            </a>\n                            <ul class=\"treeview-menu\" >\n                                <#if resource.children?? && resource.children?size gt 0>\n                                    <@renderMenu resource.children />\n                                </#if>\n                            </ul>\n                        </li>\n                    <#elseif resource.type ==1>\n                    <#-- menu -->\n                        <li class=\"nav-click\">\n                            <#-- url -->\n                            <#assign resourceUrl = request.contextPath + resource.url />\n                            <#if resource.url?starts_with(\"http\") >\n                                <#assign resourceUrl = resource.url />\n                            </#if>\n                            <#-- menu -->\n                            <a class=\"J_menuItem\" href=\"${resourceUrl}\">\n                                <i class=\"fa ${resource.icon}\"></i>\n                                <span>${resource.name}</span>\n                            </a>\n                        </li>\n                    </#if>\n                </#list>\n            </#macro>\n        </section>\n    </aside>\n    <!-- 3-left end -->\n\n    <!-- 4-right start -->\n    <div class=\"content-wrapper\">\n\n        <!-- Tabs -->\n        <div class=\"content-tabs\">\n            <!-- left -->\n            <button class=\"roll-nav roll-left J_tabLeft\"><i class=\"fa fa-backward\"></i></button>\n\n            <!-- Tab -->\n            <nav class=\"page-tabs J_menuTabs\">\n                <div class=\"page-tabs-content\">\n                    <#-- Tab content -->\n                    <#-- <a href=\"javascript:;\" class=\"active J_menuTab\" data-id=\"' + tabSrc + '\" title=\"'+ tabName +'\" >' + tabNameShow + ' <i class=\"fa fa-times-circle\"></i></a> -->\n                </div>\n            </nav>\n\n            <!-- right -->\n            <button class=\"roll-nav roll-right J_tabRight\"><i class=\"fa fa-forward\"></i></button>\n            <!-- opt -->\n            <div class=\"btn-group roll-nav roll-right\">\n                <button class=\"dropdown\" data-toggle=\"dropdown\">${I18n.tab_opt}<span class=\"caret\"></span></button>\n                <ul role=\"menu\" class=\"dropdown-menu dropdown-menu-right\">\n                    <li class=\"tabCloseCurrent\"><a>${I18n.tab_close_current}</a></li>\n                    <li class=\"J_tabCloseOther\"><a>${I18n.tab_close_other}</a></li>\n                    <li class=\"J_tabCloseAll\"><a>${I18n.tab_close_all}</a></li>\n                </ul>\n            </div>\n            <!-- refresh -->\n            <a href=\"#\" class=\"roll-nav roll-right tabReload\"><i class=\"fa fa-refresh\"></i> ${I18n.tab_refresh}</a>\n            <!-- fullscreen -->\n            <a href=\"#\" class=\"roll-nav roll-right fullscreen\" id=\"fullScreen\"><i class=\"fa fa-arrows-alt\"></i></a>\n        </div>\n        <!-- Iframe Content -->\n        <div class=\"J_mainContent\" id=\"content-main\" >\n            <!-- Iframe content -->\n            <#-- <iframe class=\"J_iframe\" width=\"100%\" height=\"100%\" src=\"' + tabSrc + '\" frameborder=\"0\" data-id=\"' + tabSrc + '\" seamless></iframe> -->\n        </div>\n\n    </div>\n    <!-- 4-right end -->\n\n    <!-- 5-footer start -->\n    <footer class=\"main-footer\">\n        Powered by <b>XXL-JOB</b> ${I18n.admin_version}\n        <div class=\"pull-right hidden-xs\">\n            <strong>Copyright &copy; 2015-${.now?string('yyyy')} &nbsp;\n                <a href=\"https://www.xuxueli.com/\" target=\"_blank\" >xuxueli</a>\n                &nbsp;\n                <a href=\"https://github.com/xuxueli/xxl-job\" target=\"_blank\" >github</a>\n            </strong><!-- All rights reserved. -->\n        </div>\n    </footer>\n    <!-- 5-footer end -->\n\n</div>\n\n<!-- 6-script start -->\n<@netCommon.commonScript />\n<script src=\"${request.contextPath}/static/biz/common/admin.tab.js?v=${I18n.admin_version}\"></script>\n<script src=\"${request.contextPath}/static/biz/common/admin.setting.js?v=${I18n.admin_version}\"></script>\n<script>\n    $(function () {\n        // init admin tab\n        $.adminTab.initTab();\n    });\n</script>\n<!-- 6-script end -->\n\n</body>\n</html>\n"
  },
  {
    "path": "xxl-job-admin/src/main/resources/templates/base/login.ftl",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n\t<#-- import macro -->\n\t<#import \"../common/common.macro.ftl\" as netCommon>\n\n\t<!-- 1-style start -->\n\t<@netCommon.commonStyle />\n\t<!-- iCheck -->\n\t<link rel=\"stylesheet\" href=\"${request.contextPath}/static/adminlte/plugins/iCheck/square/blue.css\">\n\t<!-- 1-style end -->\n\n</head>\n<body class=\"hold-transition login-page\">\n\n\t<!-- 2-biz start -->\n\t<div class=\"login-box\">\n\t\t<div class=\"login-logo\">\n\t\t\t<a><b>XXL-JOB</b></a>\n\t\t</div>\n\t\t<form id=\"loginForm\" method=\"post\" >\n\t\t\t<div class=\"login-box-body\">\n\t\t\t\t<p class=\"login-box-msg\">${I18n.admin_name}</p>\n\t\t\t\t<div class=\"form-group has-feedback\">\n\t            \t<input type=\"text\" name=\"userName\" class=\"form-control\" placeholder=\"${I18n.login_username_placeholder}\"  maxlength=\"20\" >\n\t            \t<span class=\"glyphicon glyphicon-envelope form-control-feedback\"></span>\n\t\t\t\t</div>\n\t          \t<div class=\"form-group has-feedback\">\n\t            \t<input type=\"password\" name=\"password\" class=\"form-control\" placeholder=\"${I18n.login_password_placeholder}\"  maxlength=\"20\" >\n\t            \t<span class=\"glyphicon glyphicon-lock form-control-feedback\"></span>\n\t          \t</div>\n\t\t\t\t<div class=\"row\">\n\t\t\t\t\t<div class=\"col-xs-8\">\n\t\t              \t<div class=\"checkbox icheck\">\n\t\t                \t<label>\n\t\t                  \t\t<input type=\"checkbox\" name=\"ifRemember\" > &nbsp; ${I18n.login_remember_me}\n\t\t                \t</label>\n\t\t\t\t\t\t</div>\n\t\t            </div><!-- /.col -->\n\t\t            <div class=\"col-xs-4\">\n\t\t\t\t\t\t<button type=\"submit\" class=\"btn btn-primary btn-block btn-flat\">${I18n.login_btn}</button>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</form>\n\t</div>\n\t<!-- 2-biz end -->\n\n<!-- 3-script start -->\n<@netCommon.commonScript />\n<script src=\"${request.contextPath}/static/adminlte/plugins/iCheck/icheck.min.js\"></script>\n<script>\n$(function () {\n\n\t// input iCheck\n\t$('input').iCheck({\n\t\tcheckboxClass: 'icheckbox_square-blue',\n\t\tradioClass: 'iradio_square-blue',\n\t\tincreaseArea: '20%' // optional\n\t});\n\n\t// login Form Valid\n\tvar loginFormValid = $(\"#loginForm\").validate({\n\t\terrorElement : 'span',\n\t\terrorClass : 'help-block',\n\t\tfocusInvalid : true,\n\t\trules : {\n\t\t\tuserName : {\n\t\t\t\trequired : true ,\n\t\t\t\tminlength: 4,\n\t\t\t\tmaxlength: 20\n\t\t\t},\n\t\t\tpassword : {\n\t\t\t\trequired : true ,\n\t\t\t\tminlength: 4,\n\t\t\t\tmaxlength: 20\n\t\t\t}\n\t\t},\n\t\tmessages : {\n\t\t\tuserName : {\n\t\t\t\trequired  : I18n.login_username_empty,\n\t\t\t\tminlength : I18n.login_username_lt_4\n\t\t\t},\n\t\t\tpassword : {\n\t\t\t\trequired  : I18n.login_password_empty  ,\n\t\t\t\tminlength : I18n.login_password_lt_4\n\t\t\t\t/*,maxlength:\"登录密码不应超过18位\"*/\n\t\t\t}\n\t\t},\n\t\thighlight : function(element) {\n\t\t\t$(element).closest('.form-group').addClass('has-error');\n\t\t},\n\t\tsuccess : function(label) {\n\t\t\tlabel.closest('.form-group').removeClass('has-error');\n\t\t\tlabel.remove();\n\t\t},\n\t\terrorPlacement : function(error, element) {\n\t\t\telement.parent('div').append(error);\n\t\t},\n\t\tsubmitHandler : function(form) {\n\t\t\t$.post(base_url + \"/auth/doLogin\", $(\"#loginForm\").serialize(), function(data, status) {\n\t\t\t\tif (data.code === 200) {\n\t\t\t\t\tlayer.msg( I18n.login_success );\n\t\t\t\t\tsetTimeout(function(){\n\t\t\t\t\t\twindow.location.href = base_url + \"/\";\n\t\t\t\t\t}, 500);\n\t\t\t\t} else {\n\t\t\t\t\tlayer.open({\n\t\t\t\t\t\ttitle: I18n.system_tips,\n\t\t\t\t\t\tbtn: [ I18n.system_ok ],\n\t\t\t\t\t\tcontent: (data.msg || I18n.login_fail ),\n\t\t\t\t\t\ticon: '2'\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t});\n\n});\n</script>\n<!-- 3-script end -->\n\n\n</body>\n</html>\n"
  },
  {
    "path": "xxl-job-admin/src/main/resources/templates/biz/group.list.ftl",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n\t<#-- import macro -->\n\t<#import \"../common/common.macro.ftl\" as netCommon>\n\n\t<!-- 1-style start -->\n\t<@netCommon.commonStyle />\n\t<link rel=\"stylesheet\" href=\"${request.contextPath}/static/plugins/bootstrap-table/bootstrap-table.min.css\">\n\t<link rel=\"stylesheet\" href=\"${request.contextPath}/static/adminlte/plugins/iCheck/square/blue.css\">\n\t<!-- 1-style end -->\n\n</head>\n<body class=\"hold-transition\" style=\"background-color: #ecf0f5;\">\n<div class=\"wrapper\">\n\t<section class=\"content\">\n\n\t\t<!-- 2-content start -->\n\n\t\t<#-- 查询区域 -->\n\t\t<div class=\"box\" style=\"margin-bottom:9px;\">\n\t\t\t<div class=\"box-body\">\n\t\t\t\t<div class=\"row\" id=\"data_filter\" >\n\n\t\t\t\t\t<div class=\"col-xs-3\">\n\t\t\t\t\t\t<div class=\"input-group\">\n\t\t\t\t\t\t\t<span class=\"input-group-addon\">AppName</span>\n\t\t\t\t\t\t\t<input type=\"text\" class=\"form-control\" id=\"appname\" placeholder=\"${I18n.system_please_input}AppName\" >\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"col-xs-3\">\n\t\t\t\t\t\t<div class=\"input-group\">\n\t\t\t\t\t\t\t<span class=\"input-group-addon\">${I18n.jobgroup_field_title}</span>\n\t\t\t\t\t\t\t<input type=\"text\" class=\"form-control\" id=\"title\" placeholder=\"${I18n.jobgroup_field_title}\" >\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div class=\"col-xs-1\">\n\t\t\t\t\t\t<button class=\"btn btn-block btn-primary searchBtn\" >${I18n.system_search}</button>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"col-xs-1\">\n\t\t\t\t\t\t<button class=\"btn btn-block btn-default resetBtn\" >${I18n.system_reset}</button>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<#-- 数据表格区域 -->\n\t\t<div class=\"row\">\n\t\t\t<div class=\"col-xs-12\">\n\t\t\t\t<div class=\"box\">\n\t\t\t\t\t<div class=\"box-header pull-left\" id=\"data_operation\" >\n\t\t\t\t\t\t<button class=\"btn btn-sm btn-info add\" type=\"button\"><i class=\"fa fa-plus\" ></i>${I18n.system_opt_add}</button>\n\t\t\t\t\t\t<button class=\"btn btn-sm btn-warning selectOnlyOne update\" type=\"button\"><i class=\"fa fa-edit\"></i>${I18n.system_opt_edit}</button>\n\t\t\t\t\t\t<button class=\"btn btn-sm btn-danger selectOnlyOne delete\" type=\"button\"><i class=\"fa fa-remove \"></i>${I18n.system_opt_del}</button>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"box-body\" >\n\t\t\t\t\t\t<table id=\"data_list\" class=\"table table-bordered table-striped\" width=\"100%\" >\n\t\t\t\t\t\t\t<thead></thead>\n\t\t\t\t\t\t\t<tbody></tbody>\n\t\t\t\t\t\t\t<tfoot></tfoot>\n\t\t\t\t\t\t</table>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<!-- 注册列表查看.模态框 -->\n\t\t<div class=\"modal fade\" id=\"showRegistryListModal\" tabindex=\"-1\" role=\"dialog\"  aria-hidden=\"true\">\n\t\t\t<div class=\"modal-dialog\">\n\t\t\t\t<div class=\"modal-content\">\n\t\t\t\t\t<div class=\"modal-header\">\n\t\t\t\t\t\t<h4 class=\"modal-title\" >${I18n.jobinfo_opt_registryinfo}</h4>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"modal-body\">\n\t\t\t\t\t\t<div class=\"data\" style=\"word-wrap: break-word;\"></div>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"modal-footer\">\n\t\t\t\t\t\t<div class=\"text-center\" >\n\t\t\t\t\t\t\t<button type=\"button\" class=\"btn btn-info ok\" data-dismiss=\"modal\" >${I18n.system_ok}</button>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<!-- 新增.模态框 -->\n\t\t<div class=\"modal fade\" id=\"addModal\" tabindex=\"-1\" role=\"dialog\"  aria-hidden=\"true\">\n\t\t\t<div class=\"modal-dialog \">\n\t\t\t\t<div class=\"modal-content\">\n\t\t\t\t\t<div class=\"modal-header\">\n\t\t\t\t\t\t<h4 class=\"modal-title\" >${I18n.jobgroup_add}</h4>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"modal-body\">\n\t\t\t\t\t\t<form class=\"form-horizontal form\" role=\"form\" >\n\t\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t\t<label for=\"lastname\" class=\"col-sm-2 control-label\">AppName<font color=\"red\">*</font></label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-10\"><input type=\"text\" class=\"form-control\" name=\"appname\" placeholder=\"${I18n.system_please_input}AppName\" maxlength=\"64\" ></div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t\t<label for=\"lastname\" class=\"col-sm-2 control-label\">${I18n.jobgroup_field_title}<font color=\"red\">*</font></label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-10\"><input type=\"text\" class=\"form-control\" name=\"title\" placeholder=\"${I18n.system_please_input}${I18n.jobgroup_field_title}\" maxlength=\"12\" ></div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t\t<label for=\"lastname\" class=\"col-sm-2 control-label\">${I18n.jobgroup_field_addressType}<font color=\"red\">*</font></label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-10\">\n\t\t\t\t\t\t\t\t\t<input type=\"radio\" name=\"addressType\" value=\"0\" checked />${I18n.jobgroup_field_addressType_0}\n\t\t\t\t\t\t\t\t\t&nbsp;&nbsp;&nbsp;&nbsp;\n\t\t\t\t\t\t\t\t\t<input type=\"radio\" name=\"addressType\" value=\"1\" />${I18n.jobgroup_field_addressType_1}\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t\t<label for=\"lastname\" class=\"col-sm-2 control-label\">${I18n.jobgroup_field_registryList}<font color=\"red\">*</font></label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-10\">\n\t\t\t\t\t\t\t\t\t<textarea class=\"textarea\" name=\"addressList\" maxlength=\"20000\" placeholder=\"${I18n.jobgroup_field_registryList_placeholder}\" readonly=\"readonly\" style=\"background-color:#eee; width: 100%; height: 100px; font-size: 14px; line-height: 15px; border: 1px solid #dddddd; padding: 5px;\"></textarea>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<hr>\n\t\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t\t<div class=\"col-sm-offset-3 col-sm-6\">\n\t\t\t\t\t\t\t\t\t<button type=\"submit\" class=\"btn btn-primary\"  >${I18n.system_save}</button>\n\t\t\t\t\t\t\t\t\t<button type=\"button\" class=\"btn btn-default\" data-dismiss=\"modal\">${I18n.system_cancel}</button>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</form>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<!-- 更新.模态框 -->\n\t\t<div class=\"modal fade\" id=\"updateModal\" tabindex=\"-1\" role=\"dialog\"  aria-hidden=\"true\">\n\t\t\t<div class=\"modal-dialog \">\n\t\t\t\t<div class=\"modal-content\">\n\t\t\t\t\t<div class=\"modal-header\">\n\t\t\t\t\t\t<h4 class=\"modal-title\" >${I18n.jobgroup_edit}</h4>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"modal-body\">\n\t\t\t\t\t\t<form class=\"form-horizontal form\" role=\"form\" >\n\t\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t\t<label for=\"lastname\" class=\"col-sm-2 control-label\">AppName<font color=\"red\">*</font></label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-10\"><input type=\"text\" class=\"form-control\" name=\"appname\" placeholder=\"${I18n.system_please_input}AppName\" maxlength=\"64\" ></div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t\t<label for=\"lastname\" class=\"col-sm-2 control-label\">${I18n.jobgroup_field_title}<font color=\"red\">*</font></label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-10\"><input type=\"text\" class=\"form-control\" name=\"title\" placeholder=\"${I18n.system_please_input}${I18n.jobgroup_field_title}\" maxlength=\"12\" ></div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t\t<label for=\"lastname\" class=\"col-sm-2 control-label\">${I18n.jobgroup_field_addressType}<font color=\"red\">*</font></label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-10\">\n\t\t\t\t\t\t\t\t\t<input type=\"radio\" name=\"addressType\" value=\"0\" />${I18n.jobgroup_field_addressType_0}\n\t\t\t\t\t\t\t\t\t&nbsp;&nbsp;&nbsp;&nbsp;\n\t\t\t\t\t\t\t\t\t<input type=\"radio\" name=\"addressType\" value=\"1\" />${I18n.jobgroup_field_addressType_1}\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t\t<label for=\"lastname\" class=\"col-sm-2 control-label\">${I18n.jobgroup_field_registryList}<font color=\"red\">*</font></label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-10\">\n\t\t\t\t\t\t\t\t\t<textarea class=\"textarea\" name=\"addressList\" maxlength=\"20000\" placeholder=\"${I18n.jobgroup_field_registryList_placeholder}\" readonly=\"readonly\" style=\"background-color:#eee; width: 100%; height: 100px; font-size: 14px; line-height: 15px; border: 1px solid #dddddd; padding: 5px;\"></textarea>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<hr>\n\t\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t\t<div class=\"col-sm-offset-3 col-sm-6\">\n\t\t\t\t\t\t\t\t\t<button type=\"submit\" class=\"btn btn-primary\"  >${I18n.system_save}</button>\n\t\t\t\t\t\t\t\t\t<button type=\"button\" class=\"btn btn-default\" data-dismiss=\"modal\">${I18n.system_cancel}</button>\n\t\t\t\t\t\t\t\t\t<input type=\"hidden\" name=\"id\" >\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</form>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<!-- 2-content end -->\n\n\t</section>\n</div>\n\n<!-- 3-script start -->\n<@netCommon.commonScript />\n<script src=\"${request.contextPath}/static/plugins/bootstrap-table/bootstrap-table.min.js\"></script>\n<script src=\"${request.contextPath}/static/plugins/bootstrap-table/locale/<#if I18n.admin_i18n?? && I18n.admin_i18n == 'en'>bootstrap-table-en-US.min.js<#else>bootstrap-table-zh-CN.min.js</#if>\"></script>\n<script src=\"${request.contextPath}/static/adminlte/plugins/iCheck/icheck.min.js\"></script>\n<#-- admin table -->\n<script src=\"${request.contextPath}/static/biz/common/admin.table.js\"></script>\n<script>\n\t$(function() {\n\n\t\t/**\n\t\t * init table\n\t\t */\n\t\t$.adminTable.initTable({\n\t\t\ttable: '#data_list',\n\t\t\turl: base_url + \"/jobgroup/pageList\",\n\t\t\tqueryParams: function (params) {\n\t\t\t\tvar obj = {};\n\t\t\t\tobj.appname = $('#appname').val();\n\t\t\t\tobj.title = $('#title').val();\n\t\t\t\tobj.offset = params.offset;\n\t\t\t\tobj.pagesize = params.limit;\n\t\t\t\treturn obj;\n\t\t\t},\n\t\t\tcolumns:[\n\t\t\t\t{\n\t\t\t\t\tcheckbox: true,\n\t\t\t\t\tfield: 'state',\n\t\t\t\t\twidth: '5',\n\t\t\t\t\twidthUnit: '%',\n\t\t\t\t\talign: 'center',\n\t\t\t\t\tvalign: 'middle'\n\t\t\t\t},{\n\t\t\t\t\ttitle: 'AppName',\n\t\t\t\t\tfield: 'appname',\n\t\t\t\t\twidth: '30',\n\t\t\t\t\twidthUnit: '%',\n\t\t\t\t\talign: 'left'\n\t\t\t\t},{\n\t\t\t\t\ttitle: I18n.jobgroup_field_title,\n\t\t\t\t\tfield: 'title',\n\t\t\t\t\twidth: '30',\n\t\t\t\t\twidthUnit: '%'\n\t\t\t\t},{\n\t\t\t\t\ttitle: I18n.jobgroup_field_addressType,\n\t\t\t\t\tfield: 'addressType',\n\t\t\t\t\twidth: '10',\n\t\t\t\t\twidthUnit: '%',\n\t\t\t\t\tformatter: function(value, row, index) {\n\t\t\t\t\t\tif (row.addressType == 0) {\n\t\t\t\t\t\t\treturn I18n.jobgroup_field_addressType_0;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treturn I18n.jobgroup_field_addressType_1;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},{\n\t\t\t\t\ttitle: 'OnLine' + I18n.jobgroup_field_registryList,\n\t\t\t\t\tfield: 'registryList',\n\t\t\t\t\twidth: '15',\n\t\t\t\t\twidthUnit: '%',\n\t\t\t\t\tformatter: function(value, row, index) {\n\t\t\t\t\t\ttableData['key' + row.id] = row;\n\t\t\t\t\t\treturn row.registryList\n\t\t\t\t\t\t\t\t?'<a class=\"show_registryList\" href=\"javascript:;\" _id=\"'+ row.id +'\" >' + I18n.system_show +' ( ' + row.registryList.length+ ' ）</a>'\n\t\t\t\t\t\t\t\t:I18n.system_empty;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t]\n\t\t});\n\n\t\t// job registryinfo\n\t\tvar tableData = {};\n\t\t$(\"#data_list\").on('click', '.show_registryList',function() {\n\t\t\tvar id = $(this).attr(\"_id\");\n\t\t\tvar row = tableData['key'+id];\n\n\t\t\tvar html = '<table class=\"table table-bordered\"><tbody>';\n\t\t\tif (row.registryList) {\n\t\t\t\tfor (var index in row.registryList) {\n\t\t\t\t\thtml += '<tr><th class=\"col-md-3\" >' + (parseInt(index)+1) + '</th>';\n\t\t\t\t\thtml += '<th class=\"col-md-9\" ><span class=\"badge bg-green\" >' + row.registryList[index] + '</span></th><tr>';\n\t\t\t\t}\n\t\t\t}\n\t\t\thtml += '</tbody></table>';\n\n\t\t\t$('#showRegistryListModal .data').html(html);\n\t\t\t$('#showRegistryListModal').modal({backdrop: false, keyboard: false}).modal('show');\n\t\t});\n\n\t\t/**\n\t\t * init delete\n\t\t */\n\t\t$.adminTable.initDelete({\n\t\t\turl: base_url + \"/jobgroup/delete\"\n\t\t});\n\n\t\t/**\n\t\t * init add\n\t\t */\n\t\t// add validator method\n\t\tjQuery.validator.addMethod(\"myValid01\", function(value, element) {\n\t\t\tvar length = value.length;\n\t\t\tvar valid = /^[a-z][a-zA-Z0-9-]*$/;\n\t\t\treturn this.optional(element) || valid.test(value);\n\t\t}, I18n.jobgroup_field_appname_limit );\n\t\t$.adminTable.initAdd( {\n\t\t\turl: base_url + \"/jobgroup/insert\",\n\t\t\trules : {\n\t\t\t\tappname : {\n\t\t\t\t\trequired : true,\n\t\t\t\t\trangelength:[4,64],\n\t\t\t\t\tmyValid01 : true\n\t\t\t\t},\n\t\t\t\ttitle : {\n\t\t\t\t\trequired : true,\n\t\t\t\t\trangelength:[4, 12]\n\t\t\t\t}\n\t\t\t},\n\t\t\tmessages : {\n\t\t\t\tappname : {\n\t\t\t\t\trequired : I18n.system_please_input+\"AppName\",\n\t\t\t\t\trangelength: I18n.jobgroup_field_appname_length ,\n\t\t\t\t\tmyValid01: I18n.jobgroup_field_appname_limit\n\t\t\t\t},\n\t\t\t\ttitle : {\n\t\t\t\t\trequired : I18n.system_please_input + I18n.jobgroup_field_title ,\n\t\t\t\t\trangelength: I18n.jobgroup_field_title_length\n\t\t\t\t}\n\t\t\t},\n\t\t\twriteFormData: function() {\n\t\t\t\t$(\"#addModal .form input[name='role'][value='0']\").change();\n\t\t\t},\n\t\t\treadFormData: function() {\n\t\t\t\t// request\n\t\t\t\treturn $(\"#addModal .form\").serializeArray();\n\t\t\t}\n\t\t});\n\n\t\t// addressType change\n\t\t$(\"#addModal input[name=addressType], #updateModal input[name=addressType]\").click(function(){\n\t\t\tvar addressType = $(this).val();\n\t\t\tvar $addressList = $(this).parents(\"form\").find(\"textarea[name=addressList]\");\n\t\t\tif (addressType == 0) {\n\t\t\t\t$addressList.css(\"background-color\", \"#eee\");\t// 自动注册\n\t\t\t\t$addressList.attr(\"readonly\",\"readonly\");\n\t\t\t\t$addressList.val(\"\");\n\t\t\t} else {\n\t\t\t\t$addressList.css(\"background-color\", \"white\");\n\t\t\t\t$addressList.removeAttr(\"readonly\");\n\t\t\t}\n\t\t});\n\n\t\t/**\n\t\t * init update\n\t\t */\n\t\t$.adminTable.initUpdate( {\n\t\t\turl: base_url + \"/jobgroup/update\",\n\t\t\twriteFormData: function(row) {\n\n\t\t\t\t$(\"#updateModal .form input[name='id']\").val( row.id );\n\t\t\t\t$(\"#updateModal .form input[name='appname']\").val( row.appname );\n\t\t\t\t$(\"#updateModal .form input[name='title']\").val( row.title );\n\n\t\t\t\t// 注册方式\n\t\t\t\t$(\"#updateModal .form input[name='addressType']\").removeAttr('checked');\n\t\t\t\t$(\"#updateModal .form input[name='addressType'][value='\"+ row.addressType +\"']\").click();\n\t\t\t\t// 机器地址\n\t\t\t\t$(\"#updateModal .form textarea[name='addressList']\").val( row.addressList );\n\n\t\t\t},\n\t\t\trules : {\n\t\t\t\tappname : {\n\t\t\t\t\trequired : true,\n\t\t\t\t\trangelength:[4,64],\n\t\t\t\t\tmyValid01 : true\n\t\t\t\t},\n\t\t\t\ttitle : {\n\t\t\t\t\trequired : true,\n\t\t\t\t\trangelength:[4, 12]\n\t\t\t\t}\n\t\t\t},\n\t\t\tmessages : {\n\t\t\t\tappname : {\n\t\t\t\t\trequired : I18n.system_please_input+\"AppName\",\n\t\t\t\t\trangelength: I18n.jobgroup_field_appname_length ,\n\t\t\t\t\tmyValid01: I18n.jobgroup_field_appname_limit\n\t\t\t\t},\n\t\t\t\ttitle : {\n\t\t\t\t\trequired : I18n.system_please_input + I18n.jobgroup_field_title ,\n\t\t\t\t\trangelength: I18n.jobgroup_field_title_length\n\t\t\t\t}\n\t\t\t},\n\t\t\treadFormData: function() {\n\t\t\t\t// request\n\t\t\t\treturn $(\"#updateModal .form\").serializeArray();\n\t\t\t}\n\t\t});\n\n\t});\n\n</script>\n<!-- 3-script end -->\n\n</body>\n</html>"
  },
  {
    "path": "xxl-job-admin/src/main/resources/templates/biz/job.code.ftl",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n\t<#-- import macro -->\n\t<#import \"../common/common.macro.ftl\" as netCommon>\n\n\t<!-- 1-style start -->\n\t<@netCommon.commonStyle />\n\t<link rel=\"stylesheet\" href=\"${request.contextPath}/static/plugins/codemirror/lib/codemirror.css\">\n\t<link rel=\"stylesheet\" href=\"${request.contextPath}/static/plugins/codemirror/addon/hint/show-hint.css\">\n\t<title>${I18n.admin_name}</title>\n\t<style type=\"text/css\" >\n\t\t.CodeMirror {\n\t\t\tfont-size:16px;\n\t\t\twidth: 100%;\n\t\t\theight: 100%;\n\t\t\t/*bottom: 0;\n            top: 0px;*/\n\t\t\tposition: absolute;\n\t\t}\n\t</style>\n\t<!-- 1-style end -->\n\n</head>\n<body class=\"hold-transition skin-blue layout-top-nav\" >\n<div class=\"wrapper\" >\n\n\t<!-- 2-header start -->\n\t<header class=\"main-header\">\n\t\t<nav class=\"navbar navbar-static-top\">\n\t\t\t<div class=\"container\">\n\n\t\t\t\t<#-- icon -->\n\t\t\t\t<div class=\"navbar-header\">\n\t\t\t\t\t<a class=\"navbar-brand\" href=\"javascript:void(0);\" ><b>Web</b>IDE</a>\n\t\t\t\t\t<button type=\"button\" class=\"navbar-toggle collapsed\" data-toggle=\"collapse\" data-target=\"#navbar-collapse\">\n\t\t\t\t\t\t<i class=\"fa fa-bars\"></i>\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\n\t\t\t\t<#-- left nav -->\n\t\t\t\t<div class=\"collapse navbar-collapse pull-left\" id=\"navbar-collapse\">\n\t\t\t\t\t<ul class=\"nav navbar-nav\">\n\t\t\t\t\t\t<li class=\"active\" >\n\t\t\t\t\t\t\t<a href=\"javascript:;\">${I18n.jobinfo_job}：${jobInfo.jobDesc} ｜<#list GlueTypeEnum as item><#if item == jobInfo.glueType>${item.desc}</#if></#list></a>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t</ul>\n\t\t\t\t</div>\n\n\t\t\t\t<#-- right nav -->\n\t\t\t\t<div class=\"navbar-custom-menu\">\n\t\t\t\t\t<ul class=\"nav navbar-nav\">\n\t\t\t\t\t\t<li class=\"dropdown\">\n\t\t\t\t\t\t\t<a href=\"#\" class=\"dropdown-toggle\" data-toggle=\"dropdown\" aria-expanded=\"false\">${I18n.jobinfo_glue_rollback} <span class=\"caret\"></span></a>\n\t\t\t\t\t\t\t<ul class=\"dropdown-menu\" role=\"menu\">\n\t\t\t\t\t\t\t\t<li <#if jobLogGlues?exists && jobLogGlues?size gt 0 >style=\"display: none;\"</#if> >\n\t\t\t\t\t\t\t\t\t<a href=\"javascript:;\" class=\"source_version\" version=\"version_now\" glueType=\"${jobInfo.glueType}\" >\n\t\t\t\t\t\t\t\t\t\t<#list GlueTypeEnum as item><#if item == jobInfo.glueType>${item.desc}</#if></#list>： ${jobInfo.glueRemark}\n\t\t\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t\t<textarea id=\"version_now\" style=\"display:none;\" >${jobInfo.glueSource}</textarea>\n\t\t\t\t\t\t\t\t<#if jobLogGlues?exists && jobLogGlues?size gt 0 >\n\t\t\t\t\t\t\t\t\t<#list jobLogGlues as glue>\n\t\t\t\t\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t\t\t\t\t<a href=\"javascript:;\" class=\"source_version\" version=\"version_${glue.id}\" glueType=\"${glue.glueType}\" >\n\t\t\t\t\t\t\t\t\t\t\t\t${glue.addTime?string[\"yyyy-MM-dd HH:mm:ss\"]}： ${glue.glueRemark}\n\t\t\t\t\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t\t\t\t<textarea id=\"version_${glue.id}\" style=\"display:none;\" >${glue.glueSource}</textarea>\n\t\t\t\t\t\t\t\t\t</#list>\n\t\t\t\t\t\t\t\t</#if>\n\t\t\t\t\t\t\t</ul>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li id=\"save\" >\n\t\t\t\t\t\t\t<a href=\"javascript:;\" >\n\t\t\t\t\t\t\t\t<i class=\"fa fa-fw fa-save\" ></i>\n\t\t\t\t\t\t\t\t${I18n.system_save}\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<a href=\"javascript:window.close();\" >\n\t\t\t\t\t\t\t\t<i class=\"fa fa-fw fa-close\" ></i>\n\t\t\t\t\t\t\t\t${I18n.system_close}\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t</ul>\n\t\t\t\t</div>\n\n\t\t\t</div>\n\t\t</nav>\n\t</header>\n\t<!-- 2-header end -->\n\n\t<!-- 3-content start -->\n\t<div class=\"content-wrapper\" id=\"ideWindow\" >\n\t</div>\n\n\t<!-- 保存.模态框 -->\n\t<div class=\"modal fade\" id=\"saveModal\" tabindex=\"-1\" role=\"dialog\"  aria-hidden=\"true\">\n\t\t<div class=\"modal-dialog \">\n\t\t\t<div class=\"modal-content\">\n\t\t\t\t<div class=\"modal-header\">\n\t\t\t\t\t<h4 class=\"modal-title\" ><i class=\"fa fa-fw fa-save\"></i>${I18n.system_save}</h4>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"modal-body\">\n\t\t\t\t\t<div class=\"form-horizontal form\" role=\"form\" >\n\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t<label for=\"lastname\" class=\"col-sm-2 control-label\">${I18n.jobinfo_glue_remark}<font color=\"red\">*</font></label>\n\t\t\t\t\t\t\t<div class=\"col-sm-10\"><input type=\"text\" class=\"form-control\" id=\"glueRemark\" placeholder=\"${I18n.system_please_input}${I18n.jobinfo_glue_remark}\" maxlength=\"64\" ></div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<hr>\n\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t<div class=\"col-sm-offset-3 col-sm-6\">\n\t\t\t\t\t\t\t\t<button type=\"button\" class=\"btn btn-primary ok\" >${I18n.system_save}</button>\n\t\t\t\t\t\t\t\t<button type=\"button\" class=\"btn btn-default\" data-dismiss=\"modal\">${I18n.system_cancel}</button>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n\t<!-- 3-content end -->\n\n\t<!-- 4-footer start -->\n\t<footer class=\"main-footer\">\n\t\tPowered by <b>XXL-JOB</b> ${I18n.admin_version}\n\t\t<div class=\"pull-right hidden-xs\">\n\t\t\t<strong>Copyright &copy; 2015-${.now?string('yyyy')} &nbsp;\n\t\t\t\t<a href=\"https://www.xuxueli.com/\" target=\"_blank\" >xuxueli</a>\n\t\t\t\t&nbsp;\n\t\t\t\t<a href=\"https://github.com/xuxueli/xxl-job\" target=\"_blank\" >github</a>\n\t\t\t</strong><!-- All rights reserved. -->\n\t\t</div>\n\t</footer>\n\t<!-- 4-footer end -->\n\n</div>\n\n<!-- 5-script start -->\n<#-- glueModel -->\n<#assign glueTypeModeSrc = \"${request.contextPath}/static/plugins/codemirror/mode/clike/clike.js\" />\n<#assign glueTypeIdeMode = \"text/x-java\" />\n\n<#if jobInfo.glueType == \"GLUE_GROOVY\" >\n\t<#assign glueTypeModeSrc = \"${request.contextPath}/static/plugins/codemirror/mode/clike/clike.js\" />\n\t<#assign glueTypeIdeMode = \"text/x-java\" />\n<#elseif jobInfo.glueType == \"GLUE_SHELL\" >\n\t<#assign glueTypeModeSrc = \"${request.contextPath}/static/plugins/codemirror/mode/shell/shell.js\" />\n\t<#assign glueTypeIdeMode = \"text/x-sh\" />\n<#elseif jobInfo.glueType == \"GLUE_PYTHON\" >\n\t<#assign glueTypeModeSrc = \"${request.contextPath}/static/plugins/codemirror/mode/python/python.js\" />\n\t<#assign glueTypeIdeMode = \"text/x-python\" />\n<#elseif jobInfo.glueType == \"GLUE_PYTHON2\" >\n\t<#assign glueTypeModeSrc = \"${request.contextPath}/static/plugins/codemirror/mode/python/python.js\" />\n\t<#assign glueTypeIdeMode = \"text/x-python\" />\n<#elseif jobInfo.glueType == \"GLUE_PHP\" >\n\t<#assign glueTypeModeSrc = \"${request.contextPath}/static/plugins/codemirror/mode/php/php.js\" />\n\t<#assign glueTypeIdeMode = \"text/x-php\" />\n\t<#assign glueTypeModeSrc02 = \"${request.contextPath}/static/plugins/codemirror/mode/clike/clike.js\" />\n<#elseif jobInfo.glueType == \"GLUE_NODEJS\" >\n\t<#assign glueTypeModeSrc = \"${request.contextPath}/static/plugins/codemirror/mode/javascript/javascript.js\" />\n\t<#assign glueTypeIdeMode = \"text/javascript\" />\n<#elseif jobInfo.glueType == \"GLUE_POWERSHELL\" >\n\t<#assign glueTypeModeSrc = \"${request.contextPath}/static/plugins/codemirror/mode/powershell/powershell.js\" />\n\t<#assign glueTypeIdeMode = \"powershell\" />\n</#if>\n\n<#-- script -->\n<@netCommon.commonScript />\n<script src=\"${request.contextPath}/static/biz/common/admin.setting.js?v=${I18n.admin_version}\"></script>\n<#-- glue ide -->\n<script src=\"${request.contextPath}/static/plugins/codemirror/lib/codemirror.js\"></script>\n<script src=\"${glueTypeModeSrc}\"></script>\n<#if glueTypeModeSrc02?exists>\n\t<script src=\"${glueTypeModeSrc02}\"></script>\n</#if>\n<script src=\"${request.contextPath}/static/plugins/codemirror/addon/hint/show-hint.js\"></script>\n<script src=\"${request.contextPath}/static/plugins/codemirror/addon/hint/anyword-hint.js\"></script>\n<script>\n\t$(function() {\n\t\t// init param\n\t\tvar id = '${jobInfo.id}';\n\t\tvar ideMode = '${glueTypeIdeMode}';\n\n\t\t/**\n\t\t * init code editor\n \t\t */\n\t\tvar codeEditor;\n\t\tfunction initIde(glueSource) {\n\t\t\tif (codeEditor == null) {\n\t\t\t\tcodeEditor = CodeMirror(document.getElementById(\"ideWindow\"), {\n\t\t\t\t\tmode : ideMode,\n\t\t\t\t\tlineNumbers : true,\n\t\t\t\t\tmatchBrackets : true,\n\t\t\t\t\tvalue: glueSource\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tcodeEditor.setValue(glueSource);\n\t\t\t}\n\t\t}\n\t\tinitIde($(\"#version_now\").val());\n\n\t\t// code change\n\t\t$(\".source_version\").click(function(){\n\t\t\tvar sourceId = $(this).attr('version');\n\t\t\tvar temp = $( \"#\" + sourceId ).val();\n\n\t\t\t//codeEditor.setValue('');\n\t\t\tinitIde(temp);\n\t\t});\n\n\t\t// code source save\n\t\t$(\"#save\").click(function() {\n\t\t\t$('#saveModal').modal({backdrop: false, keyboard: false}).modal('show');\n\t\t});\n\t\t$(\"#saveModal .ok\").click(function() {\n\n\t\t\tvar glueSource = codeEditor.getValue();\n\t\t\tvar glueRemark = $(\"#glueRemark\").val();\n\n\t\t\tif (!glueRemark) {\n\t\t\t\tlayer.open({\n\t\t\t\t\ttitle: I18n.system_tips,\n\t\t\t\t\tbtn: [ I18n.system_ok],\n\t\t\t\t\tcontent: I18n.system_please_input + I18n.jobinfo_glue_remark ,\n\t\t\t\t\ticon: '2'\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (glueRemark.length <4 || glueRemark.length > 100) {\n\t\t\t\tlayer.open({\n\t\t\t\t\ttitle: I18n.system_tips ,\n\t\t\t\t\tbtn: [ I18n.system_ok ],\n\t\t\t\t\tcontent: I18n.jobinfo_glue_remark_limit ,\n\t\t\t\t\ticon: '2'\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t$.ajax({\n\t\t\t\ttype : 'POST',\n\t\t\t\turl : base_url + '/jobcode/save',\n\t\t\t\tdata : {\n\t\t\t\t\t'id' : id,\n\t\t\t\t\t'glueSource' : glueSource,\n\t\t\t\t\t'glueRemark' : glueRemark\n\t\t\t\t},\n\t\t\t\tdataType : \"json\",\n\t\t\t\tsuccess : function(data){\n\t\t\t\t\tif (data.code == 200) {\n\t\t\t\t\t\tlayer.open({\n\t\t\t\t\t\t\ttitle: I18n.system_tips,\n\t\t\t\t\t\t\tbtn: [ I18n.system_ok ],\n\t\t\t\t\t\t\tcontent: (I18n.system_save + I18n.system_success) ,\n\t\t\t\t\t\t\ticon: '1',\n\t\t\t\t\t\t\tend: function(layero, index){\n\t\t\t\t\t\t\t\t//$(window).unbind('beforeunload');\n\t\t\t\t\t\t\t\twindow.location.reload();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlayer.open({\n\t\t\t\t\t\t\ttitle: I18n.system_tips,\n\t\t\t\t\t\t\tbtn: [ I18n.system_ok ],\n\t\t\t\t\t\t\tcontent: (data.msg || (I18n.system_save + I18n.system_fail) ),\n\t\t\t\t\t\t\ticon: '2'\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});\n\n\t});\n</script>\n<!-- 5-script end -->\n\n</body>\n</html>"
  },
  {
    "path": "xxl-job-admin/src/main/resources/templates/biz/job.list.ftl",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n\t<#-- import macro -->\n\t<#import \"../common/common.macro.ftl\" as netCommon>\n\n\t<!-- 1-style start -->\n\t<@netCommon.commonStyle />\n\t<link rel=\"stylesheet\" href=\"${request.contextPath}/static/plugins/bootstrap-table/bootstrap-table.min.css\">\n\t<!-- 1-style end -->\n\n</head>\n<body class=\"hold-transition\" style=\"background-color: #ecf0f5;\">\n<div class=\"wrapper\">\n\t<section class=\"content\">\n\n\t\t<!-- 2-content start -->\n\n\t\t<#-- 查询区域 -->\n\t\t<div class=\"box\" style=\"margin-bottom:9px;\">\n\t\t\t<div class=\"box-body\">\n\t\t\t\t<div class=\"row\" id=\"data_filter\" >\n\n\t\t\t\t\t<div class=\"col-xs-3\">\n\t\t\t\t\t\t<div class=\"input-group\">\n\t\t\t\t\t\t\t<span class=\"input-group-addon\">${I18n.jobinfo_field_jobgroup}</span>\n\t\t\t\t\t\t\t<select class=\"form-control\" id=\"jobGroup\" >\n\t\t\t\t\t\t\t\t<#list JobGroupList as group>\n\t\t\t\t\t\t\t\t\t<option value=\"${group.id}\" <#if jobGroup==group.id>selected</#if> >${group.title}</option>\n\t\t\t\t\t\t\t\t</#list>\n\t\t\t\t\t\t\t</select>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"col-xs-1\">\n\t\t\t\t\t\t<div class=\"input-group\">\n\t\t\t\t\t\t\t<select class=\"form-control\" id=\"triggerStatus\" >\n\t\t\t\t\t\t\t\t<option value=\"-1\" >${I18n.system_all}</option>\n\t\t\t\t\t\t\t\t<option value=\"0\" >${I18n.jobinfo_opt_stop}</option>\n\t\t\t\t\t\t\t\t<option value=\"1\" >${I18n.jobinfo_opt_start}</option>\n\t\t\t\t\t\t\t</select>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"col-xs-2\">\n\t\t\t\t\t\t<div class=\"input-group\">\n\t\t\t\t\t\t\t<input type=\"text\" class=\"form-control\" id=\"jobDesc\" placeholder=\"${I18n.system_please_input}${I18n.jobinfo_field_jobdesc}\" >\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"col-xs-2\">\n\t\t\t\t\t\t<div class=\"input-group\">\n\t\t\t\t\t\t\t<input type=\"text\" class=\"form-control\" id=\"executorHandler\" placeholder=\"${I18n.system_please_input}JobHandler\" >\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"col-xs-2\">\n\t\t\t\t\t\t<div class=\"input-group\">\n\t\t\t\t\t\t\t<input type=\"text\" class=\"form-control\" id=\"author\" placeholder=\"${I18n.system_please_input}${I18n.jobinfo_field_author}\" >\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div class=\"col-xs-1\">\n\t\t\t\t\t\t<button class=\"btn btn-block btn-primary searchBtn\" >${I18n.system_search}</button>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"col-xs-1\">\n\t\t\t\t\t\t<button class=\"btn btn-block btn-default resetBtn\" >${I18n.system_reset}</button>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<#-- 数据表格区域 -->\n\t\t<div class=\"row\">\n\t\t\t<div class=\"col-xs-12\">\n\t\t\t\t<div class=\"box\">\n\t\t\t\t\t<div class=\"box-header pull-left\" id=\"data_operation\" >\n\t\t\t\t\t\t<button class=\"btn btn-sm btn-info add\" type=\"button\"><i class=\"fa fa-plus\" ></i>${I18n.system_opt_add}</button>                        <#-- add -->\n\t\t\t\t\t\t<button class=\"btn btn-sm btn-warning selectOnlyOne update\" type=\"button\"><i class=\"fa fa-edit\"></i>${I18n.system_opt_edit}</button>    <#-- update -->\n                        <button class=\"btn btn-sm btn-warning selectOnlyOne glue_ide\" type=\"button\">GLUE IDE</button>\t\t\t\t\t\t\t\t\t        <#-- GLUE IDE：'BEAN' != row.glueType -->\n\t\t\t\t\t\t<button class=\"btn btn-sm btn-danger selectOnlyOne delete\" type=\"button\"><i class=\"fa fa-remove \"></i>${I18n.system_opt_del}</button>   <#-- delete -->\n\t\t\t\t\t\t｜\n\t\t\t\t\t\t<button class=\"btn btn-sm btn-default selectOnlyOne job_copy\" type=\"button\">${I18n.system_opt_copy}</button>\n\t\t\t\t\t\t<button class=\"btn btn-sm btn-warning selectOnlyOne job_resume\" type=\"button\">${I18n.jobinfo_opt_start}</button>\t\t\t\t<#-- 启动 -->\n\t\t\t\t\t\t<button class=\"btn btn-sm btn-warning selectOnlyOne job_pause\" type=\"button\">${I18n.jobinfo_opt_stop}</button>\t\t\t\t\t<#-- 停止 -->\n\t\t\t\t\t\t｜\n\t\t\t\t\t\t<button class=\"btn btn-sm btn-primary selectOnlyOne job_trigger\" type=\"button\">${I18n.jobinfo_opt_run}</button>\t\t\t\t\t<#-- 执行一次 -->\n\t\t\t\t\t\t<button class=\"btn btn-sm btn-primary selectOnlyOne job_log\" type=\"button\">${I18n.jobinfo_opt_log}</button>\t\t\t\t\t\t<#-- 执行日志：base_url +'/joblog?jobId='+ row.id -->\n\t\t\t\t\t\t<button class=\"btn btn-sm btn-default selectOnlyOne job_registryinfo\" type=\"button\">${I18n.jobinfo_opt_registryinfo}</button>\t<#-- 注册节点 -->\n\t\t\t\t\t\t<button class=\"btn btn-sm btn-default selectOnlyOne job_next_time\" type=\"button\">${I18n.jobinfo_opt_next_time}</button>\t\t\t<#-- 下次执行时间：row.scheduleType == 'CRON' || row.scheduleType == 'FIX_RATE' -->\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"box-body\" >\n\t\t\t\t\t\t<table id=\"data_list\" class=\"table table-bordered table-striped\" width=\"100%\" >\n\t\t\t\t\t\t\t<thead></thead>\n\t\t\t\t\t\t\t<tbody></tbody>\n\t\t\t\t\t\t\t<tfoot></tfoot>\n\t\t\t\t\t\t</table>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<!-- job新增.模态框 -->\n\t\t<div class=\"modal fade\" id=\"addModal\" tabindex=\"-1\" role=\"dialog\"  aria-hidden=\"true\">\n\t\t\t<div class=\"modal-dialog modal-lg\">\n\t\t\t\t<div class=\"modal-content\">\n\t\t\t\t\t<div class=\"modal-header\">\n\t\t\t\t\t\t<h4 class=\"modal-title\" >${I18n.jobinfo_field_add}</h4>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"modal-body\">\n\t\t\t\t\t\t<form class=\"form-horizontal form\" role=\"form\" >\n\n\t\t\t\t\t\t\t<p style=\"margin: 0 0 10px;text-align: left;border-bottom: 1px solid #e5e5e5;color: gray;\">${I18n.jobinfo_conf_base}</p>    <#-- 基础信息 -->\n\t\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t\t<label for=\"firstname\" class=\"col-sm-2 control-label\">${I18n.jobinfo_field_jobgroup}<font color=\"red\">*</font></label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-4\">\n\t\t\t\t\t\t\t\t\t<select class=\"form-control\" name=\"jobGroup\" >\n\t\t\t\t\t\t\t\t\t\t<#list JobGroupList as group>\n\t\t\t\t\t\t\t\t\t\t\t<option value=\"${group.id}\" <#if jobGroup==group.id>selected</#if> >${group.title}</option>\n\t\t\t\t\t\t\t\t\t\t</#list>\n\t\t\t\t\t\t\t\t\t</select>\n\t\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t\t\t<label for=\"lastname\" class=\"col-sm-2 control-label\">${I18n.jobinfo_field_jobdesc}<font color=\"red\">*</font></label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-4\"><input type=\"text\" class=\"form-control\" name=\"jobDesc\" placeholder=\"${I18n.system_please_input}${I18n.jobinfo_field_jobdesc}\" maxlength=\"50\" ></div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t\t<label for=\"lastname\" class=\"col-sm-2 control-label\">${I18n.jobinfo_field_author}<font color=\"red\">*</font></label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-4\"><input type=\"text\" class=\"form-control\" name=\"author\" placeholder=\"${I18n.system_please_input}${I18n.jobinfo_field_author}\" maxlength=\"50\" ></div>\n\t\t\t\t\t\t\t\t<label for=\"lastname\" class=\"col-sm-2 control-label\">${I18n.jobinfo_field_alarmemail}<font color=\"black\">*</font></label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-4\"><input type=\"text\" class=\"form-control\" name=\"alarmEmail\" placeholder=\"${I18n.jobinfo_field_alarmemail_placeholder}\" maxlength=\"100\" ></div>\n\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t\t<br>\n\t\t\t\t\t\t\t<p style=\"margin: 0 0 10px;text-align: left;border-bottom: 1px solid #e5e5e5;color: gray;\">${I18n.jobinfo_conf_schedule}</p>    <#-- 调度 -->\n\t\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t\t<label for=\"firstname\" class=\"col-sm-2 control-label\">${I18n.schedule_type}<font color=\"red\">*</font></label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-4\">\n\t\t\t\t\t\t\t\t\t<select class=\"form-control scheduleType\" name=\"scheduleType\" >\n\t\t\t\t\t\t\t\t\t\t<#list ScheduleTypeEnum as item>\n\t\t\t\t\t\t\t\t\t\t\t<option value=\"${item}\" <#if 'CRON' == item >selected</#if> >${item.title}</option>\n\t\t\t\t\t\t\t\t\t\t</#list>\n\t\t\t\t\t\t\t\t\t</select>\n\t\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t\t\t<input type=\"hidden\" name=\"scheduleConf\" />\n\t\t\t\t\t\t\t\t<div class=\"schedule_conf schedule_conf_NONE\" style=\"display: none\" >\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<div class=\"schedule_conf schedule_conf_CRON\" >\n\t\t\t\t\t\t\t\t\t<label for=\"lastname\" class=\"col-sm-2 control-label\">Cron<font color=\"red\">*</font></label>\n\t\t\t\t\t\t\t\t\t<div class=\"col-sm-4\"><input type=\"text\" class=\"form-control\" name=\"schedule_conf_CRON\" placeholder=\"${I18n.system_please_input}Cron\" maxlength=\"128\" ></div>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<div class=\"schedule_conf schedule_conf_FIX_RATE\" style=\"display: none\" >\n\t\t\t\t\t\t\t\t\t<label for=\"lastname\" class=\"col-sm-2 control-label\">${I18n.schedule_type_fix_rate}<font color=\"red\">*</font></label>\n\t\t\t\t\t\t\t\t\t<div class=\"col-sm-4\"><input type=\"text\" class=\"form-control\" name=\"schedule_conf_FIX_RATE\" placeholder=\"${I18n.system_please_input} （ Second ）\" maxlength=\"10\" onkeyup=\"this.value=this.value.replace(/\\D/g,'')\" onafterpaste=\"this.value=this.value.replace(/\\D/g,'')\" ></div>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<div class=\"schedule_conf schedule_conf_FIX_DELAY\" style=\"display: none\" >\n\t\t\t\t\t\t\t\t\t<label for=\"lastname\" class=\"col-sm-2 control-label\">${I18n.schedule_type_fix_delay}<font color=\"red\">*</font></label>\n\t\t\t\t\t\t\t\t\t<div class=\"col-sm-4\"><input type=\"text\" class=\"form-control\" name=\"schedule_conf_FIX_DELAY\" placeholder=\"${I18n.system_please_input} （ Second ）\" maxlength=\"10\" onkeyup=\"this.value=this.value.replace(/\\D/g,'')\" onafterpaste=\"this.value=this.value.replace(/\\D/g,'')\" ></div>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t\t<br>\n\t\t\t\t\t\t\t<p style=\"margin: 0 0 10px;text-align: left;border-bottom: 1px solid #e5e5e5;color: gray;\">${I18n.jobinfo_conf_job}</p>    <#-- 任务配置 -->\n\n\t\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t\t<label for=\"firstname\" class=\"col-sm-2 control-label\">${I18n.jobinfo_field_gluetype}<font color=\"red\">*</font></label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-4\">\n\t\t\t\t\t\t\t\t\t<select class=\"form-control glueType\" name=\"glueType\" >\n\t\t\t\t\t\t\t\t\t\t<#list GlueTypeEnum as item>\n\t\t\t\t\t\t\t\t\t\t\t<option value=\"${item}\" >${item.desc}</option>\n\t\t\t\t\t\t\t\t\t\t</#list>\n\t\t\t\t\t\t\t\t\t</select>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<label for=\"firstname\" class=\"col-sm-2 control-label\">JobHandler<font color=\"red\">*</font></label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-4\"><input type=\"text\" class=\"form-control\" name=\"executorHandler\" placeholder=\"${I18n.system_please_input}JobHandler\" maxlength=\"100\" ></div>\n\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t\t<label for=\"firstname\" class=\"col-sm-2 control-label\">${I18n.jobinfo_field_executorparam}<font color=\"black\">*</font></label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-10\">\n\t\t\t\t\t\t\t\t\t<textarea class=\"textarea form-control\" name=\"executorParam\" placeholder=\"${I18n.system_please_input}${I18n.jobinfo_field_executorparam}\" maxlength=\"512\" style=\"height: 63px; line-height: 1.2;\"></textarea>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t\t<br>\n\t\t\t\t\t\t\t<p style=\"margin: 0 0 10px;text-align: left;border-bottom: 1px solid #e5e5e5;color: gray;\">${I18n.jobinfo_conf_advanced}</p>    <#-- 高级配置 -->\n\n\t\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t\t<label for=\"firstname\" class=\"col-sm-2 control-label\">${I18n.jobinfo_field_executorRouteStrategy}<font color=\"black\">*</font></label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-4\">\n\t\t\t\t\t\t\t\t\t<select class=\"form-control\" name=\"executorRouteStrategy\" >\n\t\t\t\t\t\t\t\t\t\t<#list ExecutorRouteStrategyEnum as item>\n\t\t\t\t\t\t\t\t\t\t\t<option value=\"${item}\" >${item.title}</option>\n\t\t\t\t\t\t\t\t\t\t</#list>\n\t\t\t\t\t\t\t\t\t</select>\n\t\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t\t\t<label for=\"lastname\" class=\"col-sm-2 control-label\">${I18n.jobinfo_field_childJobId}<font color=\"black\">*</font></label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-4\"><input type=\"text\" class=\"form-control\" name=\"childJobId\" placeholder=\"${I18n.jobinfo_field_childJobId_placeholder}\" maxlength=\"100\" ></div>\n\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t\t<label for=\"firstname\" class=\"col-sm-2 control-label\">${I18n.misfire_strategy}<font color=\"black\">*</font></label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-4\">\n\t\t\t\t\t\t\t\t\t<select class=\"form-control\" name=\"misfireStrategy\" >\n\t\t\t\t\t\t\t\t\t\t<#list MisfireStrategyEnum as item>\n\t\t\t\t\t\t\t\t\t\t\t<option value=\"${item}\" <#if 'DO_NOTHING' == item >selected</#if> >${item.title}</option>\n\t\t\t\t\t\t\t\t\t\t</#list>\n\t\t\t\t\t\t\t\t\t</select>\n\t\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t\t\t<label for=\"firstname\" class=\"col-sm-2 control-label\">${I18n.jobinfo_field_executorBlockStrategy}<font color=\"black\">*</font></label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-4\">\n\t\t\t\t\t\t\t\t\t<select class=\"form-control\" name=\"executorBlockStrategy\" >\n\t\t\t\t\t\t\t\t\t\t<#list ExecutorBlockStrategyEnum as item>\n\t\t\t\t\t\t\t\t\t\t\t<option value=\"${item}\" >${item.title}</option>\n\t\t\t\t\t\t\t\t\t\t</#list>\n\t\t\t\t\t\t\t\t\t</select>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t\t<label for=\"lastname\" class=\"col-sm-2 control-label\">${I18n.jobinfo_field_timeout}<font color=\"black\">*</font></label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-4\"><input type=\"text\" class=\"form-control\" name=\"executorTimeout\" placeholder=\"${I18n.jobinfo_field_executorTimeout_placeholder}\" maxlength=\"6\" onkeyup=\"this.value=this.value.replace(/\\D/g,'')\" onafterpaste=\"this.value=this.value.replace(/\\D/g,'')\" ></div>\n\t\t\t\t\t\t\t\t<label for=\"lastname\" class=\"col-sm-2 control-label\">${I18n.jobinfo_field_executorFailRetryCount}<font color=\"black\">*</font></label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-4\"><input type=\"text\" class=\"form-control\" name=\"executorFailRetryCount\" placeholder=\"${I18n.jobinfo_field_executorFailRetryCount_placeholder}\" maxlength=\"4\" onkeyup=\"this.value=this.value.replace(/\\D/g,'')\" onafterpaste=\"this.value=this.value.replace(/\\D/g,'')\" ></div>\n\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t\t<hr>\n\t\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t\t<div class=\"col-sm-offset-3 col-sm-6\">\n\t\t\t\t\t\t\t\t\t<button type=\"submit\" class=\"btn btn-primary\"  >${I18n.system_save}</button>\n\t\t\t\t\t\t\t\t\t<button type=\"button\" class=\"btn btn-default\" data-dismiss=\"modal\">${I18n.system_cancel}</button>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\n<input type=\"hidden\" name=\"glueRemark\" value=\"GLUE代码初始化\" >\n<textarea name=\"glueSource\" style=\"display:none;\" ></textarea>\n<textarea class=\"glueSource_java\" style=\"display:none;\" >\npackage com.xxl.job.service.handler;\n\nimport com.xxl.job.core.context.XxlJobHelper;\nimport com.xxl.job.core.handler.IJobHandler;\n\npublic class DemoGlueJobHandler extends IJobHandler {\n\n\t@Override\n\tpublic void execute() throws Exception {\n\t\tXxlJobHelper.log(\"XXL-JOB, Hello World.\");\n\t}\n\n}\n</textarea>\n<textarea class=\"glueSource_shell\" style=\"display:none;\" >\n#!/bin/bash\necho \"xxl-job: hello shell\"\n\necho \"${I18n.jobinfo_script_location}：$0\"\necho \"${I18n.jobinfo_field_executorparam}：$1\"\necho \"${I18n.jobinfo_shard_index} = $2\"\necho \"${I18n.jobinfo_shard_total} = $3\"\n<#--echo \"参数数量：$#\"\nfor param in $*\ndo\n    echo \"参数 : $param\"\n    sleep 1s\ndone-->\n\necho \"Good bye!\"\nexit 0\n</textarea>\n<textarea class=\"glueSource_python\" style=\"display:none;\" >\n#!/usr/bin/python\n# -*- coding: UTF-8 -*-\nimport time\nimport sys\n\nprint(\"xxl-job: hello python\")\n\nprint(\"${I18n.jobinfo_script_location}：\", sys.argv[0])\nprint(\"${I18n.jobinfo_field_executorparam}：\", sys.argv[1])\nprint(\"${I18n.jobinfo_shard_index}：\", sys.argv[2])\nprint(\"${I18n.jobinfo_shard_total}：\", sys.argv[3])\n\nprint(\"Good bye!\")\nexit(0)\n</textarea>\n<textarea class=\"glueSource_python2\" style=\"display:none;\" >\n#!/usr/bin/python\n# -*- coding: UTF-8 -*-\nimport time\nimport sys\n\nprint \"xxl-job: hello python\"\n\nprint \"${I18n.jobinfo_script_location}：\", sys.argv[0]\nprint \"${I18n.jobinfo_field_executorparam}：\", sys.argv[1]\nprint \"${I18n.jobinfo_shard_index}：\", sys.argv[2]\nprint \"${I18n.jobinfo_shard_total}：\", sys.argv[3]\n<#--for i in range(1, len(sys.argv)):\n\ttime.sleep(1)\n\tprint \"参数\", i, sys.argv[i]-->\n\nprint \"Good bye!\"\nexit(0)\n<#--\nimport logging\nlogging.basicConfig(level=logging.DEBUG)\nlogging.info(\"脚本文件：\" + sys.argv[0])\n-->\n</textarea>\n<textarea class=\"glueSource_php\" style=\"display:none;\" >\n<?php\n\n    echo \"xxl-job: hello php  \\n\";\n\n    echo \"${I18n.jobinfo_script_location}：$argv[0]  \\n\";\n    echo \"${I18n.jobinfo_field_executorparam}：$argv[1]  \\n\";\n    echo \"${I18n.jobinfo_shard_index} = $argv[2]  \\n\";\n    echo \"${I18n.jobinfo_shard_total} = $argv[3]  \\n\";\n\n    echo \"Good bye!  \\n\";\n    exit(0);\n\n?>\n</textarea>\n<textarea class=\"glueSource_nodejs\" style=\"display:none;\" >\n#!/usr/bin/env node\nconsole.log(\"xxl-job: hello nodejs\")\n\nvar arguments = process.argv\n\nconsole.log(\"${I18n.jobinfo_script_location}: \" + arguments[1])\nconsole.log(\"${I18n.jobinfo_field_executorparam}: \" + arguments[2])\nconsole.log(\"${I18n.jobinfo_shard_index}: \" + arguments[3])\nconsole.log(\"${I18n.jobinfo_shard_total}: \" + arguments[4])\n<#--for (var i = 2; i < arguments.length; i++){\n\tconsole.log(\"参数 %s = %s\", (i-1), arguments[i]);\n}-->\n\nconsole.log(\"Good bye!\")\nprocess.exit(0)\n</textarea>\n<textarea class=\"glueSource_powershell\" style=\"display:none;\" >\nWrite-Host \"xxl-job: hello powershell\"\n\nWrite-Host \"${I18n.jobinfo_script_location}: \" $MyInvocation.MyCommand.Definition\nWrite-Host \"${I18n.jobinfo_field_executorparam}: \"\n\tif ($args.Count -gt 2) { $args[0..($args.Count-3)] }\nWrite-Host \"${I18n.jobinfo_shard_index}: \" $args[$args.Count-2]\nWrite-Host \"${I18n.jobinfo_shard_total}: \" $args[$args.Count-1]\n\nWrite-Host \"Good bye!\"\nexit 0\n</textarea>\n\t\t\t\t\t\t</form>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<!-- 更新.模态框 -->\n\t\t<div class=\"modal fade\" id=\"updateModal\" tabindex=\"-1\" role=\"dialog\"  aria-hidden=\"true\">\n\t\t\t<div class=\"modal-dialog modal-lg\">\n\t\t\t\t<div class=\"modal-content\">\n\t\t\t\t\t<div class=\"modal-header\">\n\t\t\t\t\t\t<h4 class=\"modal-title\" >${I18n.jobinfo_field_update}</h4>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"modal-body\">\n\t\t\t\t\t\t<form class=\"form-horizontal form\" role=\"form\" >\n\n\t\t\t\t\t\t\t<p style=\"margin: 0 0 10px;text-align: left;border-bottom: 1px solid #e5e5e5;color: gray;\">${I18n.jobinfo_conf_base}</p>    <#-- 基础信息 -->\n\t\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t\t<label for=\"firstname\" class=\"col-sm-2 control-label\">${I18n.jobinfo_field_jobgroup}<font color=\"red\">*</font></label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-4\">\n\t\t\t\t\t\t\t\t\t<select class=\"form-control\" name=\"jobGroup\" >\n\t\t\t\t\t\t\t\t\t\t<#list JobGroupList as group>\n\t\t\t\t\t\t\t\t\t\t\t<option value=\"${group.id}\" >${group.title}</option>\n\t\t\t\t\t\t\t\t\t\t</#list>\n\t\t\t\t\t\t\t\t\t</select>\n\t\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t\t\t<label for=\"lastname\" class=\"col-sm-2 control-label\">${I18n.jobinfo_field_jobdesc}<font color=\"red\">*</font></label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-4\"><input type=\"text\" class=\"form-control\" name=\"jobDesc\" placeholder=\"${I18n.system_please_input}${I18n.jobinfo_field_jobdesc}\" maxlength=\"50\" ></div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t\t<label for=\"lastname\" class=\"col-sm-2 control-label\">${I18n.jobinfo_field_author}<font color=\"red\">*</font></label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-4\"><input type=\"text\" class=\"form-control\" name=\"author\" placeholder=\"${I18n.system_please_input}${I18n.jobinfo_field_author}\" maxlength=\"50\" ></div>\n\t\t\t\t\t\t\t\t<label for=\"lastname\" class=\"col-sm-2 control-label\">${I18n.jobinfo_field_alarmemail}<font color=\"black\">*</font></label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-4\"><input type=\"text\" class=\"form-control\" name=\"alarmEmail\" placeholder=\"${I18n.jobinfo_field_alarmemail_placeholder}\" maxlength=\"100\" ></div>\n\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t\t<br>\n\t\t\t\t\t\t\t<p style=\"margin: 0 0 10px;text-align: left;border-bottom: 1px solid #e5e5e5;color: gray;\">${I18n.jobinfo_conf_schedule}</p>    <#-- 调度配置 -->\n\t\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t\t<label for=\"firstname\" class=\"col-sm-2 control-label\">${I18n.schedule_type}<font color=\"red\">*</font></label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-4\">\n\t\t\t\t\t\t\t\t\t<select class=\"form-control scheduleType\" name=\"scheduleType\" >\n\t\t\t\t\t\t\t\t\t\t<#list ScheduleTypeEnum as item>\n\t\t\t\t\t\t\t\t\t\t\t<option value=\"${item}\" >${item.title}</option>\n\t\t\t\t\t\t\t\t\t\t</#list>\n\t\t\t\t\t\t\t\t\t</select>\n\t\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t\t\t<input type=\"hidden\" name=\"scheduleConf\" />\n\t\t\t\t\t\t\t\t<div class=\"schedule_conf schedule_conf_NONE\" style=\"display: none\" >\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<div class=\"schedule_conf schedule_conf_CRON\" >\n\t\t\t\t\t\t\t\t\t<label for=\"lastname\" class=\"col-sm-2 control-label\">Cron<font color=\"red\">*</font></label>\n\t\t\t\t\t\t\t\t\t<div class=\"col-sm-4\"><input type=\"text\" class=\"form-control\" name=\"schedule_conf_CRON\" placeholder=\"${I18n.system_please_input}Cron\" maxlength=\"128\" ></div>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<div class=\"schedule_conf schedule_conf_FIX_RATE\" style=\"display: none\" >\n\t\t\t\t\t\t\t\t\t<label for=\"lastname\" class=\"col-sm-2 control-label\">${I18n.schedule_type_fix_rate}<font color=\"red\">*</font></label>\n\t\t\t\t\t\t\t\t\t<div class=\"col-sm-4\"><input type=\"text\" class=\"form-control\" name=\"schedule_conf_FIX_RATE\" placeholder=\"${I18n.system_please_input} （ Second ）\" maxlength=\"10\" onkeyup=\"this.value=this.value.replace(/\\D/g,'')\" onafterpaste=\"this.value=this.value.replace(/\\D/g,'')\" ></div>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<div class=\"schedule_conf schedule_conf_FIX_DELAY\" style=\"display: none\" >\n\t\t\t\t\t\t\t\t\t<label for=\"lastname\" class=\"col-sm-2 control-label\">${I18n.schedule_type_fix_delay}<font color=\"red\">*</font></label>\n\t\t\t\t\t\t\t\t\t<div class=\"col-sm-4\"><input type=\"text\" class=\"form-control\" name=\"schedule_conf_FIX_DELAY\" placeholder=\"${I18n.system_please_input} （ Second ）\" maxlength=\"10\" onkeyup=\"this.value=this.value.replace(/\\D/g,'')\" onafterpaste=\"this.value=this.value.replace(/\\D/g,'')\" ></div>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t\t<br>\n\t\t\t\t\t\t\t<p style=\"margin: 0 0 10px;text-align: left;border-bottom: 1px solid #e5e5e5;color: gray;\">${I18n.jobinfo_conf_job}</p>    <#-- 任务配置 -->\n\n\t\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t\t<label for=\"firstname\" class=\"col-sm-2 control-label\">${I18n.jobinfo_field_gluetype}<font color=\"red\">*</font></label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-4\">\n\t\t\t\t\t\t\t\t\t<select class=\"form-control glueType\" name=\"glueType\" disabled >\n\t\t\t\t\t\t\t\t\t\t<#list GlueTypeEnum as item>\n\t\t\t\t\t\t\t\t\t\t\t<option value=\"${item}\" >${item.desc}</option>\n\t\t\t\t\t\t\t\t\t\t</#list>\n\t\t\t\t\t\t\t\t\t</select>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<label for=\"firstname\" class=\"col-sm-2 control-label\">JobHandler<font color=\"red\">*</font></label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-4\"><input type=\"text\" class=\"form-control\" name=\"executorHandler\" placeholder=\"${I18n.system_please_input}JobHandler\" maxlength=\"100\" ></div>\n\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t\t<label for=\"firstname\" class=\"col-sm-2 control-label\">${I18n.jobinfo_field_executorparam}<font color=\"black\">*</font></label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-10\">\n\t\t\t\t\t\t\t\t\t<textarea class=\"textarea form-control\" name=\"executorParam\" placeholder=\"${I18n.system_please_input}${I18n.jobinfo_field_executorparam}\" maxlength=\"512\" style=\"height: 63px; line-height: 1.2;\"></textarea>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t\t<br>\n\t\t\t\t\t\t\t<p style=\"margin: 0 0 10px;text-align: left;border-bottom: 1px solid #e5e5e5;color: gray;\">${I18n.jobinfo_conf_advanced}</p>    <#-- 高级配置 -->\n\n\t\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t\t<label for=\"firstname\" class=\"col-sm-2 control-label\">${I18n.jobinfo_field_executorRouteStrategy}<font color=\"red\">*</font></label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-4\">\n\t\t\t\t\t\t\t\t\t<select class=\"form-control\" name=\"executorRouteStrategy\" >\n\t\t\t\t\t\t\t\t\t\t<#list ExecutorRouteStrategyEnum as item>\n\t\t\t\t\t\t\t\t\t\t\t<option value=\"${item}\" >${item.title}</option>\n\t\t\t\t\t\t\t\t\t\t</#list>\n\t\t\t\t\t\t\t\t\t</select>\n\t\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t\t\t<label for=\"lastname\" class=\"col-sm-2 control-label\">${I18n.jobinfo_field_childJobId}<font color=\"black\">*</font></label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-4\"><input type=\"text\" class=\"form-control\" name=\"childJobId\" placeholder=\"${I18n.jobinfo_field_childJobId_placeholder}\" maxlength=\"100\" ></div>\n\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t\t<label for=\"firstname\" class=\"col-sm-2 control-label\">${I18n.misfire_strategy}<font color=\"black\">*</font></label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-4\">\n\t\t\t\t\t\t\t\t\t<select class=\"form-control\" name=\"misfireStrategy\" >\n\t\t\t\t\t\t\t\t\t\t<#list MisfireStrategyEnum as item>\n\t\t\t\t\t\t\t\t\t\t\t<option value=\"${item}\" <#if 'DO_NOTHING' == item >selected</#if> >${item.title}</option>\n\t\t\t\t\t\t\t\t\t\t</#list>\n\t\t\t\t\t\t\t\t\t</select>\n\t\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t\t\t<label for=\"firstname\" class=\"col-sm-2 control-label\">${I18n.jobinfo_field_executorBlockStrategy}<font color=\"red\">*</font></label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-4\">\n\t\t\t\t\t\t\t\t\t<select class=\"form-control\" name=\"executorBlockStrategy\" >\n\t\t\t\t\t\t\t\t\t\t<#list ExecutorBlockStrategyEnum as item>\n\t\t\t\t\t\t\t\t\t\t\t<option value=\"${item}\" >${item.title}</option>\n\t\t\t\t\t\t\t\t\t\t</#list>\n\t\t\t\t\t\t\t\t\t</select>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t\t<label for=\"lastname\" class=\"col-sm-2 control-label\">${I18n.jobinfo_field_timeout}<font color=\"black\">*</font></label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-4\"><input type=\"text\" class=\"form-control\" name=\"executorTimeout\" placeholder=\"${I18n.jobinfo_field_executorTimeout_placeholder}\" maxlength=\"6\" onkeyup=\"this.value=this.value.replace(/\\D/g,'')\" onafterpaste=\"this.value=this.value.replace(/\\D/g,'')\" ></div>\n\t\t\t\t\t\t\t\t<label for=\"lastname\" class=\"col-sm-2 control-label\">${I18n.jobinfo_field_executorFailRetryCount}<font color=\"black\">*</font></label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-4\"><input type=\"text\" class=\"form-control\" name=\"executorFailRetryCount\" placeholder=\"${I18n.jobinfo_field_executorFailRetryCount_placeholder}\" maxlength=\"4\" onkeyup=\"this.value=this.value.replace(/\\D/g,'')\" onafterpaste=\"this.value=this.value.replace(/\\D/g,'')\" ></div>\n\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t\t<hr>\n\t\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t\t<div class=\"col-sm-offset-3 col-sm-6\">\n\t\t\t\t\t\t\t\t\t<button type=\"submit\" class=\"btn btn-primary\"  >${I18n.system_save}</button>\n\t\t\t\t\t\t\t\t\t<button type=\"button\" class=\"btn btn-default\" data-dismiss=\"modal\">${I18n.system_cancel}</button>\n\t\t\t\t\t\t\t\t\t<input type=\"hidden\" name=\"id\" >\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t</form>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<#-- trigger -->\n\t\t<div class=\"modal fade\" id=\"jobTriggerModal\" tabindex=\"-1\" role=\"dialog\"  aria-hidden=\"true\">\n\t\t\t<div class=\"modal-dialog \">\n\t\t\t\t<div class=\"modal-content\">\n\t\t\t\t\t<div class=\"modal-header\">\n\t\t\t\t\t\t<h4 class=\"modal-title\" >${I18n.jobinfo_opt_run}</h4>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"modal-body\">\n\t\t\t\t\t\t<form class=\"form-horizontal form\" role=\"form\" >\n\t\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t\t<label for=\"firstname\" class=\"col-sm-2 control-label\">${I18n.jobinfo_field_executorparam}<font color=\"black\">*</font></label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-10\">\n\t\t\t\t\t\t\t\t\t<textarea class=\"textarea form-control\" name=\"executorParam\" placeholder=\"${I18n.system_please_input}${I18n.jobinfo_field_executorparam}\" maxlength=\"512\" style=\"height: 63px; line-height: 1.2;\"></textarea>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t\t<label for=\"firstname\" class=\"col-sm-2 control-label\">${I18n.jobgroup_field_registryList}<font color=\"black\">*</font></label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-10\">\n\t\t\t\t\t\t\t\t\t<textarea class=\"textarea form-control\" name=\"addressList\" placeholder=\"${I18n.jobinfo_opt_run_tips}\" maxlength=\"512\" style=\"height: 63px; line-height: 1.2;\"></textarea>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<hr>\n\t\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t\t<div class=\"col-sm-offset-3 col-sm-6\">\n\t\t\t\t\t\t\t\t\t<button type=\"button\" class=\"btn btn-primary ok\" >${I18n.system_save}</button>\n\t\t\t\t\t\t\t\t\t<button type=\"button\" class=\"btn btn-default\" data-dismiss=\"modal\">${I18n.system_cancel}</button>\n\t\t\t\t\t\t\t\t\t<input type=\"hidden\" name=\"id\" >\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</form>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<!-- 2-content end -->\n\n\t</section>\n</div>\n\n<!-- 3-script start -->\n<@netCommon.commonScript />\n<script src=\"${request.contextPath}/static/plugins/bootstrap-table/bootstrap-table.min.js\"></script>\n<script src=\"${request.contextPath}/static/plugins/bootstrap-table/locale/<#if I18n.admin_i18n?? && I18n.admin_i18n == 'en'>bootstrap-table-en-US.min.js<#else>bootstrap-table-zh-CN.min.js</#if>\"></script>\n<#-- admin table -->\n<script src=\"${request.contextPath}/static/biz/common/admin.table.js\"></script>\n<#-- admin util -->\n<script src=\"${request.contextPath}/static/biz/common/admin.util.js\"></script>\n<#-- moment -->\n<script src=\"${request.contextPath}/static/adminlte/bower_components/moment/moment.min.js\"></script>\n<#-- cronGen -->\n<script src=\"${request.contextPath}/static/plugins/cronGen/<#if I18n.admin_i18n?? && I18n.admin_i18n == 'en'>cronGen_en.js<#else>cronGen.js</#if>\"></script>\n<script>\n\t$(function() {\n\n\t\t// ---------------------- filter ----------------------\n\n\t\t/**\n\t\t * jobGroup change\n\t\t */\n\t\t$('#jobGroup').on('change', function(){\n\t\t\t//reload\n\t\t\tvar jobGroup = $('#jobGroup').val();\n\t\t\twindow.location.href = base_url + \"/jobinfo?jobGroup=\" + jobGroup;\n\t\t});\n\n\t\t// reset filter\n\t\tvar jobGroup = '${jobGroup}';\n\t\tfunction resetFilter(){\n\t\t\tif (jobGroup > 0) {\n\t\t\t\t$(\"#jobGroup\").val( jobGroup );\n\t\t\t}\n\t\t}\n\t\tresetFilter();\n\n\t\t// ---------------------- table ----------------------\n\n\t\t/**\n\t\t * init table\n\t\t */\n\t\t$.adminTable.initTable({\n\t\t\ttable: '#data_list',\n\t\t\turl: base_url + \"/jobinfo/pageList\",\n\t\t\tqueryParams: function (params) {\n\t\t\t\tvar obj = {};\n\t\t\t\tobj.jobGroup = $('#jobGroup').val();\n\t\t\t\tobj.triggerStatus = $('#triggerStatus').val();\n\t\t\t\tobj.jobDesc = $('#jobDesc').val();\n\t\t\t\tobj.executorHandler = $('#executorHandler').val();\n\t\t\t\tobj.author = $('#author').val();\n\t\t\t\tobj.offset = params.offset;\n\t\t\t\tobj.pagesize = params.limit;\n\t\t\t\treturn obj;\n\t\t\t},resetHandler : function() {\n\t\t\t\t// default\n\t\t\t\t$('#data_filter input[type=\"text\"]').val('');\n\t\t\t\t$('#data_filter select').each(function() {\n\t\t\t\t\t$(this).prop('selectedIndex', 0);\n\t\t\t\t});\n\n\t\t\t\t// reset filter\n\t\t\t\tresetFilter();\n\t\t\t},\n\t\t\tcolumns:[\n\t\t\t\t{\n\t\t\t\t\tcheckbox: true,\n\t\t\t\t\tfield: 'state',\n\t\t\t\t\twidth: '5',\n\t\t\t\t\twidthUnit: '%',\n\t\t\t\t\talign: 'center',\n\t\t\t\t\tvalign: 'middle'\n\t\t\t\t},{\n\t\t\t\t\ttitle: I18n.jobinfo_field_id,\n\t\t\t\t\tfield: 'id',\n\t\t\t\t\twidth: '5',\n\t\t\t\t\twidthUnit: '%',\n\t\t\t\t\talign: 'left'\n\t\t\t\t}\n\t\t\t\t,{\n\t\t\t\t\ttitle: I18n.jobinfo_field_jobdesc,\n\t\t\t\t\tfield: 'jobDesc',\n\t\t\t\t\twidth: '25',\n\t\t\t\t\twidthUnit: '%',\n\t\t\t\t\talign: 'left',\n\t\t\t\t\tformatter: function(value, row, index) {\n\t\t\t\t\t\tif (value.length > 15) {\n\t\t\t\t\t\t\treturn '<span title=\"' + value + '\">' + value.substr(0, 15) + '...</span>';\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treturn value;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},{\n\t\t\t\t\ttitle: I18n.schedule_type,\n\t\t\t\t\tfield: 'scheduleType',\n\t\t\t\t\twidth: '15',\n\t\t\t\t\twidthUnit: '%',\n\t\t\t\t\tformatter: function(value, row, index) {\n\t\t\t\t\t\tif (row.scheduleConf) {\n\t\t\t\t\t\t\treturn row.scheduleType + '：'+ row.scheduleConf;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treturn row.scheduleType;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},{\n\t\t\t\t\ttitle: I18n.jobinfo_field_gluetype,\n\t\t\t\t\tfield: 'glueType',\n\t\t\t\t\twidth: '25',\n\t\t\t\t\twidthUnit: '%',\n\t\t\t\t\tformatter: function(value, row, index) {\n\t\t\t\t\t\t// find glueType title\n\t\t\t\t\t\tlet glueTypeTitle = '';\n\t\t\t\t\t\t$(\"#addModal .form select[name=glueType] option\").each(function () {\n\t\t\t\t\t\t\tif (row.glueType == $(this).val()) {\n\t\t\t\t\t\t\t\tglueTypeTitle = $(this).text();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\t// append handler\n\t\t\t\t\t\tif (row.executorHandler) {\n\t\t\t\t\t\t\treturn glueTypeTitle +\"：\" + row.executorHandler;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treturn glueTypeTitle;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},{\n\t\t\t\t\ttitle: I18n.system_status,\n\t\t\t\t\tfield: 'triggerStatus',\n\t\t\t\t\twidth: '10',\n\t\t\t\t\twidthUnit: '%',\n\t\t\t\t\tformatter: function(value, row, index) {\n\t\t\t\t\t\t// 调度状态：0-停止，1-运行\n\t\t\t\t\t\tif (1 == value) {\n\t\t\t\t\t\t\treturn '<small class=\"label label-success\" >RUNNING</small>';\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treturn '<small class=\"label label-default\" >STOP</small>';\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn value;\n\t\t\t\t\t}\n\t\t\t\t},{\n\t\t\t\t\ttitle: I18n.jobinfo_field_author,\n\t\t\t\t\tfield: 'author',\n\t\t\t\t\twidth: '10',\n\t\t\t\t\twidthUnit: '%'\n\t\t\t\t}\n\t\t\t]\n\t\t});\n\n\t\t// ---------------------- delete ----------------------\n\n\t\t/**\n\t\t * delete\n\t\t */\n\t\t/*$.adminTable.initDelete({\n\t\t\turl: base_url + \"/jobinfo/delete\"\n\t\t});*/\n\t\t$(\"#data_operation\").on('click', '.delete',function() {\n\t\t\t// get select rows\n\t\t\tvar rows = $.adminTable.table.bootstrapTable('getSelections');\n\n\t\t\t// find select ids\n\t\t\tconst selectIds = (rows && rows.length > 0) ? rows.map(row => row.id) : [];\n\t\t\tif (selectIds.length !== 1) {\n\t\t\t\tlayer.msg(I18n.system_please_choose + I18n.system_one + I18n.system_data);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// do delete\n\t\t\tlayer.confirm( I18n.system_ok + I18n.system_opt_del + '?', {\n\t\t\t\ticon: 3,\n\t\t\t\ttitle: I18n.system_tips ,\n\t\t\t\tbtn: [ I18n.system_ok, I18n.system_cancel ]\n\t\t\t}, function(index){\n\t\t\t\tlayer.close(index);\n\n\t\t\t\t$.ajax({\n\t\t\t\t\ttype : 'POST',\n\t\t\t\t\turl : base_url + \"/jobinfo/delete\",\n\t\t\t\t\tdata : {\n\t\t\t\t\t\t\"ids\" : selectIds\n\t\t\t\t\t},\n\t\t\t\t\tdataType : \"json\",\n\t\t\t\t\tsuccess : function(data){\n\t\t\t\t\t\tif (data.code === 200) {\n\t\t\t\t\t\t\tlayer.msg( I18n.system_opt_del + I18n.system_success );\n\t\t\t\t\t\t\t// refresh table\n\t\t\t\t\t\t\t$('#data_filter .searchBtn').click();\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tlayer.msg( data.msg || I18n.system_opt_del + I18n.system_fail );\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\terror: function(xhr, status, error) {\n\t\t\t\t\t\t// Handle error\n\t\t\t\t\t\tconsole.log(\"Error: \" + error);\n\t\t\t\t\t\tlayer.open({\n\t\t\t\t\t\t\ticon: '2',\n\t\t\t\t\t\t\tcontent: (I18n.system_opt_del + I18n.system_fail)\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// ---------------------- start  ----------------------\n\n\t\t/**\n\t\t * start\n\t\t */\n\t\t$(\"#data_operation\").on('click', '.job_resume',function() {\n\t\t\t// get select rows\n\t\t\tvar rows = $.adminTable.table.bootstrapTable('getSelections');\n\n\t\t\t// find select ids\n\t\t\tconst selectIds = (rows && rows.length > 0) ? rows.map(row => row.id) : [];\n\t\t\tif (selectIds.length !== 1) {\n\t\t\t\tlayer.msg(I18n.system_please_choose + I18n.system_one + I18n.system_data);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// invoke\n\t\t\tlayer.confirm( I18n.system_ok + I18n.jobinfo_opt_start + '?', {\n\t\t\t\ticon: 3,\n\t\t\t\ttitle: I18n.system_tips ,\n\t\t\t\tbtn: [ I18n.system_ok, I18n.system_cancel ]\n\t\t\t}, function(index){\n\t\t\t\tlayer.close(index);\n\n\t\t\t\t$.ajax({\n\t\t\t\t\ttype : 'POST',\n\t\t\t\t\turl : base_url + \"/jobinfo/start\",\n\t\t\t\t\tdata : {\n\t\t\t\t\t\t\"ids\" : selectIds\n\t\t\t\t\t},\n\t\t\t\t\tdataType : \"json\",\n\t\t\t\t\tsuccess : function(data){\n\t\t\t\t\t\tif (data.code === 200) {\n\t\t\t\t\t\t\tlayer.msg( I18n.jobinfo_opt_start + I18n.system_success );\n\t\t\t\t\t\t\t// refresh table\n\t\t\t\t\t\t\t$('#data_filter .searchBtn').click();\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tlayer.msg( data.msg || I18n.jobinfo_opt_start + I18n.system_fail );\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\terror: function(xhr, status, error) {\n\t\t\t\t\t\t// Handle error\n\t\t\t\t\t\tconsole.log(\"Error: \" + error);\n\t\t\t\t\t\tlayer.open({\n\t\t\t\t\t\t\ticon: '2',\n\t\t\t\t\t\t\tcontent: (I18n.jobinfo_opt_start + I18n.system_fail)\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// ---------------------- stop ----------------------\n\n\t\t/**\n\t\t * stop\n\t\t */\n\t\t$(\"#data_operation\").on('click', '.job_pause',function() {\n\t\t\t// get select rows\n\t\t\tvar rows = $.adminTable.table.bootstrapTable('getSelections');\n\n\t\t\t// find select ids\n\t\t\tconst selectIds = (rows && rows.length > 0) ? rows.map(row => row.id) : [];\n\t\t\tif (selectIds.length !== 1) {\n\t\t\t\tlayer.msg(I18n.system_please_choose + I18n.system_one + I18n.system_data);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// invoke\n\t\t\tlayer.confirm( I18n.system_ok + I18n.jobinfo_opt_stop + '?', {\n\t\t\t\ticon: 3,\n\t\t\t\ttitle: I18n.system_tips ,\n\t\t\t\tbtn: [ I18n.system_ok, I18n.system_cancel ]\n\t\t\t}, function(index){\n\t\t\t\tlayer.close(index);\n\n\t\t\t\t$.ajax({\n\t\t\t\t\ttype : 'POST',\n\t\t\t\t\turl : base_url + \"/jobinfo/stop\",\n\t\t\t\t\tdata : {\n\t\t\t\t\t\t\"ids\" : selectIds\n\t\t\t\t\t},\n\t\t\t\t\tdataType : \"json\",\n\t\t\t\t\tsuccess : function(data){\n\t\t\t\t\t\tif (data.code === 200) {\n\t\t\t\t\t\t\tlayer.msg( I18n.jobinfo_opt_stop + I18n.system_success );\n\t\t\t\t\t\t\t// refresh table\n\t\t\t\t\t\t\t$('#data_filter .searchBtn').click();\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tlayer.msg( data.msg || I18n.jobinfo_opt_stop + I18n.system_fail );\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\terror: function(xhr, status, error) {\n\t\t\t\t\t\t// Handle error\n\t\t\t\t\t\tconsole.log(\"Error: \" + error);\n\t\t\t\t\t\tlayer.open({\n\t\t\t\t\t\t\ticon: '2',\n\t\t\t\t\t\t\tcontent: (I18n.jobinfo_opt_stop + I18n.system_fail)\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// ---------------------- trigger ----------------------\n\n\t\t/**\n\t\t * job trigger\n\t\t */\n\t\t$(\"#data_operation\").on('click', '.job_trigger',function() {\n\t\t\t// get select rows\n\t\t\tvar rows = $.adminTable.table.bootstrapTable('getSelections');\n\n\t\t\t// find select row\n\t\t\tif (rows.length !== 1) {\n\t\t\t\tlayer.msg(I18n.system_please_choose + I18n.system_one + I18n.system_data);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tvar row = rows[0];\n\n\t\t\t// fill modal\n\t\t\t$(\"#jobTriggerModal .form input[name='id']\").val( row.id );\n\t\t\t$(\"#jobTriggerModal .form textarea[name='executorParam']\").val( row.executorParam );\n\n\t\t\t$('#jobTriggerModal').modal({backdrop: false, keyboard: false}).modal('show');\n\t\t});\n\t\t$(\"#jobTriggerModal .ok\").on('click',function() {\n\t\t\t$.ajax({\n\t\t\t\ttype : 'POST',\n\t\t\t\turl : base_url + \"/jobinfo/trigger\",\n\t\t\t\tdata : {\n\t\t\t\t\t\"id\" : $(\"#jobTriggerModal .form input[name='id']\").val(),\n\t\t\t\t\t\"executorParam\" : $(\"#jobTriggerModal .textarea[name='executorParam']\").val(),\n\t\t\t\t\t\"addressList\" : $(\"#jobTriggerModal .textarea[name='addressList']\").val()\n\t\t\t\t},\n\t\t\t\tdataType : \"json\",\n\t\t\t\tsuccess : function(data){\n\t\t\t\t\tif (data.code == 200) {\n\t\t\t\t\t\t$('#jobTriggerModal').modal('hide');\n\n\t\t\t\t\t\tlayer.msg( I18n.jobinfo_opt_run + I18n.system_success );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlayer.msg( data.msg || I18n.jobinfo_opt_run + I18n.system_fail );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t\t$(\"#jobTriggerModal\").on('hide.bs.modal', function () {\n\t\t\t$(\"#jobTriggerModal .form\")[0].reset();\n\t\t});\n\n\t\t// ---------------------- registryinfo ----------------------\n\n\t\t/**\n\t\t * job registryinfo\n\t\t */\n\t\t$(\"#data_operation\").on('click', '.job_registryinfo',function() {\n\t\t\t// get select rows\n\t\t\tvar rows = $.adminTable.table.bootstrapTable('getSelections');\n\n\t\t\t// find select row\n\t\t\tif (rows.length !== 1) {\n\t\t\t\tlayer.msg(I18n.system_please_choose + I18n.system_one + I18n.system_data);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tvar row = rows[0];\n\n\t\t\t// invoke\n\t\t\t$.ajax({\n\t\t\t\ttype : 'POST',\n\t\t\t\turl : base_url + \"/jobgroup/loadById\",\n\t\t\t\tdata : {\n\t\t\t\t\t\"id\" : row.jobGroup\n\t\t\t\t},\n\t\t\t\tdataType : \"json\",\n\t\t\t\tsuccess : function(data){\n\n\t\t\t\t\tvar html = '<div>';\n\t\t\t\t\tif (data.code == 200 && data.data.registryList) {\n\t\t\t\t\t\tfor (var index in data.data.registryList) {\n\t\t\t\t\t\t\thtml += (parseInt(index)+1) + '. <span class=\"badge bg-green\" >' + data.data.registryList[index] + '</span><br>';\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\thtml += '</div>';\n\n\t\t\t\t\tlayer.open({\n\t\t\t\t\t\ttitle: I18n.jobinfo_opt_registryinfo ,\n\t\t\t\t\t\tbtn: [ I18n.system_ok ],\n\t\t\t\t\t\tcontent: html\n\t\t\t\t\t});\n\n\t\t\t\t}\n\t\t\t});\n\n\t\t});\n\n\t\t// ---------------------- job_log ----------------------\n\n\t\t/**\n\t\t * job_log\n\t\t */\n\t\t$(\"#data_operation\").on('click', '.job_log',function() {\n\t\t\t// get select rows\n\t\t\tvar rows = $.adminTable.table.bootstrapTable('getSelections');\n\n\t\t\t// find select row\n\t\t\tif (rows.length !== 1) {\n\t\t\t\tlayer.msg(I18n.system_please_choose + I18n.system_one + I18n.system_data);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tvar row = rows[0];\n\n\t\t\t// open tab\n\t\t\tlet url = base_url +'/joblog?jobId='+ row.id;\n\t\t\topenTab(url, I18n.joblog_name, false);\n\t\t});\n\n\t\t// ---------------------- glue_ide ----------------------\n\n\t\t/**\n\t\t * glue_ide\n\t\t */\n\t\t$(\"#data_operation\").on('click', '.glue_ide',function() {\n\t\t\t// get select rows\n\t\t\tvar rows = $.adminTable.table.bootstrapTable('getSelections');\n\n\t\t\t// find select row\n\t\t\tif (rows.length !== 1) {\n\t\t\t\tlayer.msg(I18n.system_please_choose + I18n.system_one + I18n.system_data);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tvar row = rows[0];\n\n\t\t\t// valid\n\t\t\tif ('BEAN' === row.glueType) {\n\t\t\t\tlayer.msg(I18n.jobinfo_glue_gluetype_unvalid);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// open tab\n\t\t\tlet url = base_url +'/jobcode?jobId='+ row.id;\n\t\t\twindow.open(url);\n\t\t\t//openTab(url, 'GLUE IDE', false);\n\t\t});\n\n\t\t// ---------------------- job_next_time ----------------------\n\n\t\t/**\n\t\t * job registryinfo\n\t\t */\n\t\t$(\"#data_operation\").on('click', '.job_next_time',function() {\n\t\t\t// get select rows\n\t\t\tvar rows = $.adminTable.table.bootstrapTable('getSelections');\n\n\t\t\t// find select row\n\t\t\tif (rows.length !== 1) {\n\t\t\t\tlayer.msg(I18n.system_please_choose + I18n.system_one + I18n.system_data);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tvar row = rows[0];\n\n\t\t\t// invoke\n\t\t\t$.ajax({\n\t\t\t\ttype : 'POST',\n\t\t\t\turl : base_url + \"/jobinfo/nextTriggerTime\",\n\t\t\t\tdata : {\n\t\t\t\t\t\"scheduleType\" : row.scheduleType,\n\t\t\t\t\t\"scheduleConf\" : row.scheduleConf\n\t\t\t\t},\n\t\t\t\tdataType : \"json\",\n\t\t\t\tsuccess : function(data){\n\n\t\t\t\t\tif (data.code != 200) {\n\t\t\t\t\t\tlayer.open({\n\t\t\t\t\t\t\ttitle: I18n.jobinfo_opt_next_time ,\n\t\t\t\t\t\t\tbtn: [ I18n.system_ok ],\n\t\t\t\t\t\t\tcontent: data.msg\n\t\t\t\t\t\t});\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvar html = '<center>';\n\t\t\t\t\t\tif (data.code == 200 && data.data) {\n\t\t\t\t\t\t\tfor (var index in data.data) {\n\t\t\t\t\t\t\t\thtml += '<span>' + data.data[index] + '</span><br>';\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\thtml += '</center>';\n\n\t\t\t\t\t\tlayer.open({\n\t\t\t\t\t\t\ttitle: I18n.jobinfo_opt_next_time ,\n\t\t\t\t\t\t\tbtn: [ I18n.system_ok ],\n\t\t\t\t\t\t\tcontent: html\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t}\n\t\t\t});\n\n\t\t});\n\n\t\t// ---------------------- add ----------------------\n\n\t\t/**\n\t\t * add\n\t\t */\n\t\t$.adminTable.initAdd( {\n\t\t\turl: base_url + \"/jobinfo/insert\",\n\t\t\trules : {\n\t\t\t\tjobDesc : {\n\t\t\t\t\trequired : true,\n\t\t\t\t\tmaxlength: 50\n\t\t\t\t},\n\t\t\t\tauthor : {\n\t\t\t\t\trequired : true\n\t\t\t\t}\n\t\t\t},\n\t\t\tmessages : {\n\t\t\t\tjobDesc : {\n\t\t\t\t\trequired : I18n.system_please_input + I18n.jobinfo_field_jobdesc\n\t\t\t\t},\n\t\t\t\tauthor : {\n\t\t\t\t\trequired : I18n.system_please_input + I18n.jobinfo_field_author\n\t\t\t\t}\n\t\t\t},\n\t\t\twriteFormData: function() {\n\t\t\t\t// init-cronGen\n\t\t\t\t$(\"#addModal .form input[name='schedule_conf_CRON']\").show().siblings().remove();\n\t\t\t\t$(\"#addModal .form input[name='schedule_conf_CRON']\").cronGen({});\n\n\t\t\t\t// 》init scheduleType\n\t\t\t\t$(\"#addModal .form select[name=scheduleType]\").change();\n\n\t\t\t\t// 》init glueType\n\t\t\t\t$(\"#addModal .form select[name=glueType]\").change();\n\t\t\t},\n\t\t\treadFormData: function() {\n\n\t\t\t\t// process executorTimeout+executorFailRetryCount\n\t\t\t\tvar executorTimeout = $(\"#addModal .form input[name='executorTimeout']\").val();\n\t\t\t\tif(!/^\\d+$/.test(executorTimeout)) {\n\t\t\t\t\texecutorTimeout = 0;\n\t\t\t\t}\n\t\t\t\t$(\"#addModal .form input[name='executorTimeout']\").val(executorTimeout);\n\t\t\t\tvar executorFailRetryCount = $(\"#addModal .form input[name='executorFailRetryCount']\").val();\n\t\t\t\tif(!/^\\d+$/.test(executorFailRetryCount)) {\n\t\t\t\t\texecutorFailRetryCount = 0;\n\t\t\t\t}\n\t\t\t\t$(\"#addModal .form input[name='executorFailRetryCount']\").val(executorFailRetryCount);\n\n\t\t\t\t// process schedule_conf\n\t\t\t\tvar scheduleType = $(\"#addModal .form select[name='scheduleType']\").val();\n\t\t\t\tvar scheduleConf;\n\t\t\t\tif (scheduleType == 'CRON') {\n\t\t\t\t\tscheduleConf = $(\"#addModal .form input[name='cronGen_display']\").val();\n\t\t\t\t} else if (scheduleType == 'FIX_RATE') {\n\t\t\t\t\tscheduleConf = $(\"#addModal .form input[name='schedule_conf_FIX_RATE']\").val();\n\t\t\t\t} else if (scheduleType == 'FIX_DELAY') {\n\t\t\t\t\tscheduleConf = $(\"#addModal .form input[name='schedule_conf_FIX_DELAY']\").val();\n\t\t\t\t}\n\t\t\t\t$(\"#addModal .form input[name='scheduleConf']\").val( scheduleConf );\n\n\t\t\t\treturn $(\"#addModal .form\").serialize();\n\t\t\t}\n\t\t});\n\n\t\t// scheduleType change\n\t\t$(\".scheduleType\").change(function(){\n\t\t\tvar scheduleType = $(this).val();\n\t\t\t$(this).parents(\"form\").find(\".schedule_conf\").hide();\n\t\t\t$(this).parents(\"form\").find(\".schedule_conf_\" + scheduleType).show();\n\n\t\t});\n\n\t\t// glueType change\n\t\t$(\".glueType\").change(function(){\n\t\t\t// executorHandler\n\t\t\tvar $executorHandler = $(this).parents(\"form\").find(\"input[name='executorHandler']\");\n\t\t\tvar glueType = $(this).val();\n\t\t\tif ('BEAN' != glueType) {\n\t\t\t\t$executorHandler.val(\"\");\n\t\t\t\t$executorHandler.attr(\"readonly\",\"readonly\");\n\t\t\t} else {\n\t\t\t\t$executorHandler.removeAttr(\"readonly\");\n\t\t\t}\n\t\t});\n\n\t\t// glueType init source\n\t\t$(\"#addModal .glueType\").change(function(){\n\t\t\t// glueSource\n\t\t\tvar glueType = $(this).val();\n\t\t\tif ('GLUE_GROOVY'==glueType){\n\t\t\t\t$(\"#addModal .form textarea[name='glueSource']\").val( $(\"#addModal .form .glueSource_java\").val() );\n\t\t\t} else if ('GLUE_SHELL'==glueType){\n\t\t\t\t$(\"#addModal .form textarea[name='glueSource']\").val( $(\"#addModal .form .glueSource_shell\").val() );\n\t\t\t} else if ('GLUE_PYTHON'==glueType){\n\t\t\t\t$(\"#addModal .form textarea[name='glueSource']\").val( $(\"#addModal .form .glueSource_python\").val() );\n\t\t\t} else if ('GLUE_PYTHON2'==glueType){\n\t\t\t\t$(\"#addModal .form textarea[name='glueSource']\").val( $(\"#addModal .form .glueSource_python2\").val() );\n\t\t\t} else if ('GLUE_PHP'==glueType){\n\t\t\t\t$(\"#addModal .form textarea[name='glueSource']\").val( $(\"#addModal .form .glueSource_php\").val() );\n\t\t\t} else if ('GLUE_NODEJS'==glueType){\n\t\t\t\t$(\"#addModal .form textarea[name='glueSource']\").val( $(\"#addModal .form .glueSource_nodejs\").val() );\n\t\t\t} else if ('GLUE_POWERSHELL'==glueType){\n\t\t\t\t$(\"#addModal .form textarea[name='glueSource']\").val( $(\"#addModal .form .glueSource_powershell\").val() );\n\t\t\t} else {\n\t\t\t\t$(\"#addModal .form textarea[name='glueSource']\").val(\"\");\n\t\t\t}\n\t\t});\n\n\t\t// ---------------------- update ----------------------\n\n\t\t/**\n\t\t * init update\n\t\t */\n\t\t$.adminTable.initUpdate( {\n\t\t\turl: base_url + \"/jobinfo/update\",\n\t\t\trules : {\n\t\t\t\tjobDesc : {\n\t\t\t\t\trequired : true,\n\t\t\t\t\tmaxlength: 50\n\t\t\t\t},\n\t\t\t\tauthor : {\n\t\t\t\t\trequired : true\n\t\t\t\t}\n\t\t\t},\n\t\t\tmessages : {\n\t\t\t\tjobDesc : {\n\t\t\t\t\trequired : I18n.system_please_input + I18n.jobinfo_field_jobdesc\n\t\t\t\t},\n\t\t\t\tauthor : {\n\t\t\t\t\trequired : I18n.system_please_input + I18n.jobinfo_field_author\n\t\t\t\t}\n\t\t\t},\n\t\t\twriteFormData: function(row) {\n\n\t\t\t\t// fill base\n\t\t\t\t$(\"#updateModal .form input[name='id']\").val( row.id );\n\t\t\t\t$('#updateModal .form select[name=jobGroup] option[value='+ row.jobGroup +']').prop('selected', true);\n\t\t\t\t$(\"#updateModal .form input[name='jobDesc']\").val( row.jobDesc );\n\t\t\t\t$(\"#updateModal .form input[name='author']\").val( row.author );\n\t\t\t\t$(\"#updateModal .form input[name='alarmEmail']\").val( row.alarmEmail );\n\n\t\t\t\t// fill trigger\n\t\t\t\t$('#updateModal .form select[name=scheduleType] option[value='+ row.scheduleType +']').prop('selected', true);\n\t\t\t\t$(\"#updateModal .form input[name='scheduleConf']\").val( row.scheduleConf );\n\t\t\t\tif (row.scheduleType == 'CRON') {\n\t\t\t\t\t$(\"#updateModal .form input[name='schedule_conf_CRON']\").val( row.scheduleConf );\n\t\t\t\t} else if (row.scheduleType == 'FIX_RATE') {\n\t\t\t\t\t$(\"#updateModal .form input[name='schedule_conf_FIX_RATE']\").val( row.scheduleConf );\n\t\t\t\t} else if (row.scheduleType == 'FIX_DELAY') {\n\t\t\t\t\t$(\"#updateModal .form input[name='schedule_conf_FIX_DELAY']\").val( row.scheduleConf );\n\t\t\t\t}\n\n\t\t\t\t// 》init scheduleType\n\t\t\t\t$(\"#updateModal .form select[name=scheduleType]\").change();\n\n\t\t\t\t// fill job\n\t\t\t\t$('#updateModal .form select[name=glueType] option[value='+ row.glueType +']').prop('selected', true);\n\t\t\t\t$(\"#updateModal .form input[name='executorHandler']\").val( row.executorHandler );\n\t\t\t\t$(\"#updateModal .form textarea[name='executorParam']\").val( row.executorParam );\n\n\t\t\t\t// 》init glueType\n\t\t\t\t$(\"#updateModal .form select[name=glueType]\").change();\n\n\t\t\t\t// 》init-cronGen\n\t\t\t\t$(\"#updateModal .form input[name='schedule_conf_CRON']\").show().siblings().remove();\n\t\t\t\t$(\"#updateModal .form input[name='schedule_conf_CRON']\").cronGen({});\n\n\t\t\t\t// fill advanced\n\t\t\t\t$('#updateModal .form select[name=executorRouteStrategy] option[value='+ row.executorRouteStrategy +']').prop('selected', true);\n\t\t\t\t$(\"#updateModal .form input[name='childJobId']\").val( row.childJobId );\n\t\t\t\t$('#updateModal .form select[name=misfireStrategy] option[value='+ row.misfireStrategy +']').prop('selected', true);\n\t\t\t\t$('#updateModal .form select[name=executorBlockStrategy] option[value='+ row.executorBlockStrategy +']').prop('selected', true);\n\t\t\t\t$(\"#updateModal .form input[name='executorTimeout']\").val( row.executorTimeout );\n\t\t\t\t$(\"#updateModal .form input[name='executorFailRetryCount']\").val( row.executorFailRetryCount );\n\n\t\t\t},\n\t\t\treadFormData: function() {\n\n\t\t\t\t// process executorTimeout + executorFailRetryCount\n\t\t\t\tvar executorTimeout = $(\"#updateModal .form input[name='executorTimeout']\").val();\n\t\t\t\tif(!/^\\d+$/.test(executorTimeout)) {\n\t\t\t\t\texecutorTimeout = 0;\n\t\t\t\t}\n\t\t\t\t$(\"#updateModal .form input[name='executorTimeout']\").val(executorTimeout);\n\t\t\t\tvar executorFailRetryCount = $(\"#updateModal .form input[name='executorFailRetryCount']\").val();\n\t\t\t\tif(!/^\\d+$/.test(executorFailRetryCount)) {\n\t\t\t\t\texecutorFailRetryCount = 0;\n\t\t\t\t}\n\t\t\t\t$(\"#updateModal .form input[name='executorFailRetryCount']\").val(executorFailRetryCount);\n\n\n\t\t\t\t// process schedule_conf\n\t\t\t\tvar scheduleType = $(\"#updateModal .form select[name='scheduleType']\").val();\n\t\t\t\tvar scheduleConf;\n\t\t\t\tif (scheduleType == 'CRON') {\n\t\t\t\t\tscheduleConf = $(\"#updateModal .form input[name='cronGen_display']\").val();\n\t\t\t\t} else if (scheduleType == 'FIX_RATE') {\n\t\t\t\t\tscheduleConf = $(\"#updateModal .form input[name='schedule_conf_FIX_RATE']\").val();\n\t\t\t\t} else if (scheduleType == 'FIX_DELAY') {\n\t\t\t\t\tscheduleConf = $(\"#updateModal .form input[name='schedule_conf_FIX_DELAY']\").val();\n\t\t\t\t}\n\t\t\t\t$(\"#updateModal .form input[name='scheduleConf']\").val( scheduleConf );\n\n\t\t\t\treturn $(\"#updateModal .form\").serialize();\n\t\t\t}\n\t\t});\n\n\t\t// ---------------------- job_copy ----------------------\n\n\t\t/**\n\t\t * job_copy\n\t\t */\n\t\t$(\"#data_operation\").on('click', '.job_copy',function() {\n\t\t\t// get select rows\n\t\t\tvar rows = $.adminTable.table.bootstrapTable('getSelections');\n\n\t\t\t// find select row\n\t\t\tif (rows.length !== 1) {\n\t\t\t\tlayer.msg(I18n.system_please_choose + I18n.system_one + I18n.system_data);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tvar row = rows[0];\n\n\t\t\t// open addModel\n\t\t\t$(\"#data_operation .add\").click();\n\n\t\t\t// fill base\n\t\t\t$('#addModal .form select[name=jobGroup] option[value='+ row.jobGroup +']').prop('selected', true);\n\t\t\t$(\"#addModal .form input[name='jobDesc']\").val( row.jobDesc );\n\t\t\t$(\"#addModal .form input[name='author']\").val( row.author );\n\t\t\t$(\"#addModal .form input[name='alarmEmail']\").val( row.alarmEmail );\n\n\t\t\t// fill trigger\n\t\t\t$('#addModal .form select[name=scheduleType] option[value='+ row.scheduleType +']').prop('selected', true);\n\t\t\t$(\"#addModal .form input[name='scheduleConf']\").val( row.scheduleConf );\n\t\t\tif (row.scheduleType == 'CRON') {\n\t\t\t\t$(\"#addModal .form input[name='schedule_conf_CRON']\").val( row.scheduleConf );\n\t\t\t} else if (row.scheduleType == 'FIX_RATE') {\n\t\t\t\t$(\"#addModal .form input[name='schedule_conf_FIX_RATE']\").val( row.scheduleConf );\n\t\t\t} else if (row.scheduleType == 'FIX_DELAY') {\n\t\t\t\t$(\"#addModal .form input[name='schedule_conf_FIX_DELAY']\").val( row.scheduleConf );\n\t\t\t}\n\n\t\t\t// 》init scheduleType\n\t\t\t$(\"#addModal .form select[name=scheduleType]\").change();\n\n\t\t\t// fill job\n\t\t\t$('#addModal .form select[name=glueType] option[value='+ row.glueType +']').prop('selected', true);\n\t\t\t$(\"#addModal .form input[name='executorHandler']\").val( row.executorHandler );\n\t\t\t$(\"#addModal .form textarea[name='executorParam']\").val( row.executorParam );\n\n\t\t\t// 》init glueType\n\t\t\t$(\"#addModal .form select[name=glueType]\").change();\n\n\t\t\t// 》init-cronGen\n\t\t\t$(\"#addModal .form input[name='schedule_conf_CRON']\").show().siblings().remove();\n\t\t\t$(\"#addModal .form input[name='schedule_conf_CRON']\").cronGen({});\n\n\t\t\t// fill advanced\n\t\t\t$('#addModal .form select[name=executorRouteStrategy] option[value='+ row.executorRouteStrategy +']').prop('selected', true);\n\t\t\t$(\"#addModal .form input[name='childJobId']\").val( row.childJobId );\n\t\t\t$('#addModal .form select[name=misfireStrategy] option[value='+ row.misfireStrategy +']').prop('selected', true);\n\t\t\t$('#addModal .form select[name=executorBlockStrategy] option[value='+ row.executorBlockStrategy +']').prop('selected', true);\n\t\t\t$(\"#addModal .form input[name='executorTimeout']\").val( row.executorTimeout );\n\t\t\t$(\"#addModal .form input[name='executorFailRetryCount']\").val( row.executorFailRetryCount );\n\t\t});\n\n\t});\n\n</script>\n<!-- 3-script end -->\n\n</body>\n</html>"
  },
  {
    "path": "xxl-job-admin/src/main/resources/templates/biz/log.detail.ftl",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n\t<#-- import macro -->\n\t<#import \"../common/common.macro.ftl\" as netCommon>\n\n\t<!-- 1-style start -->\n\t<@netCommon.commonStyle />\n\t<!-- 1-style end -->\n\n</head>\n<body class=\"hold-transition skin-blue layout-top-nav\" >\n<div class=\"wrapper\" >\n\n\t<!-- 2-header start -->\n\t<header class=\"main-header\">\n\t\t<nav class=\"navbar navbar-static-top\">\n\t\t\t<div class=\"container\">\n\t\t\t\t<#-- icon -->\n\t\t\t\t<div class=\"navbar-header\">\n\t\t\t\t\t<a class=\"navbar-brand\" href=\"javascript:void(0);\" ><b>${I18n.joblog_rolling_log}</b> Console</a>\n\t\t\t\t\t<button type=\"button\" class=\"navbar-toggle collapsed\" data-toggle=\"collapse\" data-target=\"#navbar-collapse\">\n\t\t\t\t\t\t<i class=\"fa fa-bars\"></i>\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\n\t\t\t\t<#-- left nav -->\n\t\t\t\t<div class=\"collapse navbar-collapse pull-left\" id=\"navbar-collapse\">\n\t\t\t\t\t<ul class=\"nav navbar-nav\">\n\t\t\t\t\t\t<li class=\"active\" >\n\t\t\t\t\t\t\t<a href=\"javascript:;\">${I18n.jobinfo_job}：${jobInfo.jobDesc}</a>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t</ul>\n\t\t\t\t</div>\n\n\t\t\t\t<#-- right nav -->\n\t\t\t\t<div class=\"navbar-custom-menu\">\n\t\t\t\t\t<ul class=\"nav navbar-nav\">\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<a href=\"javascript:window.location.reload();\" >\n\t\t\t\t\t\t\t\t<i class=\"fa fa-fw fa-refresh\" ></i>\n\t\t\t\t\t\t\t\t${I18n.joblog_rolling_log_refresh}\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<a href=\"javascript:window.close();\" >\n\t\t\t\t\t\t\t\t<i class=\"fa fa-fw fa-close\" ></i>\n\t\t\t\t\t\t\t\t${I18n.system_close}\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t</ul>\n\t\t\t\t</div>\n\n\t\t\t</div>\n\t\t</nav>\n\t</header>\n\t<!-- 2-header end -->\n\n\t<!-- 3-content start -->\n\t<div class=\"content-wrapper\">\n\t\t<section class=\"content\">\n\t\t\t<!-- rolling log -->\n\t\t\t<pre style=\"font-size:12px;position:relative;\" >\n\t\t\t\t<div id=\"logConsole\"></div>\n\t\t\t\t<li class=\"fa fa-refresh fa-spin\" style=\"font-size: 20px;float: left;\" id=\"logConsoleRunning\" ></li>\n\t\t\t</pre>\n\t\t</section>\n\t</div>\n\t<!-- 3-content end -->\n\n\t<!-- 4-footer start -->\n\t<footer class=\"main-footer\">\n\t\tPowered by <b>XXL-JOB</b> ${I18n.admin_version}\n\t\t<div class=\"pull-right hidden-xs\">\n\t\t\t<strong>Copyright &copy; 2015-${.now?string('yyyy')} &nbsp;\n\t\t\t\t<a href=\"https://www.xuxueli.com/\" target=\"_blank\" >xuxueli</a>\n\t\t\t\t&nbsp;\n\t\t\t\t<a href=\"https://github.com/xuxueli/xxl-job\" target=\"_blank\" >github</a>\n\t\t\t</strong><!-- All rights reserved. -->\n\t\t</div>\n\t</footer>\n\t<!-- 4-footer end -->\n\n</div>\n\n<!-- 5-script start -->\n<@netCommon.commonScript />\n<script src=\"${request.contextPath}/static/biz/common/admin.setting.js?v=${I18n.admin_version}\"></script>\n<script>\n\t$(function() {\n\n\t\t// init param\n\t\tvar triggerCode = '${triggerCode}';\n\t\tvar handleCode = '${handleCode}';\n\t\tvar logId = '${logId}';\n\n\t\t// trigger fail and not handle\n        if (triggerCode != 200 && handleCode == 0) {\n\t\t\t$('#logConsoleRunning').hide();\n\t\t\t$('#logConsole').append('<span style=\"color: red;\">['+ I18n.joblog_rolling_log_triggerfail +']</span>');\n\t\t\treturn;\n\t\t}\n\n\t\t/**\n\t\t * pull log\n\t\t */\n\t\tvar fromLineNum = 1;    // [from, to], start as 1\n\t\tvar pullFailCount = 0;\n\t\tfunction pullLog() {\n            // limit max pull-fail count, max=20\n\t\t\tif (pullFailCount++ > 20) {\n\t\t\t\tlogRunStop('<span style=\"color: red;\">['+ I18n.joblog_rolling_log_failoften +']</span>');\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// load\n\t\t\tconsole.log(\"pullLog, fromLineNum:\" + fromLineNum);\n\t\t\t$.ajax({\n\t\t\t\ttype : 'POST',\n\t\t\t\tasync: false,   // sync, make log ordered\n\t\t\t\turl : base_url + '/joblog/logDetailCat',\n\t\t\t\tdata : {\n\t\t\t\t\t\"logId\":logId,\n\t\t\t\t\t\"fromLineNum\":fromLineNum\n\t\t\t\t},\n\t\t\t\tdataType : \"json\",\n\t\t\t\tsuccess : function(data){\n\n\t\t\t\t\tif (data.code == 200) {\n                        // pull fail\n\t\t\t\t\t\tif (!data.data) {\n\t\t\t\t\t\t\tconsole.log('pullLog fail');\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (fromLineNum != data.data.fromLineNum) {\n\t\t\t\t\t\t\tconsole.log('pullLog fromLineNum not match');\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n                        // pull to end\n\t\t\t\t\t\tif (fromLineNum > data.data.toLineNum ) {\n\t\t\t\t\t\t\tconsole.log('pullLog already line-end');\n\n\t\t\t\t\t\t\t// valid end\n\t\t\t\t\t\t\tif (data.data.end) {\n\t\t\t\t\t\t\t\tlogRunStop('<br><span style=\"color: green;\">[Rolling Log End]</span>');\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// append content\n\t\t\t\t\t\tfromLineNum = data.data.toLineNum + 1;\n\t\t\t\t\t\t$('#logConsole').append(data.data.logContent);\n\t\t\t\t\t\tpullFailCount = 0;\n\n\t\t\t\t\t\t// scroll to bottom\n\t\t\t\t\t\tscrollTo(0, document.body.scrollHeight);        // $('#logConsolePre').scrollTop( document.body.scrollHeight + 300 );\n\n\t\t\t\t\t} else {\n                        // pull fail\n\t\t\t\t\t\tconsole.log('pullLog fail:'+data.msg);\n                        $('#logConsole').append('<span style=\"color: red;\">[Rolling Log Error]: '+ data.msg +'</span>');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t// pull first page\n\t\tpullLog();\n\n\t\t// if handle already callback, stop cycle pull\n\t\tif (handleCode > 0) {\n\t\t\tlogRunStop('<br><span style=\"color: green;\">[Rolling Log Finish]</span>');\n\t\t\treturn;\n\t\t}\n\n\t\t/**\n\t\t * cycle pull, until end\n\t\t */\n\t\tvar logRun = setInterval(function () {\n\t\t\tpullLog()\n\t\t}, 3000);\n\t\tfunction logRunStop(content){\n\t\t\t$('#logConsoleRunning').hide();\n\t\t\tlogRun = window.clearInterval(logRun);\n\t\t\t$('#logConsole').append(content);\n\t\t}\n\n\t});\n</script>\n<!-- 5-script end -->\n\n</body>\n</html>"
  },
  {
    "path": "xxl-job-admin/src/main/resources/templates/biz/log.list.ftl",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n\t<#-- import macro -->\n\t<#import \"../common/common.macro.ftl\" as netCommon>\n\n\t<!-- 1-style start -->\n\t<@netCommon.commonStyle />\n\t<link rel=\"stylesheet\" href=\"${request.contextPath}/static/plugins/bootstrap-table/bootstrap-table.min.css\">\n\t<!-- daterangepicker -->\n\t<link rel=\"stylesheet\" href=\"${request.contextPath}/static/adminlte/bower_components/bootstrap-daterangepicker/daterangepicker.css\">\n\t<!-- 1-style end -->\n\n</head>\n<body class=\"hold-transition\" style=\"background-color: #ecf0f5;\">\n<div class=\"wrapper\">\n\t<section class=\"content\">\n\n\t\t<!-- 2-content start -->\n\n\t\t<#-- 查询区域 -->\n\t\t<div class=\"box\" style=\"margin-bottom:9px;\">\n\t\t\t<div class=\"box-body\">\n\t\t\t\t<div class=\"row\" id=\"data_filter\" >\n\n\t\t\t\t\t<div class=\"col-xs-2\">\n\t\t\t\t\t\t<div class=\"input-group\">\n\t\t\t\t\t\t\t<span class=\"input-group-addon\">${I18n.jobinfo_field_jobgroup}</span>\n\t\t\t\t\t\t\t<select class=\"form-control\" id=\"jobGroup\"  >\n\t\t\t\t\t\t\t\t<#list JobGroupList as group>\n\t\t\t\t\t\t\t\t\t<option value=\"${group.id}\" <#if jobGroup==group.id>selected</#if> >${group.title}</option>\n\t\t\t\t\t\t\t\t</#list>\n\t\t\t\t\t\t\t</select>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"col-xs-2\">\n\t\t\t\t\t\t<div class=\"input-group\">\n\t\t\t\t\t\t\t<span class=\"input-group-addon\">${I18n.jobinfo_job}</span>\n\t\t\t\t\t\t\t<select class=\"form-control\" id=\"jobId\" >\n\t\t\t\t\t\t\t\t<#if jobInfoList?size gt 0>\n\t\t\t\t\t\t\t\t\t<#list jobInfoList as jobItem>\n\t\t\t\t\t\t\t\t\t\t<option value=\"${jobItem.id}\" >${jobItem.jobDesc}</option>\n\t\t\t\t\t\t\t\t\t</#list>\n\t\t\t\t\t\t\t\t<#else>\n\t\t\t\t\t\t\t\t\t<option value=\"0\" >${I18n.system_selected_nothing}</option>\n\t\t\t\t\t\t\t\t</#if>\n\t\t\t\t\t\t\t</select>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"col-xs-2\">\n\t\t\t\t\t\t<div class=\"input-group\">\n\t\t\t\t\t\t\t<span class=\"input-group-addon\">${I18n.joblog_status}</span>\n\t\t\t\t\t\t\t<select class=\"form-control\" id=\"logStatus\" >\n\t\t\t\t\t\t\t\t<option value=\"-1\" >${I18n.joblog_status_all}</option>\n\t\t\t\t\t\t\t\t<option value=\"1\" >${I18n.joblog_status_suc}</option>\n\t\t\t\t\t\t\t\t<option value=\"2\" >${I18n.joblog_status_fail}</option>\n\t\t\t\t\t\t\t\t<option value=\"3\" >${I18n.joblog_status_running}</option>\n\t\t\t\t\t\t\t</select>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"col-xs-4\">\n\t\t\t\t\t\t<div class=\"input-group\">\n                \t\t<span class=\"input-group-addon\">\n\t                  \t\t${I18n.joblog_field_triggerTime}\n\t                \t</span>\n\t\t\t\t\t\t\t<input type=\"text\" class=\"form-control\" id=\"filterTime\" readonly >\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div class=\"col-xs-1\">\n\t\t\t\t\t\t<button class=\"btn btn-block btn-primary searchBtn\" >${I18n.system_search}</button>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"col-xs-1\">\n\t\t\t\t\t\t<button class=\"btn btn-block btn-default resetBtn\" >${I18n.system_reset}</button>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<#-- 数据表格区域 -->\n\t\t<div class=\"row\">\n\t\t\t<div class=\"col-xs-12\">\n\t\t\t\t<div class=\"box\">\n\t\t\t\t\t<div class=\"box-header pull-left\" id=\"data_operation\" >\n\t\t\t\t\t\t<button class=\"btn btn-sm btn-warning selectOnlyOne logKill\" type=\"button\">${I18n.joblog_kill_log}</button>\n\t\t\t\t\t\t<button class=\"btn btn-sm btn-danger selectAny clearLog\" type=\"button\">${I18n.joblog_clean_log}</button>\n\t\t\t\t\t\t｜\n\t\t\t\t\t\t<button class=\"btn btn-sm btn-primary selectOnlyOne logDetail\" type=\"button\"><#--<i class=\"fa fa-edit\"></i>-->${I18n.joblog_rolling_log}</button>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"box-body\" >\n\t\t\t\t\t\t<table id=\"data_list\" class=\"table table-bordered table-striped\" width=\"100%\" >\n\t\t\t\t\t\t\t<thead></thead>\n\t\t\t\t\t\t\t<tbody></tbody>\n\t\t\t\t\t\t\t<tfoot></tfoot>\n\t\t\t\t\t\t</table>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<!-- 日志清理.模态框 -->\n\t\t<div class=\"modal fade\" id=\"clearLogModal\" tabindex=\"-1\" role=\"dialog\"  aria-hidden=\"true\">\n\t\t\t<div class=\"modal-dialog\">\n\t\t\t\t<div class=\"modal-content\">\n\t\t\t\t\t<div class=\"modal-header\">\n\t\t\t\t\t\t<h4 class=\"modal-title\" >${I18n.joblog_clean_log}</h4>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"modal-body\">\n\t\t\t\t\t\t<form class=\"form-horizontal form\" role=\"form\" >\n\t\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t\t<label class=\"col-sm-3 control-label\">${I18n.jobinfo_field_jobgroup}：</label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-9\">\n\t\t\t\t\t\t\t\t\t<input type=\"text\" class=\"form-control jobGroupText\" readonly >\n\t\t\t\t\t\t\t\t\t<input type=\"hidden\" name=\"jobGroup\" >\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t\t<label class=\"col-sm-3 control-label\">${I18n.jobinfo_job}：</label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-9\">\n\t\t\t\t\t\t\t\t\t<input type=\"text\" class=\"form-control jobIdText\" readonly >\n\t\t\t\t\t\t\t\t\t<input type=\"hidden\" name=\"jobId\" >\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t\t<label class=\"col-sm-3 control-label\">${I18n.joblog_clean_type}：</label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-9\">\n\t\t\t\t\t\t\t\t\t<select class=\"form-control\" name=\"type\" >\n\t\t\t\t\t\t\t\t\t\t<option value=\"1\" >${I18n.joblog_clean_type_1}</option>\n\t\t\t\t\t\t\t\t\t\t<option value=\"2\" >${I18n.joblog_clean_type_2}</option>\n\t\t\t\t\t\t\t\t\t\t<option value=\"3\" >${I18n.joblog_clean_type_3}</option>\n\t\t\t\t\t\t\t\t\t\t<option value=\"4\" >${I18n.joblog_clean_type_4}</option>\n\t\t\t\t\t\t\t\t\t\t<option value=\"5\" >${I18n.joblog_clean_type_5}</option>\n\t\t\t\t\t\t\t\t\t\t<option value=\"6\" >${I18n.joblog_clean_type_6}</option>\n\t\t\t\t\t\t\t\t\t\t<option value=\"7\" >${I18n.joblog_clean_type_7}</option>\n\t\t\t\t\t\t\t\t\t\t<option value=\"8\" >${I18n.joblog_clean_type_8}</option>\n\t\t\t\t\t\t\t\t\t\t<option value=\"9\" >${I18n.joblog_clean_type_9}</option>\n\t\t\t\t\t\t\t\t\t</select>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t\t<hr>\n\t\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t\t<div class=\"col-sm-offset-3 col-sm-6\">\n\t\t\t\t\t\t\t\t\t<button type=\"button\" class=\"btn btn-primary ok\" >${I18n.system_ok}</button>\n\t\t\t\t\t\t\t\t\t<button type=\"button\" class=\"btn btn-default\" data-dismiss=\"modal\">${I18n.system_cancel}</button>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</form>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<!-- 2-content end -->\n\n\t</section>\n</div>\n\n<!-- 3-script start -->\n<@netCommon.commonScript />\n<script src=\"${request.contextPath}/static/plugins/bootstrap-table/bootstrap-table.min.js\"></script>\n<script src=\"${request.contextPath}/static/plugins/bootstrap-table/locale/<#if I18n.admin_i18n?? && I18n.admin_i18n == 'en'>bootstrap-table-en-US.min.js<#else>bootstrap-table-zh-CN.min.js</#if>\"></script>\n<#--daterangepicker-->\n<script src=\"${request.contextPath}/static/adminlte/bower_components/moment/moment.min.js\"></script>\n<script src=\"${request.contextPath}/static/adminlte/bower_components/bootstrap-daterangepicker/daterangepicker.js\"></script>\n<#-- admin table -->\n<script src=\"${request.contextPath}/static/biz/common/admin.table.js\"></script>\n<script>\n\t$(function() {\n\n\t\t// ---------------------- filter ----------------------\n\n\t\t/**\n\t\t * jobGroup change\n \t\t */\n\t\t$('#jobGroup').on('change', function(){\n\t\t\t//reload\n\t\t\tvar jobGroup = $('#jobGroup').val();\n\t\t\twindow.location.href = base_url + \"/joblog?jobGroup=\" + jobGroup;\n\t\t});\n\n\t\t/**\n\t\t * filter Time\n\t\t */\n\t\tvar rangesConf = {};\n\t\trangesConf[I18n.daterangepicker_ranges_today] = [moment().startOf('day'), moment().endOf('day')];\n\t\trangesConf[I18n.daterangepicker_ranges_yesterday] = [moment().subtract(1, 'days').startOf('day'), moment().subtract(1, 'days').endOf('day')];\n\t\trangesConf[I18n.daterangepicker_ranges_this_month] = [moment().startOf('month'), moment().endOf('month')];\n\t\trangesConf[I18n.daterangepicker_ranges_last_month] = [moment().subtract(1, 'months').startOf('month'), moment().subtract(1, 'months').endOf('month')];\n\t\trangesConf[I18n.daterangepicker_ranges_recent_week] = [moment().subtract(1, 'weeks').startOf('day'), moment().endOf('day')];\n\t\trangesConf[I18n.daterangepicker_ranges_recent_month] = [moment().subtract(1, 'months').startOf('day'), moment().endOf('day')];\n\n\t\t$('#filterTime').daterangepicker({\n\t\t\tautoApply:false,\n\t\t\tsingleDatePicker:false,\t\t// 范围选择 or 单时间选择\n\t\t\tshowDropdowns:true,         // 年月 选择条件是否为下拉框\n\t\t\ttimePicker: true,\n\t\t\ttimePicker24Hour: true,\n\t\t\ttimePickerSeconds: true,\t// 时间选择是否显示秒\n\t\t\topens : 'left', \t\t\t// 日期选择框的弹出位置\n\t\t\tranges: rangesConf,\n\t\t\tlocale : {\n\t\t\t\tformat: 'YYYY-MM-DD HH:mm:ss',\n\t\t\t\tseparator : ' - ',\n\t\t\t\tcustomRangeLabel : I18n.daterangepicker_custom_name ,\n\t\t\t\tapplyLabel : I18n.system_ok ,\n\t\t\t\tcancelLabel : I18n.system_cancel ,\n\t\t\t\tfromLabel : I18n.daterangepicker_custom_starttime ,\n\t\t\t\ttoLabel : I18n.daterangepicker_custom_endtime ,\n\t\t\t\tdaysOfWeek : I18n.daterangepicker_custom_daysofweek.split(',') ,        // '日', '一', '二', '三', '四', '五', '六'\n\t\t\t\tmonthNames : I18n.daterangepicker_custom_monthnames.split(',') ,        // '一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'\n\t\t\t\tfirstDay : 1\n\t\t\t}/*,\n\t\t\tstartDate: rangesConf[I18n.daterangepicker_ranges_today][0],\n\t\t\tendDate: rangesConf[I18n.daterangepicker_ranges_today][1]*/\n\t\t});\n\n\t\t// init filter\n\t\tvar jobGroup = '${jobGroup}';\n\t\tvar jobId = '${jobId}';\n\t\tfunction resetFilter(){\n\t\t\t$('#filterTime').data(\"daterangepicker\").setStartDate( rangesConf[I18n.daterangepicker_ranges_recent_week][0] );\n\t\t\t$('#filterTime').data(\"daterangepicker\").setEndDate( rangesConf[I18n.daterangepicker_ranges_recent_week][1] );\n\n\t\t\t$(\"#jobGroup\").val( jobGroup );\n\t\t\t$(\"#jobId\").val( jobId );\n\t\t\t$('#logStatus').prop('selectedIndex', 0);\n\t\t}\n\t\tresetFilter();\n\n\t\t// ---------------------- page ----------------------\n\n\t\t/**\n\t\t * init table\n\t\t */\n\t\t$.adminTable.initTable({\n\t\t\ttable: '#data_list',\n\t\t\turl: base_url + \"/joblog/pageList\",\n\t\t\tqueryParams: function (params) {\n\t\t\t\tvar obj = {};\n\t\t\t\tobj.jobGroup = $('#jobGroup').val();\n\t\t\t\tobj.jobId = $('#jobId').val();\n\t\t\t\tobj.logStatus = $('#logStatus').val();\n\t\t\t\tobj.filterTime = $('#filterTime').val();\n\t\t\t\tobj.offset = params.offset;\n\t\t\t\tobj.pagesize = params.limit;\n\t\t\t\treturn obj;\n\t\t\t},\n\t\t\tresetHandler : function() {\n\t\t\t\t// reset filter\n\t\t\t\tresetFilter();\n\t\t\t},\n\t\t\tcolumns:[\n\t\t\t\t{\n\t\t\t\t\tcheckbox: true,\n\t\t\t\t\tfield: 'state',\n\t\t\t\t\twidth: '5',\n\t\t\t\t\twidthUnit: '%',\n\t\t\t\t\talign: 'center',\n\t\t\t\t\tvalign: 'middle'\n\t\t\t\t},\n                {\n                    title: I18n.joblog_name + 'ID',\n                    field: 'id',\n                    width: '10',\n                    widthUnit: '%',\n                    align: 'left'\n                },\n                {\n\t\t\t\t\ttitle: I18n.jobinfo_job,\n\t\t\t\t\tfield: 'jobId',\n\t\t\t\t\twidth: '15',\n\t\t\t\t\twidthUnit: '%',\n\t\t\t\t\talign: 'left',\n\t\t\t\t\tformatter: function(value, row, index) {\n                        // build\n                        let jobShow = '【'+ row.jobId +'】';\n                        let jobDesc = $(\"#jobId\").find(\"option[value='\"+ row.jobId +\"']\").text();\n                        if (jobDesc) {\n                            jobShow += jobDesc;\n                        }\n                        if (jobShow.length > 10) {\n                            jobShow = jobShow.substr(0, 10) + '...';\n                        }\n\t\t\t\t\t\t// show\n\t\t\t\t\t\treturn jobShow;\n\t\t\t\t\t}\n\t\t\t\t},{\n\t\t\t\t\ttitle: I18n.joblog_field_triggerTime,\n\t\t\t\t\tfield: 'triggerTime',\n\t\t\t\t\twidth: '15',\n\t\t\t\t\twidthUnit: '%',\n\t\t\t\t\tformatter: function(value, row, index) {\n\t\t\t\t\t\treturn value?moment(value).format(\"YYYY-MM-DD HH:mm:ss\"):\"\";\n\t\t\t\t\t}\n\t\t\t\t},{\n\t\t\t\t\ttitle: I18n.joblog_field_triggerCode,\n\t\t\t\t\tfield: 'triggerCode',\n\t\t\t\t\twidth: '10',\n\t\t\t\t\twidthUnit: '%',\n\t\t\t\t\tformatter: function(value, row, index) {\n\t\t\t\t\t\tvar html = value;\n\t\t\t\t\t\tif (value == 200) {\t\t\t// 200, success\n\t\t\t\t\t\t\thtml = '<span style=\"color: green\">'+ I18n.system_success +'</span>';\n\t\t\t\t\t\t} else if (value > 0) {\t\t// >0 or 500, fail\n\t\t\t\t\t\t\thtml = '<span style=\"color: red\">'+ I18n.system_fail +'</span>';\n\t\t\t\t\t\t} else if (value == 0) {\t\t// 0, original pass\n\t\t\t\t\t\t\thtml = '';\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn html;\n\t\t\t\t\t}\n\t\t\t\t},{\n\t\t\t\t\ttitle: I18n.joblog_field_triggerMsg,\n\t\t\t\t\tfield: 'triggerMsg',\n\t\t\t\t\twidth: '10',\n\t\t\t\t\twidthUnit: '%',\n\t\t\t\t\tformatter: function(value, row, index) {\n\t\t\t\t\t\treturn value?'<a class=\"logTips\" href=\"javascript:;\" >'+ I18n.system_show +'<span style=\"display:none;\">'+ value +'</span></a>':I18n.system_empty;\n\t\t\t\t\t}\n\t\t\t\t},{\n\t\t\t\t\ttitle: I18n.joblog_field_handleTime,\n\t\t\t\t\tfield: 'handleTime',\n\t\t\t\t\twidth: '15',\n\t\t\t\t\twidthUnit: '%',\n\t\t\t\t\tformatter: function(value, row, index) {\n\t\t\t\t\t\treturn value?moment(value).format(\"YYYY-MM-DD HH:mm:ss\"):\"\";\n\t\t\t\t\t}\n\t\t\t\t},{\n\t\t\t\t\ttitle: I18n.joblog_field_handleCode,\n\t\t\t\t\tfield: 'handleCode',\n\t\t\t\t\twidth: '10',\n\t\t\t\t\twidthUnit: '%',\n\t\t\t\t\tformatter: function(value, row, index) {\n\t\t\t\t\t\tvar html = value;\n\t\t\t\t\t\tif (value == 200) {\t\t\t// 200, success\n\t\t\t\t\t\t\thtml = '<span style=\"color: green\">'+ I18n.joblog_handleCode_200 +'</span>';\n\t\t\t\t\t\t} else if (value == 502) {\t// 502, timeout\n\t\t\t\t\t\t\thtml = '<span style=\"color: red\">'+ I18n.joblog_handleCode_502 +'</span>';\n\t\t\t\t\t\t} else if (value > 0) {\t\t// >0 or 500, fail\n\t\t\t\t\t\t\thtml = '<span style=\"color: red\">'+ I18n.joblog_handleCode_500 +'</span>';\n\t\t\t\t\t\t} else if (value == 0) {\t\t// 0, original pass\n\t\t\t\t\t\t\thtml = '';\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn html;\n\t\t\t\t\t}\n\t\t\t\t},{\n\t\t\t\t\ttitle: I18n.joblog_field_handleMsg,\n\t\t\t\t\tfield: 'handleMsg',\n\t\t\t\t\twidth: '10',\n\t\t\t\t\twidthUnit: '%',\n\t\t\t\t\tformatter: function(value, row, index) {\n\t\t\t\t\t\treturn value?'<a class=\"logTips\" href=\"javascript:;\" >'+ I18n.system_show +'<span style=\"display:none;\">'+ value +'</span></a>':I18n.system_empty;\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 * logDetail\n\t\t */\n\t\t$(\"#data_operation\").on('click', '.logDetail',function() {\n\t\t\t// get select rows\n\t\t\tvar rows = $.adminTable.table.bootstrapTable('getSelections');\n\n\t\t\t// find select row\n\t\t\tif (rows.length !== 1) {\n\t\t\t\tlayer.msg(I18n.system_please_choose + I18n.system_one + I18n.system_data);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tvar row = rows[0];\n\n\t\t\twindow.open(base_url + '/joblog/logDetailPage?id=' + row.id);\n\t\t});\n\n\t\t/**\n\t\t * log Kill\n\t\t */\n\t\t$('#data_operation').on('click', '.logKill', function(){\n\t\t\t// get select rows\n\t\t\tvar rows = $.adminTable.table.bootstrapTable('getSelections');\n\n\t\t\t// find select row\n\t\t\tif (rows.length !== 1) {\n\t\t\t\tlayer.msg(I18n.system_please_choose + I18n.system_one + I18n.system_data);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tvar row = rows[0];\n\n\t\t\t// do kill\n\t\t\tlayer.confirm( (I18n.system_ok + I18n.joblog_kill_log + '?'), {\n\t\t\t\ticon: 3,\n\t\t\t\ttitle: I18n.system_tips ,\n\t\t\t\tbtn: [ I18n.system_ok, I18n.system_cancel ]\n\t\t\t}, function(index){\n\t\t\t\tlayer.close(index);\n\n\t\t\t\t$.ajax({\n\t\t\t\t\ttype : 'POST',\n\t\t\t\t\turl : base_url + '/joblog/logKill',\n\t\t\t\t\tdata : {\n\t\t\t\t\t\t\"id\": row.id\n\t\t\t\t\t},\n\t\t\t\t\tdataType : \"json\",\n\t\t\t\t\tsuccess : function(data){\n\t\t\t\t\t\tif (data.code == 200) {\n\t\t\t\t\t\t\tlayer.open({\n\t\t\t\t\t\t\t\ttitle: I18n.system_tips,\n\t\t\t\t\t\t\t\tbtn: [ I18n.system_ok ],\n\t\t\t\t\t\t\t\tcontent: I18n.system_opt_suc ,\n\t\t\t\t\t\t\t\ticon: '1',\n\t\t\t\t\t\t\t\tend: function(layero, index){\n\t\t\t\t\t\t\t\t\t// refresh table\n\t\t\t\t\t\t\t\t\t$('#data_filter .searchBtn').click();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tlayer.open({\n\t\t\t\t\t\t\t\ttitle: I18n.system_tips,\n\t\t\t\t\t\t\t\tbtn: [ I18n.system_ok ],\n\t\t\t\t\t\t\t\tcontent: (data.msg || I18n.system_opt_fail ),\n\t\t\t\t\t\t\t\ticon: '2'\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});\n\n\t\t/**\n\t\t * clear Log\n\t\t */\n\t\t$('#data_operation').on('click', '.clearLog', function(){\n\n\t\t\tvar jobGroup = $('#jobGroup').val();\n\t\t\tvar jobId = $('#jobId').val();\n\n\t\t\tvar jobGroupText = $(\"#jobGroup\").find(\"option:selected\").text();\n\t\t\tvar jobIdText = $(\"#jobId\").find(\"option:selected\").text();\n\n\t\t\t$('#clearLogModal input[name=jobGroup]').val(jobGroup);\n\t\t\t$('#clearLogModal input[name=jobId]').val(jobId);\n\n\t\t\t$('#clearLogModal .jobGroupText').val(jobGroupText);\n\t\t\t$('#clearLogModal .jobIdText').val(jobIdText);\n\n\t\t\t$('#clearLogModal').modal('show');\n\n\t\t});\n\t\t$(\"#clearLogModal .ok\").on('click', function(){\n\t\t\t$.post(base_url + \"/joblog/clearLog\",  $(\"#clearLogModal .form\").serialize(), function(data, status) {\n\t\t\t\tif (data.code == \"200\") {\n\t\t\t\t\t$('#clearLogModal').modal('hide');\n\t\t\t\t\tlayer.open({\n\t\t\t\t\t\ttitle: I18n.system_tips ,\n\t\t\t\t\t\tbtn: [ I18n.system_ok ],\n\t\t\t\t\t\tcontent: (I18n.joblog_clean_log + I18n.system_success) ,\n\t\t\t\t\t\ticon: '1',\n\t\t\t\t\t\tend: function(layero, index){\n\t\t\t\t\t\t\t// refresh table\n\t\t\t\t\t\t\t$('#data_filter .searchBtn').click();\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\tlayer.open({\n\t\t\t\t\t\ttitle: I18n.system_tips ,\n\t\t\t\t\t\tbtn: [ I18n.system_ok ],\n\t\t\t\t\t\tcontent: (data.msg || (I18n.joblog_clean_log + I18n.system_fail) ),\n\t\t\t\t\t\ticon: '2'\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t\t$(\"#clearLogModal\").on('hide.bs.modal', function () {\n\t\t\t$(\"#clearLogModal .form\")[0].reset();\n\t\t});\n\n\t\t// ---------------------- ComAlertTec ----------------------\n\n\t\t/**\n\t\t * logTips alert\n\t\t */\n\t\t$('body').on('click', '.logTips', function(){\n\t\t\tvar msg = $(this).find('span').html();\n\t\t\tComAlertTec.show(msg);\n\t\t});\n\n\t\t// Com Alert by Tec theme\n\t\tvar ComAlertTec = {\n\t\t\thtml:function(){\n\t\t\t\tvar html =\n\t\t\t\t\t\t'<div class=\"modal fade\" id=\"ComAlertTec\" tabindex=\"-1\" role=\"dialog\" aria-labelledby=\"myModalLabel\" aria-hidden=\"true\">' +\n\t\t\t\t\t\t'\t<div class=\"modal-dialog modal-lg-\">' +\n\t\t\t\t\t\t'\t\t<div class=\"modal-content-tec\">' +\n\t\t\t\t\t\t'\t\t\t<div class=\"modal-body\">' +\n\t\t\t\t\t\t'\t\t\t\t<div class=\"alert\" style=\"color:#fff;word-wrap: break-word;\">' +\n\t\t\t\t\t\t'\t\t\t\t</div>' +\n\t\t\t\t\t\t'\t\t\t</div>' +\n\t\t\t\t\t\t'\t\t\t\t<div class=\"modal-footer\">' +\n\t\t\t\t\t\t'\t\t\t\t<div class=\"text-center\" >' +\n\t\t\t\t\t\t'\t\t\t\t\t<button type=\"button\" class=\"btn btn-info ok\" data-dismiss=\"modal\" >'+ I18n.system_ok +'</button>' +\n\t\t\t\t\t\t'\t\t\t\t</div>' +\n\t\t\t\t\t\t'\t\t\t</div>' +\n\t\t\t\t\t\t'\t\t</div>' +\n\t\t\t\t\t\t'\t</div>' +\n\t\t\t\t\t\t'</div>';\n\t\t\t\treturn html;\n\t\t\t},\n\t\t\tshow:function(msg, callback){\n\t\t\t\t// dom init\n\t\t\t\tif ($('#ComAlertTec').length == 0){\n\t\t\t\t\t$('body').append(ComAlertTec.html());\n\t\t\t\t}\n\n\t\t\t\t// init com alert\n\t\t\t\t$('#ComAlertTec .alert').html(msg);\n\t\t\t\t$('#ComAlertTec').modal('show');\n\n\t\t\t\t$('#ComAlertTec .ok').click(function(){\n\t\t\t\t\t$('#ComAlertTec').modal('hide');\n\t\t\t\t\tif(typeof callback == 'function') {\n\t\t\t\t\t\tcallback();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t};\n\n\t});\n</script>\n<!-- 3-script end -->\n\n</body>\n</html>"
  },
  {
    "path": "xxl-job-admin/src/main/resources/templates/biz/user.list.ftl",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n\t<#-- import macro -->\n\t<#import \"../common/common.macro.ftl\" as netCommon>\n\n\t<!-- 1-style start -->\n\t<@netCommon.commonStyle />\n\t<link rel=\"stylesheet\" href=\"${request.contextPath}/static/plugins/bootstrap-table/bootstrap-table.min.css\">\n\t<link rel=\"stylesheet\" href=\"${request.contextPath}/static/adminlte/plugins/iCheck/square/blue.css\">\n\t<!-- 1-style end -->\n\n</head>\n<body class=\"hold-transition\" style=\"background-color: #ecf0f5;\">\n<div class=\"wrapper\">\n\t<section class=\"content\">\n\n\t\t<!-- 2-content start -->\n\n\t\t<#-- 查询区域 -->\n\t\t<div class=\"box\" style=\"margin-bottom:9px;\">\n\t\t\t<div class=\"box-body\">\n\t\t\t\t<div class=\"row\" id=\"data_filter\" >\n\n\t\t\t\t\t<div class=\"col-xs-3\">\n\t\t\t\t\t\t<div class=\"input-group\">\n\t\t\t\t\t\t\t<span class=\"input-group-addon\">${I18n.user_role}</span>\n\t\t\t\t\t\t\t<select class=\"form-control\" id=\"role\" >\n\t\t\t\t\t\t\t\t<option value=\"-1\" >${I18n.system_all}</option>\n\t\t\t\t\t\t\t\t<option value=\"1\" >${I18n.user_role_admin}</option>\n\t\t\t\t\t\t\t\t<option value=\"0\" >${I18n.user_role_normal}</option>\n\t\t\t\t\t\t\t</select>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"col-xs-3\">\n\t\t\t\t\t\t<div class=\"input-group\">\n\t\t\t\t\t\t\t<span class=\"input-group-addon\">${I18n.user_username}</span>\n\t\t\t\t\t\t\t<input type=\"text\" class=\"form-control\" id=\"username\" autocomplete=\"on\" >\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div class=\"col-xs-1\">\n\t\t\t\t\t\t<button class=\"btn btn-block btn-primary searchBtn\" >${I18n.system_search}</button>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"col-xs-1\">\n\t\t\t\t\t\t<button class=\"btn btn-block btn-default resetBtn\" >${I18n.system_reset}</button>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<#-- 数据表格区域 -->\n\t\t<div class=\"row\">\n\t\t\t<div class=\"col-xs-12\">\n\t\t\t\t<div class=\"box\">\n\t\t\t\t\t<div class=\"box-header pull-left\" id=\"data_operation\" >\n\t\t\t\t\t\t<button class=\"btn btn-sm btn-info add\" type=\"button\"><i class=\"fa fa-plus\" ></i>${I18n.system_opt_add}</button>\n\t\t\t\t\t\t<button class=\"btn btn-sm btn-warning selectOnlyOne update\" type=\"button\"><i class=\"fa fa-edit\"></i>${I18n.system_opt_edit}</button>\n\t\t\t\t\t\t<button class=\"btn btn-sm btn-danger selectAny delete\" type=\"button\"><i class=\"fa fa-remove \"></i>${I18n.system_opt_del}</button>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"box-body\" >\n\t\t\t\t\t\t<table id=\"data_list\" class=\"table table-bordered table-striped\" width=\"100%\" >\n\t\t\t\t\t\t\t<thead></thead>\n\t\t\t\t\t\t\t<tbody></tbody>\n\t\t\t\t\t\t\t<tfoot></tfoot>\n\t\t\t\t\t\t</table>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<!-- 新增.模态框 -->\n\t\t<div class=\"modal fade\" id=\"addModal\" tabindex=\"-1\" role=\"dialog\"  aria-hidden=\"true\">\n\t\t\t<div class=\"modal-dialog\">\n\t\t\t\t<div class=\"modal-content\">\n\t\t\t\t\t<div class=\"modal-header\">\n\t\t\t\t\t\t<h4 class=\"modal-title\" >${I18n.user_add}</h4>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"modal-body\">\n\t\t\t\t\t\t<form class=\"form-horizontal form\" role=\"form\" >\n\t\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t\t<label for=\"lastname\" class=\"col-sm-2 control-label\">${I18n.user_username}<font color=\"red\">*</font></label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-8\"><input type=\"text\" class=\"form-control\" name=\"username\" placeholder=\"${I18n.system_please_input}${I18n.user_username}\" maxlength=\"20\" ></div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t\t<label for=\"lastname\" class=\"col-sm-2 control-label\">${I18n.user_password}<font color=\"red\">*</font></label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-8\"><input type=\"text\" class=\"form-control\" name=\"password\" placeholder=\"${I18n.system_please_input}${I18n.user_password}\" maxlength=\"20\" ></div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t\t<label for=\"lastname\" class=\"col-sm-2 control-label\">${I18n.user_role}<font color=\"red\">*</font></label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-10\">\n\t\t\t\t\t\t\t\t\t<input type=\"radio\" name=\"role\" value=\"0\" checked />${I18n.user_role_normal}\n\t\t\t\t\t\t\t\t\t&nbsp;&nbsp;&nbsp;&nbsp;\n\t\t\t\t\t\t\t\t\t<input type=\"radio\" name=\"role\" value=\"1\" />${I18n.user_role_admin}\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t\t<label for=\"lastname\" class=\"col-sm-2 control-label\">${I18n.user_permission}<font color=\"black\">*</font></label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-10\">\n\t\t\t\t\t\t\t\t\t<#if groupList?exists && groupList?size gt 0>\n\t\t\t\t\t\t\t\t\t\t<#list groupList as item>\n\t\t\t\t\t\t\t\t\t\t\t<input type=\"checkbox\" name=\"permission\" value=\"${item.id}\" />&nbsp;&nbsp;${item.title}：${item.appname}\n\t\t\t\t\t\t\t\t\t\t\t<br>\n\t\t\t\t\t\t\t\t\t\t</#list>\n\t\t\t\t\t\t\t\t\t</#if>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t\t<hr>\n\t\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t\t<div class=\"col-sm-offset-3 col-sm-6\">\n\t\t\t\t\t\t\t\t\t<button type=\"submit\" class=\"btn btn-primary\"  >${I18n.system_save}</button>\n\t\t\t\t\t\t\t\t\t<button type=\"button\" class=\"btn btn-default\" data-dismiss=\"modal\">${I18n.system_cancel}</button>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t</form>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<!-- 更新.模态框 -->\n\t\t<div class=\"modal fade\" id=\"updateModal\" tabindex=\"-1\" role=\"dialog\"  aria-hidden=\"true\">\n\t\t\t<div class=\"modal-dialog\">\n\t\t\t\t<div class=\"modal-content\">\n\t\t\t\t\t<div class=\"modal-header\">\n\t\t\t\t\t\t<h4 class=\"modal-title\" >${I18n.user_update}</h4>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"modal-body\">\n\t\t\t\t\t\t<form class=\"form-horizontal form\" role=\"form\" >\n\t\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t\t<label for=\"lastname\" class=\"col-sm-2 control-label\">${I18n.user_username}<font color=\"red\">*</font></label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-8\"><input type=\"text\" class=\"form-control\" name=\"username\" placeholder=\"${I18n.system_please_input}${I18n.user_username}\" maxlength=\"20\" readonly ></div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t\t<label for=\"lastname\" class=\"col-sm-2 control-label\">${I18n.user_password}<font color=\"red\">*</font></label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-8\"><input type=\"text\" class=\"form-control\" name=\"password\" placeholder=\"${I18n.user_password_update_placeholder}\" maxlength=\"20\" ></div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t\t<label for=\"lastname\" class=\"col-sm-2 control-label\">${I18n.user_role}<font color=\"red\">*</font></label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-10\">\n\t\t\t\t\t\t\t\t\t<input type=\"radio\" name=\"role\" value=\"0\" />${I18n.user_role_normal}\n\t\t\t\t\t\t\t\t\t&nbsp;&nbsp;&nbsp;&nbsp;\n\t\t\t\t\t\t\t\t\t<input type=\"radio\" name=\"role\" value=\"1\" />${I18n.user_role_admin}\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t\t<label for=\"lastname\" class=\"col-sm-2 control-label\">${I18n.user_permission}<font color=\"black\">*</font></label>\n\t\t\t\t\t\t\t\t<div class=\"col-sm-10\">\n\t\t\t\t\t\t\t\t\t<#if groupList?exists && groupList?size gt 0>\n\t\t\t\t\t\t\t\t\t\t<#list groupList as item>\n\t\t\t\t\t\t\t\t\t\t\t<input type=\"checkbox\" name=\"permission\" value=\"${item.id}\" />${item.title}(${item.appname})<br>\n\t\t\t\t\t\t\t\t\t\t</#list>\n\t\t\t\t\t\t\t\t\t</#if>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t\t<hr>\n\t\t\t\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t\t\t\t<div class=\"col-sm-offset-3 col-sm-6\">\n\t\t\t\t\t\t\t\t\t<button type=\"submit\" class=\"btn btn-primary\"  >${I18n.system_save}</button>\n\t\t\t\t\t\t\t\t\t<button type=\"button\" class=\"btn btn-default\" data-dismiss=\"modal\">${I18n.system_cancel}</button>\n\t\t\t\t\t\t\t\t\t<input type=\"hidden\" name=\"id\" >\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t</form>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<!-- 2-content end -->\n\n\t</section>\n</div>\n\n<!-- 3-script start -->\n<@netCommon.commonScript />\n<script src=\"${request.contextPath}/static/plugins/bootstrap-table/bootstrap-table.min.js\"></script>\n<script src=\"${request.contextPath}/static/plugins/bootstrap-table/locale/<#if I18n.admin_i18n?? && I18n.admin_i18n == 'en'>bootstrap-table-en-US.min.js<#else>bootstrap-table-zh-CN.min.js</#if>\"></script>\n<script src=\"${request.contextPath}/static/adminlte/plugins/iCheck/icheck.min.js\"></script>\n<#-- admin table -->\n<script src=\"${request.contextPath}/static/biz/common/admin.table.js\"></script>\n<script>\n\t$(function() {\n\n\t\t/**\n\t\t * init table\n\t\t */\n\t\t$.adminTable.initTable({\n\t\t\ttable: '#data_list',\n\t\t\turl: base_url + \"/user/pageList\",\n\t\t\tqueryParams: function (params) {\n\t\t\t\tvar obj = {};\n\t\t\t\tobj.username = $('#username').val();\n\t\t\t\tobj.role = $('#role').val();\n\t\t\t\tobj.offset = params.offset;\n\t\t\t\tobj.pagesize = params.limit;\n\t\t\t\treturn obj;\n\t\t\t},\n\t\t\tcolumns:[\n\t\t\t\t{\n\t\t\t\t\tcheckbox: true,\n\t\t\t\t\tfield: 'state',\n\t\t\t\t\twidth: '5',\n\t\t\t\t\twidthUnit: '%',\n\t\t\t\t\talign: 'center',\n\t\t\t\t\tvalign: 'middle'\n\t\t\t\t},{\n\t\t\t\t\ttitle: I18n.user_username,\n\t\t\t\t\tfield: 'username',\n\t\t\t\t\twidth: '20',\n\t\t\t\t\twidthUnit: '%',\n\t\t\t\t\talign: 'left'\n\t\t\t\t},{\n\t\t\t\t\ttitle: I18n.user_password,\n\t\t\t\t\tfield: 'password',\n\t\t\t\t\twidth: '20',\n\t\t\t\t\twidthUnit: '%',\n\t\t\t\t\tformatter: function(value, row, index) {\n\t\t\t\t\t\treturn '******';\n\t\t\t\t\t}\n\t\t\t\t},{\n\t\t\t\t\ttitle: I18n.user_role,\n\t\t\t\t\tfield: 'role',\n\t\t\t\t\twidth: '10',\n\t\t\t\t\twidthUnit: '%',\n\t\t\t\t\tformatter: function(value, row, index) {\n\t\t\t\t\t\tlet result = value;\n\t\t\t\t\t\t$('#data_filter #role option').each(function(){\n\t\t\t\t\t\t\tif ( value+\"\" === $(this).val() ) {\n\t\t\t\t\t\t\t\tresult = $(this).text();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t\treturn result;\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 * init delete\n\t\t */\n\t\t$.adminTable.initDelete({\n\t\t\turl: base_url + \"/user/delete\"\n\t\t});\n\n\t\t/**\n\t\t * init add\n\t\t */\n\t\t// add validator method\n\t\tjQuery.validator.addMethod(\"myValid01\", function(value, element) {\n\t\t\tvar length = value.length;\n\t\t\tvar valid = /^[a-z][a-z0-9]*$/;\n\t\t\treturn this.optional(element) || valid.test(value);\n\t\t}, I18n.user_username_valid );\n\t\t$.adminTable.initAdd( {\n\t\t\turl: base_url + \"/user/insert\",\n\t\t\trules : {\n\t\t\t\tusername : {\n\t\t\t\t\trequired : true,\n\t\t\t\t\trangelength:[4, 20],\n\t\t\t\t\tmyValid01: true\n\t\t\t\t},\n\t\t\t\tpassword : {\n\t\t\t\t\trequired : true,\n\t\t\t\t\trangelength:[4, 20]\n\t\t\t\t}\n\t\t\t},\n\t\t\tmessages : {\n\t\t\t\tusername : {\n\t\t\t\t\trequired : I18n.system_please_input + I18n.user_username,\n\t\t\t\t\trangelength: I18n.system_lengh_limit + \"[4-20]\"\n\t\t\t\t},\n\t\t\t\tpassword : {\n\t\t\t\t\trequired : I18n.system_please_input + I18n.user_password,\n\t\t\t\t\trangelength: I18n.system_lengh_limit + \"[4-20]\"\n\t\t\t\t}\n\t\t\t},\n\t\t\twriteFormData: function() {\n\t\t\t\t$(\"#addModal .form input[name='role'][value='0']\").change();\n\t\t\t},\n\t\t\treadFormData: function() {\n\t\t\t\t// request\n\t\t\t\treturn $(\"#addModal .form\").serializeArray();\n\t\t\t}\n\t\t});\n\n\t\t// add role\n\t\t$(\"#addModal .form input[name=role]\").change(function () {\n\t\t\tvar role = $(this).val();\n\t\t\tif (role == 1) {\n\t\t\t\t$(\"#addModal .form input[name=permission]\").parents('.form-group').hide();\n\t\t\t} else {\n\t\t\t\t$(\"#addModal .form input[name=permission]\").parents('.form-group').show();\n\t\t\t}\n\t\t\t$(\"#addModal .form input[name='permission']\").prop(\"checked\",false);\n\t\t});\n\n\t\t/**\n\t\t * init update\n\t\t */\n\t\t$.adminTable.initUpdate( {\n\t\t\turl: base_url + \"/user/update\",\n\t\t\twriteFormData: function(row) {\n\n\t\t\t\t// base data\n\t\t\t\t$(\"#updateModal .form input[name='id']\").val( row.id );\n\t\t\t\t$(\"#updateModal .form input[name='username']\").val( row.username );\n\t\t\t\t$(\"#updateModal .form input[name='password']\").val( '' );\n\t\t\t\t$(\"#updateModal .form input[name='role'][value='\"+ row.role +\"']\").click();\n\t\t\t\tvar permissionArr = [];\n\t\t\t\tif (row.permission) {\n\t\t\t\t\tpermissionArr = row.permission.split(\",\");\n\t\t\t\t}\n\t\t\t\t$(\"#updateModal .form input[name='permission']\").each(function () {\n\t\t\t\t\tif($.inArray($(this).val(), permissionArr) > -1) {\n\t\t\t\t\t\t$(this).prop(\"checked\",true);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t$(this).prop(\"checked\",false);\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t},\n\t\t\treadFormData: function() {\n\t\t\t\t// request\n\t\t\t\treturn $(\"#updateModal .form\").serializeArray();\n\t\t\t}\n\t\t});\n\n\t\t// update role\n\t\t$(\"#updateModal .form input[name=role]\").change(function () {\n\t\t\tvar role = $(this).val();\n\t\t\tif (role == 1) {\n\t\t\t\t$(\"#updateModal .form input[name=permission]\").parents('.form-group').hide();\n\t\t\t} else {\n\t\t\t\t$(\"#updateModal .form input[name=permission]\").parents('.form-group').show();\n\t\t\t}\n\t\t\t$(\"#updateModal .form input[name='permission']\").prop(\"checked\",false);\n\t\t});\n\n\t});\n\n</script>\n<!-- 3-script end -->\n\n</body>\n</html>"
  },
  {
    "path": "xxl-job-admin/src/main/resources/templates/common/common.errorpage.ftl",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n\t<#-- import macro -->\n\t<#import \"../common/common.macro.ftl\" as netCommon>\n\n\t<meta charset=\"UTF-8\">\n\t<title>Error</title>\n    <style type=\"text/css\"> \n        body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }\n        div.dialog {\n            width: 80%;\n            padding: 1em 4em;\n            margin: 4em auto 0 auto;\n            border: 1px solid #ccc;\n            border-right-color: #999;\n            border-bottom-color: #999;\n        }\n        h1 { font-size: 100%; color: #f00; line-height: 1.5em; }\n    </style>\n    \n</head> \n</head>\n<body> \n\n\t<div class=\"dialog\"> \n\t    <h1>System Error</h1>\n\t\t<p><#if exceptionMsg?exists>${exceptionMsg}<#else>Unknown Error.</#if></p>\n\t\t<a href=\"javascript:window.location.href='${request.contextPath}/'\" id=\"go_back\" >Back</a>\n\t    </p> \n\t</div>\n\n<!-- 3-script start -->\n<script src=\"${request.contextPath}/static/adminlte/bower_components/jquery/jquery.min.js\"></script>\n<script src=\"${request.contextPath}/static/biz/common/admin.util.js\"></script>\n<script>\n\t$(function() {\n\t\tif (isOpenWithTab()) {\n\t\t\t$('#go_back').hide();\n\t\t}\n\t});\n</script>\n<!-- 3-script end -->\n\n</body>\n</html>"
  },
  {
    "path": "xxl-job-admin/src/main/resources/templates/common/common.macro.ftl",
    "content": "<#-- import: style -->\n<#macro commonStyle>\n\n<#-- i18n -->\n<#global I18n = I18nUtil.getMultString()?eval />\n<#-- title、favicon、meta -->\n<title>${I18n.admin_name_full}</title>\n<link rel=\"icon\" href=\"${request.contextPath}/static/favicon.ico\" />\n<meta charset=\"utf-8\">\n<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n<meta content=\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\" name=\"viewport\">\n<#-- css -->\n<link rel=\"stylesheet\" href=\"${request.contextPath}/static/adminlte/bower_components/bootstrap/css/bootstrap.min.css\">\n<link rel=\"stylesheet\" href=\"${request.contextPath}/static/adminlte/bower_components/font-awesome/css/font-awesome.min.css\">\n<link rel=\"stylesheet\" href=\"${request.contextPath}/static/adminlte/bower_components/Ionicons/css/ionicons.min.css\">\n<link rel=\"stylesheet\" href=\"${request.contextPath}/static/adminlte/dist/css/AdminLTE.min.css\">\n<link rel=\"stylesheet\" href=\"${request.contextPath}/static/adminlte/dist/css/skins/_all-skins.min.css\">\n<!--[if lt IE 9]>\n<script src=\"https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js\"></script>\n<script src=\"https://oss.maxcdn.com/respond/1.4.2/respond.min.js\"></script>\n<![endif]-->\n<link rel=\"stylesheet\" href=\"${request.contextPath}/static/plugins/nprogress/nprogress.css\">\n\n</#macro>\n\n<#-- import: script -->\n<#macro commonScript>\n\n<script src=\"${request.contextPath}/static/adminlte/bower_components/jquery/jquery.min.js\"></script>\n<script src=\"${request.contextPath}/static/adminlte/bower_components/bootstrap/js/bootstrap.min.js\"></script>\n<script src=\"${request.contextPath}/static/adminlte/dist/js/adminlte.min.js\"></script>\n<script src=\"${request.contextPath}/static/adminlte/bower_components/jquery-slimscroll/jquery.slimscroll.min.js\"></script>\n<script src=\"${request.contextPath}/static/adminlte/bower_components/fastclick/fastclick.js\"></script>\n<script src=\"${request.contextPath}/static/plugins/jquery/jquery.validate.min.js\"></script>\n<script src=\"${request.contextPath}/static/plugins/layer/layer.js\"></script>\n<script src=\"${request.contextPath}/static/plugins/nprogress/nprogress.js\"></script>\n<script src=\"${request.contextPath}/static/plugins/fullscreen/jquery.fullscreen.js\"></script>\n<script>\n\t// init page param\n\tvar base_url = '${request.contextPath}';\n\tvar I18n = ${I18nUtil.getMultString()};\n</script>\n\n</#macro>\n"
  },
  {
    "path": "xxl-job-admin/src/test/java/com/xxl/job/admin/controller/AbstractSpringMvcTest.java",
    "content": "package com.xxl.job.admin.controller;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.web.servlet.MockMvc;\nimport org.springframework.test.web.servlet.setup.MockMvcBuilders;\nimport org.springframework.web.context.WebApplicationContext;\n\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)\npublic class AbstractSpringMvcTest {\n\n  @Autowired\n  private WebApplicationContext applicationContext;\n  protected MockMvc mockMvc;\n\n  @BeforeEach\n  public void setup() {\n    this.mockMvc = MockMvcBuilders.webAppContextSetup(this.applicationContext).build();\n  }\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/test/java/com/xxl/job/admin/controller/JobInfoControllerTest.java",
    "content": "package com.xxl.job.admin.controller;\n\nimport com.xxl.sso.core.constant.Const;\nimport jakarta.servlet.http.Cookie;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.web.servlet.MvcResult;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\n\nimport static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;\n\npublic class JobInfoControllerTest extends AbstractSpringMvcTest {\n  private static Logger logger = LoggerFactory.getLogger(JobInfoControllerTest.class);\n\n  private Cookie cookie;\n\n  @BeforeEach\n  public void login() throws Exception {\n    MvcResult ret = mockMvc.perform(\n        post(\"/auth/doLogin\")\n            .contentType(MediaType.APPLICATION_FORM_URLENCODED)\n            .param(\"userName\", \"admin\")\n            .param(\"password\", \"123456\")\n    ).andReturn();\n    cookie = ret.getResponse().getCookie(Const.XXL_SSO_TOKEN);\n  }\n\n  @Test\n  public void testAdd() throws Exception {\n    MultiValueMap<String, String> parameters = new LinkedMultiValueMap<String, String>();\n    parameters.add(\"jobGroup\", \"1\");\n    parameters.add(\"triggerStatus\", \"-1\");\n\n    MvcResult ret = mockMvc.perform(\n        post(\"/jobinfo/pageList\")\n            .contentType(MediaType.APPLICATION_FORM_URLENCODED)\n            //.content(paramsJson)\n            .params(parameters)\n            .cookie(cookie)\n    ).andReturn();\n\n    logger.info(ret.getResponse().getContentAsString());\n  }\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/test/java/com/xxl/job/admin/core/util/CronExpressionTest.java",
    "content": "package com.xxl.job.admin.core.util;\n\nimport com.xxl.job.admin.scheduler.cron.CronExpression;\nimport com.xxl.tool.core.DateTool;\nimport org.junit.jupiter.api.Test;\n\nimport java.text.ParseException;\nimport java.util.Date;\n\npublic class CronExpressionTest {\n\n    @Test\n    public void shouldWriteValueAsString() throws ParseException {\n        CronExpression cronExpression = new CronExpression(\"0 0 0 ? * 1\");\n        Date lastTriggerTime = new Date();\n        for (int i = 0; i < 5; i++) {\n            Date nextTriggerTime = cronExpression.getNextValidTimeAfter(lastTriggerTime);\n            System.out.println(DateTool.formatDateTime(nextTriggerTime));\n\n            lastTriggerTime = nextTriggerTime;\n        }\n    }\n}\n"
  },
  {
    "path": "xxl-job-admin/src/test/java/com/xxl/job/admin/core/util/JacksonUtilTest.java",
    "content": "//package com.xxl.job.admin.core.util;\n//\n//import com.xxl.job.admin.util.JacksonUtil;\n//import org.junit.jupiter.api.Test;\n//\n//import java.util.HashMap;\n//import java.util.Map;\n//\n//import static com.xxl.job.admin.util.JacksonUtil.writeValueAsString;\n//import static org.junit.jupiter.api.Assertions.assertEquals;\n//\n//public class JacksonUtilTest {\n//\n//    @Test\n//    public void shouldWriteValueAsString() {\n//        //given\n//        Map<String, String> map = new HashMap<>();\n//        map.put(\"aaa\", \"111\");\n//        map.put(\"bbb\", \"222\");\n//\n//        //when\n//        String json = writeValueAsString(map);\n//\n//        //then\n//        assertEquals(json, \"{\\\"aaa\\\":\\\"111\\\",\\\"bbb\\\":\\\"222\\\"}\");\n//    }\n//\n//    @Test\n//    public void shouldReadValueAsObject() {\n//        //given\n//        String jsonString = \"{\\\"aaa\\\":\\\"111\\\",\\\"bbb\\\":\\\"222\\\"}\";\n//\n//        //when\n//        Map result = JacksonUtil.readValue(jsonString, Map.class);\n//\n//        //then\n//        assertEquals(result.get(\"aaa\"), \"111\");\n//        assertEquals(result.get(\"bbb\"),\"222\");\n//\n//    }\n//}\n"
  },
  {
    "path": "xxl-job-admin/src/test/java/com/xxl/job/admin/mapper/XxlJobGroupMapperTest.java",
    "content": "package com.xxl.job.admin.mapper;\n\nimport com.xxl.job.admin.model.XxlJobGroup;\nimport jakarta.annotation.Resource;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.boot.test.context.SpringBootTest;\n\nimport java.util.Date;\nimport java.util.List;\n\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)\npublic class XxlJobGroupMapperTest {\n\n    @Resource\n    private XxlJobGroupMapper xxlJobGroupMapper;\n\n    @Test\n    public void test(){\n        List<XxlJobGroup> list = xxlJobGroupMapper.findAll();\n\n        List<XxlJobGroup> list2 = xxlJobGroupMapper.findByAddressType(0);\n\n        XxlJobGroup group = new XxlJobGroup();\n        group.setAppname(\"setAppName\");\n        group.setTitle(\"setTitle\");\n        group.setAddressType(0);\n        group.setAddressList(\"setAddressList\");\n        group.setUpdateTime(new Date());\n\n        int ret = xxlJobGroupMapper.save(group);\n\n        XxlJobGroup group2 = xxlJobGroupMapper.load(group.getId());\n        group2.setAppname(\"setAppName2\");\n        group2.setTitle(\"setTitle2\");\n        group2.setAddressType(2);\n        group2.setAddressList(\"setAddressList2\");\n        group2.setUpdateTime(new Date());\n\n        int ret2 = xxlJobGroupMapper.update(group2);\n\n        int ret3 = xxlJobGroupMapper.remove(group.getId());\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/test/java/com/xxl/job/admin/mapper/XxlJobInfoMapperTest.java",
    "content": "package com.xxl.job.admin.mapper;\n\nimport com.xxl.job.admin.model.XxlJobInfo;\nimport com.xxl.job.admin.scheduler.misfire.MisfireStrategyEnum;\nimport com.xxl.job.admin.scheduler.type.ScheduleTypeEnum;\nimport jakarta.annotation.Resource;\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.boot.test.context.SpringBootTest;\n\nimport java.util.Date;\nimport java.util.List;\n\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)\npublic class XxlJobInfoMapperTest {\n\tprivate static Logger logger = LoggerFactory.getLogger(XxlJobInfoMapperTest.class);\n\t\n\t@Resource\n\tprivate XxlJobInfoMapper xxlJobInfoMapper;\n\t\n\t@Test\n\tpublic void pageList(){\n\t\tList<XxlJobInfo> list = xxlJobInfoMapper.pageList(0, 20, 0, -1, null, null, null);\n\t\tint list_count = xxlJobInfoMapper.pageListCount(0, 20, 0, -1, null, null, null);\n\n\t\tlogger.info(\"\", list);\n\t\tlogger.info(\"\", list_count);\n\n\t\tList<XxlJobInfo> list2 = xxlJobInfoMapper.getJobsByGroup(1);\n\t}\n\t\n\t@Test\n\tpublic void save_load(){\n\t\tXxlJobInfo info = new XxlJobInfo();\n\t\tinfo.setJobGroup(1);\n\t\tinfo.setJobDesc(\"desc\");\n\t\tinfo.setAuthor(\"setAuthor\");\n\t\tinfo.setAlarmEmail(\"setAlarmEmail\");\n\t\tinfo.setScheduleType(ScheduleTypeEnum.FIX_RATE.name());\n\t\tinfo.setScheduleConf(String.valueOf(33));\n\t\tinfo.setMisfireStrategy(MisfireStrategyEnum.DO_NOTHING.name());\n\t\tinfo.setExecutorRouteStrategy(\"setExecutorRouteStrategy\");\n\t\tinfo.setExecutorHandler(\"setExecutorHandler\");\n\t\tinfo.setExecutorParam(\"setExecutorParam\");\n\t\tinfo.setExecutorBlockStrategy(\"setExecutorBlockStrategy\");\n\t\tinfo.setGlueType(\"setGlueType\");\n\t\tinfo.setGlueSource(\"setGlueSource\");\n\t\tinfo.setGlueRemark(\"setGlueRemark\");\n\t\tinfo.setChildJobId(\"1\");\n\n\t\tinfo.setAddTime(new Date());\n\t\tinfo.setUpdateTime(new Date());\n\t\tinfo.setGlueUpdatetime(new Date());\n\n\t\tint count = xxlJobInfoMapper.save(info);\n\n\t\tXxlJobInfo info2 = xxlJobInfoMapper.loadById(info.getId());\n\t\tinfo.setScheduleType(ScheduleTypeEnum.FIX_RATE.name());\n\t\tinfo.setScheduleConf(String.valueOf(44));\n\t\tinfo.setMisfireStrategy(MisfireStrategyEnum.FIRE_ONCE_NOW.name());\n\t\tinfo2.setJobDesc(\"desc2\");\n\t\tinfo2.setAuthor(\"setAuthor2\");\n\t\tinfo2.setAlarmEmail(\"setAlarmEmail2\");\n\t\tinfo2.setExecutorRouteStrategy(\"setExecutorRouteStrategy2\");\n\t\tinfo2.setExecutorHandler(\"setExecutorHandler2\");\n\t\tinfo2.setExecutorParam(\"setExecutorParam2\");\n\t\tinfo2.setExecutorBlockStrategy(\"setExecutorBlockStrategy2\");\n\t\tinfo2.setGlueType(\"setGlueType2\");\n\t\tinfo2.setGlueSource(\"setGlueSource2\");\n\t\tinfo2.setGlueRemark(\"setGlueRemark2\");\n\t\tinfo2.setGlueUpdatetime(new Date());\n\t\tinfo2.setChildJobId(\"1\");\n\n\t\tinfo2.setUpdateTime(new Date());\n\t\tint item2 = xxlJobInfoMapper.update(info2);\n\n\t\txxlJobInfoMapper.delete(info2.getId());\n\n\t\tList<XxlJobInfo> list2 = xxlJobInfoMapper.getJobsByGroup(1);\n\n\t\tint ret3 = xxlJobInfoMapper.findAllCount();\n\n\t}\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/test/java/com/xxl/job/admin/mapper/XxlJobLogGlueMapperTest.java",
    "content": "package com.xxl.job.admin.mapper;\n\nimport com.xxl.job.admin.model.XxlJobLogGlue;\nimport jakarta.annotation.Resource;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.boot.test.context.SpringBootTest;\n\nimport java.util.Date;\nimport java.util.List;\n\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)\npublic class XxlJobLogGlueMapperTest {\n\n    @Resource\n    private XxlJobLogGlueMapper xxlJobLogGlueMapper;\n\n    @Test\n    public void test(){\n        XxlJobLogGlue logGlue = new XxlJobLogGlue();\n        logGlue.setJobId(1);\n        logGlue.setGlueType(\"1\");\n        logGlue.setGlueSource(\"1\");\n        logGlue.setGlueRemark(\"1\");\n\n        logGlue.setAddTime(new Date());\n        logGlue.setUpdateTime(new Date());\n        int ret = xxlJobLogGlueMapper.save(logGlue);\n\n        List<XxlJobLogGlue> list = xxlJobLogGlueMapper.findByJobId(1);\n\n        int ret2 = xxlJobLogGlueMapper.removeOld(1, 1);\n\n        int ret3 = xxlJobLogGlueMapper.deleteByJobId(1);\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/test/java/com/xxl/job/admin/mapper/XxlJobLogMapperTest.java",
    "content": "package com.xxl.job.admin.mapper;\n\nimport com.xxl.job.admin.model.XxlJobLog;\nimport jakarta.annotation.Resource;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.boot.test.context.SpringBootTest;\n\nimport java.util.Date;\nimport java.util.List;\n\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)\npublic class XxlJobLogMapperTest {\n\n    @Resource\n    private XxlJobLogMapper xxlJobLogMapper;\n\n    @Test\n    public void test(){\n        List<XxlJobLog> list = xxlJobLogMapper.pageList(0, 10, 1, 1, null, null, 1);\n        int list_count = xxlJobLogMapper.pageListCount(0, 10, 1, 1, null, null, 1);\n\n        XxlJobLog log = new XxlJobLog();\n        log.setJobGroup(1);\n        log.setJobId(1);\n\n        long ret1 = xxlJobLogMapper.save(log);\n        XxlJobLog dto = xxlJobLogMapper.load(log.getId());\n\n        log.setTriggerTime(new Date());\n        log.setTriggerCode(1);\n        log.setTriggerMsg(\"1\");\n        log.setExecutorAddress(\"1\");\n        log.setExecutorHandler(\"1\");\n        log.setExecutorParam(\"1\");\n        ret1 = xxlJobLogMapper.updateTriggerInfo(log);\n        dto = xxlJobLogMapper.load(log.getId());\n\n\n        log.setHandleTime(new Date());\n        log.setHandleCode(2);\n        log.setHandleMsg(\"2\");\n        ret1 = xxlJobLogMapper.updateHandleInfo(log);\n        dto = xxlJobLogMapper.load(log.getId());\n\n\n        List<Long> ret4 = xxlJobLogMapper.findClearLogIds(1, 1, new Date(), 100, 100);\n\n        int ret2 = xxlJobLogMapper.delete(log.getJobId());\n\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/test/java/com/xxl/job/admin/mapper/XxlJobLogReportMapperTest.java",
    "content": "package com.xxl.job.admin.mapper;\n\nimport com.xxl.job.admin.model.XxlJobLogReport;\nimport com.xxl.tool.core.DateTool;\nimport jakarta.annotation.Resource;\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.boot.test.context.SpringBootTest;\n\nimport java.util.Date;\n\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)\npublic class XxlJobLogReportMapperTest {\n    private static final Logger logger = LoggerFactory.getLogger(XxlJobLogMapperTest.class);\n\n    @Resource\n    private XxlJobLogReportMapper xxlJobLogReportMapper;\n\n    @Test\n    public void test(){\n\n        Date date = DateTool.parseDate(\"2025-10-01\");\n\n        XxlJobLogReport xxlJobLogReport = new XxlJobLogReport();\n        xxlJobLogReport.setTriggerDay(date);\n        xxlJobLogReport.setRunningCount(444);\n        xxlJobLogReport.setSucCount(555);\n        xxlJobLogReport.setFailCount(666);\n\n        int ret = xxlJobLogReportMapper.saveOrUpdate(xxlJobLogReport);\n        logger.info(\"ret:{}\", ret);\n    }\n}\n"
  },
  {
    "path": "xxl-job-admin/src/test/java/com/xxl/job/admin/mapper/XxlJobRegistryMapperTest.java",
    "content": "package com.xxl.job.admin.mapper;\n\nimport com.xxl.job.admin.model.XxlJobRegistry;\nimport com.xxl.job.core.constant.RegistType;\nimport jakarta.annotation.Resource;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.boot.test.context.SpringBootTest;\n\nimport java.util.Arrays;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\n\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)\npublic class XxlJobRegistryMapperTest {\n\n    @Resource\n    private XxlJobRegistryMapper xxlJobRegistryMapper;\n\n    @Test\n    public void test(){\n        int ret = xxlJobRegistryMapper.registrySaveOrUpdate(RegistType.EXECUTOR.name(), \"xxl-job-executor-z1\", \"v1\", new Date());\n        /*int ret = xxlJobRegistryDao.registryUpdate(\"g1\", \"k1\", \"v1\", new Date());\n        if (ret < 1) {\n            ret = xxlJobRegistryDao.registrySave(\"g1\", \"k1\", \"v1\", new Date());\n        }*/\n\n        List<XxlJobRegistry> list = xxlJobRegistryMapper.findAll(1, new Date());\n\n        int ret2 = xxlJobRegistryMapper.removeDead(Arrays.asList(1));\n    }\n\n    @Test\n    public void test2() throws InterruptedException {\n        for (int i = 0; i < 100; i++) {\n            new Thread(()->{\n                int ret = xxlJobRegistryMapper.registrySaveOrUpdate(\"g1\", \"k1\", \"v1\", new Date());\n                System.out.println(ret);\n\n                /*int ret = xxlJobRegistryDao.registryUpdate(\"g1\", \"k1\", \"v1\", new Date());\n                if (ret < 1) {\n                    ret = xxlJobRegistryDao.registrySave(\"g1\", \"k1\", \"v1\", new Date());\n                }*/\n            }).start();\n        }\n\n        TimeUnit.SECONDS.sleep(10);\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/test/java/com/xxl/job/admin/schedule/JobScheduleTest.java",
    "content": "package com.xxl.job.admin.schedule;\n\nimport com.xxl.job.admin.scheduler.config.XxlJobAdminBootstrap;\nimport com.xxl.tool.core.DateTool;\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.transaction.TransactionStatus;\nimport org.springframework.transaction.support.DefaultTransactionDefinition;\n\nimport java.util.Date;\nimport java.util.concurrent.TimeUnit;\n\n@SpringBootTest\npublic class JobScheduleTest {\n    private static Logger logger = LoggerFactory.getLogger(JobScheduleTest.class);\n\n    @Test\n    public void test() throws InterruptedException {\n\n        // thread\n        for (int i = 0; i < 10; i++) {\n            int finalI = i;\n            new Thread(() -> {\n                lockTest(\"threadName-\" + finalI);\n            }).start();\n        }\n\n        TimeUnit.MINUTES.sleep(10);\n    }\n\n    private void lockTest(String threadName) {\n\n        TransactionStatus transactionStatus = XxlJobAdminBootstrap.getInstance().getTransactionManager().getTransaction(new DefaultTransactionDefinition());\n        try {\n            String lockedRecord = XxlJobAdminBootstrap.getInstance().getXxlJobLockMapper().scheduleLock(); // for update\n\n            logger.info(threadName + \" : start at \" + DateTool.format(new Date(), \"yyyy-MM-dd HH:mm:ss SSS\") );\n            TimeUnit.MILLISECONDS.sleep(500);\n            logger.info(threadName + \" : end at \" + DateTool.format(new Date(), \"yyyy-MM-dd HH:mm:ss SSS\") );\n        } catch (Throwable e) {\n            logger.error(\"error: \",  e);\n        } finally {\n            logger.info(threadName + \" : commit at \" + DateTool.format(new Date(), \"yyyy-MM-dd HH:mm:ss SSS\") );\n            XxlJobAdminBootstrap.getInstance().getTransactionManager().commit(transactionStatus);\n        }\n    }\n}\n"
  },
  {
    "path": "xxl-job-admin/src/test/java/com/xxl/job/admin/util/I18nUtilTest.java",
    "content": "package com.xxl.job.admin.util;\n\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.boot.test.context.SpringBootTest;\n\n/**\n * email util test\n *\n * @author xuxueli 2017-12-22 17:16:23\n */\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)\npublic class I18nUtilTest {\n    private static Logger logger = LoggerFactory.getLogger(I18nUtilTest.class);\n\n    @Test\n    public void test(){\n        logger.info(I18nUtil.getString(\"admin_name\"));\n        logger.info(I18nUtil.getMultString(\"admin_name\", \"admin_name_full\"));\n        logger.info(I18nUtil.getMultString());\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/test/java/com/xxl/job/openapi/AdminBizTest.java",
    "content": "package com.xxl.job.openapi;\n\nimport com.xxl.job.core.constant.RegistType;\nimport com.xxl.job.core.openapi.AdminBiz;\nimport com.xxl.job.core.openapi.model.CallbackRequest;\nimport com.xxl.job.core.openapi.model.RegistryRequest;\nimport com.xxl.job.core.context.XxlJobContext;\nimport com.xxl.job.core.constant.Const;\nimport com.xxl.tool.http.HttpTool;\nimport com.xxl.tool.response.Response;\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.Arrays;\nimport java.util.List;\n\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * admin api test\n *\n * @author xuxueli 2017-07-28 22:14:52\n */\npublic class AdminBizTest {\n    private static final Logger logger = LoggerFactory.getLogger(AdminBizTest.class);\n\n    private static String addressUrl = \"http://127.0.0.1:8080/xxl-job-admin\";\n    private static String accessToken = \"default_token\";\n\n    private AdminBiz buildClient(){\n        String finalUrl = addressUrl + \"/api\";\n\n        return HttpTool.createClient()\n                .url(finalUrl)\n                .timeout(3 * 1000)\n                .header(Const.XXL_JOB_ACCESS_TOKEN, accessToken)\n                .proxy(AdminBiz.class);\n    }\n\n    @Test\n    public void callback() throws Exception {\n        AdminBiz adminBiz = buildClient();\n\n        CallbackRequest param = new CallbackRequest();\n        param.setLogId(1);\n        param.setHandleCode(XxlJobContext.HANDLE_CODE_SUCCESS);\n\n        List<CallbackRequest> callbackParamList = Arrays.asList(param);\n\n        Response<String> returnT = adminBiz.callback(callbackParamList);\n        assertTrue(returnT.isSuccess());\n    }\n\n    /**\n     * registry executor\n     *\n     * @throws Exception\n     */\n    @Test\n    public void registry() throws Exception {\n        AdminBiz adminBiz = buildClient();\n\n        RegistryRequest registryParam = new RegistryRequest(RegistType.EXECUTOR.name(), \"xxl-job-executor-example\", \"127.0.0.1:9999\");\n\n        Response<String> returnT = adminBiz.registry(registryParam);\n        assertTrue(returnT.isSuccess());\n    }\n\n    /**\n     * registry executor remove\n     *\n     * @throws Exception\n     */\n    @Test\n    public void registryRemove() throws Exception {\n        AdminBiz adminBiz = buildClient();\n\n        RegistryRequest registryParam = new RegistryRequest(RegistType.EXECUTOR.name(), \"xxl-job-executor-example\", \"127.0.0.1:9999\");\n\n        Response<String> returnT = adminBiz.registryRemove(registryParam);\n        assertTrue(returnT.isSuccess());\n\n    }\n\n    // ---------------------- job opt ----------------------\n\n    @Test\n    public void jobManage() throws Exception {\n        // jobAdd、jobUpdate、jobRemove、jobStart、jobStop\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-admin/src/test/java/com/xxl/job/openapi/ExecutorBizTest.java",
    "content": "package com.xxl.job.openapi;\n\nimport com.xxl.job.core.constant.Const;\nimport com.xxl.job.core.openapi.ExecutorBiz;\nimport com.xxl.job.core.openapi.model.*;\nimport com.xxl.job.core.constant.ExecutorBlockStrategyEnum;\nimport com.xxl.job.core.glue.GlueTypeEnum;\nimport com.xxl.tool.http.HttpTool;\nimport com.xxl.tool.response.Response;\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * executor api test\n *\n * Created by xuxueli on 17/5/12.\n */\npublic class ExecutorBizTest {\n    private static final Logger logger = LoggerFactory.getLogger(ExecutorBizTest.class);\n\n    private static String addressUrl = \"http://127.0.0.1:9999/\";\n    private static String accessToken = \"default_token\";\n\n    private ExecutorBiz buildClient(){\n        return HttpTool.createClient()\n                .url(addressUrl)\n                .timeout(3 * 1000)\n                .header(Const.XXL_JOB_ACCESS_TOKEN, accessToken)\n                .proxy(ExecutorBiz.class);\n    }\n\n    @Test\n    public void beat() throws Exception {\n        ExecutorBiz executorBiz = buildClient();\n        // Act\n        final Response<String> retval = executorBiz.beat();\n\n        // Assert result\n        Assertions.assertNotNull(retval);\n        Assertions.assertNull(((Response<String>) retval).getData());\n        Assertions.assertEquals(200, retval.getCode());\n        Assertions.assertNull(retval.getMsg());\n    }\n\n    @Test\n    public void idleBeat(){\n        ExecutorBiz executorBiz = buildClient();\n\n        final int jobId = 0;\n\n        // Act\n        final Response<String> retval = executorBiz.idleBeat(new IdleBeatRequest(jobId));\n\n        // Assert result\n        Assertions.assertNotNull(retval);\n        Assertions.assertNull(((Response<String>) retval).getData());\n        Assertions.assertEquals(500, retval.getCode());\n        Assertions.assertEquals(\"job thread is running or has trigger queue.\", retval.getMsg());\n    }\n\n    @Test\n    public void run(){\n        ExecutorBiz executorBiz = buildClient();\n\n        // trigger data\n        final TriggerRequest triggerParam = new TriggerRequest();\n        triggerParam.setJobId(1);\n        triggerParam.setExecutorHandler(\"demoJobHandler\");\n        triggerParam.setExecutorParams(null);\n        triggerParam.setExecutorBlockStrategy(ExecutorBlockStrategyEnum.COVER_EARLY.name());\n        triggerParam.setGlueType(GlueTypeEnum.BEAN.name());\n        triggerParam.setGlueSource(null);\n        triggerParam.setGlueUpdatetime(System.currentTimeMillis());\n        triggerParam.setLogId(1);\n        triggerParam.setLogDateTime(System.currentTimeMillis());\n\n        // Act\n        final Response<String> retval = executorBiz.run(triggerParam);\n\n        // Assert result\n        Assertions.assertNotNull(retval);\n\n    }\n\n    @Test\n    public void kill(){\n        ExecutorBiz executorBiz = buildClient();\n\n        final int jobId = 0;\n\n        // Act\n        final Response<String> retval = executorBiz.kill(new KillRequest(jobId));\n\n        // Assert result\n        Assertions.assertNotNull(retval);\n        Assertions.assertNull(((Response<String>) retval).getData());\n        Assertions.assertEquals(200, retval.getCode());\n        Assertions.assertNull(retval.getMsg());\n    }\n\n    @Test\n    public void log(){\n        ExecutorBiz executorBiz = buildClient();\n\n        final long logDateTim = 0L;\n        final long logId = 0;\n        final int fromLineNum = 0;\n\n        // Act\n        final Response<LogResult> retval = executorBiz.log(new LogRequest(logDateTim, logId, fromLineNum));\n\n        // Assert result\n        Assertions.assertNotNull(retval);\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-core/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>com.xuxueli</groupId>\n\t\t<artifactId>xxl-job</artifactId>\n\t\t<version>3.4.0-SNAPSHOT</version>\n\t</parent>\n\t<artifactId>xxl-job-core</artifactId>\n\t<packaging>jar</packaging>\n\n\t<name>${project.artifactId}</name>\n\t<description>A distributed task scheduling framework.</description>\n\t<url>https://www.xuxueli.com/</url>\n\n\t<dependencies>\n\n\t\t<!-- ********************** base ********************** -->\n\t\t<!-- slf4j -->\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>slf4j-api</artifactId>\n\t\t</dependency>\n\n\t\t<!-- jakarta.annotation-api -->\n\t\t<dependency>\n\t\t\t<groupId>jakarta.annotation</groupId>\n\t\t\t<artifactId>jakarta.annotation-api</artifactId>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\n\t\t<!-- ********************** embed server: netty + gson ********************** -->\n\t\t<dependency>\n\t\t\t<groupId>io.netty</groupId>\n\t\t\t<artifactId>netty-codec-http</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.google.code.gson</groupId>\n\t\t\t<artifactId>gson</artifactId>\n\t\t</dependency>\n\n\t\t<!-- ********************** tool: xxl-tool ********************** -->\n\t\t<dependency>\n\t\t\t<groupId>com.xuxueli</groupId>\n\t\t\t<artifactId>xxl-tool</artifactId>\n\t\t</dependency>\n\n\t\t<!-- ********************** plugin: groovy + spring ********************** -->\n\t\t<!-- groovy-all -->\n\t\t<dependency>\n\t\t\t<groupId>org.apache.groovy</groupId>\n\t\t\t<artifactId>groovy</artifactId>\n\t\t</dependency>\n\n\t\t<!-- spring-context -->\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-context</artifactId>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\n\t</dependencies>\n\n</project>"
  },
  {
    "path": "xxl-job-core/src/main/java/com/xxl/job/core/constant/Const.java",
    "content": "package com.xxl.job.core.constant;\n\n/**\n * Created by xuxueli on 17/5/10.\n */\npublic class Const {\n\n    // ---------------------- for openapi ----------------------\n\n    /**\n     * access token\n     */\n    public static final String XXL_JOB_ACCESS_TOKEN = \"XXL-JOB-ACCESS-TOKEN\";\n\n\n    // ---------------------- for registry ----------------------\n\n    /**\n     * registry beat interval, default 30s\n     */\n    public static final int BEAT_TIMEOUT = 30;\n\n    /**\n     * registry dead timeout, default 90s\n     */\n    public static final int DEAD_TIMEOUT = BEAT_TIMEOUT * 3;\n\n}\n"
  },
  {
    "path": "xxl-job-core/src/main/java/com/xxl/job/core/constant/ExecutorBlockStrategyEnum.java",
    "content": "package com.xxl.job.core.constant;\n\n/**\n * Created by xuxueli on 17/5/9.\n */\npublic enum ExecutorBlockStrategyEnum {\n\n    SERIAL_EXECUTION(\"Serial execution\"),\n    /*CONCURRENT_EXECUTION(\"并行\"),*/\n    DISCARD_LATER(\"Discard Later\"),\n    COVER_EARLY(\"Cover Early\");\n\n    private String title;\n    private ExecutorBlockStrategyEnum (String title) {\n        this.title = title;\n    }\n\n    public void setTitle(String title) {\n        this.title = title;\n    }\n    public String getTitle() {\n        return title;\n    }\n\n    public static ExecutorBlockStrategyEnum match(String name, ExecutorBlockStrategyEnum defaultItem) {\n        if (name != null) {\n            for (ExecutorBlockStrategyEnum item:ExecutorBlockStrategyEnum.values()) {\n                if (item.name().equals(name)) {\n                    return item;\n                }\n            }\n        }\n        return defaultItem;\n    }\n}\n"
  },
  {
    "path": "xxl-job-core/src/main/java/com/xxl/job/core/constant/RegistType.java",
    "content": "package com.xxl.job.core.constant;\n\n/**\n * Created by xuxueli on 17/5/9.\n */\npublic enum RegistType{\n\n    /**\n     * executor registry\n     */\n    EXECUTOR,\n\n    /**\n     * admin registry\n     */\n    ADMIN;\n\n}"
  },
  {
    "path": "xxl-job-core/src/main/java/com/xxl/job/core/context/XxlJobContext.java",
    "content": "package com.xxl.job.core.context;\n\n/**\n * xxl-job context\n *\n * @author xuxueli 2020-05-21\n * [Dear hj]\n */\npublic class XxlJobContext {\n\n    public static final int HANDLE_CODE_SUCCESS = 200;\n    public static final int HANDLE_CODE_FAIL = 500;\n    public static final int HANDLE_CODE_TIMEOUT = 502;\n\n    // ---------------------- base info ----------------------\n\n    /**\n     * job id\n     */\n    private final long jobId;\n\n    /**\n     * job param\n     */\n    private final String jobParam;\n\n    // ---------------------- for log ----------------------\n\n    /**\n     * log id\n     */\n    private final long logId;\n\n    /**\n     * log timestamp\n     */\n    private final long logDateTime;\n\n    /**\n     * log filename\n     */\n    private final String logFileName;\n\n    // ---------------------- for shard ----------------------\n\n    /**\n     * shard index\n     */\n    private final int shardIndex;\n\n    /**\n     * shard total\n     */\n    private final int shardTotal;\n\n    // ---------------------- for handle ----------------------\n\n    /**\n     * handleCode：The result status of job execution\n     *\n     *      200 : success\n     *      500 : fail\n     *      502 : timeout\n     *\n     */\n    private int handleCode;\n\n    /**\n     * handleMsg：The simple log msg of job execution\n     */\n    private String handleMsg;\n\n\n    public XxlJobContext(long jobId,\n                         String jobParam,\n                         long logId,\n                         long logDateTime,\n                         String logFileName,\n                         int shardIndex, \n                         int shardTotal) {\n        this.jobId = jobId;\n        this.jobParam = jobParam;\n        this.logId = logId;\n        this.logDateTime = logDateTime;\n        this.logFileName = logFileName;\n        this.shardIndex = shardIndex;\n        this.shardTotal = shardTotal;\n\n        this.handleCode = HANDLE_CODE_SUCCESS;  // default success\n    }\n\n    public long getJobId() {\n        return jobId;\n    }\n\n    public String getJobParam() {\n        return jobParam;\n    }\n\n    public long getLogId() {\n        return logId;\n    }\n\n    public long getLogDateTime() {\n        return logDateTime;\n    }\n\n    public String getLogFileName() {\n        return logFileName;\n    }\n\n    public int getShardIndex() {\n        return shardIndex;\n    }\n\n    public int getShardTotal() {\n        return shardTotal;\n    }\n\n    public void setHandleCode(int handleCode) {\n        this.handleCode = handleCode;\n    }\n\n    public int getHandleCode() {\n        return handleCode;\n    }\n\n    public void setHandleMsg(String handleMsg) {\n        this.handleMsg = handleMsg;\n    }\n\n    public String getHandleMsg() {\n        return handleMsg;\n    }\n\n    // ---------------------- tool ----------------------\n\n    /**\n     * xxl-job context store\n     */\n    private static final InheritableThreadLocal<XxlJobContext> contextHolder = new InheritableThreadLocal<XxlJobContext>(); // support for child thread of job handler)\n\n    /**\n     * set xxl-job context\n     */\n    public static void setXxlJobContext(XxlJobContext xxlJobContext){\n        contextHolder.set(xxlJobContext);\n    }\n\n    /**\n     * get xxl-job context\n     */\n    public static XxlJobContext getXxlJobContext(){\n        return contextHolder.get();\n    }\n\n}"
  },
  {
    "path": "xxl-job-core/src/main/java/com/xxl/job/core/context/XxlJobHelper.java",
    "content": "package com.xxl.job.core.context;\n\nimport com.xxl.job.core.log.XxlJobFileAppender;\nimport com.xxl.tool.core.DateTool;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.slf4j.helpers.FormattingTuple;\nimport org.slf4j.helpers.MessageFormatter;\n\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.util.Date;\n\n/**\n * helper for xxl-job\n *\n * @author xuxueli 2020-11-05\n */\npublic class XxlJobHelper {\n\n    // ---------------------- job info ----------------------\n\n    /**\n     * current JobId\n     *\n     * @return jobId\n     */\n    public static long getJobId() {\n        XxlJobContext xxlJobContext = XxlJobContext.getXxlJobContext();\n        if (xxlJobContext == null) {\n            return -1;\n        }\n\n        return xxlJobContext.getJobId();\n    }\n\n    /**\n     * current JobParam\n     *\n     * @return jobParam\n     */\n    public static String getJobParam() {\n        XxlJobContext xxlJobContext = XxlJobContext.getXxlJobContext();\n        if (xxlJobContext == null) {\n            return null;\n        }\n\n        return xxlJobContext.getJobParam();\n    }\n\n    // ---------------------- log info ----------------------\n\n    /**\n     * current job log time\n     *\n     * @return logDateTime\n     */\n    public static long getLogId() {\n        XxlJobContext xxlJobContext = XxlJobContext.getXxlJobContext();\n        if (xxlJobContext == null) {\n            return -1;\n        }\n\n        return xxlJobContext.getLogId();\n    }\n\n    /**\n     * current job log time\n     *\n     * @return logDateTime\n     */\n    public static long getLogDateTime() {\n        XxlJobContext xxlJobContext = XxlJobContext.getXxlJobContext();\n        if (xxlJobContext == null) {\n            return -1;\n        }\n\n        return xxlJobContext.getLogDateTime();\n    }\n\n    /**\n     * current job log filename\n     *\n     * @return logFileName\n     */\n    public static String getLogFileName() {\n        XxlJobContext xxlJobContext = XxlJobContext.getXxlJobContext();\n        if (xxlJobContext == null) {\n            return null;\n        }\n\n        return xxlJobContext.getLogFileName();\n    }\n\n    // ---------------------- shard info ----------------------\n\n    /**\n     * current ShardIndex\n     *\n     * @return shardIndex\n     */\n    public static int getShardIndex() {\n        XxlJobContext xxlJobContext = XxlJobContext.getXxlJobContext();\n        if (xxlJobContext == null) {\n            return -1;\n        }\n\n        return xxlJobContext.getShardIndex();\n    }\n\n    /**\n     * current ShardTotal\n     *\n     * @return shardTotal\n     */\n    public static int getShardTotal() {\n        XxlJobContext xxlJobContext = XxlJobContext.getXxlJobContext();\n        if (xxlJobContext == null) {\n            return -1;\n        }\n\n        return xxlJobContext.getShardTotal();\n    }\n\n    // ---------------------- tool for log ----------------------\n\n    private static final Logger logger = LoggerFactory.getLogger(\"xxl-job logger\");\n\n    /**\n     * append log with pattern\n     *\n     * @param appendLogPattern  like \"aaa {} bbb {} ccc\"\n     * @param appendLogArguments    like \"111, true\"\n     */\n    public static boolean log(String appendLogPattern, Object ... appendLogArguments) {\n\n        FormattingTuple ft = MessageFormatter.arrayFormat(appendLogPattern, appendLogArguments);\n        String appendLog = ft.getMessage();\n\n        /*appendLog = appendLogPattern;\n        if (appendLogArguments!=null && appendLogArguments.length>0) {\n            appendLog = MessageFormat.format(appendLogPattern, appendLogArguments);\n        }*/\n\n        StackTraceElement callInfo = new Throwable().getStackTrace()[1];\n        return logDetail(callInfo, appendLog);\n    }\n\n    /**\n     * append exception stack\n     *\n     * @param e exception to log\n     * return true if log success\n     */\n    public static boolean log(Throwable e) {\n\n        StringWriter stringWriter = new StringWriter();\n        e.printStackTrace(new PrintWriter(stringWriter));\n        String appendLog = stringWriter.toString();\n\n        StackTraceElement callInfo = new Throwable().getStackTrace()[1];\n        return logDetail(callInfo, appendLog);\n    }\n\n    /**\n     * append log\n     *\n     * @param callInfo      call info\n     * @param appendLog     append log\n     */\n    private static boolean logDetail(StackTraceElement callInfo, String appendLog) {\n        XxlJobContext xxlJobContext = XxlJobContext.getXxlJobContext();\n        if (xxlJobContext == null) {\n            return false;\n        }\n\n        /*// \"yyyy-MM-dd HH:mm:ss [ClassName]-[MethodName]-[LineNumber]-[ThreadName] log\";\n        StackTraceElement[] stackTraceElements = new Throwable().getStackTrace();\n        StackTraceElement callInfo = stackTraceElements[1];*/\n\n        String formatAppendLog = DateTool.formatDateTime(new Date()) + \" \" +\n                \"[\" + callInfo.getClassName() + \"#\" + callInfo.getMethodName() + \"]\" + \"-\" +\n                \"[\" + callInfo.getLineNumber() + \"]\" + \"-\" +\n                \"[\" + Thread.currentThread().getName() + \"]\" + \" \" +\n                (appendLog != null ? appendLog : \"\");\n\n        // appendlog\n        String logFileName = xxlJobContext.getLogFileName();\n\n        if (logFileName!=null && !logFileName.trim().isEmpty()) {\n            XxlJobFileAppender.appendLog(logFileName, formatAppendLog);\n            return true;\n        } else {\n            logger.info(\">>>>>>>>>>> {}\", formatAppendLog);\n            return false;\n        }\n    }\n\n    // ---------------------- tool for handleResult ----------------------\n\n    /**\n     * handle success\n     *\n     * @return true if handle success\n     */\n    public static boolean handleSuccess(){\n        return handleResult(XxlJobContext.HANDLE_CODE_SUCCESS, null);\n    }\n\n    /**\n     * handle success with log msg\n     *\n     * @param handleMsg log msg\n     * @return true if handle success\n     */\n    public static boolean handleSuccess(String handleMsg) {\n        return handleResult(XxlJobContext.HANDLE_CODE_SUCCESS, handleMsg);\n    }\n\n    /**\n     * handle fail\n     *\n     * @return true if handle fail\n     */\n    public static boolean handleFail(){\n        return handleResult(XxlJobContext.HANDLE_CODE_FAIL, null);\n    }\n\n    /**\n     * handle fail with log msg\n     *\n     * @param handleMsg log msg\n     * @return true if handle fail\n     */\n    public static boolean handleFail(String handleMsg) {\n        return handleResult(XxlJobContext.HANDLE_CODE_FAIL, handleMsg);\n    }\n\n    /**\n     * handle timeout\n     *\n     * @return true if handle timeout\n     */\n    public static boolean handleTimeout(){\n        return handleResult(XxlJobContext.HANDLE_CODE_TIMEOUT, null);\n    }\n\n    /**\n     * handle timeout with log msg\n     *\n     * @param handleMsg log msg\n     * @return true if handle timeout\n     */\n    public static boolean handleTimeout(String handleMsg){\n        return handleResult(XxlJobContext.HANDLE_CODE_TIMEOUT, handleMsg);\n    }\n\n    /**\n     * @param handleCode\n     *\n     *      200 : success\n     *      500 : fail\n     *      502 : timeout\n     *\n     * @param handleMsg log msg\n     * @return true if handle success\n     */\n    public static boolean handleResult(int handleCode, String handleMsg) {\n        XxlJobContext xxlJobContext = XxlJobContext.getXxlJobContext();\n        if (xxlJobContext == null) {\n            return false;\n        }\n\n        xxlJobContext.setHandleCode(handleCode);\n        if (handleMsg != null) {\n            xxlJobContext.setHandleMsg(handleMsg);\n        }\n        return true;\n    }\n\n\n}\n"
  },
  {
    "path": "xxl-job-core/src/main/java/com/xxl/job/core/executor/XxlJobExecutor.java",
    "content": "package com.xxl.job.core.executor;\n\nimport com.xxl.job.core.constant.Const;\nimport com.xxl.job.core.openapi.AdminBiz;\nimport com.xxl.job.core.handler.IJobHandler;\nimport com.xxl.job.core.handler.annotation.XxlJob;\nimport com.xxl.job.core.handler.impl.MethodJobHandler;\nimport com.xxl.job.core.log.XxlJobFileAppender;\nimport com.xxl.job.core.server.EmbedServer;\nimport com.xxl.job.core.thread.JobLogFileCleanThread;\nimport com.xxl.job.core.thread.JobThread;\nimport com.xxl.job.core.thread.TriggerCallbackThread;\nimport com.xxl.tool.core.StringTool;\nimport com.xxl.tool.http.HttpTool;\nimport com.xxl.tool.http.IPTool;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.lang.reflect.Method;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * Created by xuxueli on 2016/3/2 21:14.\n */\npublic class XxlJobExecutor  {\n    private static final Logger logger = LoggerFactory.getLogger(XxlJobExecutor.class);\n\n    /*\n     * elegant shutdown wait seconds\n     */\n    private static final long ELEGANT_SHUTDOWN_WAITING_SECONDS = 5;\n\n    // ---------------------- field ----------------------\n    private String adminAddresses;\n    private String accessToken;\n    private int timeout;\n    private Boolean enabled;\n    private String appname;\n    private String address;\n    private String ip;\n    private int port;\n    private String logPath;\n    private int logRetentionDays;\n\n    public void setAdminAddresses(String adminAddresses) {\n        this.adminAddresses = adminAddresses;\n    }\n    public void setAccessToken(String accessToken) {\n        this.accessToken = accessToken;\n    }\n    public void setTimeout(int timeout) {\n        this.timeout = timeout;\n    }\n    public void setEnabled(Boolean enabled) {\n        this.enabled = enabled;\n    }\n    public void setAppname(String appname) {\n        this.appname = appname;\n    }\n    public void setAddress(String address) {\n        this.address = address;\n    }\n    public void setIp(String ip) {\n        this.ip = ip;\n    }\n    public void setPort(int port) {\n        this.port = port;\n    }\n    public void setLogPath(String logPath) {\n        this.logPath = logPath;\n    }\n    public void setLogRetentionDays(int logRetentionDays) {\n        this.logRetentionDays = logRetentionDays;\n    }\n\n\n    // ---------------------- start + stop ----------------------\n    public void start() throws Exception {\n\n        // valid enabled\n        if (enabled!=null && !enabled) {\n            logger.info(\">>>>>>>>>>> xxl-job executor start fail, enabled:{}\", enabled);\n            return;\n        }\n\n        // init logpath\n        XxlJobFileAppender.initLogPath(logPath);\n\n        // init invoker, admin-client\n        initAdminBizList(adminAddresses, accessToken, timeout);\n\n\n        // 1、init JobLogFileCleanThread\n        JobLogFileCleanThread.getInstance().start(logRetentionDays);\n\n        // 2、init TriggerCallbackThread\n        TriggerCallbackThread.getInstance().start();\n\n        // 3、init executor-server\n        initEmbedServer(address, ip, port, appname, accessToken);\n    }\n\n    public void destroy(){\n        // 1、destroy executor-server\n        stopEmbedServer();\n\n        // destroy jobThreadRepository\n        if (!jobThreadRepository.isEmpty()) {\n\n            // 1.1、elegant shutdown wait job finish\n            try {\n                TimeUnit.SECONDS.sleep(ELEGANT_SHUTDOWN_WAITING_SECONDS);\n            } catch (Throwable e) {\n                logger.error(e.getMessage(), e);\n            }\n\n            // 1.2、interupt all job-thread\n            for (Map.Entry<Integer, JobThread> item: jobThreadRepository.entrySet()) {\n                JobThread oldJobThread = removeJobThread(item.getKey(), \"web container destroy and kill the job.\");\n                // wait for job thread push result to callback queue\n                if (oldJobThread != null) {\n                    try {\n                        oldJobThread.join();\n                    } catch (InterruptedException e) {\n                        logger.error(\">>>>>>>>>>> xxl-job, JobThread destroy(join) error, jobId:{}\", item.getKey(), e);\n                    }\n                }\n            }\n            jobThreadRepository.clear();\n        }\n        jobHandlerRepository.clear();\n\n\n        // 2、destroy JobLogFileCleanThread\n        JobLogFileCleanThread.getInstance().toStop();\n\n        // 3、destroy TriggerCallbackThread\n        TriggerCallbackThread.getInstance().toStop();\n\n    }\n\n\n    // ---------------------- admin-client (rpc invoker) ----------------------\n    private static List<AdminBiz> adminBizList;\n    private void initAdminBizList(String adminAddresses, String accessToken, int timeout) throws Exception {\n        // valid\n        if (StringTool.isBlank(adminAddresses)) {\n            return;\n        }\n\n        // build adminBizList\n        for (String address: adminAddresses.trim().split(\",\")) {\n            if (StringTool.isBlank(address)) {\n                continue;\n            }\n\n            // parse param\n            String finalAddress = address.trim();\n            finalAddress = finalAddress.endsWith(\"/\") ? (finalAddress + \"api\") : (finalAddress + \"/api\");\n            int finalTimeout = (timeout >=1 && timeout <= 10)\n                    ?timeout\n                    :3;\n\n            // build\n            AdminBiz adminBiz = HttpTool.createClient()\n                    .url(finalAddress)\n                    .timeout(finalTimeout * 1000)\n                    .header(Const.XXL_JOB_ACCESS_TOKEN, accessToken)\n                    .proxy(AdminBiz.class);\n\n            // registry\n            if (adminBizList == null) {\n                adminBizList = new ArrayList<AdminBiz>();\n            }\n            adminBizList.add(adminBiz);\n        }\n    }\n\n    public static List<AdminBiz> getAdminBizList(){\n        return adminBizList;\n    }\n\n    // ---------------------- executor-server (rpc provider) ----------------------\n    private EmbedServer embedServer = null;\n\n    private void initEmbedServer(String address, String ip, int port, String appname, String accessToken) throws Exception {\n\n        // fill ip port\n        port = port>0?port: IPTool.getAvailablePort(9999);\n        ip = StringTool.isNotBlank(ip) ? ip : IPTool.getIp();\n\n        // generate address\n        if (StringTool.isBlank(address)) {\n            // registry-address：default use address to registry , otherwise use ip:port if address is null\n            String ip_port_address = IPTool.toAddressString(ip, port);\n            address = \"http://{ip_port}/\".replace(\"{ip_port}\", ip_port_address);\n        }\n\n        // accessToken\n        if (StringTool.isBlank(accessToken)) {\n            logger.warn(\">>>>>>>>>>> xxl-job accessToken is empty. To ensure system security, please set the accessToken.\");\n        }\n\n        // start\n        embedServer = new EmbedServer();\n        embedServer.start(address, port, appname, accessToken);\n    }\n\n    private void stopEmbedServer() {\n        // stop provider factory\n        if (embedServer != null) {\n            try {\n                embedServer.stop();\n            } catch (Exception e) {\n                logger.error(e.getMessage(), e);\n            }\n        }\n    }\n\n\n    // ---------------------- job handler repository ----------------------\n    private static ConcurrentMap<String, IJobHandler> jobHandlerRepository = new ConcurrentHashMap<String, IJobHandler>();\n    public static IJobHandler loadJobHandler(String name){\n        return jobHandlerRepository.get(name);\n    }\n    public static IJobHandler registryJobHandler(String name, IJobHandler jobHandler){\n        logger.info(\">>>>>>>>>>> xxl-job register jobhandler success, name:{}, jobHandler:{}\", name, jobHandler);\n        return jobHandlerRepository.put(name, jobHandler);\n    }\n    protected void registryJobHandler(XxlJob xxlJob, Object bean, Method executeMethod){\n        if (xxlJob == null) {\n            return;\n        }\n\n        String name = xxlJob.value();\n        //make and simplify the variables since they'll be called several times later\n        Class<?> clazz = bean.getClass();\n        String methodName = executeMethod.getName();\n        if (name.trim().length() == 0) {\n            throw new RuntimeException(\"xxl-job method-jobhandler name invalid, for[\" + clazz + \"#\" + methodName + \"] .\");\n        }\n        if (loadJobHandler(name) != null) {\n            throw new RuntimeException(\"xxl-job jobhandler[\" + name + \"] naming conflicts.\");\n        }\n\n        // execute method\n        /*if (!(method.getParameterTypes().length == 1 && method.getParameterTypes()[0].isAssignableFrom(String.class))) {\n            throw new RuntimeException(\"xxl-job method-jobhandler param-classtype invalid, for[\" + bean.getClass() + \"#\" + method.getName() + \"] , \" +\n                    \"The correct method format like \\\" public ReturnT<String> execute(String param) \\\" .\");\n        }\n        if (!method.getReturnType().isAssignableFrom(ReturnT.class)) {\n            throw new RuntimeException(\"xxl-job method-jobhandler return-classtype invalid, for[\" + bean.getClass() + \"#\" + method.getName() + \"] , \" +\n                    \"The correct method format like \\\" public ReturnT<String> execute(String param) \\\" .\");\n        }*/\n\n        executeMethod.setAccessible(true);\n\n        // init and destroy\n        Method initMethod = null;\n        Method destroyMethod = null;\n\n        if (xxlJob.init().trim().length() > 0) {\n            try {\n                initMethod = clazz.getDeclaredMethod(xxlJob.init());\n                initMethod.setAccessible(true);\n            } catch (NoSuchMethodException e) {\n                throw new RuntimeException(\"xxl-job method-jobhandler initMethod invalid, for[\" + clazz + \"#\" + methodName + \"] .\");\n            }\n        }\n        if (xxlJob.destroy().trim().length() > 0) {\n            try {\n                destroyMethod = clazz.getDeclaredMethod(xxlJob.destroy());\n                destroyMethod.setAccessible(true);\n            } catch (NoSuchMethodException e) {\n                throw new RuntimeException(\"xxl-job method-jobhandler destroyMethod invalid, for[\" + clazz + \"#\" + methodName + \"] .\");\n            }\n        }\n\n        // registry jobhandler\n        registryJobHandler(name, new MethodJobHandler(bean, executeMethod, initMethod, destroyMethod));\n\n    }\n\n\n    // ---------------------- job thread repository ----------------------\n    private static ConcurrentMap<Integer, JobThread> jobThreadRepository = new ConcurrentHashMap<Integer, JobThread>();\n    public static JobThread registJobThread(int jobId, IJobHandler handler, String removeOldReason){\n        JobThread newJobThread = new JobThread(jobId, handler);\n        newJobThread.start();\n        logger.info(\">>>>>>>>>>> xxl-job regist JobThread success, jobId:{}, handler:{}\", new Object[]{jobId, handler});\n\n        JobThread oldJobThread = jobThreadRepository.put(jobId, newJobThread);\t// putIfAbsent | oh my god, map's put method return the old value!!!\n        if (oldJobThread != null) {\n            oldJobThread.toStop(removeOldReason);\n            oldJobThread.interrupt();\n        }\n\n        return newJobThread;\n    }\n\n    public static JobThread removeJobThread(int jobId, String removeOldReason){\n        JobThread oldJobThread = jobThreadRepository.remove(jobId);\n        if (oldJobThread != null) {\n            oldJobThread.toStop(removeOldReason);\n            oldJobThread.interrupt();\n\n            return oldJobThread;\n        }\n        return null;\n    }\n\n    public static JobThread loadJobThread(int jobId){\n        return jobThreadRepository.get(jobId);\n    }\n}\n"
  },
  {
    "path": "xxl-job-core/src/main/java/com/xxl/job/core/executor/impl/XxlJobSimpleExecutor.java",
    "content": "package com.xxl.job.core.executor.impl;\n\nimport com.xxl.job.core.executor.XxlJobExecutor;\nimport com.xxl.job.core.handler.annotation.XxlJob;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.lang.reflect.Method;\nimport java.util.ArrayList;\nimport java.util.List;\n\n\n/**\n * xxl-job executor (for frameless)\n *\n * @author xuxueli 2020-11-05\n */\npublic class XxlJobSimpleExecutor extends XxlJobExecutor {\n    private static final Logger logger = LoggerFactory.getLogger(XxlJobSimpleExecutor.class);\n\n\n    private List<Object> xxlJobBeanList = new ArrayList<>();\n    public List<Object> getXxlJobBeanList() {\n        return xxlJobBeanList;\n    }\n    public void setXxlJobBeanList(List<Object> xxlJobBeanList) {\n        this.xxlJobBeanList = xxlJobBeanList;\n    }\n\n\n    @Override\n    public void start() {\n\n        // init JobHandler Repository (for method)\n        initJobHandlerMethodRepository(xxlJobBeanList);\n\n        // super start\n        try {\n            super.start();\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    @Override\n    public void destroy() {\n        super.destroy();\n    }\n\n\n    private void initJobHandlerMethodRepository(List<Object> xxlJobBeanList) {\n        if (xxlJobBeanList==null || xxlJobBeanList.isEmpty()) {\n            return;\n        }\n\n        // init job handler from method\n        for (Object bean: xxlJobBeanList) {\n            // method\n            Method[] methods = bean.getClass().getDeclaredMethods();\n            if (methods.length == 0) {\n                continue;\n            }\n            for (Method executeMethod : methods) {\n                XxlJob xxlJob = executeMethod.getAnnotation(XxlJob.class);\n                // registry\n                registryJobHandler(xxlJob, bean, executeMethod);\n            }\n\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-core/src/main/java/com/xxl/job/core/executor/impl/XxlJobSpringExecutor.java",
    "content": "package com.xxl.job.core.executor.impl;\n\nimport com.xxl.job.core.executor.XxlJobExecutor;\nimport com.xxl.job.core.glue.GlueFactory;\nimport com.xxl.job.core.handler.annotation.XxlJob;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.DisposableBean;\nimport org.springframework.beans.factory.SmartInitializingSingleton;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.core.MethodIntrospector;\nimport org.springframework.core.annotation.AnnotatedElementUtils;\n\nimport java.lang.reflect.Method;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\n\n/**\n * xxl-job executor (for spring)\n *\n * @author xuxueli 2018-11-01 09:24:52\n */\npublic class XxlJobSpringExecutor extends XxlJobExecutor implements ApplicationContextAware, SmartInitializingSingleton, DisposableBean {\n    private static final Logger logger = LoggerFactory.getLogger(XxlJobSpringExecutor.class);\n\n    // ---------------------- field ----------------------\n\n    /**\n     * excluded package, like \"org.springframework\"、\"org.aaa,org.bbb\"\n     */\n    private String excludedPackage = \"org.springframework.,spring.\";\n\n    public void setExcludedPackage(String excludedPackage) {\n        this.excludedPackage = excludedPackage;\n    }\n\n\n    // ---------------------- start / stop ----------------------\n\n    /**\n     * start\n      */\n    @Override\n    public void afterSingletonsInstantiated() {\n\n        // scan JobHandler method\n        scanJobHandlerMethod(applicationContext);\n\n        // refresh GlueFactory\n        GlueFactory.refreshInstance(1);\n\n        // super start\n        try {\n            super.start();\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    /**\n     * stop\n      */\n    @Override\n    public void destroy() {\n        super.destroy();\n    }\n\n\n    /**\n     * init job handler from method\n     *\n     * @param applicationContext applicationContext\n     */\n    private void scanJobHandlerMethod(ApplicationContext applicationContext) {\n        // valid\n        if (applicationContext == null) {\n            return;\n        }\n\n        // 1、build excluded-package list\n        List<String> excludedPackageList = new ArrayList<>();\n        if (excludedPackage != null) {\n            for (String excludedPackage : excludedPackage.split(\",\")) {\n                if (!excludedPackage.trim().isEmpty()){\n                    excludedPackageList.add(excludedPackage.trim());\n                }\n            }\n        }\n\n        // 2、scan bean form jobhandler\n        String[] beanNames = applicationContext.getBeanNamesForType(Object.class, false, false);  // allowEagerInit=false, avoid early initialization\n        for (String beanName : beanNames) {\n\n            /**\n             * 2.1、skip by BeanDefinition:\n             *      - skip excluded-package bean\n             *      - skip lazy-init bean\n              */\n            if (applicationContext instanceof BeanDefinitionRegistry beanDefinitionRegistry) {\n                // get BeanDefinition\n                if (!beanDefinitionRegistry.containsBeanDefinition(beanName)) {\n                    continue;\n                }\n                BeanDefinition beanDefinition = beanDefinitionRegistry.getBeanDefinition(beanName);\n\n                // skip excluded-package bean\n                String beanClassName = beanDefinition.getBeanClassName();\n                if (isExcluded(excludedPackageList, beanClassName)) {\n                    logger.debug(\">>>>>>>>>>> xxl-job bean-definition scan, skip excluded-package beanName:{}, beanClassName:{}\", beanName, beanClassName);\n                    continue;\n                }\n\n                // skip lazy-init bean\n                if (beanDefinition.isLazyInit()) {\n                    logger.debug(\">>>>>>>>>>> xxl-job bean-definition scan, skip lazy-init beanName:{}\", beanName);\n                    continue;\n                }\n            }\n\n            /**\n             * 2.2、skip by BeanDefinition Class\n             *      - skip beanClass is null\n             *      - skip method annotation(@XxlJob) is null\n             */\n            Class<?> beanClass = applicationContext.getType(beanName, false);\n            if (beanClass == null) {\n                logger.debug(\">>>>>>>>>>> xxl-job bean-definition scan, skip beanClass-null beanName:{}\", beanName);\n                continue;\n            }\n            // filter method\n            Map<Method, XxlJob> annotatedMethods = null;\n            try {\n                annotatedMethods = MethodIntrospector.selectMethods(beanClass,\n                        new MethodIntrospector.MetadataLookup<XxlJob>() {\n                            @Override\n                            public XxlJob inspect(Method method) {\n                                return AnnotatedElementUtils.findMergedAnnotation(method, XxlJob.class);\n                            }\n                        });\n            } catch (Throwable ex) {\n                logger.error(\">>>>>>>>>>> xxl-job method-jobhandler resolve error for bean[\" + beanName + \"].\", ex);\n            }\n            if (annotatedMethods==null || annotatedMethods.isEmpty()) {\n                continue;\n            }\n\n            // 2.3、scan + registry Jobhandler\n            Object jobBean = applicationContext.getBean(beanName);\n            for (Map.Entry<Method, XxlJob> jobMethodEntry : annotatedMethods.entrySet()) {\n                Method jobMethod = jobMethodEntry.getKey();\n                XxlJob xxlJob = jobMethodEntry.getValue();\n                // regist\n                registryJobHandler(xxlJob, jobBean, jobMethod);\n            }\n\n        }\n    }\n\n    /**\n     * check bean if excluded\n     *\n     * @param excludedPackageList   excludedPackageList\n     * @param beanClassName         beanClassName\n     * @return  true if excluded\n     */\n    private boolean isExcluded(List<String> excludedPackageList, String beanClassName) {\n        // excludedPackageList is empty, no excluded\n        if (excludedPackageList == null || excludedPackageList.isEmpty()) {\n            return false;\n        }\n\n        // beanClassName is null, no excluded\n        if (beanClassName == null) {\n            return false;\n        }\n\n        // excludedPackageList match, excluded (not scan)\n        for (String excludedPackage : excludedPackageList) {\n            if (beanClassName.startsWith(excludedPackage)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n\n    // ---------------------- applicationContext ----------------------\n    private static ApplicationContext applicationContext;\n\n    @Override\n    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {\n        XxlJobSpringExecutor.applicationContext = applicationContext;\n    }\n\n    public static ApplicationContext getApplicationContext() {\n        return applicationContext;\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-core/src/main/java/com/xxl/job/core/glue/GlueFactory.java",
    "content": "package com.xxl.job.core.glue;\r\n\r\nimport com.xxl.job.core.glue.impl.SpringGlueFactory;\r\nimport com.xxl.job.core.handler.IJobHandler;\r\nimport groovy.lang.GroovyClassLoader;\r\n\r\nimport java.math.BigInteger;\r\nimport java.security.MessageDigest;\r\nimport java.util.concurrent.ConcurrentHashMap;\r\nimport java.util.concurrent.ConcurrentMap;\r\n\r\n/**\r\n * glue factory, product class/object by name\r\n *\r\n * @author xuxueli 2016-1-2 20:02:27\r\n */\r\npublic class GlueFactory {\r\n\r\n\r\n\tprivate static GlueFactory glueFactory = new GlueFactory();\r\n\tpublic static GlueFactory getInstance(){\r\n\t\treturn glueFactory;\r\n\t}\r\n\r\n\t/**\r\n\t * refresh instance by type\r\n\t *\r\n\t * @param type\t\t0-frameless, 1-spring;\r\n\t */\r\n\tpublic static void refreshInstance(int type){\r\n\t\tif (type == 0) {\r\n\t\t\tglueFactory = new GlueFactory();\r\n\t\t} else if (type == 1) {\r\n\t\t\tglueFactory = new SpringGlueFactory();\r\n\t\t}\r\n\t}\r\n\r\n\r\n\t/**\r\n\t * groovy class loader\r\n\t */\r\n\tprivate GroovyClassLoader groovyClassLoader = new GroovyClassLoader();\r\n\tprivate ConcurrentMap<String, Class<?>> CLASS_CACHE = new ConcurrentHashMap<>();\r\n\r\n\t/**\r\n\t * load new instance, prototype\r\n\t *\r\n\t * @param codeSource\r\n\t * @return\r\n\t * @throws Exception\r\n\t */\r\n\tpublic IJobHandler loadNewInstance(String codeSource) throws Exception{\r\n\t\tif (codeSource!=null && codeSource.trim().length()>0) {\r\n\t\t\tClass<?> clazz = getCodeSourceClass(codeSource);\r\n\t\t\tif (clazz != null) {\r\n\t\t\t\tObject instance = clazz.newInstance();\r\n\t\t\t\tif (instance!=null) {\r\n\t\t\t\t\tif (instance instanceof IJobHandler) {\r\n\t\t\t\t\t\tthis.injectService(instance);\r\n\t\t\t\t\t\treturn (IJobHandler) instance;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tthrow new IllegalArgumentException(\">>>>>>>>>>> xxl-glue, loadNewInstance error, \"\r\n\t\t\t\t\t\t\t\t+ \"cannot convert from instance[\"+ instance.getClass() +\"] to IJobHandler\");\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\tthrow new IllegalArgumentException(\">>>>>>>>>>> xxl-glue, loadNewInstance error, instance is null\");\r\n\t}\r\n\tprivate Class<?> getCodeSourceClass(String codeSource){\r\n\t\ttry {\r\n\t\t\t// md5\r\n\t\t\tbyte[] md5 = MessageDigest.getInstance(\"MD5\").digest(codeSource.getBytes());\r\n\t\t\tString md5Str = new BigInteger(1, md5).toString(16);\r\n\r\n\t\t\tClass<?> clazz = CLASS_CACHE.get(md5Str);\r\n\t\t\tif(clazz == null){\r\n\t\t\t\tclazz = groovyClassLoader.parseClass(codeSource);\r\n\t\t\t\tCLASS_CACHE.putIfAbsent(md5Str, clazz);\r\n\t\t\t}\r\n\t\t\treturn clazz;\r\n\t\t} catch (Exception e) {\r\n\t\t\treturn groovyClassLoader.parseClass(codeSource);\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * inject service of bean field\r\n\t *\r\n\t * @param instance\r\n\t */\r\n\tpublic void injectService(Object instance) {\r\n\t\t// do something\r\n\t}\r\n\r\n}\r\n"
  },
  {
    "path": "xxl-job-core/src/main/java/com/xxl/job/core/glue/GlueTypeEnum.java",
    "content": "package com.xxl.job.core.glue;\n\n/**\n * Created by xuxueli on 17/4/26.\n */\npublic enum GlueTypeEnum {\n\n    BEAN(\"BEAN\", false, null, null),\n    GLUE_GROOVY(\"GLUE(Java)\", false, null, null),\n    GLUE_SHELL(\"GLUE(Shell)\", true, \"bash\", \".sh\"),\n    GLUE_PYTHON(\"GLUE(Python3)\", true, \"python3\", \".py\"),\n    GLUE_PYTHON2(\"GLUE(Python2)\", true, \"python\", \".py\"),\n    GLUE_NODEJS(\"GLUE(Nodejs)\", true, \"node\", \".js\"),\n    GLUE_POWERSHELL(\"GLUE(PowerShell)\", true, \"powershell\", \".ps1\"),\n    GLUE_PHP(\"GLUE(PHP)\", true, \"php\", \".php\");\n\n    private String desc;\n    private boolean isScript;\n    private String cmd;\n    private String suffix;\n\n    private GlueTypeEnum(String desc, boolean isScript, String cmd, String suffix) {\n        this.desc = desc;\n        this.isScript = isScript;\n        this.cmd = cmd;\n        this.suffix = suffix;\n    }\n\n    public String getDesc() {\n        return desc;\n    }\n\n    public boolean isScript() {\n        return isScript;\n    }\n\n    public String getCmd() {\n        return cmd;\n    }\n\n    public String getSuffix() {\n        return suffix;\n    }\n\n    public static GlueTypeEnum match(String name){\n        for (GlueTypeEnum item: GlueTypeEnum.values()) {\n            if (item.name().equals(name)) {\n                return item;\n            }\n        }\n        return null;\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-core/src/main/java/com/xxl/job/core/glue/impl/SpringGlueFactory.java",
    "content": "package com.xxl.job.core.glue.impl;\n\nimport com.xxl.job.core.executor.impl.XxlJobSpringExecutor;\nimport com.xxl.job.core.glue.GlueFactory;\nimport jakarta.annotation.Resource;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.core.annotation.AnnotationUtils;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Modifier;\n\n/**\n * @author xuxueli 2018-11-01\n */\npublic class SpringGlueFactory extends GlueFactory {\n    private static Logger logger = LoggerFactory.getLogger(SpringGlueFactory.class);\n\n\n    /**\n     * inject action of spring\n     * @param instance\n     */\n    @Override\n    public void injectService(Object instance){\n        if (instance==null) {\n            return;\n        }\n\n        if (XxlJobSpringExecutor.getApplicationContext() == null) {\n            return;\n        }\n\n        Field[] fields = instance.getClass().getDeclaredFields();\n        for (Field field : fields) {\n            if (Modifier.isStatic(field.getModifiers())) {\n                continue;\n            }\n\n            Object fieldBean = null;\n            // with bean-id, bean could be found by both @Resource and @Autowired, or bean could only be found by @Autowired\n\n            if (AnnotationUtils.getAnnotation(field, Resource.class) != null) {\n                try {\n                    Resource resource = AnnotationUtils.getAnnotation(field, Resource.class);\n                    if (resource.name()!=null && resource.name().length()>0){\n                        fieldBean = XxlJobSpringExecutor.getApplicationContext().getBean(resource.name());\n                    } else {\n                        fieldBean = XxlJobSpringExecutor.getApplicationContext().getBean(field.getName());\n                    }\n                } catch (Exception e) {\n                }\n                if (fieldBean==null ) {\n                    fieldBean = XxlJobSpringExecutor.getApplicationContext().getBean(field.getType());\n                }\n            } else if (AnnotationUtils.getAnnotation(field, Autowired.class) != null) {\n                Qualifier qualifier = AnnotationUtils.getAnnotation(field, Qualifier.class);\n                if (qualifier!=null && qualifier.value()!=null && qualifier.value().length()>0) {\n                    fieldBean = XxlJobSpringExecutor.getApplicationContext().getBean(qualifier.value());\n                } else {\n                    fieldBean = XxlJobSpringExecutor.getApplicationContext().getBean(field.getType());\n                }\n            }\n\n            if (fieldBean!=null) {\n                field.setAccessible(true);\n                try {\n                    field.set(instance, fieldBean);\n                } catch (Exception e) {\n                    logger.error(e.getMessage(), e);\n                }\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-core/src/main/java/com/xxl/job/core/handler/IJobHandler.java",
    "content": "package com.xxl.job.core.handler;\n\n/**\n * job handler\n *\n * @author xuxueli 2015-12-19 19:06:38\n */\npublic abstract class IJobHandler {\n\n\n\t/**\n\t * execute handler, invoked when executor receives a scheduling request\n\t *\n\t * @throws Exception\n\t */\n\tpublic abstract void execute() throws Exception;\n\n\n\t/*@Deprecated\n\tpublic abstract ReturnT<String> execute(String param) throws Exception;*/\n\n\t/**\n\t * init handler, invoked when JobThread init\n\t */\n\tpublic void init() throws Exception {\n\t\t// do something\n\t}\n\n\n\t/**\n\t * destroy handler, invoked when JobThread destroy\n\t */\n\tpublic void destroy() throws Exception {\n\t\t// do something\n\t}\n\n\n}\n"
  },
  {
    "path": "xxl-job-core/src/main/java/com/xxl/job/core/handler/annotation/JobHandler.java",
    "content": "//package com.xxl.job.core.handler.annotation;\n//\n//import java.lang.annotation.ElementType;\n//import java.lang.annotation.Inherited;\n//import java.lang.annotation.Retention;\n//import java.lang.annotation.RetentionPolicy;\n//import java.lang.annotation.Target;\n//\n///**\n// * annotation for job handler\n// *\n// * will be replaced by {@link com.xxl.job.core.handler.annotation.XxlJob}\n// *\n// * @author 2016-5-17 21:06:49\n// */\n//@Target({ElementType.TYPE})\n//@Retention(RetentionPolicy.RUNTIME)\n//@Inherited\n//@Deprecated\n//public @interface JobHandler {\n//\n//    String value();\n//\n//}\n"
  },
  {
    "path": "xxl-job-core/src/main/java/com/xxl/job/core/handler/annotation/XxlJob.java",
    "content": "package com.xxl.job.core.handler.annotation;\n\nimport java.lang.annotation.*;\n\n/**\n * annotation for method jobhandler\n *\n * @author xuxueli 2019-12-11 20:50:13\n */\n@Target({ElementType.METHOD})\n@Retention(RetentionPolicy.RUNTIME)\n@Inherited\npublic @interface XxlJob {\n\n    /**\n     * jobhandler name\n     */\n    String value();\n\n    /**\n     * init handler, invoked when JobThread init\n     */\n    String init() default \"\";\n\n    /**\n     * destroy handler, invoked when JobThread destroy\n     */\n    String destroy() default \"\";\n\n}\n"
  },
  {
    "path": "xxl-job-core/src/main/java/com/xxl/job/core/handler/impl/GlueJobHandler.java",
    "content": "package com.xxl.job.core.handler.impl;\n\nimport com.xxl.job.core.context.XxlJobHelper;\nimport com.xxl.job.core.handler.IJobHandler;\n\n/**\n * glue job handler\n *\n * @author xuxueli 2016-5-19 21:05:45\n */\npublic class GlueJobHandler extends IJobHandler {\n\n\tprivate long glueUpdatetime;\n\tprivate IJobHandler jobHandler;\n\tpublic GlueJobHandler(IJobHandler jobHandler, long glueUpdatetime) {\n\t\tthis.jobHandler = jobHandler;\n\t\tthis.glueUpdatetime = glueUpdatetime;\n\t}\n\tpublic long getGlueUpdatetime() {\n\t\treturn glueUpdatetime;\n\t}\n\n\t@Override\n\tpublic void execute() throws Exception {\n\t\tXxlJobHelper.log(\"----------- glue.version:\"+ glueUpdatetime +\" -----------\");\n\t\tjobHandler.execute();\n\t}\n\n\t@Override\n\tpublic void init() throws Exception {\n\t\tthis.jobHandler.init();\n\t}\n\n\t@Override\n\tpublic void destroy() throws Exception {\n\t\tthis.jobHandler.destroy();\n\t}\n}\n"
  },
  {
    "path": "xxl-job-core/src/main/java/com/xxl/job/core/handler/impl/MethodJobHandler.java",
    "content": "package com.xxl.job.core.handler.impl;\n\nimport com.xxl.job.core.handler.IJobHandler;\n\nimport java.lang.reflect.Method;\n\n/**\n * @author xuxueli 2019-12-11 21:12:18\n */\npublic class MethodJobHandler extends IJobHandler {\n\n    private final Object target;\n    private final Method method;\n    private Method initMethod;\n    private Method destroyMethod;\n\n    public MethodJobHandler(Object target, Method method, Method initMethod, Method destroyMethod) {\n        this.target = target;\n        this.method = method;\n\n        this.initMethod = initMethod;\n        this.destroyMethod = destroyMethod;\n    }\n\n    @Override\n    public void execute() throws Exception {\n        Class<?>[] paramTypes = method.getParameterTypes();\n        if (paramTypes.length > 0) {\n            method.invoke(target, new Object[paramTypes.length]);       // method-param can not be primitive-types\n        } else {\n            method.invoke(target);\n        }\n    }\n\n    @Override\n    public void init() throws Exception {\n        if(initMethod != null) {\n            initMethod.invoke(target);\n        }\n    }\n\n    @Override\n    public void destroy() throws Exception {\n        if(destroyMethod != null) {\n            destroyMethod.invoke(target);\n        }\n    }\n\n    @Override\n    public String toString() {\n        return super.toString()+\"[\"+ target.getClass() + \"#\" + method.getName() +\"]\";\n    }\n}\n"
  },
  {
    "path": "xxl-job-core/src/main/java/com/xxl/job/core/handler/impl/ScriptJobHandler.java",
    "content": "package com.xxl.job.core.handler.impl;\n\nimport com.xxl.job.core.context.XxlJobContext;\nimport com.xxl.job.core.context.XxlJobHelper;\nimport com.xxl.job.core.glue.GlueTypeEnum;\nimport com.xxl.job.core.handler.IJobHandler;\nimport com.xxl.job.core.log.XxlJobFileAppender;\nimport com.xxl.job.core.util.ScriptUtil;\n\nimport java.io.File;\n\n/**\n * Created by xuxueli on 17/4/27.\n */\npublic class ScriptJobHandler extends IJobHandler {\n\n    private int jobId;\n    private long glueUpdatetime;\n    private String gluesource;\n    private GlueTypeEnum glueType;\n\n    public ScriptJobHandler(int jobId, long glueUpdatetime, String gluesource, GlueTypeEnum glueType){\n        this.jobId = jobId;\n        this.glueUpdatetime = glueUpdatetime;\n        this.gluesource = gluesource;\n        this.glueType = glueType;\n\n        // clean old script file\n        File glueSrcPath = new File(XxlJobFileAppender.getGlueSrcPath());\n        if (glueSrcPath.exists()) {\n            File[] glueSrcFileList = glueSrcPath.listFiles();\n            if (glueSrcFileList != null) {\n                for (File glueSrcFileItem : glueSrcFileList) {\n                    if (glueSrcFileItem.getName().startsWith(jobId +\"_\")) {\n                        glueSrcFileItem.delete();\n                    }\n                }\n            }\n        }\n\n    }\n\n    public long getGlueUpdatetime() {\n        return glueUpdatetime;\n    }\n\n    @Override\n    public void execute() throws Exception {\n\n        // valid\n        if (!glueType.isScript()) {\n            XxlJobHelper.handleFail(\"glueType[\"+ glueType +\"] invalid.\");\n            return;\n        }\n\n        // cmd\n        String cmd = glueType.getCmd();\n\n        // make script file\n        String scriptFileName = XxlJobFileAppender.getGlueSrcPath()\n                .concat(File.separator)\n                .concat(String.valueOf(jobId))\n                .concat(\"_\")\n                .concat(String.valueOf(glueUpdatetime))\n                .concat(glueType.getSuffix());\n        File scriptFile = new File(scriptFileName);\n        if (!scriptFile.exists()) {\n            ScriptUtil.markScriptFile(scriptFileName, gluesource);\n        }\n\n        // log file\n        String logFileName = XxlJobContext.getXxlJobContext().getLogFileName();\n\n        // script params：0=param、1=分片序号、2=分片总数\n        String jobParam = XxlJobHelper.getJobParam();\n        String[] scriptParams = new String[3];\n        scriptParams[0] = jobParam!=null?jobParam:\"\";\n        scriptParams[1] = String.valueOf(XxlJobContext.getXxlJobContext().getShardIndex());\n        scriptParams[2] = String.valueOf(XxlJobContext.getXxlJobContext().getShardTotal());\n\n        // invoke\n        XxlJobHelper.log(\"----------- script file:\"+ scriptFileName +\" -----------\");\n        int exitValue = ScriptUtil.execToFile(cmd, scriptFileName, logFileName, scriptParams);\n\n        if (exitValue == 0) {\n            XxlJobHelper.handleSuccess();\n            return;\n        } else {\n            XxlJobHelper.handleFail(\"script exit value(\"+exitValue+\") is failed\");\n            return ;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-core/src/main/java/com/xxl/job/core/log/XxlJobFileAppender.java",
    "content": "package com.xxl.job.core.log;\n\nimport com.xxl.job.core.openapi.model.LogResult;\nimport com.xxl.tool.core.DateTool;\nimport com.xxl.tool.core.StringTool;\nimport com.xxl.tool.io.FileTool;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.function.Consumer;\n\n/**\n * store trigger log in each log-file\n *\n * @author xuxueli 2016-3-12 19:25:12\n */\npublic class XxlJobFileAppender {\n\tprivate static final Logger logger = LoggerFactory.getLogger(XxlJobFileAppender.class);\n\n\t/**\n\t * log base path\n\t *\n\t * strut like:\n\t * \t---/\n\t * \t---/gluesource/10_1514171108000.js\n\t * \t---/callbacklogs/xxl-job-callback-1761412677119.log\n\t * \t---/2017-12-25/639.log\n\t * \t---/2017-12-25/821.log\n\t *\n\t */\n\tprivate static String logBasePath = \"/data/applogs/xxl-job/jobhandler\";\n\tprivate static String glueSrcPath = logBasePath.concat(File.separator).concat(\"gluesource\");\n\tprivate static String callbackLogPath = logBasePath.concat(File.separator).concat(\"callbacklogs\");\n\tpublic static void initLogPath(String logPath) throws IOException {\n\t\t// init\n\t\tif (StringTool.isNotBlank(logPath)) {\n\t\t\tlogBasePath = logPath.trim();\n\t\t}\n\t\t// mk base dir\n\t\tFile logPathDir = new File(logBasePath);\n        FileTool.createDirectories(logPathDir);\n\t\tlogBasePath = logPathDir.getPath();\n\n\t\t// mk glue dir\n\t\tFile glueBaseDir = new File(logPathDir, \"gluesource\");\n        FileTool.createDirectories(glueBaseDir);\n\t\tglueSrcPath = glueBaseDir.getPath();\n\t}\n\tpublic static String getLogPath() {\n\t\treturn logBasePath;\n\t}\n\tpublic static String getGlueSrcPath() {\n\t\treturn glueSrcPath;\n\t}\n\tpublic static String getCallbackLogPath() {\n\t\treturn callbackLogPath;\n\t}\n\n\t/**\n\t * log filename, like \"logPath/yyyy-MM-dd/9999.log\"\n\t *\n\t * @param logId log id\n\t * @return      log file name\n\t */\n\tpublic static String makeLogFileName(Date triggerDate, long logId) {\n\n\t\t// \"filePath/yyyy-MM-dd\"\n\t\tFile logFilePath = new File(getLogPath(), DateTool.formatDate(triggerDate));\n        try {\n            FileTool.createDirectories(logFilePath);\n        } catch (IOException e) {\n            throw new RuntimeException(\"XxlJobFileAppender makeLogFileName error, logFilePath:\"+ logFilePath.getPath(), e);\n        }\n\n        // filePath/yyyy-MM-dd/9999.log\n        return logFilePath.getPath()\n                .concat(File.separator)\n                .concat(String.valueOf(logId))\n                .concat(\".log\");\n\t}\n\n\t/**\n\t * append log\n\t *\n\t * @param logFileName\tlog file name\n\t * @param appendLog\t\tappend log\n\t */\n\tpublic static void appendLog(String logFileName, String appendLog) {\n\n\t\t// valid\n\t\tif (StringTool.isBlank(logFileName) || appendLog == null) {\n\t\t\treturn;\n\t\t}\n\n\t\t// append log\n        try {\n            FileTool.writeLines(logFileName, List.of(appendLog), true);\n        } catch (IOException e) {\n            throw new RuntimeException(\"XxlJobFileAppender appendLog error, logFileName:\"+ logFileName, e);\n        }\n\t}\n\n\t/**\n\t * support read log-file\n\t *\n\t * @param logFileName\tlog file name\n\t * @param fromLineNum\tfrom line num\n\t * @return log content\n\t */\n\tpublic static LogResult readLog(String logFileName, final int fromLineNum){\n\n\t\t// valid\n\t\tif (StringTool.isBlank(logFileName)) {\n            return new LogResult(fromLineNum, 0, \"readLog fail, logFile not found\", true);\n\t\t}\n\t\tif (!FileTool.exists(logFileName)) {\n            return new LogResult(fromLineNum, 0, \"readLog fail, logFile not exists\", true);\n\t\t}\n\n\t\t// read data\n        StringBuilder logContentBuilder = new StringBuilder();\n        // num: [from, to], start as 1\n        AtomicInteger toLineNum = new AtomicInteger(0);\n        AtomicInteger currentLineNum = new AtomicInteger(0);\n        /*int readLineCount = 0;*/\n\n        // do read\n        try {\n            FileTool.readLines(logFileName, new Consumer<String>() {\n                @Override\n                public void accept(String line) {\n                    // refresh line num\n                    currentLineNum.incrementAndGet();\n\n                    // valid\n                    if (currentLineNum.get() < fromLineNum) {\n                        return;\n                    }\n\n                    // Limit return less than 1000 rows per query request\t// todo\n                    /*if(++readLineCount >= 1000) {\n                        break;\n                    }*/\n\n                    // collect line data\n                    toLineNum.set(currentLineNum.get());\n                    logContentBuilder.append(line).append(System.lineSeparator());      // [from, to], start as 1\n                }\n            });\n        } catch (IOException e) {\n            logger.error(\"XxlJobFileAppender readLog error, logFileName:{}, fromLineNum:{}\", logFileName, fromLineNum, e);\n        }\n\n        // result\n        return new LogResult(fromLineNum, toLineNum.get(), logContentBuilder.toString(), false);\n\t}\n\n}\n"
  },
  {
    "path": "xxl-job-core/src/main/java/com/xxl/job/core/openapi/AdminBiz.java",
    "content": "package com.xxl.job.core.openapi;\n\nimport com.xxl.job.core.openapi.model.CallbackRequest;\nimport com.xxl.job.core.openapi.model.RegistryRequest;\nimport com.xxl.tool.response.Response;\n\nimport java.util.List;\n\n/**\n * @author xuxueli 2017-07-27 21:52:49\n */\npublic interface AdminBiz {\n\n\n    // ---------------------- callback ----------------------\n\n    /**\n     * callback\n     *\n     * @param callbackRequestList\n     * @return\n     */\n    public Response<String> callback(List<CallbackRequest> callbackRequestList);\n\n\n    // ---------------------- registry ----------------------\n\n    /**\n     * registry\n     *\n     * @param registryRequest\n     * @return\n     */\n    public Response<String> registry(RegistryRequest registryRequest);\n\n    /**\n     * registry remove\n     *\n     * @param registryRequest\n     * @return\n     */\n    public Response<String> registryRemove(RegistryRequest registryRequest);\n\n\n    // ---------------------- biz (custome) ----------------------\n    // group、job ... manage\n\n}\n"
  },
  {
    "path": "xxl-job-core/src/main/java/com/xxl/job/core/openapi/ExecutorBiz.java",
    "content": "package com.xxl.job.core.openapi;\n\nimport com.xxl.job.core.openapi.model.*;\nimport com.xxl.tool.response.Response;\n\n/**\n * Created by xuxueli on 17/3/1.\n */\npublic interface ExecutorBiz {\n\n    /**\n     * beat\n     * @return response\n     */\n    public Response<String> beat();\n\n    /**\n     * idle beat\n     *\n     * @param idleBeatRequest idleBeatRequest\n     * @return response\n     */\n    public Response<String> idleBeat(IdleBeatRequest idleBeatRequest);\n\n    /**\n     * run\n     * @param triggerRequest triggerRequest\n     * @return response\n     */\n    public Response<String> run(TriggerRequest triggerRequest);\n\n    /**\n     * kill\n     * @param killRequest killRequest\n     * @return response\n     */\n    public Response<String> kill(KillRequest killRequest);\n\n    /**\n     * log\n     * @param logRequest logRequest\n     * @return response\n     */\n    public Response<LogResult> log(LogRequest logRequest);\n\n}\n"
  },
  {
    "path": "xxl-job-core/src/main/java/com/xxl/job/core/openapi/impl/ExecutorBizImpl.java",
    "content": "package com.xxl.job.core.openapi.impl;\n\nimport com.xxl.job.core.context.XxlJobContext;\nimport com.xxl.job.core.openapi.ExecutorBiz;\nimport com.xxl.job.core.openapi.model.*;\nimport com.xxl.job.core.constant.ExecutorBlockStrategyEnum;\nimport com.xxl.job.core.executor.XxlJobExecutor;\nimport com.xxl.job.core.glue.GlueFactory;\nimport com.xxl.job.core.glue.GlueTypeEnum;\nimport com.xxl.job.core.handler.IJobHandler;\nimport com.xxl.job.core.handler.impl.GlueJobHandler;\nimport com.xxl.job.core.handler.impl.ScriptJobHandler;\nimport com.xxl.job.core.log.XxlJobFileAppender;\nimport com.xxl.job.core.thread.JobThread;\nimport com.xxl.tool.response.Response;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.Date;\n\n/**\n * Created by xuxueli on 17/3/1.\n */\npublic class ExecutorBizImpl implements ExecutorBiz {\n    private static Logger logger = LoggerFactory.getLogger(ExecutorBizImpl.class);\n\n    @Override\n    public Response<String> beat() {\n        return Response.ofSuccess();\n    }\n\n    @Override\n    public Response<String> idleBeat(IdleBeatRequest idleBeatRequest) {\n\n        // isRunningOrHasQueue\n        boolean isRunningOrHasQueue = false;\n        JobThread jobThread = XxlJobExecutor.loadJobThread(idleBeatRequest.getJobId());\n        if (jobThread != null && jobThread.isRunningOrHasQueue()) {\n            isRunningOrHasQueue = true;\n        }\n\n        if (isRunningOrHasQueue) {\n            return Response.ofFail(\"job thread is running or has trigger queue.\");\n        }\n        return Response.ofSuccess();\n    }\n\n    @Override\n    public Response<String> run(TriggerRequest triggerRequest) {\n        // load old：jobHandler + jobThread\n        JobThread jobThread = XxlJobExecutor.loadJobThread(triggerRequest.getJobId());\n        IJobHandler jobHandler = jobThread!=null?jobThread.getHandler():null;\n        String removeOldReason = null;\n\n        // valid：jobHandler + jobThread\n        GlueTypeEnum glueTypeEnum = GlueTypeEnum.match(triggerRequest.getGlueType());\n        if (GlueTypeEnum.BEAN == glueTypeEnum) {\n\n            // new jobhandler\n            IJobHandler newJobHandler = XxlJobExecutor.loadJobHandler(triggerRequest.getExecutorHandler());\n\n            // valid old jobThread\n            if (jobThread!=null && jobHandler != newJobHandler) {\n                // change handler, need kill old thread\n                removeOldReason = \"change jobhandler or glue type, and terminate the old job thread.\";\n\n                jobThread = null;\n                jobHandler = null;\n            }\n\n            // valid handler\n            if (jobHandler == null) {\n                jobHandler = newJobHandler;\n                if (jobHandler == null) {\n                    return Response.of(XxlJobContext.HANDLE_CODE_FAIL, \"job handler [\" + triggerRequest.getExecutorHandler() + \"] not found.\");\n                }\n            }\n\n        } else if (GlueTypeEnum.GLUE_GROOVY == glueTypeEnum) {\n\n            // valid old jobThread\n            if (jobThread != null &&\n                    !(jobThread.getHandler() instanceof GlueJobHandler\n                        && ((GlueJobHandler) jobThread.getHandler()).getGlueUpdatetime()== triggerRequest.getGlueUpdatetime() )) {\n                // change handler or gluesource updated, need kill old thread\n                removeOldReason = \"change job source or glue type, and terminate the old job thread.\";\n\n                jobThread = null;\n                jobHandler = null;\n            }\n\n            // valid handler\n            if (jobHandler == null) {\n                try {\n                    IJobHandler originJobHandler = GlueFactory.getInstance().loadNewInstance(triggerRequest.getGlueSource());\n                    jobHandler = new GlueJobHandler(originJobHandler, triggerRequest.getGlueUpdatetime());\n                } catch (Exception e) {\n                    logger.error(e.getMessage(), e);\n                    return Response.of(XxlJobContext.HANDLE_CODE_FAIL, e.getMessage());\n                }\n            }\n        } else if (glueTypeEnum!=null && glueTypeEnum.isScript()) {\n\n            // valid old jobThread\n            if (jobThread != null &&\n                    !(jobThread.getHandler() instanceof ScriptJobHandler\n                            && ((ScriptJobHandler) jobThread.getHandler()).getGlueUpdatetime()== triggerRequest.getGlueUpdatetime() )) {\n                // change script or gluesource updated, need kill old thread\n                removeOldReason = \"change job source or glue type, and terminate the old job thread.\";\n\n                jobThread = null;\n                jobHandler = null;\n            }\n\n            // valid handler\n            if (jobHandler == null) {\n                jobHandler = new ScriptJobHandler(triggerRequest.getJobId(), triggerRequest.getGlueUpdatetime(), triggerRequest.getGlueSource(), GlueTypeEnum.match(triggerRequest.getGlueType()));\n            }\n        } else {\n            return Response.of(XxlJobContext.HANDLE_CODE_FAIL, \"glueType[\" + triggerRequest.getGlueType() + \"] is not valid.\");\n        }\n\n        // executor block strategy\n        if (jobThread != null) {\n            ExecutorBlockStrategyEnum blockStrategy = ExecutorBlockStrategyEnum.match(triggerRequest.getExecutorBlockStrategy(), null);\n            if (ExecutorBlockStrategyEnum.DISCARD_LATER == blockStrategy) {\n                // discard when running\n                if (jobThread.isRunningOrHasQueue()) {\n                    return Response.of(XxlJobContext.HANDLE_CODE_FAIL, \"block strategy effect：\"+ExecutorBlockStrategyEnum.DISCARD_LATER.getTitle());\n                }\n            } else if (ExecutorBlockStrategyEnum.COVER_EARLY == blockStrategy) {\n                // kill running jobThread\n                if (jobThread.isRunningOrHasQueue()) {\n                    removeOldReason = \"block strategy effect：\" + ExecutorBlockStrategyEnum.COVER_EARLY.getTitle();\n\n                    jobThread = null;\n                }\n            } else {\n                // just queue trigger\n            }\n        }\n\n        // replace thread (new or exists invalid)\n        if (jobThread == null) {\n            jobThread = XxlJobExecutor.registJobThread(triggerRequest.getJobId(), jobHandler, removeOldReason);\n        }\n\n        // push data to queue\n        return jobThread.pushTriggerQueue(triggerRequest);\n    }\n\n    @Override\n    public Response<String> kill(KillRequest killRequest) {\n        // kill handlerThread, and create new one\n        JobThread jobThread = XxlJobExecutor.loadJobThread(killRequest.getJobId());\n        if (jobThread != null) {\n            XxlJobExecutor.removeJobThread(killRequest.getJobId(), \"scheduling center kill job.\");\n            return Response.ofSuccess();\n        }\n\n        return Response.ofSuccess( \"job thread already killed.\");\n    }\n\n    @Override\n    public Response<LogResult> log(LogRequest logRequest) {\n        // log filename: logPath/yyyy-MM-dd/9999.log\n        String logFileName = XxlJobFileAppender.makeLogFileName(new Date(logRequest.getLogDateTim()), logRequest.getLogId());\n\n        LogResult logResult = XxlJobFileAppender.readLog(logFileName, logRequest.getFromLineNum());\n        return Response.ofSuccess(logResult);\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-core/src/main/java/com/xxl/job/core/openapi/model/CallbackRequest.java",
    "content": "package com.xxl.job.core.openapi.model;\n\nimport java.io.Serializable;\n\n/**\n * Created by xuxueli on 17/3/2.\n */\npublic class CallbackRequest implements Serializable {\n    private static final long serialVersionUID = 42L;\n\n    private long logId;\n    private long logDateTim;\n\n    private int handleCode;\n    private String handleMsg;\n\n    public CallbackRequest(){}\n    public CallbackRequest(long logId, long logDateTim, int handleCode, String handleMsg) {\n        this.logId = logId;\n        this.logDateTim = logDateTim;\n        this.handleCode = handleCode;\n        this.handleMsg = handleMsg;\n    }\n\n    public long getLogId() {\n        return logId;\n    }\n\n    public void setLogId(long logId) {\n        this.logId = logId;\n    }\n\n    public long getLogDateTim() {\n        return logDateTim;\n    }\n\n    public void setLogDateTim(long logDateTim) {\n        this.logDateTim = logDateTim;\n    }\n\n    public int getHandleCode() {\n        return handleCode;\n    }\n\n    public void setHandleCode(int handleCode) {\n        this.handleCode = handleCode;\n    }\n\n    public String getHandleMsg() {\n        return handleMsg;\n    }\n\n    public void setHandleMsg(String handleMsg) {\n        this.handleMsg = handleMsg;\n    }\n\n    @Override\n    public String toString() {\n        return \"HandleCallbackParam{\" +\n                \"logId=\" + logId +\n                \", logDateTim=\" + logDateTim +\n                \", handleCode=\" + handleCode +\n                \", handleMsg='\" + handleMsg + '\\'' +\n                '}';\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-core/src/main/java/com/xxl/job/core/openapi/model/IdleBeatRequest.java",
    "content": "package com.xxl.job.core.openapi.model;\n\nimport java.io.Serializable;\n\n/**\n * @author xuxueli 2020-04-11 22:27\n */\npublic class IdleBeatRequest implements Serializable {\n    private static final long serialVersionUID = 42L;\n\n    public IdleBeatRequest() {\n    }\n    public IdleBeatRequest(int jobId) {\n        this.jobId = jobId;\n    }\n\n    private int jobId;\n\n\n    public int getJobId() {\n        return jobId;\n    }\n\n    public void setJobId(int jobId) {\n        this.jobId = jobId;\n    }\n\n}"
  },
  {
    "path": "xxl-job-core/src/main/java/com/xxl/job/core/openapi/model/KillRequest.java",
    "content": "package com.xxl.job.core.openapi.model;\n\nimport java.io.Serializable;\n\n/**\n * @author xuxueli 2020-04-11 22:27\n */\npublic class KillRequest implements Serializable {\n    private static final long serialVersionUID = 42L;\n\n    public KillRequest() {\n    }\n    public KillRequest(int jobId) {\n        this.jobId = jobId;\n    }\n\n    private int jobId;\n\n\n    public int getJobId() {\n        return jobId;\n    }\n\n    public void setJobId(int jobId) {\n        this.jobId = jobId;\n    }\n\n}"
  },
  {
    "path": "xxl-job-core/src/main/java/com/xxl/job/core/openapi/model/LogRequest.java",
    "content": "package com.xxl.job.core.openapi.model;\n\nimport java.io.Serializable;\n\n/**\n * @author xuxueli 2020-04-11 22:27\n */\npublic class LogRequest implements Serializable {\n    private static final long serialVersionUID = 42L;\n\n    public LogRequest() {\n    }\n    public LogRequest(long logDateTim, long logId, int fromLineNum) {\n        this.logDateTim = logDateTim;\n        this.logId = logId;\n        this.fromLineNum = fromLineNum;\n    }\n\n    private long logDateTim;\n    private long logId;\n    private int fromLineNum;\n\n    public long getLogDateTim() {\n        return logDateTim;\n    }\n\n    public void setLogDateTim(long logDateTim) {\n        this.logDateTim = logDateTim;\n    }\n\n    public long getLogId() {\n        return logId;\n    }\n\n    public void setLogId(long logId) {\n        this.logId = logId;\n    }\n\n    public int getFromLineNum() {\n        return fromLineNum;\n    }\n\n    public void setFromLineNum(int fromLineNum) {\n        this.fromLineNum = fromLineNum;\n    }\n\n}"
  },
  {
    "path": "xxl-job-core/src/main/java/com/xxl/job/core/openapi/model/LogResult.java",
    "content": "package com.xxl.job.core.openapi.model;\n\nimport java.io.Serializable;\n\n/**\n * Created by xuxueli on 17/3/23.\n */\npublic class LogResult implements Serializable {\n    private static final long serialVersionUID = 42L;\n\n    public LogResult() {\n    }\n    public LogResult(int fromLineNum, int toLineNum, String logContent, boolean isEnd) {\n        this.fromLineNum = fromLineNum;\n        this.toLineNum = toLineNum;\n        this.logContent = logContent;\n        this.isEnd = isEnd;\n    }\n\n    private int fromLineNum;\n    private int toLineNum;\n    private String logContent;\n    private boolean isEnd;\n\n    public int getFromLineNum() {\n        return fromLineNum;\n    }\n\n    public void setFromLineNum(int fromLineNum) {\n        this.fromLineNum = fromLineNum;\n    }\n\n    public int getToLineNum() {\n        return toLineNum;\n    }\n\n    public void setToLineNum(int toLineNum) {\n        this.toLineNum = toLineNum;\n    }\n\n    public String getLogContent() {\n        return logContent;\n    }\n\n    public void setLogContent(String logContent) {\n        this.logContent = logContent;\n    }\n\n    public boolean isEnd() {\n        return isEnd;\n    }\n\n    public void setEnd(boolean end) {\n        isEnd = end;\n    }\n}\n"
  },
  {
    "path": "xxl-job-core/src/main/java/com/xxl/job/core/openapi/model/RegistryRequest.java",
    "content": "package com.xxl.job.core.openapi.model;\n\nimport java.io.Serializable;\n\n/**\n * Created by xuxueli on 2017-05-10 20:22:42\n */\npublic class RegistryRequest implements Serializable {\n    private static final long serialVersionUID = 42L;\n\n    private String registryGroup;\n    private String registryKey;\n    private String registryValue;\n\n    public RegistryRequest(){}\n    public RegistryRequest(String registryGroup, String registryKey, String registryValue) {\n        this.registryGroup = registryGroup;\n        this.registryKey = registryKey;\n        this.registryValue = registryValue;\n    }\n\n    public String getRegistryGroup() {\n        return registryGroup;\n    }\n\n    public void setRegistryGroup(String registryGroup) {\n        this.registryGroup = registryGroup;\n    }\n\n    public String getRegistryKey() {\n        return registryKey;\n    }\n\n    public void setRegistryKey(String registryKey) {\n        this.registryKey = registryKey;\n    }\n\n    public String getRegistryValue() {\n        return registryValue;\n    }\n\n    public void setRegistryValue(String registryValue) {\n        this.registryValue = registryValue;\n    }\n\n    @Override\n    public String toString() {\n        return \"RegistryParam{\" +\n                \"registryGroup='\" + registryGroup + '\\'' +\n                \", registryKey='\" + registryKey + '\\'' +\n                \", registryValue='\" + registryValue + '\\'' +\n                '}';\n    }\n}\n"
  },
  {
    "path": "xxl-job-core/src/main/java/com/xxl/job/core/openapi/model/TriggerRequest.java",
    "content": "package com.xxl.job.core.openapi.model;\n\nimport java.io.Serializable;\n\n/**\n * Created by xuxueli on 16/7/22.\n */\npublic class TriggerRequest implements Serializable{\n    private static final long serialVersionUID = 42L;\n\n    // job base info\n    private int jobId;\n\n    // job execute info\n    private String executorHandler;\n    private String executorParams;\n    private String executorBlockStrategy;\n    private int executorTimeout;\n\n    // log info\n    private long logId;\n    private long logDateTime;\n\n    // glue info\n    private String glueType;\n    private String glueSource;\n    private long glueUpdatetime;\n\n    // broadcast info\n    private int broadcastIndex;\n    private int broadcastTotal;\n\n\n    public int getJobId() {\n        return jobId;\n    }\n\n    public void setJobId(int jobId) {\n        this.jobId = jobId;\n    }\n\n    public String getExecutorHandler() {\n        return executorHandler;\n    }\n\n    public void setExecutorHandler(String executorHandler) {\n        this.executorHandler = executorHandler;\n    }\n\n    public String getExecutorParams() {\n        return executorParams;\n    }\n\n    public void setExecutorParams(String executorParams) {\n        this.executorParams = executorParams;\n    }\n\n    public String getExecutorBlockStrategy() {\n        return executorBlockStrategy;\n    }\n\n    public void setExecutorBlockStrategy(String executorBlockStrategy) {\n        this.executorBlockStrategy = executorBlockStrategy;\n    }\n\n    public int getExecutorTimeout() {\n        return executorTimeout;\n    }\n\n    public void setExecutorTimeout(int executorTimeout) {\n        this.executorTimeout = executorTimeout;\n    }\n\n    public long getLogId() {\n        return logId;\n    }\n\n    public void setLogId(long logId) {\n        this.logId = logId;\n    }\n\n    public long getLogDateTime() {\n        return logDateTime;\n    }\n\n    public void setLogDateTime(long logDateTime) {\n        this.logDateTime = logDateTime;\n    }\n\n    public String getGlueType() {\n        return glueType;\n    }\n\n    public void setGlueType(String glueType) {\n        this.glueType = glueType;\n    }\n\n    public String getGlueSource() {\n        return glueSource;\n    }\n\n    public void setGlueSource(String glueSource) {\n        this.glueSource = glueSource;\n    }\n\n    public long getGlueUpdatetime() {\n        return glueUpdatetime;\n    }\n\n    public void setGlueUpdatetime(long glueUpdatetime) {\n        this.glueUpdatetime = glueUpdatetime;\n    }\n\n    public int getBroadcastIndex() {\n        return broadcastIndex;\n    }\n\n    public void setBroadcastIndex(int broadcastIndex) {\n        this.broadcastIndex = broadcastIndex;\n    }\n\n    public int getBroadcastTotal() {\n        return broadcastTotal;\n    }\n\n    public void setBroadcastTotal(int broadcastTotal) {\n        this.broadcastTotal = broadcastTotal;\n    }\n\n\n    @Override\n    public String toString() {\n        return \"TriggerParam{\" +\n                \"jobId=\" + jobId +\n                \", executorHandler='\" + executorHandler + '\\'' +\n                \", executorParams='\" + executorParams + '\\'' +\n                \", executorBlockStrategy='\" + executorBlockStrategy + '\\'' +\n                \", executorTimeout=\" + executorTimeout +\n                \", logId=\" + logId +\n                \", logDateTime=\" + logDateTime +\n                \", glueType='\" + glueType + '\\'' +\n                \", glueSource='\" + glueSource + '\\'' +\n                \", glueUpdatetime=\" + glueUpdatetime +\n                \", broadcastIndex=\" + broadcastIndex +\n                \", broadcastTotal=\" + broadcastTotal +\n                '}';\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-core/src/main/java/com/xxl/job/core/server/EmbedServer.java",
    "content": "package com.xxl.job.core.server;\n\nimport com.xxl.job.core.constant.Const;\nimport com.xxl.job.core.openapi.ExecutorBiz;\nimport com.xxl.job.core.openapi.impl.ExecutorBizImpl;\nimport com.xxl.job.core.openapi.model.*;\nimport com.xxl.job.core.thread.ExecutorRegistryThread;\nimport com.xxl.tool.error.ThrowableTool;\nimport com.xxl.tool.json.GsonTool;\nimport com.xxl.tool.response.Response;\nimport io.netty.bootstrap.ServerBootstrap;\nimport io.netty.buffer.Unpooled;\nimport io.netty.channel.*;\nimport io.netty.channel.nio.NioEventLoopGroup;\nimport io.netty.channel.socket.SocketChannel;\nimport io.netty.channel.socket.nio.NioServerSocketChannel;\nimport io.netty.handler.codec.http.*;\nimport io.netty.handler.timeout.IdleStateEvent;\nimport io.netty.handler.timeout.IdleStateHandler;\nimport io.netty.util.CharsetUtil;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.concurrent.*;\n\n/**\n * Copy from : https://github.com/xuxueli/xxl-rpc\n *\n * @author xuxueli 2020-04-11 21:25\n */\npublic class EmbedServer {\n    private static final Logger logger = LoggerFactory.getLogger(EmbedServer.class);\n\n    private ExecutorBiz executorBiz;\n    private Thread thread;\n\n    public void start(final String address, final int port, final String appname, final String accessToken) {\n        executorBiz = new ExecutorBizImpl();\n        thread = new Thread(new Runnable() {\n            @Override\n            public void run() {\n                // param\n                EventLoopGroup bossGroup = new NioEventLoopGroup();\n                EventLoopGroup workerGroup = new NioEventLoopGroup();\n                ThreadPoolExecutor bizThreadPool = new ThreadPoolExecutor(\n                        0,\n                        200,\n                        60L,\n                        TimeUnit.SECONDS,\n                        new LinkedBlockingQueue<Runnable>(2000),\n                        new ThreadFactory() {\n                            @Override\n                            public Thread newThread(Runnable r) {\n                                return new Thread(r, \"xxl-job, EmbedServer bizThreadPool-\" + r.hashCode());\n                            }\n                        },\n                        new RejectedExecutionHandler() {\n                            @Override\n                            public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {\n                                throw new RuntimeException(\"xxl-job, EmbedServer bizThreadPool is EXHAUSTED!\");\n                            }\n                        });\n                try {\n                    // start server\n                    ServerBootstrap bootstrap = new ServerBootstrap();\n                    bootstrap.group(bossGroup, workerGroup)\n                            .channel(NioServerSocketChannel.class)\n                            .childHandler(new ChannelInitializer<SocketChannel>() {\n                                @Override\n                                public void initChannel(SocketChannel channel) throws Exception {\n                                    channel.pipeline()\n                                            .addLast(new IdleStateHandler(0, 0, 30 * 3, TimeUnit.SECONDS))  // beat 3N, close if idle\n                                            .addLast(new HttpServerCodec())\n                                            .addLast(new HttpObjectAggregator(5 * 1024 * 1024))  // merge request & reponse to FULL\n                                            .addLast(new EmbedHttpServerHandler(executorBiz, accessToken, bizThreadPool));\n                                }\n                            })\n                            .childOption(ChannelOption.SO_KEEPALIVE, true);\n\n                    // bind\n                    ChannelFuture future = bootstrap.bind(port).sync();\n\n                    logger.info(\">>>>>>>>>>> xxl-job remoting server start success, nettype = {}, port = {}\", EmbedServer.class, port);\n\n                    // start registry\n                    startRegistry(appname, address);\n\n                    // wait util stop\n                    future.channel().closeFuture().sync();\n\n                } catch (InterruptedException e) {\n                    logger.info(\">>>>>>>>>>> xxl-job remoting server stop.\");\n                } catch (Throwable e) {\n                    logger.error(\">>>>>>>>>>> xxl-job remoting server error.\", e);\n                } finally {\n                    // stop\n                    try {\n                        workerGroup.shutdownGracefully();\n                        bossGroup.shutdownGracefully();\n                    } catch (Throwable e) {\n                        logger.error(e.getMessage(), e);\n                    }\n                }\n            }\n        });\n        thread.setDaemon(true);    // daemon, service jvm, user thread leave >>> daemon leave >>> jvm leave\n        thread.start();\n    }\n\n    public void stop() throws Exception {\n        // destroy server thread\n        if (thread != null && thread.isAlive()) {\n            thread.interrupt();\n        }\n\n        // stop registry\n        stopRegistry();\n        logger.info(\">>>>>>>>>>> xxl-job remoting server destroy success.\");\n    }\n\n\n    // ---------------------- registry ----------------------\n\n    /**\n     * netty_http\n     * <p>\n     * Copy from : https://github.com/xuxueli/xxl-rpc\n     *\n     * @author xuxueli 2015-11-24 22:25:15\n     */\n    public static class EmbedHttpServerHandler extends SimpleChannelInboundHandler<FullHttpRequest> {\n        private static final Logger logger = LoggerFactory.getLogger(EmbedHttpServerHandler.class);\n\n        private ExecutorBiz executorBiz;\n        private String accessToken;\n        private ThreadPoolExecutor bizThreadPool;\n\n        public EmbedHttpServerHandler(ExecutorBiz executorBiz, String accessToken, ThreadPoolExecutor bizThreadPool) {\n            this.executorBiz = executorBiz;\n            this.accessToken = accessToken;\n            this.bizThreadPool = bizThreadPool;\n        }\n\n        @Override\n        protected void channelRead0(final ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception {\n            // request parse\n            //final byte[] requestBytes = ByteBufUtil.getBytes(msg.content());    // byteBuf.toString(io.netty.util.CharsetUtil.UTF_8);\n            String requestData = msg.content().toString(CharsetUtil.UTF_8);\n            String uri = msg.uri();\n            HttpMethod httpMethod = msg.method();\n            boolean keepAlive = HttpUtil.isKeepAlive(msg);\n            String accessTokenReq = msg.headers().get(Const.XXL_JOB_ACCESS_TOKEN);\n\n            // invoke\n            bizThreadPool.execute(new Runnable() {\n                @Override\n                public void run() {\n                    // do invoke\n                    Object responseObj = dispatchRequest(httpMethod, uri, requestData, accessTokenReq);\n\n                    // to json\n                    String responseJson = GsonTool.toJson(responseObj);\n\n                    // write response\n                    writeResponse(ctx, keepAlive, responseJson);\n                }\n            });\n        }\n\n        private Object dispatchRequest(HttpMethod httpMethod, String uri, String requestData, String accessTokenReq) {\n            // valid\n            if (HttpMethod.POST != httpMethod) {\n                return Response.ofFail(\"invalid request, HttpMethod not support.\");\n            }\n            if (uri == null || uri.trim().isEmpty()) {\n                return Response.ofFail( \"invalid request, uri-mapping empty.\");\n            }\n            if (accessToken != null\n                    && !accessToken.trim().isEmpty()\n                    && !accessToken.equals(accessTokenReq)) {\n                return Response.ofFail(\"The access token is wrong.\");\n            }\n\n            // services mapping\n            try {\n                switch (uri) {\n                    case \"/beat\":\n                        return executorBiz.beat();\n                    case \"/idleBeat\":\n                        IdleBeatRequest idleBeatParam = GsonTool.fromJson(requestData, IdleBeatRequest.class);\n                        return executorBiz.idleBeat(idleBeatParam);\n                    case \"/run\":\n                        TriggerRequest triggerParam = GsonTool.fromJson(requestData, TriggerRequest.class);\n                        return executorBiz.run(triggerParam);\n                    case \"/kill\":\n                        KillRequest killParam = GsonTool.fromJson(requestData, KillRequest.class);\n                        return executorBiz.kill(killParam);\n                    case \"/log\":\n                        LogRequest logParam = GsonTool.fromJson(requestData, LogRequest.class);\n                        return executorBiz.log(logParam);\n                    default:\n                        return Response.ofFail( \"invalid request, uri-mapping(\" + uri + \") not found.\");\n                }\n            } catch (Throwable e) {\n                logger.error(e.getMessage(), e);\n                return Response.ofFail(\"request error:\" + ThrowableTool.toString(e));\n            }\n        }\n\n        /**\n         * write response\n         */\n        private void writeResponse(ChannelHandlerContext ctx, boolean keepAlive, String responseJson) {\n            // write response\n            FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.copiedBuffer(responseJson, CharsetUtil.UTF_8));   //  Unpooled.wrappedBuffer(responseJson)\n            response.headers().set(HttpHeaderNames.CONTENT_TYPE, \"text/html;charset=UTF-8\");       // HttpHeaderValues.TEXT_PLAIN.toString()\n            response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());\n            if (keepAlive) {\n                response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);\n            }\n            ctx.writeAndFlush(response);\n        }\n\n        @Override\n        public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {\n            ctx.flush();\n        }\n\n        @Override\n        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {\n            logger.error(\">>>>>>>>>>> xxl-job provider netty_http server caught exception\", cause);\n            ctx.close();\n        }\n\n        @Override\n        public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {\n            if (evt instanceof IdleStateEvent) {\n                ctx.channel().close();      // beat 3N, close if idle\n                logger.debug(\">>>>>>>>>>> xxl-job provider netty_http server close an idle channel.\");\n            } else {\n                super.userEventTriggered(ctx, evt);\n            }\n        }\n    }\n\n    // ---------------------- registry ----------------------\n\n    public void startRegistry(final String appname, final String address) {\n        // start registry\n        ExecutorRegistryThread.getInstance().start(appname, address);\n    }\n\n    public void stopRegistry() {\n        // stop registry\n        ExecutorRegistryThread.getInstance().toStop();\n    }\n}\n"
  },
  {
    "path": "xxl-job-core/src/main/java/com/xxl/job/core/thread/ExecutorRegistryThread.java",
    "content": "package com.xxl.job.core.thread;\n\nimport com.xxl.job.core.constant.RegistType;\nimport com.xxl.job.core.openapi.AdminBiz;\nimport com.xxl.job.core.openapi.model.RegistryRequest;\nimport com.xxl.job.core.constant.Const;\nimport com.xxl.job.core.executor.XxlJobExecutor;\nimport com.xxl.tool.response.Response;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.concurrent.TimeUnit;\n\n/**\n * Created by xuxueli on 17/3/2.\n */\npublic class ExecutorRegistryThread {\n    private static Logger logger = LoggerFactory.getLogger(ExecutorRegistryThread.class);\n\n    private static ExecutorRegistryThread instance = new ExecutorRegistryThread();\n    public static ExecutorRegistryThread getInstance(){\n        return instance;\n    }\n\n    private Thread registryThread;\n    private volatile boolean toStop = false;\n    public void start(final String appname, final String address){\n\n        // valid\n        if (appname==null || appname.trim().length()==0) {\n            logger.warn(\">>>>>>>>>>> xxl-job, executor registry config fail, appname is null.\");\n            return;\n        }\n        if (XxlJobExecutor.getAdminBizList() == null) {\n            logger.warn(\">>>>>>>>>>> xxl-job, executor registry config fail, adminAddresses is null.\");\n            return;\n        }\n\n        registryThread = new Thread(new Runnable() {\n            @Override\n            public void run() {\n\n                // registry\n                while (!toStop) {\n                    try {\n                        RegistryRequest registryParam = new RegistryRequest(RegistType.EXECUTOR.name(), appname, address);\n                        for (AdminBiz adminBiz: XxlJobExecutor.getAdminBizList()) {\n                            try {\n                                Response<String> registryResult = adminBiz.registry(registryParam);\n                                if (registryResult!=null && registryResult.isSuccess()) {\n                                    registryResult = Response.ofSuccess();\n                                    logger.debug(\">>>>>>>>>>> xxl-job registry success, registryParam:{}, registryResult:{}\", new Object[]{registryParam, registryResult});\n                                    break;\n                                } else {\n                                    logger.info(\">>>>>>>>>>> xxl-job registry fail, registryParam:{}, registryResult:{}\", new Object[]{registryParam, registryResult});\n                                }\n                            } catch (Throwable e) {\n                                logger.info(\">>>>>>>>>>> xxl-job registry error, registryParam:{}\", registryParam, e);\n                            }\n\n                        }\n                    } catch (Throwable e) {\n                        if (!toStop) {\n                            logger.error(e.getMessage(), e);\n                        }\n\n                    }\n\n                    try {\n                        if (!toStop) {\n                            TimeUnit.SECONDS.sleep(Const.BEAT_TIMEOUT);\n                        }\n                    } catch (Throwable e) {\n                        if (!toStop) {\n                            logger.warn(\">>>>>>>>>>> xxl-job, executor registry thread interrupted, error msg:{}\", e.getMessage());\n                        }\n                    }\n                }\n\n                // registry remove\n                try {\n                    RegistryRequest registryParam = new RegistryRequest(RegistType.EXECUTOR.name(), appname, address);\n                    for (AdminBiz adminBiz: XxlJobExecutor.getAdminBizList()) {\n                        try {\n                            Response<String> registryResult = adminBiz.registryRemove(registryParam);\n                            if (registryResult!=null && registryResult.isSuccess()) {\n                                registryResult = Response.ofSuccess();\n                                logger.info(\">>>>>>>>>>> xxl-job registry-remove success, registryParam:{}, registryResult:{}\", new Object[]{registryParam, registryResult});\n                                break;\n                            } else {\n                                logger.info(\">>>>>>>>>>> xxl-job registry-remove fail, registryParam:{}, registryResult:{}\", new Object[]{registryParam, registryResult});\n                            }\n                        } catch (Throwable e) {\n                            if (!toStop) {\n                                logger.info(\">>>>>>>>>>> xxl-job registry-remove error, registryParam:{}\", registryParam, e);\n                            }\n\n                        }\n\n                    }\n                } catch (Throwable e) {\n                    if (!toStop) {\n                        logger.error(e.getMessage(), e);\n                    }\n                }\n                logger.info(\">>>>>>>>>>> xxl-job, executor registry thread destroy.\");\n\n            }\n        });\n        registryThread.setDaemon(true);\n        registryThread.setName(\"xxl-job, executor ExecutorRegistryThread\");\n        registryThread.start();\n    }\n\n    public void toStop() {\n        toStop = true;\n\n        // interrupt and wait\n        if (registryThread != null) {\n            registryThread.interrupt();\n            try {\n                registryThread.join();\n            } catch (Throwable e) {\n                logger.error(e.getMessage(), e);\n            }\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-core/src/main/java/com/xxl/job/core/thread/JobLogFileCleanThread.java",
    "content": "package com.xxl.job.core.thread;\n\nimport com.xxl.job.core.log.XxlJobFileAppender;\nimport com.xxl.tool.core.DateTool;\nimport com.xxl.tool.io.FileTool;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.File;\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * job file clean thread\n *\n * @author xuxueli 2017-12-29 16:23:43\n */\npublic class JobLogFileCleanThread {\n    private static Logger logger = LoggerFactory.getLogger(JobLogFileCleanThread.class);\n\n    private static JobLogFileCleanThread instance = new JobLogFileCleanThread();\n    public static JobLogFileCleanThread getInstance(){\n        return instance;\n    }\n\n    private Thread localThread;\n    private volatile boolean toStop = false;\n    public void start(final long logRetentionDays){\n\n        // limit min value\n        if (logRetentionDays < 3 ) {\n            return;     // effective only when logRetentionDays >= 3\n        }\n\n        localThread = new Thread(new Runnable() {\n            @Override\n            public void run() {\n                while (!toStop) {\n                    try {\n                        // clean log dir, over logRetentionDays\n                        File[] childDirs = new File(XxlJobFileAppender.getLogPath()).listFiles();\n                        if (childDirs!=null && childDirs.length>0) {\n\n                            // today\n                            Calendar todayCal = Calendar.getInstance();\n                            todayCal.set(Calendar.HOUR_OF_DAY,0);\n                            todayCal.set(Calendar.MINUTE,0);\n                            todayCal.set(Calendar.SECOND,0);\n                            todayCal.set(Calendar.MILLISECOND,0);\n\n                            Date todayDate = todayCal.getTime();\n\n                            // clean expired logfile\n                            for (File childFile: childDirs) {\n\n                                // valid log-path: must be directory\n                                if (!childFile.isDirectory()) {\n                                    continue;\n                                }\n\n                                // valid day log-path: like \"---/2017-12-25/639.log\"\n                                if (!childFile.getName().contains(\"-\")) {\n                                    continue;\n                                }\n\n                                // parse create-day of file-path\n                                Date logFileCreateDate = null;\n                                try {\n                                    logFileCreateDate = DateTool.parseDate(childFile.getName());\n                                } catch (Exception e) {\n                                    logger.error(e.getMessage(), e);\n                                }\n                                if (logFileCreateDate == null) {\n                                    continue;\n                                }\n\n                                // check expired\n                                Date expiredDate = DateTool.addDays(logFileCreateDate, logRetentionDays);\n                                if (todayDate.getTime() > expiredDate.getTime()) {\n                                    // expired, remove all log of this day\n                                    FileTool.delete(childFile);\n                                    //FileUtil.deleteRecursively(childFile);\n                                }\n                            }\n                        }\n\n                    } catch (Throwable e) {\n                        if (!toStop) {\n                            logger.error(e.getMessage(), e);\n                        }\n                    }\n\n                    try {\n                        TimeUnit.DAYS.sleep(1);\n                    } catch (Throwable e) {\n                        if (!toStop) {\n                            logger.error(e.getMessage(), e);\n                        }\n                    }\n                }\n                logger.info(\">>>>>>>>>>> xxl-job, executor JobLogFileCleanThread thread destroy.\");\n\n            }\n        });\n        localThread.setDaemon(true);\n        localThread.setName(\"xxl-job, executor JobLogFileCleanThread\");\n        localThread.start();\n    }\n\n    public void toStop() {\n        toStop = true;\n\n        if (localThread == null) {\n            return;\n        }\n\n        // interrupt and wait\n        localThread.interrupt();\n        try {\n            localThread.join();\n        } catch (InterruptedException e) {\n            logger.error(e.getMessage(), e);\n        }\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-core/src/main/java/com/xxl/job/core/thread/JobThread.java",
    "content": "package com.xxl.job.core.thread;\n\nimport com.xxl.job.core.openapi.model.CallbackRequest;\nimport com.xxl.job.core.openapi.model.TriggerRequest;\nimport com.xxl.job.core.context.XxlJobContext;\nimport com.xxl.job.core.context.XxlJobHelper;\nimport com.xxl.job.core.executor.XxlJobExecutor;\nimport com.xxl.job.core.handler.IJobHandler;\nimport com.xxl.job.core.log.XxlJobFileAppender;\nimport com.xxl.tool.response.Response;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.util.Date;\nimport java.util.Set;\nimport java.util.concurrent.*;\n\n\n/**\n * handler thread\n * @author xuxueli 2016-1-16 19:52:47\n */\npublic class JobThread extends Thread{\n\tprivate static final Logger logger = LoggerFactory.getLogger(JobThread.class);\n\n\tprivate int jobId;\n\tprivate IJobHandler handler;\n\tprivate LinkedBlockingQueue<TriggerRequest> triggerQueue;\n\tprivate Set<Long> triggerLogIdSet;\t\t// avoid repeat trigger for the same TRIGGER_LOG_ID\n\n\tprivate volatile boolean toStop = false;\n\tprivate String stopReason;\n\n    private boolean running = false;    // if running job\n\tprivate int idleTimes = 0;\t\t\t// idle times\n\n\n\tpublic JobThread(int jobId, IJobHandler handler) {\n\t\tthis.jobId = jobId;\n\t\tthis.handler = handler;\n\t\tthis.triggerQueue = new LinkedBlockingQueue<TriggerRequest>();\n\t\t//this.triggerLogIdSet = Collections.synchronizedSet(new HashSet<Long>());\n\t\tthis.triggerLogIdSet = ConcurrentHashMap.newKeySet();\n\n\t\t// assign job thread name\n\t\tthis.setName(\"xxl-job, JobThread-\"+jobId+\"-\"+System.currentTimeMillis());\n\t}\n\tpublic IJobHandler getHandler() {\n\t\treturn handler;\n\t}\n\n    /**\n     * new trigger to queue\n     */\n\tpublic Response<String> pushTriggerQueue(TriggerRequest triggerParam) {\n        // avoid repeat\n\t\tif (!triggerLogIdSet.add(triggerParam.getLogId())) {\n\t\t\tlogger.info(\">>>>>>>>>>> repeate trigger job, logId:{}\", triggerParam.getLogId());\n\t\t\treturn Response.of(XxlJobContext.HANDLE_CODE_FAIL, \"repeate trigger job, logId:\" + triggerParam.getLogId());\n\t\t}\n\n\t\t// push trigger queue\n\t\ttriggerQueue.add(triggerParam);\n        return Response.ofSuccess();\n\t}\n\n    /**\n     * kill job thread\n     */\n\tpublic void toStop(String stopReason) {\n\t\t/**\n\t\t * Thread.interrupt只支持终止线程的阻塞状态(wait、join、sleep)，\n\t\t * 在阻塞出抛出InterruptedException异常,但是并不会终止运行的线程本身；\n\t\t * 所以需要注意，此处彻底销毁本线程，需要通过共享变量方式；\n\t\t */\n\t\tthis.toStop = true;\n\t\tthis.stopReason = stopReason;\n\t}\n\n    /**\n     * is running job\n     */\n    public boolean isRunningOrHasQueue() {\n        return running || triggerQueue.size()>0;\n    }\n\n    @Override\n\tpublic void run() {\n\n    \t// init\n    \ttry {\n\t\t\thandler.init();\n\t\t} catch (Throwable e) {\n    \t\tlogger.error(e.getMessage(), e);\n\t\t}\n\n\t\t// execute\n\t\twhile(!toStop){\n\t\t\trunning = false;\n\t\t\tidleTimes++;\n\n            TriggerRequest triggerParam = null;\n            try {\n\t\t\t\t// to check toStop signal, we need cycle, so we cannot use queue.take(), instead of poll(timeout)\n\t\t\t\ttriggerParam = triggerQueue.poll(3L, TimeUnit.SECONDS);\n\t\t\t\tif (triggerParam!=null) {\n\t\t\t\t\trunning = true;\n\t\t\t\t\tidleTimes = 0;\n\t\t\t\t\ttriggerLogIdSet.remove(triggerParam.getLogId());\n\n\t\t\t\t\t// log filename, like \"logPath/yyyy-MM-dd/9999.log\"\n\t\t\t\t\tString logFileName = XxlJobFileAppender.makeLogFileName(new Date(triggerParam.getLogDateTime()), triggerParam.getLogId());\n\t\t\t\t\tXxlJobContext xxlJobContext = new XxlJobContext(\n\t\t\t\t\t\t\ttriggerParam.getJobId(),\n\t\t\t\t\t\t\ttriggerParam.getExecutorParams(),\n                            triggerParam.getLogId(),\n                            triggerParam.getLogDateTime(),\n                            logFileName,\n\t\t\t\t\t\t\ttriggerParam.getBroadcastIndex(),\n\t\t\t\t\t\t\ttriggerParam.getBroadcastTotal());\n\n\t\t\t\t\t// init job context\n\t\t\t\t\tXxlJobContext.setXxlJobContext(xxlJobContext);\n\n\t\t\t\t\t// execute\n\t\t\t\t\tXxlJobHelper.log(\"<br>----------- xxl-job job execute start -----------<br>----------- Param:\" + xxlJobContext.getJobParam());\n\n\t\t\t\t\tif (triggerParam.getExecutorTimeout() > 0) {\n\t\t\t\t\t\t// limit timeout\n\t\t\t\t\t\tThread futureThread = null;\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tFutureTask<Boolean> futureTask = new FutureTask<Boolean>(new Callable<Boolean>() {\n\t\t\t\t\t\t\t\t@Override\n\t\t\t\t\t\t\t\tpublic Boolean call() throws Exception {\n\n\t\t\t\t\t\t\t\t\t// init job context\n\t\t\t\t\t\t\t\t\tXxlJobContext.setXxlJobContext(xxlJobContext);\n\n\t\t\t\t\t\t\t\t\thandler.execute();\n\t\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tfutureThread = new Thread(futureTask);\n\t\t\t\t\t\t\tfutureThread.start();\n\n\t\t\t\t\t\t\tBoolean tempResult = futureTask.get(triggerParam.getExecutorTimeout(), TimeUnit.SECONDS);\n\t\t\t\t\t\t} catch (TimeoutException e) {\n\n\t\t\t\t\t\t\tXxlJobHelper.log(\"<br>----------- xxl-job job execute timeout\");\n\t\t\t\t\t\t\tXxlJobHelper.log(e);\n\n\t\t\t\t\t\t\t// handle result\n\t\t\t\t\t\t\tXxlJobHelper.handleTimeout(\"job execute timeout \");\n\t\t\t\t\t\t} finally {\n\t\t\t\t\t\t\tfutureThread.interrupt();\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// just execute\n\t\t\t\t\t\thandler.execute();\n\t\t\t\t\t}\n\n\t\t\t\t\t// valid execute handle data\n\t\t\t\t\tif (XxlJobContext.getXxlJobContext().getHandleCode() <= 0) {\n\t\t\t\t\t\tXxlJobHelper.handleFail(\"job handle result lost.\");\n\t\t\t\t\t} else {\n\t\t\t\t\t\tString tempHandleMsg = XxlJobContext.getXxlJobContext().getHandleMsg();\n\t\t\t\t\t\ttempHandleMsg = (tempHandleMsg!=null&&tempHandleMsg.length()>50000)\n\t\t\t\t\t\t\t\t?tempHandleMsg.substring(0, 50000).concat(\"...\")\n\t\t\t\t\t\t\t\t:tempHandleMsg;\n\t\t\t\t\t\tXxlJobContext.getXxlJobContext().setHandleMsg(tempHandleMsg);\n\t\t\t\t\t}\n\t\t\t\t\tXxlJobHelper.log(\"<br>----------- xxl-job job execute end(finish) -----------<br>----------- Result: handleCode=\"\n\t\t\t\t\t\t\t+ XxlJobContext.getXxlJobContext().getHandleCode()\n\t\t\t\t\t\t\t+ \", handleMsg = \"\n\t\t\t\t\t\t\t+ XxlJobContext.getXxlJobContext().getHandleMsg()\n\t\t\t\t\t);\n\n\t\t\t\t} else {\n\t\t\t\t\tif (idleTimes > 30) {\n\t\t\t\t\t\tif(triggerQueue.isEmpty()) {\t// avoid concurrent trigger causes jobId-lost\n\t\t\t\t\t\t\tXxlJobExecutor.removeJobThread(jobId, \"excutor idle times over limit.\");\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (Throwable e) {\n\t\t\t\tif (toStop) {\n\t\t\t\t\tXxlJobHelper.log(\"<br>----------- JobThread toStop, stopReason:\" + stopReason);\n\t\t\t\t}\n\n\t\t\t\t// handle result\n\t\t\t\tStringWriter stringWriter = new StringWriter();\n\t\t\t\te.printStackTrace(new PrintWriter(stringWriter));\n\t\t\t\tString errorMsg = stringWriter.toString();\n\n\t\t\t\tXxlJobHelper.handleFail(errorMsg);\n\n\t\t\t\tXxlJobHelper.log(\"<br>----------- JobThread Exception:\" + errorMsg + \"<br>----------- xxl-job job execute end(error) -----------\");\n\t\t\t} finally {\n                if(triggerParam != null) {\n                    // callback handler info\n                    if (!toStop) {\n                        // common\n                        TriggerCallbackThread.pushCallBack(new CallbackRequest(\n                        \t\ttriggerParam.getLogId(),\n\t\t\t\t\t\t\t\ttriggerParam.getLogDateTime(),\n\t\t\t\t\t\t\t\tXxlJobContext.getXxlJobContext().getHandleCode(),\n\t\t\t\t\t\t\t\tXxlJobContext.getXxlJobContext().getHandleMsg() )\n\t\t\t\t\t\t);\n                    } else {\n                        // is killed\n                        TriggerCallbackThread.pushCallBack(new CallbackRequest(\n                        \t\ttriggerParam.getLogId(),\n\t\t\t\t\t\t\t\ttriggerParam.getLogDateTime(),\n\t\t\t\t\t\t\t\tXxlJobContext.HANDLE_CODE_FAIL,\n\t\t\t\t\t\t\t\tstopReason + \" [job running, killed]\" )\n\t\t\t\t\t\t);\n                    }\n                }\n            }\n        }\n\n\t\t// callback trigger request in queue\n\t\twhile(triggerQueue !=null && !triggerQueue.isEmpty()){\n\t\t\tTriggerRequest triggerParam = triggerQueue.poll();\n\t\t\tif (triggerParam!=null) {\n\t\t\t\t// is killed\n\t\t\t\tTriggerCallbackThread.pushCallBack(new CallbackRequest(\n\t\t\t\t\t\ttriggerParam.getLogId(),\n\t\t\t\t\t\ttriggerParam.getLogDateTime(),\n\t\t\t\t\t\tXxlJobContext.HANDLE_CODE_FAIL,\n\t\t\t\t\t\tstopReason + \" [job not executed, in the job queue, killed.]\")\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// destroy\n\t\ttry {\n\t\t\thandler.destroy();\n\t\t} catch (Throwable e) {\n\t\t\tlogger.error(e.getMessage(), e);\n\t\t}\n\n\t\tlogger.info(\">>>>>>>>>>> xxl-job JobThread stoped, hashCode:{}\", Thread.currentThread());\n\t}\n}\n"
  },
  {
    "path": "xxl-job-core/src/main/java/com/xxl/job/core/thread/TriggerCallbackThread.java",
    "content": "package com.xxl.job.core.thread;\n\nimport com.xxl.job.core.openapi.AdminBiz;\nimport com.xxl.job.core.openapi.model.CallbackRequest;\nimport com.xxl.job.core.context.XxlJobContext;\nimport com.xxl.job.core.context.XxlJobHelper;\nimport com.xxl.job.core.constant.Const;\nimport com.xxl.job.core.executor.XxlJobExecutor;\nimport com.xxl.job.core.log.XxlJobFileAppender;\nimport com.xxl.tool.core.ArrayTool;\nimport com.xxl.tool.core.CollectionTool;\nimport com.xxl.tool.core.StringTool;\nimport com.xxl.tool.crypto.Md5Tool;\nimport com.xxl.tool.json.GsonTool;\nimport com.xxl.tool.io.FileTool;\nimport com.xxl.tool.response.Response;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * Trigger Callback Thread\n *\n * Created by xuxueli on 16/7/22.\n */\npublic class TriggerCallbackThread {\n    private static final Logger logger = LoggerFactory.getLogger(TriggerCallbackThread.class);\n\n    private static final TriggerCallbackThread instance = new TriggerCallbackThread();\n    public static TriggerCallbackThread getInstance(){\n        return instance;\n    }\n\n    /**\n     * job results callback queue\n     */\n    private final LinkedBlockingQueue<CallbackRequest> callBackQueue = new LinkedBlockingQueue<>();\n    public static void pushCallBack(CallbackRequest callback){\n        getInstance().callBackQueue.add(callback);\n        logger.debug(\">>>>>>>>>>> xxl-job, push callback request, logId:{}\", callback.getLogId());\n    }\n\n    /**\n     * callback thread\n     */\n    private Thread triggerCallbackThread;\n    private Thread triggerRetryCallbackThread;\n    private volatile boolean toStop = false;\n    public void start() {\n\n        // valid\n        if (XxlJobExecutor.getAdminBizList() == null) {\n            logger.warn(\">>>>>>>>>>> xxl-job, executor callback config fail, adminAddresses is null.\");\n            return;\n        }\n\n        /**\n         * trigger callback thread\n         */\n        triggerCallbackThread = new Thread(new Runnable() {\n\n            @Override\n            public void run() {\n\n                // normal callback\n                while(!toStop){\n                    try {\n                        CallbackRequest callback = getInstance().callBackQueue.take();\n                        if (callback != null) {\n\n                            // collect callback data\n                            List<CallbackRequest> callbackParamList = new ArrayList<>();\n                            callbackParamList.add(callback);                                            // add one element\n                            int drainToNum = getInstance().callBackQueue.drainTo(callbackParamList);    // drainTo other all elements\n\n                            // do callback, will retry if error\n                            if (CollectionTool.isNotEmpty(callbackParamList)) {\n                                doCallback(callbackParamList);\n                            }\n                        }\n                    } catch (Throwable e) {\n                        if (!toStop) {\n                            logger.error(e.getMessage(), e);\n                        }\n                    }\n                }\n\n                // thead stop, callback lasttime\n                try {\n                    // collect callback data\n                    List<CallbackRequest> callbackParamList = new ArrayList<>();\n                    int drainToNum = getInstance().callBackQueue.drainTo(callbackParamList);\n\n                    // do callback\n                    if (CollectionTool.isNotEmpty(callbackParamList)) {\n                        doCallback(callbackParamList);\n                    }\n                } catch (Throwable e) {\n                    if (!toStop) {\n                        logger.error(e.getMessage(), e);\n                    }\n                }\n                logger.info(\">>>>>>>>>>> xxl-job, executor callback thread destroy.\");\n\n            }\n        });\n        triggerCallbackThread.setDaemon(true);\n        triggerCallbackThread.setName(\"xxl-job, executor TriggerCallbackThread\");\n        triggerCallbackThread.start();\n\n\n        /**\n         * callback fail retry thread\n         */\n        triggerRetryCallbackThread = new Thread(new Runnable() {\n            @Override\n            public void run() {\n                while(!toStop){\n                    try {\n                        retryFailCallbackFile();\n                    } catch (Throwable e) {\n                        if (!toStop) {\n                            logger.error(e.getMessage(), e);\n                        }\n\n                    }\n                    try {\n                        TimeUnit.SECONDS.sleep(Const.BEAT_TIMEOUT);\n                    } catch (Throwable e) {\n                        if (!toStop) {\n                            logger.error(e.getMessage(), e);\n                        }\n                    }\n                }\n                logger.info(\">>>>>>>>>>> xxl-job, executor retry callback thread destroy.\");\n            }\n        });\n        triggerRetryCallbackThread.setDaemon(true);\n        triggerRetryCallbackThread.setName(\"xxl-job, executor TriggerRetryCallbackThread\");\n        triggerRetryCallbackThread.start();\n\n    }\n    public void toStop(){\n        toStop = true;\n        // stop callback, interrupt and wait\n        if (triggerCallbackThread != null) {    // support empty admin address\n            triggerCallbackThread.interrupt();\n            try {\n                triggerCallbackThread.join();\n            } catch (Throwable e) {\n                logger.error(e.getMessage(), e);\n            }\n        }\n\n        // stop retry, interrupt and wait\n        if (triggerRetryCallbackThread != null) {\n            triggerRetryCallbackThread.interrupt();\n            try {\n                triggerRetryCallbackThread.join();\n            } catch (Throwable e) {\n                logger.error(e.getMessage(), e);\n            }\n        }\n\n    }\n\n    /**\n     * do callback, will retry if error\n     *\n     * @param callbackParamList callback param list\n     */\n    private void doCallback(List<CallbackRequest> callbackParamList){\n        boolean callbackRet = false;\n        // callback, will retry if error\n        for (AdminBiz adminBiz: XxlJobExecutor.getAdminBizList()) {\n            try {\n                Response<String> callbackResult = adminBiz.callback(callbackParamList);\n                if (callbackResult!=null && callbackResult.isSuccess()) {\n                    callbackLog(callbackParamList, \"<br>----------- xxl-job job callback finish.\");\n                    callbackRet = true;\n                    break;\n                } else {\n                    callbackLog(callbackParamList, \"<br>----------- xxl-job job callback fail, callbackResult:\" + callbackResult);\n                }\n            } catch (Throwable e) {\n                callbackLog(callbackParamList, \"<br>----------- xxl-job job callback error, errorMsg:\" + e.getMessage());\n            }\n        }\n        if (!callbackRet) {\n            appendFailCallbackFile(callbackParamList);\n        }\n    }\n\n    /**\n     * callback log\n     */\n    private void callbackLog(List<CallbackRequest> callbackParamList, String logContent){\n        for (CallbackRequest callbackParam: callbackParamList) {\n            String logFileName = XxlJobFileAppender.makeLogFileName(new Date(callbackParam.getLogDateTim()), callbackParam.getLogId());\n            XxlJobContext.setXxlJobContext(new XxlJobContext(\n                    -1,\n                    null,\n                    -1,\n                    -1,\n                    logFileName,\n                    -1,\n                    -1));\n            XxlJobHelper.log(logContent);\n        }\n    }\n\n\n    // ---------------------- fail-callback file ----------------------\n\n    /**\n     * fail-callback file name\n     */\n    private static final String failCallbackFileName = XxlJobFileAppender\n            .getCallbackLogPath()\n            .concat(File.separator)\n            .concat(\"xxl-job-callback-{x}\")\n            .concat(\".log\");\n\n    /**\n     * append fail-callback file\n     *\n     * @param callbackParamList callback param list\n     */\n    private void appendFailCallbackFile(List<CallbackRequest> callbackParamList) {\n        // valid\n        if (CollectionTool.isEmpty(callbackParamList)) {\n            return;\n        }\n\n        // generate callback data\n        String callbackData = GsonTool.toJson(callbackParamList);\n        String callbackDataMd5 = Md5Tool.md5(callbackData);\n\n\n        // create file\n        String finalLogFileName = failCallbackFileName.replace(\"{x}\", callbackDataMd5);\n\n        // write callback log\n        try {\n            FileTool.writeString(finalLogFileName, callbackData);\n        } catch (IOException e) {\n            logger.error(\">>>>>>>>>>> TriggerCallbackThread appendFailCallbackFile error, finalLogFileName:{}\", finalLogFileName, e);\n        }\n    }\n\n    /**\n     * retry fail-callback file\n     */\n    private void retryFailCallbackFile() {\n\n        // valid\n        File callbackLogPath = new File(XxlJobFileAppender.getCallbackLogPath());\n        if (!callbackLogPath.exists()) {\n            return;\n        }\n        // valid file type: must be directory\n        if (!FileTool.isDirectory(callbackLogPath)) {\n            FileTool.delete(callbackLogPath);\n            return;\n        }\n        // valid file in path: pass if empty\n        if (ArrayTool.isEmpty(callbackLogPath.listFiles())) {\n            return;\n        }\n\n        // load and clear file, do retry\n        for (File callbackLogFile: callbackLogPath.listFiles()) {\n            try {\n                // load data\n                String callbackData = FileTool.readString(callbackLogFile.getPath());\n                if (StringTool.isBlank(callbackData)) {\n                    FileTool.delete(callbackLogFile);\n                    continue;\n                }\n\n                // parse callback param\n                List<CallbackRequest> callbackParamList = GsonTool.fromJsonList(callbackData, CallbackRequest.class);\n                FileTool.delete(callbackLogFile);\n\n                // retry callback\n                doCallback(callbackParamList);\n            } catch (IOException e) {\n                logger.error(\">>>>>>>>>>> TriggerCallbackThread retryFailCallbackFile error, callbackLogFile:{}\", callbackLogFile.getPath(), e);\n            }\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-core/src/main/java/com/xxl/job/core/util/ScriptUtil.java",
    "content": "package com.xxl.job.core.util;\n\nimport com.xxl.job.core.context.XxlJobHelper;\nimport com.xxl.tool.core.ArrayTool;\nimport com.xxl.tool.io.FileTool;\nimport com.xxl.tool.io.IOTool;\n\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n *  1、内嵌编译器如\"PythonInterpreter\"无法引用扩展包，因此推荐使用java调用控制台进程方式\"Runtime.getRuntime().exec()\"来运行脚本(shell或python)；\n *  2、因为通过java调用控制台进程方式实现，需要保证目标机器PATH路径正确配置对应编译器；\n *  3、暂时脚本执行日志只能在脚本执行结束后一次性获取，无法保证实时性；因此为确保日志实时性，可改为将脚本打印的日志存储在指定的日志文件上；\n *  4、python 异常输出优先级高于标准输出，体现在Log文件中，因此推荐通过logging方式打日志保持和异常信息一致；否则用prinf日志顺序会错乱\n *\n * Created by xuxueli on 17/2/25.\n */\npublic class ScriptUtil {\n\n    /**\n     * make script file\n     *\n     * @param scriptFileName        script file name\n     * @param scriptContent         script content\n     * @throws IOException exception\n     */\n    public static void markScriptFile(String scriptFileName, String scriptContent) throws IOException {\n        // make file: filePath/gluesource/666-123456789.py\n        FileTool.writeString(scriptFileName, scriptContent);\n\n        /*FileOutputStream fileOutputStream = null;\n        try {\n            fileOutputStream = new FileOutputStream(scriptFileName);\n            fileOutputStream.write(scriptContent.getBytes(\"UTF-8\"));\n            fileOutputStream.close();\n        } catch (Exception e) {\n            throw e;\n        }finally{\n            if(fileOutputStream != null){\n                fileOutputStream.close();\n            }\n        }*/\n    }\n\n    /**\n     * 脚本执行，日志文件实时输出\n     *\n     * @param command       command\n     * @param scriptFile    script file\n     * @param logFile       log file\n     * @param params        params\n     * @return  exit code\n     * @throws IOException exception\n     */\n    public static int execToFile(String command, String scriptFile, String logFile, String... params) throws IOException {\n\n        FileOutputStream fileOutputStream = null;\n        Thread inputThread = null;\n        Thread errorThread = null;\n        Process process = null;\n        try {\n            // 1、build file OutputStream\n            fileOutputStream = new FileOutputStream(logFile, true);\n\n            // 2、build command\n            List<String> cmdarray = new ArrayList<>();\n            cmdarray.add(command);\n            cmdarray.add(scriptFile);\n            if (ArrayTool.isNotEmpty(params)) {\n                for (String param:params) {\n                    cmdarray.add(param);\n                }\n            }\n            String[] cmdarrayFinal = cmdarray.toArray(new String[0]);\n\n            // 3、process：exec\n            process = Runtime.getRuntime().exec(cmdarrayFinal);\n            Process finalProcess = process;\n\n            // 4、read script log: inputStream + errStream\n            final FileOutputStream finalFileOutputStream = fileOutputStream;\n            inputThread = new Thread(() -> {\n                try {\n                    // 数据流Copy（Input自动关闭，Output不处理）\n                    IOTool.copy(finalProcess.getInputStream(), finalFileOutputStream, true, false);\n                } catch (IOException e) {\n                    XxlJobHelper.log(e);\n                }\n            });\n            errorThread = new Thread(() -> {\n                try {\n                    IOTool.copy(finalProcess.getErrorStream(), finalFileOutputStream, true, false);\n                } catch (IOException e) {\n                    XxlJobHelper.log(e);\n                }\n            });\n            inputThread.start();\n            errorThread.start();\n\n            // 5、process：wait for result\n            int exitValue = process.waitFor();      // exit code: 0=success, 1=error\n\n            // 6、thread join, wait for log\n            inputThread.join();\n            errorThread.join();\n\n            return exitValue;\n        } catch (Exception e) {\n            XxlJobHelper.log(e);\n            return -1;\n        } finally {\n            // 7、close file OutputStream\n            if (fileOutputStream != null) {\n                try {\n                    fileOutputStream.close();\n                } catch (IOException e) {\n                    XxlJobHelper.log(e);\n                }\n            }\n            // 8、interrupt thread\n            if (inputThread != null && inputThread.isAlive()) {\n                inputThread.interrupt();\n            }\n            if (errorThread != null && errorThread.isAlive()) {\n                errorThread.interrupt();\n            }\n            // 9、process destroy\n            if (process != null) {\n                process.destroy();\n                // process.destroyForcibly();\n            }\n        }\n    }\n\n    /**\n     * 脚本执行，日志文件实时输出\n     *\n     * 优点：支持将目标数据实时输出到指定日志文件中去\n     * 缺点：\n     *      标准输出和错误输出优先级固定，可能和脚本中顺序不一致\n     *      Java无法实时获取\n     *\n     *      <!-- commons-exec -->\n     * \t\t<dependency>\n     * \t\t\t<groupId>org.apache.commons</groupId>\n     * \t\t\t<artifactId>commons-exec</artifactId>\n     * \t\t\t<version>${commons-exec.version}</version>\n     * \t\t</dependency>\n     *\n     * @param command\n     * @param scriptFile\n     * @param logFile\n     * @param params\n     * @return\n     * @throws IOException\n     */\n    /*public static int execToFileB(String command, String scriptFile, String logFile, String... params) throws IOException {\n        // 标准输出：print （null if watchdog timeout）\n        // 错误输出：logging + 异常 （still exists if watchdog timeout）\n        // 标准输入\n\n        FileOutputStream fileOutputStream = null;   //\n        try {\n            fileOutputStream = new FileOutputStream(logFile, true);\n            PumpStreamHandler streamHandler = new PumpStreamHandler(fileOutputStream, fileOutputStream, null);\n\n            // command\n            CommandLine commandline = new CommandLine(command);\n            commandline.addArgument(scriptFile);\n            if (params!=null && params.length>0) {\n                commandline.addArguments(params);\n            }\n\n            // exec\n            DefaultExecutor exec = new DefaultExecutor();\n            exec.setExitValues(null);\n            exec.setStreamHandler(streamHandler);\n            int exitValue = exec.execute(commandline);  // exit code: 0=success, 1=error\n            return exitValue;\n        } catch (Exception e) {\n            XxlJobLogger.log(e);\n            return -1;\n        } finally {\n            if (fileOutputStream != null) {\n                try {\n                    fileOutputStream.close();\n                } catch (IOException e) {\n                    XxlJobLogger.log(e);\n                }\n\n            }\n        }\n    }*/\n\n}\n"
  },
  {
    "path": "xxl-job-core/src/main/java/com/xxl/job/core/util/deprecated/AdminBizClient.java",
    "content": "//package com.xxl.job.core.openapi.client;\n//\n//import com.xxl.job.core.openapi.AdminBiz;\n//import com.xxl.job.core.openapi.model.HandleCallbackRequest;\n//import com.xxl.job.core.openapi.model.RegistryRequest;\n//import com.xxl.job.core.util.XxlJobRemotingUtil;\n//import com.xxl.tool.response.Response;\n//\n//import java.util.List;\n//\n///**\n// * admin api test\n// *\n// * @author xuxueli 2017-07-28 22:14:52\n// */\n//public class AdminBizClient implements AdminBiz {\n//\n//    public AdminBizClient() {\n//    }\n//    public AdminBizClient(String addressUrl, String accessToken, int timeout) {\n//        this.addressUrl = addressUrl;\n//        this.accessToken = accessToken;\n//        this.timeout = timeout;\n//\n//        // valid\n//        if (!this.addressUrl.endsWith(\"/\")) {\n//            this.addressUrl = this.addressUrl + \"/\";\n//        }\n//        if (!(this.timeout >=1 && this.timeout <= 10)) {\n//            this.timeout = 3;\n//        }\n//    }\n//\n//    private String addressUrl ;\n//    private String accessToken;\n//    private int timeout;\n//\n//\n//    @Override\n//    public Response<String> callback(List<HandleCallbackRequest> handleCallbackRequestList) {\n//        return XxlJobRemotingUtil.postBody(addressUrl+\"api/callback\", accessToken, timeout, handleCallbackRequestList, String.class);\n//    }\n//\n//    @Override\n//    public Response<String> registry(RegistryRequest registryRequest) {\n//        return XxlJobRemotingUtil.postBody(addressUrl + \"api/registry\", accessToken, timeout, registryRequest, String.class);\n//    }\n//\n//    @Override\n//    public Response<String> registryRemove(RegistryRequest registryRequest) {\n//        return XxlJobRemotingUtil.postBody(addressUrl + \"api/registryRemove\", accessToken, timeout, registryRequest, String.class);\n//    }\n//\n//}\n"
  },
  {
    "path": "xxl-job-core/src/main/java/com/xxl/job/core/util/deprecated/DateUtil.java",
    "content": "//package com.xxl.job.core.util;\n//\n//import org.slf4j.Logger;\n//import org.slf4j.LoggerFactory;\n//\n//import java.text.DateFormat;\n//import java.text.ParseException;\n//import java.text.SimpleDateFormat;\n//import java.util.Calendar;\n//import java.util.Date;\n//import java.util.HashMap;\n//import java.util.Map;\n//\n///**\n// * date util\n// *\n// * @author xuxueli 2018-08-19 01:24:11\n// */\n//public class DateUtil {\n//\n//    // ---------------------- format parse ----------------------\n//    private static Logger logger = LoggerFactory.getLogger(DateUtil.class);\n//\n//    private static final String DATE_FORMAT = \"yyyy-MM-dd\";\n//    private static final String DATETIME_FORMAT = \"yyyy-MM-dd HH:mm:ss\";\n//\n//    private static final ThreadLocal<Map<String, DateFormat>> dateFormatThreadLocal = new ThreadLocal<Map<String, DateFormat>>();\n//    private static DateFormat getDateFormat(String pattern) {\n//        if (pattern==null || pattern.trim().length()==0) {\n//            throw new IllegalArgumentException(\"pattern cannot be empty.\");\n//        }\n//\n//        Map<String, DateFormat> dateFormatMap = dateFormatThreadLocal.get();\n//        if(dateFormatMap!=null && dateFormatMap.containsKey(pattern)){\n//            return dateFormatMap.get(pattern);\n//        }\n//\n//        synchronized (dateFormatThreadLocal) {\n//            if (dateFormatMap == null) {\n//                dateFormatMap = new HashMap<String, DateFormat>();\n//            }\n//            dateFormatMap.put(pattern, new SimpleDateFormat(pattern));\n//            dateFormatThreadLocal.set(dateFormatMap);\n//        }\n//\n//        return dateFormatMap.get(pattern);\n//    }\n//\n//    /**\n//     * format datetime. like \"yyyy-MM-dd\"\n//     *\n//     * @param date\n//     * @return\n//     * @throws ParseException\n//     */\n//    public static String formatDate(Date date) {\n//        return format(date, DATE_FORMAT);\n//    }\n//\n//    /**\n//     * format date. like \"yyyy-MM-dd HH:mm:ss\"\n//     *\n//     * @param date\n//     * @return\n//     * @throws ParseException\n//     */\n//    public static String formatDateTime(Date date) {\n//        return format(date, DATETIME_FORMAT);\n//    }\n//\n//    /**\n//     * format date\n//     *\n//     * @param date\n//     * @param patten\n//     * @return\n//     * @throws ParseException\n//     */\n//    public static String format(Date date, String patten) {\n//        return getDateFormat(patten).format(date);\n//    }\n//\n//    /**\n//     * parse date string, like \"yyyy-MM-dd HH:mm:s\"\n//     *\n//     * @param dateString\n//     * @return\n//     * @throws ParseException\n//     */\n//    public static Date parseDate(String dateString){\n//        return parse(dateString, DATE_FORMAT);\n//    }\n//\n//    /**\n//     * parse datetime string, like \"yyyy-MM-dd HH:mm:ss\"\n//     *\n//     * @param dateString\n//     * @return\n//     * @throws ParseException\n//     */\n//    public static Date parseDateTime(String dateString) {\n//        return parse(dateString, DATETIME_FORMAT);\n//    }\n//\n//    /**\n//     * parse date\n//     *\n//     * @param dateString\n//     * @param pattern\n//     * @return\n//     * @throws ParseException\n//     */\n//    public static Date parse(String dateString, String pattern) {\n//        try {\n//            Date date = getDateFormat(pattern).parse(dateString);\n//            return date;\n//        } catch (Exception e) {\n//            logger.warn(\"parse date error, dateString = {}, pattern={}; errorMsg = {}\", dateString, pattern, e.getMessage());\n//            return null;\n//        }\n//    }\n//\n//\n//    // ---------------------- add date ----------------------\n//\n//    public static Date addYears(final Date date, final int amount) {\n//        return add(date, Calendar.YEAR, amount);\n//    }\n//\n//    public static Date addMonths(final Date date, final int amount) {\n//        return add(date, Calendar.MONTH, amount);\n//    }\n//\n//    public static Date addDays(final Date date, final int amount) {\n//        return add(date, Calendar.DAY_OF_MONTH, amount);\n//    }\n//\n//    public static Date addHours(final Date date, final int amount) {\n//        return add(date, Calendar.HOUR_OF_DAY, amount);\n//    }\n//\n//    public static Date addMinutes(final Date date, final int amount) {\n//        return add(date, Calendar.MINUTE, amount);\n//    }\n//\n//    private static Date add(final Date date, final int calendarField, final int amount) {\n//        if (date == null) {\n//            return null;\n//        }\n//        final Calendar c = Calendar.getInstance();\n//        c.setTime(date);\n//        c.add(calendarField, amount);\n//        return c.getTime();\n//    }\n//\n//}"
  },
  {
    "path": "xxl-job-core/src/main/java/com/xxl/job/core/util/deprecated/ExecutorBizClient.java",
    "content": "//package com.xxl.job.core.openapi.client;\n//\n//import com.xxl.job.core.openapi.ExecutorBiz;\n//import com.xxl.job.core.openapi.model.*;\n//import com.xxl.job.core.util.XxlJobRemotingUtil;\n//import com.xxl.tool.response.Response;\n//\n///**\n// * admin api test\n// *\n// * @author xuxueli 2017-07-28 22:14:52\n// */\n//public class ExecutorBizClient implements ExecutorBiz {\n//\n//    public ExecutorBizClient() {\n//    }\n//    public ExecutorBizClient(String addressUrl, String accessToken, int timeout) {\n//        this.addressUrl = addressUrl;\n//        this.accessToken = accessToken;\n//        this.timeout = timeout;\n//\n//        // valid\n//        if (!this.addressUrl.endsWith(\"/\")) {\n//            this.addressUrl = this.addressUrl + \"/\";\n//        }\n//        if (!(this.timeout >=1 && this.timeout <= 10)) {\n//            this.timeout = 3;\n//        }\n//    }\n//\n//    private String addressUrl ;\n//    private String accessToken;\n//    private int timeout;\n//\n//\n//    @Override\n//    public Response<String> beat() {\n//        return XxlJobRemotingUtil.postBody(addressUrl+\"beat\", accessToken, timeout, \"\", String.class);\n//    }\n//\n//    @Override\n//    public Response<String> idleBeat(IdleBeatRequest idleBeatRequest){\n//        return XxlJobRemotingUtil.postBody(addressUrl+\"idleBeat\", accessToken, timeout, idleBeatRequest, String.class);\n//    }\n//\n//    @Override\n//    public Response<String> run(TriggerRequest triggerRequest) {\n//        return XxlJobRemotingUtil.postBody(addressUrl + \"run\", accessToken, timeout, triggerRequest, String.class);\n//    }\n//\n//    @Override\n//    public Response<String> kill(KillRequest killRequest) {\n//        return XxlJobRemotingUtil.postBody(addressUrl + \"kill\", accessToken, timeout, killRequest, String.class);\n//    }\n//\n//    @Override\n//    public Response<LogResult> log(LogRequest logRequest) {\n//        return XxlJobRemotingUtil.postBody(addressUrl + \"log\", accessToken, timeout, logRequest, LogResult.class);\n//    }\n//\n//}\n"
  },
  {
    "path": "xxl-job-core/src/main/java/com/xxl/job/core/util/deprecated/FileUtil.java",
    "content": "//package com.xxl.job.core.util;\n//\n//import org.slf4j.Logger;\n//import org.slf4j.LoggerFactory;\n//\n//import java.io.File;\n//import java.io.FileInputStream;\n//import java.io.FileOutputStream;\n//import java.io.IOException;\n//\n///**\n// * file tool\n// *\n// * @author xuxueli 2017-12-29 17:56:48\n// */\n//public class FileUtil {\n//    private static Logger logger = LoggerFactory.getLogger(FileUtil.class);\n//\n//\n//    /**\n//     * delete recursively\n//     *\n//     * @param root\n//     * @return\n//     */\n//    public static boolean deleteRecursively(File root) {\n//        if (root != null && root.exists()) {\n//            if (root.isDirectory()) {\n//                File[] children = root.listFiles();\n//                if (children != null) {\n//                    for (File child : children) {\n//                        deleteRecursively(child);\n//                    }\n//                }\n//            }\n//            return root.delete();\n//        }\n//        return false;\n//    }\n//\n//\n//    public static void deleteFile(String fileName) {\n//        // file\n//        File file = new File(fileName);\n//        if (file.exists()) {\n//            file.delete();\n//        }\n//    }\n//\n//\n//    public static void writeFileContent(File file, byte[] data) {\n//\n//        // file\n//        if (!file.exists()) {\n//            file.getParentFile().mkdirs();\n//        }\n//\n//        // append file content\n//        FileOutputStream fos = null;\n//        try {\n//            fos = new FileOutputStream(file);\n//            fos.write(data);\n//            fos.flush();\n//        } catch (Exception e) {\n//            logger.error(e.getMessage(), e);\n//        } finally {\n//            if (fos != null) {\n//                try {\n//                    fos.close();\n//                } catch (IOException e) {\n//                    logger.error(e.getMessage(), e);\n//                }\n//            }\n//        }\n//\n//    }\n//\n//    public static byte[] readFileContent(File file) {\n//        Long fileLength = file.length();\n//        byte[] fileContent = new byte[fileLength.intValue()];\n//\n//        FileInputStream in = null;\n//        try {\n//            in = new FileInputStream(file);\n//            in.read(fileContent);\n//            in.close();\n//\n//            return fileContent;\n//        } catch (Exception e) {\n//            logger.error(e.getMessage(), e);\n//            return null;\n//        } finally {\n//            if (in != null) {\n//                try {\n//                    in.close();\n//                } catch (IOException e) {\n//                    logger.error(e.getMessage(), e);\n//                }\n//            }\n//        }\n//    }\n//\n//\n//    /*public static void appendFileLine(String fileName, String content) {\n//\n//        // file\n//        File file = new File(fileName);\n//        if (!file.exists()) {\n//            try {\n//                file.createNewFile();\n//            } catch (IOException e) {\n//                logger.error(e.getMessage(), e);\n//                return;\n//            }\n//        }\n//\n//        // content\n//        if (content == null) {\n//            content = \"\";\n//        }\n//        content += \"\\r\\n\";\n//\n//        // append file content\n//        FileOutputStream fos = null;\n//        try {\n//            fos = new FileOutputStream(file, true);\n//            fos.write(content.getBytes(\"utf-8\"));\n//            fos.flush();\n//        } catch (Exception e) {\n//            logger.error(e.getMessage(), e);\n//        } finally {\n//            if (fos != null) {\n//                try {\n//                    fos.close();\n//                } catch (IOException e) {\n//                    logger.error(e.getMessage(), e);\n//                }\n//            }\n//        }\n//\n//    }\n//\n//    public static List<String> loadFileLines(String fileName){\n//\n//        List<String> result = new ArrayList<>();\n//\n//        // valid log file\n//        File file = new File(fileName);\n//        if (!file.exists()) {\n//            return result;\n//        }\n//\n//        // read file\n//        StringBuffer logContentBuffer = new StringBuffer();\n//        int toLineNum = 0;\n//        LineNumberReader reader = null;\n//        try {\n//            //reader = new LineNumberReader(new FileReader(logFile));\n//            reader = new LineNumberReader(new InputStreamReader(new FileInputStream(file), \"utf-8\"));\n//            String line = null;\n//            while ((line = reader.readLine())!=null) {\n//                if (line!=null && line.trim().length()>0) {\n//                    result.add(line);\n//                }\n//            }\n//        } catch (IOException e) {\n//            logger.error(e.getMessage(), e);\n//        } finally {\n//            if (reader != null) {\n//                try {\n//                    reader.close();\n//                } catch (IOException e) {\n//                    logger.error(e.getMessage(), e);\n//                }\n//            }\n//        }\n//\n//        return result;\n//    }*/\n//\n//}\n"
  },
  {
    "path": "xxl-job-core/src/main/java/com/xxl/job/core/util/deprecated/GsonTool.java",
    "content": "//package com.xxl.job.core.util;\n//\n//import com.google.gson.Gson;\n//import com.google.gson.GsonBuilder;\n//import com.google.gson.JsonElement;\n//import com.google.gson.reflect.TypeToken;\n//\n//import java.lang.reflect.Type;\n//import java.util.ArrayList;\n//import java.util.HashMap;\n//\n///**\n// * gson tool （From https://github.com/xuxueli/xxl-tool ）\n// *\n// * @author xuxueli 2020-04-11 20:56:31\n// */\n//public class GsonTool {\n//\n//    private static Gson gson = null;\n//    static {\n//        gson= new GsonBuilder().setDateFormat(\"yyyy-MM-dd HH:mm:ss\").disableHtmlEscaping().create();\n//    }\n//\n//    /**\n//     * Object 转成 json\n//     *\n//     * <pre>\n//     *     String json = GsonTool.toJson(new Demo());\n//     * </pre>\n//     *\n//     * @param src\n//     * @return String\n//     */\n//    public static String toJson(Object src) {\n//        return gson.toJson(src);\n//    }\n//\n//    /**\n//     * json 转成 特定的cls的Object\n//     *\n//     * <pre>\n//     *     Demo demo = GsonTool.fromJson(json, Demo.class);\n//     * </pre>\n//     *\n//     * @param json\n//     * @param classOfT\n//     * @return\n//     */\n//    public static <T> T fromJson(String json, Class<T> classOfT) {\n//        return gson.fromJson(json, classOfT);\n//    }\n//\n//    /**\n//     * json 转成 特定的 rawClass<classOfT> 的Object\n//     *\n//     * <pre>\n//     *     Response<Demo> response = GsonTool.fromJson(json, Response.class, Demo.class);\n//     * </pre>\n//     *\n//     * @param json\n//     * @param classOfT\n//     * @param argClassOfT\n//     * @return\n//     */\n//    /*public static <T> T fromJson(String json, Class<T> classOfT, Class argClassOfT) {\n//        Type type = new ParameterizedType4ReturnT(classOfT, new Class[]{argClassOfT});\n//        return gson.fromJson(json, type);\n//    }\n//    public static class ParameterizedType4ReturnT implements ParameterizedType {\n//        private final Class raw;\n//        private final Type[] args;\n//        public ParameterizedType4ReturnT(Class raw, Type[] args) {\n//            this.raw = raw;\n//            this.args = args != null ? args : new Type[0];\n//        }\n//        @Override\n//        public Type[] getActualTypeArguments() {\n//            return args;\n//        }\n//        @Override\n//        public Type getRawType() {\n//            return raw;\n//        }\n//        @Override\n//        public Type getOwnerType() {return null;}\n//    }*/\n//\n//    /**\n//     * json 转成 特定的 Type 的Object\n//     *\n//     * @param json\n//     * @param typeOfT\n//     * @return\n//     * @param <T>\n//     */\n//    public static <T> T  fromJson(String json, Type typeOfT) {\n//        return gson.fromJson(json, typeOfT);\n//    }\n//\n//    /**\n//     * json 转成 特定的 Type 的Object\n//     *\n//     * <pre>\n//     *     Response<Demo> response = GsonTool.fromJson(json, Response.class, Demo.class);\n//     * </pre>\n//     *\n//     * @param json\n//     * @param rawType\n//     * @param typeArguments\n//     * @return\n//     */\n//    public static <T> T  fromJson(String json, Type rawType, Type... typeArguments) {\n//        Type type = TypeToken.getParameterized(rawType, typeArguments).getType();\n//        return gson.fromJson(json, type);\n//    }\n//\n//    /**\n//     * json 转成 特定的cls的 ArrayList\n//     *\n//     * <pre>\n//     *     List<Demo> demoList = GsonTool.fromJsonList(json, Demo.class);\n//     * </pre>\n//     *\n//     * @param json\n//     * @param classOfT\n//     * @return\n//     */\n//    public static <T> ArrayList<T> fromJsonList(String json, Class<T> classOfT) {\n//        Type type = TypeToken.getParameterized(ArrayList.class, classOfT).getType();\n//        return gson.fromJson(json, type);\n//    }\n//\n//    /**\n//     * json 转成 特定的cls的 HashMap\n//     *\n//     * <pre>\n//     *     HashMap<String, Demo> map = GsonTool.fromJsonMap(json, String.class, Demo.class);\n//     * </pre>\n//     *\n//     * @param json\n//     * @param keyClass\n//     * @param valueClass\n//     * @return\n//     * @param <K>\n//     * @param <V>\n//     */\n//    public static <K, V> HashMap<K, V> fromJsonMap(String json, Class<K> keyClass, Class<V> valueClass) {\n//        Type type = TypeToken.getParameterized(HashMap.class, keyClass, valueClass).getType();\n//        return gson.fromJson(json, type);\n//    }\n//\n//    // ---------------------------------\n//\n//    /**\n//     * Object 转成 JsonElement\n//     *\n//     * @param src\n//     * @return\n//     */\n//    public static JsonElement toJsonElement(Object src) {\n//        return gson.toJsonTree(src);\n//    }\n//\n//    /**\n//     * JsonElement 转成 特定的cls的Object\n//     *\n//     * @param json\n//     * @param classOfT\n//     * @return\n//     * @param <T>\n//     */\n//    public static <T> T fromJsonElement(JsonElement json, Class<T> classOfT) {\n//        return gson.fromJson(json, classOfT);\n//    }\n//\n//    /**\n//     * JsonElement 转成 特定的 rawClass<classOfT> 的Object\n//     *\n//     * @param json\n//     * @param typeOfT\n//     * @return\n//     * @param <T>\n//     */\n//    public static <T> T fromJsonElement(JsonElement json, Type typeOfT) {\n//        return gson.fromJson(json, typeOfT);\n//    }\n//\n//    /**\n//     * JsonElement 转成 特定的 Type 的 Object\n//     *\n//     * @param json\n//     * @param rawType\n//     * @param typeArguments\n//     * @return\n//     * @param <T>\n//     */\n//    public static <T> T fromJsonElement(JsonElement json, Type rawType, Type... typeArguments) {\n//        Type typeOfT = TypeToken.getParameterized(rawType, typeArguments).getType();\n//        return gson.fromJson(json, typeOfT);\n//    }\n//\n//}\n"
  },
  {
    "path": "xxl-job-core/src/main/java/com/xxl/job/core/util/deprecated/IpUtil.java",
    "content": "//package com.xxl.job.core.util;\n//\n//import org.slf4j.Logger;\n//import org.slf4j.LoggerFactory;\n//\n//import java.io.IOException;\n//import java.net.Inet6Address;\n//import java.net.InetAddress;\n//import java.net.NetworkInterface;\n//import java.net.UnknownHostException;\n//import java.util.Enumeration;\n//import java.util.regex.Pattern;\n//\n///**\n// * ip tool\n// *\n// * @author xuxueli 2016-5-22 11:38:05\n// */\n//public class IpUtil {\n//    private static final Logger logger = LoggerFactory.getLogger(IpUtil.class);\n//\n//    private static final String ANYHOST_VALUE = \"0.0.0.0\";\n//    private static final String LOCALHOST_VALUE = \"127.0.0.1\";\n//    private static final Pattern IP_PATTERN = Pattern.compile(\"\\\\d{1,3}(\\\\.\\\\d{1,3}){3,5}$\");\n//\n//\n//\n//    private static volatile InetAddress LOCAL_ADDRESS = null;\n//\n//    // ---------------------- valid ----------------------\n//\n//    private static InetAddress toValidAddress(InetAddress address) {\n//        if (address instanceof Inet6Address) {\n//            Inet6Address v6Address = (Inet6Address) address;\n//            if (isPreferIPV6Address()) {\n//                return normalizeV6Address(v6Address);\n//            }\n//        }\n//        if (isValidV4Address(address)) {\n//            return address;\n//        }\n//        return null;\n//    }\n//\n//    private static boolean isPreferIPV6Address() {\n//        return Boolean.getBoolean(\"java.net.preferIPv6Addresses\");\n//    }\n//\n//    /**\n//     * valid Inet4Address\n//     *\n//     * @param address\n//     * @return\n//     */\n//    private static boolean isValidV4Address(InetAddress address) {\n//        if (address == null || address.isLoopbackAddress()) {\n//            return false;\n//        }\n//        String name = address.getHostAddress();\n//        boolean result = (name != null\n//                && IP_PATTERN.matcher(name).matches()\n//                && !ANYHOST_VALUE.equals(name)\n//                && !LOCALHOST_VALUE.equals(name));\n//        return result;\n//    }\n//\n//\n//    /**\n//     * normalize the ipv6 Address, convert scope name to scope id.\n//     * e.g.\n//     * convert\n//     * fe80:0:0:0:894:aeec:f37d:23e1%en0\n//     * to\n//     * fe80:0:0:0:894:aeec:f37d:23e1%5\n//     * <p>\n//     * The %5 after ipv6 address is called scope id.\n//     * see java doc of {@link Inet6Address} for more details.\n//     *\n//     * @param address the input address\n//     * @return the normalized address, with scope id converted to int\n//     */\n//    private static InetAddress normalizeV6Address(Inet6Address address) {\n//        String addr = address.getHostAddress();\n//        int i = addr.lastIndexOf('%');\n//        if (i > 0) {\n//            try {\n//                return InetAddress.getByName(addr.substring(0, i) + '%' + address.getScopeId());\n//            } catch (UnknownHostException e) {\n//                // ignore\n//                logger.debug(\"Unknown IPV6 address: \", e);\n//            }\n//        }\n//        return address;\n//    }\n//\n//    // ---------------------- find ip ----------------------\n//\n//\n//    private static InetAddress getLocalAddress0() {\n//        InetAddress localAddress = null;\n//        // 1、prefer filter NetworkInterface\n//        try {\n//            Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();\n//            if (null == interfaces) {\n//                return localAddress;\n//            }\n//            while (interfaces.hasMoreElements()) {\n//                try {\n//                    NetworkInterface network = interfaces.nextElement();\n//                    if (network.isLoopback() || network.isVirtual() || !network.isUp()) {\n//                        continue;\n//                    }\n//                    Enumeration<InetAddress> addresses = network.getInetAddresses();\n//                    while (addresses.hasMoreElements()) {\n//                        try {\n//                            InetAddress addressItem = toValidAddress(addresses.nextElement());\n//                            if (addressItem != null) {\n//                                try {\n//                                    if(addressItem.isReachable(100)){\n//                                        return addressItem;\n//                                    }\n//                                } catch (IOException e) {\n//                                    // ignore\n//                                }\n//                            }\n//                        } catch (Throwable e) {\n//                            logger.error(e.getMessage(), e);\n//                        }\n//                    }\n//                } catch (Throwable e) {\n//                    logger.error(e.getMessage(), e);\n//                }\n//            }\n//        } catch (Throwable e) {\n//            logger.error(e.getMessage(), e);\n//        }\n//\n//        // 2、getLocalAddress\n//        try {\n//            localAddress = InetAddress.getLocalHost();\n//            InetAddress addressItem = toValidAddress(localAddress);\n//            if (addressItem != null) {\n//                return addressItem;\n//            }\n//        } catch (Throwable e) {\n//            logger.error(e.getMessage(), e);\n//        }\n//\n//        return localAddress;\n//    }\n//\n//\n//    // ---------------------- tool ----------------------\n//\n//    /**\n//     * Find first valid IP from local network card\n//     *\n//     * @return first valid local IP\n//     */\n//    public static InetAddress getLocalAddress() {\n//        if (LOCAL_ADDRESS != null) {\n//            return LOCAL_ADDRESS;\n//        }\n//        InetAddress localAddress = getLocalAddress0();\n//        LOCAL_ADDRESS = localAddress;\n//        return localAddress;\n//    }\n//\n//    /**\n//     * get ip address\n//     *\n//     * @return String\n//     */\n//    public static String getIp(){\n//        return getLocalAddress().getHostAddress();\n//    }\n//\n//    /**\n//     * get ip:port\n//     *\n//     * @param port\n//     * @return String\n//     */\n//    public static String getIpPort(int port){\n//        String ip = getIp();\n//        return getIpPort(ip, port);\n//    }\n//\n//    public static String getIpPort(String ip, int port){\n//        if (ip==null) {\n//            return null;\n//        }\n//        return ip.concat(\":\").concat(String.valueOf(port));\n//    }\n//\n//    public static Object[] parseIpPort(String address){\n//        String[] array = address.split(\":\");\n//\n//        String host = array[0];\n//        int port = Integer.parseInt(array[1]);\n//\n//        return new Object[]{host, port};\n//    }\n//\n//\n//}\n"
  },
  {
    "path": "xxl-job-core/src/main/java/com/xxl/job/core/util/deprecated/JdkSerializeTool.java",
    "content": "//package com.xxl.job.core.util;\n//\n//import org.slf4j.Logger;\n//import org.slf4j.LoggerFactory;\n//\n//import java.io.*;\n//\n///**\n// * @author xuxueli 2020-04-12 0:14:00\n// */\n//public class JdkSerializeTool {\n//    private static Logger logger = LoggerFactory.getLogger(JdkSerializeTool.class);\n//\n//\n//    // ------------------------ serialize and unserialize ------------------------\n//\n//    /**\n//     * 将对象-->byte[] (由于jedis中不支持直接存储object所以转换成byte[]存入)\n//     *\n//     * @param object\n//     * @return\n//     */\n//    public static byte[] serialize(Object object) {\n//        ObjectOutputStream oos = null;\n//        ByteArrayOutputStream baos = null;\n//        try {\n//            // 序列化\n//            baos = new ByteArrayOutputStream();\n//            oos = new ObjectOutputStream(baos);\n//            oos.writeObject(object);\n//            byte[] bytes = baos.toByteArray();\n//            return bytes;\n//        } catch (Exception e) {\n//            logger.error(e.getMessage(), e);\n//        } finally {\n//            try {\n//                oos.close();\n//                baos.close();\n//            } catch (IOException e) {\n//                logger.error(e.getMessage(), e);\n//            }\n//        }\n//        return null;\n//    }\n//\n//\n//    /**\n//     * 将byte[] -->Object\n//     *\n//     * @param bytes\n//     * @return\n//     */\n//    public static  <T> Object deserialize(byte[] bytes, Class<T> clazz) {\n//        ObjectInputStream ois = null;\n//        ByteArrayInputStream bais = null;\n//        try {\n//            // 反序列化\n//            bais = new ByteArrayInputStream(bytes);\n//            ois = new ObjectInputStream(bais);\n//            return ois.readObject();\n//        } catch (Exception e) {\n//            logger.error(e.getMessage(), e);\n//        } finally {\n//            try {\n//                ois.close();\n//                bais.close();\n//            } catch (IOException e) {\n//                logger.error(e.getMessage(), e);\n//            }\n//        }\n//        return null;\n//    }\n//\n//\n//}\n"
  },
  {
    "path": "xxl-job-core/src/main/java/com/xxl/job/core/util/deprecated/NetUtil.java",
    "content": "//package com.xxl.job.core.util;\n//\n//import org.slf4j.Logger;\n//import org.slf4j.LoggerFactory;\n//\n//import java.io.IOException;\n//import java.net.ServerSocket;\n//\n///**\n// * net util\n// *\n// * @author xuxueli 2017-11-29 17:00:25\n// */\n//public class NetUtil {\n//    private static Logger logger = LoggerFactory.getLogger(NetUtil.class);\n//\n//    /**\n//     * find available port\n//     *\n//     * @param defaultPort\n//     * @return\n//     */\n//    public static int findAvailablePort(int defaultPort) {\n//        int portTmp = defaultPort;\n//        while (portTmp < 65535) {\n//            if (!isPortUsed(portTmp)) {\n//                return portTmp;\n//            } else {\n//                portTmp++;\n//            }\n//        }\n//        portTmp = defaultPort - 1;\n//        while (portTmp > 0) {\n//            if (!isPortUsed(portTmp)) {\n//                return portTmp;\n//            } else {\n//                portTmp--;\n//            }\n//        }\n//        throw new RuntimeException(\"no available port.\");\n//    }\n//\n//    /**\n//     * check port used\n//     *\n//     * @param port\n//     * @return\n//     */\n//    public static boolean isPortUsed(int port) {\n//        boolean used = false;\n//        ServerSocket serverSocket = null;\n//        try {\n//            serverSocket = new ServerSocket(port);\n//            used = false;\n//        } catch (IOException e) {\n//            logger.info(\">>>>>>>>>>> xxl-job, port[{}] is in use.\", port);\n//            used = true;\n//        } finally {\n//            if (serverSocket != null) {\n//                try {\n//                    serverSocket.close();\n//                } catch (IOException e) {\n//                    logger.info(\"\");\n//                }\n//            }\n//        }\n//        return used;\n//    }\n//\n//}\n"
  },
  {
    "path": "xxl-job-core/src/main/java/com/xxl/job/core/util/deprecated/ReturnT.java",
    "content": "//package com.xxl.job.core.openapi.model;\n//\n//import java.io.Serializable;\n//\n///**\n// * common return\n// *\n// * @author xuxueli 2015-12-4 16:32:31\n// * @param <T>\n// */\n//public class ReturnT<T> implements Serializable {\n//\tpublic static final long serialVersionUID = 42L;\n//\n//\tprivate int code;\n//\n//\tprivate String msg;\n//\n//\tprivate T content;\n//\n//\tpublic ReturnT(){}\n//\n//\tpublic ReturnT(int code, String msg) {\n//\t\tthis.code = code;\n//\t\tthis.msg = msg;\n//\t}\n//\n//\tpublic ReturnT(int code, String msg, T content) {\n//\t\tthis.code = code;\n//\t\tthis.msg = msg;\n//\t\tthis.content = content;\n//\t}\n//\n//\tpublic int getCode() {\n//\t\treturn code;\n//\t}\n//\n//\tpublic void setCode(int code) {\n//\t\tthis.code = code;\n//\t}\n//\n//\tpublic String getMsg() {\n//\t\treturn msg;\n//\t}\n//\n//\tpublic void setMsg(String msg) {\n//\t\tthis.msg = msg;\n//\t}\n//\n//\tpublic T getContent() {\n//\t\treturn content;\n//\t}\n//\n//\tpublic void setContent(T content) {\n//\t\tthis.content = content;\n//\t}\n//\n//\t@Override\n//\tpublic String toString() {\n//\t\treturn \"ReturnT{\" +\n//\t\t\t\t\"code=\" + code +\n//\t\t\t\t\", msg='\" + msg + '\\'' +\n//\t\t\t\t\", content=\" + content +\n//\t\t\t\t'}';\n//\t}\n//\n//\n//\t// --------------------------- tool ---------------------------\n//\n//\tpublic static final int SUCCESS_CODE = 200;\n//\tpublic static final int FAIL_CODE = 500;\n//\n//\t/**\n//\t * is success\n//\t *\n//\t * @return\n//\t */\n//\tpublic boolean isSuccess() {\n//\t\treturn code == SUCCESS_CODE;\n//\t}\n//\n//\tpublic static <T> ReturnT<T> of(int code, String msg, T data) {\n//\t\treturn new ReturnT<T>(code, msg, data);\n//\t}\n//\tpublic static <T> ReturnT<T> of(int code, String msg) {\n//\t\treturn new ReturnT<T>(code, msg, null);\n//\t}\n//\n//\tpublic static <T> ReturnT<T> ofSuccess(T data) {\n//\t\treturn new ReturnT<T>(SUCCESS_CODE, \"Success\", data);\n//\t}\n//\n//\tpublic static <T> ReturnT<T> ofSuccess() {\n//\t\treturn new ReturnT<T>(SUCCESS_CODE, \"Success\", null);\n//\t}\n//\n//\tpublic static <T> ReturnT<T> ofFail(String msg) {\n//\t\treturn new ReturnT<T>(FAIL_CODE, msg, null);\n//\t}\n//\tpublic static <T> ReturnT<T> ofFail() {\n//\t\treturn new ReturnT<T>(FAIL_CODE, \"Fail\", null);\n//\t}\n//\n//}\n"
  },
  {
    "path": "xxl-job-core/src/main/java/com/xxl/job/core/util/deprecated/ShardingUtil.java",
    "content": "//package com.xxl.job.core.util;\n//\n///**\n// * sharding vo\n// * @author xuxueli 2017-07-25 21:26:38\n// */\n//public class ShardingUtil {\n//\n//    private static InheritableThreadLocal<ShardingVO> contextHolder = new InheritableThreadLocal<ShardingVO>();\n//\n//    public static class ShardingVO {\n//\n//        private int index;  // sharding index\n//        private int total;  // sharding total\n//\n//        public ShardingVO(int index, int total) {\n//            this.index = index;\n//            this.total = total;\n//        }\n//\n//        public int getIndex() {\n//            return index;\n//        }\n//\n//        public void setIndex(int index) {\n//            this.index = index;\n//        }\n//\n//        public int getTotal() {\n//            return total;\n//        }\n//\n//        public void setTotal(int total) {\n//            this.total = total;\n//        }\n//    }\n//\n//    public static void setShardingVo(ShardingVO shardingVo){\n//        contextHolder.set(shardingVo);\n//    }\n//\n//    public static ShardingVO getShardingVo(){\n//        return contextHolder.get();\n//    }\n//\n//}\n"
  },
  {
    "path": "xxl-job-core/src/main/java/com/xxl/job/core/util/deprecated/ThrowableUtil.java",
    "content": "//package com.xxl.job.core.util;\n//\n//import java.io.PrintWriter;\n//import java.io.StringWriter;\n//\n///**\n// * @author xuxueli 2018-10-20 20:07:26\n// */\n//public class ThrowableUtil {\n//\n//    /**\n//     * parse error to string\n//     *\n//     * @param e\n//     * @return\n//     */\n//    public static String toString(Throwable e) {\n//        StringWriter stringWriter = new StringWriter();\n//        e.printStackTrace(new PrintWriter(stringWriter));\n//        String errorMsg = stringWriter.toString();\n//        return errorMsg;\n//    }\n//\n//}\n"
  },
  {
    "path": "xxl-job-core/src/main/java/com/xxl/job/core/util/deprecated/XxlJobRemotingUtil.java",
    "content": "//package com.xxl.job.core.util;\n//\n//import com.xxl.tool.gson.GsonTool;\n//import com.xxl.tool.response.Response;\n//import org.slf4j.Logger;\n//import org.slf4j.LoggerFactory;\n//\n//import javax.net.ssl.*;\n//import java.io.BufferedReader;\n//import java.io.DataOutputStream;\n//import java.io.InputStreamReader;\n//import java.net.HttpURLConnection;\n//import java.net.URL;\n//import java.security.cert.CertificateException;\n//import java.security.cert.X509Certificate;\n//\n///**\n// * @author xuxueli 2018-11-25 00:55:31\n// */\n//public class XxlJobRemotingUtil {\n//    private static Logger logger = LoggerFactory.getLogger(XxlJobRemotingUtil.class);\n//    public static final String XXL_JOB_ACCESS_TOKEN = \"XXL-JOB-ACCESS-TOKEN\";\n//\n//\n//    // trust-https start\n//    private static void trustAllHosts(HttpsURLConnection connection) {\n//        try {\n//            SSLContext sc = SSLContext.getInstance(\"TLS\");\n//            sc.init(null, trustAllCerts, new java.security.SecureRandom());\n//            SSLSocketFactory newFactory = sc.getSocketFactory();\n//\n//            connection.setSSLSocketFactory(newFactory);\n//        } catch (Exception e) {\n//            logger.error(e.getMessage(), e);\n//        }\n//        connection.setHostnameVerifier(new HostnameVerifier() {\n//            @Override\n//            public boolean verify(String hostname, SSLSession session) {\n//                return true;\n//            }\n//        });\n//    }\n//    private static final TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {\n//        @Override\n//        public java.security.cert.X509Certificate[] getAcceptedIssuers() {\n//            return new java.security.cert.X509Certificate[]{};\n//        }\n//        @Override\n//        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {\n//        }\n//        @Override\n//        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {\n//        }\n//    }};\n//    // trust-https end\n//\n//\n//    /**\n//     * post\n//     *\n//     * @param url\n//     * @param accessToken\n//     * @param timeout           by second\n//     * @param requestObj\n//     * @param returnTargClassOfT\n//     * @return\n//     */\n//    public static Response postBody(String url, String accessToken, int timeout, Object requestObj, Class returnTargClassOfT) {\n//        HttpURLConnection connection = null;\n//        BufferedReader bufferedReader = null;\n//        DataOutputStream dataOutputStream = null;\n//        try {\n//            // connection\n//            URL realUrl = new URL(url);\n//            connection = (HttpURLConnection) realUrl.openConnection();\n//\n//            // trust-https\n//            boolean useHttps = url.startsWith(\"https\");\n//            if (useHttps) {\n//                HttpsURLConnection https = (HttpsURLConnection) connection;\n//                trustAllHosts(https);\n//            }\n//\n//            // connection setting\n//            connection.setRequestMethod(\"POST\");\n//            connection.setDoOutput(true);\n//            connection.setDoInput(true);\n//            connection.setUseCaches(false);\n//            connection.setReadTimeout(timeout * 1000);\n//            connection.setConnectTimeout(timeout * 1000);\n//            connection.setRequestProperty(\"connection\", \"Keep-Alive\");\n//            connection.setRequestProperty(\"Content-Type\", \"application/json;charset=UTF-8\");\n//            connection.setRequestProperty(\"Accept-Charset\", \"application/json;charset=UTF-8\");\n//\n//            if(accessToken!=null && !accessToken.trim().isEmpty()){\n//                connection.setRequestProperty(XXL_JOB_ACCESS_TOKEN, accessToken);\n//            }\n//\n//            // do connection\n//            connection.connect();\n//\n//            // write requestBody\n//            if (requestObj != null) {\n//                String requestBody = GsonTool.toJson(requestObj);\n//\n//                dataOutputStream = new DataOutputStream(connection.getOutputStream());\n//                dataOutputStream.write(requestBody.getBytes(\"UTF-8\"));\n//                dataOutputStream.flush();\n//                dataOutputStream.close();\n//            }\n//\n//            /*byte[] requestBodyBytes = requestBody.getBytes(\"UTF-8\");\n//            connection.setRequestProperty(\"Content-Length\", String.valueOf(requestBodyBytes.length));\n//            OutputStream outwritestream = connection.getOutputStream();\n//            outwritestream.write(requestBodyBytes);\n//            outwritestream.flush();\n//            outwritestream.close();*/\n//\n//            // valid StatusCode\n//            int statusCode = connection.getResponseCode();\n//            if (statusCode != 200) {\n//                return Response.ofFail(\"xxl-job remoting fail, StatusCode(\"+ statusCode +\") invalid. for url : \" + url);\n//            }\n//\n//            // result\n//            bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream(), \"UTF-8\"));\n//            StringBuilder result = new StringBuilder();\n//            String line;\n//            while ((line = bufferedReader.readLine()) != null) {\n//                result.append(line);\n//            }\n//            String resultJson = result.toString();\n//\n//            // parse returnT\n//            try {\n//                Response returnT = GsonTool.fromJson(resultJson, Response.class, returnTargClassOfT);\n//                return returnT;\n//            } catch (Exception e) {\n//                logger.error(\"xxl-job remoting (url=\"+url+\") response content invalid(\"+ resultJson +\").\", e);\n//                return Response.ofFail(\"xxl-job remoting (url=\"+url+\") response content invalid(\"+ resultJson +\").\");\n//            }\n//\n//        } catch (Exception e) {\n//            logger.error(e.getMessage(), e);\n//            return Response.ofFail(\"xxl-job remoting error(\"+ e.getMessage() +\"), for url : \" + url);\n//        } finally {\n//            try {\n//                if (dataOutputStream != null) {\n//                    dataOutputStream.close();\n//                }\n//                if (bufferedReader != null) {\n//                    bufferedReader.close();\n//                }\n//                if (connection != null) {\n//                    connection.disconnect();\n//                }\n//            } catch (Exception e2) {\n//                logger.error(e2.getMessage(), e2);\n//            }\n//        }\n//    }\n//\n//}\n"
  },
  {
    "path": "xxl-job-executor-samples/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>com.xuxueli</groupId>\n        <artifactId>xxl-job</artifactId>\n        <version>3.4.0-SNAPSHOT</version>\n    </parent>\n    <artifactId>xxl-job-executor-samples</artifactId>\n    <packaging>pom</packaging>\n\n    <modules>\n        <module>xxl-job-executor-sample-frameless</module>\n        <module>xxl-job-executor-sample-springboot</module>\n        <module>xxl-job-executor-sample-springboot-ai</module>\n    </modules>\n\n    <properties>\n        <maven.install.skip>true</maven.install.skip>\n        <maven.deploy.skip>true</maven.deploy.skip>\n    </properties>\n\n</project>"
  },
  {
    "path": "xxl-job-executor-samples/xxl-job-executor-sample-frameless/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>com.xuxueli</groupId>\n        <artifactId>xxl-job-executor-samples</artifactId>\n        <version>3.4.0-SNAPSHOT</version>\n    </parent>\n    <artifactId>xxl-job-executor-sample-frameless</artifactId>\n    <packaging>jar</packaging>\n\n    <name>${project.artifactId}</name>\n    <description>Example executor project for spring boot.</description>\n    <url>https://www.xuxueli.com/</url>\n\n\n    <dependencies>\n\n        <!-- slf4j -->\n        <dependency>\n            <groupId>org.slf4j</groupId>\n            <artifactId>slf4j-reload4j</artifactId>\n        </dependency>\n        <!-- junit -->\n        <dependency>\n            <groupId>org.junit.jupiter</groupId>\n            <artifactId>junit-jupiter-engine</artifactId>\n            <scope>test</scope>\n        </dependency>\n\n        <!-- xxl-job-core -->\n        <dependency>\n            <groupId>com.xuxueli</groupId>\n            <artifactId>xxl-job-core</artifactId>\n        </dependency>\n\n    </dependencies>\n\n\n</project>"
  },
  {
    "path": "xxl-job-executor-samples/xxl-job-executor-sample-frameless/src/main/java/com/xxl/job/executor/sample/frameless/XxlJobFramelessApplication.java",
    "content": "package com.xxl.job.executor.sample.frameless;\n\nimport com.xxl.job.executor.sample.frameless.config.FrameLessXxlJobConfig;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.concurrent.TimeUnit;\n\n/**\n * @author xuxueli 2018-10-31 19:05:43\n */\npublic class XxlJobFramelessApplication {\n    private static final Logger logger = LoggerFactory.getLogger(XxlJobFramelessApplication.class);\n\n    public static void main(String[] args) {\n\n        try {\n            // start\n            FrameLessXxlJobConfig.getInstance().initXxlJobExecutor();\n\n            // Blocks until interrupted\n            while (true) {\n                try {\n                    TimeUnit.HOURS.sleep(1);\n                } catch (InterruptedException e) {\n                    break;\n                }\n            }\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n        } finally {\n            // destroy\n            FrameLessXxlJobConfig.getInstance().destroyXxlJobExecutor();\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-executor-samples/xxl-job-executor-sample-frameless/src/main/java/com/xxl/job/executor/sample/frameless/config/FrameLessXxlJobConfig.java",
    "content": "package com.xxl.job.executor.sample.frameless.config;\n\nimport com.xxl.job.executor.sample.frameless.jobhandler.SampleXxlJob;\nimport com.xxl.job.core.executor.impl.XxlJobSimpleExecutor;\nimport com.xxl.tool.core.PropTool;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.Arrays;\nimport java.util.Properties;\n\n/**\n * @author xuxueli 2018-10-31 19:05:43\n */\npublic class FrameLessXxlJobConfig {\n    private static final Logger logger = LoggerFactory.getLogger(FrameLessXxlJobConfig.class);\n\n\n    private static final FrameLessXxlJobConfig instance = new FrameLessXxlJobConfig();\n    public static FrameLessXxlJobConfig getInstance() {\n        return instance;\n    }\n\n\n    private XxlJobSimpleExecutor xxlJobExecutor = null;\n\n    /**\n     * init\n     */\n    public void initXxlJobExecutor() {\n\n        // load executor prop\n        Properties xxlJobProp = PropTool.loadProp(\"xxl-job-executor.properties\");\n\n        // init executor\n        xxlJobExecutor = new XxlJobSimpleExecutor();\n        xxlJobExecutor.setAdminAddresses(xxlJobProp.getProperty(\"xxl.job.admin.addresses\"));\n        xxlJobExecutor.setAccessToken(xxlJobProp.getProperty(\"xxl.job.admin.accessToken\"));\n        xxlJobExecutor.setTimeout(Integer.valueOf(xxlJobProp.getProperty(\"xxl.job.admin.timeout\")));\n        xxlJobExecutor.setEnabled(Boolean.valueOf(xxlJobProp.getProperty(\"xxl.job.executor.enabled\")));\n        xxlJobExecutor.setAppname(xxlJobProp.getProperty(\"xxl.job.executor.appname\"));\n        xxlJobExecutor.setAddress(xxlJobProp.getProperty(\"xxl.job.executor.address\"));\n        xxlJobExecutor.setIp(xxlJobProp.getProperty(\"xxl.job.executor.ip\"));\n        xxlJobExecutor.setPort(Integer.valueOf(xxlJobProp.getProperty(\"xxl.job.executor.port\")));\n        xxlJobExecutor.setLogPath(xxlJobProp.getProperty(\"xxl.job.executor.logpath\"));\n        xxlJobExecutor.setLogRetentionDays(Integer.valueOf(xxlJobProp.getProperty(\"xxl.job.executor.logretentiondays\")));\n\n        // registry job bean\n        xxlJobExecutor.setXxlJobBeanList(Arrays.asList(new SampleXxlJob()));\n\n        // start executor\n        try {\n            xxlJobExecutor.start();\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n        }\n    }\n\n    /**\n     * destroy\n     */\n    public void destroyXxlJobExecutor() {\n        if (xxlJobExecutor != null) {\n            xxlJobExecutor.destroy();\n        }\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-executor-samples/xxl-job-executor-sample-frameless/src/main/java/com/xxl/job/executor/sample/frameless/jobhandler/SampleXxlJob.java",
    "content": "package com.xxl.job.executor.sample.frameless.jobhandler;\n\nimport com.xxl.job.core.context.XxlJobHelper;\nimport com.xxl.job.core.handler.annotation.XxlJob;\nimport com.xxl.tool.core.StringTool;\nimport com.xxl.tool.json.GsonTool;\nimport com.xxl.tool.http.HttpTool;\nimport com.xxl.tool.http.http.HttpResponse;\nimport com.xxl.tool.http.http.enums.ContentType;\nimport com.xxl.tool.http.http.enums.Method;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.BufferedInputStream;\nimport java.io.BufferedReader;\nimport java.io.InputStreamReader;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * XxlJob开发示例（Bean模式）\n *\n * 开发步骤：\n *      1、任务开发：在Spring Bean实例中，开发Job方法；\n *      2、注解配置：为Job方法添加注解 \"@XxlJob(value=\"自定义jobhandler名称\", init = \"JobHandler初始化方法\", destroy = \"JobHandler销毁方法\")\"，注解value值对应的是调度中心新建任务的JobHandler属性的值。\n *      3、执行日志：需要通过 \"XxlJobHelper.log\" 打印执行日志；\n *      4、任务结果：默认任务结果为 \"成功\" 状态，不需要主动设置；如有诉求，比如设置任务结果为失败，可以通过 \"XxlJobHelper.handleFail/handleSuccess\" 自主设置任务结果；\n *\n * @author xuxueli 2019-12-11 21:52:51\n */\npublic class SampleXxlJob {\n    private static final Logger logger = LoggerFactory.getLogger(SampleXxlJob.class);\n\n\n    /**\n     * 1、简单任务示例（Bean模式）\n     */\n    @XxlJob(\"demoJobHandler\")\n    public void demoJobHandler() throws Exception {\n        XxlJobHelper.log(\"XXL-JOB, Hello World.\");\n\n        for (int i = 0; i < 5; i++) {\n            XxlJobHelper.log(\"beat at:\" + i);\n            TimeUnit.SECONDS.sleep(2);\n        }\n        // default success\n    }\n\n\n    /**\n     * 2、分片广播任务\n     */\n    @XxlJob(\"shardingJobHandler\")\n    public void shardingJobHandler() throws Exception {\n\n        // 分片参数\n        int shardIndex = XxlJobHelper.getShardIndex();\n        int shardTotal = XxlJobHelper.getShardTotal();\n\n        XxlJobHelper.log(\"分片参数：当前分片序号 = {}, 总分片数 = {}\", shardIndex, shardTotal);\n\n        // 业务逻辑\n        for (int i = 0; i < shardTotal; i++) {\n            if (i == shardIndex) {\n                XxlJobHelper.log(\"第 {} 片, 命中分片开始处理\", i);\n            } else {\n                XxlJobHelper.log(\"第 {} 片, 忽略\", i);\n            }\n        }\n\n    }\n\n\n    /**\n     * 3、命令行任务\n     *\n     *  参数示例：\"ls -a\" 或者 \"pwd\"\n     */\n    @XxlJob(\"commandJobHandler\")\n    public void commandJobHandler() throws Exception {\n        String command = XxlJobHelper.getJobParam();\n        int exitValue = -1;\n\n        BufferedReader bufferedReader = null;\n        try {\n            // valid\n            if (command==null || command.trim().isEmpty()) {\n                XxlJobHelper.handleFail(\"command empty.\");\n                return;\n            }\n\n            // command split\n            String[] commandArray = command.split(\" \");\n\n            // command process\n            ProcessBuilder processBuilder = new ProcessBuilder();\n            processBuilder.command(commandArray);\n            processBuilder.redirectErrorStream(true);\n\n            Process process = processBuilder.start();\n            //Process process = Runtime.getRuntime().exec(command);\n\n            BufferedInputStream bufferedInputStream = new BufferedInputStream(process.getInputStream());\n            bufferedReader = new BufferedReader(new InputStreamReader(bufferedInputStream));\n\n            // command log\n            String line;\n            while ((line = bufferedReader.readLine()) != null) {\n                XxlJobHelper.log(line);\n            }\n\n            // command exit\n            process.waitFor();\n            exitValue = process.exitValue();\n        } catch (Exception e) {\n            XxlJobHelper.log(e);\n        } finally {\n            if (bufferedReader != null) {\n                bufferedReader.close();\n            }\n        }\n\n        if (exitValue == 0) {\n            // default success\n        } else {\n            XxlJobHelper.handleFail(\"command exit value(\"+exitValue+\") is failed\");\n        }\n\n    }\n\n\n    /**\n     * 4、跨平台Http任务\n     *\n     *  参数示例：\n     *  <pre>\n     *      // 1、简单示例：\n     *      {\n     *          \"url\": \"http://www.baidu.com\",\n     *          \"method\": \"get\",\n     *          \"data\": \"hello world\"\n     *      }\n     *\n     *      // 2、完整参数示例：\n     *      {\n     *          \"url\": \"http://www.baidu.com\",\n     *          \"method\": \"POST\",\n     *          \"contentType\": \"application/json\",\n     *          \"headers\": {\n     *              \"header01\": \"value01\"\n     *          },\n     *          \"cookies\": {\n     *              \"cookie01\": \"value01\"\n     *          },\n     *          \"timeout\": 3000,\n     *          \"data\": \"request body data\",\n     *          \"form\": {\n     *              \"key01\": \"value01\"\n     *          },\n     *          \"auth\": \"auth data\"\n     *      }\n     *  </pre>\n     */\n    @XxlJob(\"httpJobHandler\")\n    public void httpJobHandler() throws Exception {\n\n        // param data\n        String param = XxlJobHelper.getJobParam();\n        if (param==null || param.trim().isEmpty()) {\n            XxlJobHelper.log(\"param[\"+ param +\"] invalid.\");\n\n            XxlJobHelper.handleFail();\n            return;\n        }\n\n        // param parse\n        HttpJobParam httpJobParam = null;\n        try {\n            httpJobParam = GsonTool.fromJson(param, HttpJobParam.class);\n        } catch (Exception e) {\n            XxlJobHelper.log(new RuntimeException(\"HttpJobParam parse error\", e));\n            XxlJobHelper.handleFail();\n            return;\n        }\n\n        // param valid\n        if (httpJobParam == null) {\n            XxlJobHelper.log(\"param parse fail.\");\n            XxlJobHelper.handleFail();\n            return;\n        }\n        if (StringTool.isBlank(httpJobParam.getUrl())) {\n            XxlJobHelper.log(\"url[\"+ httpJobParam.getUrl() +\"] invalid.\");\n            XxlJobHelper.handleFail();\n            return;\n        }\n        if (!isValidDomain(httpJobParam.getUrl())) {\n            XxlJobHelper.log(\"url[\"+ httpJobParam.getUrl() +\"] not allowed.\");\n            XxlJobHelper.handleFail();\n            return;\n        }\n        Method method = Method.POST;\n        if (StringTool.isNotBlank(httpJobParam.getMethod())) {\n            Method methodParam = Method.valueOf(httpJobParam.getMethod().toUpperCase());\n            if (methodParam == null) {\n                XxlJobHelper.log(\"method[\"+ httpJobParam.getMethod() +\"] invalid.\");\n                XxlJobHelper.handleFail();\n                return;\n            }\n            method = methodParam;\n        }\n        ContentType contentType = ContentType.JSON;\n        if (StringTool.isNotBlank(httpJobParam.getContentType())) {\n            for (ContentType contentTypeParam : ContentType.values()) {\n                if (contentTypeParam.getValue().equals(httpJobParam.getContentType())) {\n                    contentType = contentTypeParam;\n                    break;\n                }\n            }\n        }\n        if (httpJobParam.getTimeout() <= 0) {\n            httpJobParam.setTimeout(3000);\n        }\n\n        // do request\n        try {\n            HttpResponse httpResponse = HttpTool.createRequest()\n                    .url(httpJobParam.getUrl())\n                    .method(method)\n                    .contentType(contentType)\n                    .header(httpJobParam.getHeaders())\n                    .cookie(httpJobParam.getCookies())\n                    .body(httpJobParam.getData())\n                    .form(httpJobParam.getForm())\n                    .auth(httpJobParam.getAuth())\n                    .execute();\n\n            XxlJobHelper.log(\"StatusCode: \" + httpResponse.statusCode());\n            XxlJobHelper.log(\"Response: <br>\" + httpResponse.response());\n        } catch (Exception e) {\n            XxlJobHelper.log(e);\n            XxlJobHelper.handleFail();\n        }\n    }\n\n    /**\n     * domain white-list, for httpJobHandler\n     */\n    private static Set<String> DOMAIN_WHITE_LIST = Set.of(\n            \"http://www.baidu.com\",\n            \"http://cn.bing.com\"\n    );\n\n    /**\n     * valid if domain is in white-list\n     */\n    private boolean isValidDomain(String url) {\n        if (url == null || DOMAIN_WHITE_LIST.isEmpty()) {\n            return false;\n        }\n        for (String prefix : DOMAIN_WHITE_LIST) {\n            if (url.startsWith(prefix)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /*public static void main(String[] args) {\n        HttpJobParam httpJobParam = new HttpJobParam();\n        httpJobParam.setUrl(\"http://www.baidu.com\");\n        httpJobParam.setMethod(Method.POST.name());\n        httpJobParam.setContentType(ContentType.JSON.getValue());\n        httpJobParam.setHeaders(Map.of(\"header01\", \"value01\"));\n        httpJobParam.setCookies(Map.of(\"cookie01\", \"value01\"));\n        httpJobParam.setTimeout(3000);\n        httpJobParam.setData(\"request body data\");\n        httpJobParam.setForm(Map.of(\"form01\", \"value01\"));\n        httpJobParam.setAuth(\"auth data\");\n\n        logger.info(GsonTool.toJson(httpJobParam));\n    }*/\n\n    /**\n     * http job param\n     */\n    private static class HttpJobParam{\n        private String url;                                     // 请求 Url\n        private String method;                                  // Method\n        private String contentType;                             // Content-Type\n        private Map<String, String> headers;                    // 存储请求头\n        private Map<String, String> cookies;                    // Cookie（需要格式转换）\n        private int timeout;                                    // 请求超时时间\n        private String data;                                    // 存储请求体\n        private Map<String, String> form;                       // 存储表单数据\n        private String auth;                                    // 鉴权信息\n\n        public String getUrl() {\n            return url;\n        }\n\n        public void setUrl(String url) {\n            this.url = url;\n        }\n\n        public String getMethod() {\n            return method;\n        }\n\n        public void setMethod(String method) {\n            this.method = method;\n        }\n\n        public String getContentType() {\n            return contentType;\n        }\n\n        public void setContentType(String contentType) {\n            this.contentType = contentType;\n        }\n\n        public Map<String, String> getHeaders() {\n            return headers;\n        }\n\n        public void setHeaders(Map<String, String> headers) {\n            this.headers = headers;\n        }\n\n        public Map<String, String> getCookies() {\n            return cookies;\n        }\n\n        public void setCookies(Map<String, String> cookies) {\n            this.cookies = cookies;\n        }\n\n        public int getTimeout() {\n            return timeout;\n        }\n\n        public void setTimeout(int timeout) {\n            this.timeout = timeout;\n        }\n\n        public String getData() {\n            return data;\n        }\n\n        public void setData(String data) {\n            this.data = data;\n        }\n\n        public Map<String, String> getForm() {\n            return form;\n        }\n\n        public void setForm(Map<String, String> form) {\n            this.form = form;\n        }\n\n        public String getAuth() {\n            return auth;\n        }\n\n        public void setAuth(String auth) {\n            this.auth = auth;\n        }\n    }\n\n\n    /**\n     * 5、生命周期任务示例：任务初始化与销毁时，支持自定义相关逻辑；\n     */\n    @XxlJob(value = \"demoJobHandler2\", init = \"init\", destroy = \"destroy\")\n    public void demoJobHandler2() throws Exception {\n        XxlJobHelper.log(\"XXL-JOB, Hello World.\");\n    }\n    public void init(){\n        logger.info(\"init\");\n    }\n    public void destroy(){\n        logger.info(\"destroy\");\n    }\n\n\n}\n"
  },
  {
    "path": "xxl-job-executor-samples/xxl-job-executor-sample-frameless/src/main/resources/log4j.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE log4j:configuration PUBLIC \"-//log4j/log4j Configuration//EN\" \"log4j.dtd\">\n<log4j:configuration xmlns:log4j=\"http://jakarta.apache.org/log4j/\" threshold=\"null\" debug=\"null\">\n\n\t<appender name=\"CONSOLE\" class=\"org.apache.log4j.ConsoleAppender\">\n\t\t<param name=\"Target\" value=\"System.out\" />\n\t\t<layout class=\"org.apache.log4j.PatternLayout\">\n            <param name=\"ConversionPattern\" value=\"%-d{yyyy-MM-dd HH:mm:ss} xxl-job-executor-sample-frameless [%c]-[%t]-[%M]-[%L]-[%p] %m%n\"/>\n\t\t</layout>\n\t</appender>\n\t\n    <appender name=\"FILE\" class=\"org.apache.log4j.DailyRollingFileAppender\">\n        <param name=\"file\" value=\"/data/applogs/xxl-job/xxl-job-executor-sample-frameless.log\"/>\n        <param name=\"append\" value=\"true\"/>\n        <param name=\"encoding\" value=\"UTF-8\"/>\n        <layout class=\"org.apache.log4j.PatternLayout\">\n            <param name=\"ConversionPattern\" value=\"%-d{yyyy-MM-dd HH:mm:ss} xxl-job-executor-sample-frameless [%c]-[%t]-[%M]-[%L]-[%p] %m%n\"/>\n        </layout>\n    </appender>\n\n    <root>\n        <level value=\"INFO\" />\n        <appender-ref ref=\"CONSOLE\" />\n        <appender-ref ref=\"FILE\" />\n    </root>\n\n</log4j:configuration>"
  },
  {
    "path": "xxl-job-executor-samples/xxl-job-executor-sample-frameless/src/main/resources/xxl-job-executor.properties",
    "content": "### xxl-job admin address list, such as \"http://address\" or \"http://address01,http://address02\"\nxxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin\n### xxl-job access token\nxxl.job.admin.accessToken=default_token\n### xxl-job timeout by second, default 3s\nxxl.job.admin.timeout=3\n\n### xxl-job executor enable, default true\nxxl.job.executor.enabled=true\n### xxl-job executor appname\nxxl.job.executor.appname=xxl-job-executor-sample\n### xxl-job executor registry-address: default use address to registry , otherwise use ip:port if address is null\nxxl.job.executor.address=\n### xxl-job executor server-info\nxxl.job.executor.ip=\nxxl.job.executor.port=9998\n### xxl-job executor log-path\nxxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler\n### xxl-job executor log-retention-days\nxxl.job.executor.logretentiondays=30"
  },
  {
    "path": "xxl-job-executor-samples/xxl-job-executor-sample-frameless/src/test/java/com/xxl/job/executor/sample/frameless/test/FramelessApplicationTest.java",
    "content": "package com.xxl.job.executor.sample.frameless.test;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.DisplayName;\nimport org.junit.jupiter.api.Test;\nimport org.junit.platform.commons.annotation.Testable;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n@Testable\npublic class FramelessApplicationTest {\n    private static final Logger logger = LoggerFactory.getLogger(FramelessApplicationTest.class);\n\n    @Test\n    @DisplayName(\"test1\")\n    public void test1(){\n        logger.info(\"111\");\n        Assertions.assertNull( null);\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-executor-samples/xxl-job-executor-sample-springboot/Dockerfile",
    "content": "# base image\nFROM openjdk:21-jdk-slim\n\n# maintainer\nMAINTAINER xuxueli\n\n# set params\nENV PARAMS=\"\"\n\n# set timezone\nENV TZ=PRC\nRUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone\n\n# copy jar\nADD target/xxl-job-executor-sample-springboot-*.jar /app.jar\n\n# command\n# log home: -e LOG_HOME=/data/applogs\n# jvm options: -e JAVA_OPTS=\"-Xms128m -Xmx128m\"\n# app params: -e PARAMS=\"--server.port=8080\"\nENTRYPOINT [\"sh\",\"-c\",\"java ${LOG_HOME:+-DLOG_HOME=$LOG_HOME} -jar $JAVA_OPTS /app.jar $PARAMS\"]"
  },
  {
    "path": "xxl-job-executor-samples/xxl-job-executor-sample-springboot/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>com.xuxueli</groupId>\n        <artifactId>xxl-job-executor-samples</artifactId>\n        <version>3.4.0-SNAPSHOT</version>\n    </parent>\n    <artifactId>xxl-job-executor-sample-springboot</artifactId>\n    <packaging>jar</packaging>\n\n    <name>${project.artifactId}</name>\n    <description>Example executor project for spring boot.</description>\n    <url>https://www.xuxueli.com/</url>\n\n    <properties>\n    </properties>\n\n    <dependencies>\n        <!-- spring-boot-starter-web (spring-webmvc + tomcat) -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n\n        <!-- xxl-job-core -->\n        <dependency>\n            <groupId>com.xuxueli</groupId>\n            <artifactId>xxl-job-core</artifactId>\n        </dependency>\n\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <version>${spring-boot.version}</version>\n                <executions>\n                    <execution>\n                        <goals>\n                            <goal>repackage</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\n    </build>\n\n\n</project>"
  },
  {
    "path": "xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/java/com/xxl/job/executor/XxlJobExecutorApplication.java",
    "content": "package com.xxl.job.executor;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * @author xuxueli 2018-10-28 00:38:13\n */\n@SpringBootApplication\npublic class XxlJobExecutorApplication {\n\n\tpublic static void main(String[] args) {\n        SpringApplication.run(XxlJobExecutorApplication.class, args);\n\t}\n\n}"
  },
  {
    "path": "xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/java/com/xxl/job/executor/config/XxlJobConfig.java",
    "content": "package com.xxl.job.executor.config;\n\nimport com.xxl.job.core.executor.impl.XxlJobSpringExecutor;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * xxl-job config\n *\n * @author xuxueli 2017-04-28\n */\n@Configuration\npublic class XxlJobConfig {\n    private static final Logger logger = LoggerFactory.getLogger(XxlJobConfig.class);\n\n    @Value(\"${xxl.job.admin.addresses}\")\n    private String adminAddresses;\n\n    @Value(\"${xxl.job.admin.accessToken}\")\n    private String accessToken;\n\n    @Value(\"${xxl.job.admin.timeout}\")\n    private int timeout;\n\n    @Value(\"${xxl.job.executor.enabled}\")\n    private Boolean enabled;\n\n    @Value(\"${xxl.job.executor.appname}\")\n    private String appname;\n\n    @Value(\"${xxl.job.executor.address}\")\n    private String address;\n\n    @Value(\"${xxl.job.executor.ip}\")\n    private String ip;\n\n    @Value(\"${xxl.job.executor.port}\")\n    private int port;\n\n    @Value(\"${xxl.job.executor.logpath}\")\n    private String logPath;\n\n    @Value(\"${xxl.job.executor.logretentiondays}\")\n    private int logRetentionDays;\n\n    @Value(\"${xxl.job.executor.excludedpackage}\")\n    private String excludedPackage;\n\n\n    @Bean\n    public XxlJobSpringExecutor xxlJobExecutor() {\n        logger.info(\">>>>>>>>>>> xxl-job config init.\");\n        XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();\n        xxlJobSpringExecutor.setAdminAddresses(adminAddresses);\n        xxlJobSpringExecutor.setAccessToken(accessToken);\n        xxlJobSpringExecutor.setTimeout(timeout);\n        xxlJobSpringExecutor.setEnabled(enabled);\n        xxlJobSpringExecutor.setAppname(appname);\n        xxlJobSpringExecutor.setAddress(address);\n        xxlJobSpringExecutor.setIp(ip);\n        xxlJobSpringExecutor.setPort(port);\n        xxlJobSpringExecutor.setLogPath(logPath);\n        xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);\n        xxlJobSpringExecutor.setExcludedPackage(excludedPackage);\n\n        return xxlJobSpringExecutor;\n    }\n\n    /**\n     * 针对多网卡、容器内部署等情况，可借助 \"spring-cloud-commons\" 提供的 \"InetUtils\" 组件灵活定制注册IP；\n     *\n     *      1、引入依赖：\n     *          <dependency>\n     *             <groupId>org.springframework.cloud</groupId>\n     *             <artifactId>spring-cloud-commons</artifactId>\n     *             <version>${version}</version>\n     *         </dependency>\n     *\n     *      2、配置文件，或者容器启动变量\n     *          spring.cloud.inetutils.preferred-networks: 'xxx.xxx.xxx.'\n     *\n     *      3、获取IP\n     *          String ip_ = inetUtils.findFirstNonLoopbackHostInfo().getIpAddress();\n     */\n\n\n}"
  },
  {
    "path": "xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/java/com/xxl/job/executor/controller/IndexController.java",
    "content": "//package com.xxl.job.executor.mvc.controller;\n//\n//import org.springframework.boot.autoconfigure.EnableAutoConfiguration;\n//import org.springframework.stereotype.Controller;\n//import org.springframework.web.bind.annotation.RequestMapping;\n//import org.springframework.web.bind.annotation.ResponseBody;\n//\n//@Controller\n//@EnableAutoConfiguration\n//public class IndexController {\n//\n//    @RequestMapping(\"/\")\n//    @ResponseBody\n//    String index() {\n//        return \"xxl job executor running.\";\n//    }\n//\n//}"
  },
  {
    "path": "xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/java/com/xxl/job/executor/jobhandler/SampleXxlJob.java",
    "content": "package com.xxl.job.executor.jobhandler;\n\nimport com.xxl.job.core.context.XxlJobHelper;\nimport com.xxl.job.core.handler.annotation.XxlJob;\nimport com.xxl.tool.core.StringTool;\nimport com.xxl.tool.json.GsonTool;\nimport com.xxl.tool.http.HttpTool;\nimport com.xxl.tool.http.http.HttpResponse;\nimport com.xxl.tool.http.http.enums.ContentType;\nimport com.xxl.tool.http.http.enums.Method;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.stereotype.Component;\n\nimport java.io.BufferedInputStream;\nimport java.io.BufferedReader;\nimport java.io.InputStreamReader;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * XxlJob开发示例（Bean模式）\n *\n * 开发步骤：\n *      1、任务开发：在Spring Bean实例中，开发Job方法；\n *      2、注解配置：为Job方法添加注解 \"@XxlJob(value=\"自定义jobhandler名称\", init = \"JobHandler初始化方法\", destroy = \"JobHandler销毁方法\")\"，注解value值对应的是调度中心新建任务的JobHandler属性的值。\n *      3、执行日志：需要通过 \"XxlJobHelper.log\" 打印执行日志；\n *      4、任务结果：默认任务结果为 \"成功\" 状态，不需要主动设置；如有诉求，比如设置任务结果为失败，可以通过 \"XxlJobHelper.handleFail/handleSuccess\" 自主设置任务结果；\n *\n * @author xuxueli 2019-12-11 21:52:51\n */\n@Component\npublic class SampleXxlJob {\n    private static final Logger logger = LoggerFactory.getLogger(SampleXxlJob.class);\n\n\n    /**\n     * 1、简单任务示例（Bean模式）\n     */\n    @XxlJob(\"demoJobHandler\")\n    public void demoJobHandler() throws Exception {\n        XxlJobHelper.log(\"XXL-JOB, Hello World.\");\n\n        for (int i = 0; i < 5; i++) {\n            XxlJobHelper.log(\"beat at:\" + i);\n            TimeUnit.SECONDS.sleep(2);\n        }\n        // default success\n    }\n\n\n    /**\n     * 2、分片广播任务\n     */\n    @XxlJob(\"shardingJobHandler\")\n    public void shardingJobHandler() throws Exception {\n\n        // 分片参数\n        int shardIndex = XxlJobHelper.getShardIndex();\n        int shardTotal = XxlJobHelper.getShardTotal();\n\n        XxlJobHelper.log(\"分片参数：当前分片序号 = {}, 总分片数 = {}\", shardIndex, shardTotal);\n\n        // 业务逻辑\n        for (int i = 0; i < shardTotal; i++) {\n            if (i == shardIndex) {\n                XxlJobHelper.log(\"第 {} 片, 命中分片开始处理\", i);\n            } else {\n                XxlJobHelper.log(\"第 {} 片, 忽略\", i);\n            }\n        }\n\n    }\n\n\n    /**\n     * 3、命令行任务\n     *\n     *  参数示例：\"ls -a\" 或者 \"pwd\"\n     */\n    @XxlJob(\"commandJobHandler\")\n    public void commandJobHandler() throws Exception {\n        String command = XxlJobHelper.getJobParam();\n        int exitValue = -1;\n\n        BufferedReader bufferedReader = null;\n        try {\n            // valid\n            if (command==null || command.trim().length()==0) {\n                XxlJobHelper.handleFail(\"command empty.\");\n                return;\n            }\n\n            // command split\n            String[] commandArray = command.split(\" \");\n\n            // command process\n            ProcessBuilder processBuilder = new ProcessBuilder();\n            processBuilder.command(commandArray);\n            processBuilder.redirectErrorStream(true);\n\n            Process process = processBuilder.start();\n            //Process process = Runtime.getRuntime().exec(command);\n\n            BufferedInputStream bufferedInputStream = new BufferedInputStream(process.getInputStream());\n            bufferedReader = new BufferedReader(new InputStreamReader(bufferedInputStream));\n\n            // command log\n            String line;\n            while ((line = bufferedReader.readLine()) != null) {\n                XxlJobHelper.log(line);\n            }\n\n            // command exit\n            process.waitFor();\n            exitValue = process.exitValue();\n        } catch (Exception e) {\n            XxlJobHelper.log(e);\n        } finally {\n            if (bufferedReader != null) {\n                bufferedReader.close();\n            }\n        }\n\n        if (exitValue == 0) {\n            // default success\n        } else {\n            XxlJobHelper.handleFail(\"command exit value(\"+exitValue+\") is failed\");\n        }\n\n    }\n\n\n    /**\n     * 4、跨平台Http任务\n     *\n     *  参数示例：\n     *  <pre>\n     *      // 1、简单示例：\n     *      {\n     *          \"url\": \"http://www.baidu.com\",\n     *          \"method\": \"get\",\n     *          \"data\": \"hello world\"\n     *      }\n     *\n     *      // 2、完整参数示例：\n     *      {\n     *          \"url\": \"http://www.baidu.com\",\n     *          \"method\": \"POST\",\n     *          \"contentType\": \"application/json\",\n     *          \"headers\": {\n     *              \"header01\": \"value01\"\n     *          },\n     *          \"cookies\": {\n     *              \"cookie01\": \"value01\"\n     *          },\n     *          \"timeout\": 3000,\n     *          \"data\": \"request body data\",\n     *          \"form\": {\n     *              \"key01\": \"value01\"\n     *          },\n     *          \"auth\": \"auth data\"\n     *      }\n     *  </pre>\n     */\n    @XxlJob(\"httpJobHandler\")\n    public void httpJobHandler() throws Exception {\n\n        // param data\n        String param = XxlJobHelper.getJobParam();\n        if (param==null || param.trim().isEmpty()) {\n            XxlJobHelper.log(\"param[\"+ param +\"] invalid.\");\n\n            XxlJobHelper.handleFail();\n            return;\n        }\n\n        // param parse\n        HttpJobParam httpJobParam = null;\n        try {\n            httpJobParam = GsonTool.fromJson(param, HttpJobParam.class);\n        } catch (Exception e) {\n            XxlJobHelper.log(new RuntimeException(\"HttpJobParam parse error\", e));\n            XxlJobHelper.handleFail();\n            return;\n        }\n\n        // param valid\n        if (httpJobParam == null) {\n            XxlJobHelper.log(\"param parse fail.\");\n            XxlJobHelper.handleFail();\n            return;\n        }\n        if (StringTool.isBlank(httpJobParam.getUrl())) {\n            XxlJobHelper.log(\"url[\"+ httpJobParam.getUrl() +\"] invalid.\");\n            XxlJobHelper.handleFail();\n            return;\n        }\n        if (!isValidDomain(httpJobParam.getUrl())) {\n            XxlJobHelper.log(\"url[\"+ httpJobParam.getUrl() +\"] not allowed.\");\n            XxlJobHelper.handleFail();\n            return;\n        }\n        Method method = Method.POST;\n        if (StringTool.isNotBlank(httpJobParam.getMethod())) {\n            Method methodParam = Method.valueOf(httpJobParam.getMethod().toUpperCase());\n            if (methodParam == null) {\n                XxlJobHelper.log(\"method[\"+ httpJobParam.getMethod() +\"] invalid.\");\n                XxlJobHelper.handleFail();\n                return;\n            }\n            method = methodParam;\n        }\n        ContentType contentType = ContentType.JSON;\n        if (StringTool.isNotBlank(httpJobParam.getContentType())) {\n            for (ContentType contentTypeParam : ContentType.values()) {\n                if (contentTypeParam.getValue().equals(httpJobParam.getContentType())) {\n                    contentType = contentTypeParam;\n                    break;\n                }\n            }\n        }\n        if (httpJobParam.getTimeout() <= 0) {\n            httpJobParam.setTimeout(3000);\n        }\n\n        // do request\n        try {\n            HttpResponse httpResponse = HttpTool.createRequest()\n                    .url(httpJobParam.getUrl())\n                    .method(method)\n                    .contentType(contentType)\n                    .header(httpJobParam.getHeaders())\n                    .cookie(httpJobParam.getCookies())\n                    .body(httpJobParam.getData())\n                    .form(httpJobParam.getForm())\n                    .auth(httpJobParam.getAuth())\n                    .execute();\n\n            XxlJobHelper.log(\"StatusCode: \" + httpResponse.statusCode());\n            XxlJobHelper.log(\"Response: <br>\" + httpResponse.response());\n        } catch (Exception e) {\n            XxlJobHelper.log(e);\n            XxlJobHelper.handleFail();\n        }\n    }\n\n    /**\n     * domain white-list, for httpJobHandler\n     */\n    private static Set<String> DOMAIN_WHITE_LIST = Set.of(\n            \"http://www.baidu.com\",\n            \"http://cn.bing.com\"\n    );\n\n    /**\n     * valid if domain is in white-list\n     */\n    private boolean isValidDomain(String url) {\n        if (url == null || DOMAIN_WHITE_LIST.isEmpty()) {\n            return false;\n        }\n        for (String prefix : DOMAIN_WHITE_LIST) {\n            if (url.startsWith(prefix)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /*public static void main(String[] args) {\n        HttpJobParam httpJobParam = new HttpJobParam();\n        httpJobParam.setUrl(\"http://www.baidu.com\");\n        httpJobParam.setMethod(Method.POST.name());\n        httpJobParam.setContentType(ContentType.JSON.getValue());\n        httpJobParam.setHeaders(Map.of(\"header01\", \"value01\"));\n        httpJobParam.setCookies(Map.of(\"cookie01\", \"value01\"));\n        httpJobParam.setTimeout(3000);\n        httpJobParam.setData(\"request body data\");\n        httpJobParam.setForm(Map.of(\"form01\", \"value01\"));\n        httpJobParam.setAuth(\"auth data\");\n\n        logger.info(GsonTool.toJson(httpJobParam));\n    }*/\n\n    /**\n     * http job param\n     */\n    private static class HttpJobParam{\n        private String url;                                     // 请求 Url\n        private String method;                                  // Method\n        private String contentType;                             // Content-Type\n        private Map<String, String> headers;                    // 存储请求头\n        private Map<String, String> cookies;                    // Cookie（需要格式转换）\n        private int timeout;                                    // 请求超时时间\n        private String data;                                    // 存储请求体\n        private Map<String, String> form;                       // 存储表单数据\n        private String auth;                                    // 鉴权信息\n\n        public String getUrl() {\n            return url;\n        }\n\n        public void setUrl(String url) {\n            this.url = url;\n        }\n\n        public String getMethod() {\n            return method;\n        }\n\n        public void setMethod(String method) {\n            this.method = method;\n        }\n\n        public String getContentType() {\n            return contentType;\n        }\n\n        public void setContentType(String contentType) {\n            this.contentType = contentType;\n        }\n\n        public Map<String, String> getHeaders() {\n            return headers;\n        }\n\n        public void setHeaders(Map<String, String> headers) {\n            this.headers = headers;\n        }\n\n        public Map<String, String> getCookies() {\n            return cookies;\n        }\n\n        public void setCookies(Map<String, String> cookies) {\n            this.cookies = cookies;\n        }\n\n        public int getTimeout() {\n            return timeout;\n        }\n\n        public void setTimeout(int timeout) {\n            this.timeout = timeout;\n        }\n\n        public String getData() {\n            return data;\n        }\n\n        public void setData(String data) {\n            this.data = data;\n        }\n\n        public Map<String, String> getForm() {\n            return form;\n        }\n\n        public void setForm(Map<String, String> form) {\n            this.form = form;\n        }\n\n        public String getAuth() {\n            return auth;\n        }\n\n        public void setAuth(String auth) {\n            this.auth = auth;\n        }\n    }\n\n    /**\n     * 5、生命周期任务示例：任务初始化与销毁时，支持自定义相关逻辑；\n     */\n    @XxlJob(value = \"demoJobHandler2\", init = \"init\", destroy = \"destroy\")\n    public void demoJobHandler2() throws Exception {\n        XxlJobHelper.log(\"XXL-JOB, Hello World.\");\n    }\n    public void init(){\n        logger.info(\"init\");\n    }\n    public void destroy(){\n        logger.info(\"destroy\");\n    }\n\n\n}\n"
  },
  {
    "path": "xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/resources/application.properties",
    "content": "# web port\nserver.port=8081\n# no web\n#spring.main.web-environment=false\n\n# log config\nlogging.config=classpath:logback.xml\n\n\n### xxl-job admin address list, such as \"http://address\" or \"http://address01,http://address02\"\nxxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin\n### xxl-job access token\nxxl.job.admin.accessToken=default_token\n### xxl-job timeout by second, default 3s\nxxl.job.admin.timeout=3\n\n### xxl-job executor enable, default true\nxxl.job.executor.enabled=true\n### xxl-job executor appname\nxxl.job.executor.appname=xxl-job-executor-sample\n### xxl-job executor registry-address: default use address to registry , otherwise use ip:port if address is null\nxxl.job.executor.address=\n### xxl-job executor server-info\nxxl.job.executor.ip=\nxxl.job.executor.port=9999\n### xxl-job executor log-path\nxxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler\n### xxl-job executor log-retention-days\nxxl.job.executor.logretentiondays=30\n### xxl-job executor excluded package, will skip scan job. such as \"org.package01\" or \"org.package01,org.package02\"\nxxl.job.executor.excludedpackage=\n"
  },
  {
    "path": "xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/resources/logback.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration debug=\"false\" scan=\"true\" scanPeriod=\"1 seconds\">\n\n    <contextName>logback</contextName>\n    <property name=\"log.path\" value=\"${LOG_HOME:-/data/applogs}/xxl-job/xxl-job-executor-sample-springboot.log\" />\n    <appender name=\"console\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <encoder>\n            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>\n        </encoder>\n    </appender>\n\n    <appender name=\"file\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n        <file>${log.path}</file>\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n            <fileNamePattern>${log.path}.%d{yyyy-MM-dd}.log</fileNamePattern>\n        </rollingPolicy>\n        <encoder>\n            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>\n        </encoder>\n    </appender>\n\n    <root level=\"info\">\n        <appender-ref ref=\"console\"/>\n        <!--<appender-ref ref=\"file\"/>-->\n    </root>\n\n</configuration>"
  },
  {
    "path": "xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/test/java/com/xxl/job/executor/test/XxlJobExecutorExampleBootApplicationTests.java",
    "content": "package com.xxl.job.executor.test;\n\nimport org.junit.jupiter.api.Test;\nimport org.springframework.boot.test.context.SpringBootTest;\n\n@SpringBootTest\npublic class XxlJobExecutorExampleBootApplicationTests {\n\n\t@Test\n\tpublic void test() {\n\t\tSystem.out.println(11);\n\t}\n\n}"
  },
  {
    "path": "xxl-job-executor-samples/xxl-job-executor-sample-springboot-ai/Dockerfile",
    "content": "# base image\nFROM openjdk:21-jdk-slim\n\n# maintainer\nMAINTAINER xuxueli\n\n# set params\nENV PARAMS=\"\"\n\n# set timezone\nENV TZ=PRC\nRUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone\n\n# copy jar\nADD target/xxl-job-executor-sample-springboot-ai*.jar /app.jar\n\n# command\n# log home: -e LOG_HOME=/data/applogs\n# jvm options: -e JAVA_OPTS=\"-Xms128m -Xmx128m\"\n# app params: -e PARAMS=\"--server.port=8080\"\nENTRYPOINT [\"sh\",\"-c\",\"java ${LOG_HOME:+-DLOG_HOME=$LOG_HOME} -jar $JAVA_OPTS /app.jar $PARAMS\"]"
  },
  {
    "path": "xxl-job-executor-samples/xxl-job-executor-sample-springboot-ai/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>com.xuxueli</groupId>\n        <artifactId>xxl-job-executor-samples</artifactId>\n        <version>3.4.0-SNAPSHOT</version>\n    </parent>\n    <artifactId>xxl-job-executor-sample-springboot-ai</artifactId>\n    <packaging>jar</packaging>\n\n    <name>${project.artifactId}</name>\n    <description>Example executor project for spring boot.</description>\n    <url>https://www.xuxueli.com/</url>\n\n    <properties>\n\n    </properties>\n\n    <dependencies>\n        <!-- spring-boot-starter-web (spring-webmvc + tomcat) -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n\n        <!-- xxl-job-core -->\n        <dependency>\n            <groupId>com.xuxueli</groupId>\n            <artifactId>xxl-job-core</artifactId>\n        </dependency>\n\n        <!-- spring-ai -->\n        <dependency>\n            <groupId>org.springframework.ai</groupId>\n            <artifactId>spring-ai-starter-model-ollama</artifactId>\n        </dependency>\n        <!-- dify -->\n        <dependency>\n            <groupId>io.github.imfangs</groupId>\n            <artifactId>dify-java-client</artifactId>\n        </dependency>\n\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <version>${spring-boot.version}</version>\n                <executions>\n                    <execution>\n                        <goals>\n                            <goal>repackage</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>"
  },
  {
    "path": "xxl-job-executor-samples/xxl-job-executor-sample-springboot-ai/src/main/java/com/xxl/job/executor/XxlJobAIExecutorApplication.java",
    "content": "package com.xxl.job.executor;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * @author xuxueli 2018-10-28 00:38:13\n */\n@SpringBootApplication\npublic class XxlJobAIExecutorApplication {\n\n\tpublic static void main(String[] args) {\n        SpringApplication.run(XxlJobAIExecutorApplication.class, args);\n\t}\n\n}"
  },
  {
    "path": "xxl-job-executor-samples/xxl-job-executor-sample-springboot-ai/src/main/java/com/xxl/job/executor/config/XxlJobConfig.java",
    "content": "package com.xxl.job.executor.config;\n\nimport com.xxl.job.core.executor.impl.XxlJobSpringExecutor;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * xxl-job config\n *\n * @author xuxueli 2017-04-28\n */\n@Configuration\npublic class XxlJobConfig {\n    private static final Logger logger = LoggerFactory.getLogger(XxlJobConfig.class);\n\n    @Value(\"${xxl.job.admin.addresses}\")\n    private String adminAddresses;\n\n    @Value(\"${xxl.job.admin.accessToken}\")\n    private String accessToken;\n\n    @Value(\"${xxl.job.admin.timeout}\")\n    private int timeout;\n\n    @Value(\"${xxl.job.executor.enabled}\")\n    private Boolean enabled;\n\n    @Value(\"${xxl.job.executor.appname}\")\n    private String appname;\n\n    @Value(\"${xxl.job.executor.address}\")\n    private String address;\n\n    @Value(\"${xxl.job.executor.ip}\")\n    private String ip;\n\n    @Value(\"${xxl.job.executor.port}\")\n    private int port;\n\n    @Value(\"${xxl.job.executor.logpath}\")\n    private String logPath;\n\n    @Value(\"${xxl.job.executor.logretentiondays}\")\n    private int logRetentionDays;\n\n    @Value(\"${xxl.job.executor.excludedpackage}\")\n    private String excludedPackage;\n\n\n    @Bean\n    public XxlJobSpringExecutor xxlJobExecutor() {\n        logger.info(\">>>>>>>>>>> xxl-job config init.\");\n        XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();\n        xxlJobSpringExecutor.setAdminAddresses(adminAddresses);\n        xxlJobSpringExecutor.setAccessToken(accessToken);\n        xxlJobSpringExecutor.setTimeout(timeout);\n        xxlJobSpringExecutor.setEnabled(enabled);\n        xxlJobSpringExecutor.setAppname(appname);\n        xxlJobSpringExecutor.setAddress(address);\n        xxlJobSpringExecutor.setIp(ip);\n        xxlJobSpringExecutor.setPort(port);\n        xxlJobSpringExecutor.setLogPath(logPath);\n        xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);\n        xxlJobSpringExecutor.setExcludedPackage(excludedPackage);\n\n        return xxlJobSpringExecutor;\n    }\n\n}"
  },
  {
    "path": "xxl-job-executor-samples/xxl-job-executor-sample-springboot-ai/src/main/java/com/xxl/job/executor/controller/IndexController.java",
    "content": "package com.xxl.job.executor.controller;//package com.xxl.job.executor.mvc.controller;\n\nimport com.fasterxml.jackson.core.JsonProcessingException;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport io.github.imfangs.dify.client.DifyClientFactory;\nimport io.github.imfangs.dify.client.DifyWorkflowClient;\nimport io.github.imfangs.dify.client.callback.WorkflowStreamCallback;\nimport io.github.imfangs.dify.client.enums.ResponseMode;\nimport io.github.imfangs.dify.client.event.*;\nimport io.github.imfangs.dify.client.model.workflow.WorkflowRunRequest;\nimport io.github.imfangs.dify.client.model.workflow.WorkflowRunResponse;\nimport jakarta.annotation.Resource;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.ai.chat.client.ChatClient;\nimport org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;\nimport org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;\nimport org.springframework.ai.chat.memory.MessageWindowChatMemory;\nimport org.springframework.ai.ollama.OllamaChatModel;\nimport org.springframework.ai.ollama.api.OllamaChatOptions;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.ResponseBody;\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.FluxSink;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.function.Consumer;\n\n@Controller\n@EnableAutoConfiguration\npublic class IndexController {\n    private static Logger logger = LoggerFactory.getLogger(IndexController.class);\n\n\n    @RequestMapping(\"/\")\n    @ResponseBody\n    String index() {\n        return \"xxl job ai executor running.\";\n    }\n\n\n    // --------------------------------- ollama chat ---------------------------------\n\n    @Resource\n    private OllamaChatModel ollamaChatModel;\n    private String prompt = \"你好，你是一个研发工程师，擅长解决技术类问题。\";\n    private String modle = \"qwen3:0.6b\";\n\n    /**\n     * ChatClient 简单调用\n     */\n    @GetMapping(\"/chat/simple\")\n    @ResponseBody\n    public String simpleChat(@RequestParam(value = \"input\", required = false, defaultValue = \"介绍你自己\") String input) {\n\n        // build chat-client\n        ChatClient ollamaChatClient = ChatClient\n                .builder(ollamaChatModel)\n                .defaultAdvisors(MessageChatMemoryAdvisor.builder(MessageWindowChatMemory.builder().build()).build())       // add memory\n                .defaultAdvisors(SimpleLoggerAdvisor.builder().build())                                                     // add logger\n                .defaultOptions(OllamaChatOptions.builder().model(modle).build())                                           // assign model\n                .build();\n\n        // call ollama\n        String response = ollamaChatClient\n                .prompt(prompt)\n                .user(input)\n                .call()\n                .content();\n\n        logger.info(\"result: \" + response);\n        return response;\n    }\n\n    /**\n     * ChatClient 流式调用\n     */\n    @GetMapping(\"/chat/stream\")\n    public Flux<String> streamChat(HttpServletResponse response, @RequestParam(value = \"input\", required = false, defaultValue = \"介绍你自己\") String input) {\n        response.setCharacterEncoding(\"UTF-8\");\n\n        // build chat-client\n        ChatClient ollamaChatClient = ChatClient\n                .builder(ollamaChatModel)\n                .defaultAdvisors(MessageChatMemoryAdvisor.builder(MessageWindowChatMemory.builder().build()).build())\n                .defaultAdvisors(SimpleLoggerAdvisor.builder().build())\n                .defaultOptions(OllamaChatOptions.builder().model(modle).build())\n                .build();\n\n        // call ollama\n        return ollamaChatClient\n                .prompt(prompt)\n                .user(input)\n                .stream()\n                .content();\n    }\n\n\n    // --------------------------------- dify workflow ---------------------------------\n\n    // dify config sample\n    private final String apiKey = \"app-46gHBiqUb5jqAHl9TDWwnRZ8\";\n    private final String baseUrl = \"http://localhost/v1\";\n\n    @GetMapping(\"/dify/simple\")\n    @ResponseBody\n    public String difySimple(@RequestParam(required = false, value = \"input\") String input) throws Exception {\n\n        Map<String, Object> inputs = new HashMap<>();\n        inputs.put(\"input\", input);\n\n        // request\n        WorkflowRunRequest request = WorkflowRunRequest.builder()\n                .inputs(inputs)\n                .responseMode(ResponseMode.BLOCKING)\n                .user(\"user-123\")\n                .build();\n\n        // invoke\n        DifyWorkflowClient workflowClient = DifyClientFactory.createWorkflowClient(baseUrl, apiKey);\n        WorkflowRunResponse response = workflowClient.runWorkflow(request);\n\n        // response\n        return write2Json(response.getData().getOutputs());\n    }\n\n    private String write2Json(Object obj) {\n        if (obj == null) {\n            return \"null\";\n        }\n        try {\n            return new ObjectMapper().writeValueAsString(obj);\n        } catch (JsonProcessingException e) {\n            return obj.toString();\n        }\n    }\n\n    @GetMapping( \"/dify/stream\")\n    public Flux<String> difyStream(@RequestParam(required = false, value = \"input\") String input) {\n\n        Map<String, Object> inputs = new HashMap<>();\n        inputs.put(\"input\", input);\n\n        // request\n        WorkflowRunRequest request = WorkflowRunRequest.builder()\n                .inputs(inputs)\n                .responseMode(ResponseMode.STREAMING)\n                .user(\"user-123\")\n                .build();\n\n        // invoke\n        DifyWorkflowClient workflowClient = DifyClientFactory.createWorkflowClient(baseUrl, apiKey);\n        return Flux.create(new Consumer<FluxSink<String>>() {\n            @Override\n            public void accept(FluxSink<String> sink) {\n                try {\n                    workflowClient.runWorkflowStream(request, new WorkflowStreamCallback() {\n                        @Override\n                        public void onWorkflowStarted(WorkflowStartedEvent event) {\n                            sink.next(\"工作流开始: \" + write2Json(event.getData()));\n                        }\n\n                        @Override\n                        public void onNodeStarted(NodeStartedEvent event) {\n                            sink.next(\"节点开始: \" + write2Json(event.getData()));\n                        }\n\n                        @Override\n                        public void onNodeFinished(NodeFinishedEvent event) {\n                            sink.next(\"节点完成: \" + write2Json(event.getData().getOutputs()));\n                        }\n\n                        @Override\n                        public void onWorkflowFinished(WorkflowFinishedEvent event) {\n                            sink.next(\"工作流完成: \" + write2Json(event.getData().getOutputs()));\n                            sink.complete();\n                        }\n\n                        @Override\n                        public void onError(ErrorEvent event) {\n                            sink.error(new RuntimeException(event.getMessage()));\n                        }\n\n                        @Override\n                        public void onException(Throwable throwable) {\n                            sink.error(throwable);\n                        }\n                    });\n                } catch (Exception e) {\n                    throw new RuntimeException(e);\n                }\n            }\n        });\n    }\n\n}"
  },
  {
    "path": "xxl-job-executor-samples/xxl-job-executor-sample-springboot-ai/src/main/java/com/xxl/job/executor/jobhandler/AIXxlJob.java",
    "content": "package com.xxl.job.executor.jobhandler;\n\nimport com.xxl.job.core.context.XxlJobHelper;\nimport com.xxl.job.core.handler.annotation.XxlJob;\nimport com.xxl.tool.json.GsonTool;\nimport io.github.imfangs.dify.client.DifyClientFactory;\nimport io.github.imfangs.dify.client.DifyWorkflowClient;\nimport io.github.imfangs.dify.client.enums.ResponseMode;\nimport io.github.imfangs.dify.client.model.workflow.WorkflowRunRequest;\nimport io.github.imfangs.dify.client.model.workflow.WorkflowRunResponse;\nimport jakarta.annotation.Resource;\nimport org.springframework.ai.chat.client.ChatClient;\nimport org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;\nimport org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;\nimport org.springframework.ai.chat.memory.MessageWindowChatMemory;\nimport org.springframework.ai.ollama.OllamaChatModel;\nimport org.springframework.ai.ollama.api.OllamaChatOptions;\nimport org.springframework.stereotype.Component;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * AI 任务开发示例\n *\n * @author xuxueli 2025-04-06\n */\n@Component\npublic class AIXxlJob {\n\n    // --------------------------------- ollama chat ---------------------------------\n\n    @Resource\n    private OllamaChatModel ollamaChatModel;\n\n    /**\n     * 1、ollama Chat任务\n     *\n     *  参数示例：格式见 OllamaParam\n     *  <pre>\n     *      {\n     *          \"input\": \"{输入信息，必填信息}\",\n     *          \"prompt\": \"{模型prompt，可选信息}\"\n     *      }\n     *  </pre>\n     */\n    @XxlJob(\"ollamaJobHandler\")\n    public void ollamaJobHandler() {\n\n        // param\n        String param = XxlJobHelper.getJobParam();\n        if (param==null || param.trim().isEmpty()) {\n            XxlJobHelper.log(\"param is empty.\");\n\n            XxlJobHelper.handleFail();\n            return;\n        }\n\n        // ollama param\n        OllamaParam ollamaParam = null;\n        try {\n            ollamaParam = GsonTool.fromJson(param, OllamaParam.class);\n            if (ollamaParam.getPrompt()==null || ollamaParam.getPrompt().isBlank()) {\n                ollamaParam.setPrompt(\"你是一个研发工程师，擅长解决技术类问题。\");\n            }\n            if (ollamaParam.getInput() == null || ollamaParam.getInput().isBlank()) {\n                XxlJobHelper.log(\"input is empty.\");\n\n                XxlJobHelper.handleFail();\n                return;\n            }\n            if (ollamaParam.getModel()==null || ollamaParam.getModel().isBlank()) {\n                ollamaParam.setModel(\"qwen3:0.6b\");\n            }\n        } catch (Exception e) {\n            XxlJobHelper.log(new RuntimeException(\"OllamaParam parse error\", e));\n            XxlJobHelper.handleFail();\n            return;\n        }\n\n        // input\n        XxlJobHelper.log(\"<br><br><b>【Input】: \" + ollamaParam.getInput()+ \"</b><br><br>\");\n\n        // build chat-client\n        ChatClient ollamaChatClient = ChatClient\n                .builder(ollamaChatModel)\n                .defaultAdvisors(MessageChatMemoryAdvisor.builder(MessageWindowChatMemory.builder().build()).build())\n                .defaultAdvisors(SimpleLoggerAdvisor.builder().build())\n                .defaultOptions(OllamaChatOptions.builder().model(ollamaParam.getModel()).build())\n                .build();\n\n        // call ollama\n        String response = ollamaChatClient\n                .prompt(ollamaParam.getPrompt())\n                .user(ollamaParam.getInput())\n                .call()\n                .content();\n\n        XxlJobHelper.log(\"<br><br><b>【Output】: \" + response + \"</b><br><br>\");\n    }\n\n    private static class OllamaParam{\n        private String input;\n        private String prompt;\n        private String model;\n\n        public String getInput() {\n            return input;\n        }\n\n        public void setInput(String input) {\n            this.input = input;\n        }\n\n        public String getPrompt() {\n            return prompt;\n        }\n\n        public void setPrompt(String prompt) {\n            this.prompt = prompt;\n        }\n\n        public String getModel() {\n            return model;\n        }\n\n        public void setModel(String model) {\n            this.model = model;\n        }\n    }\n\n\n    // --------------------------------- dify workflow ---------------------------------\n\n    /**\n     * 2、dify Workflow任务\n     *\n     *  参数示例：格式见 DifyParam\n     *  <pre>\n     *      {\n     *          \"inputs\":{                      // inputs 为dify工作流任务参数；参数不固定，结合各自 workflow 自行定义。\n     *              \"input\":\"{用户输入信息}\"      // 该参数为示例变量，需要 workflow 的“开始”节点 自定义参数 “input”，可自行调整或删除。\n     *          },\n     *          \"user\": \"{用户标识，选填}\"\n     *      }\n     *  </pre>\n     */\n    @XxlJob(\"difyWorkflowJobHandler\")\n    public void difyWorkflowJobHandler() throws Exception {\n\n        // param\n        String param = XxlJobHelper.getJobParam();\n        if (param==null || param.trim().isEmpty()) {\n            XxlJobHelper.log(\"param is empty.\");\n            XxlJobHelper.handleFail();\n            return;\n        }\n\n        // param parse\n        DifyParam difyParam;\n        try {\n            difyParam =GsonTool.fromJson(param, DifyParam.class);\n            if (difyParam.getInputs() == null) {\n                difyParam.setInputs(new HashMap<>());\n            }\n            if (difyParam.getUser() == null) {\n                difyParam.setUser(\"xxl-job\");\n            }\n            if (difyParam.getBaseUrl()==null || difyParam.getApiKey()==null) {\n                XxlJobHelper.log(\"baseUrl or apiKey invalid.\");\n                XxlJobHelper.handleFail();\n                return;\n            }\n        } catch (Exception e) {\n            XxlJobHelper.log(new RuntimeException(\"DifyParam parse error\", e));\n            XxlJobHelper.handleFail();\n            return;\n        }\n\n\n        // dify param\n        XxlJobHelper.log(\"<br><br><b>【inputs】: \" + difyParam.getInputs() + \"</b><br><br>\");\n\n        // dify request\n        WorkflowRunRequest request = WorkflowRunRequest.builder()\n                .inputs(difyParam.getInputs())\n                .responseMode(ResponseMode.BLOCKING)\n                .user(difyParam.getUser())\n                .build();\n\n        // dify invoke\n        DifyWorkflowClient workflowClient = DifyClientFactory.createWorkflowClient(difyParam.getBaseUrl(), difyParam.getApiKey());\n        WorkflowRunResponse response = workflowClient.runWorkflow(request);\n\n        // response\n        XxlJobHelper.log(\"<br><br><b>【Output】: \" + response.getData().getOutputs()+ \"</b><br><br>\");\n    }\n\n    private static class DifyParam{\n\n        /**\n         * dify input, 允许传入 Dify App 定义的各变量值\n         */\n        private Map<String, Object> inputs;\n\n        /**\n         * dify user\n         */\n        private String user;\n\n        /**\n         * dify baseUrl\n         */\n        private String baseUrl;\n\n        /**\n         * dify apiKey\n         */\n        private String apiKey;\n\n        public Map<String, Object> getInputs() {\n            return inputs;\n        }\n\n        public void setInputs(Map<String, Object> inputs) {\n            this.inputs = inputs;\n        }\n\n        public String getUser() {\n            return user;\n        }\n\n        public void setUser(String user) {\n            this.user = user;\n        }\n\n        public String getBaseUrl() {\n            return baseUrl;\n        }\n\n        public void setBaseUrl(String baseUrl) {\n            this.baseUrl = baseUrl;\n        }\n\n        public String getApiKey() {\n            return apiKey;\n        }\n\n        public void setApiKey(String apiKey) {\n            this.apiKey = apiKey;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-executor-samples/xxl-job-executor-sample-springboot-ai/src/main/resources/application.properties",
    "content": "# web port\nserver.port=8082\n# no web\n#spring.main.web-environment=false\n\nserver.servlet.encoding.force=true\nserver.servlet.encoding.charset=UTF-8\n\n# log config\nlogging.config=classpath:logback.xml\n\n\n### xxl-job admin address list, such as \"http://address\" or \"http://address01,http://address02\"\nxxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin\n### xxl-job access token\nxxl.job.admin.accessToken=default_token\n### xxl-job timeout by second, default 3s\nxxl.job.admin.timeout=3\n\n### xxl-job executor enable, default true\nxxl.job.executor.enabled=true\n### xxl-job executor appname\nxxl.job.executor.appname=xxl-job-executor-sample-ai\n### xxl-job executor registry-address: default use address to registry , otherwise use ip:port if address is null\nxxl.job.executor.address=\n### xxl-job executor server-info\nxxl.job.executor.ip=\nxxl.job.executor.port=9997\n### xxl-job executor log-path\nxxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler\n### xxl-job executor log-retention-days\nxxl.job.executor.logretentiondays=30\n### xxl-job executor excluded package, will skip scan job. such as \"org.package01\" or \"org.package01,org.package02\"\nxxl.job.executor.excludedpackage=\n\n\n### ollama\nspring.ai.model.chat=ollama\n### ollama url\nspring.ai.ollama.base-url=http://localhost:11434\n"
  },
  {
    "path": "xxl-job-executor-samples/xxl-job-executor-sample-springboot-ai/src/main/resources/logback.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration debug=\"false\" scan=\"true\" scanPeriod=\"1 seconds\">\n\n    <contextName>logback</contextName>\n    <property name=\"log.path\" value=\"${LOG_HOME:-/data/applogs}/xxl-job/xxl-job-executor-sample-springboot-ai.log\" />\n    <appender name=\"console\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <encoder>\n            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>\n        </encoder>\n    </appender>\n\n    <appender name=\"file\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n        <file>${log.path}</file>\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n            <fileNamePattern>${log.path}.%d{yyyy-MM-dd}.log</fileNamePattern>\n        </rollingPolicy>\n        <encoder>\n            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>\n        </encoder>\n    </appender>\n\n    <root level=\"info\">\n        <appender-ref ref=\"console\"/>\n        <!--<appender-ref ref=\"file\"/>-->\n    </root>\n\n</configuration>"
  },
  {
    "path": "xxl-job-executor-samples/xxl-job-executor-sample-springboot-ai/src/test/java/com/xxl/job/executor/test/BaseTests.java",
    "content": "package com.xxl.job.executor.test;\n\nimport org.junit.jupiter.api.Test;\nimport org.springframework.boot.test.context.SpringBootTest;\n\n@SpringBootTest\npublic class BaseTests {\n\n\t@Test\n\tpublic void test() {\n\t\tSystem.out.println(11);\n\t}\n\n}"
  },
  {
    "path": "xxl-job-executor-samples/xxl-job-executor-sample-springboot-ai/src/test/java/com/xxl/job/executor/test/dify/DifyTest.java",
    "content": "package com.xxl.job.executor.test.dify;\n\nimport com.xxl.job.core.executor.impl.XxlJobSpringExecutor;\nimport io.github.imfangs.dify.client.DifyClientFactory;\nimport io.github.imfangs.dify.client.DifyWorkflowClient;\nimport io.github.imfangs.dify.client.enums.ResponseMode;\nimport io.github.imfangs.dify.client.model.workflow.WorkflowRunRequest;\nimport io.github.imfangs.dify.client.model.workflow.WorkflowRunResponse;\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.bean.override.mockito.MockitoBean;\n\nimport java.util.Map;\n\n@SpringBootTest\npublic class DifyTest {\n    private static final Logger logger = LoggerFactory.getLogger(DifyTest.class);\n\n    // ignore\n    @MockitoBean\n    private XxlJobSpringExecutor xxlJobSpringExecutor;\n\n    @Test\n    public void test() throws Exception {\n\n        String baseUrl = \"https://xx.ai\";\n        String apiKey = \"xx\";\n        String user = \"zhangsan\";\n        Map<String, Object> inputs = Map.of(\n                \"input\", \"请写一个java程序，实现一个方法，输入一个字符串，返回字符串的长度。\"\n        );\n\n        // dify request\n        WorkflowRunRequest request = WorkflowRunRequest.builder()\n                .inputs(inputs)\n                .responseMode(ResponseMode.BLOCKING)\n                .user(user)\n                .build();\n\n        // dify invoke\n        DifyWorkflowClient workflowClient = DifyClientFactory.createWorkflowClient(baseUrl, apiKey);\n        WorkflowRunResponse response = workflowClient.runWorkflow(request);\n\n        // response\n        logger.info(\"input: \" + inputs);\n        logger.info(\"output: \" + response.getData().getOutputs());\n    }\n\n}\n"
  },
  {
    "path": "xxl-job-executor-samples/xxl-job-executor-sample-springboot-ai/src/test/java/com/xxl/job/executor/test/ollama/OllamaTest.java",
    "content": "package com.xxl.job.executor.test.ollama;\n\nimport com.xxl.job.core.executor.impl.XxlJobSpringExecutor;\nimport jakarta.annotation.Resource;\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.ai.chat.client.ChatClient;\nimport org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;\nimport org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;\nimport org.springframework.ai.chat.memory.MessageWindowChatMemory;\nimport org.springframework.ai.ollama.OllamaChatModel;\nimport org.springframework.ai.ollama.api.OllamaChatOptions;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.bean.override.mockito.MockitoBean;\nimport reactor.core.publisher.Flux;\n\nimport java.util.concurrent.TimeUnit;\n\n@SpringBootTest\npublic class OllamaTest {\n    private static final Logger logger = LoggerFactory.getLogger(OllamaTest.class);\n\n    // ignore\n    @MockitoBean\n    private XxlJobSpringExecutor xxlJobSpringExecutor;\n\n\n    @Resource\n    private OllamaChatModel ollamaChatModel;\n\n    @Test\n    public void chatTest() {\n\n        String model = \"qwen3:0.6b\";\n        String prompt = \"背景说明：你是一个研发工程师，擅长解决技术类问题。\";\n        String input = \"请写一个java程序，实现一个方法，输入一个字符串，返回字符串的长度。\";\n\n\n        // build chat-client\n        ChatClient ollamaChatClient = ChatClient\n                .builder(ollamaChatModel)\n                .defaultAdvisors(MessageChatMemoryAdvisor.builder(MessageWindowChatMemory.builder().build()).build())\n                .defaultAdvisors(SimpleLoggerAdvisor.builder().build())\n                .defaultOptions(OllamaChatOptions.builder().model(model).build())\n                .build();\n\n        // call ollama\n        String response = ollamaChatClient\n                .prompt(prompt)\n                .user(input)\n                .call()\n                .content();\n\n        logger.info(\"input: {}\", input);\n        logger.info(\"response: {}\", response);\n    }\n\n    @Test\n    public void chatStreamTest() throws InterruptedException {\n\n        String model = \"qwen3:0.6b\";\n        String prompt = \"背景说明：你是一个研发工程师，擅长解决技术类问题。\";\n        String input = \"请写一个java程序，实现一个方法，输入一个字符串，返回字符串的长度。\";\n\n\n        // build chat-client\n        ChatClient ollamaChatClient = ChatClient\n                .builder(ollamaChatModel)\n                .defaultAdvisors(MessageChatMemoryAdvisor.builder(MessageWindowChatMemory.builder().build()).build())\n                .defaultAdvisors(SimpleLoggerAdvisor.builder().build())\n                .defaultOptions(OllamaChatOptions.builder().model(model).build())\n                .build();\n\n        // call ollama\n        logger.info(\"input: {}\", input);\n        Flux<String> flux = ollamaChatClient\n                .prompt(prompt)\n                .user(input)\n                .stream()\n                .content();\n\n        flux.subscribe(\n                data -> System.out.println(\"Received: \" + data),  // onNext 处理\n                error -> System.err.println(\"Error: \" + error),   // onError 处理\n                () -> System.out.println(\"Completed\")             // onComplete 处理\n        );\n\n        TimeUnit.SECONDS.sleep(10);\n\n    }\n\n\n}\n"
  }
]