[
  {
    "path": ".github/workflows/build-docker-image.yml",
    "content": "name: Build & Publish Docker Image\n\non:\n  workflow_dispatch:\n  push:\n    branches:\n      - master\n      - main\n\npermissions:\n  packages: write\n  contents: read\n\nenv:\n  IMAGE_NAME: ${{ github.repository }}\n  REGISTRY: ghcr.io\n\njobs:\n  build:\n    timeout-minutes: 15\n    runs-on: ubuntu-22.04\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v3\n\n      - name: Generate Docker Metadata\n        id: meta\n        uses: docker/metadata-action@v4\n        with:\n          github-token: ${{ secrets.GITHUB_TOKEN }}\n          images: |\n            ghcr.io/${{ github.actor }}/${{ github.repository }}\n          tags: |\n            type=schedule\n            type=ref,event=branch\n            type=ref,event=pr\n            type=semver,pattern={{version}}\n            type=semver,pattern={{major}}.{{minor}}\n            type=semver,pattern={{major}}\n            type=sha\n\n      - name: Set up QEMU To support build amd64 and arm64 images\n        uses: docker/setup-qemu-action@v2\n\n      - name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@v2\n\n      - name: Login to the Github Container Registry\n        uses: docker/login-action@v2\n        with:\n          registry: ghcr.io\n          username: ${{ github.actor }}\n          password: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Build and push\n        uses: docker/build-push-action@v3\n        id: docker_build\n        with:\n          push: ${{ github.event_name != 'pull_request' && ( github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master' ) }}\n          context: .\n          platforms: linux/amd64,linux/arm64\n          tags: ${{ steps.meta.outputs.tags }}\n          labels: ${{ steps.meta.outputs.labels }}\n          cache-from: type=gha\n          cache-to: type=gha,mode=max\n\n      - name: Output image, digest and metadata to summary\n        run: |\n          {\n          echo imageid: \"${{ steps.docker_build.outputs.imageid }}\"\n          echo digest: \"${{ steps.docker_build.outputs.digest }}\"\n          echo labels: \"${{ steps.meta.outputs.labels }}\"\n          echo tags: \"${{ steps.meta.outputs.tags }}\"\n          echo version: \"${{ steps.meta.outputs.version }}\"\n          } >> \"$GITHUB_STEP_SUMMARY\"\n"
  },
  {
    "path": ".github/workflows/build-test.yml",
    "content": "# This workflow will install Python dependencies, run tests and lint with a single version of Python\n# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions\n\nname: Build and Test Python Package\n\non:\n  workflow_dispatch:\n  push:\n    branches: [ \"master\" ]\n  pull_request:\n    branches: [ \"master\" ]\n\npermissions:\n  contents: read\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@v3\n    - uses: actions/setup-python@v3\n      with:\n        python-version: \"2.7\"\n    - name: Install dependencies\n      run: |\n        python -m pip install --upgrade pip\n        pip install flake8 pytest\n        if [ -f requirements.txt ]; then pip install -r requirements.txt; fi\n    - name: Lint with flake8\n      run: |\n        # stop the build if there are Python syntax errors or undefined names\n        flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics\n        # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide\n        flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics\n    - name: Spin up MongoDB for running tests\n      uses: supercharge/mongodb-github-action@1.8.0\n      with:\n        mongodb-version: \"5\"\n    - name: Run nosetests\n      run: |\n        mongorestore dump/explainshell && mongorestore -d explainshell_tests dump/explainshell\n        make tests\n"
  },
  {
    "path": ".github/workflows/lint-docker.yml",
    "content": "name: \"Lint Dockerfile\"\n\non:\n  pull_request:\n    paths:\n      - \"**/Dockerfile.*\"\n      - \"**/docker-compose.*\"\n    branches:\n      - main\n      - master\n  workflow_dispatch:\n\njobs:\n  hadolint:\n    name: \"Lint Docker with hadolint\"\n    runs-on: ubuntu-22.04\n    steps:\n      - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3\n      - name: run tflint\n        uses: reviewdog/action-hadolint@master\n        with:\n          github_token: ${{ secrets.github_token }}\n          reporter: github-pr-review\n          fail_on_error: \"false\"\n          level: warning\n          filter_mode: \"nofilter\" # Optional. Check all files, not just the diff\n"
  },
  {
    "path": ".gitignore",
    "content": "*.pyc\n*.swp\n.coverage\n.vagrant\napplication.log"
  },
  {
    "path": "Dockerfile",
    "content": "FROM python:2.7\n\nRUN sed -i 's|deb.debian.org/debian|archive.debian.org/debian|g' /etc/apt/sources.list \\\n  && sed -i 's|security.debian.org/debian-security|archive.debian.org/debian-security|g' /etc/apt/sources.list \\\n  && sed -i '/buster-updates/d' /etc/apt/sources.list \\\n  && apt-get update \\\n  && apt-get install man-db -y \\\n  && apt-get clean\n\nADD ./requirements.txt /tmp/requirements.txt\n\nRUN pip install --upgrade pip \\\n  && python --version \\\n  && pip install -r /tmp/requirements.txt \\\n  && rm -rf ~/.cache/pip/*\n\nADD ./ /opt/webapp/\nWORKDIR /opt/webapp\nEXPOSE 5000\n\nCMD [\"make\", \"serve\"]\n"
  },
  {
    "path": "LICENSE",
    "content": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU General Public License is a free, copyleft license for\nsoftware and other kinds of works.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nthe GNU General Public License is intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.  We, the Free Software Foundation, use the\nGNU General Public License for most of our software; it applies also to\nany other work released this way by its authors.  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  To protect your rights, we need to prevent others from denying you\nthese rights or asking you to surrender the rights.  Therefore, you have\ncertain responsibilities if you distribute copies of the software, or if\nyou modify it: responsibilities to respect the freedom of others.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must pass on to the recipients the same\nfreedoms that you received.  You must make sure that they, too, receive\nor can get the source code.  And you must show them these terms so they\nknow their rights.\n\n  Developers that use the GNU GPL protect your rights with two steps:\n(1) assert copyright on the software, and (2) offer you this License\ngiving you legal permission to copy, distribute and/or modify it.\n\n  For the developers' and authors' protection, the GPL clearly explains\nthat there is no warranty for this free software.  For both users' and\nauthors' sake, the GPL requires that modified versions be marked as\nchanged, so that their problems will not be attributed erroneously to\nauthors of previous versions.\n\n  Some devices are designed to deny users access to install or run\nmodified versions of the software inside them, although the manufacturer\ncan do so.  This is fundamentally incompatible with the aim of\nprotecting users' freedom to change the software.  The systematic\npattern of such abuse occurs in the area of products for individuals to\nuse, which is precisely where it is most unacceptable.  Therefore, we\nhave designed this version of the GPL to prohibit the practice for those\nproducts.  If such problems arise substantially in other domains, we\nstand ready to extend this provision to those domains in future versions\nof the GPL, as needed to protect the freedom of users.\n\n  Finally, every program is threatened constantly by software patents.\nStates should not allow patents to restrict development and use of\nsoftware on general-purpose computers, but in those that do, we wish to\navoid the special danger that patents applied to a free program could\nmake it effectively proprietary.  To prevent this, the GPL assures that\npatents cannot be used to render the program non-free.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Use with the GNU Affero General Public License.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU Affero General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the special requirements of the GNU Affero General Public License,\nsection 13, concerning interaction through a network will apply to the\ncombination as such.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If the program does terminal interaction, make it output a short\nnotice like this when it starts in an interactive mode:\n\n    <program>  Copyright (C) <year>  <name of author>\n    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, your program's commands\nmight be different; for a GUI interface, you would use an \"about box\".\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU GPL, see\n<http://www.gnu.org/licenses/>.\n\n  The GNU General Public License does not permit incorporating your program\ninto proprietary programs.  If your program is a subroutine library, you\nmay consider it more useful to permit linking proprietary applications with\nthe library.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.  But first, please read\n<http://www.gnu.org/philosophy/why-not-lgpl.html>.\n"
  },
  {
    "path": "Makefile",
    "content": "tests:\n\tnosetests --exe --with-doctest tests/ explainshell/\n\nserve:\n\tpython runserver.py\n\n.PHONY: tests\n"
  },
  {
    "path": "README.md",
    "content": "# [explainshell.com](http://www.explainshell.com) - match command-line arguments to their help text\n\nexplainshell is a tool (with a web interface) capable of parsing man pages, extracting options and\nexplaining a given command-line by matching each argument to the relevant help text in the man page.\n\n## How?\n\nexplainshell is built from the following components:\n\n1. man page reader which converts a given man page from raw format to html (manpage.py)\n2. classifier which goes through every paragraph in the man page and classifies\n   it as contains options or not (algo/classifier.py)\n3. an options extractor that scans classified paragraphs and looks for options (options.py)\n4. a storage backend that saves processed man pages to mongodb (store.py)\n5. a matcher that walks the command's AST (parsed by [bashlex](https://github.com/idank/bashlex)) and contextually matches each node\n   to the relevant help text (matcher.py)\n\nWhen querying explainshell, it:\n\n1. parses the query into an AST\n2. visits interesting nodes in the AST, such as:\n   - command nodes - these nodes represent a simple command\n   - shell related nodes - these nodes represent something the shell\n     interprets such as '|', '&&'\n3. for every command node we check if we know how to explain the current program,\n   and then go through the rest of the tokens, trying to match each one to the\n   list of known options\n4. returns a list of matches that are rendered with Flask\n\n## Manpages\n\n> [!IMPORTANT]  \n>\n> explainshell is actively maintained in terms of keeping it healthy and functional -- issues are addressed, and the core remains stable.\n> \n> However, please note that the **manpages are outdated**. The previous system for generating them was unsustainable, and they haven’t been updated in some time. There are currently **no active plans** to revise this mechanism.\n> \n> If you're relying on manpages, be aware that they may not reflect the latest behavior. Contributions in this area are welcome but would require rethinking the documentation pipeline.\n\nRight now explainshell.com contains the entire [archive of Ubuntu](http://manpages.ubuntu.com/). It's not\npossible to directly add a missing man page to the live site (it might be in the future).\n\n## Running explainshell locally\n\nSetup a working environment that lets you run the web interface locally using docker:\n\n```ShellSession\n\n# download db dump\n$ curl -L -o /tmp/dump.gz https://github.com/idank/explainshell/releases/download/db-dump/dump.gz\n\n# Clone Repository\n$ git clone https://github.com/idank/explainshell.git\n\n# start containers, load man pages from dump\n$ docker-compose build\n$ docker-compose up\n\n$ docker-compose exec -T db mongorestore --archive --gzip < /tmp/dump.gz\n\n# run tests\n$ docker-compose exec -T web make tests\n..SSSSSSSSS.....................................................................\n----------------------------------------------------------------------\nRan 80 tests in 0.041s\n\nOK (SKIP=9)\n# open http://localhost:5001 to view the ui\n```\n\n### Processing a man page\n\nUse the manager to parse and save a gzipped man page in raw format:\n\n```ShellSession\n$ docker-compose exec -T web bash -c \"PYTHONPATH=. python explainshell/manager.py --log info /usr/share/man/man1/echo.1.gz\"\nINFO:explainshell.store:creating store, db = 'explainshell_tests', host = 'mongodb://localhost'\nINFO:explainshell.algo.classifier:train on 994 instances\nINFO:explainshell.manager:handling manpage echo (from /tmp/es/manpages/1/echo.1.gz)\nINFO:explainshell.store:looking up manpage in mapping with src 'echo'\nINFO:explainshell.manpage:executing '/tmp/es/tools/w3mman2html.cgi local=%2Ftmp%2Fes%2Fmanpages%2F1%2Fecho.1.gz'\nINFO:explainshell.algo.classifier:classified <paragraph 3, DESCRIPTION: '-n     do not output the trailing newlin'> (0.991381) as an option paragraph\nINFO:explainshell.algo.classifier:classified <paragraph 4, DESCRIPTION: '-e     enable interpretation of backslash escape'> (0.996904) as an option paragraph\nINFO:explainshell.algo.classifier:classified <paragraph 5, DESCRIPTION: '-E     disable interpretation of backslash escapes (default'> (0.998640) as an option paragraph\nINFO:explainshell.algo.classifier:classified <paragraph 6, DESCRIPTION: '--help display this help and exi'> (0.999215) as an option paragraph\nINFO:explainshell.algo.classifier:classified <paragraph 7, DESCRIPTION: '--version'> (0.999993) as an option paragraph\nINFO:explainshell.store:inserting mapping (alias) echo -> echo (52207a1fa9b52e42fb59df36) with score 10\nsuccessfully added echo\n```\n\nNote that if you've setup using the docker instructions above, echo will already be in the database.\n"
  },
  {
    "path": "docker-compose.yml",
    "content": "services:\n  db:\n    image: mongo\n  web:\n    build: .\n    command: make serve\n    environment:\n      - MONGO_URI=mongodb://db\n      - HOST_IP=0.0.0.0\n    volumes:\n      - .:/opt/webapp\n    ports:\n      - \"5001:5000\"\n    depends_on:\n      - db\n"
  },
  {
    "path": "explainshell/__init__.py",
    "content": ""
  },
  {
    "path": "explainshell/algo/__init__.py",
    "content": "import explainshell.algo.features\nimport explainshell.util\n"
  },
  {
    "path": "explainshell/algo/classifier.py",
    "content": "import itertools, collections, logging\n\nimport nltk\nimport nltk.metrics\nimport nltk.classify\nimport nltk.classify.maxent\n\nfrom explainshell import algo, config\n\nlogger = logging.getLogger(__name__)\n\ndef get_features(paragraph):\n    features = {}\n    ptext = paragraph.cleantext()\n    assert ptext\n\n    features['starts_with_hyphen'] = algo.features.starts_with_hyphen(ptext)\n    features['is_indented'] = algo.features.is_indented(ptext)\n    features['par_length'] = algo.features.par_length(ptext)\n    for w in ('=', '--', '[', '|', ','):\n        features['first_line_contains_%s' % w] = algo.features.first_line_contains(ptext, w)\n    features['first_line_length'] = algo.features.first_line_length(ptext)\n    features['first_line_word_count'] = algo.features.first_line_word_count(ptext)\n    features['is_good_section'] = algo.features.is_good_section(paragraph)\n    features['word_count'] = algo.features.word_count(ptext)\n\n    return features\n\nclass classifier(object):\n    '''classify the paragraphs of a man page as having command line options\n    or not'''\n    def __init__(self, store, algo, **classifier_args):\n        self.store = store\n        self.algo = algo\n        self.classifier_args = classifier_args\n        self.classifier = None\n\n    def train(self):\n        if self.classifier:\n            return\n\n        manpages = self.store.trainingset()\n\n        # flatten the manpages so we get a list of (manpage-name, paragraph)\n        def flatten_manpages(manpage):\n            l = []\n            for para in manpage.paragraphs:\n                l.append(para)\n            return l\n        paragraphs = itertools.chain(*[flatten_manpages(m) for m in manpages])\n        training = list(paragraphs)\n\n        negids = [p for p in training if not p.is_option]\n        posids = [p for p in training if p.is_option]\n\n        negfeats = [(get_features(p), False) for p in negids]\n        posfeats = [(get_features(p), True) for p in posids]\n\n        negcutoff = len(negfeats)*3/4\n        poscutoff = len(posfeats)*3/4\n\n        trainfeats = negfeats[:negcutoff] + posfeats[:poscutoff]\n        self.testfeats = negfeats[negcutoff:] + posfeats[poscutoff:]\n\n        logger.info('train on %d instances', len(trainfeats))\n\n        if self.algo == 'maxent':\n            c = nltk.classify.maxent.MaxentClassifier\n        elif self.algo == 'bayes':\n            c = nltk.classify.NaiveBayesClassifier\n        else:\n            raise ValueError('unknown classifier')\n\n        self.classifier = c.train(trainfeats, **self.classifier_args)\n\n    def evaluate(self):\n        self.train()\n        refsets = collections.defaultdict(set)\n        testsets = collections.defaultdict(set)\n\n        for i, (feats, label) in enumerate(self.testfeats):\n            refsets[label].add(i)\n            guess = self.classifier.prob_classify(feats)\n            observed = guess.max()\n            testsets[observed].add(i)\n            #if label != observed:\n            #    print 'label:', label, 'observed:', observed, feats\n\n        print 'pos precision:', nltk.metrics.precision(refsets[True], testsets[True])\n        print 'pos recall:', nltk.metrics.recall(refsets[True], testsets[True])\n        print 'neg precision:', nltk.metrics.precision(refsets[False], testsets[False])\n        print 'neg recall:', nltk.metrics.recall(refsets[False], testsets[False])\n\n        print self.classifier.show_most_informative_features(10)\n\n    def classify(self, manpage):\n        self.train()\n        for item in manpage.paragraphs:\n\n            features = get_features(item)\n            guess = self.classifier.prob_classify(features)\n            option = guess.max()\n            certainty = guess.prob(option)\n\n            if option:\n                if certainty < config.CLASSIFIER_CUTOFF:\n                    pass\n                else:\n                    logger.info('classified %s (%f) as an option paragraph', item, certainty)\n                    item.is_option = True\n                    yield certainty, item\n"
  },
  {
    "path": "explainshell/algo/features.py",
    "content": "import re\n\ndef extract_first_line(paragraph):\n    '''\n    >>> extract_first_line('a b  cd')\n    'a b'\n    >>> extract_first_line('a b cd')\n    'a b cd'\n    >>> extract_first_line('  a b cd')\n    'a b cd'\n    >>> extract_first_line('  a b   cd')\n    'a b'\n    '''\n    lines = paragraph.splitlines()\n    first = lines[0].strip()\n    spaces = list(re.finditer(r'(\\s+)', first))\n    # handle options that have their description in the first line by trying\n    # to treat it as two lines (looking at spaces between option and the rest\n    # of the text)\n    if spaces:\n        longest = max(spaces, key=lambda m: m.span()[1] - m.span()[0])\n        if longest and longest.start() > 1 and longest.end() - longest.start() > 1:\n            first = first[:longest.start()]\n    return first\n\ndef starts_with_hyphen(paragraph):\n    return paragraph.lstrip()[0] == '-'\n\ndef is_indented(paragraph):\n    return paragraph != paragraph.lstrip()\n\ndef par_length(paragraph):\n    return round(len(paragraph.strip()), -1) / 2\n\ndef first_line_contains(paragraph, what):\n    l = paragraph.splitlines()[0]\n    return what in l\n\ndef first_line_length(paragraph):\n    first = extract_first_line(paragraph)\n    return round(len(first), -1) / 2\n\ndef first_line_word_count(paragraph):\n    first = extract_first_line(paragraph)\n    splitted = [s for s in first.split() if len(s) > 1]\n\n    return round(len(splitted), -1)\n\ndef is_good_section(paragraph):\n    if not paragraph.section:\n        return False\n    s = paragraph.section.lower()\n    if 'options' in s:\n        return True\n    if s in ('description', 'function letters'):\n        return True\n    return False\n\ndef word_count(text):\n    return round(len(re.findall(r'\\w+', text)), -1)\n\ndef has_bold(html):\n    return '<b>' in html\n"
  },
  {
    "path": "explainshell/config.py",
    "content": "import os\n\n_currdir = os.path.dirname(os.path.dirname(__file__))\n\nMANPAGEDIR = os.path.join(_currdir, 'manpages')\nCLASSIFIER_CUTOFF = 0.7\nTOOLSDIR = os.path.join(_currdir, 'tools')\n\nMAN2HTML = os.path.join(TOOLSDIR, 'w3mman2html.cgi')\n\n# host to pass into Flask's app.run.\nHOST_IP = os.getenv('HOST_IP', False)\nMONGO_URI = os.getenv('MONGO_URI', 'mongodb://localhost')\nDEBUG = True\n\nLOGGING_DICT = {\n    'version': 1,\n    'disable_existing_loggers': False,\n    'formatters': {\n        'standard': {\n            'format': '%(asctime)s [%(levelname)s] %(name)s: %(message)s'\n        },\n    },\n    'handlers': {\n        'console': {\n            'level' : 'INFO',\n            'class' : 'logging.StreamHandler',\n            'formatter': 'standard',\n        },\n        'file': {\n            'class': 'logging.FileHandler',\n            'level': 'INFO',\n            'formatter': 'standard',\n            'filename': 'application.log',\n            'mode': 'a',\n        },\n    },\n    'loggers': {\n        'explainshell': {\n            'handlers': ['console'],\n            'level': 'INFO',\n            'propagate': False\n        }\n    }\n}\n"
  },
  {
    "path": "explainshell/errors.py",
    "content": "class ProgramDoesNotExist(Exception):\n    pass\n\nclass EmptyManpage(Exception):\n    pass\n"
  },
  {
    "path": "explainshell/fixer.py",
    "content": "import textwrap, logging\n\nfrom explainshell import util\n\nclass basefixer(object):\n    '''The base fixer class which other fixers inherit from.\n\n    Subclasses override the base methods in order to fix manpage content during\n    different parts of the parsing/classifying/saving process.'''\n    runbefore = []\n    runlast = False\n\n    def __init__(self, mctx):\n        self.mctx = mctx\n        self.run = True\n        self.logger = logging.getLogger(self.__class__.__name__)\n\n    def pre_get_raw_manpage(self):\n        pass\n\n    def pre_parse_manpage(self):\n        pass\n\n    def post_parse_manpage(self):\n        pass\n\n    def pre_classify(self):\n        pass\n\n    def post_classify(self):\n        pass\n\n    def post_option_extraction(self):\n        pass\n\n    def pre_add_manpage(self):\n        pass\n\nfixerscls = []\nfixerspriority = {}\n\nclass runner(object):\n    '''The runner coordinates the fixers.'''\n    def __init__(self, mctx):\n        self.mctx = mctx\n        self.fixers = [f(mctx) for f in fixerscls]\n\n    def disable(self, name):\n        before = len(self.fixers)\n        self.fixers = [f for f in self.fixers if f.__class__.__name__ != name]\n        if before == len(self.fixers):\n            raise ValueError('fixer %r not found' % name)\n\n    def _fixers(self):\n        return (f for f in self.fixers if f.run)\n\n    def pre_get_raw_manpage(self):\n        for f in self._fixers():\n            f.pre_get_raw_manpage()\n\n    def pre_parse_manpage(self):\n        for f in self._fixers():\n            f.pre_parse_manpage()\n\n    def post_parse_manpage(self):\n        for f in self._fixers():\n            f.post_parse_manpage()\n\n    def pre_classify(self):\n        for f in self._fixers():\n            f.pre_classify()\n\n    def post_classify(self):\n        for f in self._fixers():\n            f.post_classify()\n\n    def post_option_extraction(self):\n        for f in self._fixers():\n            f.post_option_extraction()\n\n    def pre_add_manpage(self):\n        for f in self._fixers():\n            f.pre_add_manpage()\n\ndef register(fixercls):\n    fixerscls.append(fixercls)\n    for f in fixercls.runbefore:\n        if not hasattr(f, '_parents'):\n            f._parents = []\n        f._parents.append(fixercls)\n    return fixercls\n\n@register\nclass bulletremover(basefixer):\n    '''remove list bullets from paragraph start, see mysqlslap.1'''\n    def post_parse_manpage(self):\n        toremove = []\n        for i, p in enumerate(self.mctx.manpage.paragraphs):\n            try:\n                idx = p.text.index('\\xc2\\xb7')\n                p.text = p.text[:idx] + p.text[idx+2:]\n                if not p.text.strip():\n                    toremove.append(i)\n            except ValueError:\n                pass\n        for i in reversed(toremove):\n            del self.mctx.manpage.paragraphs[i]\n\n@register\nclass leadingspaceremover(basefixer):\n    '''go over all known option paragraphs and remove their leading spaces\n    by the amount of spaces in the first line'''\n\n    def post_option_extraction(self):\n        for i, p in enumerate(self.mctx.manpage.options):\n            text = self._removewhitespace(p.text)\n            p.text = text\n\n    def _removewhitespace(self, text):\n        '''\n        >>> f = leadingspaceremover(None)\n        >>> f._removewhitespace(' a\\\\n  b ')\n        'a\\\\n b'\n        >>> f._removewhitespace('\\\\t a\\\\n\\\\t \\\\tb')\n        'a\\\\n\\\\tb'\n        '''\n        return textwrap.dedent(text).rstrip()\n\n@register\nclass tarfixer(basefixer):\n    def __init__(self, *args):\n        super(tarfixer, self).__init__(*args)\n        self.run = self.mctx.name == 'tar'\n\n    def pre_add_manpage(self):\n        self.mctx.manpage.partialmatch = True\n\n@register\nclass paragraphjoiner(basefixer):\n    runbefore = [leadingspaceremover]\n    maxdistance = 5\n\n    def post_option_extraction(self):\n        options = [p for p in self.mctx.manpage.paragraphs if p.is_option]\n        self._join(self.mctx.manpage.paragraphs, options)\n\n    def _join(self, paragraphs, options):\n        def _paragraphsbetween(op1, op2):\n            assert op1.idx < op2.idx\n            r = []\n            start = None\n            for i, p in enumerate(paragraphs):\n                if op1.idx < p.idx < op2.idx:\n                    if not r:\n                        start = i\n                    r.append(p)\n            return r, start\n\n        totalmerged = 0\n        for curr, next in util.pairwise(options):\n            between, start = _paragraphsbetween(curr, next)\n            if curr.section == next.section and 1 <= len(between) < self.maxdistance:\n                self.logger.info('merging paragraphs %d through %d (inclusive)', curr.idx, next.idx-1)\n                newdesc = [curr.text.rstrip()]\n                newdesc.extend([p.text.rstrip() for p in between])\n                curr.text = '\\n\\n'.join(newdesc)\n                del paragraphs[start:start+len(between)]\n                totalmerged += len(between)\n        return totalmerged\n\n@register\nclass optiontrimmer(basefixer):\n    runbefore = [paragraphjoiner]\n\n    d = {'git-rebase' : (50, -1)}\n\n    def __init__(self, mctx):\n        super(optiontrimmer, self).__init__(mctx)\n        self.run = self.mctx.name in self.d\n\n    def post_classify(self):\n        start, end = self.d[self.mctx.name]\n        classifiedoptions = [p for p in self.mctx.manpage.paragraphs if p.is_option]\n        assert classifiedoptions\n        if end == -1:\n            end = classifiedoptions[-1].idx\n        else:\n            assert start > end\n\n        for p in classifiedoptions:\n            if not (start <= p.idx <= end):\n                p.is_option = False\n                self.logger.info('removing option %r', p)\n\ndef _parents(fixercls):\n    p = getattr(fixercls, '_parents', [])\n    last = fixercls.runlast\n\n    if last and p:\n        raise ValueError(\"%s can't be last and also run before someone else\" % fixercls.__name__)\n\n    if last:\n        return [f for f in fixerscls if f is not fixercls]\n    return p\n\nfixerscls = util.toposorted(fixerscls, _parents)\n"
  },
  {
    "path": "explainshell/helpconstants.py",
    "content": "# -*- coding: utf-8 -*-\n\nimport textwrap\n\nNOSYNOPSIS = 'no synopsis found'\n\nPIPELINES = textwrap.dedent('''   <b>Pipelines</b>\n       A  <u>pipeline</u> is a sequence of one or more commands separated by one of the control operators <b>|</b> or <b>|&amp;</b>.  The\n       format for a pipeline is:\n\n              [<b>time</b> [<b>-p</b>]] [ ! ] <u>command</u> [ [<b>|</b>⎪<b>|&amp;</b>] <u>command2</u> ... ]\n\n       The standard output of <u>command</u> is connected  via  a  pipe  to  the  standard  input  of  <u>command2</u>.   This\n       connection  is performed before any redirections specified by the command (see <b>REDIRECTION</b> below).  If <b>|&amp;</b>\n       is used, the standard error of <u>command</u> is connected to <u>command2</u>'s standard input through the pipe; it  is\n       shorthand  for  <b>2&gt;&amp;1</b>  <b>|</b>.   This  implicit  redirection  of  the  standard  error  is  performed after any\n       redirections specified by the command.\n\n       The return status of a pipeline is the exit status of the last command, unless  the  <b>pipefail</b>  option  is\n       enabled.   If  <b>pipefail</b>  is  enabled,  the  pipeline's return status is the value of the last (rightmost)\n       command to exit with a non-zero status, or zero if all commands exit successfully.  If the reserved  word\n       <b>!</b>   precedes  a  pipeline, the exit status of that pipeline is the logical negation of the exit status as\n       described above.  The shell waits for all commands in the pipeline to terminate before returning a value.\n\n       If the <b>time</b> reserved word precedes a pipeline, the elapsed as well as user and system  time  consumed  by\n       its execution are reported when the pipeline terminates.  The <b>-p</b> option changes the output format to that\n       specified by POSIX.  When the shell is in <u>posix</u> <u>mode</u>, it does not recognize <b>time</b> as a  reserved  word  if\n       the  next  token begins with a `-'.  The <b>TIMEFORMAT</b> variable may be set to a format string that specifies\n       how the timing information should be displayed; see the description of <b>TIMEFORMAT</b> under  <b>Shell</b>  <b>Variables</b>\n       below.\n\n       When the shell is in <u>posix</u> <u>mode</u>, <b>time</b> may be followed by a newline.  In this case, the shell displays the\n       total user and system time consumed by the shell and its children.  The <b>TIMEFORMAT</b> variable may  be  used\n       to specify the format of the time information.\n\n       Each command in a pipeline is executed as a separate process (i.e., in a subshell).''')\n\nOPSEMICOLON = textwrap.dedent('''       Commands separated  by  a <b>;</b> are executed sequentially; the shell waits for each command to terminate in turn.  The\n       return status is the exit status of the last command executed.''')\n\nOPBACKGROUND = textwrap.dedent('''       If a command is terminated by the control operator <b>&amp;</b>, the shell executes the command in the <u>background</u> in\n       a subshell.  The shell does not wait for the command to finish, and the return  status  is  0.''')\n\nOPANDOR = textwrap.dedent('''       AND and OR lists are sequences of one of more pipelines separated by the <b>&amp;&amp;</b>  and  <b>||</b>  control  operators,\n       respectively.  AND and OR lists are executed with left associativity.  An AND list has the form\n\n              <u>command1</u> <b>&amp;&amp;</b> <u>command2</u>\n\n       <u>command2</u> is executed if, and only if, <u>command1</u> returns an exit status of zero.\n\n       An OR list has the form\n\n              <u>command1</u> <b>||</b> <u>command2</u>\n\n       <u>command2</u>  is  executed  if and only if <u>command1</u> returns a non-zero exit status.  The return status of AND\n       and OR lists is the exit status of the last command executed in the list.''')\n\nOPERATORS = {';' : OPSEMICOLON, '&' : OPBACKGROUND, '&&' : OPANDOR, '||' : OPANDOR}\n\nREDIRECTION = textwrap.dedent('''       Before a command is executed, its input and output may be <u>redirected</u> using a special notation interpreted\n       by  the  shell.   Redirection  may  also  be used to open and close files for the current shell execution\n       environment.  The following redirection operators may precede or appear anywhere within a <u>simple</u>  <u>command</u>\n       or may follow a <u>command</u>.  Redirections are processed in the order they appear, from left to right.''')\n\nREDIRECTING_INPUT = textwrap.dedent('''   <b>Redirecting</b> <b>Input</b>\n       Redirection  of  input  causes  the  file  whose name results from the expansion of <u>word</u> to be opened for\n       reading on file descriptor <u>n</u>, or the standard input (file descriptor 0) if <u>n</u> is not specified.\n\n       The general format for redirecting input is:\n\n              [<u>n</u>]<b>&lt;</b><u>word</u>''')\n\nREDIRECTING_OUTPUT = textwrap.dedent('''   <b>Redirecting</b> <b>Output</b>\n       Redirection of output causes the file whose name results from the expansion of  <u>word</u>  to  be  opened  for\n       writing  on  file descriptor <u>n</u>, or the standard output (file descriptor 1) if <u>n</u> is not specified.  If the\n       file does not exist it is created; if it does exist it is truncated to zero size.\n\n       The general format for redirecting output is:\n\n              [<u>n</u>]<b>&gt;</b><u>word</u>\n\n       If the redirection operator is <b>&gt;</b>, and the <b>noclobber</b> option to the  <b>set</b>  builtin  has  been  enabled,  the\n       redirection  will  fail if the file whose name results from the expansion of <u>word</u> exists and is a regular\n       file.  If the redirection operator is <b>&gt;|</b>, or the redirection operator is <b>&gt;</b> and the  <b>noclobber</b>  option  to\n       the  <b>set</b>  builtin  command  is  not  enabled, the redirection is attempted even if the file named by <u>word</u>\n       exists.''')\n\nAPPENDING_REDIRECTED_OUTPUT = textwrap.dedent('''   <b>Appending</b> <b>Redirected</b> <b>Output</b>\n       Redirection of output in this fashion causes the file whose name results from the expansion of <u>word</u> to be\n       opened  for  appending  on  file  descriptor  <u>n</u>,  or  the standard output (file descriptor 1) if <u>n</u> is not\n       specified.  If the file does not exist it is created.\n\n       The general format for appending output is:\n\n              [<u>n</u>]<b>&gt;&gt;</b><u>word</u>''')\n\nREDIRECTING_OUTPUT_ERROR = textwrap.dedent('''   <b>Redirecting</b> <b>Standard</b> <b>Output</b> <b>and</b> <b>Standard</b> <b>Error</b>\n       This construct allows both the standard output (file descriptor 1) and the standard  error  output  (file\n       descriptor 2) to be redirected to the file whose name is the expansion of <u>word</u>.\n\n       There are two formats for redirecting standard output and standard error:\n\n              <b>&amp;&gt;</b><u>word</u>\n       and\n              <b>&gt;&amp;</b><u>word</u>\n\n       Of the two forms, the first is preferred.  This is semantically equivalent to\n\n              <b>&gt;</b><u>word</u> 2<b>&gt;&amp;</b>1''')\n\nAPPENDING_OUTPUT_ERROR = textwrap.dedent('''   <b>Appending</b> <b>Standard</b> <b>Output</b> <b>and</b> <b>Standard</b> <b>Error</b>\n       This  construct  allows  both the standard output (file descriptor 1) and the standard error output (file\n       descriptor 2) to be appended to the file whose name is the expansion of <u>word</u>.\n\n       The format for appending standard output and standard error is:\n\n              <b>&amp;&gt;&gt;</b><u>word</u>\n\n       This is semantically equivalent to\n\n              <b>&gt;&gt;</b><u>word</u> 2<b>&gt;&amp;</b>1''')\n\nHERE_DOCUMENTS = textwrap.dedent('''   <b>Here</b> <b>Documents</b>\n       This type of redirection instructs the shell  to  read  input  from  the  current  source  until  a  line\n       containing  only <u>delimiter</u> (with no trailing blanks) is seen.  All of the lines read up to that point are\n       then used as the standard input for a command.\n\n       The format of here-documents is:\n\n              <b>&lt;&lt;</b>[<b>-</b>]<u>word</u>\n                      <u>here-document</u>\n              <u>delimiter</u>\n\n       No parameter expansion, command substitution, arithmetic expansion, or pathname expansion is performed on\n       <u>word</u>.   If  any  characters in <u>word</u> are quoted, the <u>delimiter</u> is the result of quote removal on <u>word</u>, and\n       the lines in the here-document are not expanded.  If <u>word</u> is unquoted, all lines of the here-document are\n       subjected  to  parameter  expansion, command substitution, and arithmetic expansion.  In the latter case,\n       the character sequence <b>\\&lt;newline&gt;</b> is ignored, and <b>\\</b> must be used to quote the characters <b>\\</b>, <b>$</b>, and <b>`</b>.\n\n       If the redirection operator is <b>&lt;&lt;-</b>, then all leading tab characters are stripped from input lines and the\n       line  containing  <u>delimiter</u>.  This allows here-documents within shell scripts to be indented in a natural\n       fashion.\n\n   <b>Here</b> <b>Strings</b>\n       A variant of here documents, the format is:\n\n              <b>&lt;&lt;&lt;</b><u>word</u>\n\n       The <u>word</u> is expanded and supplied to the command on its standard input.''')\n\nREDIRECTION_KIND = {'<' : REDIRECTING_INPUT,\n                   '>' : REDIRECTING_OUTPUT,\n                   '>>' : APPENDING_REDIRECTED_OUTPUT,\n                   '&>' : REDIRECTING_OUTPUT_ERROR,\n                   '>&' : REDIRECTING_OUTPUT_ERROR,\n                   '&>>' : APPENDING_OUTPUT_ERROR,\n                   '<<' : HERE_DOCUMENTS,\n                   '<<<' : HERE_DOCUMENTS}\n\nASSIGNMENT = textwrap.dedent('''       A <u>variable</u> may be assigned to by a statement of the form\n\n              <u>name</u>=[<u>value</u>]\n\n       If <u>value</u> is not given, the variable is assigned the null string.  All  <u>values</u>  undergo  tilde  expansion,\n       parameter  and  variable  expansion,  command  substitution, arithmetic expansion, and quote removal (see\n       <b>EXPANSION</b> below).  If the variable has  its  <b>integer</b>  attribute  set,  then  <u>value</u>  is  evaluated  as  an\n       arithmetic  expression even if the $((...)) expansion is not used (see <b>Arithmetic</b> <b>Expansion</b> below).  Word\n       splitting is not performed, with the exception of <b>\"$@\"</b>  as  explained  below  under  <b>Special</b>  <b>Parameters</b>.\n       Pathname  expansion  is  not performed.  Assignment statements may also appear as arguments to the <b>alias</b>,\n       <b>declare</b>, <b>typeset</b>, <b>export</b>, <b>readonly</b>, and <b>local</b> builtin commands.\n\n       In the context where an assignment statement is assigning a value to a shell variable or array index, the\n       +=  operator  can  be used to append to or add to the variable's previous value.  When += is applied to a\n       variable for which the <u>integer</u> attribute has been set, <u>value</u> is evaluated as an arithmetic expression and\n       added  to the variable's current value, which is also evaluated.  When += is applied to an array variable\n       using compound assignment (see <b>Arrays</b> below), the variable's value is not unset (as it is when using  =),\n       and  new  values  are  appended to the array beginning at one greater than the array's maximum index (for\n       indexed arrays) or added as additional key-value pairs in  an  associative  array.   When  applied  to  a\n       string-valued variable, <u>value</u> is expanded and appended to the variable's value.''')\n\n_group = textwrap.dedent('''       { <u>list</u>; }\n              <u>list</u> is simply executed in the current shell environment.  <u>list</u> must be terminated with a  newline\n              or  semicolon.   This  is known as a <u>group</u> <u>command</u>.  The return status is the exit status of <u>list</u>.\n              Note that unlike the metacharacters <b>(</b> and <b>)</b>, <b>{</b> and <b>}</b> are <u>reserved</u> <u>words</u> and  must  occur  where  a\n              reserved  word  is permitted to be recognized.  Since they do not cause a word break, they must be\n              separated from <u>list</u> by whitespace or another shell metacharacter.''')\n\n_subshell = textwrap.dedent('''       (<u>list</u>) <u>list</u> is executed in a subshell environment (see <b>COMMAND</b> <b>EXECUTION</b>  <b>ENVIRONMENT</b>  below).   Variable\n              assignments and builtin commands that affect the shell's environment do not remain in effect after\n              the command completes.  The return status is the exit status of <u>list</u>.''')\n\n_negate = '''If the reserved word <b>!</b> precedes a pipeline, the exit status of that pipeline is the logical negation of the\nexit status as described above.'''\n\n_if = textwrap.dedent('''       <b>if</b> <u>list</u>; <b>then</b> <u>list;</u> [ <b>elif</b> <u>list</u>; <b>then</b> <u>list</u>; ] ... [ <b>else</b> <u>list</u>; ] <b>fi</b>\n              The  <b>if</b> <u>list</u> is executed.  If its exit status is zero, the <b>then</b> <u>list</u> is executed.  Otherwise, each\n              <b>elif</b> <u>list</u> is executed in turn, and if its exit status is zero,  the  corresponding  <b>then</b>  <u>list</u>  is\n              executed  and  the command completes.  Otherwise, the <b>else</b> <u>list</u> is executed, if present.  The exit\n              status is the exit status of the last command executed, or zero if no condition tested true.''')\n\n_for = textwrap.dedent('''       <b>for</b> <u>name</u> [ [ <b>in</b> [ <u>word</u> <u>...</u> ] ] ; ] <b>do</b> <u>list</u> ; <b>done</b>\n              The  list of words following <b>in</b> is expanded, generating a list of items.  The variable <u>name</u> is set\n              to each element of this list in turn, and <u>list</u> is executed each time.  If the <b>in</b> <u>word</u> is  omitted,\n              the  <b>for</b>  command  executes  <u>list</u>  once  for each positional parameter that is set (see <b>PARAMETERS</b>\n              below).  The return status is the exit status of the last command that executes.  If the expansion\n              of  the  items  following  <b>in</b>  results  in an empty list, no commands are executed, and the return\n              status is 0.''')\n\n_whileuntil = textwrap.dedent('''       <b>while</b> <u>list-1</u>; <b>do</b> <u>list-2</u>; <b>done</b>\n       <b>until</b> <u>list-1</u>; <b>do</b> <u>list-2</u>; <b>done</b>\n              The <b>while</b> command continuously executes the list <u>list-2</u> as long as the last command  in  the  list\n              <u>list-1</u>  returns  an  exit  status  of  zero.  The <b>until</b> command is identical to the <b>while</b> command,\n              except that the test is negated; <u>list-2</u> is executed as long as the last command in <u>list-1</u>  returns\n              a non-zero exit status.  The exit status of the <b>while</b> and <b>until</b> commands is the exit status of the\n              last command executed in <u>list-2</u>, or zero if none was executed.''')\n\n_select = textwrap.dedent('''       <b>select</b> <u>name</u> [ <b>in</b> <u>word</u> ] ; <b>do</b> <u>list</u> ; <b>done</b>\n              The list of words following <b>in</b> is expanded, generating a list of items.  The set of expanded words\n              is printed on the standard error, each preceded by a number.  If  the  <b>in</b>  <u>word</u>  is  omitted,  the\n              positional  parameters are printed (see <b>PARAMETERS</b> below).  The <b>PS3</b> prompt is then displayed and a\n              line read from the standard input.  If the line consists of a number corresponding to one  of  the\n              displayed  words, then the value of <u>name</u> is set to that word.  If the line is empty, the words and\n              prompt are displayed again.  If EOF is read, the command completes.  Any other value  read  causes\n              <u>name</u> to be set to null.  The line read is saved in the variable <b>REPLY</b>.  The <u>list</u> is executed after\n              each selection until a <b>break</b> command is executed.  The exit status of <b>select</b> is the exit status of\n              the last command executed in <u>list</u>, or zero if no commands were executed.''')\n\nRESERVEDWORDS = {\n    '!' : _negate,\n    '{' : _group,\n    '}' : _group,\n    '(' : _subshell,\n    ')' : _subshell,\n    ';' : OPSEMICOLON,\n}\n\ndef _addwords(key, text, *words):\n    for word in words:\n        COMPOUNDRESERVEDWORDS.setdefault(key, {})[word] = text\n\nCOMPOUNDRESERVEDWORDS = {}\n_addwords('if', _if, 'if', 'then', 'elif', 'else', 'fi', ';')\n_addwords('for', _for, 'for', 'in', 'do', 'done', ';')\n_addwords('while', _whileuntil, 'while', 'do', 'done', ';')\n_addwords('until', _whileuntil, 'until', 'do', 'done')\n_addwords('select', _select, 'select', 'in', 'do', 'done')\n\n_function = textwrap.dedent('''       A shell function is an object that is called like a simple command and executes a compound command with a\n       new set of positional parameters.  Shell functions are declared as follows:\n\n       <u>name</u> () <u>compound-command</u> [<u>redirection</u>]\n       <b>function</b> <u>name</u> [()] <u>compound-command</u> [<u>redirection</u>]\n              This  defines  a  function  named  <u>name</u>.  The reserved word <b>function</b> is optional.  If the <b>function</b>\n              reserved word is supplied, the parentheses are optional.  The <u>body</u> of the function is the compound\n              command  <u>compound-command</u>  (see  <b>Compound</b>  <b>Commands</b>  above).   That  command  is usually a <u>list</u> of\n              commands between {  and  },  but  may  be  any  command  listed  under  <b>Compound</b>  <b>Commands</b>  above.\n              <u>compound-command</u>  is  executed  whenever  <u>name</u>  is specified as the name of a simple command.  Any\n              redirections (see <b>REDIRECTION</b> below) specified when a function is defined are performed  when  the\n              function  is  executed.   The  exit  status of a function definition is zero unless a syntax error\n              occurs or a readonly function with the same name already exists.  When executed, the  exit  status\n              of a function is the exit status of the last command executed in the body.  (See <b>FUNCTIONS</b> below.)''')\n\n_functioncall = 'call shell function %r'\n_functionarg = 'argument for shell function %r'\n\nCOMMENT = textwrap.dedent('''<b>COMMENTS</b>\n      In a non-interactive shell, or an interactive shell in which the <b>interactive_comments</b> option to the <b>shopt</b>\n      builtin is enabled (see <b>SHELL</b> <b>BUILTIN</b> <b>COMMANDS</b> below), a word beginning with <b>#</b> causes that word  and  all\n      remaining  characters  on that line to be ignored.  An interactive shell without the <b>interactive_comments</b>\n      option enabled does not allow comments.  The <b>interactive_comments</b> option is on by default in  interactive\n      shells.''')\n\nparameters = {\n        '*' : 'star',\n        '@' : 'at',\n        '#' : 'pound',\n        '?' : 'question',\n        '-' : 'hyphen',\n        '$' : 'dollar',\n        '!' : 'exclamation',\n        '0' : 'zero',\n        '_' : 'underscore',\n}\n"
  },
  {
    "path": "explainshell/manager.py",
    "content": "import sys, os, argparse, logging, glob\n\nfrom explainshell import options, store, fixer, manpage, errors, util, config\nfrom explainshell.algo import classifier\n\nlogger = logging.getLogger('explainshell.manager')\n\nclass managerctx(object):\n    def __init__(self, classifier, store, manpage):\n        self.classifier = classifier\n        self.store = store\n        self.manpage = manpage\n        self.name = manpage.name\n\n        self.classifiermanpage = None\n        self.optionsraw = None\n        self.optionsextracted = None\n        self.aliases = None\n\nclass manager(object):\n    '''the manager uses all parts of the system to read, classify, parse, extract\n    and write a man page to the database'''\n    def __init__(self, dbhost, dbname, paths, overwrite=False, drop=False):\n        self.paths = paths\n        self.overwrite = overwrite\n\n        self.store = store.store(dbname, dbhost)\n\n        self.classifier = classifier.classifier(self.store, 'bayes')\n        self.classifier.train()\n\n        if drop:\n            self.store.drop(True)\n\n    def ctx(self, m):\n        return managerctx(self.classifier, self.store, m)\n\n    def _read(self, ctx, frunner):\n        frunner.pre_get_raw_manpage()\n        ctx.manpage.read()\n        ctx.manpage.parse()\n        assert len(ctx.manpage.paragraphs) > 1\n\n        ctx.manpage = store.manpage(ctx.manpage.shortpath, ctx.manpage.name,\n                ctx.manpage.synopsis, ctx.manpage.paragraphs, list(ctx.manpage.aliases))\n        frunner.post_parse_manpage()\n\n    def _classify(self, ctx, frunner):\n        ctx.classifiermanpage = store.classifiermanpage(ctx.name, ctx.manpage.paragraphs)\n        frunner.pre_classify()\n        _ = list(ctx.classifier.classify(ctx.classifiermanpage))\n        frunner.post_classify()\n\n    def _extract(self, ctx, frunner):\n        options.extract(ctx.manpage)\n        frunner.post_option_extraction()\n        if not ctx.manpage.options:\n            logger.warn(\"couldn't find any options for manpage %s\", ctx.manpage.name)\n\n    def _write(self, ctx, frunner):\n        frunner.pre_add_manpage()\n        return ctx.store.addmanpage(ctx.manpage)\n\n    def _update(self, ctx, frunner):\n        frunner.pre_add_manpage()\n        return ctx.store.updatemanpage(ctx.manpage)\n\n    def process(self, ctx):\n        frunner = fixer.runner(ctx)\n\n        self._read(ctx, frunner)\n        self._classify(ctx, frunner)\n        self._extract(ctx, frunner)\n\n        m = self._write(ctx, frunner)\n        return m\n\n    def edit(self, m, paragraphs=None):\n        ctx = self.ctx(m)\n        frunner = fixer.runner(ctx)\n\n        if paragraphs:\n            m.paragraphs = paragraphs\n            frunner.disable('paragraphjoiner')\n            frunner.post_option_extraction()\n        else:\n            self._extract(ctx, frunner)\n        m = self._update(ctx, frunner)\n        return m\n\n    def run(self):\n        added = []\n        exists = []\n        for path in self.paths:\n            try:\n                m = manpage.manpage(path)\n                logger.info('handling manpage %s (from %s)', m.name, path)\n                try:\n                    mps = self.store.findmanpage(m.shortpath[:-3])\n                    mps = [mp for mp in mps if m.shortpath == mp.source]\n                    if mps:\n                        assert len(mps) == 1\n                        mp = mps[0]\n                        if not self.overwrite or mp.updated:\n                            logger.info('manpage %r already in the data store, not overwriting it', m.name)\n                            exists.append(m)\n                            continue\n                except errors.ProgramDoesNotExist:\n                    pass\n\n                # the manpage is not in the data store; process and add it\n                ctx = self.ctx(m)\n                m = self.process(ctx)\n                if m:\n                    added.append(m)\n            except errors.EmptyManpage, e:\n                logger.error('manpage %r is empty!', e.args[0])\n            except ValueError:\n                logger.fatal('uncaught exception when handling manpage %s', path)\n            except KeyboardInterrupt:\n                raise\n            except:\n                logger.fatal('uncaught exception when handling manpage %s', path)\n                raise\n        if not added:\n            logger.warn('no manpages added')\n        else:\n            self.findmulticommands()\n\n        return added, exists\n\n    def findmulticommands(self):\n        manpages = {}\n        potential = []\n        for _id, m in self.store.names():\n            if '-' in m:\n                potential.append((m.split('-'), _id))\n            else:\n                manpages[m] = _id\n\n        mappings = set([x[0] for x in self.store.mappings()])\n        mappingstoadd = []\n        multicommands = {}\n\n        for p, _id in potential:\n            if ' '.join(p) in mappings:\n                continue\n            if p[0] in manpages:\n                mappingstoadd.append((' '.join(p), _id))\n                multicommands[p[0]] = manpages[p[0]]\n\n        for src, dst in mappingstoadd:\n            self.store.addmapping(src, dst, 1)\n            logger.info('inserting mapping (multicommand) %s -> %s', src, dst)\n\n        for multicommand, _id in multicommands.iteritems():\n            self.store.setmulticommand(_id)\n            logger.info('making %r a multicommand', multicommand)\n\n        return mappingstoadd, multicommands\n\ndef main(files, dbname, dbhost, overwrite, drop, verify):\n    if verify:\n        s = store.store(dbname, dbhost)\n        ok = s.verify()\n        return 0 if ok else 1\n\n    if drop:\n        if raw_input('really drop db (y/n)? ').strip().lower() != 'y':\n            drop = False\n        else:\n            overwrite = True # if we drop, no need to take overwrite into account\n\n    gzs = set()\n\n    for path in files:\n        if os.path.isdir(path):\n            gzs.update([os.path.abspath(f) for f in glob.glob(os.path.join(path, '*.gz'))])\n        else:\n            gzs.add(os.path.abspath(path))\n\n    m = manager(dbhost, dbname, gzs, overwrite, drop)\n    added, exists = m.run()\n    for mp in added:\n        print 'successfully added %s' % mp.source\n    if exists:\n        print 'these manpages already existed and werent overwritten: \\n\\n%s' % '\\n'.join([m.path for m in exists])\n\nif __name__ == '__main__':\n    parser = argparse.ArgumentParser(description='process man pages and save them in the store')\n    parser.add_argument('--log', type=str, default='ERROR', help='use log as the logger log level')\n    parser.add_argument('--overwrite', action='store_true', default=False, help='overwrite man pages that already exist in the store')\n    parser.add_argument('--drop', action='store_true', default=False, help='delete all existing man pages')\n    parser.add_argument('--db', default='explainshell', help='mongo db name')\n    parser.add_argument('--host', default=config.MONGO_URI, help='mongo host')\n    parser.add_argument('--verify', action='store_true', default=False, help='verify db integrity')\n    parser.add_argument('files', nargs='*')\n\n    args = parser.parse_args()\n    logging.basicConfig(level=getattr(logging, args.log.upper()))\n    sys.exit(main(args.files, args.db, args.host, args.overwrite, args.drop, args.verify))\n"
  },
  {
    "path": "explainshell/manpage.py",
    "content": "import os, subprocess, re, logging, collections, urllib\n\nfrom explainshell import config, store, errors\n\ndevnull = open(os.devnull, 'w')\nSPLITSYNOP = re.compile(r'([^ ]+) - (.*)$')\n\nENV = dict(os.environ)\nENV[\"W3MMAN_MAN\"] = \"man --no-hyphenation\"\nENV[\"MAN_KEEP_FORMATTING\"] = \"1\"\nENV[\"MANWIDTH\"] = \"115\"\nENV[\"LC_ALL\"] = \"en_US.UTF-8\"\n\nlogger = logging.getLogger(__name__)\n\ndef extractname(gzname):\n    '''\n    >>> extractname('ab.1.gz')\n    'ab'\n    >>> extractname('ab.1.1.gz')\n    'ab.1'\n    >>> extractname('ab.1xyz.gz')\n    'ab'\n    >>> extractname('ab.1.1xyz.gz')\n    'ab.1'\n    >>> extractname('a/b/c/ab.1.1xyz.gz')\n    'ab.1'\n    '''\n    if '/' in gzname:\n        gzname = os.path.basename(gzname)\n    return gzname.rsplit('.', 2)[0]\n\ndef bold(l):\n    '''\n    >>> bold('a')\n    ([], ['a'])\n    >>> bold('<b>a</b>')\n    (['a'], [])\n    >>> bold('a<b>b</b>c')\n    (['b'], ['a', 'c'])\n    >>> bold('<b>first</b> <b>second:</b>')\n    (['first', 'second:'], [])\n    '''\n    inside = []\n    for m in _section.finditer(l):\n        inside.append(m.span(0))\n\n    current = 0\n    outside = []\n    for start, end in inside:\n        outside.append((current, start))\n        current = end\n    outside.append((current, len(l)))\n\n    inside = [l[s:e] for s, e in inside]\n    inside = [s.replace('<b>', '').replace('</b>', '') for s in inside]\n\n    outside = [l[s:e] for s, e in outside]\n    outside = [l for l in outside if l and not l.isspace()]\n    return inside, outside\n\n# w3mman2html.cgi (the tool we're using to output html from a man page) does\n# some strange escaping which causes it to output invalid utf8. we look these\n# up and fix them manually\n_replacementsprefix = [\n        ('\\xe2\\x80\\xe2\\x80\\x98', None, True), # left single quote\n        ('\\xe2\\x80\\xe2\\x80\\x99', None, True), # right single quote\n        ('\\xe2\\x80\\xe2\\x80\\x9c', None, True), # left double quote\n        ('\\xe2\\x80\\xe2\\x80\\x9d', None, True), # right double quote\n        ('\\xe2\\x94\\xe2\\x94\\x82', '|', False), # pipe\n        ('\\xe2\\x8e\\xe2\\x8e\\xaa', None, False), # pipe 2\n        ('\\xe2\\x80\\xe2\\x80\\x90', None, True), # hyphen\n        ('\\xe2\\x80\\xe2\\x80\\x94', None, True), # hyphen 2\n        ('\\xe2\\x80\\xc2\\xbd', None, True), # half\n        ('\\xe2\\x88\\xe2\\x88\\x97', None, True), # asterisk\n        ('\\xe2\\x86\\xe2\\x86\\x92', None, True), # right arrow\n        ('\\xe2\\x88\\xe2\\x88\\x92', None, True), # minus sign\n        ('\\xe2\\x80\\xe2\\x80\\x93', None, True), # en dash\n        ('\\xe2\\x80\\xe2\\x80\\xb2', None, False), # prime\n        ('\\xe2\\x88\\xe2\\x88\\xbc', None, False), # tilde operator\n        ('\\xe2\\x86\\xe2\\x86\\xb5', None, False), # downwards arrow with corner leftwards\n        ('\\xef\\xbf\\xef\\xbf\\xbd', None, False) # replacement char\n        ]\n\n_replacements = []\n\nfor searchfor, replacewith, underline in _replacementsprefix:\n    if replacewith is None:\n        replacewith = searchfor[2:]\n    _replacements.append((searchfor, replacewith))\n    if underline:\n        x = list(replacewith)\n        x.insert(1, '</u>')\n        x = ''.join(x)\n        _replacements.append((x, '%s</u>' % replacewith))\n\n_replacementsnoprefix = ['\\xc2\\xb7', # bullet\n        '\\xc2\\xb4', # apostrophe\n        '\\xc2\\xa0', # no break space\n        '\\xc3\\xb8', '\\xe4\\xbd\\xa0', '\\xe5\\xa5\\xbd', # gibberish\n        '\\xc2\\xa7', # section sign\n        '\\xef\\xbf\\xbd', # replacement char\n        '\\xc2\\xa4',  # latin small letter a with diaeresis\n        '\\xc3\\xa4', # latin small letter a with diaeresis\n        '\\xc4\\xa4',  # latin small letter a with diaeresis\n        '\\xc3\\xaa',  # latin small letter e with circumflex\n        ]\n\nfor s in _replacementsnoprefix:\n    x = list(s)\n    x.insert(1, '</u>')\n    x = ''.join(x)\n    _replacements.append((x, '%s</u>' % s))\n\n_href = re.compile(r'<a href=\"file:///[^\\?]*\\?([^\\(]*)\\(([^\\)]*)\\)\">')\n_section = re.compile(r'<b>([^<]+)</b>')\n\ndef _parsetext(lines):\n    paragraphlines = []\n    section = None\n    i = 0\n    for l in lines:\n        l = re.sub(_href, r'<a href=\"http://manpages.ubuntu.com/manpages/precise/en/man\\2/\\1.\\2.html\">', l)\n        for lookfor, replacewith in _replacements:\n            l = re.sub(lookfor, replacewith, l)\n        # confirm the line is valid utf8\n        lreplaced = l.decode('utf8', 'ignore').encode('utf8')\n        if lreplaced != l:\n            logger.error('line %r contains invalid utf8', l)\n            l = lreplaced\n            raise ValueError\n        if l.startswith('<b>'): # section\n            section = re.sub(_section, r'\\1', l)\n        else:\n            foundsection = False\n            if l.strip().startswith('<b>'):\n                inside, outside = bold(l.strip())\n                if not outside and inside[-1][-1] == ':':\n                    foundsection = True\n                    section = ' '.join(inside)[:-1]\n            if not foundsection:\n                if not l.strip() and paragraphlines:\n                    yield store.paragraph(i, '\\n'.join(paragraphlines), section, False)\n                    i += 1\n                    paragraphlines = []\n                elif l.strip():\n                    paragraphlines.append(l)\n    if paragraphlines:\n        yield store.paragraph(i, '\\n'.join(paragraphlines), section, False)\n\ndef _parsesynopsis(base, synopsis):\n    '''\n    >>> _parsesynopsis('/a/b/c', '/a/b/c: \"p-r+o++g - foo bar.\"')\n    ('p-r+o++g', 'foo bar')\n    '''\n    synopsis = synopsis[len(base)+3:-1]\n    if synopsis[-1] == '.':\n        synopsis = synopsis[:-1]\n    return SPLITSYNOP.match(synopsis).groups()\n\nclass manpage(object):\n    '''read the man page at path by executing w3mman2html.cgi and find its\n    synopsis with lexgrog\n\n    since some man pages share the same name (different versions), each\n    alias of a man page has a score that's determined in this simple fashion:\n    - name of man page source file is given a score of 10\n    - all other names found for a particular man page are given a score of 1\n      (other names are found by scanning the output of lexgrog)\n    '''\n    def __init__(self, path):\n        self.path = path\n        self.shortpath = os.path.basename(self.path)\n        self.name = extractname(self.path)\n        self.aliases = set([self.name])\n        self.synopsis = None\n        self.paragraphs = None\n        self._text = None\n\n    def read(self):\n        '''Read the content from a local manpage file and store it in usable formats\n        on the class instance.'''\n        cmd = [config.MAN2HTML, urllib.urlencode({'local' : os.path.abspath(self.path)})]\n        logger.info('executing %r', ' '.join(cmd))\n        self._text = subprocess.check_output(cmd, stderr=devnull, env=ENV)\n        try:\n            self.synopsis = subprocess.check_output(['lexgrog', self.path], stderr=devnull).rstrip()\n        except subprocess.CalledProcessError:\n            logger.error('failed to extract synopsis for %s', self.name)\n\n    def parse(self):\n        self.paragraphs = list(_parsetext(self._text.splitlines()[7:-3]))\n        if not self.paragraphs:\n            raise errors.EmptyManpage(self.shortpath)\n        if self.synopsis:\n            self.synopsis = [_parsesynopsis(self.path, l) for l in self.synopsis.splitlines()]\n\n            # figure out aliases from the synopsis\n            d = collections.OrderedDict()\n            for prog, text in self.synopsis:\n                d.setdefault(text, []).append(prog)\n            text, progs = d.items()[0]\n            self.synopsis = text\n            self.aliases.update(progs)\n        self.aliases.remove(self.name)\n\n        # give the name of the man page the highest score\n        self.aliases = [(self.name, 10)] + [(x, 1) for x in self.aliases]\n"
  },
  {
    "path": "explainshell/matcher.py",
    "content": "import collections, logging, itertools\n\nimport bashlex.parser\nimport bashlex.ast\n\nfrom explainshell import errors, util, helpconstants\n\nclass matchgroup(object):\n    '''a class to group matchresults together\n\n    we group all shell results in one group and create a new group for every\n    command'''\n    def __init__(self, name):\n        self.name = name\n        self.results = []\n\n    def __repr__(self):\n        return '<matchgroup %r with %d results>' % (self.name, len(self.results))\n\nclass matchresult(collections.namedtuple('matchresult', 'start end text match')):\n    @property\n    def unknown(self):\n        return self.text is None\n\nmatchwordexpansion = collections.namedtuple('matchwordexpansion',\n                                            'start end kind')\n\nlogger = logging.getLogger(__name__)\n\nclass matcher(bashlex.ast.nodevisitor):\n    '''parse a command line and return a list of matchresults describing\n    each token.\n    '''\n    def __init__(self, s, store):\n        self.s = s.encode('latin1', 'replace')\n        self.store = store\n        self._prevoption = self._currentoption = None\n        self.groups = [matchgroup('shell')]\n\n        # a list of matchwordexpansions where expansions happened during word\n        # expansion\n        self.expansions = []\n\n        # a stack to manage nested command groups: whenever a new simple\n        # command is started, we push a tuple with:\n        # - the node that started this group. this is used to find it when\n        #   a command ends (see visitnodeend)\n        # - its matchgroup. new matchresults will be added to it.\n        # - a word used to end the top-most command. this is used when a flag\n        #   starts a new command, e.g.  find -exec.\n        self.groupstack = [(None, self.groups[-1], None)]\n\n        # keep a stack of the currently visited compound command (if/for..)\n        # to provide context when matching reserved words, since for example\n        # the keyword 'done' can appear in a for, while..\n        self.compoundstack = []\n\n        # a set of functions defined in the current input, we will try to match\n        # commands against them so if one refers to defined function, it won't\n        # show up as unknown or be taken from the db\n        self.functions = set()\n\n    def _generatecommandgroupname(self):\n        existing = len([g for g in self.groups if g.name.startswith('command')])\n        return 'command%d' % existing\n\n    @property\n    def matches(self):\n        '''return the list of results from the most recently created group'''\n        return self.groupstack[-1][1].results\n\n    @property\n    def allmatches(self):\n        return list(itertools.chain.from_iterable(g.results for g in self.groups))\n\n    @property\n    def manpage(self):\n        group = self.groupstack[-1][1]\n        # we do not have a manpage if the top of the stack is the shell group.\n        # this can happen if the first argument is a command substitution\n        # and we're not treating it as a \"man page not found\"\n        if group.name != 'shell':\n            return group.manpage\n\n    def find_option(self, opt):\n        self._currentoption = self.manpage.find_option(opt)\n        logger.debug('looking up option %r, got %r', opt, self._currentoption)\n        return self._currentoption\n\n    def findmanpages(self, prog):\n        prog = prog.decode('latin1')\n        logger.info('looking up %r in store', prog)\n        manpages = self.store.findmanpage(prog)\n        logger.info('found %r in store, got: %r, using %r', prog, manpages, manpages[0])\n        return manpages\n\n    def unknown(self, token, start, end):\n        logger.debug('nothing to do with token %r', token)\n        return matchresult(start, end, None, None)\n\n    def visitreservedword(self, node, word):\n        # first try the compound reserved words\n        helptext = None\n        if self.compoundstack:\n            currentcompound = self.compoundstack[-1]\n            helptext = helpconstants.COMPOUNDRESERVEDWORDS.get(currentcompound, {}).get(word)\n\n        # try these if we don't have anything specific\n        if not helptext:\n            helptext = helpconstants.RESERVEDWORDS[word]\n\n        self.groups[0].results.append(matchresult(node.pos[0], node.pos[1], helptext, None))\n\n    def visitoperator(self, node, op):\n        helptext = None\n        if self.compoundstack:\n            currentcompound = self.compoundstack[-1]\n            helptext = helpconstants.COMPOUNDRESERVEDWORDS.get(currentcompound, {}).get(op)\n\n        if not helptext:\n            helptext = helpconstants.OPERATORS[op]\n\n        self.groups[0].results.append(matchresult(node.pos[0], node.pos[1], helptext, None))\n\n    def visitpipe(self, node, pipe):\n        self.groups[0].results.append(\n                matchresult(node.pos[0], node.pos[1], helpconstants.PIPELINES, None))\n\n    def visitredirect(self, node, input, type, output, heredoc):\n        helptext = [helpconstants.REDIRECTION]\n\n        if type == '>&' and isinstance(output, int):\n            type = type[:-1]\n\n        if type in helpconstants.REDIRECTION_KIND:\n            helptext.append(helpconstants.REDIRECTION_KIND[type])\n\n        self.groups[0].results.append(\n                matchresult(node.pos[0], node.pos[1], '\\n\\n'.join(helptext), None))\n\n        # the output might contain a wordnode, visiting it will confuse the\n        # matcher who'll think it's an argument, instead visit the expansions\n        # directly, if we have any\n        if isinstance(output, bashlex.ast.node):\n            for part in output.parts:\n                self.visit(part)\n\n        return False\n\n    def visitcommand(self, node, parts):\n        assert parts\n\n        # look for the first WordNode, which might not be at parts[0]\n        idxwordnode = bashlex.ast.findfirstkind(parts, 'word')\n        if idxwordnode == -1:\n            logger.info('no words found in command (probably contains only redirects)')\n            return\n\n        wordnode = parts[idxwordnode]\n\n        # check if this refers to a previously defined function\n        if wordnode.word in self.functions:\n            logger.info('word %r is a function, not trying to match it or its '\n                        'arguments', wordnode)\n\n            # first, add a matchresult for the function call\n            mr = matchresult(wordnode.pos[0], wordnode.pos[1],\n                             helpconstants._functioncall % wordnode.word, None)\n            self.matches.append(mr)\n\n            # this is a bit nasty: if we were to visit the command like we\n            # normally do it would try to match it against a manpage. but\n            # we don't have one here, we just want to take all the words and\n            # consider them part of the function call\n            for part in parts:\n                # maybe it's a redirect...\n                if part.kind != 'word':\n                    self.visit(part)\n                else:\n                    # this is an argument to the function\n                    if part is not wordnode:\n                        mr = matchresult(part.pos[0], part.pos[1],\n                                         helpconstants._functionarg % wordnode.word,\n                                         None)\n                        self.matches.append(mr)\n\n                        # visit any expansions in there\n                        for ppart in part.parts:\n                            self.visit(ppart)\n\n            # we're done with this commandnode, don't visit its children\n            return False\n\n\n        self.startcommand(node, parts, None)\n\n    def visitif(self, *args):\n        self.compoundstack.append('if')\n    def visitfor(self, node, parts):\n        self.compoundstack.append('for')\n\n        for part in parts:\n            # don't visit words since they're not part of the current command,\n            # instead consider them part of the for construct\n            if part.kind == 'word':\n                mr = matchresult(part.pos[0], part.pos[1], helpconstants._for, None)\n                self.groups[0].results.append(mr)\n\n                # but we do want to visit expanions\n                for ppart in part.parts:\n                    self.visit(ppart)\n            else:\n                self.visit(part)\n\n        return False\n\n    def visitwhile(self, *args):\n        self.compoundstack.append('while')\n    def visituntil(self, *args):\n        self.compoundstack.append('until')\n\n    def visitnodeend(self, node):\n        if node.kind == 'command':\n            # it's possible for visitcommand/end to be called without a command\n            # group being pushed if it contains only redirect nodes\n            if len(self.groupstack) > 1:\n                logger.info('visitnodeend %r, groups %d', node, len(self.groupstack))\n\n                while self.groupstack[-1][0] is not node:\n                    logger.info('popping groups that are a result of nested commands')\n                    self.endcommand()\n                self.endcommand()\n        elif node.kind in ('if', 'for', 'while', 'until'):\n            kind = self.compoundstack.pop()\n            assert kind == node.kind\n\n    def startcommand(self, commandnode, parts, endword, addgroup=True):\n        logger.info('startcommand commandnode=%r parts=%r, endword=%r, addgroup=%s',\n                    commandnode, parts, endword, addgroup)\n        idxwordnode = bashlex.ast.findfirstkind(parts, 'word')\n        assert idxwordnode != -1\n\n        wordnode = parts[idxwordnode]\n        if wordnode.parts:\n            logger.info('node %r has parts (it was expanded), no point in looking'\n                        ' up a manpage for it', wordnode)\n\n            if addgroup:\n                mg = matchgroup(self._generatecommandgroupname())\n                mg.manpage = None\n                mg.suggestions = None\n                self.groups.append(mg)\n                self.groupstack.append((commandnode, mg, endword))\n\n            return False\n\n        startpos, endpos = wordnode.pos\n\n        try:\n            mps = self.findmanpages(wordnode.word)\n            # we consume this node here, pop it from parts so we\n            # don't visit it again as an argument\n            parts.pop(idxwordnode)\n        except errors.ProgramDoesNotExist, e:\n            if addgroup:\n                # add a group for this command, we'll mark it as unknown\n                # when visitword is called\n                logger.info('no manpage found for %r, adding a group for it',\n                            wordnode.word)\n\n                mg = matchgroup(self._generatecommandgroupname())\n                mg.error = e\n                mg.manpage = None\n                mg.suggestions = None\n                self.groups.append(mg)\n                self.groupstack.append((commandnode, mg, endword))\n\n            return False\n\n        manpage = mps[0]\n        idxnextwordnode = bashlex.ast.findfirstkind(parts, 'word')\n\n        # check the next word for a possible multicommand if:\n        # - the matched manpage says so\n        # - we have another word node\n        # - the word node has no expansions in it\n        if manpage.multicommand and idxnextwordnode != -1 and not parts[idxnextwordnode].parts:\n            nextwordnode = parts[idxnextwordnode]\n            try:\n                multi = '%s %s' % (wordnode.word, nextwordnode.word)\n                logger.info('%r is a multicommand, trying to get another token and look up %r', manpage, multi)\n                mps = self.findmanpages(multi)\n                manpage = mps[0]\n                # we consume this node here, pop it from parts so we\n                # don't visit it again as an argument\n                parts.pop(idxnextwordnode)\n                endpos = nextwordnode.pos[1]\n            except errors.ProgramDoesNotExist:\n                logger.info('no manpage %r for multicommand %r', multi, manpage)\n\n        # create a new matchgroup for the current command\n        mg = matchgroup(self._generatecommandgroupname())\n        mg.manpage = manpage\n        mg.suggestions = mps[1:]\n        self.groups.append(mg)\n        self.groupstack.append((commandnode, mg, endword))\n\n        self.matches.append(matchresult(startpos, endpos,\n                            manpage.synopsis or helpconstants.NOSYNOPSIS, None))\n        return True\n\n    def endcommand(self):\n        '''end the most recently created command group by popping it from the\n        group stack. groups are created by visitcommand or a nested command'''\n        assert len(self.groupstack) >= 2, 'groupstack must contain shell and command groups'\n        g = self.groupstack.pop()\n        logger.info('ending group %s', g)\n\n    def visitcommandsubstitution(self, node, command):\n        kind = self.s[node.pos[0]]\n        substart = 2 if kind == '$' else 1\n\n        # start the expansion after the $( or `\n        self.expansions.append(matchwordexpansion(node.pos[0] + substart,\n                                                  node.pos[1] - 1,\n                                                  'substitution'))\n\n        # do not try to match the child nodes\n        return False\n\n    def visitprocesssubstitution(self, node, command):\n        # don't include opening <( and closing )\n        self.expansions.append(matchwordexpansion(node.pos[0] + 2,\n                                                  node.pos[1] - 1,\n                                                  'substitution'))\n\n        # do not try to match the child nodes\n        return False\n\n    def visitassignment(self, node, word):\n        helptext = helpconstants.ASSIGNMENT\n        self.groups[0].results.append(matchresult(node.pos[0], node.pos[1], helptext, None))\n\n    def visitword(self, node, word):\n        def attemptfuzzy(chars):\n            m = []\n            if chars[0] == '-':\n                tokens = [chars[0:2]] + list(chars[2:])\n                considerarg = True\n            else:\n                tokens = list(chars)\n                considerarg = False\n\n            pos = node.pos[0]\n            prevoption = None\n            for i, t in enumerate(tokens):\n                op = t if t[0] == '-' else '-' + t\n                option = self.find_option(op)\n                if option:\n                    if considerarg and not m and option.expectsarg:\n                        logger.info('option %r expected an arg, taking the rest too', option)\n                        # reset the current option if we already took an argument,\n                        # this prevents the next word node to also consider itself\n                        # as an argument\n                        self._currentoption = None\n                        return [matchresult(pos, pos+len(chars), option.text, None)]\n\n                    mr = matchresult(pos, pos+len(t), option.text, None)\n                    m.append(mr)\n                # if the previous option expected an argument and we couldn't\n                # match the current token, take the rest as its argument, this\n                # covers a series of short options where the last one has an argument\n                # with no space between it, such as 'xargs -r0n1'\n                elif considerarg and prevoption and prevoption.expectsarg:\n                    pmr = m[-1]\n                    mr = matchresult(pmr.start, pmr.end+(len(tokens)-i), pmr.text, None)\n                    m[-1] = mr\n                    # reset the current option if we already took an argument,\n                    # this prevents the next word node to also consider itself\n                    # as an argument\n                    self._currentoption = None\n                    break\n                else:\n                    m.append(self.unknown(t, pos, pos+len(t)))\n                pos += len(t)\n                prevoption = option\n            return m\n\n        def _visitword(node, word):\n            if not self.manpage:\n                logger.info('inside an unknown command, giving up on %r', word)\n                self.matches.append(self.unknown(word, node.pos[0], node.pos[1]))\n                return\n\n            logger.info('trying to match token: %r', word)\n\n            self._prevoption = self._currentoption\n            if word.startswith('--'):\n                word = word.split('=', 1)[0]\n            option = self.find_option(word)\n            if option:\n                logger.info('found an exact match for %r: %r', word, option)\n                mr = matchresult(node.pos[0], node.pos[1], option.text, None)\n                self.matches.append(mr)\n\n                # check if we splitted the word just above, if we did then reset\n                # the current option so the next word doesn't consider itself\n                # an argument\n                if word != node.word:\n                    self._currentoption = None\n            else:\n                word = node.word\n\n                # check if we're inside a nested command and this word marks the end\n                if isinstance(self.groupstack[-1][-1], list) and word in self.groupstack[-1][-1]:\n                    logger.info('token %r ends current nested command', word)\n                    self.endcommand()\n                    mr = matchresult(node.pos[0], node.pos[1], self.matches[-1].text, None)\n                    self.matches.append(mr)\n                elif word != '-' and word.startswith('-') and not word.startswith('--'):\n                    logger.debug('looks like a short option')\n                    if len(word) > 2:\n                        logger.info(\"trying to split it up\")\n                        self.matches.extend(attemptfuzzy(word))\n                    else:\n                        self.matches.append(self.unknown(word, node.pos[0], node.pos[1]))\n                elif self._prevoption and self._prevoption.expectsarg:\n                    logger.info(\"previous option possibly expected an arg, and we can't\"\n                            \" find an option to match the current token, assuming it's an arg\")\n                    ea = self._prevoption.expectsarg\n                    possibleargs = ea if isinstance(ea, list) else []\n                    take = True\n                    if possibleargs and word not in possibleargs:\n                        take = False\n                        logger.info('token %r not in list of possible args %r for %r',\n                                    word, possibleargs, self._prevoption)\n                    if take:\n                        if self._prevoption.nestedcommand:\n                            logger.info('option %r can nest commands', self._prevoption)\n                            if self.startcommand(None, [node], self._prevoption.nestedcommand, addgroup=False):\n                                self._currentoption = None\n                                return\n\n                        pmr = self.matches[-1]\n                        mr = matchresult(pmr.start, node.pos[1], pmr.text, None)\n                        self.matches[-1] = mr\n                    else:\n                        self.matches.append(self.unknown(word, node.pos[0], node.pos[1]))\n                else:\n                    if self.manpage.partialmatch:\n                        logger.info('attemping to do a partial match')\n\n                        m = attemptfuzzy(word)\n                        if not any(mm.unknown for mm in m):\n                            logger.info('found a match for everything, taking it')\n                            self.matches.extend(m)\n                            return\n\n                    if self.manpage.arguments:\n                        if self.manpage.nestedcommand:\n                            logger.info('manpage %r can nest commands', self.manpage)\n                            if self.startcommand(None, [node], self.manpage.nestedcommand, addgroup=False):\n                                self._currentoption = None\n                                return\n\n                        d = self.manpage.arguments\n                        k = list(d.keys())[0]\n                        logger.info('got arguments, using %r', k)\n                        text = d[k]\n                        mr = matchresult(node.pos[0], node.pos[1], text, None)\n                        self.matches.append(mr)\n                        return\n\n                    # if all of that failed, we can't explain it so mark it unknown\n                    self.matches.append(self.unknown(word, node.pos[0], node.pos[1]))\n\n        _visitword(node, word)\n\n    def visitfunction(self, node, name, body, parts):\n        self.functions.add(name.word)\n\n        def _iscompoundopenclosecurly(compound):\n            first, last = compound.list[0], compound.list[-1]\n            if (first.kind == 'reservedword' and last.kind == 'reservedword' and\n                first.word == '{' and last.word == '}'):\n                return True\n\n        # if the compound command we have there is { }, let's include the\n        # {} as part of the function declaration. normally it would be\n        # treated as a group command, but that seems less informative in this\n        # context\n        if _iscompoundopenclosecurly(body):\n            # create a matchresult until after the first {\n            mr = matchresult(node.pos[0], body.list[0].pos[1],\n                             helpconstants._function, None)\n            self.groups[0].results.append(mr)\n\n            # create a matchresult for the closing }\n            mr = matchresult(body.list[-1].pos[0], body.list[-1].pos[1],\n                             helpconstants._function, None)\n            self.groups[0].results.append(mr)\n\n            # visit anything in between the { }\n            for part in body.list[1:-1]:\n                self.visit(part)\n        else:\n            beforebody = bashlex.ast.findfirstkind(parts, 'compound') - 1\n            assert beforebody > 0\n            beforebody = parts[beforebody]\n\n            # create a matchresult ending at the node before body\n            mr = matchresult(node.pos[0], beforebody.pos[1],\n                             helpconstants._function, None)\n            self.groups[0].results.append(mr)\n\n            self.visit(body)\n\n        return False\n\n    def visittilde(self, node, value):\n        self.expansions.append(matchwordexpansion(node.pos[0], node.pos[1],\n                                                  'tilde'))\n\n    def visitparameter(self, node, value):\n        try:\n            int(value)\n            kind = 'digits'\n        except ValueError:\n            kind = helpconstants.parameters.get(value, 'param')\n\n        self.expansions.append(matchwordexpansion(node.pos[0], node.pos[1],\n                                                  'parameter-%s' % kind))\n\n    def match(self):\n        logger.info('matching string %r', self.s)\n\n        # limit recursive parsing to a depth of 1\n        self.ast = bashlex.parser.parsesingle(self.s, expansionlimit=1,\n                                              strictmode=False)\n        if self.ast:\n            self.visit(self.ast)\n            assert len(self.groupstack) == 1, 'groupstack should contain only shell group after matching'\n\n            # if we only have one command in there and no shell results/expansions,\n            # reraise the original exception\n            if (len(self.groups) == 2 and not self.groups[0].results and\n                self.groups[1].manpage is None and not self.expansions):\n                raise self.groups[1].error\n        else:\n            logger.warn('no AST generated for %r', self.s)\n\n        def debugmatch():\n            s = '\\n'.join(['%d) %r = %r' % (i, self.s[m.start:m.end], m.text) for i, m in enumerate(self.allmatches)])\n            return s\n\n        self._markunparsedunknown()\n\n        # fix each matchgroup seperately\n        for group in self.groups:\n            if group.results:\n                if getattr(group, 'manpage', None):\n                    # ensure that the program part isn't unknown (i.e. it has\n                    # something as its synopsis)\n                    assert not group.results[0].unknown\n\n                group.results = self._mergeadjacent(group.results)\n\n                # add matchresult.match to existing matches\n                for i, m in enumerate(group.results):\n                    assert m.end <= len(self.s), '%d %d' % (m.end, len(self.s))\n\n                    portion = self.s[m.start:m.end].decode('latin1')\n                    group.results[i] = matchresult(m.start, m.end, m.text, portion)\n\n        logger.debug('%r matches:\\n%s', self.s, debugmatch())\n\n        # not strictly needed, but doesn't hurt\n        self.expansions.sort()\n\n        return self.groups\n\n    def _markunparsedunknown(self):\n        '''the parser may leave a remainder at the end of the string if it doesn't\n        match any of the rules, mark them as unknowns'''\n        parsed = [False]*len(self.s)\n\n        # go over all existing matches to see if we've covered the\n        # current position\n        for start, end, _, _ in self.allmatches:\n            for i in range(start, end):\n                parsed[i] = True\n\n        for i in range(len(parsed)):\n            c = self.s[i]\n            # whitespace is always 'unparsed'\n            if c.isspace():\n                parsed[i] = True\n\n            # the parser ignores comments but we can use a trick to see if this\n            # starts a comment and is beyond the ending index of the parsed\n            # portion of the inpnut\n            if (not self.ast or i > self.ast.pos[1]) and c == '#':\n                comment = matchresult(i, len(parsed), helpconstants.COMMENT, None)\n                self.groups[0].results.append(comment)\n                break\n\n            if not parsed[i]:\n                # add unparsed results to the 'shell' group\n                self.groups[0].results.append(self.unknown(c, i, i+1))\n\n        # there are no overlaps, so sorting by the start is enough\n        self.groups[0].results.sort(key=lambda mr: mr.start)\n\n    def _resultindex(self):\n        '''return a mapping of matchresults to their index among all\n        matches, sorted by the start position of the matchresult'''\n        d = {}\n        i = 0\n        for result in sorted(self.allmatches, key=lambda mr: mr.start):\n            d[result] = i\n            i += 1\n        return d\n\n    def _mergeadjacent(self, matches):\n        merged = []\n        resultindex = self._resultindex()\n        sametext = itertools.groupby(matches, lambda m: m.text)\n        for text, ll in sametext:\n            for l in util.groupcontinuous(ll, key=lambda m: resultindex[m]):\n                if len(l) == 1:\n                    merged.append(l[0])\n                else:\n                    start = l[0].start\n                    end = l[-1].end\n                    endindex = resultindex[l[-1]]\n                    for mr in l:\n                        del resultindex[mr]\n                    merged.append(matchresult(start, end, text, None))\n                    resultindex[merged[-1]] = endindex\n        return merged\n"
  },
  {
    "path": "explainshell/options.py",
    "content": "import re, collections, logging\n\nfrom explainshell import store\n\ntokenstate = collections.namedtuple('tokenstate', 'startpos endpos token')\n\nlogger = logging.getLogger(__name__)\n\ndef extract(manpage):\n    '''extract options from all paragraphs that have been classified as containing\n    options'''\n    for i, p in enumerate(manpage.paragraphs):\n        if p.is_option:\n            s, l = extract_option(p.cleantext())\n            if s or l:\n                expectsarg = any(x.expectsarg for x in s + l)\n                s = [x.flag for x in s]\n                l = [x.flag for x in l]\n                manpage.paragraphs[i] = store.option(p, s, l, expectsarg)\n            else:\n                logger.error(\"no options could be extracted from paragraph %r\", p)\n\nopt_regex = re.compile(r'''\n    (?P<opt>--?(?:\\?|\\#|(?:\\w+-)*\\w+))  # option starts with - or -- and can have - in the middle but not at the end, also allow '-?'\n    (?:\n     (?:\\s?(=)?\\s?)           # -a=\n     (?P<argoptional>[<\\[])?  # -a=< or -a=[\n     (?:\\s?(=)?\\s?)           # or maybe -a<=\n     (?P<arg>\n      (?(argoptional)         # if we think we have an arg (we saw [ or <)\n       [^\\]>]+                # either read everything until the closing ] or >\n       |\n       (?(2)\n        [-a-zA-Z]+             # or if we didn't see [ or < but just saw =, read all letters, e.g. -a=abc\n        |\n        [A-Z]+                # but if we didn't have =, only allow uppercase letters, e.g. -a FOO\n       )\n      )\n     )\n     (?(argoptional)(?P<argoptionalc>[\\]>])) # read closing ] or > if we have an arg\n    )?                        # the whole arg thing is optional\n    (?P<ending>,\\s*|\\s+|\\Z|/|\\|)''', re.X)  # read any trailing whitespace or the end of the string\n\nopt2_regex = re.compile(r'''\n        (?P<opt>\\w+)    # an option that doesn't start with any of the usual characters, e.g. options from 'dd' like bs=BYTES\n        (?:\n         (?:\\s*=\\s*)    # an optional arg, e.g. bs=BYTES\n         (?P<arg>\\w+)\n        )\n        (?:,\\s*|\\s+|\\Z)''', re.X) # end with , or whitespace or the end of the string\n\ndef _flag(s, pos=0):\n    '''\n    >>> _flag('a=b').groupdict()\n    {'opt': 'a', 'arg': 'b'}\n    >>> bool(_flag('---c-d'))\n    False\n    >>> bool(_flag('foobar'))\n    False\n    '''\n    m = opt2_regex.match(s, pos)\n    return m\n\ndef _option(s, pos=0):\n    '''\n    >>> bool(_option('-'))\n    False\n    >>> bool(_option('--'))\n    False\n    >>> bool(_option('---'))\n    False\n    >>> bool(_option('-a-'))\n    False\n    >>> bool(_option('--a-'))\n    False\n    >>> bool(_option('--a-b-'))\n    False\n    >>> sorted(_option('-a').groupdict().iteritems())\n    [('arg', None), ('argoptional', None), ('argoptionalc', None), ('ending', ''), ('opt', '-a')]\n    >>> sorted(_option('--a').groupdict().iteritems())\n    [('arg', None), ('argoptional', None), ('argoptionalc', None), ('ending', ''), ('opt', '--a')]\n    >>> sorted(_option('-a<b>').groupdict().iteritems())\n    [('arg', 'b'), ('argoptional', '<'), ('argoptionalc', '>'), ('ending', ''), ('opt', '-a')]\n    >>> sorted(_option('-a=[foo]').groupdict().iteritems())\n    [('arg', 'foo'), ('argoptional', '['), ('argoptionalc', ']'), ('ending', ''), ('opt', '-a')]\n    >>> sorted(_option('-a=<foo>').groupdict().iteritems())\n    [('arg', 'foo'), ('argoptional', '<'), ('argoptionalc', '>'), ('ending', ''), ('opt', '-a')]\n    >>> sorted(_option('-a=<foo bar>').groupdict().iteritems())\n    [('arg', 'foo bar'), ('argoptional', '<'), ('argoptionalc', '>'), ('ending', ''), ('opt', '-a')]\n    >>> sorted(_option('-a=foo').groupdict().iteritems())\n    [('arg', 'foo'), ('argoptional', None), ('argoptionalc', None), ('ending', ''), ('opt', '-a')]\n    >>> bool(_option('-a=[foo>'))\n    False\n    >>> bool(_option('-a=[foo bar'))\n    False\n    >>> _option('-a foo').end(0)\n    3\n    '''\n    m = opt_regex.match(s, pos)\n    if m:\n        if m.group('argoptional'):\n            c = m.group('argoptional')\n            cc = m.group('argoptionalc')\n            if (c == '[' and cc == ']') or (c == '<' and cc == '>'):\n                return m\n            else:\n                return\n    return m\n\n_eatbetweenregex = re.compile(r'\\s*(?:or|,|\\|)\\s*')\n\ndef _eatbetween(s, pos):\n    '''\n    >>> _eatbetween('foo', 0)\n    0\n    >>> _eatbetween('a, b', 1)\n    3\n    >>> _eatbetween('a|b', 1)\n    2\n    >>> _eatbetween('a or b', 1)\n    5\n    '''\n    m = _eatbetweenregex.match(s, pos)\n    if m:\n        return m.end(0)\n    return pos\n\nclass extractedoption(collections.namedtuple('extractedoption', 'flag expectsarg')):\n    def __eq__(self, other):\n        if isinstance(other, str):\n            return self.flag == other\n        else:\n            return super(extractedoption, self).__eq__(other)\n\n    def __str__(self):\n        return self.flag\n\ndef extract_option(txt):\n    '''this is where the magic is (suppose) to happen. try and find options\n    using a regex'''\n    startpos = currpos = len(txt) - len(txt.lstrip())\n    short, long = [], []\n\n    m = _option(txt, currpos)\n\n    # keep going as long as options are found\n    while m:\n        s = m.group('opt')\n        po = extractedoption(s, m.group('arg'))\n        if s.startswith('--'):\n            long.append(po)\n        else:\n            short.append(po)\n        currpos = m.end(0)\n        currpos = _eatbetween(txt, currpos)\n        if m.group('ending') == '|':\n            m = _option(txt, currpos)\n            if not m:\n                startpos = currpos\n                while currpos < len(txt) and not txt[currpos].isspace():\n                    if txt[currpos] == '|':\n                        short.append(extractedoption(txt[startpos:currpos], None))\n                        startpos = currpos\n                    currpos += 1\n                leftover = txt[startpos:currpos]\n                if leftover:\n                    short.append(extractedoption(leftover, None))\n        else:\n            m = _option(txt, currpos)\n\n    if currpos == startpos:\n        m = _flag(txt, currpos)\n        while m:\n            s = m.group('opt')\n            po = extractedoption(s, m.group('arg'))\n            long.append(po)\n            currpos = m.end(0)\n            currpos = _eatbetween(txt, currpos)\n            m = _flag(txt, currpos)\n\n    return short, long\n"
  },
  {
    "path": "explainshell/store.py",
    "content": "'''data objects to save processed man pages to mongodb'''\nimport pymongo, collections, re, logging\n\nfrom explainshell import errors, util, helpconstants, config\n\nlogger = logging.getLogger(__name__)\n\nclass classifiermanpage(collections.namedtuple('classifiermanpage', 'name paragraphs')):\n    '''a man page that had its paragraphs manually tagged as containing options\n    or not'''\n    @staticmethod\n    def from_store(d):\n        m = classifiermanpage(d['name'], [paragraph.from_store(p) for p in d['paragraphs']])\n        return m\n\n    def to_store(self):\n        return {'name' : self.name,\n                'paragraphs' : [p.to_store() for p in self.paragraphs]}\n\nclass paragraph(object):\n    '''a paragraph inside a man page is text that ends with two new lines'''\n    def __init__(self, idx, text, section, is_option):\n        self.idx = idx\n        self.text = text\n        self.section = section\n        self.is_option = is_option\n\n    def cleantext(self):\n        t = re.sub(r'<[^>]+>', '', self.text)\n        t = re.sub('&lt;', '<', t)\n        t = re.sub('&gt;', '>', t)\n        return t\n\n    @staticmethod\n    def from_store(d):\n        p = paragraph(d.get('idx', 0), d['text'].encode('utf8'), d['section'], d['is_option'])\n        return p\n\n    def to_store(self):\n        return {'idx' : self.idx, 'text' : self.text, 'section' : self.section,\n                'is_option' : self.is_option}\n\n    def __repr__(self):\n        t = self.cleantext()\n        t = t[:min(20, t.find('\\n'))].lstrip()\n        return '<paragraph %d, %s: %r>' % (self.idx, self.section, t)\n\n    def __eq__(self, other):\n        if not other:\n            return False\n        return self.__dict__ == other.__dict__\n\nclass option(paragraph):\n    '''a paragraph that contains extracted options\n\n    short - a list of short options (-a, -b, ..)\n    long - a list of long options (--a, --b)\n    expectsarg - specifies if one of the short/long options expects an additional argument\n    argument - specifies if to consider this as positional arguments\n    nestedcommand - specifies if the arguments to this option can start a nested command\n    '''\n    def __init__(self, p, short, long, expectsarg, argument=None, nestedcommand=False):\n        paragraph.__init__(self, p.idx, p.text, p.section, p.is_option)\n        self.short = short\n        self.long = long\n        self._opts = self.short + self.long\n        self.argument = argument\n        self.expectsarg = expectsarg\n        self.nestedcommand = nestedcommand\n        if nestedcommand:\n            assert expectsarg, 'an option that can nest commands must expect an argument'\n\n    @property\n    def opts(self):\n        return self._opts\n\n    @classmethod\n    def from_store(cls, d):\n        p = paragraph.from_store(d)\n\n        return cls(p, d['short'], d['long'], d['expectsarg'], d['argument'],\n                   d.get('nestedcommand'))\n\n    def to_store(self):\n        d = paragraph.to_store(self)\n        assert d['is_option']\n        d['short'] = self.short\n        d['long'] = self.long\n        d['expectsarg'] = self.expectsarg\n        d['argument'] = self.argument\n        d['nestedcommand'] = self.nestedcommand\n        return d\n\n    def __str__(self):\n        return '(%s)' % ', '.join([str(x) for x in self.opts])\n\n    def __repr__(self):\n        return '<options for paragraph %d: %s>' % (self.idx, str(self))\n\nclass manpage(object):\n    '''processed man page\n\n    source - the path to the original source man page\n    name - the name of this man page as extracted by manpage.manpage\n    synopsis - the synopsis of this man page as extracted by manpage.manpage\n    paragraphs - a list of paragraphs (and options) that contain all of the text and options\n        extracted from this man page\n    aliases - a list of aliases found for this man page\n    partialmatch - allow interperting options without a leading '-'\n    multicommand - consider sub commands when explaining a command with this man page,\n        e.g. git -> git commit\n    updated - whether this man page was manually updated\n    nestedcommand - specifies if positional arguments to this program can start a nested command,\n        e.g. sudo, xargs\n    '''\n    def __init__(self, source, name, synopsis, paragraphs, aliases,\n                 partialmatch=False, multicommand=False, updated=False,\n                 nestedcommand=False):\n        self.source = source\n        self.name = name\n        self.synopsis = synopsis\n        self.paragraphs = paragraphs\n        self.aliases = aliases\n        self.partialmatch = partialmatch\n        self.multicommand = multicommand\n        self.updated = updated\n        self.nestedcommand = nestedcommand\n\n    def removeoption(self, idx):\n        for i, p in self.paragraphs:\n            if p.idx == idx:\n                if not isinstance(p, option):\n                    raise ValueError(\"paragraph %d isn't an option\" % idx)\n                self.paragraphs[i] = paragraph(p.idx, p.text, p.section, False)\n                return\n        raise ValueError('idx %d not found' % idx)\n\n    @property\n    def namesection(self):\n        name, section = util.namesection(self.source[:-3])\n        return '%s(%s)' % (name, section)\n\n    @property\n    def section(self):\n        name, section = util.namesection(self.source[:-3])\n        return section\n\n    @property\n    def options(self):\n        return [p for p in self.paragraphs if isinstance(p, option)]\n\n    @property\n    def arguments(self):\n        # go over all paragraphs and look for those with the same 'argument'\n        # field\n        groups = collections.OrderedDict()\n        for opt in self.options:\n            if opt.argument:\n                groups.setdefault(opt.argument, []).append(opt)\n\n        # merge all the paragraphs under the same argument to a single string\n        for k, l in groups.iteritems():\n            groups[k] = '\\n\\n'.join([p.text for p in l])\n\n        return groups\n\n    @property\n    def synopsisnoname(self):\n        return re.match(r'[\\w|-]+ - (.*)$', self.synopsis).group(1)\n\n    def find_option(self, flag):\n        for option in self.options:\n            for o in option.opts:\n                if o == flag:\n                    return option\n\n    def to_store(self):\n        return {'source' : self.source, 'name' : self.name, 'synopsis' : self.synopsis,\n                'paragraphs' : [p.to_store() for p in self.paragraphs],\n                'aliases' : self.aliases, 'partialmatch' : self.partialmatch,\n                'multicommand' : self.multicommand, 'updated' : self.updated,\n                'nestedcommand' : self.nestedcommand}\n\n    @staticmethod\n    def from_store(d):\n        paragraphs = []\n        for pd in d.get('paragraphs', []):\n            pp = paragraph.from_store(pd)\n            if pp.is_option == True and 'short' in pd:\n                pp = option.from_store(pd)\n            paragraphs.append(pp)\n\n        synopsis = d['synopsis']\n        if synopsis:\n            synopsis = synopsis.encode('utf8')\n        else:\n            synopsis = helpconstants.NOSYNOPSIS\n\n        return manpage(d['source'], d['name'], synopsis, paragraphs,\n                       [tuple(x) for x in d['aliases']], d['partialmatch'],\n                       d['multicommand'], d['updated'], d.get('nestedcommand'))\n\n    @staticmethod\n    def from_store_name_only(name, source):\n        return manpage(source, name, None, [], [], None, None, None)\n\n    def __repr__(self):\n        return '<manpage %r(%s), %d options>' % (self.name, self.section, len(self.options))\n\nclass store(object):\n    '''read/write processed man pages from mongodb\n\n    we use three collections:\n    1) classifier - contains manually tagged paragraphs from man pages\n    2) manpage - contains a processed man page\n    3) mapping - contains (name, manpageid, score) tuples\n    '''\n    def __init__(self, db='explainshell', host=config.MONGO_URI):\n        logger.info('creating store, db = %r, host = %r', db, host)\n        self.connection = pymongo.MongoClient(host)\n        self.db = self.connection[db]\n        self.classifier = self.db['classifier']\n        self.manpage = self.db['manpage']\n        self.mapping = self.db['mapping']\n\n    def close(self):\n        self.connection.disconnect()\n        self.classifier = self.manpage = self.mapping = self.db = None\n\n    def drop(self, confirm=False):\n        if not confirm:\n            return\n\n        logger.info('dropping mapping, manpage, collections')\n        self.mapping.drop()\n        self.manpage.drop()\n\n    def trainingset(self):\n        for d in self.classifier.find():\n            yield classifiermanpage.from_store(d)\n\n    def __contains__(self, name):\n        c = self.mapping.find({'src' : name}).count()\n        return c > 0\n\n    def __iter__(self):\n        for d in self.manpage.find():\n            yield manpage.from_store(d)\n\n    def findmanpage(self, name):\n        '''find a man page by its name, everything following the last dot (.) in name,\n        is taken as the section of the man page\n\n        we return the man page found with the highest score, and a list of\n        suggestions that also matched the given name (only the first item\n        is prepopulated with the option data)'''\n        if name.endswith('.gz'):\n            logger.info('name ends with .gz, looking up an exact match by source')\n            d = self.manpage.find_one({'source':name})\n            if not d:\n                raise errors.ProgramDoesNotExist(name)\n            m = manpage.from_store(d)\n            logger.info('returning %s', m)\n            return [m]\n\n        section = None\n        origname = name\n\n        # don't try to look for a section if it's . (source)\n        if name != '.':\n            splitted = name.rsplit('.', 1)\n            name = splitted[0]\n            if len(splitted) > 1:\n                section = splitted[1]\n\n        logger.info('looking up manpage in mapping with src %r', name)\n        cursor = self.mapping.find({'src' : name})\n        count = cursor.count()\n        if not count:\n            raise errors.ProgramDoesNotExist(name)\n\n        dsts = dict(((d['dst'], d['score']) for d in cursor))\n        cursor = self.manpage.find({'_id' : {'$in' : list(dsts.keys())}}, {'name' : 1, 'source' : 1})\n        if cursor.count() != len(dsts):\n            logger.error('one of %r mappings is missing in manpage collection '\n                         '(%d mappings, %d found)', dsts, len(dsts), cursor.count())\n        results = [(d.pop('_id'), manpage.from_store_name_only(**d)) for d in cursor]\n        results.sort(key=lambda x: dsts.get(x[0], 0), reverse=True)\n        logger.info('got %s', results)\n        if section is not None:\n            if len(results) > 1:\n                results.sort(key=lambda (oid, m): m.section == section, reverse=True)\n                logger.info(r'sorting %r so %s is first', results, section)\n            if not results[0][1].section == section:\n                raise errors.ProgramDoesNotExist(origname)\n            results.extend(self._discovermanpagesuggestions(results[0][0], results))\n\n        oid = results[0][0]\n        results = [x[1] for x in results]\n        results[0] = manpage.from_store(self.manpage.find_one({'_id' : oid}))\n        return results\n\n    def _discovermanpagesuggestions(self, oid, existing):\n        '''find suggestions for a given man page\n\n        oid is the objectid of the man page in question,\n        existing is a list of (oid, man page) of suggestions that were\n        already discovered\n        '''\n        skip = set([oid for oid, m in existing])\n        cursor = self.mapping.find({'dst' : oid})\n        # find all srcs that point to oid\n        srcs = [d['src'] for d in cursor]\n        # find all dsts of srcs\n        suggestionoids = self.mapping.find({'src' : {'$in' : srcs}}, {'dst' : 1})\n        # remove already discovered\n        suggestionoids = [d['dst'] for d in suggestionoids if d['dst'] not in skip]\n        if not suggestionoids:\n            return []\n\n        # get just the name and source of found suggestions\n        suggestionoids = self.manpage.find({'_id' : {'$in' : suggestionoids}},\n                                           {'name' : 1, 'source' : 1})\n        return [(d.pop('_id'), manpage.from_store_name_only(**d)) for d in suggestionoids]\n\n    def addmapping(self, src, dst, score):\n        self.mapping.insert({'src' : src, 'dst' : dst, 'score' : score})\n\n    def addmanpage(self, m):\n        '''add m into the store, if it exists first remove it and its mappings\n\n        each man page may have aliases besides the name determined by its\n        basename'''\n        d = self.manpage.find_one({'source' : m.source})\n        if d:\n            logger.info('removing old manpage %s (%s)', m.source, d['_id'])\n            self.manpage.remove(d['_id'])\n\n            # remove old mappings if there are any\n            c = self.mapping.count()\n            self.mapping.remove({'dst' : d['_id']})\n            c -= self.mapping.count()\n            logger.info('removed %d mappings for manpage %s', c, m.source)\n\n        o = self.manpage.insert(m.to_store())\n\n        for alias, score in m.aliases:\n            self.addmapping(alias, o, score)\n            logger.info('inserting mapping (alias) %s -> %s (%s) with score %d', alias, m.name, o, score)\n        return m\n\n    def updatemanpage(self, m):\n        '''update m and add new aliases if necessary\n\n        change updated attribute so we don't overwrite this in the future'''\n        logger.info('updating manpage %s', m.source)\n        m.updated = True\n        self.manpage.update({'source' : m.source}, m.to_store())\n        _id = self.manpage.find_one({'source' : m.source}, fields={'_id':1})['_id']\n        for alias, score in m.aliases:\n            if alias not in self:\n                self.addmapping(alias, _id, score)\n                logger.info('inserting mapping (alias) %s -> %s (%s) with score %d', alias, m.name, _id, score)\n            else:\n                logger.debug('mapping (alias) %s -> %s (%s) already exists', alias, m.name, _id)\n        return m\n\n    def verify(self):\n        # check that everything in manpage is reachable\n        mappings = list(self.mapping.find())\n        reachable = set([m['dst'] for m in mappings])\n        manpages = set([m['_id'] for m in self.manpage.find(fields={'_id':1})])\n\n        ok = True\n        unreachable = manpages - reachable\n        if unreachable:\n            logger.error('manpages %r are unreachable (nothing maps to them)', unreachable)\n            unreachable = [self.manpage.find_one({'_id' : u})['name'] for u in unreachable]\n            ok = False\n\n        notfound = reachable - manpages\n        if notfound:\n            logger.error('mappings to inexisting manpages: %r', notfound)\n            ok = False\n\n        return ok, unreachable, notfound\n\n    def names(self):\n        cursor = self.manpage.find(fields={'name':1})\n        for d in cursor:\n            yield d['_id'], d['name']\n\n    def mappings(self):\n        cursor = self.mapping.find(fields={'src':1})\n        for d in cursor:\n            yield d['src'], d['_id']\n\n    def setmulticommand(self, manpageid):\n        self.manpage.update({'_id' : manpageid}, {'$set' : {'multicommand' : True}})\n"
  },
  {
    "path": "explainshell/util.py",
    "content": "import itertools\nfrom operator import itemgetter\n\ndef consecutive(l, fn):\n    '''yield consecutive items from l that fn returns True for them\n\n    >>> even = lambda x: x % 2 == 0\n    >>> list(consecutive([], even))\n    []\n    >>> list(consecutive([1], even))\n    [[1]]\n    >>> list(consecutive([1, 2], even))\n    [[1], [2]]\n    >>> list(consecutive([2, 4], even))\n    [[2, 4]]\n    >>> list(consecutive([1, 2, 4], even))\n    [[1], [2, 4]]\n    >>> list(consecutive([1, 2, 4, 5, 7, 8, 10], even))\n    [[1], [2, 4], [5], [7], [8, 10]]\n    '''\n    it = iter(l)\n    ll = []\n    try:\n        while True:\n            x = it.next()\n            if fn(x):\n                ll.append(x)\n            else:\n                if ll:\n                    yield ll\n                    ll = []\n                yield [x]\n    except StopIteration:\n        if ll:\n            yield ll\n\ndef groupcontinuous(l, key=None):\n    '''\n    >>> list(groupcontinuous([1, 2, 4, 5, 7, 8, 10]))\n    [[1, 2], [4, 5], [7, 8], [10]]\n    >>> list(groupcontinuous(range(5)))\n    [[0, 1, 2, 3, 4]]\n    '''\n    if key is None:\n        key = lambda x: x\n    for k, g in itertools.groupby(enumerate(l), lambda (i, x): i-key(x)):\n        yield map(itemgetter(1), g)\n\ndef toposorted(graph, parents):\n    \"\"\"\n    Returns vertices of a DAG in topological order.\n\n    Arguments:\n    graph -- vetices of a graph to be toposorted\n    parents -- function (vertex) -> vertices to preceed\n               given vertex in output\n    \"\"\"\n    result = []\n    used = set()\n    def use(v, top):\n        if id(v) in used:\n            return\n        for parent in parents(v):\n            if parent is top:\n                raise ValueError('graph is cyclical', graph)\n            use(parent, v)\n        used.add(id(v))\n        result.append(v)\n    for v in graph:\n        use(v, v)\n    return result\n\ndef pairwise(iterable):\n    a, b = itertools.tee(iterable)\n    next(b, None)\n    return itertools.izip(a, b)\n\nclass peekable(object):\n    '''\n    >>> it = peekable(iter('abc'))\n    >>> it.index, it.peek(), it.index, it.peek(), it.next(), it.index, it.peek(), it.next(), it.next(), it.index\n    (0, 'a', 0, 'a', 'a', 1, 'b', 'b', 'c', 3)\n    >>> it.peek()\n    Traceback (most recent call last):\n      File \"<stdin>\", line 1, in ?\n    StopIteration\n    >>> it.peek()\n    Traceback (most recent call last):\n      File \"<stdin>\", line 1, in ?\n    StopIteration\n    >>> it.next()\n    Traceback (most recent call last):\n      File \"<stdin>\", line 1, in ?\n    StopIteration\n    '''\n    def __init__(self, it):\n        self.it = it\n        self._peeked = False\n        self._peekvalue = None\n        self._idx = 0\n    def __iter__(self):\n        return self\n    def next(self):\n        if self._peeked:\n            self._peeked = False\n            self._idx += 1\n            return self._peekvalue\n        n = self.it.next()\n        self._idx += 1\n        return n\n    def hasnext(self):\n        try:\n            self.peek()\n            return True\n        except StopIteration:\n            return False\n    def peek(self):\n        if self._peeked:\n            return self._peekvalue\n        else:\n            self._peekvalue = self.it.next()\n            self._peeked = True\n            return self._peekvalue\n    @property\n    def index(self):\n        '''return the index of the next item returned by next()'''\n        return self._idx\n\ndef namesection(path):\n    assert '.gz' not in path\n    name, section = path.rsplit('.', 1)\n    return name, section\n\nclass propertycache(object):\n    def __init__(self, func):\n        self.func = func\n        self.name = func.__name__\n\n    def __get__(self, obj, type=None):\n        result = self.func(obj)\n        self.cachevalue(obj, result)\n        return result\n\n    def cachevalue(self, obj, value):\n        setattr(obj, self.name, value)\n"
  },
  {
    "path": "explainshell/web/__init__.py",
    "content": "from flask import Flask\napp = Flask(__name__)\n\nfrom explainshell.web import views\nfrom explainshell import store, config\n\nif config.DEBUG:\n    from explainshell.web import debugviews\n\napp.config.from_object(config)\n"
  },
  {
    "path": "explainshell/web/debugviews.py",
    "content": "import logging\n\nfrom flask import render_template, request, abort, redirect, url_for, json\n\nfrom explainshell import manager, config, store\nfrom explainshell.web import app, helpers\n\nlogger = logging.getLogger(__name__)\n\n@app.route('/debug')\ndef debug():\n    s = store.store('explainshell', config.MONGO_URI)\n    d = {'manpages' : []}\n    for mp in s:\n        synopsis = ''\n        if mp.synopsis:\n            synopsis = mp.synopsis[:20]\n        dd = {'name' : mp.name, 'synopsis' : synopsis}\n        l = []\n        for o in mp.options:\n            l.append(str(o))\n        dd['options'] = ', '.join(l)\n        d['manpages'].append(dd)\n    d['manpages'].sort(key=lambda d: d['name'].lower())\n    return render_template('debug.html', d=d)\n\ndef _convertvalue(value):\n    if isinstance(value, list):\n        return [s.strip() for s in value]\n    elif value.lower() == 'true':\n        return True\n    elif value:\n        return value.strip()\n    return False\n\n@app.route('/debug/tag/<source>', methods=['GET', 'POST'])\ndef tag(source):\n    mngr = manager.manager(config.MONGO_URI, 'explainshell', [], False, False)\n    s = mngr.store\n    m = s.findmanpage(source)[0]\n    assert m\n\n    if 'paragraphs' in request.form:\n        paragraphs = json.loads(request.form['paragraphs'])\n        mparagraphs = []\n        for d in paragraphs:\n            idx = d['idx']\n            text = d['text']\n            section = d['section']\n            short = [s.strip() for s in d['short']]\n            long = [s.strip() for s in d['long']]\n            expectsarg = _convertvalue(d['expectsarg'])\n            nestedcommand = _convertvalue(d['nestedcommand'])\n            if isinstance(nestedcommand, str):\n                nestedcommand = [nestedcommand]\n            elif nestedcommand is True:\n                logger.error('nestedcommand %r must be a string or list', nestedcommand)\n                abort(503)\n            argument = d['argument']\n            if not argument:\n                argument = None\n            p = store.paragraph(idx, text, section, d['is_option'])\n            if d['is_option'] and (short or long or argument):\n                p = store.option(p, short, long, expectsarg, argument, nestedcommand)\n            mparagraphs.append(p)\n\n        if request.form.get('nestedcommand', '').lower() == 'true':\n            m.nestedcommand = True\n        else:\n            m.nestedcommand = False\n        m = mngr.edit(m, mparagraphs)\n        if m:\n            return redirect(url_for('explain', cmd=m.name))\n        else:\n            abort(503)\n    else:\n        helpers.convertparagraphs(m)\n        for p in m.paragraphs:\n            if isinstance(p, store.option):\n                if isinstance(p.expectsarg, list):\n                    p.expectsarg = ', '.join(p.expectsarg)\n                if isinstance(p.nestedcommand, list):\n                    p.nestedcommand = ', '.join(p.nestedcommand)\n\n        return render_template('tagger.html', m=m)\n"
  },
  {
    "path": "explainshell/web/helpers.py",
    "content": "from explainshell import util\n\ndef convertparagraphs(manpage):\n    for p in manpage.paragraphs:\n        p.text = p.text.decode('utf-8')\n    return manpage\n\ndef suggestions(matches, command):\n    '''enrich command matches with links to other man pages with the\n    same name'''\n    for m in matches:\n        if 'name' in m and 'suggestions' in m:\n            before = command[:m['start']]\n            after = command[m['end']:]\n            newsuggestions = []\n            for othermp in sorted(m['suggestions'], key=lambda mp: mp.section):\n                mid = '%s.%s' % (othermp.name, othermp.section)\n                newsuggestions.append({'cmd' : ''.join([before, mid, after]),\n                                  'text' : othermp.namesection})\n            m['suggestions'] = newsuggestions\n"
  },
  {
    "path": "explainshell/web/static/css/bootstrap-responsive.css",
    "content": "/*!\n * Bootstrap Responsive v2.3.1\n *\n * Copyright 2012 Twitter, Inc\n * Licensed under the Apache License v2.0\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Designed and built with all the love in the world @twitter by @mdo and @fat.\n */\n\n.clearfix {\n  *zoom: 1;\n}\n\n.clearfix:before,\n.clearfix:after {\n  display: table;\n  line-height: 0;\n  content: \"\";\n}\n\n.clearfix:after {\n  clear: both;\n}\n\n.hide-text {\n  font: 0/0 a;\n  color: transparent;\n  text-shadow: none;\n  background-color: transparent;\n  border: 0;\n}\n\n.input-block-level {\n  display: block;\n  width: 100%;\n  min-height: 30px;\n  -webkit-box-sizing: border-box;\n     -moz-box-sizing: border-box;\n          box-sizing: border-box;\n}\n\n@-ms-viewport {\n  width: device-width;\n}\n\n.hidden {\n  display: none;\n  visibility: hidden;\n}\n\n.visible-phone {\n  display: none !important;\n}\n\n.visible-tablet {\n  display: none !important;\n}\n\n.hidden-desktop {\n  display: none !important;\n}\n\n.visible-desktop {\n  display: inherit !important;\n}\n\n@media (min-width: 768px) and (max-width: 979px) {\n  .hidden-desktop {\n    display: inherit !important;\n  }\n  .visible-desktop {\n    display: none !important ;\n  }\n  .visible-tablet {\n    display: inherit !important;\n  }\n  .hidden-tablet {\n    display: none !important;\n  }\n}\n\n@media (max-width: 767px) {\n  .hidden-desktop {\n    display: inherit !important;\n  }\n  .visible-desktop {\n    display: none !important;\n  }\n  .visible-phone {\n    display: inherit !important;\n  }\n  .hidden-phone {\n    display: none !important;\n  }\n}\n\n.visible-print {\n  display: none !important;\n}\n\n@media print {\n  .visible-print {\n    display: inherit !important;\n  }\n  .hidden-print {\n    display: none !important;\n  }\n}\n\n@media (min-width: 1200px) {\n  .row {\n    margin-left: -30px;\n    *zoom: 1;\n  }\n  .row:before,\n  .row:after {\n    display: table;\n    line-height: 0;\n    content: \"\";\n  }\n  .row:after {\n    clear: both;\n  }\n  [class*=\"span\"] {\n    float: left;\n    min-height: 1px;\n    margin-left: 30px;\n  }\n  .container,\n  .navbar-static-top .container,\n  .navbar-fixed-top .container,\n  .navbar-fixed-bottom .container {\n    width: 1170px;\n  }\n  .span12 {\n    width: 1170px;\n  }\n  .span11 {\n    width: 1070px;\n  }\n  .span10 {\n    width: 970px;\n  }\n  .span9 {\n    width: 870px;\n  }\n  .span8 {\n    width: 770px;\n  }\n  .span7 {\n    width: 670px;\n  }\n  .span6 {\n    width: 570px;\n  }\n  .span5 {\n    width: 470px;\n  }\n  .span4 {\n    width: 370px;\n  }\n  .span3 {\n    width: 270px;\n  }\n  .span2 {\n    width: 170px;\n  }\n  .span1 {\n    width: 70px;\n  }\n  .offset12 {\n    margin-left: 1230px;\n  }\n  .offset11 {\n    margin-left: 1130px;\n  }\n  .offset10 {\n    margin-left: 1030px;\n  }\n  .offset9 {\n    margin-left: 930px;\n  }\n  .offset8 {\n    margin-left: 830px;\n  }\n  .offset7 {\n    margin-left: 730px;\n  }\n  .offset6 {\n    margin-left: 630px;\n  }\n  .offset5 {\n    margin-left: 530px;\n  }\n  .offset4 {\n    margin-left: 430px;\n  }\n  .offset3 {\n    margin-left: 330px;\n  }\n  .offset2 {\n    margin-left: 230px;\n  }\n  .offset1 {\n    margin-left: 130px;\n  }\n  .row-fluid {\n    width: 100%;\n    *zoom: 1;\n  }\n  .row-fluid:before,\n  .row-fluid:after {\n    display: table;\n    line-height: 0;\n    content: \"\";\n  }\n  .row-fluid:after {\n    clear: both;\n  }\n  .row-fluid [class*=\"span\"] {\n    display: block;\n    float: left;\n    width: 100%;\n    min-height: 30px;\n    margin-left: 2.564102564102564%;\n    *margin-left: 2.5109110747408616%;\n    -webkit-box-sizing: border-box;\n       -moz-box-sizing: border-box;\n            box-sizing: border-box;\n  }\n  .row-fluid [class*=\"span\"]:first-child {\n    margin-left: 0;\n  }\n  .row-fluid .controls-row [class*=\"span\"] + [class*=\"span\"] {\n    margin-left: 2.564102564102564%;\n  }\n  .row-fluid .span12 {\n    width: 100%;\n    *width: 99.94680851063829%;\n  }\n  .row-fluid .span11 {\n    width: 91.45299145299145%;\n    *width: 91.39979996362975%;\n  }\n  .row-fluid .span10 {\n    width: 82.90598290598291%;\n    *width: 82.8527914166212%;\n  }\n  .row-fluid .span9 {\n    width: 74.35897435897436%;\n    *width: 74.30578286961266%;\n  }\n  .row-fluid .span8 {\n    width: 65.81196581196582%;\n    *width: 65.75877432260411%;\n  }\n  .row-fluid .span7 {\n    width: 57.26495726495726%;\n    *width: 57.21176577559556%;\n  }\n  .row-fluid .span6 {\n    width: 48.717948717948715%;\n    *width: 48.664757228587014%;\n  }\n  .row-fluid .span5 {\n    width: 40.17094017094017%;\n    *width: 40.11774868157847%;\n  }\n  .row-fluid .span4 {\n    width: 31.623931623931625%;\n    *width: 31.570740134569924%;\n  }\n  .row-fluid .span3 {\n    width: 23.076923076923077%;\n    *width: 23.023731587561375%;\n  }\n  .row-fluid .span2 {\n    width: 14.52991452991453%;\n    *width: 14.476723040552828%;\n  }\n  .row-fluid .span1 {\n    width: 5.982905982905983%;\n    *width: 5.929714493544281%;\n  }\n  .row-fluid .offset12 {\n    margin-left: 105.12820512820512%;\n    *margin-left: 105.02182214948171%;\n  }\n  .row-fluid .offset12:first-child {\n    margin-left: 102.56410256410257%;\n    *margin-left: 102.45771958537915%;\n  }\n  .row-fluid .offset11 {\n    margin-left: 96.58119658119658%;\n    *margin-left: 96.47481360247316%;\n  }\n  .row-fluid .offset11:first-child {\n    margin-left: 94.01709401709402%;\n    *margin-left: 93.91071103837061%;\n  }\n  .row-fluid .offset10 {\n    margin-left: 88.03418803418803%;\n    *margin-left: 87.92780505546462%;\n  }\n  .row-fluid .offset10:first-child {\n    margin-left: 85.47008547008548%;\n    *margin-left: 85.36370249136206%;\n  }\n  .row-fluid .offset9 {\n    margin-left: 79.48717948717949%;\n    *margin-left: 79.38079650845607%;\n  }\n  .row-fluid .offset9:first-child {\n    margin-left: 76.92307692307693%;\n    *margin-left: 76.81669394435352%;\n  }\n  .row-fluid .offset8 {\n    margin-left: 70.94017094017094%;\n    *margin-left: 70.83378796144753%;\n  }\n  .row-fluid .offset8:first-child {\n    margin-left: 68.37606837606839%;\n    *margin-left: 68.26968539734497%;\n  }\n  .row-fluid .offset7 {\n    margin-left: 62.393162393162385%;\n    *margin-left: 62.28677941443899%;\n  }\n  .row-fluid .offset7:first-child {\n    margin-left: 59.82905982905982%;\n    *margin-left: 59.72267685033642%;\n  }\n  .row-fluid .offset6 {\n    margin-left: 53.84615384615384%;\n    *margin-left: 53.739770867430444%;\n  }\n  .row-fluid .offset6:first-child {\n    margin-left: 51.28205128205128%;\n    *margin-left: 51.175668303327875%;\n  }\n  .row-fluid .offset5 {\n    margin-left: 45.299145299145295%;\n    *margin-left: 45.1927623204219%;\n  }\n  .row-fluid .offset5:first-child {\n    margin-left: 42.73504273504273%;\n    *margin-left: 42.62865975631933%;\n  }\n  .row-fluid .offset4 {\n    margin-left: 36.75213675213675%;\n    *margin-left: 36.645753773413354%;\n  }\n  .row-fluid .offset4:first-child {\n    margin-left: 34.18803418803419%;\n    *margin-left: 34.081651209310785%;\n  }\n  .row-fluid .offset3 {\n    margin-left: 28.205128205128204%;\n    *margin-left: 28.0987452264048%;\n  }\n  .row-fluid .offset3:first-child {\n    margin-left: 25.641025641025642%;\n    *margin-left: 25.53464266230224%;\n  }\n  .row-fluid .offset2 {\n    margin-left: 19.65811965811966%;\n    *margin-left: 19.551736679396257%;\n  }\n  .row-fluid .offset2:first-child {\n    margin-left: 17.094017094017094%;\n    *margin-left: 16.98763411529369%;\n  }\n  .row-fluid .offset1 {\n    margin-left: 11.11111111111111%;\n    *margin-left: 11.004728132387708%;\n  }\n  .row-fluid .offset1:first-child {\n    margin-left: 8.547008547008547%;\n    *margin-left: 8.440625568285142%;\n  }\n  input,\n  textarea,\n  .uneditable-input {\n    margin-left: 0;\n  }\n  .controls-row [class*=\"span\"] + [class*=\"span\"] {\n    margin-left: 30px;\n  }\n  input.span12,\n  textarea.span12,\n  .uneditable-input.span12 {\n    width: 1156px;\n  }\n  input.span11,\n  textarea.span11,\n  .uneditable-input.span11 {\n    width: 1056px;\n  }\n  input.span10,\n  textarea.span10,\n  .uneditable-input.span10 {\n    width: 956px;\n  }\n  input.span9,\n  textarea.span9,\n  .uneditable-input.span9 {\n    width: 856px;\n  }\n  input.span8,\n  textarea.span8,\n  .uneditable-input.span8 {\n    width: 756px;\n  }\n  input.span7,\n  textarea.span7,\n  .uneditable-input.span7 {\n    width: 656px;\n  }\n  input.span6,\n  textarea.span6,\n  .uneditable-input.span6 {\n    width: 556px;\n  }\n  input.span5,\n  textarea.span5,\n  .uneditable-input.span5 {\n    width: 456px;\n  }\n  input.span4,\n  textarea.span4,\n  .uneditable-input.span4 {\n    width: 356px;\n  }\n  input.span3,\n  textarea.span3,\n  .uneditable-input.span3 {\n    width: 256px;\n  }\n  input.span2,\n  textarea.span2,\n  .uneditable-input.span2 {\n    width: 156px;\n  }\n  input.span1,\n  textarea.span1,\n  .uneditable-input.span1 {\n    width: 56px;\n  }\n  .thumbnails {\n    margin-left: -30px;\n  }\n  .thumbnails > li {\n    margin-left: 30px;\n  }\n  .row-fluid .thumbnails {\n    margin-left: 0;\n  }\n}\n\n@media (min-width: 768px) and (max-width: 979px) {\n  .row {\n    margin-left: -20px;\n    *zoom: 1;\n  }\n  .row:before,\n  .row:after {\n    display: table;\n    line-height: 0;\n    content: \"\";\n  }\n  .row:after {\n    clear: both;\n  }\n  [class*=\"span\"] {\n    float: left;\n    min-height: 1px;\n    margin-left: 20px;\n  }\n  .container,\n  .navbar-static-top .container,\n  .navbar-fixed-top .container,\n  .navbar-fixed-bottom .container {\n    width: 724px;\n  }\n  .span12 {\n    width: 724px;\n  }\n  .span11 {\n    width: 662px;\n  }\n  .span10 {\n    width: 600px;\n  }\n  .span9 {\n    width: 538px;\n  }\n  .span8 {\n    width: 476px;\n  }\n  .span7 {\n    width: 414px;\n  }\n  .span6 {\n    width: 352px;\n  }\n  .span5 {\n    width: 290px;\n  }\n  .span4 {\n    width: 228px;\n  }\n  .span3 {\n    width: 166px;\n  }\n  .span2 {\n    width: 104px;\n  }\n  .span1 {\n    width: 42px;\n  }\n  .offset12 {\n    margin-left: 764px;\n  }\n  .offset11 {\n    margin-left: 702px;\n  }\n  .offset10 {\n    margin-left: 640px;\n  }\n  .offset9 {\n    margin-left: 578px;\n  }\n  .offset8 {\n    margin-left: 516px;\n  }\n  .offset7 {\n    margin-left: 454px;\n  }\n  .offset6 {\n    margin-left: 392px;\n  }\n  .offset5 {\n    margin-left: 330px;\n  }\n  .offset4 {\n    margin-left: 268px;\n  }\n  .offset3 {\n    margin-left: 206px;\n  }\n  .offset2 {\n    margin-left: 144px;\n  }\n  .offset1 {\n    margin-left: 82px;\n  }\n  .row-fluid {\n    width: 100%;\n    *zoom: 1;\n  }\n  .row-fluid:before,\n  .row-fluid:after {\n    display: table;\n    line-height: 0;\n    content: \"\";\n  }\n  .row-fluid:after {\n    clear: both;\n  }\n  .row-fluid [class*=\"span\"] {\n    display: block;\n    float: left;\n    width: 100%;\n    min-height: 30px;\n    margin-left: 2.7624309392265194%;\n    *margin-left: 2.709239449864817%;\n    -webkit-box-sizing: border-box;\n       -moz-box-sizing: border-box;\n            box-sizing: border-box;\n  }\n  .row-fluid [class*=\"span\"]:first-child {\n    margin-left: 0;\n  }\n  .row-fluid .controls-row [class*=\"span\"] + [class*=\"span\"] {\n    margin-left: 2.7624309392265194%;\n  }\n  .row-fluid .span12 {\n    width: 100%;\n    *width: 99.94680851063829%;\n  }\n  .row-fluid .span11 {\n    width: 91.43646408839778%;\n    *width: 91.38327259903608%;\n  }\n  .row-fluid .span10 {\n    width: 82.87292817679558%;\n    *width: 82.81973668743387%;\n  }\n  .row-fluid .span9 {\n    width: 74.30939226519337%;\n    *width: 74.25620077583166%;\n  }\n  .row-fluid .span8 {\n    width: 65.74585635359117%;\n    *width: 65.69266486422946%;\n  }\n  .row-fluid .span7 {\n    width: 57.18232044198895%;\n    *width: 57.12912895262725%;\n  }\n  .row-fluid .span6 {\n    width: 48.61878453038674%;\n    *width: 48.56559304102504%;\n  }\n  .row-fluid .span5 {\n    width: 40.05524861878453%;\n    *width: 40.00205712942283%;\n  }\n  .row-fluid .span4 {\n    width: 31.491712707182323%;\n    *width: 31.43852121782062%;\n  }\n  .row-fluid .span3 {\n    width: 22.92817679558011%;\n    *width: 22.87498530621841%;\n  }\n  .row-fluid .span2 {\n    width: 14.3646408839779%;\n    *width: 14.311449394616199%;\n  }\n  .row-fluid .span1 {\n    width: 5.801104972375691%;\n    *width: 5.747913483013988%;\n  }\n  .row-fluid .offset12 {\n    margin-left: 105.52486187845304%;\n    *margin-left: 105.41847889972962%;\n  }\n  .row-fluid .offset12:first-child {\n    margin-left: 102.76243093922652%;\n    *margin-left: 102.6560479605031%;\n  }\n  .row-fluid .offset11 {\n    margin-left: 96.96132596685082%;\n    *margin-left: 96.8549429881274%;\n  }\n  .row-fluid .offset11:first-child {\n    margin-left: 94.1988950276243%;\n    *margin-left: 94.09251204890089%;\n  }\n  .row-fluid .offset10 {\n    margin-left: 88.39779005524862%;\n    *margin-left: 88.2914070765252%;\n  }\n  .row-fluid .offset10:first-child {\n    margin-left: 85.6353591160221%;\n    *margin-left: 85.52897613729868%;\n  }\n  .row-fluid .offset9 {\n    margin-left: 79.8342541436464%;\n    *margin-left: 79.72787116492299%;\n  }\n  .row-fluid .offset9:first-child {\n    margin-left: 77.07182320441989%;\n    *margin-left: 76.96544022569647%;\n  }\n  .row-fluid .offset8 {\n    margin-left: 71.2707182320442%;\n    *margin-left: 71.16433525332079%;\n  }\n  .row-fluid .offset8:first-child {\n    margin-left: 68.50828729281768%;\n    *margin-left: 68.40190431409427%;\n  }\n  .row-fluid .offset7 {\n    margin-left: 62.70718232044199%;\n    *margin-left: 62.600799341718584%;\n  }\n  .row-fluid .offset7:first-child {\n    margin-left: 59.94475138121547%;\n    *margin-left: 59.838368402492065%;\n  }\n  .row-fluid .offset6 {\n    margin-left: 54.14364640883978%;\n    *margin-left: 54.037263430116376%;\n  }\n  .row-fluid .offset6:first-child {\n    margin-left: 51.38121546961326%;\n    *margin-left: 51.27483249088986%;\n  }\n  .row-fluid .offset5 {\n    margin-left: 45.58011049723757%;\n    *margin-left: 45.47372751851417%;\n  }\n  .row-fluid .offset5:first-child {\n    margin-left: 42.81767955801105%;\n    *margin-left: 42.71129657928765%;\n  }\n  .row-fluid .offset4 {\n    margin-left: 37.01657458563536%;\n    *margin-left: 36.91019160691196%;\n  }\n  .row-fluid .offset4:first-child {\n    margin-left: 34.25414364640884%;\n    *margin-left: 34.14776066768544%;\n  }\n  .row-fluid .offset3 {\n    margin-left: 28.45303867403315%;\n    *margin-left: 28.346655695309746%;\n  }\n  .row-fluid .offset3:first-child {\n    margin-left: 25.69060773480663%;\n    *margin-left: 25.584224756083227%;\n  }\n  .row-fluid .offset2 {\n    margin-left: 19.88950276243094%;\n    *margin-left: 19.783119783707537%;\n  }\n  .row-fluid .offset2:first-child {\n    margin-left: 17.12707182320442%;\n    *margin-left: 17.02068884448102%;\n  }\n  .row-fluid .offset1 {\n    margin-left: 11.32596685082873%;\n    *margin-left: 11.219583872105325%;\n  }\n  .row-fluid .offset1:first-child {\n    margin-left: 8.56353591160221%;\n    *margin-left: 8.457152932878806%;\n  }\n  input,\n  textarea,\n  .uneditable-input {\n    margin-left: 0;\n  }\n  .controls-row [class*=\"span\"] + [class*=\"span\"] {\n    margin-left: 20px;\n  }\n  input.span12,\n  textarea.span12,\n  .uneditable-input.span12 {\n    width: 710px;\n  }\n  input.span11,\n  textarea.span11,\n  .uneditable-input.span11 {\n    width: 648px;\n  }\n  input.span10,\n  textarea.span10,\n  .uneditable-input.span10 {\n    width: 586px;\n  }\n  input.span9,\n  textarea.span9,\n  .uneditable-input.span9 {\n    width: 524px;\n  }\n  input.span8,\n  textarea.span8,\n  .uneditable-input.span8 {\n    width: 462px;\n  }\n  input.span7,\n  textarea.span7,\n  .uneditable-input.span7 {\n    width: 400px;\n  }\n  input.span6,\n  textarea.span6,\n  .uneditable-input.span6 {\n    width: 338px;\n  }\n  input.span5,\n  textarea.span5,\n  .uneditable-input.span5 {\n    width: 276px;\n  }\n  input.span4,\n  textarea.span4,\n  .uneditable-input.span4 {\n    width: 214px;\n  }\n  input.span3,\n  textarea.span3,\n  .uneditable-input.span3 {\n    width: 152px;\n  }\n  input.span2,\n  textarea.span2,\n  .uneditable-input.span2 {\n    width: 90px;\n  }\n  input.span1,\n  textarea.span1,\n  .uneditable-input.span1 {\n    width: 28px;\n  }\n}\n\n@media (max-width: 767px) {\n  body {\n    padding-right: 20px;\n    padding-left: 20px;\n  }\n  .navbar-fixed-top,\n  .navbar-fixed-bottom,\n  .navbar-static-top {\n    margin-right: -20px;\n    margin-left: -20px;\n  }\n  .container-fluid {\n    padding: 0;\n  }\n  .dl-horizontal dt {\n    float: none;\n    width: auto;\n    clear: none;\n    text-align: left;\n  }\n  .dl-horizontal dd {\n    margin-left: 0;\n  }\n  .container {\n    width: auto;\n  }\n  .row-fluid {\n    width: 100%;\n  }\n  .row,\n  .thumbnails {\n    margin-left: 0;\n  }\n  .thumbnails > li {\n    float: none;\n    margin-left: 0;\n  }\n  [class*=\"span\"],\n  .uneditable-input[class*=\"span\"],\n  .row-fluid [class*=\"span\"] {\n    display: block;\n    float: none;\n    width: 100%;\n    margin-left: 0;\n    -webkit-box-sizing: border-box;\n       -moz-box-sizing: border-box;\n            box-sizing: border-box;\n  }\n  .span12,\n  .row-fluid .span12 {\n    width: 100%;\n    -webkit-box-sizing: border-box;\n       -moz-box-sizing: border-box;\n            box-sizing: border-box;\n  }\n  .row-fluid [class*=\"offset\"]:first-child {\n    margin-left: 0;\n  }\n  .input-large,\n  .input-xlarge,\n  .input-xxlarge,\n  input[class*=\"span\"],\n  select[class*=\"span\"],\n  textarea[class*=\"span\"],\n  .uneditable-input {\n    display: block;\n    width: 100%;\n    min-height: 30px;\n    -webkit-box-sizing: border-box;\n       -moz-box-sizing: border-box;\n            box-sizing: border-box;\n  }\n  .input-prepend input,\n  .input-append input,\n  .input-prepend input[class*=\"span\"],\n  .input-append input[class*=\"span\"] {\n    display: inline-block;\n    width: auto;\n  }\n  .controls-row [class*=\"span\"] + [class*=\"span\"] {\n    margin-left: 0;\n  }\n  .modal {\n    position: fixed;\n    top: 20px;\n    right: 20px;\n    left: 20px;\n    width: auto;\n    margin: 0;\n  }\n  .modal.fade {\n    top: -100px;\n  }\n  .modal.fade.in {\n    top: 20px;\n  }\n}\n\n@media (max-width: 480px) {\n  .nav-collapse {\n    -webkit-transform: translate3d(0, 0, 0);\n  }\n  .page-header h1 small {\n    display: block;\n    line-height: 20px;\n  }\n  input[type=\"checkbox\"],\n  input[type=\"radio\"] {\n    border: 1px solid #ccc;\n  }\n  .form-horizontal .control-label {\n    float: none;\n    width: auto;\n    padding-top: 0;\n    text-align: left;\n  }\n  .form-horizontal .controls {\n    margin-left: 0;\n  }\n  .form-horizontal .control-list {\n    padding-top: 0;\n  }\n  .form-horizontal .form-actions {\n    padding-right: 10px;\n    padding-left: 10px;\n  }\n  .media .pull-left,\n  .media .pull-right {\n    display: block;\n    float: none;\n    margin-bottom: 10px;\n  }\n  .media-object {\n    margin-right: 0;\n    margin-left: 0;\n  }\n  .modal {\n    top: 10px;\n    right: 10px;\n    left: 10px;\n  }\n  .modal-header .close {\n    padding: 10px;\n    margin: -10px;\n  }\n  .carousel-caption {\n    position: static;\n  }\n}\n\n@media (max-width: 979px) {\n  body {\n    padding-top: 0;\n  }\n  .navbar-fixed-top,\n  .navbar-fixed-bottom {\n    position: static;\n  }\n  .navbar-fixed-top {\n    margin-bottom: 20px;\n  }\n  .navbar-fixed-bottom {\n    margin-top: 20px;\n  }\n  .navbar-fixed-top .navbar-inner,\n  .navbar-fixed-bottom .navbar-inner {\n    padding: 5px;\n  }\n  .navbar .container {\n    width: auto;\n    padding: 0;\n  }\n  .navbar .brand {\n    padding-right: 10px;\n    padding-left: 10px;\n    margin: 0 0 0 -5px;\n  }\n  .nav-collapse {\n    clear: both;\n  }\n  .nav-collapse .nav {\n    float: none;\n    margin: 0 0 10px;\n  }\n  .nav-collapse .nav > li {\n    float: none;\n  }\n  .nav-collapse .nav > li > a {\n    margin-bottom: 2px;\n  }\n  .nav-collapse .nav > .divider-vertical {\n    display: none;\n  }\n  .nav-collapse .nav .nav-header {\n    color: #777777;\n    text-shadow: none;\n  }\n  .nav-collapse .nav > li > a,\n  .nav-collapse .dropdown-menu a {\n    padding: 9px 15px;\n    font-weight: bold;\n    color: #777777;\n    -webkit-border-radius: 3px;\n       -moz-border-radius: 3px;\n            border-radius: 3px;\n  }\n  .nav-collapse .btn {\n    padding: 4px 10px 4px;\n    font-weight: normal;\n    -webkit-border-radius: 4px;\n       -moz-border-radius: 4px;\n            border-radius: 4px;\n  }\n  .nav-collapse .dropdown-menu li + li a {\n    margin-bottom: 2px;\n  }\n  .nav-collapse .nav > li > a:hover,\n  .nav-collapse .nav > li > a:focus,\n  .nav-collapse .dropdown-menu a:hover,\n  .nav-collapse .dropdown-menu a:focus {\n    background-color: #f2f2f2;\n  }\n  .navbar-inverse .nav-collapse .nav > li > a,\n  .navbar-inverse .nav-collapse .dropdown-menu a {\n    color: #999999;\n  }\n  .navbar-inverse .nav-collapse .nav > li > a:hover,\n  .navbar-inverse .nav-collapse .nav > li > a:focus,\n  .navbar-inverse .nav-collapse .dropdown-menu a:hover,\n  .navbar-inverse .nav-collapse .dropdown-menu a:focus {\n    background-color: #111111;\n  }\n  .nav-collapse.in .btn-group {\n    padding: 0;\n    margin-top: 5px;\n  }\n  .nav-collapse .dropdown-menu {\n    position: static;\n    top: auto;\n    left: auto;\n    display: none;\n    float: none;\n    max-width: none;\n    padding: 0;\n    margin: 0 15px;\n    background-color: transparent;\n    border: none;\n    -webkit-border-radius: 0;\n       -moz-border-radius: 0;\n            border-radius: 0;\n    -webkit-box-shadow: none;\n       -moz-box-shadow: none;\n            box-shadow: none;\n  }\n  .nav-collapse .open > .dropdown-menu {\n    display: block;\n  }\n  .nav-collapse .dropdown-menu:before,\n  .nav-collapse .dropdown-menu:after {\n    display: none;\n  }\n  .nav-collapse .dropdown-menu .divider {\n    display: none;\n  }\n  .nav-collapse .nav > li > .dropdown-menu:before,\n  .nav-collapse .nav > li > .dropdown-menu:after {\n    display: none;\n  }\n  .nav-collapse .navbar-form,\n  .nav-collapse .navbar-search {\n    float: none;\n    padding: 10px 15px;\n    margin: 10px 0;\n    border-top: 1px solid #f2f2f2;\n    border-bottom: 1px solid #f2f2f2;\n    -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);\n       -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);\n            box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);\n  }\n  .navbar-inverse .nav-collapse .navbar-form,\n  .navbar-inverse .nav-collapse .navbar-search {\n    border-top-color: #111111;\n    border-bottom-color: #111111;\n  }\n  .navbar .nav-collapse .nav.pull-right {\n    float: none;\n    margin-left: 0;\n  }\n  .nav-collapse,\n  .nav-collapse.collapse {\n    height: 0;\n    overflow: hidden;\n  }\n  .navbar .btn-navbar {\n    display: block;\n  }\n  .navbar-static .navbar-inner {\n    padding-right: 10px;\n    padding-left: 10px;\n  }\n}\n\n@media (min-width: 980px) {\n  .nav-collapse.collapse {\n    height: auto !important;\n    overflow: visible !important;\n  }\n}\n"
  },
  {
    "path": "explainshell/web/static/css/bootstrap.css",
    "content": "/*!\n * Bootstrap v2.3.1\n *\n * Copyright 2012 Twitter, Inc\n * Licensed under the Apache License v2.0\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Designed and built with all the love in the world @twitter by @mdo and @fat.\n */\n\n.clearfix {\n  *zoom: 1;\n}\n\n.clearfix:before,\n.clearfix:after {\n  display: table;\n  line-height: 0;\n  content: \"\";\n}\n\n.clearfix:after {\n  clear: both;\n}\n\n.hide-text {\n  font: 0/0 a;\n  color: transparent;\n  text-shadow: none;\n  background-color: transparent;\n  border: 0;\n}\n\n.input-block-level {\n  display: block;\n  width: 100%;\n  min-height: 30px;\n  -webkit-box-sizing: border-box;\n     -moz-box-sizing: border-box;\n          box-sizing: border-box;\n}\n\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nnav,\nsection {\n  display: block;\n}\n\naudio,\ncanvas,\nvideo {\n  display: inline-block;\n  *display: inline;\n  *zoom: 1;\n}\n\naudio:not([controls]) {\n  display: none;\n}\n\nhtml {\n  font-size: 100%;\n  -webkit-text-size-adjust: 100%;\n      -ms-text-size-adjust: 100%;\n}\n\na:focus {\n  outline: thin dotted #333;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\n\na:hover,\na:active {\n  outline: 0;\n}\n\nsub,\nsup {\n  position: relative;\n  font-size: 75%;\n  line-height: 0;\n  vertical-align: baseline;\n}\n\nsup {\n  top: -0.5em;\n}\n\nsub {\n  bottom: -0.25em;\n}\n\nimg {\n  width: auto\\9;\n  height: auto;\n  max-width: 100%;\n  vertical-align: middle;\n  border: 0;\n  -ms-interpolation-mode: bicubic;\n}\n\n#map_canvas img,\n.google-maps img {\n  max-width: none;\n}\n\nbutton,\ninput,\nselect,\ntextarea {\n  margin: 0;\n  font-size: 100%;\n  vertical-align: middle;\n}\n\nbutton,\ninput {\n  *overflow: visible;\n  line-height: normal;\n}\n\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n  padding: 0;\n  border: 0;\n}\n\nbutton,\nhtml input[type=\"button\"],\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n  cursor: pointer;\n  -webkit-appearance: button;\n}\n\nlabel,\nselect,\nbutton,\ninput[type=\"button\"],\ninput[type=\"reset\"],\ninput[type=\"submit\"],\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n  cursor: pointer;\n}\n\ninput[type=\"search\"] {\n  -webkit-box-sizing: content-box;\n     -moz-box-sizing: content-box;\n          box-sizing: content-box;\n  -webkit-appearance: textfield;\n}\n\ninput[type=\"search\"]::-webkit-search-decoration,\ninput[type=\"search\"]::-webkit-search-cancel-button {\n  -webkit-appearance: none;\n}\n\ntextarea {\n  overflow: auto;\n  vertical-align: top;\n}\n\n@media print {\n  * {\n    color: #000 !important;\n    text-shadow: none !important;\n    background: transparent !important;\n    box-shadow: none !important;\n  }\n  a,\n  a:visited {\n    text-decoration: underline;\n  }\n  a[href]:after {\n    content: \" (\" attr(href) \")\";\n  }\n  abbr[title]:after {\n    content: \" (\" attr(title) \")\";\n  }\n  .ir a:after,\n  a[href^=\"javascript:\"]:after,\n  a[href^=\"#\"]:after {\n    content: \"\";\n  }\n  pre,\n  blockquote {\n    border: 1px solid #999;\n    page-break-inside: avoid;\n  }\n  thead {\n    display: table-header-group;\n  }\n  tr,\n  img {\n    page-break-inside: avoid;\n  }\n  img {\n    max-width: 100% !important;\n  }\n  @page  {\n    margin: 0.5cm;\n  }\n  p,\n  h2,\n  h3 {\n    orphans: 3;\n    widows: 3;\n  }\n  h2,\n  h3 {\n    page-break-after: avoid;\n  }\n}\n\nbody {\n  margin: 0;\n  font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  font-size: 14px;\n  line-height: 20px;\n  color: #333333;\n  background-color: #ffffff;\n}\n\na {\n  color: #0088cc;\n  text-decoration: none;\n}\n\na:hover,\na:focus {\n  color: #005580;\n  text-decoration: underline;\n}\n\n.img-rounded {\n  -webkit-border-radius: 6px;\n     -moz-border-radius: 6px;\n          border-radius: 6px;\n}\n\n.img-polaroid {\n  padding: 4px;\n  background-color: #fff;\n  border: 1px solid #ccc;\n  border: 1px solid rgba(0, 0, 0, 0.2);\n  -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n     -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n          box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n}\n\n.img-circle {\n  -webkit-border-radius: 500px;\n     -moz-border-radius: 500px;\n          border-radius: 500px;\n}\n\n.row {\n  margin-left: -20px;\n  *zoom: 1;\n}\n\n.row:before,\n.row:after {\n  display: table;\n  line-height: 0;\n  content: \"\";\n}\n\n.row:after {\n  clear: both;\n}\n\n[class*=\"span\"] {\n  float: left;\n  min-height: 1px;\n  margin-left: 20px;\n}\n\n.container,\n.navbar-static-top .container,\n.navbar-fixed-top .container,\n.navbar-fixed-bottom .container {\n  width: 940px;\n}\n\n.span12 {\n  width: 940px;\n}\n\n.span11 {\n  width: 860px;\n}\n\n.span10 {\n  width: 780px;\n}\n\n.span9 {\n  width: 700px;\n}\n\n.span8 {\n  width: 620px;\n}\n\n.span7 {\n  width: 540px;\n}\n\n.span6 {\n  width: 460px;\n}\n\n.span5 {\n  width: 380px;\n}\n\n.span4 {\n  width: 300px;\n}\n\n.span3 {\n  width: 220px;\n}\n\n.span2 {\n  width: 140px;\n}\n\n.span1 {\n  width: 60px;\n}\n\n.offset12 {\n  margin-left: 980px;\n}\n\n.offset11 {\n  margin-left: 900px;\n}\n\n.offset10 {\n  margin-left: 820px;\n}\n\n.offset9 {\n  margin-left: 740px;\n}\n\n.offset8 {\n  margin-left: 660px;\n}\n\n.offset7 {\n  margin-left: 580px;\n}\n\n.offset6 {\n  margin-left: 500px;\n}\n\n.offset5 {\n  margin-left: 420px;\n}\n\n.offset4 {\n  margin-left: 340px;\n}\n\n.offset3 {\n  margin-left: 260px;\n}\n\n.offset2 {\n  margin-left: 180px;\n}\n\n.offset1 {\n  margin-left: 100px;\n}\n\n.row-fluid {\n  width: 100%;\n  *zoom: 1;\n}\n\n.row-fluid:before,\n.row-fluid:after {\n  display: table;\n  line-height: 0;\n  content: \"\";\n}\n\n.row-fluid:after {\n  clear: both;\n}\n\n.row-fluid [class*=\"span\"] {\n  display: block;\n  float: left;\n  width: 100%;\n  min-height: 30px;\n  margin-left: 2.127659574468085%;\n  *margin-left: 2.074468085106383%;\n  -webkit-box-sizing: border-box;\n     -moz-box-sizing: border-box;\n          box-sizing: border-box;\n}\n\n.row-fluid [class*=\"span\"]:first-child {\n  margin-left: 0;\n}\n\n.row-fluid .controls-row [class*=\"span\"] + [class*=\"span\"] {\n  margin-left: 2.127659574468085%;\n}\n\n.row-fluid .span12 {\n  width: 100%;\n  *width: 99.94680851063829%;\n}\n\n.row-fluid .span11 {\n  width: 91.48936170212765%;\n  *width: 91.43617021276594%;\n}\n\n.row-fluid .span10 {\n  width: 82.97872340425532%;\n  *width: 82.92553191489361%;\n}\n\n.row-fluid .span9 {\n  width: 74.46808510638297%;\n  *width: 74.41489361702126%;\n}\n\n.row-fluid .span8 {\n  width: 65.95744680851064%;\n  *width: 65.90425531914893%;\n}\n\n.row-fluid .span7 {\n  width: 57.44680851063829%;\n  *width: 57.39361702127659%;\n}\n\n.row-fluid .span6 {\n  width: 48.93617021276595%;\n  *width: 48.88297872340425%;\n}\n\n.row-fluid .span5 {\n  width: 40.42553191489362%;\n  *width: 40.37234042553192%;\n}\n\n.row-fluid .span4 {\n  width: 31.914893617021278%;\n  *width: 31.861702127659576%;\n}\n\n.row-fluid .span3 {\n  width: 23.404255319148934%;\n  *width: 23.351063829787233%;\n}\n\n.row-fluid .span2 {\n  width: 14.893617021276595%;\n  *width: 14.840425531914894%;\n}\n\n.row-fluid .span1 {\n  width: 6.382978723404255%;\n  *width: 6.329787234042553%;\n}\n\n.row-fluid .offset12 {\n  margin-left: 104.25531914893617%;\n  *margin-left: 104.14893617021275%;\n}\n\n.row-fluid .offset12:first-child {\n  margin-left: 102.12765957446808%;\n  *margin-left: 102.02127659574467%;\n}\n\n.row-fluid .offset11 {\n  margin-left: 95.74468085106382%;\n  *margin-left: 95.6382978723404%;\n}\n\n.row-fluid .offset11:first-child {\n  margin-left: 93.61702127659574%;\n  *margin-left: 93.51063829787232%;\n}\n\n.row-fluid .offset10 {\n  margin-left: 87.23404255319149%;\n  *margin-left: 87.12765957446807%;\n}\n\n.row-fluid .offset10:first-child {\n  margin-left: 85.1063829787234%;\n  *margin-left: 84.99999999999999%;\n}\n\n.row-fluid .offset9 {\n  margin-left: 78.72340425531914%;\n  *margin-left: 78.61702127659572%;\n}\n\n.row-fluid .offset9:first-child {\n  margin-left: 76.59574468085106%;\n  *margin-left: 76.48936170212764%;\n}\n\n.row-fluid .offset8 {\n  margin-left: 70.2127659574468%;\n  *margin-left: 70.10638297872339%;\n}\n\n.row-fluid .offset8:first-child {\n  margin-left: 68.08510638297872%;\n  *margin-left: 67.9787234042553%;\n}\n\n.row-fluid .offset7 {\n  margin-left: 61.70212765957446%;\n  *margin-left: 61.59574468085106%;\n}\n\n.row-fluid .offset7:first-child {\n  margin-left: 59.574468085106375%;\n  *margin-left: 59.46808510638297%;\n}\n\n.row-fluid .offset6 {\n  margin-left: 53.191489361702125%;\n  *margin-left: 53.085106382978715%;\n}\n\n.row-fluid .offset6:first-child {\n  margin-left: 51.063829787234035%;\n  *margin-left: 50.95744680851063%;\n}\n\n.row-fluid .offset5 {\n  margin-left: 44.68085106382979%;\n  *margin-left: 44.57446808510638%;\n}\n\n.row-fluid .offset5:first-child {\n  margin-left: 42.5531914893617%;\n  *margin-left: 42.4468085106383%;\n}\n\n.row-fluid .offset4 {\n  margin-left: 36.170212765957444%;\n  *margin-left: 36.06382978723405%;\n}\n\n.row-fluid .offset4:first-child {\n  margin-left: 34.04255319148936%;\n  *margin-left: 33.93617021276596%;\n}\n\n.row-fluid .offset3 {\n  margin-left: 27.659574468085104%;\n  *margin-left: 27.5531914893617%;\n}\n\n.row-fluid .offset3:first-child {\n  margin-left: 25.53191489361702%;\n  *margin-left: 25.425531914893618%;\n}\n\n.row-fluid .offset2 {\n  margin-left: 19.148936170212764%;\n  *margin-left: 19.04255319148936%;\n}\n\n.row-fluid .offset2:first-child {\n  margin-left: 17.02127659574468%;\n  *margin-left: 16.914893617021278%;\n}\n\n.row-fluid .offset1 {\n  margin-left: 10.638297872340425%;\n  *margin-left: 10.53191489361702%;\n}\n\n.row-fluid .offset1:first-child {\n  margin-left: 8.51063829787234%;\n  *margin-left: 8.404255319148938%;\n}\n\n[class*=\"span\"].hide,\n.row-fluid [class*=\"span\"].hide {\n  display: none;\n}\n\n[class*=\"span\"].pull-right,\n.row-fluid [class*=\"span\"].pull-right {\n  float: right;\n}\n\n.container {\n  margin-right: auto;\n  margin-left: auto;\n  *zoom: 1;\n}\n\n.container:before,\n.container:after {\n  display: table;\n  line-height: 0;\n  content: \"\";\n}\n\n.container:after {\n  clear: both;\n}\n\n.container-fluid {\n  padding-right: 20px;\n  padding-left: 20px;\n  *zoom: 1;\n}\n\n.container-fluid:before,\n.container-fluid:after {\n  display: table;\n  line-height: 0;\n  content: \"\";\n}\n\n.container-fluid:after {\n  clear: both;\n}\n\np {\n  margin: 0 0 10px;\n}\n\n.lead {\n  margin-bottom: 20px;\n  font-size: 21px;\n  font-weight: 200;\n  line-height: 30px;\n}\n\nsmall {\n  font-size: 85%;\n}\n\nstrong {\n  font-weight: bold;\n}\n\nem {\n  font-style: italic;\n}\n\ncite {\n  font-style: normal;\n}\n\n.muted {\n  color: #999999;\n}\n\na.muted:hover,\na.muted:focus {\n  color: #808080;\n}\n\n.text-warning {\n  color: #c09853;\n}\n\na.text-warning:hover,\na.text-warning:focus {\n  color: #a47e3c;\n}\n\n.text-error {\n  color: #b94a48;\n}\n\na.text-error:hover,\na.text-error:focus {\n  color: #953b39;\n}\n\n.text-info {\n  color: #3a87ad;\n}\n\na.text-info:hover,\na.text-info:focus {\n  color: #2d6987;\n}\n\n.text-success {\n  color: #468847;\n}\n\na.text-success:hover,\na.text-success:focus {\n  color: #356635;\n}\n\n.text-left {\n  text-align: left;\n}\n\n.text-right {\n  text-align: right;\n}\n\n.text-center {\n  text-align: center;\n}\n\nh1,\nh2,\nh3,\nh4,\nh5,\nh6 {\n  margin: 10px 0;\n  font-family: inherit;\n  font-weight: bold;\n  line-height: 20px;\n  color: inherit;\n  text-rendering: optimizelegibility;\n}\n\nh1 small,\nh2 small,\nh3 small,\nh4 small,\nh5 small,\nh6 small {\n  font-weight: normal;\n  line-height: 1;\n  color: #999999;\n}\n\nh1,\nh2,\nh3 {\n  line-height: 40px;\n}\n\nh1 {\n  font-size: 38.5px;\n}\n\nh2 {\n  font-size: 31.5px;\n}\n\nh3 {\n  font-size: 24.5px;\n}\n\nh4 {\n  font-size: 17.5px;\n}\n\nh5 {\n  font-size: 14px;\n}\n\nh6 {\n  font-size: 11.9px;\n}\n\nh1 small {\n  font-size: 24.5px;\n}\n\nh2 small {\n  font-size: 17.5px;\n}\n\nh3 small {\n  font-size: 14px;\n}\n\nh4 small {\n  font-size: 14px;\n}\n\n.page-header {\n  padding-bottom: 9px;\n  margin: 20px 0 30px;\n  border-bottom: 1px solid #eeeeee;\n}\n\nul,\nol {\n  padding: 0;\n  margin: 0 0 10px 25px;\n}\n\nul ul,\nul ol,\nol ol,\nol ul {\n  margin-bottom: 0;\n}\n\nli {\n  line-height: 20px;\n}\n\nul.unstyled,\nol.unstyled {\n  margin-left: 0;\n  list-style: none;\n}\n\nul.inline,\nol.inline {\n  margin-left: 0;\n  list-style: none;\n}\n\nul.inline > li,\nol.inline > li {\n  display: inline-block;\n  *display: inline;\n  padding-right: 5px;\n  padding-left: 5px;\n  *zoom: 1;\n}\n\ndl {\n  margin-bottom: 20px;\n}\n\ndt,\ndd {\n  line-height: 20px;\n}\n\ndt {\n  font-weight: bold;\n}\n\ndd {\n  margin-left: 10px;\n}\n\n.dl-horizontal {\n  *zoom: 1;\n}\n\n.dl-horizontal:before,\n.dl-horizontal:after {\n  display: table;\n  line-height: 0;\n  content: \"\";\n}\n\n.dl-horizontal:after {\n  clear: both;\n}\n\n.dl-horizontal dt {\n  float: left;\n  width: 160px;\n  overflow: hidden;\n  clear: left;\n  text-align: right;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n}\n\n.dl-horizontal dd {\n  margin-left: 180px;\n}\n\nhr {\n  margin: 20px 0;\n  border: 0;\n  border-top: 1px solid #eeeeee;\n  border-bottom: 1px solid #ffffff;\n}\n\nabbr[title],\nabbr[data-original-title] {\n  cursor: help;\n  border-bottom: 1px dotted #999999;\n}\n\nabbr.initialism {\n  font-size: 90%;\n  text-transform: uppercase;\n}\n\nblockquote {\n  padding: 0 0 0 15px;\n  margin: 0 0 20px;\n  border-left: 5px solid #eeeeee;\n}\n\nblockquote p {\n  margin-bottom: 0;\n  font-size: 17.5px;\n  font-weight: 300;\n  line-height: 1.25;\n}\n\nblockquote small {\n  display: block;\n  line-height: 20px;\n  color: #999999;\n}\n\nblockquote small:before {\n  content: '\\2014 \\00A0';\n}\n\nblockquote.pull-right {\n  float: right;\n  padding-right: 15px;\n  padding-left: 0;\n  border-right: 5px solid #eeeeee;\n  border-left: 0;\n}\n\nblockquote.pull-right p,\nblockquote.pull-right small {\n  text-align: right;\n}\n\nblockquote.pull-right small:before {\n  content: '';\n}\n\nblockquote.pull-right small:after {\n  content: '\\00A0 \\2014';\n}\n\nq:before,\nq:after,\nblockquote:before,\nblockquote:after {\n  content: \"\";\n}\n\naddress {\n  display: block;\n  margin-bottom: 20px;\n  font-style: normal;\n  line-height: 20px;\n}\n\ncode,\npre {\n  padding: 0 3px 2px;\n  font-family: Monaco, Menlo, Consolas, \"Courier New\", monospace;\n  font-size: 12px;\n  color: #333333;\n  -webkit-border-radius: 3px;\n     -moz-border-radius: 3px;\n          border-radius: 3px;\n}\n\ncode {\n  padding: 2px 4px;\n  color: #d14;\n  white-space: nowrap;\n  background-color: #f7f7f9;\n  border: 1px solid #e1e1e8;\n}\n\npre {\n  display: block;\n  padding: 9.5px;\n  margin: 0 0 10px;\n  font-size: 13px;\n  line-height: 20px;\n  word-break: break-all;\n  word-wrap: break-word;\n  white-space: pre;\n  white-space: pre-wrap;\n  background-color: #f5f5f5;\n  border: 1px solid #ccc;\n  border: 1px solid rgba(0, 0, 0, 0.15);\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n}\n\npre.prettyprint {\n  margin-bottom: 20px;\n}\n\npre code {\n  padding: 0;\n  color: inherit;\n  white-space: pre;\n  white-space: pre-wrap;\n  background-color: transparent;\n  border: 0;\n}\n\n.pre-scrollable {\n  max-height: 340px;\n  overflow-y: scroll;\n}\n\nform {\n  margin: 0 0 20px;\n}\n\nfieldset {\n  padding: 0;\n  margin: 0;\n  border: 0;\n}\n\nlegend {\n  display: block;\n  width: 100%;\n  padding: 0;\n  margin-bottom: 20px;\n  font-size: 21px;\n  line-height: 40px;\n  color: #333333;\n  border: 0;\n  border-bottom: 1px solid #e5e5e5;\n}\n\nlegend small {\n  font-size: 15px;\n  color: #999999;\n}\n\nlabel,\ninput,\nbutton,\nselect,\ntextarea {\n  font-size: 14px;\n  font-weight: normal;\n  line-height: 20px;\n}\n\ninput,\nbutton,\nselect,\ntextarea {\n  font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n}\n\nlabel {\n  display: block;\n  margin-bottom: 5px;\n}\n\nselect,\ntextarea,\ninput[type=\"text\"],\ninput[type=\"password\"],\ninput[type=\"datetime\"],\ninput[type=\"datetime-local\"],\ninput[type=\"date\"],\ninput[type=\"month\"],\ninput[type=\"time\"],\ninput[type=\"week\"],\ninput[type=\"number\"],\ninput[type=\"email\"],\ninput[type=\"url\"],\ninput[type=\"search\"],\ninput[type=\"tel\"],\ninput[type=\"color\"],\n.uneditable-input {\n  display: inline-block;\n  height: 20px;\n  padding: 4px 6px;\n  margin-bottom: 10px;\n  font-size: 14px;\n  line-height: 20px;\n  color: #555555;\n  vertical-align: middle;\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n}\n\ninput,\ntextarea,\n.uneditable-input {\n  width: 206px;\n}\n\ntextarea {\n  height: auto;\n}\n\ntextarea,\ninput[type=\"text\"],\ninput[type=\"password\"],\ninput[type=\"datetime\"],\ninput[type=\"datetime-local\"],\ninput[type=\"date\"],\ninput[type=\"month\"],\ninput[type=\"time\"],\ninput[type=\"week\"],\ninput[type=\"number\"],\ninput[type=\"email\"],\ninput[type=\"url\"],\ninput[type=\"search\"],\ninput[type=\"tel\"],\ninput[type=\"color\"],\n.uneditable-input {\n  background-color: #ffffff;\n  border: 1px solid #cccccc;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n     -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n  -webkit-transition: border linear 0.2s, box-shadow linear 0.2s;\n     -moz-transition: border linear 0.2s, box-shadow linear 0.2s;\n       -o-transition: border linear 0.2s, box-shadow linear 0.2s;\n          transition: border linear 0.2s, box-shadow linear 0.2s;\n}\n\ntextarea:focus,\ninput[type=\"text\"]:focus,\ninput[type=\"password\"]:focus,\ninput[type=\"datetime\"]:focus,\ninput[type=\"datetime-local\"]:focus,\ninput[type=\"date\"]:focus,\ninput[type=\"month\"]:focus,\ninput[type=\"time\"]:focus,\ninput[type=\"week\"]:focus,\ninput[type=\"number\"]:focus,\ninput[type=\"email\"]:focus,\ninput[type=\"url\"]:focus,\ninput[type=\"search\"]:focus,\ninput[type=\"tel\"]:focus,\ninput[type=\"color\"]:focus,\n.uneditable-input:focus {\n  border-color: rgba(82, 168, 236, 0.8);\n  outline: 0;\n  outline: thin dotted \\9;\n  /* IE6-9 */\n\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);\n     -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);\n}\n\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n  margin: 4px 0 0;\n  margin-top: 1px \\9;\n  *margin-top: 0;\n  line-height: normal;\n}\n\ninput[type=\"file\"],\ninput[type=\"image\"],\ninput[type=\"submit\"],\ninput[type=\"reset\"],\ninput[type=\"button\"],\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n  width: auto;\n}\n\nselect,\ninput[type=\"file\"] {\n  height: 30px;\n  /* In IE7, the height of the select element cannot be changed by height, only font-size */\n\n  *margin-top: 4px;\n  /* For IE7, add top margin to align select with labels */\n\n  line-height: 30px;\n}\n\nselect {\n  width: 220px;\n  background-color: #ffffff;\n  border: 1px solid #cccccc;\n}\n\nselect[multiple],\nselect[size] {\n  height: auto;\n}\n\nselect:focus,\ninput[type=\"file\"]:focus,\ninput[type=\"radio\"]:focus,\ninput[type=\"checkbox\"]:focus {\n  outline: thin dotted #333;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\n\n.uneditable-input,\n.uneditable-textarea {\n  color: #999999;\n  cursor: not-allowed;\n  background-color: #fcfcfc;\n  border-color: #cccccc;\n  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025);\n     -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025);\n          box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025);\n}\n\n.uneditable-input {\n  overflow: hidden;\n  white-space: nowrap;\n}\n\n.uneditable-textarea {\n  width: auto;\n  height: auto;\n}\n\ninput:-moz-placeholder,\ntextarea:-moz-placeholder {\n  color: #999999;\n}\n\ninput:-ms-input-placeholder,\ntextarea:-ms-input-placeholder {\n  color: #999999;\n}\n\ninput::-webkit-input-placeholder,\ntextarea::-webkit-input-placeholder {\n  color: #999999;\n}\n\n.radio,\n.checkbox {\n  min-height: 20px;\n  padding-left: 20px;\n}\n\n.radio input[type=\"radio\"],\n.checkbox input[type=\"checkbox\"] {\n  float: left;\n  margin-left: -20px;\n}\n\n.controls > .radio:first-child,\n.controls > .checkbox:first-child {\n  padding-top: 5px;\n}\n\n.radio.inline,\n.checkbox.inline {\n  display: inline-block;\n  padding-top: 5px;\n  margin-bottom: 0;\n  vertical-align: middle;\n}\n\n.radio.inline + .radio.inline,\n.checkbox.inline + .checkbox.inline {\n  margin-left: 10px;\n}\n\n.input-mini {\n  width: 60px;\n}\n\n.input-small {\n  width: 90px;\n}\n\n.input-medium {\n  width: 150px;\n}\n\n.input-large {\n  width: 210px;\n}\n\n.input-xlarge {\n  width: 270px;\n}\n\n.input-xxlarge {\n  width: 530px;\n}\n\ninput[class*=\"span\"],\nselect[class*=\"span\"],\ntextarea[class*=\"span\"],\n.uneditable-input[class*=\"span\"],\n.row-fluid input[class*=\"span\"],\n.row-fluid select[class*=\"span\"],\n.row-fluid textarea[class*=\"span\"],\n.row-fluid .uneditable-input[class*=\"span\"] {\n  float: none;\n  margin-left: 0;\n}\n\n.input-append input[class*=\"span\"],\n.input-append .uneditable-input[class*=\"span\"],\n.input-prepend input[class*=\"span\"],\n.input-prepend .uneditable-input[class*=\"span\"],\n.row-fluid input[class*=\"span\"],\n.row-fluid select[class*=\"span\"],\n.row-fluid textarea[class*=\"span\"],\n.row-fluid .uneditable-input[class*=\"span\"],\n.row-fluid .input-prepend [class*=\"span\"],\n.row-fluid .input-append [class*=\"span\"] {\n  display: inline-block;\n}\n\ninput,\ntextarea,\n.uneditable-input {\n  margin-left: 0;\n}\n\n.controls-row [class*=\"span\"] + [class*=\"span\"] {\n  margin-left: 20px;\n}\n\ninput.span12,\ntextarea.span12,\n.uneditable-input.span12 {\n  width: 926px;\n}\n\ninput.span11,\ntextarea.span11,\n.uneditable-input.span11 {\n  width: 846px;\n}\n\ninput.span10,\ntextarea.span10,\n.uneditable-input.span10 {\n  width: 766px;\n}\n\ninput.span9,\ntextarea.span9,\n.uneditable-input.span9 {\n  width: 686px;\n}\n\ninput.span8,\ntextarea.span8,\n.uneditable-input.span8 {\n  width: 606px;\n}\n\ninput.span7,\ntextarea.span7,\n.uneditable-input.span7 {\n  width: 526px;\n}\n\ninput.span6,\ntextarea.span6,\n.uneditable-input.span6 {\n  width: 446px;\n}\n\ninput.span5,\ntextarea.span5,\n.uneditable-input.span5 {\n  width: 366px;\n}\n\ninput.span4,\ntextarea.span4,\n.uneditable-input.span4 {\n  width: 286px;\n}\n\ninput.span3,\ntextarea.span3,\n.uneditable-input.span3 {\n  width: 206px;\n}\n\ninput.span2,\ntextarea.span2,\n.uneditable-input.span2 {\n  width: 126px;\n}\n\ninput.span1,\ntextarea.span1,\n.uneditable-input.span1 {\n  width: 46px;\n}\n\n.controls-row {\n  *zoom: 1;\n}\n\n.controls-row:before,\n.controls-row:after {\n  display: table;\n  line-height: 0;\n  content: \"\";\n}\n\n.controls-row:after {\n  clear: both;\n}\n\n.controls-row [class*=\"span\"],\n.row-fluid .controls-row [class*=\"span\"] {\n  float: left;\n}\n\n.controls-row .checkbox[class*=\"span\"],\n.controls-row .radio[class*=\"span\"] {\n  padding-top: 5px;\n}\n\ninput[disabled],\nselect[disabled],\ntextarea[disabled],\ninput[readonly],\nselect[readonly],\ntextarea[readonly] {\n  cursor: not-allowed;\n  background-color: #eeeeee;\n}\n\ninput[type=\"radio\"][disabled],\ninput[type=\"checkbox\"][disabled],\ninput[type=\"radio\"][readonly],\ninput[type=\"checkbox\"][readonly] {\n  background-color: transparent;\n}\n\n.control-group.warning .control-label,\n.control-group.warning .help-block,\n.control-group.warning .help-inline {\n  color: #c09853;\n}\n\n.control-group.warning .checkbox,\n.control-group.warning .radio,\n.control-group.warning input,\n.control-group.warning select,\n.control-group.warning textarea {\n  color: #c09853;\n}\n\n.control-group.warning input,\n.control-group.warning select,\n.control-group.warning textarea {\n  border-color: #c09853;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n     -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n\n.control-group.warning input:focus,\n.control-group.warning select:focus,\n.control-group.warning textarea:focus {\n  border-color: #a47e3c;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e;\n     -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e;\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e;\n}\n\n.control-group.warning .input-prepend .add-on,\n.control-group.warning .input-append .add-on {\n  color: #c09853;\n  background-color: #fcf8e3;\n  border-color: #c09853;\n}\n\n.control-group.error .control-label,\n.control-group.error .help-block,\n.control-group.error .help-inline {\n  color: #b94a48;\n}\n\n.control-group.error .checkbox,\n.control-group.error .radio,\n.control-group.error input,\n.control-group.error select,\n.control-group.error textarea {\n  color: #b94a48;\n}\n\n.control-group.error input,\n.control-group.error select,\n.control-group.error textarea {\n  border-color: #b94a48;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n     -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n\n.control-group.error input:focus,\n.control-group.error select:focus,\n.control-group.error textarea:focus {\n  border-color: #953b39;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392;\n     -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392;\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392;\n}\n\n.control-group.error .input-prepend .add-on,\n.control-group.error .input-append .add-on {\n  color: #b94a48;\n  background-color: #f2dede;\n  border-color: #b94a48;\n}\n\n.control-group.success .control-label,\n.control-group.success .help-block,\n.control-group.success .help-inline {\n  color: #468847;\n}\n\n.control-group.success .checkbox,\n.control-group.success .radio,\n.control-group.success input,\n.control-group.success select,\n.control-group.success textarea {\n  color: #468847;\n}\n\n.control-group.success input,\n.control-group.success select,\n.control-group.success textarea {\n  border-color: #468847;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n     -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n\n.control-group.success input:focus,\n.control-group.success select:focus,\n.control-group.success textarea:focus {\n  border-color: #356635;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b;\n     -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b;\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b;\n}\n\n.control-group.success .input-prepend .add-on,\n.control-group.success .input-append .add-on {\n  color: #468847;\n  background-color: #dff0d8;\n  border-color: #468847;\n}\n\n.control-group.info .control-label,\n.control-group.info .help-block,\n.control-group.info .help-inline {\n  color: #3a87ad;\n}\n\n.control-group.info .checkbox,\n.control-group.info .radio,\n.control-group.info input,\n.control-group.info select,\n.control-group.info textarea {\n  color: #3a87ad;\n}\n\n.control-group.info input,\n.control-group.info select,\n.control-group.info textarea {\n  border-color: #3a87ad;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n     -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n\n.control-group.info input:focus,\n.control-group.info select:focus,\n.control-group.info textarea:focus {\n  border-color: #2d6987;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3;\n     -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3;\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3;\n}\n\n.control-group.info .input-prepend .add-on,\n.control-group.info .input-append .add-on {\n  color: #3a87ad;\n  background-color: #d9edf7;\n  border-color: #3a87ad;\n}\n\ninput:focus:invalid,\ntextarea:focus:invalid,\nselect:focus:invalid {\n  color: #b94a48;\n  border-color: #ee5f5b;\n}\n\ninput:focus:invalid:focus,\ntextarea:focus:invalid:focus,\nselect:focus:invalid:focus {\n  border-color: #e9322d;\n  -webkit-box-shadow: 0 0 6px #f8b9b7;\n     -moz-box-shadow: 0 0 6px #f8b9b7;\n          box-shadow: 0 0 6px #f8b9b7;\n}\n\n.form-actions {\n  padding: 19px 20px 20px;\n  margin-top: 20px;\n  margin-bottom: 20px;\n  background-color: #f5f5f5;\n  border-top: 1px solid #e5e5e5;\n  *zoom: 1;\n}\n\n.form-actions:before,\n.form-actions:after {\n  display: table;\n  line-height: 0;\n  content: \"\";\n}\n\n.form-actions:after {\n  clear: both;\n}\n\n.help-block,\n.help-inline {\n  color: #595959;\n}\n\n.help-block {\n  display: block;\n  margin-bottom: 10px;\n}\n\n.help-inline {\n  display: inline-block;\n  *display: inline;\n  padding-left: 5px;\n  vertical-align: middle;\n  *zoom: 1;\n}\n\n.input-append,\n.input-prepend {\n  display: inline-block;\n  margin-bottom: 10px;\n  font-size: 0;\n  white-space: nowrap;\n  vertical-align: middle;\n}\n\n.input-append input,\n.input-prepend input,\n.input-append select,\n.input-prepend select,\n.input-append .uneditable-input,\n.input-prepend .uneditable-input,\n.input-append .dropdown-menu,\n.input-prepend .dropdown-menu,\n.input-append .popover,\n.input-prepend .popover {\n  font-size: 14px;\n}\n\n.input-append input,\n.input-prepend input,\n.input-append select,\n.input-prepend select,\n.input-append .uneditable-input,\n.input-prepend .uneditable-input {\n  position: relative;\n  margin-bottom: 0;\n  *margin-left: 0;\n  vertical-align: top;\n  -webkit-border-radius: 0 4px 4px 0;\n     -moz-border-radius: 0 4px 4px 0;\n          border-radius: 0 4px 4px 0;\n}\n\n.input-append input:focus,\n.input-prepend input:focus,\n.input-append select:focus,\n.input-prepend select:focus,\n.input-append .uneditable-input:focus,\n.input-prepend .uneditable-input:focus {\n  z-index: 2;\n}\n\n.input-append .add-on,\n.input-prepend .add-on {\n  display: inline-block;\n  width: auto;\n  height: 20px;\n  min-width: 16px;\n  padding: 4px 5px;\n  font-size: 14px;\n  font-weight: normal;\n  line-height: 20px;\n  text-align: center;\n  text-shadow: 0 1px 0 #ffffff;\n  background-color: #eeeeee;\n  border: 1px solid #ccc;\n}\n\n.input-append .add-on,\n.input-prepend .add-on,\n.input-append .btn,\n.input-prepend .btn,\n.input-append .btn-group > .dropdown-toggle,\n.input-prepend .btn-group > .dropdown-toggle {\n  vertical-align: top;\n  -webkit-border-radius: 0;\n     -moz-border-radius: 0;\n          border-radius: 0;\n}\n\n.input-append .active,\n.input-prepend .active {\n  background-color: #a9dba9;\n  border-color: #46a546;\n}\n\n.input-prepend .add-on,\n.input-prepend .btn {\n  margin-right: -1px;\n}\n\n.input-prepend .add-on:first-child,\n.input-prepend .btn:first-child {\n  -webkit-border-radius: 4px 0 0 4px;\n     -moz-border-radius: 4px 0 0 4px;\n          border-radius: 4px 0 0 4px;\n}\n\n.input-append input,\n.input-append select,\n.input-append .uneditable-input {\n  -webkit-border-radius: 4px 0 0 4px;\n     -moz-border-radius: 4px 0 0 4px;\n          border-radius: 4px 0 0 4px;\n}\n\n.input-append input + .btn-group .btn:last-child,\n.input-append select + .btn-group .btn:last-child,\n.input-append .uneditable-input + .btn-group .btn:last-child {\n  -webkit-border-radius: 0 4px 4px 0;\n     -moz-border-radius: 0 4px 4px 0;\n          border-radius: 0 4px 4px 0;\n}\n\n.input-append .add-on,\n.input-append .btn,\n.input-append .btn-group {\n  margin-left: -1px;\n}\n\n.input-append .add-on:last-child,\n.input-append .btn:last-child,\n.input-append .btn-group:last-child > .dropdown-toggle {\n  -webkit-border-radius: 0 4px 4px 0;\n     -moz-border-radius: 0 4px 4px 0;\n          border-radius: 0 4px 4px 0;\n}\n\n.input-prepend.input-append input,\n.input-prepend.input-append select,\n.input-prepend.input-append .uneditable-input {\n  -webkit-border-radius: 0;\n     -moz-border-radius: 0;\n          border-radius: 0;\n}\n\n.input-prepend.input-append input + .btn-group .btn,\n.input-prepend.input-append select + .btn-group .btn,\n.input-prepend.input-append .uneditable-input + .btn-group .btn {\n  -webkit-border-radius: 0 4px 4px 0;\n     -moz-border-radius: 0 4px 4px 0;\n          border-radius: 0 4px 4px 0;\n}\n\n.input-prepend.input-append .add-on:first-child,\n.input-prepend.input-append .btn:first-child {\n  margin-right: -1px;\n  -webkit-border-radius: 4px 0 0 4px;\n     -moz-border-radius: 4px 0 0 4px;\n          border-radius: 4px 0 0 4px;\n}\n\n.input-prepend.input-append .add-on:last-child,\n.input-prepend.input-append .btn:last-child {\n  margin-left: -1px;\n  -webkit-border-radius: 0 4px 4px 0;\n     -moz-border-radius: 0 4px 4px 0;\n          border-radius: 0 4px 4px 0;\n}\n\n.input-prepend.input-append .btn-group:first-child {\n  margin-left: 0;\n}\n\ninput.search-query {\n  padding-right: 14px;\n  padding-right: 4px \\9;\n  padding-left: 14px;\n  padding-left: 4px \\9;\n  /* IE7-8 doesn't have border-radius, so don't indent the padding */\n\n  margin-bottom: 0;\n  -webkit-border-radius: 15px;\n     -moz-border-radius: 15px;\n          border-radius: 15px;\n}\n\n/* Allow for input prepend/append in search forms */\n\n.form-search .input-append .search-query,\n.form-search .input-prepend .search-query {\n  -webkit-border-radius: 0;\n     -moz-border-radius: 0;\n          border-radius: 0;\n}\n\n.form-search .input-append .search-query {\n  -webkit-border-radius: 14px 0 0 14px;\n     -moz-border-radius: 14px 0 0 14px;\n          border-radius: 14px 0 0 14px;\n}\n\n.form-search .input-append .btn {\n  -webkit-border-radius: 0 14px 14px 0;\n     -moz-border-radius: 0 14px 14px 0;\n          border-radius: 0 14px 14px 0;\n}\n\n.form-search .input-prepend .search-query {\n  -webkit-border-radius: 0 14px 14px 0;\n     -moz-border-radius: 0 14px 14px 0;\n          border-radius: 0 14px 14px 0;\n}\n\n.form-search .input-prepend .btn {\n  -webkit-border-radius: 14px 0 0 14px;\n     -moz-border-radius: 14px 0 0 14px;\n          border-radius: 14px 0 0 14px;\n}\n\n.form-search input,\n.form-inline input,\n.form-horizontal input,\n.form-search textarea,\n.form-inline textarea,\n.form-horizontal textarea,\n.form-search select,\n.form-inline select,\n.form-horizontal select,\n.form-search .help-inline,\n.form-inline .help-inline,\n.form-horizontal .help-inline,\n.form-search .uneditable-input,\n.form-inline .uneditable-input,\n.form-horizontal .uneditable-input,\n.form-search .input-prepend,\n.form-inline .input-prepend,\n.form-horizontal .input-prepend,\n.form-search .input-append,\n.form-inline .input-append,\n.form-horizontal .input-append {\n  display: inline-block;\n  *display: inline;\n  margin-bottom: 0;\n  vertical-align: middle;\n  *zoom: 1;\n}\n\n.form-search .hide,\n.form-inline .hide,\n.form-horizontal .hide {\n  display: none;\n}\n\n.form-search label,\n.form-inline label,\n.form-search .btn-group,\n.form-inline .btn-group {\n  display: inline-block;\n}\n\n.form-search .input-append,\n.form-inline .input-append,\n.form-search .input-prepend,\n.form-inline .input-prepend {\n  margin-bottom: 0;\n}\n\n.form-search .radio,\n.form-search .checkbox,\n.form-inline .radio,\n.form-inline .checkbox {\n  padding-left: 0;\n  margin-bottom: 0;\n  vertical-align: middle;\n}\n\n.form-search .radio input[type=\"radio\"],\n.form-search .checkbox input[type=\"checkbox\"],\n.form-inline .radio input[type=\"radio\"],\n.form-inline .checkbox input[type=\"checkbox\"] {\n  float: left;\n  margin-right: 3px;\n  margin-left: 0;\n}\n\n.control-group {\n  margin-bottom: 10px;\n}\n\nlegend + .control-group {\n  margin-top: 20px;\n  -webkit-margin-top-collapse: separate;\n}\n\n.form-horizontal .control-group {\n  margin-bottom: 20px;\n  *zoom: 1;\n}\n\n.form-horizontal .control-group:before,\n.form-horizontal .control-group:after {\n  display: table;\n  line-height: 0;\n  content: \"\";\n}\n\n.form-horizontal .control-group:after {\n  clear: both;\n}\n\n.form-horizontal .control-label {\n  float: left;\n  width: 160px;\n  padding-top: 5px;\n  text-align: right;\n}\n\n.form-horizontal .controls {\n  *display: inline-block;\n  *padding-left: 20px;\n  margin-left: 180px;\n  *margin-left: 0;\n}\n\n.form-horizontal .controls:first-child {\n  *padding-left: 180px;\n}\n\n.form-horizontal .help-block {\n  margin-bottom: 0;\n}\n\n.form-horizontal input + .help-block,\n.form-horizontal select + .help-block,\n.form-horizontal textarea + .help-block,\n.form-horizontal .uneditable-input + .help-block,\n.form-horizontal .input-prepend + .help-block,\n.form-horizontal .input-append + .help-block {\n  margin-top: 10px;\n}\n\n.form-horizontal .form-actions {\n  padding-left: 180px;\n}\n\ntable {\n  max-width: 100%;\n  background-color: transparent;\n  border-collapse: collapse;\n  border-spacing: 0;\n}\n\n.table {\n  width: 100%;\n  margin-bottom: 20px;\n}\n\n.table th,\n.table td {\n  padding: 8px;\n  line-height: 20px;\n  text-align: left;\n  vertical-align: top;\n  border-top: 1px solid #dddddd;\n}\n\n.table th {\n  font-weight: bold;\n}\n\n.table thead th {\n  vertical-align: bottom;\n}\n\n.table caption + thead tr:first-child th,\n.table caption + thead tr:first-child td,\n.table colgroup + thead tr:first-child th,\n.table colgroup + thead tr:first-child td,\n.table thead:first-child tr:first-child th,\n.table thead:first-child tr:first-child td {\n  border-top: 0;\n}\n\n.table tbody + tbody {\n  border-top: 2px solid #dddddd;\n}\n\n.table .table {\n  background-color: #ffffff;\n}\n\n.table-condensed th,\n.table-condensed td {\n  padding: 4px 5px;\n}\n\n.table-bordered {\n  border: 1px solid #dddddd;\n  border-collapse: separate;\n  *border-collapse: collapse;\n  border-left: 0;\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n}\n\n.table-bordered th,\n.table-bordered td {\n  border-left: 1px solid #dddddd;\n}\n\n.table-bordered caption + thead tr:first-child th,\n.table-bordered caption + tbody tr:first-child th,\n.table-bordered caption + tbody tr:first-child td,\n.table-bordered colgroup + thead tr:first-child th,\n.table-bordered colgroup + tbody tr:first-child th,\n.table-bordered colgroup + tbody tr:first-child td,\n.table-bordered thead:first-child tr:first-child th,\n.table-bordered tbody:first-child tr:first-child th,\n.table-bordered tbody:first-child tr:first-child td {\n  border-top: 0;\n}\n\n.table-bordered thead:first-child tr:first-child > th:first-child,\n.table-bordered tbody:first-child tr:first-child > td:first-child,\n.table-bordered tbody:first-child tr:first-child > th:first-child {\n  -webkit-border-top-left-radius: 4px;\n          border-top-left-radius: 4px;\n  -moz-border-radius-topleft: 4px;\n}\n\n.table-bordered thead:first-child tr:first-child > th:last-child,\n.table-bordered tbody:first-child tr:first-child > td:last-child,\n.table-bordered tbody:first-child tr:first-child > th:last-child {\n  -webkit-border-top-right-radius: 4px;\n          border-top-right-radius: 4px;\n  -moz-border-radius-topright: 4px;\n}\n\n.table-bordered thead:last-child tr:last-child > th:first-child,\n.table-bordered tbody:last-child tr:last-child > td:first-child,\n.table-bordered tbody:last-child tr:last-child > th:first-child,\n.table-bordered tfoot:last-child tr:last-child > td:first-child,\n.table-bordered tfoot:last-child tr:last-child > th:first-child {\n  -webkit-border-bottom-left-radius: 4px;\n          border-bottom-left-radius: 4px;\n  -moz-border-radius-bottomleft: 4px;\n}\n\n.table-bordered thead:last-child tr:last-child > th:last-child,\n.table-bordered tbody:last-child tr:last-child > td:last-child,\n.table-bordered tbody:last-child tr:last-child > th:last-child,\n.table-bordered tfoot:last-child tr:last-child > td:last-child,\n.table-bordered tfoot:last-child tr:last-child > th:last-child {\n  -webkit-border-bottom-right-radius: 4px;\n          border-bottom-right-radius: 4px;\n  -moz-border-radius-bottomright: 4px;\n}\n\n.table-bordered tfoot + tbody:last-child tr:last-child td:first-child {\n  -webkit-border-bottom-left-radius: 0;\n          border-bottom-left-radius: 0;\n  -moz-border-radius-bottomleft: 0;\n}\n\n.table-bordered tfoot + tbody:last-child tr:last-child td:last-child {\n  -webkit-border-bottom-right-radius: 0;\n          border-bottom-right-radius: 0;\n  -moz-border-radius-bottomright: 0;\n}\n\n.table-bordered caption + thead tr:first-child th:first-child,\n.table-bordered caption + tbody tr:first-child td:first-child,\n.table-bordered colgroup + thead tr:first-child th:first-child,\n.table-bordered colgroup + tbody tr:first-child td:first-child {\n  -webkit-border-top-left-radius: 4px;\n          border-top-left-radius: 4px;\n  -moz-border-radius-topleft: 4px;\n}\n\n.table-bordered caption + thead tr:first-child th:last-child,\n.table-bordered caption + tbody tr:first-child td:last-child,\n.table-bordered colgroup + thead tr:first-child th:last-child,\n.table-bordered colgroup + tbody tr:first-child td:last-child {\n  -webkit-border-top-right-radius: 4px;\n          border-top-right-radius: 4px;\n  -moz-border-radius-topright: 4px;\n}\n\n.table-striped tbody > tr:nth-child(odd) > td,\n.table-striped tbody > tr:nth-child(odd) > th {\n  background-color: #f9f9f9;\n}\n\n.table-hover tbody tr:hover > td,\n.table-hover tbody tr:hover > th {\n  background-color: #f5f5f5;\n}\n\ntable td[class*=\"span\"],\ntable th[class*=\"span\"],\n.row-fluid table td[class*=\"span\"],\n.row-fluid table th[class*=\"span\"] {\n  display: table-cell;\n  float: none;\n  margin-left: 0;\n}\n\n.table td.span1,\n.table th.span1 {\n  float: none;\n  width: 44px;\n  margin-left: 0;\n}\n\n.table td.span2,\n.table th.span2 {\n  float: none;\n  width: 124px;\n  margin-left: 0;\n}\n\n.table td.span3,\n.table th.span3 {\n  float: none;\n  width: 204px;\n  margin-left: 0;\n}\n\n.table td.span4,\n.table th.span4 {\n  float: none;\n  width: 284px;\n  margin-left: 0;\n}\n\n.table td.span5,\n.table th.span5 {\n  float: none;\n  width: 364px;\n  margin-left: 0;\n}\n\n.table td.span6,\n.table th.span6 {\n  float: none;\n  width: 444px;\n  margin-left: 0;\n}\n\n.table td.span7,\n.table th.span7 {\n  float: none;\n  width: 524px;\n  margin-left: 0;\n}\n\n.table td.span8,\n.table th.span8 {\n  float: none;\n  width: 604px;\n  margin-left: 0;\n}\n\n.table td.span9,\n.table th.span9 {\n  float: none;\n  width: 684px;\n  margin-left: 0;\n}\n\n.table td.span10,\n.table th.span10 {\n  float: none;\n  width: 764px;\n  margin-left: 0;\n}\n\n.table td.span11,\n.table th.span11 {\n  float: none;\n  width: 844px;\n  margin-left: 0;\n}\n\n.table td.span12,\n.table th.span12 {\n  float: none;\n  width: 924px;\n  margin-left: 0;\n}\n\n.table tbody tr.success > td {\n  background-color: #dff0d8;\n}\n\n.table tbody tr.error > td {\n  background-color: #f2dede;\n}\n\n.table tbody tr.warning > td {\n  background-color: #fcf8e3;\n}\n\n.table tbody tr.info > td {\n  background-color: #d9edf7;\n}\n\n.table-hover tbody tr.success:hover > td {\n  background-color: #d0e9c6;\n}\n\n.table-hover tbody tr.error:hover > td {\n  background-color: #ebcccc;\n}\n\n.table-hover tbody tr.warning:hover > td {\n  background-color: #faf2cc;\n}\n\n.table-hover tbody tr.info:hover > td {\n  background-color: #c4e3f3;\n}\n\n[class^=\"icon-\"],\n[class*=\" icon-\"] {\n  display: inline-block;\n  width: 14px;\n  height: 14px;\n  margin-top: 1px;\n  *margin-right: .3em;\n  line-height: 14px;\n  vertical-align: text-top;\n  background-image: url(\"../img/glyphicons-halflings.png\");\n  background-position: 14px 14px;\n  background-repeat: no-repeat;\n}\n\n/* White icons with optional class, or on hover/focus/active states of certain elements */\n\n.icon-white,\n.nav-pills > .active > a > [class^=\"icon-\"],\n.nav-pills > .active > a > [class*=\" icon-\"],\n.nav-list > .active > a > [class^=\"icon-\"],\n.nav-list > .active > a > [class*=\" icon-\"],\n.navbar-inverse .nav > .active > a > [class^=\"icon-\"],\n.navbar-inverse .nav > .active > a > [class*=\" icon-\"],\n.dropdown-menu > li > a:hover > [class^=\"icon-\"],\n.dropdown-menu > li > a:focus > [class^=\"icon-\"],\n.dropdown-menu > li > a:hover > [class*=\" icon-\"],\n.dropdown-menu > li > a:focus > [class*=\" icon-\"],\n.dropdown-menu > .active > a > [class^=\"icon-\"],\n.dropdown-menu > .active > a > [class*=\" icon-\"],\n.dropdown-submenu:hover > a > [class^=\"icon-\"],\n.dropdown-submenu:focus > a > [class^=\"icon-\"],\n.dropdown-submenu:hover > a > [class*=\" icon-\"],\n.dropdown-submenu:focus > a > [class*=\" icon-\"] {\n  background-image: url(\"../img/glyphicons-halflings-white.png\");\n}\n\n.icon-glass {\n  background-position: 0      0;\n}\n\n.icon-music {\n  background-position: -24px 0;\n}\n\n.icon-search {\n  background-position: -48px 0;\n}\n\n.icon-envelope {\n  background-position: -72px 0;\n}\n\n.icon-heart {\n  background-position: -96px 0;\n}\n\n.icon-star {\n  background-position: -120px 0;\n}\n\n.icon-star-empty {\n  background-position: -144px 0;\n}\n\n.icon-user {\n  background-position: -168px 0;\n}\n\n.icon-film {\n  background-position: -192px 0;\n}\n\n.icon-th-large {\n  background-position: -216px 0;\n}\n\n.icon-th {\n  background-position: -240px 0;\n}\n\n.icon-th-list {\n  background-position: -264px 0;\n}\n\n.icon-ok {\n  background-position: -288px 0;\n}\n\n.icon-remove {\n  background-position: -312px 0;\n}\n\n.icon-zoom-in {\n  background-position: -336px 0;\n}\n\n.icon-zoom-out {\n  background-position: -360px 0;\n}\n\n.icon-off {\n  background-position: -384px 0;\n}\n\n.icon-signal {\n  background-position: -408px 0;\n}\n\n.icon-cog {\n  background-position: -432px 0;\n}\n\n.icon-trash {\n  background-position: -456px 0;\n}\n\n.icon-home {\n  background-position: 0 -24px;\n}\n\n.icon-file {\n  background-position: -24px -24px;\n}\n\n.icon-time {\n  background-position: -48px -24px;\n}\n\n.icon-road {\n  background-position: -72px -24px;\n}\n\n.icon-download-alt {\n  background-position: -96px -24px;\n}\n\n.icon-download {\n  background-position: -120px -24px;\n}\n\n.icon-upload {\n  background-position: -144px -24px;\n}\n\n.icon-inbox {\n  background-position: -168px -24px;\n}\n\n.icon-play-circle {\n  background-position: -192px -24px;\n}\n\n.icon-repeat {\n  background-position: -216px -24px;\n}\n\n.icon-refresh {\n  background-position: -240px -24px;\n}\n\n.icon-list-alt {\n  background-position: -264px -24px;\n}\n\n.icon-lock {\n  background-position: -287px -24px;\n}\n\n.icon-flag {\n  background-position: -312px -24px;\n}\n\n.icon-headphones {\n  background-position: -336px -24px;\n}\n\n.icon-volume-off {\n  background-position: -360px -24px;\n}\n\n.icon-volume-down {\n  background-position: -384px -24px;\n}\n\n.icon-volume-up {\n  background-position: -408px -24px;\n}\n\n.icon-qrcode {\n  background-position: -432px -24px;\n}\n\n.icon-barcode {\n  background-position: -456px -24px;\n}\n\n.icon-tag {\n  background-position: 0 -48px;\n}\n\n.icon-tags {\n  background-position: -25px -48px;\n}\n\n.icon-book {\n  background-position: -48px -48px;\n}\n\n.icon-bookmark {\n  background-position: -72px -48px;\n}\n\n.icon-print {\n  background-position: -96px -48px;\n}\n\n.icon-camera {\n  background-position: -120px -48px;\n}\n\n.icon-font {\n  background-position: -144px -48px;\n}\n\n.icon-bold {\n  background-position: -167px -48px;\n}\n\n.icon-italic {\n  background-position: -192px -48px;\n}\n\n.icon-text-height {\n  background-position: -216px -48px;\n}\n\n.icon-text-width {\n  background-position: -240px -48px;\n}\n\n.icon-align-left {\n  background-position: -264px -48px;\n}\n\n.icon-align-center {\n  background-position: -288px -48px;\n}\n\n.icon-align-right {\n  background-position: -312px -48px;\n}\n\n.icon-align-justify {\n  background-position: -336px -48px;\n}\n\n.icon-list {\n  background-position: -360px -48px;\n}\n\n.icon-indent-left {\n  background-position: -384px -48px;\n}\n\n.icon-indent-right {\n  background-position: -408px -48px;\n}\n\n.icon-facetime-video {\n  background-position: -432px -48px;\n}\n\n.icon-picture {\n  background-position: -456px -48px;\n}\n\n.icon-pencil {\n  background-position: 0 -72px;\n}\n\n.icon-map-marker {\n  background-position: -24px -72px;\n}\n\n.icon-adjust {\n  background-position: -48px -72px;\n}\n\n.icon-tint {\n  background-position: -72px -72px;\n}\n\n.icon-edit {\n  background-position: -96px -72px;\n}\n\n.icon-share {\n  background-position: -120px -72px;\n}\n\n.icon-check {\n  background-position: -144px -72px;\n}\n\n.icon-move {\n  background-position: -168px -72px;\n}\n\n.icon-step-backward {\n  background-position: -192px -72px;\n}\n\n.icon-fast-backward {\n  background-position: -216px -72px;\n}\n\n.icon-backward {\n  background-position: -240px -72px;\n}\n\n.icon-play {\n  background-position: -264px -72px;\n}\n\n.icon-pause {\n  background-position: -288px -72px;\n}\n\n.icon-stop {\n  background-position: -312px -72px;\n}\n\n.icon-forward {\n  background-position: -336px -72px;\n}\n\n.icon-fast-forward {\n  background-position: -360px -72px;\n}\n\n.icon-step-forward {\n  background-position: -384px -72px;\n}\n\n.icon-eject {\n  background-position: -408px -72px;\n}\n\n.icon-chevron-left {\n  background-position: -432px -72px;\n}\n\n.icon-chevron-right {\n  background-position: -456px -72px;\n}\n\n.icon-plus-sign {\n  background-position: 0 -96px;\n}\n\n.icon-minus-sign {\n  background-position: -24px -96px;\n}\n\n.icon-remove-sign {\n  background-position: -48px -96px;\n}\n\n.icon-ok-sign {\n  background-position: -72px -96px;\n}\n\n.icon-question-sign {\n  background-position: -96px -96px;\n}\n\n.icon-info-sign {\n  background-position: -120px -96px;\n}\n\n.icon-screenshot {\n  background-position: -144px -96px;\n}\n\n.icon-remove-circle {\n  background-position: -168px -96px;\n}\n\n.icon-ok-circle {\n  background-position: -192px -96px;\n}\n\n.icon-ban-circle {\n  background-position: -216px -96px;\n}\n\n.icon-arrow-left {\n  background-position: -240px -96px;\n}\n\n.icon-arrow-right {\n  background-position: -264px -96px;\n}\n\n.icon-arrow-up {\n  background-position: -289px -96px;\n}\n\n.icon-arrow-down {\n  background-position: -312px -96px;\n}\n\n.icon-share-alt {\n  background-position: -336px -96px;\n}\n\n.icon-resize-full {\n  background-position: -360px -96px;\n}\n\n.icon-resize-small {\n  background-position: -384px -96px;\n}\n\n.icon-plus {\n  background-position: -408px -96px;\n}\n\n.icon-minus {\n  background-position: -433px -96px;\n}\n\n.icon-asterisk {\n  background-position: -456px -96px;\n}\n\n.icon-exclamation-sign {\n  background-position: 0 -120px;\n}\n\n.icon-gift {\n  background-position: -24px -120px;\n}\n\n.icon-leaf {\n  background-position: -48px -120px;\n}\n\n.icon-fire {\n  background-position: -72px -120px;\n}\n\n.icon-eye-open {\n  background-position: -96px -120px;\n}\n\n.icon-eye-close {\n  background-position: -120px -120px;\n}\n\n.icon-warning-sign {\n  background-position: -144px -120px;\n}\n\n.icon-plane {\n  background-position: -168px -120px;\n}\n\n.icon-calendar {\n  background-position: -192px -120px;\n}\n\n.icon-random {\n  width: 16px;\n  background-position: -216px -120px;\n}\n\n.icon-comment {\n  background-position: -240px -120px;\n}\n\n.icon-magnet {\n  background-position: -264px -120px;\n}\n\n.icon-chevron-up {\n  background-position: -288px -120px;\n}\n\n.icon-chevron-down {\n  background-position: -313px -119px;\n}\n\n.icon-retweet {\n  background-position: -336px -120px;\n}\n\n.icon-shopping-cart {\n  background-position: -360px -120px;\n}\n\n.icon-folder-close {\n  width: 16px;\n  background-position: -384px -120px;\n}\n\n.icon-folder-open {\n  width: 16px;\n  background-position: -408px -120px;\n}\n\n.icon-resize-vertical {\n  background-position: -432px -119px;\n}\n\n.icon-resize-horizontal {\n  background-position: -456px -118px;\n}\n\n.icon-hdd {\n  background-position: 0 -144px;\n}\n\n.icon-bullhorn {\n  background-position: -24px -144px;\n}\n\n.icon-bell {\n  background-position: -48px -144px;\n}\n\n.icon-certificate {\n  background-position: -72px -144px;\n}\n\n.icon-thumbs-up {\n  background-position: -96px -144px;\n}\n\n.icon-thumbs-down {\n  background-position: -120px -144px;\n}\n\n.icon-hand-right {\n  background-position: -144px -144px;\n}\n\n.icon-hand-left {\n  background-position: -168px -144px;\n}\n\n.icon-hand-up {\n  background-position: -192px -144px;\n}\n\n.icon-hand-down {\n  background-position: -216px -144px;\n}\n\n.icon-circle-arrow-right {\n  background-position: -240px -144px;\n}\n\n.icon-circle-arrow-left {\n  background-position: -264px -144px;\n}\n\n.icon-circle-arrow-up {\n  background-position: -288px -144px;\n}\n\n.icon-circle-arrow-down {\n  background-position: -312px -144px;\n}\n\n.icon-globe {\n  background-position: -336px -144px;\n}\n\n.icon-wrench {\n  background-position: -360px -144px;\n}\n\n.icon-tasks {\n  background-position: -384px -144px;\n}\n\n.icon-filter {\n  background-position: -408px -144px;\n}\n\n.icon-briefcase {\n  background-position: -432px -144px;\n}\n\n.icon-fullscreen {\n  background-position: -456px -144px;\n}\n\n.dropup,\n.dropdown {\n  position: relative;\n}\n\n.dropdown-toggle {\n  *margin-bottom: -3px;\n}\n\n.dropdown-toggle:active,\n.open .dropdown-toggle {\n  outline: 0;\n}\n\n.caret {\n  display: inline-block;\n  width: 0;\n  height: 0;\n  vertical-align: top;\n  border-top: 4px solid #000000;\n  border-right: 4px solid transparent;\n  border-left: 4px solid transparent;\n  content: \"\";\n}\n\n.dropdown .caret {\n  margin-top: 8px;\n  margin-left: 2px;\n}\n\n.dropdown-menu {\n  position: absolute;\n  top: 100%;\n  left: 0;\n  z-index: 1000;\n  display: none;\n  float: left;\n  min-width: 160px;\n  padding: 5px 0;\n  margin: 2px 0 0;\n  list-style: none;\n  background-color: #ffffff;\n  border: 1px solid #ccc;\n  border: 1px solid rgba(0, 0, 0, 0.2);\n  *border-right-width: 2px;\n  *border-bottom-width: 2px;\n  -webkit-border-radius: 6px;\n     -moz-border-radius: 6px;\n          border-radius: 6px;\n  -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n     -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n          box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n  -webkit-background-clip: padding-box;\n     -moz-background-clip: padding;\n          background-clip: padding-box;\n}\n\n.dropdown-menu.pull-right {\n  right: 0;\n  left: auto;\n}\n\n.dropdown-menu .divider {\n  *width: 100%;\n  height: 1px;\n  margin: 9px 1px;\n  *margin: -5px 0 5px;\n  overflow: hidden;\n  background-color: #e5e5e5;\n  border-bottom: 1px solid #ffffff;\n}\n\n.dropdown-menu > li > a {\n  display: block;\n  padding: 3px 20px;\n  clear: both;\n  font-weight: normal;\n  line-height: 20px;\n  color: #333333;\n  white-space: nowrap;\n}\n\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus,\n.dropdown-submenu:hover > a,\n.dropdown-submenu:focus > a {\n  color: #ffffff;\n  text-decoration: none;\n  background-color: #0081c2;\n  background-image: -moz-linear-gradient(top, #0088cc, #0077b3);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3));\n  background-image: -webkit-linear-gradient(top, #0088cc, #0077b3);\n  background-image: -o-linear-gradient(top, #0088cc, #0077b3);\n  background-image: linear-gradient(to bottom, #0088cc, #0077b3);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0);\n}\n\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n  color: #ffffff;\n  text-decoration: none;\n  background-color: #0081c2;\n  background-image: -moz-linear-gradient(top, #0088cc, #0077b3);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3));\n  background-image: -webkit-linear-gradient(top, #0088cc, #0077b3);\n  background-image: -o-linear-gradient(top, #0088cc, #0077b3);\n  background-image: linear-gradient(to bottom, #0088cc, #0077b3);\n  background-repeat: repeat-x;\n  outline: 0;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0);\n}\n\n.dropdown-menu > .disabled > a,\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n  color: #999999;\n}\n\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n  text-decoration: none;\n  cursor: default;\n  background-color: transparent;\n  background-image: none;\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);\n}\n\n.open {\n  *z-index: 1000;\n}\n\n.open > .dropdown-menu {\n  display: block;\n}\n\n.pull-right > .dropdown-menu {\n  right: 0;\n  left: auto;\n}\n\n.dropup .caret,\n.navbar-fixed-bottom .dropdown .caret {\n  border-top: 0;\n  border-bottom: 4px solid #000000;\n  content: \"\";\n}\n\n.dropup .dropdown-menu,\n.navbar-fixed-bottom .dropdown .dropdown-menu {\n  top: auto;\n  bottom: 100%;\n  margin-bottom: 1px;\n}\n\n.dropdown-submenu {\n  position: relative;\n}\n\n.dropdown-submenu > .dropdown-menu {\n  top: 0;\n  left: 100%;\n  margin-top: -6px;\n  margin-left: -1px;\n  -webkit-border-radius: 0 6px 6px 6px;\n     -moz-border-radius: 0 6px 6px 6px;\n          border-radius: 0 6px 6px 6px;\n}\n\n.dropdown-submenu:hover > .dropdown-menu {\n  display: block;\n}\n\n.dropup .dropdown-submenu > .dropdown-menu {\n  top: auto;\n  bottom: 0;\n  margin-top: 0;\n  margin-bottom: -2px;\n  -webkit-border-radius: 5px 5px 5px 0;\n     -moz-border-radius: 5px 5px 5px 0;\n          border-radius: 5px 5px 5px 0;\n}\n\n.dropdown-submenu > a:after {\n  display: block;\n  float: right;\n  width: 0;\n  height: 0;\n  margin-top: 5px;\n  margin-right: -10px;\n  border-color: transparent;\n  border-left-color: #cccccc;\n  border-style: solid;\n  border-width: 5px 0 5px 5px;\n  content: \" \";\n}\n\n.dropdown-submenu:hover > a:after {\n  border-left-color: #ffffff;\n}\n\n.dropdown-submenu.pull-left {\n  float: none;\n}\n\n.dropdown-submenu.pull-left > .dropdown-menu {\n  left: -100%;\n  margin-left: 10px;\n  -webkit-border-radius: 6px 0 6px 6px;\n     -moz-border-radius: 6px 0 6px 6px;\n          border-radius: 6px 0 6px 6px;\n}\n\n.dropdown .dropdown-menu .nav-header {\n  padding-right: 20px;\n  padding-left: 20px;\n}\n\n.typeahead {\n  z-index: 1051;\n  margin-top: 2px;\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n}\n\n.well {\n  min-height: 20px;\n  padding: 19px;\n  margin-bottom: 20px;\n  background-color: #f5f5f5;\n  border: 1px solid #e3e3e3;\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n     -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n}\n\n.well blockquote {\n  border-color: #ddd;\n  border-color: rgba(0, 0, 0, 0.15);\n}\n\n.well-large {\n  padding: 24px;\n  -webkit-border-radius: 6px;\n     -moz-border-radius: 6px;\n          border-radius: 6px;\n}\n\n.well-small {\n  padding: 9px;\n  -webkit-border-radius: 3px;\n     -moz-border-radius: 3px;\n          border-radius: 3px;\n}\n\n.fade {\n  opacity: 0;\n  -webkit-transition: opacity 0.15s linear;\n     -moz-transition: opacity 0.15s linear;\n       -o-transition: opacity 0.15s linear;\n          transition: opacity 0.15s linear;\n}\n\n.fade.in {\n  opacity: 1;\n}\n\n.collapse {\n  position: relative;\n  height: 0;\n  overflow: hidden;\n  -webkit-transition: height 0.35s ease;\n     -moz-transition: height 0.35s ease;\n       -o-transition: height 0.35s ease;\n          transition: height 0.35s ease;\n}\n\n.collapse.in {\n  height: auto;\n}\n\n.close {\n  float: right;\n  font-size: 20px;\n  font-weight: bold;\n  line-height: 20px;\n  color: #000000;\n  text-shadow: 0 1px 0 #ffffff;\n  opacity: 0.2;\n  filter: alpha(opacity=20);\n}\n\n.close:hover,\n.close:focus {\n  color: #000000;\n  text-decoration: none;\n  cursor: pointer;\n  opacity: 0.4;\n  filter: alpha(opacity=40);\n}\n\nbutton.close {\n  padding: 0;\n  cursor: pointer;\n  background: transparent;\n  border: 0;\n  -webkit-appearance: none;\n}\n\n.btn {\n  display: inline-block;\n  *display: inline;\n  padding: 4px 12px;\n  margin-bottom: 0;\n  *margin-left: .3em;\n  font-size: 14px;\n  line-height: 20px;\n  color: #333333;\n  text-align: center;\n  text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);\n  vertical-align: middle;\n  cursor: pointer;\n  background-color: #f5f5f5;\n  *background-color: #e6e6e6;\n  background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));\n  background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6);\n  background-image: -o-linear-gradient(top, #ffffff, #e6e6e6);\n  background-image: linear-gradient(to bottom, #ffffff, #e6e6e6);\n  background-repeat: repeat-x;\n  border: 1px solid #cccccc;\n  *border: 0;\n  border-color: #e6e6e6 #e6e6e6 #bfbfbf;\n  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n  border-bottom-color: #b3b3b3;\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);\n  *zoom: 1;\n  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);\n     -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);\n          box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n\n.btn:hover,\n.btn:focus,\n.btn:active,\n.btn.active,\n.btn.disabled,\n.btn[disabled] {\n  color: #333333;\n  background-color: #e6e6e6;\n  *background-color: #d9d9d9;\n}\n\n.btn:active,\n.btn.active {\n  background-color: #cccccc \\9;\n}\n\n.btn:first-child {\n  *margin-left: 0;\n}\n\n.btn:hover,\n.btn:focus {\n  color: #333333;\n  text-decoration: none;\n  background-position: 0 -15px;\n  -webkit-transition: background-position 0.1s linear;\n     -moz-transition: background-position 0.1s linear;\n       -o-transition: background-position 0.1s linear;\n          transition: background-position 0.1s linear;\n}\n\n.btn:focus {\n  outline: thin dotted #333;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\n\n.btn.active,\n.btn:active {\n  background-image: none;\n  outline: 0;\n  -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);\n     -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);\n          box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n\n.btn.disabled,\n.btn[disabled] {\n  cursor: default;\n  background-image: none;\n  opacity: 0.65;\n  filter: alpha(opacity=65);\n  -webkit-box-shadow: none;\n     -moz-box-shadow: none;\n          box-shadow: none;\n}\n\n.btn-large {\n  padding: 11px 19px;\n  font-size: 17.5px;\n  -webkit-border-radius: 6px;\n     -moz-border-radius: 6px;\n          border-radius: 6px;\n}\n\n.btn-large [class^=\"icon-\"],\n.btn-large [class*=\" icon-\"] {\n  margin-top: 4px;\n}\n\n.btn-small {\n  padding: 2px 10px;\n  font-size: 11.9px;\n  -webkit-border-radius: 3px;\n     -moz-border-radius: 3px;\n          border-radius: 3px;\n}\n\n.btn-small [class^=\"icon-\"],\n.btn-small [class*=\" icon-\"] {\n  margin-top: 0;\n}\n\n.btn-mini [class^=\"icon-\"],\n.btn-mini [class*=\" icon-\"] {\n  margin-top: -1px;\n}\n\n.btn-mini {\n  padding: 0 6px;\n  font-size: 10.5px;\n  -webkit-border-radius: 3px;\n     -moz-border-radius: 3px;\n          border-radius: 3px;\n}\n\n.btn-block {\n  display: block;\n  width: 100%;\n  padding-right: 0;\n  padding-left: 0;\n  -webkit-box-sizing: border-box;\n     -moz-box-sizing: border-box;\n          box-sizing: border-box;\n}\n\n.btn-block + .btn-block {\n  margin-top: 5px;\n}\n\ninput[type=\"submit\"].btn-block,\ninput[type=\"reset\"].btn-block,\ninput[type=\"button\"].btn-block {\n  width: 100%;\n}\n\n.btn-primary.active,\n.btn-warning.active,\n.btn-danger.active,\n.btn-success.active,\n.btn-info.active,\n.btn-inverse.active {\n  color: rgba(255, 255, 255, 0.75);\n}\n\n.btn-primary {\n  color: #ffffff;\n  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\n  background-color: #006dcc;\n  *background-color: #0044cc;\n  background-image: -moz-linear-gradient(top, #0088cc, #0044cc);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));\n  background-image: -webkit-linear-gradient(top, #0088cc, #0044cc);\n  background-image: -o-linear-gradient(top, #0088cc, #0044cc);\n  background-image: linear-gradient(to bottom, #0088cc, #0044cc);\n  background-repeat: repeat-x;\n  border-color: #0044cc #0044cc #002a80;\n  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);\n}\n\n.btn-primary:hover,\n.btn-primary:focus,\n.btn-primary:active,\n.btn-primary.active,\n.btn-primary.disabled,\n.btn-primary[disabled] {\n  color: #ffffff;\n  background-color: #0044cc;\n  *background-color: #003bb3;\n}\n\n.btn-primary:active,\n.btn-primary.active {\n  background-color: #003399 \\9;\n}\n\n.btn-warning {\n  color: #ffffff;\n  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\n  background-color: #faa732;\n  *background-color: #f89406;\n  background-image: -moz-linear-gradient(top, #fbb450, #f89406);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));\n  background-image: -webkit-linear-gradient(top, #fbb450, #f89406);\n  background-image: -o-linear-gradient(top, #fbb450, #f89406);\n  background-image: linear-gradient(to bottom, #fbb450, #f89406);\n  background-repeat: repeat-x;\n  border-color: #f89406 #f89406 #ad6704;\n  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);\n}\n\n.btn-warning:hover,\n.btn-warning:focus,\n.btn-warning:active,\n.btn-warning.active,\n.btn-warning.disabled,\n.btn-warning[disabled] {\n  color: #ffffff;\n  background-color: #f89406;\n  *background-color: #df8505;\n}\n\n.btn-warning:active,\n.btn-warning.active {\n  background-color: #c67605 \\9;\n}\n\n.btn-danger {\n  color: #ffffff;\n  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\n  background-color: #da4f49;\n  *background-color: #bd362f;\n  background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f));\n  background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f);\n  background-image: -o-linear-gradient(top, #ee5f5b, #bd362f);\n  background-image: linear-gradient(to bottom, #ee5f5b, #bd362f);\n  background-repeat: repeat-x;\n  border-color: #bd362f #bd362f #802420;\n  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffbd362f', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);\n}\n\n.btn-danger:hover,\n.btn-danger:focus,\n.btn-danger:active,\n.btn-danger.active,\n.btn-danger.disabled,\n.btn-danger[disabled] {\n  color: #ffffff;\n  background-color: #bd362f;\n  *background-color: #a9302a;\n}\n\n.btn-danger:active,\n.btn-danger.active {\n  background-color: #942a25 \\9;\n}\n\n.btn-success {\n  color: #ffffff;\n  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\n  background-color: #5bb75b;\n  *background-color: #51a351;\n  background-image: -moz-linear-gradient(top, #62c462, #51a351);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));\n  background-image: -webkit-linear-gradient(top, #62c462, #51a351);\n  background-image: -o-linear-gradient(top, #62c462, #51a351);\n  background-image: linear-gradient(to bottom, #62c462, #51a351);\n  background-repeat: repeat-x;\n  border-color: #51a351 #51a351 #387038;\n  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff51a351', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);\n}\n\n.btn-success:hover,\n.btn-success:focus,\n.btn-success:active,\n.btn-success.active,\n.btn-success.disabled,\n.btn-success[disabled] {\n  color: #ffffff;\n  background-color: #51a351;\n  *background-color: #499249;\n}\n\n.btn-success:active,\n.btn-success.active {\n  background-color: #408140 \\9;\n}\n\n.btn-info {\n  color: #ffffff;\n  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\n  background-color: #49afcd;\n  *background-color: #2f96b4;\n  background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4));\n  background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4);\n  background-image: -o-linear-gradient(top, #5bc0de, #2f96b4);\n  background-image: linear-gradient(to bottom, #5bc0de, #2f96b4);\n  background-repeat: repeat-x;\n  border-color: #2f96b4 #2f96b4 #1f6377;\n  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2f96b4', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);\n}\n\n.btn-info:hover,\n.btn-info:focus,\n.btn-info:active,\n.btn-info.active,\n.btn-info.disabled,\n.btn-info[disabled] {\n  color: #ffffff;\n  background-color: #2f96b4;\n  *background-color: #2a85a0;\n}\n\n.btn-info:active,\n.btn-info.active {\n  background-color: #24748c \\9;\n}\n\n.btn-inverse {\n  color: #ffffff;\n  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\n  background-color: #363636;\n  *background-color: #222222;\n  background-image: -moz-linear-gradient(top, #444444, #222222);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#444444), to(#222222));\n  background-image: -webkit-linear-gradient(top, #444444, #222222);\n  background-image: -o-linear-gradient(top, #444444, #222222);\n  background-image: linear-gradient(to bottom, #444444, #222222);\n  background-repeat: repeat-x;\n  border-color: #222222 #222222 #000000;\n  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff444444', endColorstr='#ff222222', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);\n}\n\n.btn-inverse:hover,\n.btn-inverse:focus,\n.btn-inverse:active,\n.btn-inverse.active,\n.btn-inverse.disabled,\n.btn-inverse[disabled] {\n  color: #ffffff;\n  background-color: #222222;\n  *background-color: #151515;\n}\n\n.btn-inverse:active,\n.btn-inverse.active {\n  background-color: #080808 \\9;\n}\n\nbutton.btn,\ninput[type=\"submit\"].btn {\n  *padding-top: 3px;\n  *padding-bottom: 3px;\n}\n\nbutton.btn::-moz-focus-inner,\ninput[type=\"submit\"].btn::-moz-focus-inner {\n  padding: 0;\n  border: 0;\n}\n\nbutton.btn.btn-large,\ninput[type=\"submit\"].btn.btn-large {\n  *padding-top: 7px;\n  *padding-bottom: 7px;\n}\n\nbutton.btn.btn-small,\ninput[type=\"submit\"].btn.btn-small {\n  *padding-top: 3px;\n  *padding-bottom: 3px;\n}\n\nbutton.btn.btn-mini,\ninput[type=\"submit\"].btn.btn-mini {\n  *padding-top: 1px;\n  *padding-bottom: 1px;\n}\n\n.btn-link,\n.btn-link:active,\n.btn-link[disabled] {\n  background-color: transparent;\n  background-image: none;\n  -webkit-box-shadow: none;\n     -moz-box-shadow: none;\n          box-shadow: none;\n}\n\n.btn-link {\n  color: #0088cc;\n  cursor: pointer;\n  border-color: transparent;\n  -webkit-border-radius: 0;\n     -moz-border-radius: 0;\n          border-radius: 0;\n}\n\n.btn-link:hover,\n.btn-link:focus {\n  color: #005580;\n  text-decoration: underline;\n  background-color: transparent;\n}\n\n.btn-link[disabled]:hover,\n.btn-link[disabled]:focus {\n  color: #333333;\n  text-decoration: none;\n}\n\n.btn-group {\n  position: relative;\n  display: inline-block;\n  *display: inline;\n  *margin-left: .3em;\n  font-size: 0;\n  white-space: nowrap;\n  vertical-align: middle;\n  *zoom: 1;\n}\n\n.btn-group:first-child {\n  *margin-left: 0;\n}\n\n.btn-group + .btn-group {\n  margin-left: 5px;\n}\n\n.btn-toolbar {\n  margin-top: 10px;\n  margin-bottom: 10px;\n  font-size: 0;\n}\n\n.btn-toolbar > .btn + .btn,\n.btn-toolbar > .btn-group + .btn,\n.btn-toolbar > .btn + .btn-group {\n  margin-left: 5px;\n}\n\n.btn-group > .btn {\n  position: relative;\n  -webkit-border-radius: 0;\n     -moz-border-radius: 0;\n          border-radius: 0;\n}\n\n.btn-group > .btn + .btn {\n  margin-left: -1px;\n}\n\n.btn-group > .btn,\n.btn-group > .dropdown-menu,\n.btn-group > .popover {\n  font-size: 14px;\n}\n\n.btn-group > .btn-mini {\n  font-size: 10.5px;\n}\n\n.btn-group > .btn-small {\n  font-size: 11.9px;\n}\n\n.btn-group > .btn-large {\n  font-size: 17.5px;\n}\n\n.btn-group > .btn:first-child {\n  margin-left: 0;\n  -webkit-border-bottom-left-radius: 4px;\n          border-bottom-left-radius: 4px;\n  -webkit-border-top-left-radius: 4px;\n          border-top-left-radius: 4px;\n  -moz-border-radius-bottomleft: 4px;\n  -moz-border-radius-topleft: 4px;\n}\n\n.btn-group > .btn:last-child,\n.btn-group > .dropdown-toggle {\n  -webkit-border-top-right-radius: 4px;\n          border-top-right-radius: 4px;\n  -webkit-border-bottom-right-radius: 4px;\n          border-bottom-right-radius: 4px;\n  -moz-border-radius-topright: 4px;\n  -moz-border-radius-bottomright: 4px;\n}\n\n.btn-group > .btn.large:first-child {\n  margin-left: 0;\n  -webkit-border-bottom-left-radius: 6px;\n          border-bottom-left-radius: 6px;\n  -webkit-border-top-left-radius: 6px;\n          border-top-left-radius: 6px;\n  -moz-border-radius-bottomleft: 6px;\n  -moz-border-radius-topleft: 6px;\n}\n\n.btn-group > .btn.large:last-child,\n.btn-group > .large.dropdown-toggle {\n  -webkit-border-top-right-radius: 6px;\n          border-top-right-radius: 6px;\n  -webkit-border-bottom-right-radius: 6px;\n          border-bottom-right-radius: 6px;\n  -moz-border-radius-topright: 6px;\n  -moz-border-radius-bottomright: 6px;\n}\n\n.btn-group > .btn:hover,\n.btn-group > .btn:focus,\n.btn-group > .btn:active,\n.btn-group > .btn.active {\n  z-index: 2;\n}\n\n.btn-group .dropdown-toggle:active,\n.btn-group.open .dropdown-toggle {\n  outline: 0;\n}\n\n.btn-group > .btn + .dropdown-toggle {\n  *padding-top: 5px;\n  padding-right: 8px;\n  *padding-bottom: 5px;\n  padding-left: 8px;\n  -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);\n     -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);\n          box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n\n.btn-group > .btn-mini + .dropdown-toggle {\n  *padding-top: 2px;\n  padding-right: 5px;\n  *padding-bottom: 2px;\n  padding-left: 5px;\n}\n\n.btn-group > .btn-small + .dropdown-toggle {\n  *padding-top: 5px;\n  *padding-bottom: 4px;\n}\n\n.btn-group > .btn-large + .dropdown-toggle {\n  *padding-top: 7px;\n  padding-right: 12px;\n  *padding-bottom: 7px;\n  padding-left: 12px;\n}\n\n.btn-group.open .dropdown-toggle {\n  background-image: none;\n  -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);\n     -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);\n          box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n\n.btn-group.open .btn.dropdown-toggle {\n  background-color: #e6e6e6;\n}\n\n.btn-group.open .btn-primary.dropdown-toggle {\n  background-color: #0044cc;\n}\n\n.btn-group.open .btn-warning.dropdown-toggle {\n  background-color: #f89406;\n}\n\n.btn-group.open .btn-danger.dropdown-toggle {\n  background-color: #bd362f;\n}\n\n.btn-group.open .btn-success.dropdown-toggle {\n  background-color: #51a351;\n}\n\n.btn-group.open .btn-info.dropdown-toggle {\n  background-color: #2f96b4;\n}\n\n.btn-group.open .btn-inverse.dropdown-toggle {\n  background-color: #222222;\n}\n\n.btn .caret {\n  margin-top: 8px;\n  margin-left: 0;\n}\n\n.btn-large .caret {\n  margin-top: 6px;\n}\n\n.btn-large .caret {\n  border-top-width: 5px;\n  border-right-width: 5px;\n  border-left-width: 5px;\n}\n\n.btn-mini .caret,\n.btn-small .caret {\n  margin-top: 8px;\n}\n\n.dropup .btn-large .caret {\n  border-bottom-width: 5px;\n}\n\n.btn-primary .caret,\n.btn-warning .caret,\n.btn-danger .caret,\n.btn-info .caret,\n.btn-success .caret,\n.btn-inverse .caret {\n  border-top-color: #ffffff;\n  border-bottom-color: #ffffff;\n}\n\n.btn-group-vertical {\n  display: inline-block;\n  *display: inline;\n  /* IE7 inline-block hack */\n\n  *zoom: 1;\n}\n\n.btn-group-vertical > .btn {\n  display: block;\n  float: none;\n  max-width: 100%;\n  -webkit-border-radius: 0;\n     -moz-border-radius: 0;\n          border-radius: 0;\n}\n\n.btn-group-vertical > .btn + .btn {\n  margin-top: -1px;\n  margin-left: 0;\n}\n\n.btn-group-vertical > .btn:first-child {\n  -webkit-border-radius: 4px 4px 0 0;\n     -moz-border-radius: 4px 4px 0 0;\n          border-radius: 4px 4px 0 0;\n}\n\n.btn-group-vertical > .btn:last-child {\n  -webkit-border-radius: 0 0 4px 4px;\n     -moz-border-radius: 0 0 4px 4px;\n          border-radius: 0 0 4px 4px;\n}\n\n.btn-group-vertical > .btn-large:first-child {\n  -webkit-border-radius: 6px 6px 0 0;\n     -moz-border-radius: 6px 6px 0 0;\n          border-radius: 6px 6px 0 0;\n}\n\n.btn-group-vertical > .btn-large:last-child {\n  -webkit-border-radius: 0 0 6px 6px;\n     -moz-border-radius: 0 0 6px 6px;\n          border-radius: 0 0 6px 6px;\n}\n\n.alert {\n  padding: 8px 35px 8px 14px;\n  margin-bottom: 20px;\n  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);\n  background-color: #fcf8e3;\n  border: 1px solid #fbeed5;\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n}\n\n.alert,\n.alert h4 {\n  color: #c09853;\n}\n\n.alert h4 {\n  margin: 0;\n}\n\n.alert .close {\n  position: relative;\n  top: -2px;\n  right: -21px;\n  line-height: 20px;\n}\n\n.alert-success {\n  color: #468847;\n  background-color: #dff0d8;\n  border-color: #d6e9c6;\n}\n\n.alert-success h4 {\n  color: #468847;\n}\n\n.alert-danger,\n.alert-error {\n  color: #b94a48;\n  background-color: #f2dede;\n  border-color: #eed3d7;\n}\n\n.alert-danger h4,\n.alert-error h4 {\n  color: #b94a48;\n}\n\n.alert-info {\n  color: #3a87ad;\n  background-color: #d9edf7;\n  border-color: #bce8f1;\n}\n\n.alert-info h4 {\n  color: #3a87ad;\n}\n\n.alert-block {\n  padding-top: 14px;\n  padding-bottom: 14px;\n}\n\n.alert-block > p,\n.alert-block > ul {\n  margin-bottom: 0;\n}\n\n.alert-block p + p {\n  margin-top: 5px;\n}\n\n.nav {\n  margin-bottom: 20px;\n  margin-left: 0;\n  list-style: none;\n}\n\n.nav > li > a {\n  display: block;\n}\n\n.nav > li > a:hover,\n.nav > li > a:focus {\n  text-decoration: none;\n  background-color: #eeeeee;\n}\n\n.nav > li > a > img {\n  max-width: none;\n}\n\n.nav > .pull-right {\n  float: right;\n}\n\n.nav-header {\n  display: block;\n  padding: 3px 15px;\n  font-size: 11px;\n  font-weight: bold;\n  line-height: 20px;\n  color: #999999;\n  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);\n  text-transform: uppercase;\n}\n\n.nav li + .nav-header {\n  margin-top: 9px;\n}\n\n.nav-list {\n  padding-right: 15px;\n  padding-left: 15px;\n  margin-bottom: 0;\n}\n\n.nav-list > li > a,\n.nav-list .nav-header {\n  margin-right: -15px;\n  margin-left: -15px;\n  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);\n}\n\n.nav-list > li > a {\n  padding: 3px 15px;\n}\n\n.nav-list > .active > a,\n.nav-list > .active > a:hover,\n.nav-list > .active > a:focus {\n  color: #ffffff;\n  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2);\n  background-color: #0088cc;\n}\n\n.nav-list [class^=\"icon-\"],\n.nav-list [class*=\" icon-\"] {\n  margin-right: 2px;\n}\n\n.nav-list .divider {\n  *width: 100%;\n  height: 1px;\n  margin: 9px 1px;\n  *margin: -5px 0 5px;\n  overflow: hidden;\n  background-color: #e5e5e5;\n  border-bottom: 1px solid #ffffff;\n}\n\n.nav-tabs,\n.nav-pills {\n  *zoom: 1;\n}\n\n.nav-tabs:before,\n.nav-pills:before,\n.nav-tabs:after,\n.nav-pills:after {\n  display: table;\n  line-height: 0;\n  content: \"\";\n}\n\n.nav-tabs:after,\n.nav-pills:after {\n  clear: both;\n}\n\n.nav-tabs > li,\n.nav-pills > li {\n  float: left;\n}\n\n.nav-tabs > li > a,\n.nav-pills > li > a {\n  padding-right: 12px;\n  padding-left: 12px;\n  margin-right: 2px;\n  line-height: 14px;\n}\n\n.nav-tabs {\n  border-bottom: 1px solid #ddd;\n}\n\n.nav-tabs > li {\n  margin-bottom: -1px;\n}\n\n.nav-tabs > li > a {\n  padding-top: 8px;\n  padding-bottom: 8px;\n  line-height: 20px;\n  border: 1px solid transparent;\n  -webkit-border-radius: 4px 4px 0 0;\n     -moz-border-radius: 4px 4px 0 0;\n          border-radius: 4px 4px 0 0;\n}\n\n.nav-tabs > li > a:hover,\n.nav-tabs > li > a:focus {\n  border-color: #eeeeee #eeeeee #dddddd;\n}\n\n.nav-tabs > .active > a,\n.nav-tabs > .active > a:hover,\n.nav-tabs > .active > a:focus {\n  color: #555555;\n  cursor: default;\n  background-color: #ffffff;\n  border: 1px solid #ddd;\n  border-bottom-color: transparent;\n}\n\n.nav-pills > li > a {\n  padding-top: 8px;\n  padding-bottom: 8px;\n  margin-top: 2px;\n  margin-bottom: 2px;\n  -webkit-border-radius: 5px;\n     -moz-border-radius: 5px;\n          border-radius: 5px;\n}\n\n.nav-pills > .active > a,\n.nav-pills > .active > a:hover,\n.nav-pills > .active > a:focus {\n  color: #ffffff;\n  background-color: #0088cc;\n}\n\n.nav-stacked > li {\n  float: none;\n}\n\n.nav-stacked > li > a {\n  margin-right: 0;\n}\n\n.nav-tabs.nav-stacked {\n  border-bottom: 0;\n}\n\n.nav-tabs.nav-stacked > li > a {\n  border: 1px solid #ddd;\n  -webkit-border-radius: 0;\n     -moz-border-radius: 0;\n          border-radius: 0;\n}\n\n.nav-tabs.nav-stacked > li:first-child > a {\n  -webkit-border-top-right-radius: 4px;\n          border-top-right-radius: 4px;\n  -webkit-border-top-left-radius: 4px;\n          border-top-left-radius: 4px;\n  -moz-border-radius-topright: 4px;\n  -moz-border-radius-topleft: 4px;\n}\n\n.nav-tabs.nav-stacked > li:last-child > a {\n  -webkit-border-bottom-right-radius: 4px;\n          border-bottom-right-radius: 4px;\n  -webkit-border-bottom-left-radius: 4px;\n          border-bottom-left-radius: 4px;\n  -moz-border-radius-bottomright: 4px;\n  -moz-border-radius-bottomleft: 4px;\n}\n\n.nav-tabs.nav-stacked > li > a:hover,\n.nav-tabs.nav-stacked > li > a:focus {\n  z-index: 2;\n  border-color: #ddd;\n}\n\n.nav-pills.nav-stacked > li > a {\n  margin-bottom: 3px;\n}\n\n.nav-pills.nav-stacked > li:last-child > a {\n  margin-bottom: 1px;\n}\n\n.nav-tabs .dropdown-menu {\n  -webkit-border-radius: 0 0 6px 6px;\n     -moz-border-radius: 0 0 6px 6px;\n          border-radius: 0 0 6px 6px;\n}\n\n.nav-pills .dropdown-menu {\n  -webkit-border-radius: 6px;\n     -moz-border-radius: 6px;\n          border-radius: 6px;\n}\n\n.nav .dropdown-toggle .caret {\n  margin-top: 6px;\n  border-top-color: #0088cc;\n  border-bottom-color: #0088cc;\n}\n\n.nav .dropdown-toggle:hover .caret,\n.nav .dropdown-toggle:focus .caret {\n  border-top-color: #005580;\n  border-bottom-color: #005580;\n}\n\n/* move down carets for tabs */\n\n.nav-tabs .dropdown-toggle .caret {\n  margin-top: 8px;\n}\n\n.nav .active .dropdown-toggle .caret {\n  border-top-color: #fff;\n  border-bottom-color: #fff;\n}\n\n.nav-tabs .active .dropdown-toggle .caret {\n  border-top-color: #555555;\n  border-bottom-color: #555555;\n}\n\n.nav > .dropdown.active > a:hover,\n.nav > .dropdown.active > a:focus {\n  cursor: pointer;\n}\n\n.nav-tabs .open .dropdown-toggle,\n.nav-pills .open .dropdown-toggle,\n.nav > li.dropdown.open.active > a:hover,\n.nav > li.dropdown.open.active > a:focus {\n  color: #ffffff;\n  background-color: #999999;\n  border-color: #999999;\n}\n\n.nav li.dropdown.open .caret,\n.nav li.dropdown.open.active .caret,\n.nav li.dropdown.open a:hover .caret,\n.nav li.dropdown.open a:focus .caret {\n  border-top-color: #ffffff;\n  border-bottom-color: #ffffff;\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n\n.tabs-stacked .open > a:hover,\n.tabs-stacked .open > a:focus {\n  border-color: #999999;\n}\n\n.tabbable {\n  *zoom: 1;\n}\n\n.tabbable:before,\n.tabbable:after {\n  display: table;\n  line-height: 0;\n  content: \"\";\n}\n\n.tabbable:after {\n  clear: both;\n}\n\n.tab-content {\n  overflow: auto;\n}\n\n.tabs-below > .nav-tabs,\n.tabs-right > .nav-tabs,\n.tabs-left > .nav-tabs {\n  border-bottom: 0;\n}\n\n.tab-content > .tab-pane,\n.pill-content > .pill-pane {\n  display: none;\n}\n\n.tab-content > .active,\n.pill-content > .active {\n  display: block;\n}\n\n.tabs-below > .nav-tabs {\n  border-top: 1px solid #ddd;\n}\n\n.tabs-below > .nav-tabs > li {\n  margin-top: -1px;\n  margin-bottom: 0;\n}\n\n.tabs-below > .nav-tabs > li > a {\n  -webkit-border-radius: 0 0 4px 4px;\n     -moz-border-radius: 0 0 4px 4px;\n          border-radius: 0 0 4px 4px;\n}\n\n.tabs-below > .nav-tabs > li > a:hover,\n.tabs-below > .nav-tabs > li > a:focus {\n  border-top-color: #ddd;\n  border-bottom-color: transparent;\n}\n\n.tabs-below > .nav-tabs > .active > a,\n.tabs-below > .nav-tabs > .active > a:hover,\n.tabs-below > .nav-tabs > .active > a:focus {\n  border-color: transparent #ddd #ddd #ddd;\n}\n\n.tabs-left > .nav-tabs > li,\n.tabs-right > .nav-tabs > li {\n  float: none;\n}\n\n.tabs-left > .nav-tabs > li > a,\n.tabs-right > .nav-tabs > li > a {\n  min-width: 74px;\n  margin-right: 0;\n  margin-bottom: 3px;\n}\n\n.tabs-left > .nav-tabs {\n  float: left;\n  margin-right: 19px;\n  border-right: 1px solid #ddd;\n}\n\n.tabs-left > .nav-tabs > li > a {\n  margin-right: -1px;\n  -webkit-border-radius: 4px 0 0 4px;\n     -moz-border-radius: 4px 0 0 4px;\n          border-radius: 4px 0 0 4px;\n}\n\n.tabs-left > .nav-tabs > li > a:hover,\n.tabs-left > .nav-tabs > li > a:focus {\n  border-color: #eeeeee #dddddd #eeeeee #eeeeee;\n}\n\n.tabs-left > .nav-tabs .active > a,\n.tabs-left > .nav-tabs .active > a:hover,\n.tabs-left > .nav-tabs .active > a:focus {\n  border-color: #ddd transparent #ddd #ddd;\n  *border-right-color: #ffffff;\n}\n\n.tabs-right > .nav-tabs {\n  float: right;\n  margin-left: 19px;\n  border-left: 1px solid #ddd;\n}\n\n.tabs-right > .nav-tabs > li > a {\n  margin-left: -1px;\n  -webkit-border-radius: 0 4px 4px 0;\n     -moz-border-radius: 0 4px 4px 0;\n          border-radius: 0 4px 4px 0;\n}\n\n.tabs-right > .nav-tabs > li > a:hover,\n.tabs-right > .nav-tabs > li > a:focus {\n  border-color: #eeeeee #eeeeee #eeeeee #dddddd;\n}\n\n.tabs-right > .nav-tabs .active > a,\n.tabs-right > .nav-tabs .active > a:hover,\n.tabs-right > .nav-tabs .active > a:focus {\n  border-color: #ddd #ddd #ddd transparent;\n  *border-left-color: #ffffff;\n}\n\n.nav > .disabled > a {\n  color: #999999;\n}\n\n.nav > .disabled > a:hover,\n.nav > .disabled > a:focus {\n  text-decoration: none;\n  cursor: default;\n  background-color: transparent;\n}\n\n.navbar {\n  *position: relative;\n  *z-index: 2;\n  margin-bottom: 20px;\n  overflow: visible;\n}\n\n.navbar-inner {\n  min-height: 40px;\n  padding-right: 20px;\n  padding-left: 20px;\n  background-color: #fafafa;\n  background-image: -moz-linear-gradient(top, #ffffff, #f2f2f2);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f2f2f2));\n  background-image: -webkit-linear-gradient(top, #ffffff, #f2f2f2);\n  background-image: -o-linear-gradient(top, #ffffff, #f2f2f2);\n  background-image: linear-gradient(to bottom, #ffffff, #f2f2f2);\n  background-repeat: repeat-x;\n  border: 1px solid #d4d4d4;\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff2f2f2', GradientType=0);\n  *zoom: 1;\n  -webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065);\n     -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065);\n          box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065);\n}\n\n.navbar-inner:before,\n.navbar-inner:after {\n  display: table;\n  line-height: 0;\n  content: \"\";\n}\n\n.navbar-inner:after {\n  clear: both;\n}\n\n.navbar .container {\n  width: auto;\n}\n\n.nav-collapse.collapse {\n  height: auto;\n  overflow: visible;\n}\n\n.navbar .brand {\n  display: block;\n  float: left;\n  padding: 10px 20px 10px;\n  margin-left: -20px;\n  font-size: 20px;\n  font-weight: 200;\n  color: #777777;\n  text-shadow: 0 1px 0 #ffffff;\n}\n\n.navbar .brand:hover,\n.navbar .brand:focus {\n  text-decoration: none;\n}\n\n.navbar-text {\n  margin-bottom: 0;\n  line-height: 40px;\n  color: #777777;\n}\n\n.navbar-link {\n  color: #777777;\n}\n\n.navbar-link:hover,\n.navbar-link:focus {\n  color: #333333;\n}\n\n.navbar .divider-vertical {\n  height: 40px;\n  margin: 0 9px;\n  border-right: 1px solid #ffffff;\n  border-left: 1px solid #f2f2f2;\n}\n\n.navbar .btn,\n.navbar .btn-group {\n  margin-top: 5px;\n}\n\n.navbar .btn-group .btn,\n.navbar .input-prepend .btn,\n.navbar .input-append .btn,\n.navbar .input-prepend .btn-group,\n.navbar .input-append .btn-group {\n  margin-top: 0;\n}\n\n.navbar-form {\n  margin-bottom: 0;\n  *zoom: 1;\n}\n\n.navbar-form:before,\n.navbar-form:after {\n  display: table;\n  line-height: 0;\n  content: \"\";\n}\n\n.navbar-form:after {\n  clear: both;\n}\n\n.navbar-form input,\n.navbar-form select,\n.navbar-form .radio,\n.navbar-form .checkbox {\n  margin-top: 5px;\n}\n\n.navbar-form input,\n.navbar-form select,\n.navbar-form .btn {\n  display: inline-block;\n  margin-bottom: 0;\n}\n\n.navbar-form input[type=\"image\"],\n.navbar-form input[type=\"checkbox\"],\n.navbar-form input[type=\"radio\"] {\n  margin-top: 3px;\n}\n\n.navbar-form .input-append,\n.navbar-form .input-prepend {\n  margin-top: 5px;\n  white-space: nowrap;\n}\n\n.navbar-form .input-append input,\n.navbar-form .input-prepend input {\n  margin-top: 0;\n}\n\n.navbar-search {\n  position: relative;\n  float: left;\n  margin-top: 5px;\n  margin-bottom: 0;\n}\n\n.navbar-search .search-query {\n  padding: 4px 14px;\n  margin-bottom: 0;\n  font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  font-size: 13px;\n  font-weight: normal;\n  line-height: 1;\n  -webkit-border-radius: 15px;\n     -moz-border-radius: 15px;\n          border-radius: 15px;\n}\n\n.navbar-static-top {\n  position: static;\n  margin-bottom: 0;\n}\n\n.navbar-static-top .navbar-inner {\n  -webkit-border-radius: 0;\n     -moz-border-radius: 0;\n          border-radius: 0;\n}\n\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n  position: fixed;\n  right: 0;\n  left: 0;\n  z-index: 1030;\n  margin-bottom: 0;\n}\n\n.navbar-fixed-top .navbar-inner,\n.navbar-static-top .navbar-inner {\n  border-width: 0 0 1px;\n}\n\n.navbar-fixed-bottom .navbar-inner {\n  border-width: 1px 0 0;\n}\n\n.navbar-fixed-top .navbar-inner,\n.navbar-fixed-bottom .navbar-inner {\n  padding-right: 0;\n  padding-left: 0;\n  -webkit-border-radius: 0;\n     -moz-border-radius: 0;\n          border-radius: 0;\n}\n\n.navbar-static-top .container,\n.navbar-fixed-top .container,\n.navbar-fixed-bottom .container {\n  width: 940px;\n}\n\n.navbar-fixed-top {\n  top: 0;\n}\n\n.navbar-fixed-top .navbar-inner,\n.navbar-static-top .navbar-inner {\n  -webkit-box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1);\n     -moz-box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1);\n          box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1);\n}\n\n.navbar-fixed-bottom {\n  bottom: 0;\n}\n\n.navbar-fixed-bottom .navbar-inner {\n  -webkit-box-shadow: 0 -1px 10px rgba(0, 0, 0, 0.1);\n     -moz-box-shadow: 0 -1px 10px rgba(0, 0, 0, 0.1);\n          box-shadow: 0 -1px 10px rgba(0, 0, 0, 0.1);\n}\n\n.navbar .nav {\n  position: relative;\n  left: 0;\n  display: block;\n  float: left;\n  margin: 0 10px 0 0;\n}\n\n.navbar .nav.pull-right {\n  float: right;\n  margin-right: 0;\n}\n\n.navbar .nav > li {\n  float: left;\n}\n\n.navbar .nav > li > a {\n  float: none;\n  padding: 10px 15px 10px;\n  color: #777777;\n  text-decoration: none;\n  text-shadow: 0 1px 0 #ffffff;\n}\n\n.navbar .nav .dropdown-toggle .caret {\n  margin-top: 8px;\n}\n\n.navbar .nav > li > a:focus,\n.navbar .nav > li > a:hover {\n  color: #333333;\n  text-decoration: none;\n  background-color: transparent;\n}\n\n.navbar .nav > .active > a,\n.navbar .nav > .active > a:hover,\n.navbar .nav > .active > a:focus {\n  color: #555555;\n  text-decoration: none;\n  background-color: #e5e5e5;\n  -webkit-box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125);\n     -moz-box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125);\n          box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125);\n}\n\n.navbar .btn-navbar {\n  display: none;\n  float: right;\n  padding: 7px 10px;\n  margin-right: 5px;\n  margin-left: 5px;\n  color: #ffffff;\n  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\n  background-color: #ededed;\n  *background-color: #e5e5e5;\n  background-image: -moz-linear-gradient(top, #f2f2f2, #e5e5e5);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f2f2f2), to(#e5e5e5));\n  background-image: -webkit-linear-gradient(top, #f2f2f2, #e5e5e5);\n  background-image: -o-linear-gradient(top, #f2f2f2, #e5e5e5);\n  background-image: linear-gradient(to bottom, #f2f2f2, #e5e5e5);\n  background-repeat: repeat-x;\n  border-color: #e5e5e5 #e5e5e5 #bfbfbf;\n  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2', endColorstr='#ffe5e5e5', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);\n  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075);\n     -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075);\n          box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075);\n}\n\n.navbar .btn-navbar:hover,\n.navbar .btn-navbar:focus,\n.navbar .btn-navbar:active,\n.navbar .btn-navbar.active,\n.navbar .btn-navbar.disabled,\n.navbar .btn-navbar[disabled] {\n  color: #ffffff;\n  background-color: #e5e5e5;\n  *background-color: #d9d9d9;\n}\n\n.navbar .btn-navbar:active,\n.navbar .btn-navbar.active {\n  background-color: #cccccc \\9;\n}\n\n.navbar .btn-navbar .icon-bar {\n  display: block;\n  width: 18px;\n  height: 2px;\n  background-color: #f5f5f5;\n  -webkit-border-radius: 1px;\n     -moz-border-radius: 1px;\n          border-radius: 1px;\n  -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);\n     -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);\n          box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);\n}\n\n.btn-navbar .icon-bar + .icon-bar {\n  margin-top: 3px;\n}\n\n.navbar .nav > li > .dropdown-menu:before {\n  position: absolute;\n  top: -7px;\n  left: 9px;\n  display: inline-block;\n  border-right: 7px solid transparent;\n  border-bottom: 7px solid #ccc;\n  border-left: 7px solid transparent;\n  border-bottom-color: rgba(0, 0, 0, 0.2);\n  content: '';\n}\n\n.navbar .nav > li > .dropdown-menu:after {\n  position: absolute;\n  top: -6px;\n  left: 10px;\n  display: inline-block;\n  border-right: 6px solid transparent;\n  border-bottom: 6px solid #ffffff;\n  border-left: 6px solid transparent;\n  content: '';\n}\n\n.navbar-fixed-bottom .nav > li > .dropdown-menu:before {\n  top: auto;\n  bottom: -7px;\n  border-top: 7px solid #ccc;\n  border-bottom: 0;\n  border-top-color: rgba(0, 0, 0, 0.2);\n}\n\n.navbar-fixed-bottom .nav > li > .dropdown-menu:after {\n  top: auto;\n  bottom: -6px;\n  border-top: 6px solid #ffffff;\n  border-bottom: 0;\n}\n\n.navbar .nav li.dropdown > a:hover .caret,\n.navbar .nav li.dropdown > a:focus .caret {\n  border-top-color: #333333;\n  border-bottom-color: #333333;\n}\n\n.navbar .nav li.dropdown.open > .dropdown-toggle,\n.navbar .nav li.dropdown.active > .dropdown-toggle,\n.navbar .nav li.dropdown.open.active > .dropdown-toggle {\n  color: #555555;\n  background-color: #e5e5e5;\n}\n\n.navbar .nav li.dropdown > .dropdown-toggle .caret {\n  border-top-color: #777777;\n  border-bottom-color: #777777;\n}\n\n.navbar .nav li.dropdown.open > .dropdown-toggle .caret,\n.navbar .nav li.dropdown.active > .dropdown-toggle .caret,\n.navbar .nav li.dropdown.open.active > .dropdown-toggle .caret {\n  border-top-color: #555555;\n  border-bottom-color: #555555;\n}\n\n.navbar .pull-right > li > .dropdown-menu,\n.navbar .nav > li > .dropdown-menu.pull-right {\n  right: 0;\n  left: auto;\n}\n\n.navbar .pull-right > li > .dropdown-menu:before,\n.navbar .nav > li > .dropdown-menu.pull-right:before {\n  right: 12px;\n  left: auto;\n}\n\n.navbar .pull-right > li > .dropdown-menu:after,\n.navbar .nav > li > .dropdown-menu.pull-right:after {\n  right: 13px;\n  left: auto;\n}\n\n.navbar .pull-right > li > .dropdown-menu .dropdown-menu,\n.navbar .nav > li > .dropdown-menu.pull-right .dropdown-menu {\n  right: 100%;\n  left: auto;\n  margin-right: -1px;\n  margin-left: 0;\n  -webkit-border-radius: 6px 0 6px 6px;\n     -moz-border-radius: 6px 0 6px 6px;\n          border-radius: 6px 0 6px 6px;\n}\n\n.navbar-inverse .navbar-inner {\n  background-color: #1b1b1b;\n  background-image: -moz-linear-gradient(top, #222222, #111111);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#222222), to(#111111));\n  background-image: -webkit-linear-gradient(top, #222222, #111111);\n  background-image: -o-linear-gradient(top, #222222, #111111);\n  background-image: linear-gradient(to bottom, #222222, #111111);\n  background-repeat: repeat-x;\n  border-color: #252525;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff111111', GradientType=0);\n}\n\n.navbar-inverse .brand,\n.navbar-inverse .nav > li > a {\n  color: #999999;\n  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\n}\n\n.navbar-inverse .brand:hover,\n.navbar-inverse .nav > li > a:hover,\n.navbar-inverse .brand:focus,\n.navbar-inverse .nav > li > a:focus {\n  color: #ffffff;\n}\n\n.navbar-inverse .brand {\n  color: #999999;\n}\n\n.navbar-inverse .navbar-text {\n  color: #999999;\n}\n\n.navbar-inverse .nav > li > a:focus,\n.navbar-inverse .nav > li > a:hover {\n  color: #ffffff;\n  background-color: transparent;\n}\n\n.navbar-inverse .nav .active > a,\n.navbar-inverse .nav .active > a:hover,\n.navbar-inverse .nav .active > a:focus {\n  color: #ffffff;\n  background-color: #111111;\n}\n\n.navbar-inverse .navbar-link {\n  color: #999999;\n}\n\n.navbar-inverse .navbar-link:hover,\n.navbar-inverse .navbar-link:focus {\n  color: #ffffff;\n}\n\n.navbar-inverse .divider-vertical {\n  border-right-color: #222222;\n  border-left-color: #111111;\n}\n\n.navbar-inverse .nav li.dropdown.open > .dropdown-toggle,\n.navbar-inverse .nav li.dropdown.active > .dropdown-toggle,\n.navbar-inverse .nav li.dropdown.open.active > .dropdown-toggle {\n  color: #ffffff;\n  background-color: #111111;\n}\n\n.navbar-inverse .nav li.dropdown > a:hover .caret,\n.navbar-inverse .nav li.dropdown > a:focus .caret {\n  border-top-color: #ffffff;\n  border-bottom-color: #ffffff;\n}\n\n.navbar-inverse .nav li.dropdown > .dropdown-toggle .caret {\n  border-top-color: #999999;\n  border-bottom-color: #999999;\n}\n\n.navbar-inverse .nav li.dropdown.open > .dropdown-toggle .caret,\n.navbar-inverse .nav li.dropdown.active > .dropdown-toggle .caret,\n.navbar-inverse .nav li.dropdown.open.active > .dropdown-toggle .caret {\n  border-top-color: #ffffff;\n  border-bottom-color: #ffffff;\n}\n\n.navbar-inverse .navbar-search .search-query {\n  color: #ffffff;\n  background-color: #515151;\n  border-color: #111111;\n  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15);\n     -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15);\n          box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15);\n  -webkit-transition: none;\n     -moz-transition: none;\n       -o-transition: none;\n          transition: none;\n}\n\n.navbar-inverse .navbar-search .search-query:-moz-placeholder {\n  color: #cccccc;\n}\n\n.navbar-inverse .navbar-search .search-query:-ms-input-placeholder {\n  color: #cccccc;\n}\n\n.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder {\n  color: #cccccc;\n}\n\n.navbar-inverse .navbar-search .search-query:focus,\n.navbar-inverse .navbar-search .search-query.focused {\n  padding: 5px 15px;\n  color: #333333;\n  text-shadow: 0 1px 0 #ffffff;\n  background-color: #ffffff;\n  border: 0;\n  outline: 0;\n  -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15);\n     -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15);\n          box-shadow: 0 0 3px rgba(0, 0, 0, 0.15);\n}\n\n.navbar-inverse .btn-navbar {\n  color: #ffffff;\n  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\n  background-color: #0e0e0e;\n  *background-color: #040404;\n  background-image: -moz-linear-gradient(top, #151515, #040404);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#151515), to(#040404));\n  background-image: -webkit-linear-gradient(top, #151515, #040404);\n  background-image: -o-linear-gradient(top, #151515, #040404);\n  background-image: linear-gradient(to bottom, #151515, #040404);\n  background-repeat: repeat-x;\n  border-color: #040404 #040404 #000000;\n  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff151515', endColorstr='#ff040404', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);\n}\n\n.navbar-inverse .btn-navbar:hover,\n.navbar-inverse .btn-navbar:focus,\n.navbar-inverse .btn-navbar:active,\n.navbar-inverse .btn-navbar.active,\n.navbar-inverse .btn-navbar.disabled,\n.navbar-inverse .btn-navbar[disabled] {\n  color: #ffffff;\n  background-color: #040404;\n  *background-color: #000000;\n}\n\n.navbar-inverse .btn-navbar:active,\n.navbar-inverse .btn-navbar.active {\n  background-color: #000000 \\9;\n}\n\n.breadcrumb {\n  padding: 8px 15px;\n  margin: 0 0 20px;\n  list-style: none;\n  background-color: #f5f5f5;\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n}\n\n.breadcrumb > li {\n  display: inline-block;\n  *display: inline;\n  text-shadow: 0 1px 0 #ffffff;\n  *zoom: 1;\n}\n\n.breadcrumb > li > .divider {\n  padding: 0 5px;\n  color: #ccc;\n}\n\n.breadcrumb > .active {\n  color: #999999;\n}\n\n.pagination {\n  margin: 20px 0;\n}\n\n.pagination ul {\n  display: inline-block;\n  *display: inline;\n  margin-bottom: 0;\n  margin-left: 0;\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n  *zoom: 1;\n  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n     -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n          box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n\n.pagination ul > li {\n  display: inline;\n}\n\n.pagination ul > li > a,\n.pagination ul > li > span {\n  float: left;\n  padding: 4px 12px;\n  line-height: 20px;\n  text-decoration: none;\n  background-color: #ffffff;\n  border: 1px solid #dddddd;\n  border-left-width: 0;\n}\n\n.pagination ul > li > a:hover,\n.pagination ul > li > a:focus,\n.pagination ul > .active > a,\n.pagination ul > .active > span {\n  background-color: #f5f5f5;\n}\n\n.pagination ul > .active > a,\n.pagination ul > .active > span {\n  color: #999999;\n  cursor: default;\n}\n\n.pagination ul > .disabled > span,\n.pagination ul > .disabled > a,\n.pagination ul > .disabled > a:hover,\n.pagination ul > .disabled > a:focus {\n  color: #999999;\n  cursor: default;\n  background-color: transparent;\n}\n\n.pagination ul > li:first-child > a,\n.pagination ul > li:first-child > span {\n  border-left-width: 1px;\n  -webkit-border-bottom-left-radius: 4px;\n          border-bottom-left-radius: 4px;\n  -webkit-border-top-left-radius: 4px;\n          border-top-left-radius: 4px;\n  -moz-border-radius-bottomleft: 4px;\n  -moz-border-radius-topleft: 4px;\n}\n\n.pagination ul > li:last-child > a,\n.pagination ul > li:last-child > span {\n  -webkit-border-top-right-radius: 4px;\n          border-top-right-radius: 4px;\n  -webkit-border-bottom-right-radius: 4px;\n          border-bottom-right-radius: 4px;\n  -moz-border-radius-topright: 4px;\n  -moz-border-radius-bottomright: 4px;\n}\n\n.pagination-centered {\n  text-align: center;\n}\n\n.pagination-right {\n  text-align: right;\n}\n\n.pagination-large ul > li > a,\n.pagination-large ul > li > span {\n  padding: 11px 19px;\n  font-size: 17.5px;\n}\n\n.pagination-large ul > li:first-child > a,\n.pagination-large ul > li:first-child > span {\n  -webkit-border-bottom-left-radius: 6px;\n          border-bottom-left-radius: 6px;\n  -webkit-border-top-left-radius: 6px;\n          border-top-left-radius: 6px;\n  -moz-border-radius-bottomleft: 6px;\n  -moz-border-radius-topleft: 6px;\n}\n\n.pagination-large ul > li:last-child > a,\n.pagination-large ul > li:last-child > span {\n  -webkit-border-top-right-radius: 6px;\n          border-top-right-radius: 6px;\n  -webkit-border-bottom-right-radius: 6px;\n          border-bottom-right-radius: 6px;\n  -moz-border-radius-topright: 6px;\n  -moz-border-radius-bottomright: 6px;\n}\n\n.pagination-mini ul > li:first-child > a,\n.pagination-small ul > li:first-child > a,\n.pagination-mini ul > li:first-child > span,\n.pagination-small ul > li:first-child > span {\n  -webkit-border-bottom-left-radius: 3px;\n          border-bottom-left-radius: 3px;\n  -webkit-border-top-left-radius: 3px;\n          border-top-left-radius: 3px;\n  -moz-border-radius-bottomleft: 3px;\n  -moz-border-radius-topleft: 3px;\n}\n\n.pagination-mini ul > li:last-child > a,\n.pagination-small ul > li:last-child > a,\n.pagination-mini ul > li:last-child > span,\n.pagination-small ul > li:last-child > span {\n  -webkit-border-top-right-radius: 3px;\n          border-top-right-radius: 3px;\n  -webkit-border-bottom-right-radius: 3px;\n          border-bottom-right-radius: 3px;\n  -moz-border-radius-topright: 3px;\n  -moz-border-radius-bottomright: 3px;\n}\n\n.pagination-small ul > li > a,\n.pagination-small ul > li > span {\n  padding: 2px 10px;\n  font-size: 11.9px;\n}\n\n.pagination-mini ul > li > a,\n.pagination-mini ul > li > span {\n  padding: 0 6px;\n  font-size: 10.5px;\n}\n\n.pager {\n  margin: 20px 0;\n  text-align: center;\n  list-style: none;\n  *zoom: 1;\n}\n\n.pager:before,\n.pager:after {\n  display: table;\n  line-height: 0;\n  content: \"\";\n}\n\n.pager:after {\n  clear: both;\n}\n\n.pager li {\n  display: inline;\n}\n\n.pager li > a,\n.pager li > span {\n  display: inline-block;\n  padding: 5px 14px;\n  background-color: #fff;\n  border: 1px solid #ddd;\n  -webkit-border-radius: 15px;\n     -moz-border-radius: 15px;\n          border-radius: 15px;\n}\n\n.pager li > a:hover,\n.pager li > a:focus {\n  text-decoration: none;\n  background-color: #f5f5f5;\n}\n\n.pager .next > a,\n.pager .next > span {\n  float: right;\n}\n\n.pager .previous > a,\n.pager .previous > span {\n  float: left;\n}\n\n.pager .disabled > a,\n.pager .disabled > a:hover,\n.pager .disabled > a:focus,\n.pager .disabled > span {\n  color: #999999;\n  cursor: default;\n  background-color: #fff;\n}\n\n.modal-backdrop {\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: 1040;\n  background-color: #000000;\n}\n\n.modal-backdrop.fade {\n  opacity: 0;\n}\n\n.modal-backdrop,\n.modal-backdrop.fade.in {\n  opacity: 0.8;\n  filter: alpha(opacity=80);\n}\n\n.modal {\n  position: fixed;\n  top: 10%;\n  left: 50%;\n  z-index: 1050;\n  width: 560px;\n  margin-left: -280px;\n  background-color: #ffffff;\n  border: 1px solid #999;\n  border: 1px solid rgba(0, 0, 0, 0.3);\n  *border: 1px solid #999;\n  -webkit-border-radius: 6px;\n     -moz-border-radius: 6px;\n          border-radius: 6px;\n  outline: none;\n  -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);\n     -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);\n          box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);\n  -webkit-background-clip: padding-box;\n     -moz-background-clip: padding-box;\n          background-clip: padding-box;\n}\n\n.modal.fade {\n  top: -25%;\n  -webkit-transition: opacity 0.3s linear, top 0.3s ease-out;\n     -moz-transition: opacity 0.3s linear, top 0.3s ease-out;\n       -o-transition: opacity 0.3s linear, top 0.3s ease-out;\n          transition: opacity 0.3s linear, top 0.3s ease-out;\n}\n\n.modal.fade.in {\n  top: 10%;\n}\n\n.modal-header {\n  padding: 9px 15px;\n  border-bottom: 1px solid #eee;\n}\n\n.modal-header .close {\n  margin-top: 2px;\n}\n\n.modal-header h3 {\n  margin: 0;\n  line-height: 30px;\n}\n\n.modal-body {\n  position: relative;\n  max-height: 400px;\n  padding: 15px;\n  overflow-y: auto;\n}\n\n.modal-form {\n  margin-bottom: 0;\n}\n\n.modal-footer {\n  padding: 14px 15px 15px;\n  margin-bottom: 0;\n  text-align: right;\n  background-color: #f5f5f5;\n  border-top: 1px solid #ddd;\n  -webkit-border-radius: 0 0 6px 6px;\n     -moz-border-radius: 0 0 6px 6px;\n          border-radius: 0 0 6px 6px;\n  *zoom: 1;\n  -webkit-box-shadow: inset 0 1px 0 #ffffff;\n     -moz-box-shadow: inset 0 1px 0 #ffffff;\n          box-shadow: inset 0 1px 0 #ffffff;\n}\n\n.modal-footer:before,\n.modal-footer:after {\n  display: table;\n  line-height: 0;\n  content: \"\";\n}\n\n.modal-footer:after {\n  clear: both;\n}\n\n.modal-footer .btn + .btn {\n  margin-bottom: 0;\n  margin-left: 5px;\n}\n\n.modal-footer .btn-group .btn + .btn {\n  margin-left: -1px;\n}\n\n.modal-footer .btn-block + .btn-block {\n  margin-left: 0;\n}\n\n.tooltip {\n  position: absolute;\n  z-index: 1030;\n  display: block;\n  font-size: 11px;\n  line-height: 1.4;\n  opacity: 0;\n  filter: alpha(opacity=0);\n  visibility: visible;\n}\n\n.tooltip.in {\n  opacity: 0.8;\n  filter: alpha(opacity=80);\n}\n\n.tooltip.top {\n  padding: 5px 0;\n  margin-top: -3px;\n}\n\n.tooltip.right {\n  padding: 0 5px;\n  margin-left: 3px;\n}\n\n.tooltip.bottom {\n  padding: 5px 0;\n  margin-top: 3px;\n}\n\n.tooltip.left {\n  padding: 0 5px;\n  margin-left: -3px;\n}\n\n.tooltip-inner {\n  max-width: 200px;\n  padding: 8px;\n  color: #ffffff;\n  text-align: center;\n  text-decoration: none;\n  background-color: #000000;\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n}\n\n.tooltip-arrow {\n  position: absolute;\n  width: 0;\n  height: 0;\n  border-color: transparent;\n  border-style: solid;\n}\n\n.tooltip.top .tooltip-arrow {\n  bottom: 0;\n  left: 50%;\n  margin-left: -5px;\n  border-top-color: #000000;\n  border-width: 5px 5px 0;\n}\n\n.tooltip.right .tooltip-arrow {\n  top: 50%;\n  left: 0;\n  margin-top: -5px;\n  border-right-color: #000000;\n  border-width: 5px 5px 5px 0;\n}\n\n.tooltip.left .tooltip-arrow {\n  top: 50%;\n  right: 0;\n  margin-top: -5px;\n  border-left-color: #000000;\n  border-width: 5px 0 5px 5px;\n}\n\n.tooltip.bottom .tooltip-arrow {\n  top: 0;\n  left: 50%;\n  margin-left: -5px;\n  border-bottom-color: #000000;\n  border-width: 0 5px 5px;\n}\n\n.popover {\n  position: absolute;\n  top: 0;\n  left: 0;\n  z-index: 1010;\n  display: none;\n  max-width: 276px;\n  padding: 1px;\n  text-align: left;\n  white-space: normal;\n  background-color: #ffffff;\n  border: 1px solid #ccc;\n  border: 1px solid rgba(0, 0, 0, 0.2);\n  -webkit-border-radius: 6px;\n     -moz-border-radius: 6px;\n          border-radius: 6px;\n  -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n     -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n          box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n  -webkit-background-clip: padding-box;\n     -moz-background-clip: padding;\n          background-clip: padding-box;\n}\n\n.popover.top {\n  margin-top: -10px;\n}\n\n.popover.right {\n  margin-left: 10px;\n}\n\n.popover.bottom {\n  margin-top: 10px;\n}\n\n.popover.left {\n  margin-left: -10px;\n}\n\n.popover-title {\n  padding: 8px 14px;\n  margin: 0;\n  font-size: 14px;\n  font-weight: normal;\n  line-height: 18px;\n  background-color: #f7f7f7;\n  border-bottom: 1px solid #ebebeb;\n  -webkit-border-radius: 5px 5px 0 0;\n     -moz-border-radius: 5px 5px 0 0;\n          border-radius: 5px 5px 0 0;\n}\n\n.popover-title:empty {\n  display: none;\n}\n\n.popover-content {\n  padding: 9px 14px;\n}\n\n.popover .arrow,\n.popover .arrow:after {\n  position: absolute;\n  display: block;\n  width: 0;\n  height: 0;\n  border-color: transparent;\n  border-style: solid;\n}\n\n.popover .arrow {\n  border-width: 11px;\n}\n\n.popover .arrow:after {\n  border-width: 10px;\n  content: \"\";\n}\n\n.popover.top .arrow {\n  bottom: -11px;\n  left: 50%;\n  margin-left: -11px;\n  border-top-color: #999;\n  border-top-color: rgba(0, 0, 0, 0.25);\n  border-bottom-width: 0;\n}\n\n.popover.top .arrow:after {\n  bottom: 1px;\n  margin-left: -10px;\n  border-top-color: #ffffff;\n  border-bottom-width: 0;\n}\n\n.popover.right .arrow {\n  top: 50%;\n  left: -11px;\n  margin-top: -11px;\n  border-right-color: #999;\n  border-right-color: rgba(0, 0, 0, 0.25);\n  border-left-width: 0;\n}\n\n.popover.right .arrow:after {\n  bottom: -10px;\n  left: 1px;\n  border-right-color: #ffffff;\n  border-left-width: 0;\n}\n\n.popover.bottom .arrow {\n  top: -11px;\n  left: 50%;\n  margin-left: -11px;\n  border-bottom-color: #999;\n  border-bottom-color: rgba(0, 0, 0, 0.25);\n  border-top-width: 0;\n}\n\n.popover.bottom .arrow:after {\n  top: 1px;\n  margin-left: -10px;\n  border-bottom-color: #ffffff;\n  border-top-width: 0;\n}\n\n.popover.left .arrow {\n  top: 50%;\n  right: -11px;\n  margin-top: -11px;\n  border-left-color: #999;\n  border-left-color: rgba(0, 0, 0, 0.25);\n  border-right-width: 0;\n}\n\n.popover.left .arrow:after {\n  right: 1px;\n  bottom: -10px;\n  border-left-color: #ffffff;\n  border-right-width: 0;\n}\n\n.thumbnails {\n  margin-left: -20px;\n  list-style: none;\n  *zoom: 1;\n}\n\n.thumbnails:before,\n.thumbnails:after {\n  display: table;\n  line-height: 0;\n  content: \"\";\n}\n\n.thumbnails:after {\n  clear: both;\n}\n\n.row-fluid .thumbnails {\n  margin-left: 0;\n}\n\n.thumbnails > li {\n  float: left;\n  margin-bottom: 20px;\n  margin-left: 20px;\n}\n\n.thumbnail {\n  display: block;\n  padding: 4px;\n  line-height: 20px;\n  border: 1px solid #ddd;\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n  -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055);\n     -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055);\n          box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055);\n  -webkit-transition: all 0.2s ease-in-out;\n     -moz-transition: all 0.2s ease-in-out;\n       -o-transition: all 0.2s ease-in-out;\n          transition: all 0.2s ease-in-out;\n}\n\na.thumbnail:hover,\na.thumbnail:focus {\n  border-color: #0088cc;\n  -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25);\n     -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25);\n          box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25);\n}\n\n.thumbnail > img {\n  display: block;\n  max-width: 100%;\n  margin-right: auto;\n  margin-left: auto;\n}\n\n.thumbnail .caption {\n  padding: 9px;\n  color: #555555;\n}\n\n.media,\n.media-body {\n  overflow: hidden;\n  *overflow: visible;\n  zoom: 1;\n}\n\n.media,\n.media .media {\n  margin-top: 15px;\n}\n\n.media:first-child {\n  margin-top: 0;\n}\n\n.media-object {\n  display: block;\n}\n\n.media-heading {\n  margin: 0 0 5px;\n}\n\n.media > .pull-left {\n  margin-right: 10px;\n}\n\n.media > .pull-right {\n  margin-left: 10px;\n}\n\n.media-list {\n  margin-left: 0;\n  list-style: none;\n}\n\n.label,\n.badge {\n  display: inline-block;\n  padding: 2px 4px;\n  font-size: 11.844px;\n  font-weight: bold;\n  line-height: 14px;\n  color: #ffffff;\n  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\n  white-space: nowrap;\n  vertical-align: baseline;\n  background-color: #999999;\n}\n\n.label {\n  -webkit-border-radius: 3px;\n     -moz-border-radius: 3px;\n          border-radius: 3px;\n}\n\n.badge {\n  padding-right: 9px;\n  padding-left: 9px;\n  -webkit-border-radius: 9px;\n     -moz-border-radius: 9px;\n          border-radius: 9px;\n}\n\n.label:empty,\n.badge:empty {\n  display: none;\n}\n\na.label:hover,\na.label:focus,\na.badge:hover,\na.badge:focus {\n  color: #ffffff;\n  text-decoration: none;\n  cursor: pointer;\n}\n\n.label-important,\n.badge-important {\n  background-color: #b94a48;\n}\n\n.label-important[href],\n.badge-important[href] {\n  background-color: #953b39;\n}\n\n.label-warning,\n.badge-warning {\n  background-color: #f89406;\n}\n\n.label-warning[href],\n.badge-warning[href] {\n  background-color: #c67605;\n}\n\n.label-success,\n.badge-success {\n  background-color: #468847;\n}\n\n.label-success[href],\n.badge-success[href] {\n  background-color: #356635;\n}\n\n.label-info,\n.badge-info {\n  background-color: #3a87ad;\n}\n\n.label-info[href],\n.badge-info[href] {\n  background-color: #2d6987;\n}\n\n.label-inverse,\n.badge-inverse {\n  background-color: #333333;\n}\n\n.label-inverse[href],\n.badge-inverse[href] {\n  background-color: #1a1a1a;\n}\n\n.btn .label,\n.btn .badge {\n  position: relative;\n  top: -1px;\n}\n\n.btn-mini .label,\n.btn-mini .badge {\n  top: 0;\n}\n\n@-webkit-keyframes progress-bar-stripes {\n  from {\n    background-position: 40px 0;\n  }\n  to {\n    background-position: 0 0;\n  }\n}\n\n@-moz-keyframes progress-bar-stripes {\n  from {\n    background-position: 40px 0;\n  }\n  to {\n    background-position: 0 0;\n  }\n}\n\n@-ms-keyframes progress-bar-stripes {\n  from {\n    background-position: 40px 0;\n  }\n  to {\n    background-position: 0 0;\n  }\n}\n\n@-o-keyframes progress-bar-stripes {\n  from {\n    background-position: 0 0;\n  }\n  to {\n    background-position: 40px 0;\n  }\n}\n\n@keyframes progress-bar-stripes {\n  from {\n    background-position: 40px 0;\n  }\n  to {\n    background-position: 0 0;\n  }\n}\n\n.progress {\n  height: 20px;\n  margin-bottom: 20px;\n  overflow: hidden;\n  background-color: #f7f7f7;\n  background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9));\n  background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9);\n  background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9);\n  background-image: linear-gradient(to bottom, #f5f5f5, #f9f9f9);\n  background-repeat: repeat-x;\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0);\n  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n     -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n          box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n}\n\n.progress .bar {\n  float: left;\n  width: 0;\n  height: 100%;\n  font-size: 12px;\n  color: #ffffff;\n  text-align: center;\n  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\n  background-color: #0e90d2;\n  background-image: -moz-linear-gradient(top, #149bdf, #0480be);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be));\n  background-image: -webkit-linear-gradient(top, #149bdf, #0480be);\n  background-image: -o-linear-gradient(top, #149bdf, #0480be);\n  background-image: linear-gradient(to bottom, #149bdf, #0480be);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf', endColorstr='#ff0480be', GradientType=0);\n  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n     -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n          box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n  -webkit-box-sizing: border-box;\n     -moz-box-sizing: border-box;\n          box-sizing: border-box;\n  -webkit-transition: width 0.6s ease;\n     -moz-transition: width 0.6s ease;\n       -o-transition: width 0.6s ease;\n          transition: width 0.6s ease;\n}\n\n.progress .bar + .bar {\n  -webkit-box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n     -moz-box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n          box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n}\n\n.progress-striped .bar {\n  background-color: #149bdf;\n  background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  -webkit-background-size: 40px 40px;\n     -moz-background-size: 40px 40px;\n       -o-background-size: 40px 40px;\n          background-size: 40px 40px;\n}\n\n.progress.active .bar {\n  -webkit-animation: progress-bar-stripes 2s linear infinite;\n     -moz-animation: progress-bar-stripes 2s linear infinite;\n      -ms-animation: progress-bar-stripes 2s linear infinite;\n       -o-animation: progress-bar-stripes 2s linear infinite;\n          animation: progress-bar-stripes 2s linear infinite;\n}\n\n.progress-danger .bar,\n.progress .bar-danger {\n  background-color: #dd514c;\n  background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35));\n  background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35);\n  background-image: -o-linear-gradient(top, #ee5f5b, #c43c35);\n  background-image: linear-gradient(to bottom, #ee5f5b, #c43c35);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffc43c35', GradientType=0);\n}\n\n.progress-danger.progress-striped .bar,\n.progress-striped .bar-danger {\n  background-color: #ee5f5b;\n  background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n\n.progress-success .bar,\n.progress .bar-success {\n  background-color: #5eb95e;\n  background-image: -moz-linear-gradient(top, #62c462, #57a957);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957));\n  background-image: -webkit-linear-gradient(top, #62c462, #57a957);\n  background-image: -o-linear-gradient(top, #62c462, #57a957);\n  background-image: linear-gradient(to bottom, #62c462, #57a957);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff57a957', GradientType=0);\n}\n\n.progress-success.progress-striped .bar,\n.progress-striped .bar-success {\n  background-color: #62c462;\n  background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n\n.progress-info .bar,\n.progress .bar-info {\n  background-color: #4bb1cf;\n  background-image: -moz-linear-gradient(top, #5bc0de, #339bb9);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9));\n  background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9);\n  background-image: -o-linear-gradient(top, #5bc0de, #339bb9);\n  background-image: linear-gradient(to bottom, #5bc0de, #339bb9);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff339bb9', GradientType=0);\n}\n\n.progress-info.progress-striped .bar,\n.progress-striped .bar-info {\n  background-color: #5bc0de;\n  background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n\n.progress-warning .bar,\n.progress .bar-warning {\n  background-color: #faa732;\n  background-image: -moz-linear-gradient(top, #fbb450, #f89406);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));\n  background-image: -webkit-linear-gradient(top, #fbb450, #f89406);\n  background-image: -o-linear-gradient(top, #fbb450, #f89406);\n  background-image: linear-gradient(to bottom, #fbb450, #f89406);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0);\n}\n\n.progress-warning.progress-striped .bar,\n.progress-striped .bar-warning {\n  background-color: #fbb450;\n  background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n\n.accordion {\n  margin-bottom: 20px;\n}\n\n.accordion-group {\n  margin-bottom: 2px;\n  border: 1px solid #e5e5e5;\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n}\n\n.accordion-heading {\n  border-bottom: 0;\n}\n\n.accordion-heading .accordion-toggle {\n  display: block;\n  padding: 8px 15px;\n}\n\n.accordion-toggle {\n  cursor: pointer;\n}\n\n.accordion-inner {\n  padding: 9px 15px;\n  border-top: 1px solid #e5e5e5;\n}\n\n.carousel {\n  position: relative;\n  margin-bottom: 20px;\n  line-height: 1;\n}\n\n.carousel-inner {\n  position: relative;\n  width: 100%;\n  overflow: hidden;\n}\n\n.carousel-inner > .item {\n  position: relative;\n  display: none;\n  -webkit-transition: 0.6s ease-in-out left;\n     -moz-transition: 0.6s ease-in-out left;\n       -o-transition: 0.6s ease-in-out left;\n          transition: 0.6s ease-in-out left;\n}\n\n.carousel-inner > .item > img,\n.carousel-inner > .item > a > img {\n  display: block;\n  line-height: 1;\n}\n\n.carousel-inner > .active,\n.carousel-inner > .next,\n.carousel-inner > .prev {\n  display: block;\n}\n\n.carousel-inner > .active {\n  left: 0;\n}\n\n.carousel-inner > .next,\n.carousel-inner > .prev {\n  position: absolute;\n  top: 0;\n  width: 100%;\n}\n\n.carousel-inner > .next {\n  left: 100%;\n}\n\n.carousel-inner > .prev {\n  left: -100%;\n}\n\n.carousel-inner > .next.left,\n.carousel-inner > .prev.right {\n  left: 0;\n}\n\n.carousel-inner > .active.left {\n  left: -100%;\n}\n\n.carousel-inner > .active.right {\n  left: 100%;\n}\n\n.carousel-control {\n  position: absolute;\n  top: 40%;\n  left: 15px;\n  width: 40px;\n  height: 40px;\n  margin-top: -20px;\n  font-size: 60px;\n  font-weight: 100;\n  line-height: 30px;\n  color: #ffffff;\n  text-align: center;\n  background: #222222;\n  border: 3px solid #ffffff;\n  -webkit-border-radius: 23px;\n     -moz-border-radius: 23px;\n          border-radius: 23px;\n  opacity: 0.5;\n  filter: alpha(opacity=50);\n}\n\n.carousel-control.right {\n  right: 15px;\n  left: auto;\n}\n\n.carousel-control:hover,\n.carousel-control:focus {\n  color: #ffffff;\n  text-decoration: none;\n  opacity: 0.9;\n  filter: alpha(opacity=90);\n}\n\n.carousel-indicators {\n  position: absolute;\n  top: 15px;\n  right: 15px;\n  z-index: 5;\n  margin: 0;\n  list-style: none;\n}\n\n.carousel-indicators li {\n  display: block;\n  float: left;\n  width: 10px;\n  height: 10px;\n  margin-left: 5px;\n  text-indent: -999px;\n  background-color: #ccc;\n  background-color: rgba(255, 255, 255, 0.25);\n  border-radius: 5px;\n}\n\n.carousel-indicators .active {\n  background-color: #fff;\n}\n\n.carousel-caption {\n  position: absolute;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  padding: 15px;\n  background: #333333;\n  background: rgba(0, 0, 0, 0.75);\n}\n\n.carousel-caption h4,\n.carousel-caption p {\n  line-height: 20px;\n  color: #ffffff;\n}\n\n.carousel-caption h4 {\n  margin: 0 0 5px;\n}\n\n.carousel-caption p {\n  margin-bottom: 0;\n}\n\n.hero-unit {\n  padding: 60px;\n  margin-bottom: 30px;\n  font-size: 18px;\n  font-weight: 200;\n  line-height: 30px;\n  color: inherit;\n  background-color: #eeeeee;\n  -webkit-border-radius: 6px;\n     -moz-border-radius: 6px;\n          border-radius: 6px;\n}\n\n.hero-unit h1 {\n  margin-bottom: 0;\n  font-size: 60px;\n  line-height: 1;\n  letter-spacing: -1px;\n  color: inherit;\n}\n\n.hero-unit li {\n  line-height: 30px;\n}\n\n.pull-right {\n  float: right;\n}\n\n.pull-left {\n  float: left;\n}\n\n.hide {\n  display: none;\n}\n\n.show {\n  display: block;\n}\n\n.invisible {\n  visibility: hidden;\n}\n\n.affix {\n  position: fixed;\n}\n"
  },
  {
    "path": "explainshell/web/static/css/es.css",
    "content": "html {\n    overflow-y: scroll;\n}\n\nbody {\n    font-family: \"Courier New\", Courier, Monaco, Menlo, Consolas, monospace;\n}\n\na {\n    color: #5795f3;\n}\n\n.logo a {\n    font-family: 'Berkshire Swash', cursive;\n    font-size: 66px;\n    color: black;\n    text-decoration: none;\n    background-image:url(/static/img/shell.png);\n    height: 132px;\n    display: inline-block;\n    background-repeat: no-repeat;\n    background-position: 276px 21px;\n    margin-bottom: -41px;\n    margin-top: 21px;\n}\n.logo a .shell {\n    color: #5795f3;\n}\n.logo a .dotcom {\n    font-size:smaller;\n}\n\n.program-text {\n    font-weight: bold;\n}\n\n#command {\n\tfont-size: 18px;\n    word-spacing: 10px;\n\ttext-align: center;\n}\n\n#command-wrapper {\n    z-index: 3;\n}\n\n#command-wrapper.affix {\n    position: fixed;\n    top: 0;\n    left: 0;\n    width: 100%;\n    height: 20px;\n    background-color: white;\n    padding-top: 10px;\n    padding-bottom: 70px;\n    box-shadow: 0 0 15px 5px #ffffff;\n}\n\n#about {\n\ttext-align: justify;\n    width: 700px;\n    margin: 0 auto;\n}\n\n.btn, #explain {\n\tfont-family: Courier;\n}\n\n#canvas {\n    position: absolute;\n    z-index: 1;\n    width: 100%;\n    left: 0;\n    pointer-events: none;\n}\n\n#help {\n    z-index: 2;\n}\n\n.small-push {\n    height: 20px;\n}\n\n.push {\n    height: 40px;\n}\n\n.taggernooption {\n    background-color: #f8c7c7;\n}\n\n.taggeroption {\n    background-color: #caf8c7;\n}\n\n.taggercurrent {\n    border-color: red;\n    border-width: 2px;\n}\n\n.dropdown-menu {\n    font-size: 14px;\n}\n\n#examples a {\n    font-size: 15px;\n}\n\n#examples h3 {\n    font-family: 'Berkshire Swash', cursive;\n}\n\n.menu {\n    width: 460px; /* necessary for right:0 to work at #themeSelector */\n    position: absolute;\n    top: -30px;\n    left: 240px;\n    font-family: 'Berkshire Swash', cursive;\n    font-size: 24px;\n}\n\n#top-search {\n   width: 150px;\n   -webkit-transition: all .5s ease;\n   -moz-transition: all .5s ease;\n   transition: all .5s ease;\n   position: relative;\n   top: -3px; /* looks a bit unaligned without this in chrome */\n   left: 0;\n}\n\n#top-search:focus {\n   left: -110px;\n   width: 260px;\n}\n\n#prevnext {\n    text-align: center;\n    padding-top: 10px;\n}\n\n#prevnext li:not(:first-child), #prevnext span:not(:first-child) {\n    cursor: pointer;\n}\n\n.help-box {\n    background-color: white;\n}\n\n.help-synopsis {\n    background-color: #f5f5f5;\n}\n\n.popover-content {\n    font-size: 12px;\n    text-align: justify;\n}\n\n.popover {\n    font-weight: normal;\n    max-width: 450px;\n}\n\n#themeContainer {\n    /* using a fixed margin-left doesn't work both\n       with and without the search bar in the menu */\n    position: absolute;\n    right: 0;\n    margin-top: 5px;\n    font-family: \"Courier New\",Courier,Monaco,Menlo,Consolas,monospace;\n    font-size: 20px;\n}\n\nbody[data-theme='dark'] {\n    color: white;\n}\n\n[data-theme='dark'] a:not(:hover) {\n    color: #92b9f3;\n}\n\n[data-theme='dark'] .logo a {\n    color: white;\n}\n\n[data-theme='dark'] #command-wrapper.affix {\n    background-color: #16181b;\n    box-shadow: 0 0 15px 5px #16181b;\n}\n\n[data-theme='dark'] .help-box {\n    background-color: transparent;\n    color: white;\n}\n\n[data-theme='dark'] pre {\n    background-color: #222;\n    color: white;\n}\n\n[data-theme='dark'] .caret {\n    /* this is probably a problem with the bootstrap theme */\n    border-top: 4px solid #fff;\n}\n"
  },
  {
    "path": "explainshell/web/static/css/font-awesome.css",
    "content": "/*!\n *  Font Awesome 3.2.1\n *  the iconic font designed for Bootstrap\n *  ------------------------------------------------------------------------------\n *  The full suite of pictographic icons, examples, and documentation can be\n *  found at http://fontawesome.io.  Stay up to date on Twitter at\n *  http://twitter.com/fontawesome.\n *\n *  License\n *  ------------------------------------------------------------------------------\n *  - The Font Awesome font is licensed under SIL OFL 1.1 -\n *    http://scripts.sil.org/OFL\n *  - Font Awesome CSS, LESS, and SASS files are licensed under MIT License -\n *    http://opensource.org/licenses/mit-license.html\n *  - Font Awesome documentation licensed under CC BY 3.0 -\n *    http://creativecommons.org/licenses/by/3.0/\n *  - Attribution is no longer required in Font Awesome 3.0, but much appreciated:\n *    \"Font Awesome by Dave Gandy - http://fontawesome.io\"\n *\n *  Author - Dave Gandy\n *  ------------------------------------------------------------------------------\n *  Email: dave@fontawesome.io\n *  Twitter: http://twitter.com/davegandy\n *  Work: Lead Product Designer @ Kyruus - http://kyruus.com\n */\n/* FONT PATH\n * -------------------------- */\n@font-face {\n  font-family: 'FontAwesome';\n  src: url('../font/fontawesome-webfont.eot?v=3.2.1');\n  src: url('../font/fontawesome-webfont.eot?#iefix&v=3.2.1') format('embedded-opentype'), url('../font/fontawesome-webfont.woff?v=3.2.1') format('woff'), url('../font/fontawesome-webfont.ttf?v=3.2.1') format('truetype'), url('../font/fontawesome-webfont.svg#fontawesomeregular?v=3.2.1') format('svg');\n  font-weight: normal;\n  font-style: normal;\n}\n/* FONT AWESOME CORE\n * -------------------------- */\n[class^=\"icon-\"],\n[class*=\" icon-\"] {\n  font-family: FontAwesome;\n  font-weight: normal;\n  font-style: normal;\n  text-decoration: inherit;\n  -webkit-font-smoothing: antialiased;\n  *margin-right: .3em;\n}\n[class^=\"icon-\"]:before,\n[class*=\" icon-\"]:before {\n  text-decoration: inherit;\n  display: inline-block;\n  speak: none;\n}\n/* makes the font 33% larger relative to the icon container */\n.icon-large:before {\n  vertical-align: -10%;\n  font-size: 1.3333333333333333em;\n}\n/* makes sure icons active on rollover in links */\na [class^=\"icon-\"],\na [class*=\" icon-\"] {\n  display: inline;\n}\n/* increased font size for icon-large */\n[class^=\"icon-\"].icon-fixed-width,\n[class*=\" icon-\"].icon-fixed-width {\n  display: inline-block;\n  width: 1.1428571428571428em;\n  text-align: right;\n  padding-right: 0.2857142857142857em;\n}\n[class^=\"icon-\"].icon-fixed-width.icon-large,\n[class*=\" icon-\"].icon-fixed-width.icon-large {\n  width: 1.4285714285714286em;\n}\n.icons-ul {\n  margin-left: 2.142857142857143em;\n  list-style-type: none;\n}\n.icons-ul > li {\n  position: relative;\n}\n.icons-ul .icon-li {\n  position: absolute;\n  left: -2.142857142857143em;\n  width: 2.142857142857143em;\n  text-align: center;\n  line-height: inherit;\n}\n[class^=\"icon-\"].hide,\n[class*=\" icon-\"].hide {\n  display: none;\n}\n.icon-muted {\n  color: #eeeeee;\n}\n.icon-light {\n  color: #ffffff;\n}\n.icon-dark {\n  color: #333333;\n}\n.icon-border {\n  border: solid 1px #eeeeee;\n  padding: .2em .25em .15em;\n  -webkit-border-radius: 3px;\n  -moz-border-radius: 3px;\n  border-radius: 3px;\n}\n.icon-2x {\n  font-size: 2em;\n}\n.icon-2x.icon-border {\n  border-width: 2px;\n  -webkit-border-radius: 4px;\n  -moz-border-radius: 4px;\n  border-radius: 4px;\n}\n.icon-3x {\n  font-size: 3em;\n}\n.icon-3x.icon-border {\n  border-width: 3px;\n  -webkit-border-radius: 5px;\n  -moz-border-radius: 5px;\n  border-radius: 5px;\n}\n.icon-4x {\n  font-size: 4em;\n}\n.icon-4x.icon-border {\n  border-width: 4px;\n  -webkit-border-radius: 6px;\n  -moz-border-radius: 6px;\n  border-radius: 6px;\n}\n.icon-5x {\n  font-size: 5em;\n}\n.icon-5x.icon-border {\n  border-width: 5px;\n  -webkit-border-radius: 7px;\n  -moz-border-radius: 7px;\n  border-radius: 7px;\n}\n.pull-right {\n  float: right;\n}\n.pull-left {\n  float: left;\n}\n[class^=\"icon-\"].pull-left,\n[class*=\" icon-\"].pull-left {\n  margin-right: .3em;\n}\n[class^=\"icon-\"].pull-right,\n[class*=\" icon-\"].pull-right {\n  margin-left: .3em;\n}\n/* BOOTSTRAP SPECIFIC CLASSES\n * -------------------------- */\n/* Bootstrap 2.0 sprites.less reset */\n[class^=\"icon-\"],\n[class*=\" icon-\"] {\n  display: inline;\n  width: auto;\n  height: auto;\n  line-height: normal;\n  vertical-align: baseline;\n  background-image: none;\n  background-position: 0% 0%;\n  background-repeat: repeat;\n  margin-top: 0;\n}\n/* more sprites.less reset */\n.icon-white,\n.nav-pills > .active > a > [class^=\"icon-\"],\n.nav-pills > .active > a > [class*=\" icon-\"],\n.nav-list > .active > a > [class^=\"icon-\"],\n.nav-list > .active > a > [class*=\" icon-\"],\n.navbar-inverse .nav > .active > a > [class^=\"icon-\"],\n.navbar-inverse .nav > .active > a > [class*=\" icon-\"],\n.dropdown-menu > li > a:hover > [class^=\"icon-\"],\n.dropdown-menu > li > a:hover > [class*=\" icon-\"],\n.dropdown-menu > .active > a > [class^=\"icon-\"],\n.dropdown-menu > .active > a > [class*=\" icon-\"],\n.dropdown-submenu:hover > a > [class^=\"icon-\"],\n.dropdown-submenu:hover > a > [class*=\" icon-\"] {\n  background-image: none;\n}\n/* keeps Bootstrap styles with and without icons the same */\n.btn [class^=\"icon-\"].icon-large,\n.nav [class^=\"icon-\"].icon-large,\n.btn [class*=\" icon-\"].icon-large,\n.nav [class*=\" icon-\"].icon-large {\n  line-height: .9em;\n}\n.btn [class^=\"icon-\"].icon-spin,\n.nav [class^=\"icon-\"].icon-spin,\n.btn [class*=\" icon-\"].icon-spin,\n.nav [class*=\" icon-\"].icon-spin {\n  display: inline-block;\n}\n.nav-tabs [class^=\"icon-\"],\n.nav-pills [class^=\"icon-\"],\n.nav-tabs [class*=\" icon-\"],\n.nav-pills [class*=\" icon-\"],\n.nav-tabs [class^=\"icon-\"].icon-large,\n.nav-pills [class^=\"icon-\"].icon-large,\n.nav-tabs [class*=\" icon-\"].icon-large,\n.nav-pills [class*=\" icon-\"].icon-large {\n  line-height: .9em;\n}\n.btn [class^=\"icon-\"].pull-left.icon-2x,\n.btn [class*=\" icon-\"].pull-left.icon-2x,\n.btn [class^=\"icon-\"].pull-right.icon-2x,\n.btn [class*=\" icon-\"].pull-right.icon-2x {\n  margin-top: .18em;\n}\n.btn [class^=\"icon-\"].icon-spin.icon-large,\n.btn [class*=\" icon-\"].icon-spin.icon-large {\n  line-height: .8em;\n}\n.btn.btn-small [class^=\"icon-\"].pull-left.icon-2x,\n.btn.btn-small [class*=\" icon-\"].pull-left.icon-2x,\n.btn.btn-small [class^=\"icon-\"].pull-right.icon-2x,\n.btn.btn-small [class*=\" icon-\"].pull-right.icon-2x {\n  margin-top: .25em;\n}\n.btn.btn-large [class^=\"icon-\"],\n.btn.btn-large [class*=\" icon-\"] {\n  margin-top: 0;\n}\n.btn.btn-large [class^=\"icon-\"].pull-left.icon-2x,\n.btn.btn-large [class*=\" icon-\"].pull-left.icon-2x,\n.btn.btn-large [class^=\"icon-\"].pull-right.icon-2x,\n.btn.btn-large [class*=\" icon-\"].pull-right.icon-2x {\n  margin-top: .05em;\n}\n.btn.btn-large [class^=\"icon-\"].pull-left.icon-2x,\n.btn.btn-large [class*=\" icon-\"].pull-left.icon-2x {\n  margin-right: .2em;\n}\n.btn.btn-large [class^=\"icon-\"].pull-right.icon-2x,\n.btn.btn-large [class*=\" icon-\"].pull-right.icon-2x {\n  margin-left: .2em;\n}\n/* Fixes alignment in nav lists */\n.nav-list [class^=\"icon-\"],\n.nav-list [class*=\" icon-\"] {\n  line-height: inherit;\n}\n/* EXTRAS\n * -------------------------- */\n/* Stacked and layered icon */\n.icon-stack {\n  position: relative;\n  display: inline-block;\n  width: 2em;\n  height: 2em;\n  line-height: 2em;\n  vertical-align: -35%;\n}\n.icon-stack [class^=\"icon-\"],\n.icon-stack [class*=\" icon-\"] {\n  display: block;\n  text-align: center;\n  position: absolute;\n  width: 100%;\n  height: 100%;\n  font-size: 1em;\n  line-height: inherit;\n  *line-height: 2em;\n}\n.icon-stack .icon-stack-base {\n  font-size: 2em;\n  *line-height: 1em;\n}\n/* Animated rotating icon */\n.icon-spin {\n  display: inline-block;\n  -moz-animation: spin 2s infinite linear;\n  -o-animation: spin 2s infinite linear;\n  -webkit-animation: spin 2s infinite linear;\n  animation: spin 2s infinite linear;\n}\n/* Prevent stack and spinners from being taken inline when inside a link */\na .icon-stack,\na .icon-spin {\n  display: inline-block;\n  text-decoration: none;\n}\n@-moz-keyframes spin {\n  0% {\n    -moz-transform: rotate(0deg);\n  }\n  100% {\n    -moz-transform: rotate(359deg);\n  }\n}\n@-webkit-keyframes spin {\n  0% {\n    -webkit-transform: rotate(0deg);\n  }\n  100% {\n    -webkit-transform: rotate(359deg);\n  }\n}\n@-o-keyframes spin {\n  0% {\n    -o-transform: rotate(0deg);\n  }\n  100% {\n    -o-transform: rotate(359deg);\n  }\n}\n@-ms-keyframes spin {\n  0% {\n    -ms-transform: rotate(0deg);\n  }\n  100% {\n    -ms-transform: rotate(359deg);\n  }\n}\n@keyframes spin {\n  0% {\n    transform: rotate(0deg);\n  }\n  100% {\n    transform: rotate(359deg);\n  }\n}\n/* Icon rotations and mirroring */\n.icon-rotate-90:before {\n  -webkit-transform: rotate(90deg);\n  -moz-transform: rotate(90deg);\n  -ms-transform: rotate(90deg);\n  -o-transform: rotate(90deg);\n  transform: rotate(90deg);\n  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1);\n}\n.icon-rotate-180:before {\n  -webkit-transform: rotate(180deg);\n  -moz-transform: rotate(180deg);\n  -ms-transform: rotate(180deg);\n  -o-transform: rotate(180deg);\n  transform: rotate(180deg);\n  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2);\n}\n.icon-rotate-270:before {\n  -webkit-transform: rotate(270deg);\n  -moz-transform: rotate(270deg);\n  -ms-transform: rotate(270deg);\n  -o-transform: rotate(270deg);\n  transform: rotate(270deg);\n  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);\n}\n.icon-flip-horizontal:before {\n  -webkit-transform: scale(-1, 1);\n  -moz-transform: scale(-1, 1);\n  -ms-transform: scale(-1, 1);\n  -o-transform: scale(-1, 1);\n  transform: scale(-1, 1);\n}\n.icon-flip-vertical:before {\n  -webkit-transform: scale(1, -1);\n  -moz-transform: scale(1, -1);\n  -ms-transform: scale(1, -1);\n  -o-transform: scale(1, -1);\n  transform: scale(1, -1);\n}\n/* ensure rotation occurs inside anchor tags */\na .icon-rotate-90:before,\na .icon-rotate-180:before,\na .icon-rotate-270:before,\na .icon-flip-horizontal:before,\na .icon-flip-vertical:before {\n  display: inline-block;\n}\n/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen\n   readers do not read off random characters that represent icons */\n.icon-glass:before {\n  content: \"\\f000\";\n}\n.icon-music:before {\n  content: \"\\f001\";\n}\n.icon-search:before {\n  content: \"\\f002\";\n}\n.icon-envelope-alt:before {\n  content: \"\\f003\";\n}\n.icon-heart:before {\n  content: \"\\f004\";\n}\n.icon-star:before {\n  content: \"\\f005\";\n}\n.icon-star-empty:before {\n  content: \"\\f006\";\n}\n.icon-user:before {\n  content: \"\\f007\";\n}\n.icon-film:before {\n  content: \"\\f008\";\n}\n.icon-th-large:before {\n  content: \"\\f009\";\n}\n.icon-th:before {\n  content: \"\\f00a\";\n}\n.icon-th-list:before {\n  content: \"\\f00b\";\n}\n.icon-ok:before {\n  content: \"\\f00c\";\n}\n.icon-remove:before {\n  content: \"\\f00d\";\n}\n.icon-zoom-in:before {\n  content: \"\\f00e\";\n}\n.icon-zoom-out:before {\n  content: \"\\f010\";\n}\n.icon-power-off:before,\n.icon-off:before {\n  content: \"\\f011\";\n}\n.icon-signal:before {\n  content: \"\\f012\";\n}\n.icon-gear:before,\n.icon-cog:before {\n  content: \"\\f013\";\n}\n.icon-trash:before {\n  content: \"\\f014\";\n}\n.icon-home:before {\n  content: \"\\f015\";\n}\n.icon-file-alt:before {\n  content: \"\\f016\";\n}\n.icon-time:before {\n  content: \"\\f017\";\n}\n.icon-road:before {\n  content: \"\\f018\";\n}\n.icon-download-alt:before {\n  content: \"\\f019\";\n}\n.icon-download:before {\n  content: \"\\f01a\";\n}\n.icon-upload:before {\n  content: \"\\f01b\";\n}\n.icon-inbox:before {\n  content: \"\\f01c\";\n}\n.icon-play-circle:before {\n  content: \"\\f01d\";\n}\n.icon-rotate-right:before,\n.icon-repeat:before {\n  content: \"\\f01e\";\n}\n.icon-refresh:before {\n  content: \"\\f021\";\n}\n.icon-list-alt:before {\n  content: \"\\f022\";\n}\n.icon-lock:before {\n  content: \"\\f023\";\n}\n.icon-flag:before {\n  content: \"\\f024\";\n}\n.icon-headphones:before {\n  content: \"\\f025\";\n}\n.icon-volume-off:before {\n  content: \"\\f026\";\n}\n.icon-volume-down:before {\n  content: \"\\f027\";\n}\n.icon-volume-up:before {\n  content: \"\\f028\";\n}\n.icon-qrcode:before {\n  content: \"\\f029\";\n}\n.icon-barcode:before {\n  content: \"\\f02a\";\n}\n.icon-tag:before {\n  content: \"\\f02b\";\n}\n.icon-tags:before {\n  content: \"\\f02c\";\n}\n.icon-book:before {\n  content: \"\\f02d\";\n}\n.icon-bookmark:before {\n  content: \"\\f02e\";\n}\n.icon-print:before {\n  content: \"\\f02f\";\n}\n.icon-camera:before {\n  content: \"\\f030\";\n}\n.icon-font:before {\n  content: \"\\f031\";\n}\n.icon-bold:before {\n  content: \"\\f032\";\n}\n.icon-italic:before {\n  content: \"\\f033\";\n}\n.icon-text-height:before {\n  content: \"\\f034\";\n}\n.icon-text-width:before {\n  content: \"\\f035\";\n}\n.icon-align-left:before {\n  content: \"\\f036\";\n}\n.icon-align-center:before {\n  content: \"\\f037\";\n}\n.icon-align-right:before {\n  content: \"\\f038\";\n}\n.icon-align-justify:before {\n  content: \"\\f039\";\n}\n.icon-list:before {\n  content: \"\\f03a\";\n}\n.icon-indent-left:before {\n  content: \"\\f03b\";\n}\n.icon-indent-right:before {\n  content: \"\\f03c\";\n}\n.icon-facetime-video:before {\n  content: \"\\f03d\";\n}\n.icon-picture:before {\n  content: \"\\f03e\";\n}\n.icon-pencil:before {\n  content: \"\\f040\";\n}\n.icon-map-marker:before {\n  content: \"\\f041\";\n}\n.icon-adjust:before {\n  content: \"\\f042\";\n}\n.icon-tint:before {\n  content: \"\\f043\";\n}\n.icon-edit:before {\n  content: \"\\f044\";\n}\n.icon-share:before {\n  content: \"\\f045\";\n}\n.icon-check:before {\n  content: \"\\f046\";\n}\n.icon-move:before {\n  content: \"\\f047\";\n}\n.icon-step-backward:before {\n  content: \"\\f048\";\n}\n.icon-fast-backward:before {\n  content: \"\\f049\";\n}\n.icon-backward:before {\n  content: \"\\f04a\";\n}\n.icon-play:before {\n  content: \"\\f04b\";\n}\n.icon-pause:before {\n  content: \"\\f04c\";\n}\n.icon-stop:before {\n  content: \"\\f04d\";\n}\n.icon-forward:before {\n  content: \"\\f04e\";\n}\n.icon-fast-forward:before {\n  content: \"\\f050\";\n}\n.icon-step-forward:before {\n  content: \"\\f051\";\n}\n.icon-eject:before {\n  content: \"\\f052\";\n}\n.icon-chevron-left:before {\n  content: \"\\f053\";\n}\n.icon-chevron-right:before {\n  content: \"\\f054\";\n}\n.icon-plus-sign:before {\n  content: \"\\f055\";\n}\n.icon-minus-sign:before {\n  content: \"\\f056\";\n}\n.icon-remove-sign:before {\n  content: \"\\f057\";\n}\n.icon-ok-sign:before {\n  content: \"\\f058\";\n}\n.icon-question-sign:before {\n  content: \"\\f059\";\n}\n.icon-info-sign:before {\n  content: \"\\f05a\";\n}\n.icon-screenshot:before {\n  content: \"\\f05b\";\n}\n.icon-remove-circle:before {\n  content: \"\\f05c\";\n}\n.icon-ok-circle:before {\n  content: \"\\f05d\";\n}\n.icon-ban-circle:before {\n  content: \"\\f05e\";\n}\n.icon-arrow-left:before {\n  content: \"\\f060\";\n}\n.icon-arrow-right:before {\n  content: \"\\f061\";\n}\n.icon-arrow-up:before {\n  content: \"\\f062\";\n}\n.icon-arrow-down:before {\n  content: \"\\f063\";\n}\n.icon-mail-forward:before,\n.icon-share-alt:before {\n  content: \"\\f064\";\n}\n.icon-resize-full:before {\n  content: \"\\f065\";\n}\n.icon-resize-small:before {\n  content: \"\\f066\";\n}\n.icon-plus:before {\n  content: \"\\f067\";\n}\n.icon-minus:before {\n  content: \"\\f068\";\n}\n.icon-asterisk:before {\n  content: \"\\f069\";\n}\n.icon-exclamation-sign:before {\n  content: \"\\f06a\";\n}\n.icon-gift:before {\n  content: \"\\f06b\";\n}\n.icon-leaf:before {\n  content: \"\\f06c\";\n}\n.icon-fire:before {\n  content: \"\\f06d\";\n}\n.icon-eye-open:before {\n  content: \"\\f06e\";\n}\n.icon-eye-close:before {\n  content: \"\\f070\";\n}\n.icon-warning-sign:before {\n  content: \"\\f071\";\n}\n.icon-plane:before {\n  content: \"\\f072\";\n}\n.icon-calendar:before {\n  content: \"\\f073\";\n}\n.icon-random:before {\n  content: \"\\f074\";\n}\n.icon-comment:before {\n  content: \"\\f075\";\n}\n.icon-magnet:before {\n  content: \"\\f076\";\n}\n.icon-chevron-up:before {\n  content: \"\\f077\";\n}\n.icon-chevron-down:before {\n  content: \"\\f078\";\n}\n.icon-retweet:before {\n  content: \"\\f079\";\n}\n.icon-shopping-cart:before {\n  content: \"\\f07a\";\n}\n.icon-folder-close:before {\n  content: \"\\f07b\";\n}\n.icon-folder-open:before {\n  content: \"\\f07c\";\n}\n.icon-resize-vertical:before {\n  content: \"\\f07d\";\n}\n.icon-resize-horizontal:before {\n  content: \"\\f07e\";\n}\n.icon-bar-chart:before {\n  content: \"\\f080\";\n}\n.icon-twitter-sign:before {\n  content: \"\\f081\";\n}\n.icon-facebook-sign:before {\n  content: \"\\f082\";\n}\n.icon-camera-retro:before {\n  content: \"\\f083\";\n}\n.icon-key:before {\n  content: \"\\f084\";\n}\n.icon-gears:before,\n.icon-cogs:before {\n  content: \"\\f085\";\n}\n.icon-comments:before {\n  content: \"\\f086\";\n}\n.icon-thumbs-up-alt:before {\n  content: \"\\f087\";\n}\n.icon-thumbs-down-alt:before {\n  content: \"\\f088\";\n}\n.icon-star-half:before {\n  content: \"\\f089\";\n}\n.icon-heart-empty:before {\n  content: \"\\f08a\";\n}\n.icon-signout:before {\n  content: \"\\f08b\";\n}\n.icon-linkedin-sign:before {\n  content: \"\\f08c\";\n}\n.icon-pushpin:before {\n  content: \"\\f08d\";\n}\n.icon-external-link:before {\n  content: \"\\f08e\";\n}\n.icon-signin:before {\n  content: \"\\f090\";\n}\n.icon-trophy:before {\n  content: \"\\f091\";\n}\n.icon-github-sign:before {\n  content: \"\\f092\";\n}\n.icon-upload-alt:before {\n  content: \"\\f093\";\n}\n.icon-lemon:before {\n  content: \"\\f094\";\n}\n.icon-phone:before {\n  content: \"\\f095\";\n}\n.icon-unchecked:before,\n.icon-check-empty:before {\n  content: \"\\f096\";\n}\n.icon-bookmark-empty:before {\n  content: \"\\f097\";\n}\n.icon-phone-sign:before {\n  content: \"\\f098\";\n}\n.icon-twitter:before {\n  content: \"\\f099\";\n}\n.icon-facebook:before {\n  content: \"\\f09a\";\n}\n.icon-github:before {\n  content: \"\\f09b\";\n}\n.icon-unlock:before {\n  content: \"\\f09c\";\n}\n.icon-credit-card:before {\n  content: \"\\f09d\";\n}\n.icon-rss:before {\n  content: \"\\f09e\";\n}\n.icon-hdd:before {\n  content: \"\\f0a0\";\n}\n.icon-bullhorn:before {\n  content: \"\\f0a1\";\n}\n.icon-bell:before {\n  content: \"\\f0a2\";\n}\n.icon-certificate:before {\n  content: \"\\f0a3\";\n}\n.icon-hand-right:before {\n  content: \"\\f0a4\";\n}\n.icon-hand-left:before {\n  content: \"\\f0a5\";\n}\n.icon-hand-up:before {\n  content: \"\\f0a6\";\n}\n.icon-hand-down:before {\n  content: \"\\f0a7\";\n}\n.icon-circle-arrow-left:before {\n  content: \"\\f0a8\";\n}\n.icon-circle-arrow-right:before {\n  content: \"\\f0a9\";\n}\n.icon-circle-arrow-up:before {\n  content: \"\\f0aa\";\n}\n.icon-circle-arrow-down:before {\n  content: \"\\f0ab\";\n}\n.icon-globe:before {\n  content: \"\\f0ac\";\n}\n.icon-wrench:before {\n  content: \"\\f0ad\";\n}\n.icon-tasks:before {\n  content: \"\\f0ae\";\n}\n.icon-filter:before {\n  content: \"\\f0b0\";\n}\n.icon-briefcase:before {\n  content: \"\\f0b1\";\n}\n.icon-fullscreen:before {\n  content: \"\\f0b2\";\n}\n.icon-group:before {\n  content: \"\\f0c0\";\n}\n.icon-link:before {\n  content: \"\\f0c1\";\n}\n.icon-cloud:before {\n  content: \"\\f0c2\";\n}\n.icon-beaker:before {\n  content: \"\\f0c3\";\n}\n.icon-cut:before {\n  content: \"\\f0c4\";\n}\n.icon-copy:before {\n  content: \"\\f0c5\";\n}\n.icon-paperclip:before,\n.icon-paper-clip:before {\n  content: \"\\f0c6\";\n}\n.icon-save:before {\n  content: \"\\f0c7\";\n}\n.icon-sign-blank:before {\n  content: \"\\f0c8\";\n}\n.icon-reorder:before {\n  content: \"\\f0c9\";\n}\n.icon-list-ul:before {\n  content: \"\\f0ca\";\n}\n.icon-list-ol:before {\n  content: \"\\f0cb\";\n}\n.icon-strikethrough:before {\n  content: \"\\f0cc\";\n}\n.icon-underline:before {\n  content: \"\\f0cd\";\n}\n.icon-table:before {\n  content: \"\\f0ce\";\n}\n.icon-magic:before {\n  content: \"\\f0d0\";\n}\n.icon-truck:before {\n  content: \"\\f0d1\";\n}\n.icon-pinterest:before {\n  content: \"\\f0d2\";\n}\n.icon-pinterest-sign:before {\n  content: \"\\f0d3\";\n}\n.icon-google-plus-sign:before {\n  content: \"\\f0d4\";\n}\n.icon-google-plus:before {\n  content: \"\\f0d5\";\n}\n.icon-money:before {\n  content: \"\\f0d6\";\n}\n.icon-caret-down:before {\n  content: \"\\f0d7\";\n}\n.icon-caret-up:before {\n  content: \"\\f0d8\";\n}\n.icon-caret-left:before {\n  content: \"\\f0d9\";\n}\n.icon-caret-right:before {\n  content: \"\\f0da\";\n}\n.icon-columns:before {\n  content: \"\\f0db\";\n}\n.icon-sort:before {\n  content: \"\\f0dc\";\n}\n.icon-sort-down:before {\n  content: \"\\f0dd\";\n}\n.icon-sort-up:before {\n  content: \"\\f0de\";\n}\n.icon-envelope:before {\n  content: \"\\f0e0\";\n}\n.icon-linkedin:before {\n  content: \"\\f0e1\";\n}\n.icon-rotate-left:before,\n.icon-undo:before {\n  content: \"\\f0e2\";\n}\n.icon-legal:before {\n  content: \"\\f0e3\";\n}\n.icon-dashboard:before {\n  content: \"\\f0e4\";\n}\n.icon-comment-alt:before {\n  content: \"\\f0e5\";\n}\n.icon-comments-alt:before {\n  content: \"\\f0e6\";\n}\n.icon-bolt:before {\n  content: \"\\f0e7\";\n}\n.icon-sitemap:before {\n  content: \"\\f0e8\";\n}\n.icon-umbrella:before {\n  content: \"\\f0e9\";\n}\n.icon-paste:before {\n  content: \"\\f0ea\";\n}\n.icon-lightbulb:before {\n  content: \"\\f0eb\";\n}\n.icon-exchange:before {\n  content: \"\\f0ec\";\n}\n.icon-cloud-download:before {\n  content: \"\\f0ed\";\n}\n.icon-cloud-upload:before {\n  content: \"\\f0ee\";\n}\n.icon-user-md:before {\n  content: \"\\f0f0\";\n}\n.icon-stethoscope:before {\n  content: \"\\f0f1\";\n}\n.icon-suitcase:before {\n  content: \"\\f0f2\";\n}\n.icon-bell-alt:before {\n  content: \"\\f0f3\";\n}\n.icon-coffee:before {\n  content: \"\\f0f4\";\n}\n.icon-food:before {\n  content: \"\\f0f5\";\n}\n.icon-file-text-alt:before {\n  content: \"\\f0f6\";\n}\n.icon-building:before {\n  content: \"\\f0f7\";\n}\n.icon-hospital:before {\n  content: \"\\f0f8\";\n}\n.icon-ambulance:before {\n  content: \"\\f0f9\";\n}\n.icon-medkit:before {\n  content: \"\\f0fa\";\n}\n.icon-fighter-jet:before {\n  content: \"\\f0fb\";\n}\n.icon-beer:before {\n  content: \"\\f0fc\";\n}\n.icon-h-sign:before {\n  content: \"\\f0fd\";\n}\n.icon-plus-sign-alt:before {\n  content: \"\\f0fe\";\n}\n.icon-double-angle-left:before {\n  content: \"\\f100\";\n}\n.icon-double-angle-right:before {\n  content: \"\\f101\";\n}\n.icon-double-angle-up:before {\n  content: \"\\f102\";\n}\n.icon-double-angle-down:before {\n  content: \"\\f103\";\n}\n.icon-angle-left:before {\n  content: \"\\f104\";\n}\n.icon-angle-right:before {\n  content: \"\\f105\";\n}\n.icon-angle-up:before {\n  content: \"\\f106\";\n}\n.icon-angle-down:before {\n  content: \"\\f107\";\n}\n.icon-desktop:before {\n  content: \"\\f108\";\n}\n.icon-laptop:before {\n  content: \"\\f109\";\n}\n.icon-tablet:before {\n  content: \"\\f10a\";\n}\n.icon-mobile-phone:before {\n  content: \"\\f10b\";\n}\n.icon-circle-blank:before {\n  content: \"\\f10c\";\n}\n.icon-quote-left:before {\n  content: \"\\f10d\";\n}\n.icon-quote-right:before {\n  content: \"\\f10e\";\n}\n.icon-spinner:before {\n  content: \"\\f110\";\n}\n.icon-circle:before {\n  content: \"\\f111\";\n}\n.icon-mail-reply:before,\n.icon-reply:before {\n  content: \"\\f112\";\n}\n.icon-github-alt:before {\n  content: \"\\f113\";\n}\n.icon-folder-close-alt:before {\n  content: \"\\f114\";\n}\n.icon-folder-open-alt:before {\n  content: \"\\f115\";\n}\n.icon-expand-alt:before {\n  content: \"\\f116\";\n}\n.icon-collapse-alt:before {\n  content: \"\\f117\";\n}\n.icon-smile:before {\n  content: \"\\f118\";\n}\n.icon-frown:before {\n  content: \"\\f119\";\n}\n.icon-meh:before {\n  content: \"\\f11a\";\n}\n.icon-gamepad:before {\n  content: \"\\f11b\";\n}\n.icon-keyboard:before {\n  content: \"\\f11c\";\n}\n.icon-flag-alt:before {\n  content: \"\\f11d\";\n}\n.icon-flag-checkered:before {\n  content: \"\\f11e\";\n}\n.icon-terminal:before {\n  content: \"\\f120\";\n}\n.icon-code:before {\n  content: \"\\f121\";\n}\n.icon-reply-all:before {\n  content: \"\\f122\";\n}\n.icon-mail-reply-all:before {\n  content: \"\\f122\";\n}\n.icon-star-half-full:before,\n.icon-star-half-empty:before {\n  content: \"\\f123\";\n}\n.icon-location-arrow:before {\n  content: \"\\f124\";\n}\n.icon-crop:before {\n  content: \"\\f125\";\n}\n.icon-code-fork:before {\n  content: \"\\f126\";\n}\n.icon-unlink:before {\n  content: \"\\f127\";\n}\n.icon-question:before {\n  content: \"\\f128\";\n}\n.icon-info:before {\n  content: \"\\f129\";\n}\n.icon-exclamation:before {\n  content: \"\\f12a\";\n}\n.icon-superscript:before {\n  content: \"\\f12b\";\n}\n.icon-subscript:before {\n  content: \"\\f12c\";\n}\n.icon-eraser:before {\n  content: \"\\f12d\";\n}\n.icon-puzzle-piece:before {\n  content: \"\\f12e\";\n}\n.icon-microphone:before {\n  content: \"\\f130\";\n}\n.icon-microphone-off:before {\n  content: \"\\f131\";\n}\n.icon-shield:before {\n  content: \"\\f132\";\n}\n.icon-calendar-empty:before {\n  content: \"\\f133\";\n}\n.icon-fire-extinguisher:before {\n  content: \"\\f134\";\n}\n.icon-rocket:before {\n  content: \"\\f135\";\n}\n.icon-maxcdn:before {\n  content: \"\\f136\";\n}\n.icon-chevron-sign-left:before {\n  content: \"\\f137\";\n}\n.icon-chevron-sign-right:before {\n  content: \"\\f138\";\n}\n.icon-chevron-sign-up:before {\n  content: \"\\f139\";\n}\n.icon-chevron-sign-down:before {\n  content: \"\\f13a\";\n}\n.icon-html5:before {\n  content: \"\\f13b\";\n}\n.icon-css3:before {\n  content: \"\\f13c\";\n}\n.icon-anchor:before {\n  content: \"\\f13d\";\n}\n.icon-unlock-alt:before {\n  content: \"\\f13e\";\n}\n.icon-bullseye:before {\n  content: \"\\f140\";\n}\n.icon-ellipsis-horizontal:before {\n  content: \"\\f141\";\n}\n.icon-ellipsis-vertical:before {\n  content: \"\\f142\";\n}\n.icon-rss-sign:before {\n  content: \"\\f143\";\n}\n.icon-play-sign:before {\n  content: \"\\f144\";\n}\n.icon-ticket:before {\n  content: \"\\f145\";\n}\n.icon-minus-sign-alt:before {\n  content: \"\\f146\";\n}\n.icon-check-minus:before {\n  content: \"\\f147\";\n}\n.icon-level-up:before {\n  content: \"\\f148\";\n}\n.icon-level-down:before {\n  content: \"\\f149\";\n}\n.icon-check-sign:before {\n  content: \"\\f14a\";\n}\n.icon-edit-sign:before {\n  content: \"\\f14b\";\n}\n.icon-external-link-sign:before {\n  content: \"\\f14c\";\n}\n.icon-share-sign:before {\n  content: \"\\f14d\";\n}\n.icon-compass:before {\n  content: \"\\f14e\";\n}\n.icon-collapse:before {\n  content: \"\\f150\";\n}\n.icon-collapse-top:before {\n  content: \"\\f151\";\n}\n.icon-expand:before {\n  content: \"\\f152\";\n}\n.icon-euro:before,\n.icon-eur:before {\n  content: \"\\f153\";\n}\n.icon-gbp:before {\n  content: \"\\f154\";\n}\n.icon-dollar:before,\n.icon-usd:before {\n  content: \"\\f155\";\n}\n.icon-rupee:before,\n.icon-inr:before {\n  content: \"\\f156\";\n}\n.icon-yen:before,\n.icon-jpy:before {\n  content: \"\\f157\";\n}\n.icon-renminbi:before,\n.icon-cny:before {\n  content: \"\\f158\";\n}\n.icon-won:before,\n.icon-krw:before {\n  content: \"\\f159\";\n}\n.icon-bitcoin:before,\n.icon-btc:before {\n  content: \"\\f15a\";\n}\n.icon-file:before {\n  content: \"\\f15b\";\n}\n.icon-file-text:before {\n  content: \"\\f15c\";\n}\n.icon-sort-by-alphabet:before {\n  content: \"\\f15d\";\n}\n.icon-sort-by-alphabet-alt:before {\n  content: \"\\f15e\";\n}\n.icon-sort-by-attributes:before {\n  content: \"\\f160\";\n}\n.icon-sort-by-attributes-alt:before {\n  content: \"\\f161\";\n}\n.icon-sort-by-order:before {\n  content: \"\\f162\";\n}\n.icon-sort-by-order-alt:before {\n  content: \"\\f163\";\n}\n.icon-thumbs-up:before {\n  content: \"\\f164\";\n}\n.icon-thumbs-down:before {\n  content: \"\\f165\";\n}\n.icon-youtube-sign:before {\n  content: \"\\f166\";\n}\n.icon-youtube:before {\n  content: \"\\f167\";\n}\n.icon-xing:before {\n  content: \"\\f168\";\n}\n.icon-xing-sign:before {\n  content: \"\\f169\";\n}\n.icon-youtube-play:before {\n  content: \"\\f16a\";\n}\n.icon-dropbox:before {\n  content: \"\\f16b\";\n}\n.icon-stackexchange:before {\n  content: \"\\f16c\";\n}\n.icon-instagram:before {\n  content: \"\\f16d\";\n}\n.icon-flickr:before {\n  content: \"\\f16e\";\n}\n.icon-adn:before {\n  content: \"\\f170\";\n}\n.icon-bitbucket:before {\n  content: \"\\f171\";\n}\n.icon-bitbucket-sign:before {\n  content: \"\\f172\";\n}\n.icon-tumblr:before {\n  content: \"\\f173\";\n}\n.icon-tumblr-sign:before {\n  content: \"\\f174\";\n}\n.icon-long-arrow-down:before {\n  content: \"\\f175\";\n}\n.icon-long-arrow-up:before {\n  content: \"\\f176\";\n}\n.icon-long-arrow-left:before {\n  content: \"\\f177\";\n}\n.icon-long-arrow-right:before {\n  content: \"\\f178\";\n}\n.icon-apple:before {\n  content: \"\\f179\";\n}\n.icon-windows:before {\n  content: \"\\f17a\";\n}\n.icon-android:before {\n  content: \"\\f17b\";\n}\n.icon-linux:before {\n  content: \"\\f17c\";\n}\n.icon-dribbble:before {\n  content: \"\\f17d\";\n}\n.icon-skype:before {\n  content: \"\\f17e\";\n}\n.icon-foursquare:before {\n  content: \"\\f180\";\n}\n.icon-trello:before {\n  content: \"\\f181\";\n}\n.icon-female:before {\n  content: \"\\f182\";\n}\n.icon-male:before {\n  content: \"\\f183\";\n}\n.icon-gittip:before {\n  content: \"\\f184\";\n}\n.icon-sun:before {\n  content: \"\\f185\";\n}\n.icon-moon:before {\n  content: \"\\f186\";\n}\n.icon-archive:before {\n  content: \"\\f187\";\n}\n.icon-bug:before {\n  content: \"\\f188\";\n}\n.icon-vk:before {\n  content: \"\\f189\";\n}\n.icon-weibo:before {\n  content: \"\\f18a\";\n}\n.icon-renren:before {\n  content: \"\\f18b\";\n}\n"
  },
  {
    "path": "explainshell/web/static/js/bootstrap.js",
    "content": "/* ===================================================\n * bootstrap-transition.js v2.3.1\n * http://twitter.github.com/bootstrap/javascript.html#transitions\n * ===================================================\n * Copyright 2012 Twitter, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * ========================================================== */\n\n\n!function ($) {\n\n  \"use strict\"; // jshint ;_;\n\n\n  /* CSS TRANSITION SUPPORT (http://www.modernizr.com/)\n   * ======================================================= */\n\n  $(function () {\n\n    $.support.transition = (function () {\n\n      var transitionEnd = (function () {\n\n        var el = document.createElement('bootstrap')\n          , transEndEventNames = {\n               'WebkitTransition' : 'webkitTransitionEnd'\n            ,  'MozTransition'    : 'transitionend'\n            ,  'OTransition'      : 'oTransitionEnd otransitionend'\n            ,  'transition'       : 'transitionend'\n            }\n          , name\n\n        for (name in transEndEventNames){\n          if (el.style[name] !== undefined) {\n            return transEndEventNames[name]\n          }\n        }\n\n      }())\n\n      return transitionEnd && {\n        end: transitionEnd\n      }\n\n    })()\n\n  })\n\n}(window.jQuery);/* ==========================================================\n * bootstrap-alert.js v2.3.1\n * http://twitter.github.com/bootstrap/javascript.html#alerts\n * ==========================================================\n * Copyright 2012 Twitter, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * ========================================================== */\n\n\n!function ($) {\n\n  \"use strict\"; // jshint ;_;\n\n\n /* ALERT CLASS DEFINITION\n  * ====================== */\n\n  var dismiss = '[data-dismiss=\"alert\"]'\n    , Alert = function (el) {\n        $(el).on('click', dismiss, this.close)\n      }\n\n  Alert.prototype.close = function (e) {\n    var $this = $(this)\n      , selector = $this.attr('data-target')\n      , $parent\n\n    if (!selector) {\n      selector = $this.attr('href')\n      selector = selector && selector.replace(/.*(?=#[^\\s]*$)/, '') //strip for ie7\n    }\n\n    $parent = $(selector)\n\n    e && e.preventDefault()\n\n    $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent())\n\n    $parent.trigger(e = $.Event('close'))\n\n    if (e.isDefaultPrevented()) return\n\n    $parent.removeClass('in')\n\n    function removeElement() {\n      $parent\n        .trigger('closed')\n        .remove()\n    }\n\n    $.support.transition && $parent.hasClass('fade') ?\n      $parent.on($.support.transition.end, removeElement) :\n      removeElement()\n  }\n\n\n /* ALERT PLUGIN DEFINITION\n  * ======================= */\n\n  var old = $.fn.alert\n\n  $.fn.alert = function (option) {\n    return this.each(function () {\n      var $this = $(this)\n        , data = $this.data('alert')\n      if (!data) $this.data('alert', (data = new Alert(this)))\n      if (typeof option == 'string') data[option].call($this)\n    })\n  }\n\n  $.fn.alert.Constructor = Alert\n\n\n /* ALERT NO CONFLICT\n  * ================= */\n\n  $.fn.alert.noConflict = function () {\n    $.fn.alert = old\n    return this\n  }\n\n\n /* ALERT DATA-API\n  * ============== */\n\n  $(document).on('click.alert.data-api', dismiss, Alert.prototype.close)\n\n}(window.jQuery);/* ============================================================\n * bootstrap-button.js v2.3.1\n * http://twitter.github.com/bootstrap/javascript.html#buttons\n * ============================================================\n * Copyright 2012 Twitter, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * ============================================================ */\n\n\n!function ($) {\n\n  \"use strict\"; // jshint ;_;\n\n\n /* BUTTON PUBLIC CLASS DEFINITION\n  * ============================== */\n\n  var Button = function (element, options) {\n    this.$element = $(element)\n    this.options = $.extend({}, $.fn.button.defaults, options)\n  }\n\n  Button.prototype.setState = function (state) {\n    var d = 'disabled'\n      , $el = this.$element\n      , data = $el.data()\n      , val = $el.is('input') ? 'val' : 'html'\n\n    state = state + 'Text'\n    data.resetText || $el.data('resetText', $el[val]())\n\n    $el[val](data[state] || this.options[state])\n\n    // push to event loop to allow forms to submit\n    setTimeout(function () {\n      state == 'loadingText' ?\n        $el.addClass(d).attr(d, d) :\n        $el.removeClass(d).removeAttr(d)\n    }, 0)\n  }\n\n  Button.prototype.toggle = function () {\n    var $parent = this.$element.closest('[data-toggle=\"buttons-radio\"]')\n\n    $parent && $parent\n      .find('.active')\n      .removeClass('active')\n\n    this.$element.toggleClass('active')\n  }\n\n\n /* BUTTON PLUGIN DEFINITION\n  * ======================== */\n\n  var old = $.fn.button\n\n  $.fn.button = function (option) {\n    return this.each(function () {\n      var $this = $(this)\n        , data = $this.data('button')\n        , options = typeof option == 'object' && option\n      if (!data) $this.data('button', (data = new Button(this, options)))\n      if (option == 'toggle') data.toggle()\n      else if (option) data.setState(option)\n    })\n  }\n\n  $.fn.button.defaults = {\n    loadingText: 'loading...'\n  }\n\n  $.fn.button.Constructor = Button\n\n\n /* BUTTON NO CONFLICT\n  * ================== */\n\n  $.fn.button.noConflict = function () {\n    $.fn.button = old\n    return this\n  }\n\n\n /* BUTTON DATA-API\n  * =============== */\n\n  $(document).on('click.button.data-api', '[data-toggle^=button]', function (e) {\n    var $btn = $(e.target)\n    if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')\n    $btn.button('toggle')\n  })\n\n}(window.jQuery);/* ==========================================================\n * bootstrap-carousel.js v2.3.1\n * http://twitter.github.com/bootstrap/javascript.html#carousel\n * ==========================================================\n * Copyright 2012 Twitter, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * ========================================================== */\n\n\n!function ($) {\n\n  \"use strict\"; // jshint ;_;\n\n\n /* CAROUSEL CLASS DEFINITION\n  * ========================= */\n\n  var Carousel = function (element, options) {\n    this.$element = $(element)\n    this.$indicators = this.$element.find('.carousel-indicators')\n    this.options = options\n    this.options.pause == 'hover' && this.$element\n      .on('mouseenter', $.proxy(this.pause, this))\n      .on('mouseleave', $.proxy(this.cycle, this))\n  }\n\n  Carousel.prototype = {\n\n    cycle: function (e) {\n      if (!e) this.paused = false\n      if (this.interval) clearInterval(this.interval);\n      this.options.interval\n        && !this.paused\n        && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))\n      return this\n    }\n\n  , getActiveIndex: function () {\n      this.$active = this.$element.find('.item.active')\n      this.$items = this.$active.parent().children()\n      return this.$items.index(this.$active)\n    }\n\n  , to: function (pos) {\n      var activeIndex = this.getActiveIndex()\n        , that = this\n\n      if (pos > (this.$items.length - 1) || pos < 0) return\n\n      if (this.sliding) {\n        return this.$element.one('slid', function () {\n          that.to(pos)\n        })\n      }\n\n      if (activeIndex == pos) {\n        return this.pause().cycle()\n      }\n\n      return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos]))\n    }\n\n  , pause: function (e) {\n      if (!e) this.paused = true\n      if (this.$element.find('.next, .prev').length && $.support.transition.end) {\n        this.$element.trigger($.support.transition.end)\n        this.cycle(true)\n      }\n      clearInterval(this.interval)\n      this.interval = null\n      return this\n    }\n\n  , next: function () {\n      if (this.sliding) return\n      return this.slide('next')\n    }\n\n  , prev: function () {\n      if (this.sliding) return\n      return this.slide('prev')\n    }\n\n  , slide: function (type, next) {\n      var $active = this.$element.find('.item.active')\n        , $next = next || $active[type]()\n        , isCycling = this.interval\n        , direction = type == 'next' ? 'left' : 'right'\n        , fallback  = type == 'next' ? 'first' : 'last'\n        , that = this\n        , e\n\n      this.sliding = true\n\n      isCycling && this.pause()\n\n      $next = $next.length ? $next : this.$element.find('.item')[fallback]()\n\n      e = $.Event('slide', {\n        relatedTarget: $next[0]\n      , direction: direction\n      })\n\n      if ($next.hasClass('active')) return\n\n      if (this.$indicators.length) {\n        this.$indicators.find('.active').removeClass('active')\n        this.$element.one('slid', function () {\n          var $nextIndicator = $(that.$indicators.children()[that.getActiveIndex()])\n          $nextIndicator && $nextIndicator.addClass('active')\n        })\n      }\n\n      if ($.support.transition && this.$element.hasClass('slide')) {\n        this.$element.trigger(e)\n        if (e.isDefaultPrevented()) return\n        $next.addClass(type)\n        $next[0].offsetWidth // force reflow\n        $active.addClass(direction)\n        $next.addClass(direction)\n        this.$element.one($.support.transition.end, function () {\n          $next.removeClass([type, direction].join(' ')).addClass('active')\n          $active.removeClass(['active', direction].join(' '))\n          that.sliding = false\n          setTimeout(function () { that.$element.trigger('slid') }, 0)\n        })\n      } else {\n        this.$element.trigger(e)\n        if (e.isDefaultPrevented()) return\n        $active.removeClass('active')\n        $next.addClass('active')\n        this.sliding = false\n        this.$element.trigger('slid')\n      }\n\n      isCycling && this.cycle()\n\n      return this\n    }\n\n  }\n\n\n /* CAROUSEL PLUGIN DEFINITION\n  * ========================== */\n\n  var old = $.fn.carousel\n\n  $.fn.carousel = function (option) {\n    return this.each(function () {\n      var $this = $(this)\n        , data = $this.data('carousel')\n        , options = $.extend({}, $.fn.carousel.defaults, typeof option == 'object' && option)\n        , action = typeof option == 'string' ? option : options.slide\n      if (!data) $this.data('carousel', (data = new Carousel(this, options)))\n      if (typeof option == 'number') data.to(option)\n      else if (action) data[action]()\n      else if (options.interval) data.pause().cycle()\n    })\n  }\n\n  $.fn.carousel.defaults = {\n    interval: 5000\n  , pause: 'hover'\n  }\n\n  $.fn.carousel.Constructor = Carousel\n\n\n /* CAROUSEL NO CONFLICT\n  * ==================== */\n\n  $.fn.carousel.noConflict = function () {\n    $.fn.carousel = old\n    return this\n  }\n\n /* CAROUSEL DATA-API\n  * ================= */\n\n  $(document).on('click.carousel.data-api', '[data-slide], [data-slide-to]', function (e) {\n    var $this = $(this), href\n      , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\\s]+$)/, '')) //strip for ie7\n      , options = $.extend({}, $target.data(), $this.data())\n      , slideIndex\n\n    $target.carousel(options)\n\n    if (slideIndex = $this.attr('data-slide-to')) {\n      $target.data('carousel').pause().to(slideIndex).cycle()\n    }\n\n    e.preventDefault()\n  })\n\n}(window.jQuery);/* =============================================================\n * bootstrap-collapse.js v2.3.1\n * http://twitter.github.com/bootstrap/javascript.html#collapse\n * =============================================================\n * Copyright 2012 Twitter, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * ============================================================ */\n\n\n!function ($) {\n\n  \"use strict\"; // jshint ;_;\n\n\n /* COLLAPSE PUBLIC CLASS DEFINITION\n  * ================================ */\n\n  var Collapse = function (element, options) {\n    this.$element = $(element)\n    this.options = $.extend({}, $.fn.collapse.defaults, options)\n\n    if (this.options.parent) {\n      this.$parent = $(this.options.parent)\n    }\n\n    this.options.toggle && this.toggle()\n  }\n\n  Collapse.prototype = {\n\n    constructor: Collapse\n\n  , dimension: function () {\n      var hasWidth = this.$element.hasClass('width')\n      return hasWidth ? 'width' : 'height'\n    }\n\n  , show: function () {\n      var dimension\n        , scroll\n        , actives\n        , hasData\n\n      if (this.transitioning || this.$element.hasClass('in')) return\n\n      dimension = this.dimension()\n      scroll = $.camelCase(['scroll', dimension].join('-'))\n      actives = this.$parent && this.$parent.find('> .accordion-group > .in')\n\n      if (actives && actives.length) {\n        hasData = actives.data('collapse')\n        if (hasData && hasData.transitioning) return\n        actives.collapse('hide')\n        hasData || actives.data('collapse', null)\n      }\n\n      this.$element[dimension](0)\n      this.transition('addClass', $.Event('show'), 'shown')\n      $.support.transition && this.$element[dimension](this.$element[0][scroll])\n    }\n\n  , hide: function () {\n      var dimension\n      if (this.transitioning || !this.$element.hasClass('in')) return\n      dimension = this.dimension()\n      this.reset(this.$element[dimension]())\n      this.transition('removeClass', $.Event('hide'), 'hidden')\n      this.$element[dimension](0)\n    }\n\n  , reset: function (size) {\n      var dimension = this.dimension()\n\n      this.$element\n        .removeClass('collapse')\n        [dimension](size || 'auto')\n        [0].offsetWidth\n\n      this.$element[size !== null ? 'addClass' : 'removeClass']('collapse')\n\n      return this\n    }\n\n  , transition: function (method, startEvent, completeEvent) {\n      var that = this\n        , complete = function () {\n            if (startEvent.type == 'show') that.reset()\n            that.transitioning = 0\n            that.$element.trigger(completeEvent)\n          }\n\n      this.$element.trigger(startEvent)\n\n      if (startEvent.isDefaultPrevented()) return\n\n      this.transitioning = 1\n\n      this.$element[method]('in')\n\n      $.support.transition && this.$element.hasClass('collapse') ?\n        this.$element.one($.support.transition.end, complete) :\n        complete()\n    }\n\n  , toggle: function () {\n      this[this.$element.hasClass('in') ? 'hide' : 'show']()\n    }\n\n  }\n\n\n /* COLLAPSE PLUGIN DEFINITION\n  * ========================== */\n\n  var old = $.fn.collapse\n\n  $.fn.collapse = function (option) {\n    return this.each(function () {\n      var $this = $(this)\n        , data = $this.data('collapse')\n        , options = $.extend({}, $.fn.collapse.defaults, $this.data(), typeof option == 'object' && option)\n      if (!data) $this.data('collapse', (data = new Collapse(this, options)))\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  $.fn.collapse.defaults = {\n    toggle: true\n  }\n\n  $.fn.collapse.Constructor = Collapse\n\n\n /* COLLAPSE NO CONFLICT\n  * ==================== */\n\n  $.fn.collapse.noConflict = function () {\n    $.fn.collapse = old\n    return this\n  }\n\n\n /* COLLAPSE DATA-API\n  * ================= */\n\n  $(document).on('click.collapse.data-api', '[data-toggle=collapse]', function (e) {\n    var $this = $(this), href\n      , target = $this.attr('data-target')\n        || e.preventDefault()\n        || (href = $this.attr('href')) && href.replace(/.*(?=#[^\\s]+$)/, '') //strip for ie7\n      , option = $(target).data('collapse') ? 'toggle' : $this.data()\n    $this[$(target).hasClass('in') ? 'addClass' : 'removeClass']('collapsed')\n    $(target).collapse(option)\n  })\n\n}(window.jQuery);/* ============================================================\n * bootstrap-dropdown.js v2.3.1\n * http://twitter.github.com/bootstrap/javascript.html#dropdowns\n * ============================================================\n * Copyright 2012 Twitter, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * ============================================================ */\n\n\n!function ($) {\n\n  \"use strict\"; // jshint ;_;\n\n\n /* DROPDOWN CLASS DEFINITION\n  * ========================= */\n\n  var toggle = '[data-toggle=dropdown]'\n    , Dropdown = function (element) {\n        var $el = $(element).on('click.dropdown.data-api', this.toggle)\n        $('html').on('click.dropdown.data-api', function () {\n          $el.parent().removeClass('open')\n        })\n      }\n\n  Dropdown.prototype = {\n\n    constructor: Dropdown\n\n  , toggle: function (e) {\n      var $this = $(this)\n        , $parent\n        , isActive\n\n      if ($this.is('.disabled, :disabled')) return\n\n      $parent = getParent($this)\n\n      isActive = $parent.hasClass('open')\n\n      clearMenus()\n\n      if (!isActive) {\n        $parent.toggleClass('open')\n      }\n\n      $this.focus()\n\n      return false\n    }\n\n  , keydown: function (e) {\n      var $this\n        , $items\n        , $active\n        , $parent\n        , isActive\n        , index\n\n      if (!/(38|40|27)/.test(e.keyCode)) return\n\n      $this = $(this)\n\n      e.preventDefault()\n      e.stopPropagation()\n\n      if ($this.is('.disabled, :disabled')) return\n\n      $parent = getParent($this)\n\n      isActive = $parent.hasClass('open')\n\n      if (!isActive || (isActive && e.keyCode == 27)) {\n        if (e.which == 27) $parent.find(toggle).focus()\n        return $this.click()\n      }\n\n      $items = $('[role=menu] li:not(.divider):visible a', $parent)\n\n      if (!$items.length) return\n\n      index = $items.index($items.filter(':focus'))\n\n      if (e.keyCode == 38 && index > 0) index--                                        // up\n      if (e.keyCode == 40 && index < $items.length - 1) index++                        // down\n      if (!~index) index = 0\n\n      $items\n        .eq(index)\n        .focus()\n    }\n\n  }\n\n  function clearMenus() {\n    $(toggle).each(function () {\n      getParent($(this)).removeClass('open')\n    })\n  }\n\n  function getParent($this) {\n    var selector = $this.attr('data-target')\n      , $parent\n\n    if (!selector) {\n      selector = $this.attr('href')\n      selector = selector && /#/.test(selector) && selector.replace(/.*(?=#[^\\s]*$)/, '') //strip for ie7\n    }\n\n    $parent = selector && $(selector)\n\n    if (!$parent || !$parent.length) $parent = $this.parent()\n\n    return $parent\n  }\n\n\n  /* DROPDOWN PLUGIN DEFINITION\n   * ========================== */\n\n  var old = $.fn.dropdown\n\n  $.fn.dropdown = function (option) {\n    return this.each(function () {\n      var $this = $(this)\n        , data = $this.data('dropdown')\n      if (!data) $this.data('dropdown', (data = new Dropdown(this)))\n      if (typeof option == 'string') data[option].call($this)\n    })\n  }\n\n  $.fn.dropdown.Constructor = Dropdown\n\n\n /* DROPDOWN NO CONFLICT\n  * ==================== */\n\n  $.fn.dropdown.noConflict = function () {\n    $.fn.dropdown = old\n    return this\n  }\n\n\n  /* APPLY TO STANDARD DROPDOWN ELEMENTS\n   * =================================== */\n\n  $(document)\n    .on('click.dropdown.data-api', clearMenus)\n    .on('click.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })\n    .on('click.dropdown-menu', function (e) { e.stopPropagation() })\n    .on('click.dropdown.data-api'  , toggle, Dropdown.prototype.toggle)\n    .on('keydown.dropdown.data-api', toggle + ', [role=menu]' , Dropdown.prototype.keydown)\n\n}(window.jQuery);\n/* =========================================================\n * bootstrap-modal.js v2.3.1\n * http://twitter.github.com/bootstrap/javascript.html#modals\n * =========================================================\n * Copyright 2012 Twitter, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * ========================================================= */\n\n\n!function ($) {\n\n  \"use strict\"; // jshint ;_;\n\n\n /* MODAL CLASS DEFINITION\n  * ====================== */\n\n  var Modal = function (element, options) {\n    this.options = options\n    this.$element = $(element)\n      .delegate('[data-dismiss=\"modal\"]', 'click.dismiss.modal', $.proxy(this.hide, this))\n    this.options.remote && this.$element.find('.modal-body').load(this.options.remote)\n  }\n\n  Modal.prototype = {\n\n      constructor: Modal\n\n    , toggle: function () {\n        return this[!this.isShown ? 'show' : 'hide']()\n      }\n\n    , show: function () {\n        var that = this\n          , e = $.Event('show')\n\n        this.$element.trigger(e)\n\n        if (this.isShown || e.isDefaultPrevented()) return\n\n        this.isShown = true\n\n        this.escape()\n\n        this.backdrop(function () {\n          var transition = $.support.transition && that.$element.hasClass('fade')\n\n          if (!that.$element.parent().length) {\n            that.$element.appendTo(document.body) //don't move modals dom position\n          }\n\n          that.$element.show()\n\n          if (transition) {\n            that.$element[0].offsetWidth // force reflow\n          }\n\n          that.$element\n            .addClass('in')\n            .attr('aria-hidden', false)\n\n          that.enforceFocus()\n\n          transition ?\n            that.$element.one($.support.transition.end, function () { that.$element.focus().trigger('shown') }) :\n            that.$element.focus().trigger('shown')\n\n        })\n      }\n\n    , hide: function (e) {\n        e && e.preventDefault()\n\n        var that = this\n\n        e = $.Event('hide')\n\n        this.$element.trigger(e)\n\n        if (!this.isShown || e.isDefaultPrevented()) return\n\n        this.isShown = false\n\n        this.escape()\n\n        $(document).off('focusin.modal')\n\n        this.$element\n          .removeClass('in')\n          .attr('aria-hidden', true)\n\n        $.support.transition && this.$element.hasClass('fade') ?\n          this.hideWithTransition() :\n          this.hideModal()\n      }\n\n    , enforceFocus: function () {\n        var that = this\n        $(document).on('focusin.modal', function (e) {\n          if (that.$element[0] !== e.target && !that.$element.has(e.target).length) {\n            that.$element.focus()\n          }\n        })\n      }\n\n    , escape: function () {\n        var that = this\n        if (this.isShown && this.options.keyboard) {\n          this.$element.on('keyup.dismiss.modal', function ( e ) {\n            e.which == 27 && that.hide()\n          })\n        } else if (!this.isShown) {\n          this.$element.off('keyup.dismiss.modal')\n        }\n      }\n\n    , hideWithTransition: function () {\n        var that = this\n          , timeout = setTimeout(function () {\n              that.$element.off($.support.transition.end)\n              that.hideModal()\n            }, 500)\n\n        this.$element.one($.support.transition.end, function () {\n          clearTimeout(timeout)\n          that.hideModal()\n        })\n      }\n\n    , hideModal: function () {\n        var that = this\n        this.$element.hide()\n        this.backdrop(function () {\n          that.removeBackdrop()\n          that.$element.trigger('hidden')\n        })\n      }\n\n    , removeBackdrop: function () {\n        this.$backdrop && this.$backdrop.remove()\n        this.$backdrop = null\n      }\n\n    , backdrop: function (callback) {\n        var that = this\n          , animate = this.$element.hasClass('fade') ? 'fade' : ''\n\n        if (this.isShown && this.options.backdrop) {\n          var doAnimate = $.support.transition && animate\n\n          this.$backdrop = $('<div class=\"modal-backdrop ' + animate + '\" />')\n            .appendTo(document.body)\n\n          this.$backdrop.click(\n            this.options.backdrop == 'static' ?\n              $.proxy(this.$element[0].focus, this.$element[0])\n            : $.proxy(this.hide, this)\n          )\n\n          if (doAnimate) this.$backdrop[0].offsetWidth // force reflow\n\n          this.$backdrop.addClass('in')\n\n          if (!callback) return\n\n          doAnimate ?\n            this.$backdrop.one($.support.transition.end, callback) :\n            callback()\n\n        } else if (!this.isShown && this.$backdrop) {\n          this.$backdrop.removeClass('in')\n\n          $.support.transition && this.$element.hasClass('fade')?\n            this.$backdrop.one($.support.transition.end, callback) :\n            callback()\n\n        } else if (callback) {\n          callback()\n        }\n      }\n  }\n\n\n /* MODAL PLUGIN DEFINITION\n  * ======================= */\n\n  var old = $.fn.modal\n\n  $.fn.modal = function (option) {\n    return this.each(function () {\n      var $this = $(this)\n        , data = $this.data('modal')\n        , options = $.extend({}, $.fn.modal.defaults, $this.data(), typeof option == 'object' && option)\n      if (!data) $this.data('modal', (data = new Modal(this, options)))\n      if (typeof option == 'string') data[option]()\n      else if (options.show) data.show()\n    })\n  }\n\n  $.fn.modal.defaults = {\n      backdrop: true\n    , keyboard: true\n    , show: true\n  }\n\n  $.fn.modal.Constructor = Modal\n\n\n /* MODAL NO CONFLICT\n  * ================= */\n\n  $.fn.modal.noConflict = function () {\n    $.fn.modal = old\n    return this\n  }\n\n\n /* MODAL DATA-API\n  * ============== */\n\n  $(document).on('click.modal.data-api', '[data-toggle=\"modal\"]', function (e) {\n    var $this = $(this)\n      , href = $this.attr('href')\n      , $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\\s]+$)/, ''))) //strip for ie7\n      , option = $target.data('modal') ? 'toggle' : $.extend({ remote:!/#/.test(href) && href }, $target.data(), $this.data())\n\n    e.preventDefault()\n\n    $target\n      .modal(option)\n      .one('hide', function () {\n        $this.focus()\n      })\n  })\n\n}(window.jQuery);\n/* ===========================================================\n * bootstrap-tooltip.js v2.3.1\n * http://twitter.github.com/bootstrap/javascript.html#tooltips\n * Inspired by the original jQuery.tipsy by Jason Frame\n * ===========================================================\n * Copyright 2012 Twitter, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * ========================================================== */\n\n\n!function ($) {\n\n  \"use strict\"; // jshint ;_;\n\n\n /* TOOLTIP PUBLIC CLASS DEFINITION\n  * =============================== */\n\n  var Tooltip = function (element, options) {\n    this.init('tooltip', element, options)\n  }\n\n  Tooltip.prototype = {\n\n    constructor: Tooltip\n\n  , init: function (type, element, options) {\n      var eventIn\n        , eventOut\n        , triggers\n        , trigger\n        , i\n\n      this.type = type\n      this.$element = $(element)\n      this.options = this.getOptions(options)\n      this.enabled = true\n\n      triggers = this.options.trigger.split(' ')\n\n      for (i = triggers.length; i--;) {\n        trigger = triggers[i]\n        if (trigger == 'click') {\n          this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))\n        } else if (trigger != 'manual') {\n          eventIn = trigger == 'hover' ? 'mouseenter' : 'focus'\n          eventOut = trigger == 'hover' ? 'mouseleave' : 'blur'\n          this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this))\n          this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))\n        }\n      }\n\n      this.options.selector ?\n        (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :\n        this.fixTitle()\n    }\n\n  , getOptions: function (options) {\n      options = $.extend({}, $.fn[this.type].defaults, this.$element.data(), options)\n\n      if (options.delay && typeof options.delay == 'number') {\n        options.delay = {\n          show: options.delay\n        , hide: options.delay\n        }\n      }\n\n      return options\n    }\n\n  , enter: function (e) {\n      var defaults = $.fn[this.type].defaults\n        , options = {}\n        , self\n\n      this._options && $.each(this._options, function (key, value) {\n        if (defaults[key] != value) options[key] = value\n      }, this)\n\n      self = $(e.currentTarget)[this.type](options).data(this.type)\n\n      if (!self.options.delay || !self.options.delay.show) return self.show()\n\n      clearTimeout(this.timeout)\n      self.hoverState = 'in'\n      this.timeout = setTimeout(function() {\n        if (self.hoverState == 'in') self.show()\n      }, self.options.delay.show)\n    }\n\n  , leave: function (e) {\n      var self = $(e.currentTarget)[this.type](this._options).data(this.type)\n\n      if (this.timeout) clearTimeout(this.timeout)\n      if (!self.options.delay || !self.options.delay.hide) return self.hide()\n\n      self.hoverState = 'out'\n      this.timeout = setTimeout(function() {\n        if (self.hoverState == 'out') self.hide()\n      }, self.options.delay.hide)\n    }\n\n  , show: function () {\n      var $tip\n        , pos\n        , actualWidth\n        , actualHeight\n        , placement\n        , tp\n        , e = $.Event('show')\n\n      if (this.hasContent() && this.enabled) {\n        this.$element.trigger(e)\n        if (e.isDefaultPrevented()) return\n        $tip = this.tip()\n        this.setContent()\n\n        if (this.options.animation) {\n          $tip.addClass('fade')\n        }\n\n        placement = typeof this.options.placement == 'function' ?\n          this.options.placement.call(this, $tip[0], this.$element[0]) :\n          this.options.placement\n\n        $tip\n          .detach()\n          .css({ top: 0, left: 0, display: 'block' })\n\n        this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)\n\n        pos = this.getPosition()\n\n        actualWidth = $tip[0].offsetWidth\n        actualHeight = $tip[0].offsetHeight\n\n        switch (placement) {\n          case 'bottom':\n            tp = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2}\n            break\n          case 'top':\n            tp = {top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2}\n            break\n          case 'left':\n            tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth}\n            break\n          case 'right':\n            tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width}\n            break\n        }\n\n        this.applyPlacement(tp, placement)\n        this.$element.trigger('shown')\n      }\n    }\n\n  , applyPlacement: function(offset, placement){\n      var $tip = this.tip()\n        , width = $tip[0].offsetWidth\n        , height = $tip[0].offsetHeight\n        , actualWidth\n        , actualHeight\n        , delta\n        , replace\n\n      $tip\n        .offset(offset)\n        .addClass(placement)\n        .addClass('in')\n\n      actualWidth = $tip[0].offsetWidth\n      actualHeight = $tip[0].offsetHeight\n\n      if (placement == 'top' && actualHeight != height) {\n        offset.top = offset.top + height - actualHeight\n        replace = true\n      }\n\n      if (placement == 'bottom' || placement == 'top') {\n        delta = 0\n\n        if (offset.left < 0){\n          delta = offset.left * -2\n          offset.left = 0\n          $tip.offset(offset)\n          actualWidth = $tip[0].offsetWidth\n          actualHeight = $tip[0].offsetHeight\n        }\n\n        this.replaceArrow(delta - width + actualWidth, actualWidth, 'left')\n      } else {\n        this.replaceArrow(actualHeight - height, actualHeight, 'top')\n      }\n\n      if (replace) $tip.offset(offset)\n    }\n\n  , replaceArrow: function(delta, dimension, position){\n      this\n        .arrow()\n        .css(position, delta ? (50 * (1 - delta / dimension) + \"%\") : '')\n    }\n\n  , setContent: function () {\n      var $tip = this.tip()\n        , title = this.getTitle()\n\n      $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)\n      $tip.removeClass('fade in top bottom left right')\n    }\n\n  , hide: function () {\n      var that = this\n        , $tip = this.tip()\n        , e = $.Event('hide')\n\n      this.$element.trigger(e)\n      if (e.isDefaultPrevented()) return\n\n      $tip.removeClass('in')\n\n      function removeWithAnimation() {\n        var timeout = setTimeout(function () {\n          $tip.off($.support.transition.end).detach()\n        }, 500)\n\n        $tip.one($.support.transition.end, function () {\n          clearTimeout(timeout)\n          $tip.detach()\n        })\n      }\n\n      $.support.transition && this.$tip.hasClass('fade') ?\n        removeWithAnimation() :\n        $tip.detach()\n\n      this.$element.trigger('hidden')\n\n      return this\n    }\n\n  , fixTitle: function () {\n      var $e = this.$element\n      if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {\n        $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')\n      }\n    }\n\n  , hasContent: function () {\n      return this.getTitle()\n    }\n\n  , getPosition: function () {\n      var el = this.$element[0]\n      return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : {\n        width: el.offsetWidth\n      , height: el.offsetHeight\n      }, this.$element.offset())\n    }\n\n  , getTitle: function () {\n      var title\n        , $e = this.$element\n        , o = this.options\n\n      title = $e.attr('data-original-title')\n        || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)\n\n      return title\n    }\n\n  , tip: function () {\n      return this.$tip = this.$tip || $(this.options.template)\n    }\n\n  , arrow: function(){\n      return this.$arrow = this.$arrow || this.tip().find(\".tooltip-arrow\")\n    }\n\n  , validate: function () {\n      if (!this.$element[0].parentNode) {\n        this.hide()\n        this.$element = null\n        this.options = null\n      }\n    }\n\n  , enable: function () {\n      this.enabled = true\n    }\n\n  , disable: function () {\n      this.enabled = false\n    }\n\n  , toggleEnabled: function () {\n      this.enabled = !this.enabled\n    }\n\n  , toggle: function (e) {\n      var self = e ? $(e.currentTarget)[this.type](this._options).data(this.type) : this\n      self.tip().hasClass('in') ? self.hide() : self.show()\n    }\n\n  , destroy: function () {\n      this.hide().$element.off('.' + this.type).removeData(this.type)\n    }\n\n  }\n\n\n /* TOOLTIP PLUGIN DEFINITION\n  * ========================= */\n\n  var old = $.fn.tooltip\n\n  $.fn.tooltip = function ( option ) {\n    return this.each(function () {\n      var $this = $(this)\n        , data = $this.data('tooltip')\n        , options = typeof option == 'object' && option\n      if (!data) $this.data('tooltip', (data = new Tooltip(this, options)))\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  $.fn.tooltip.Constructor = Tooltip\n\n  $.fn.tooltip.defaults = {\n    animation: true\n  , placement: 'top'\n  , selector: false\n  , template: '<div class=\"tooltip\"><div class=\"tooltip-arrow\"></div><div class=\"tooltip-inner\"></div></div>'\n  , trigger: 'hover focus'\n  , title: ''\n  , delay: 0\n  , html: false\n  , container: false\n  }\n\n\n /* TOOLTIP NO CONFLICT\n  * =================== */\n\n  $.fn.tooltip.noConflict = function () {\n    $.fn.tooltip = old\n    return this\n  }\n\n}(window.jQuery);\n/* ===========================================================\n * bootstrap-popover.js v2.3.1\n * http://twitter.github.com/bootstrap/javascript.html#popovers\n * ===========================================================\n * Copyright 2012 Twitter, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * =========================================================== */\n\n\n!function ($) {\n\n  \"use strict\"; // jshint ;_;\n\n\n /* POPOVER PUBLIC CLASS DEFINITION\n  * =============================== */\n\n  var Popover = function (element, options) {\n    this.init('popover', element, options)\n  }\n\n\n  /* NOTE: POPOVER EXTENDS BOOTSTRAP-TOOLTIP.js\n     ========================================== */\n\n  Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype, {\n\n    constructor: Popover\n\n  , setContent: function () {\n      var $tip = this.tip()\n        , title = this.getTitle()\n        , content = this.getContent()\n\n      $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)\n      $tip.find('.popover-content')[this.options.html ? 'html' : 'text'](content)\n\n      $tip.removeClass('fade top bottom left right in')\n    }\n\n  , hasContent: function () {\n      return this.getTitle() || this.getContent()\n    }\n\n  , getContent: function () {\n      var content\n        , $e = this.$element\n        , o = this.options\n\n      content = (typeof o.content == 'function' ? o.content.call($e[0]) :  o.content)\n        || $e.attr('data-content')\n\n      return content\n    }\n\n  , tip: function () {\n      if (!this.$tip) {\n        this.$tip = $(this.options.template)\n      }\n      return this.$tip\n    }\n\n  , destroy: function () {\n      this.hide().$element.off('.' + this.type).removeData(this.type)\n    }\n\n  })\n\n\n /* POPOVER PLUGIN DEFINITION\n  * ======================= */\n\n  var old = $.fn.popover\n\n  $.fn.popover = function (option) {\n    return this.each(function () {\n      var $this = $(this)\n        , data = $this.data('popover')\n        , options = typeof option == 'object' && option\n      if (!data) $this.data('popover', (data = new Popover(this, options)))\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  $.fn.popover.Constructor = Popover\n\n  $.fn.popover.defaults = $.extend({} , $.fn.tooltip.defaults, {\n    placement: 'right'\n  , trigger: 'click'\n  , content: ''\n  , template: '<div class=\"popover\"><div class=\"arrow\"></div><h3 class=\"popover-title\"></h3><div class=\"popover-content\"></div></div>'\n  })\n\n\n /* POPOVER NO CONFLICT\n  * =================== */\n\n  $.fn.popover.noConflict = function () {\n    $.fn.popover = old\n    return this\n  }\n\n}(window.jQuery);\n/* =============================================================\n * bootstrap-scrollspy.js v2.3.1\n * http://twitter.github.com/bootstrap/javascript.html#scrollspy\n * =============================================================\n * Copyright 2012 Twitter, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * ============================================================== */\n\n\n!function ($) {\n\n  \"use strict\"; // jshint ;_;\n\n\n /* SCROLLSPY CLASS DEFINITION\n  * ========================== */\n\n  function ScrollSpy(element, options) {\n    var process = $.proxy(this.process, this)\n      , $element = $(element).is('body') ? $(window) : $(element)\n      , href\n    this.options = $.extend({}, $.fn.scrollspy.defaults, options)\n    this.$scrollElement = $element.on('scroll.scroll-spy.data-api', process)\n    this.selector = (this.options.target\n      || ((href = $(element).attr('href')) && href.replace(/.*(?=#[^\\s]+$)/, '')) //strip for ie7\n      || '') + ' .nav li > a'\n    this.$body = $('body')\n    this.refresh()\n    this.process()\n  }\n\n  ScrollSpy.prototype = {\n\n      constructor: ScrollSpy\n\n    , refresh: function () {\n        var self = this\n          , $targets\n\n        this.offsets = $([])\n        this.targets = $([])\n\n        $targets = this.$body\n          .find(this.selector)\n          .map(function () {\n            var $el = $(this)\n              , href = $el.data('target') || $el.attr('href')\n              , $href = /^#\\w/.test(href) && $(href)\n            return ( $href\n              && $href.length\n              && [[ $href.position().top + (!$.isWindow(self.$scrollElement.get(0)) && self.$scrollElement.scrollTop()), href ]] ) || null\n          })\n          .sort(function (a, b) { return a[0] - b[0] })\n          .each(function () {\n            self.offsets.push(this[0])\n            self.targets.push(this[1])\n          })\n      }\n\n    , process: function () {\n        var scrollTop = this.$scrollElement.scrollTop() + this.options.offset\n          , scrollHeight = this.$scrollElement[0].scrollHeight || this.$body[0].scrollHeight\n          , maxScroll = scrollHeight - this.$scrollElement.height()\n          , offsets = this.offsets\n          , targets = this.targets\n          , activeTarget = this.activeTarget\n          , i\n\n        if (scrollTop >= maxScroll) {\n          return activeTarget != (i = targets.last()[0])\n            && this.activate ( i )\n        }\n\n        for (i = offsets.length; i--;) {\n          activeTarget != targets[i]\n            && scrollTop >= offsets[i]\n            && (!offsets[i + 1] || scrollTop <= offsets[i + 1])\n            && this.activate( targets[i] )\n        }\n      }\n\n    , activate: function (target) {\n        var active\n          , selector\n\n        this.activeTarget = target\n\n        $(this.selector)\n          .parent('.active')\n          .removeClass('active')\n\n        selector = this.selector\n          + '[data-target=\"' + target + '\"],'\n          + this.selector + '[href=\"' + target + '\"]'\n\n        active = $(selector)\n          .parent('li')\n          .addClass('active')\n\n        if (active.parent('.dropdown-menu').length)  {\n          active = active.closest('li.dropdown').addClass('active')\n        }\n\n        active.trigger('activate')\n      }\n\n  }\n\n\n /* SCROLLSPY PLUGIN DEFINITION\n  * =========================== */\n\n  var old = $.fn.scrollspy\n\n  $.fn.scrollspy = function (option) {\n    return this.each(function () {\n      var $this = $(this)\n        , data = $this.data('scrollspy')\n        , options = typeof option == 'object' && option\n      if (!data) $this.data('scrollspy', (data = new ScrollSpy(this, options)))\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  $.fn.scrollspy.Constructor = ScrollSpy\n\n  $.fn.scrollspy.defaults = {\n    offset: 10\n  }\n\n\n /* SCROLLSPY NO CONFLICT\n  * ===================== */\n\n  $.fn.scrollspy.noConflict = function () {\n    $.fn.scrollspy = old\n    return this\n  }\n\n\n /* SCROLLSPY DATA-API\n  * ================== */\n\n  $(window).on('load', function () {\n    $('[data-spy=\"scroll\"]').each(function () {\n      var $spy = $(this)\n      $spy.scrollspy($spy.data())\n    })\n  })\n\n}(window.jQuery);/* ========================================================\n * bootstrap-tab.js v2.3.1\n * http://twitter.github.com/bootstrap/javascript.html#tabs\n * ========================================================\n * Copyright 2012 Twitter, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * ======================================================== */\n\n\n!function ($) {\n\n  \"use strict\"; // jshint ;_;\n\n\n /* TAB CLASS DEFINITION\n  * ==================== */\n\n  var Tab = function (element) {\n    this.element = $(element)\n  }\n\n  Tab.prototype = {\n\n    constructor: Tab\n\n  , show: function () {\n      var $this = this.element\n        , $ul = $this.closest('ul:not(.dropdown-menu)')\n        , selector = $this.attr('data-target')\n        , previous\n        , $target\n        , e\n\n      if (!selector) {\n        selector = $this.attr('href')\n        selector = selector && selector.replace(/.*(?=#[^\\s]*$)/, '') //strip for ie7\n      }\n\n      if ( $this.parent('li').hasClass('active') ) return\n\n      previous = $ul.find('.active:last a')[0]\n\n      e = $.Event('show', {\n        relatedTarget: previous\n      })\n\n      $this.trigger(e)\n\n      if (e.isDefaultPrevented()) return\n\n      $target = $(selector)\n\n      this.activate($this.parent('li'), $ul)\n      this.activate($target, $target.parent(), function () {\n        $this.trigger({\n          type: 'shown'\n        , relatedTarget: previous\n        })\n      })\n    }\n\n  , activate: function ( element, container, callback) {\n      var $active = container.find('> .active')\n        , transition = callback\n            && $.support.transition\n            && $active.hasClass('fade')\n\n      function next() {\n        $active\n          .removeClass('active')\n          .find('> .dropdown-menu > .active')\n          .removeClass('active')\n\n        element.addClass('active')\n\n        if (transition) {\n          element[0].offsetWidth // reflow for transition\n          element.addClass('in')\n        } else {\n          element.removeClass('fade')\n        }\n\n        if ( element.parent('.dropdown-menu') ) {\n          element.closest('li.dropdown').addClass('active')\n        }\n\n        callback && callback()\n      }\n\n      transition ?\n        $active.one($.support.transition.end, next) :\n        next()\n\n      $active.removeClass('in')\n    }\n  }\n\n\n /* TAB PLUGIN DEFINITION\n  * ===================== */\n\n  var old = $.fn.tab\n\n  $.fn.tab = function ( option ) {\n    return this.each(function () {\n      var $this = $(this)\n        , data = $this.data('tab')\n      if (!data) $this.data('tab', (data = new Tab(this)))\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  $.fn.tab.Constructor = Tab\n\n\n /* TAB NO CONFLICT\n  * =============== */\n\n  $.fn.tab.noConflict = function () {\n    $.fn.tab = old\n    return this\n  }\n\n\n /* TAB DATA-API\n  * ============ */\n\n  $(document).on('click.tab.data-api', '[data-toggle=\"tab\"], [data-toggle=\"pill\"]', function (e) {\n    e.preventDefault()\n    $(this).tab('show')\n  })\n\n}(window.jQuery);/* =============================================================\n * bootstrap-typeahead.js v2.3.1\n * http://twitter.github.com/bootstrap/javascript.html#typeahead\n * =============================================================\n * Copyright 2012 Twitter, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * ============================================================ */\n\n\n!function($){\n\n  \"use strict\"; // jshint ;_;\n\n\n /* TYPEAHEAD PUBLIC CLASS DEFINITION\n  * ================================= */\n\n  var Typeahead = function (element, options) {\n    this.$element = $(element)\n    this.options = $.extend({}, $.fn.typeahead.defaults, options)\n    this.matcher = this.options.matcher || this.matcher\n    this.sorter = this.options.sorter || this.sorter\n    this.highlighter = this.options.highlighter || this.highlighter\n    this.updater = this.options.updater || this.updater\n    this.source = this.options.source\n    this.$menu = $(this.options.menu)\n    this.shown = false\n    this.listen()\n  }\n\n  Typeahead.prototype = {\n\n    constructor: Typeahead\n\n  , select: function () {\n      var val = this.$menu.find('.active').attr('data-value')\n      this.$element\n        .val(this.updater(val))\n        .change()\n      return this.hide()\n    }\n\n  , updater: function (item) {\n      return item\n    }\n\n  , show: function () {\n      var pos = $.extend({}, this.$element.position(), {\n        height: this.$element[0].offsetHeight\n      })\n\n      this.$menu\n        .insertAfter(this.$element)\n        .css({\n          top: pos.top + pos.height\n        , left: pos.left\n        })\n        .show()\n\n      this.shown = true\n      return this\n    }\n\n  , hide: function () {\n      this.$menu.hide()\n      this.shown = false\n      return this\n    }\n\n  , lookup: function (event) {\n      var items\n\n      this.query = this.$element.val()\n\n      if (!this.query || this.query.length < this.options.minLength) {\n        return this.shown ? this.hide() : this\n      }\n\n      items = $.isFunction(this.source) ? this.source(this.query, $.proxy(this.process, this)) : this.source\n\n      return items ? this.process(items) : this\n    }\n\n  , process: function (items) {\n      var that = this\n\n      items = $.grep(items, function (item) {\n        return that.matcher(item)\n      })\n\n      items = this.sorter(items)\n\n      if (!items.length) {\n        return this.shown ? this.hide() : this\n      }\n\n      return this.render(items.slice(0, this.options.items)).show()\n    }\n\n  , matcher: function (item) {\n      return ~item.toLowerCase().indexOf(this.query.toLowerCase())\n    }\n\n  , sorter: function (items) {\n      var beginswith = []\n        , caseSensitive = []\n        , caseInsensitive = []\n        , item\n\n      while (item = items.shift()) {\n        if (!item.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item)\n        else if (~item.indexOf(this.query)) caseSensitive.push(item)\n        else caseInsensitive.push(item)\n      }\n\n      return beginswith.concat(caseSensitive, caseInsensitive)\n    }\n\n  , highlighter: function (item) {\n      var query = this.query.replace(/[\\-\\[\\]{}()*+?.,\\\\\\^$|#\\s]/g, '\\\\$&')\n      return item.replace(new RegExp('(' + query + ')', 'ig'), function ($1, match) {\n        return '<strong>' + match + '</strong>'\n      })\n    }\n\n  , render: function (items) {\n      var that = this\n\n      items = $(items).map(function (i, item) {\n        i = $(that.options.item).attr('data-value', item)\n        i.find('a').html(that.highlighter(item))\n        return i[0]\n      })\n\n      items.first().addClass('active')\n      this.$menu.html(items)\n      return this\n    }\n\n  , next: function (event) {\n      var active = this.$menu.find('.active').removeClass('active')\n        , next = active.next()\n\n      if (!next.length) {\n        next = $(this.$menu.find('li')[0])\n      }\n\n      next.addClass('active')\n    }\n\n  , prev: function (event) {\n      var active = this.$menu.find('.active').removeClass('active')\n        , prev = active.prev()\n\n      if (!prev.length) {\n        prev = this.$menu.find('li').last()\n      }\n\n      prev.addClass('active')\n    }\n\n  , listen: function () {\n      this.$element\n        .on('focus',    $.proxy(this.focus, this))\n        .on('blur',     $.proxy(this.blur, this))\n        .on('keypress', $.proxy(this.keypress, this))\n        .on('keyup',    $.proxy(this.keyup, this))\n\n      if (this.eventSupported('keydown')) {\n        this.$element.on('keydown', $.proxy(this.keydown, this))\n      }\n\n      this.$menu\n        .on('click', $.proxy(this.click, this))\n        .on('mouseenter', 'li', $.proxy(this.mouseenter, this))\n        .on('mouseleave', 'li', $.proxy(this.mouseleave, this))\n    }\n\n  , eventSupported: function(eventName) {\n      var isSupported = eventName in this.$element\n      if (!isSupported) {\n        this.$element.setAttribute(eventName, 'return;')\n        isSupported = typeof this.$element[eventName] === 'function'\n      }\n      return isSupported\n    }\n\n  , move: function (e) {\n      if (!this.shown) return\n\n      switch(e.keyCode) {\n        case 9: // tab\n        case 13: // enter\n        case 27: // escape\n          e.preventDefault()\n          break\n\n        case 38: // up arrow\n          e.preventDefault()\n          this.prev()\n          break\n\n        case 40: // down arrow\n          e.preventDefault()\n          this.next()\n          break\n      }\n\n      e.stopPropagation()\n    }\n\n  , keydown: function (e) {\n      this.suppressKeyPressRepeat = ~$.inArray(e.keyCode, [40,38,9,13,27])\n      this.move(e)\n    }\n\n  , keypress: function (e) {\n      if (this.suppressKeyPressRepeat) return\n      this.move(e)\n    }\n\n  , keyup: function (e) {\n      switch(e.keyCode) {\n        case 40: // down arrow\n        case 38: // up arrow\n        case 16: // shift\n        case 17: // ctrl\n        case 18: // alt\n          break\n\n        case 9: // tab\n        case 13: // enter\n          if (!this.shown) return\n          this.select()\n          break\n\n        case 27: // escape\n          if (!this.shown) return\n          this.hide()\n          break\n\n        default:\n          this.lookup()\n      }\n\n      e.stopPropagation()\n      e.preventDefault()\n  }\n\n  , focus: function (e) {\n      this.focused = true\n    }\n\n  , blur: function (e) {\n      this.focused = false\n      if (!this.mousedover && this.shown) this.hide()\n    }\n\n  , click: function (e) {\n      e.stopPropagation()\n      e.preventDefault()\n      this.select()\n      this.$element.focus()\n    }\n\n  , mouseenter: function (e) {\n      this.mousedover = true\n      this.$menu.find('.active').removeClass('active')\n      $(e.currentTarget).addClass('active')\n    }\n\n  , mouseleave: function (e) {\n      this.mousedover = false\n      if (!this.focused && this.shown) this.hide()\n    }\n\n  }\n\n\n  /* TYPEAHEAD PLUGIN DEFINITION\n   * =========================== */\n\n  var old = $.fn.typeahead\n\n  $.fn.typeahead = function (option) {\n    return this.each(function () {\n      var $this = $(this)\n        , data = $this.data('typeahead')\n        , options = typeof option == 'object' && option\n      if (!data) $this.data('typeahead', (data = new Typeahead(this, options)))\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  $.fn.typeahead.defaults = {\n    source: []\n  , items: 8\n  , menu: '<ul class=\"typeahead dropdown-menu\"></ul>'\n  , item: '<li><a href=\"#\"></a></li>'\n  , minLength: 1\n  }\n\n  $.fn.typeahead.Constructor = Typeahead\n\n\n /* TYPEAHEAD NO CONFLICT\n  * =================== */\n\n  $.fn.typeahead.noConflict = function () {\n    $.fn.typeahead = old\n    return this\n  }\n\n\n /* TYPEAHEAD DATA-API\n  * ================== */\n\n  $(document).on('focus.typeahead.data-api', '[data-provide=\"typeahead\"]', function (e) {\n    var $this = $(this)\n    if ($this.data('typeahead')) return\n    $this.typeahead($this.data())\n  })\n\n}(window.jQuery);\n/* ==========================================================\n * bootstrap-affix.js v2.3.1\n * http://twitter.github.com/bootstrap/javascript.html#affix\n * ==========================================================\n * Copyright 2012 Twitter, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * ========================================================== */\n\n\n!function ($) {\n\n  \"use strict\"; // jshint ;_;\n\n\n /* AFFIX CLASS DEFINITION\n  * ====================== */\n\n  var Affix = function (element, options) {\n    this.options = $.extend({}, $.fn.affix.defaults, options)\n    this.$window = $(window)\n      .on('scroll.affix.data-api', $.proxy(this.checkPosition, this))\n      .on('click.affix.data-api',  $.proxy(function () { setTimeout($.proxy(this.checkPosition, this), 1) }, this))\n    this.$element = $(element)\n    this.checkPosition()\n  }\n\n  Affix.prototype.checkPosition = function () {\n    if (!this.$element.is(':visible')) return\n\n    var scrollHeight = $(document).height()\n      , scrollTop = this.$window.scrollTop()\n      , position = this.$element.offset()\n      , offset = this.options.offset\n      , offsetBottom = offset.bottom\n      , offsetTop = offset.top\n      , reset = 'affix affix-top affix-bottom'\n      , affix\n\n    if (typeof offset != 'object') offsetBottom = offsetTop = offset\n    if (typeof offsetTop == 'function') offsetTop = offset.top()\n    if (typeof offsetBottom == 'function') offsetBottom = offset.bottom()\n\n    affix = this.unpin != null && (scrollTop + this.unpin <= position.top) ?\n      false    : offsetBottom != null && (position.top + this.$element.height() >= scrollHeight - offsetBottom) ?\n      'bottom' : offsetTop != null && scrollTop <= offsetTop ?\n      'top'    : false\n\n    if (this.affixed === affix) return\n\n    this.affixed = affix\n    this.unpin = affix == 'bottom' ? position.top - scrollTop : null\n\n    this.$element.removeClass(reset).addClass('affix' + (affix ? '-' + affix : ''))\n  }\n\n\n /* AFFIX PLUGIN DEFINITION\n  * ======================= */\n\n  var old = $.fn.affix\n\n  $.fn.affix = function (option) {\n    return this.each(function () {\n      var $this = $(this)\n        , data = $this.data('affix')\n        , options = typeof option == 'object' && option\n      if (!data) $this.data('affix', (data = new Affix(this, options)))\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  $.fn.affix.Constructor = Affix\n\n  $.fn.affix.defaults = {\n    offset: 0\n  }\n\n\n /* AFFIX NO CONFLICT\n  * ================= */\n\n  $.fn.affix.noConflict = function () {\n    $.fn.affix = old\n    return this\n  }\n\n\n /* AFFIX DATA-API\n  * ============== */\n\n  $(window).on('load', function () {\n    $('[data-spy=\"affix\"]').each(function () {\n      var $spy = $(this)\n        , data = $spy.data()\n\n      data.offset = data.offset || {}\n\n      data.offsetBottom && (data.offset.bottom = data.offsetBottom)\n      data.offsetTop && (data.offset.top = data.offsetTop)\n\n      $spy.affix(data)\n    })\n  })\n\n\n}(window.jQuery);"
  },
  {
    "path": "explainshell/web/static/js/d3.v3.js",
    "content": "d3 = function() {\n  var d3 = {\n    version: \"3.1.4\"\n  };\n  if (!Date.now) Date.now = function() {\n    return +new Date();\n  };\n  var d3_document = document, d3_window = window;\n  try {\n    d3_document.createElement(\"div\").style.setProperty(\"opacity\", 0, \"\");\n  } catch (error) {\n    var d3_style_prototype = d3_window.CSSStyleDeclaration.prototype, d3_style_setProperty = d3_style_prototype.setProperty;\n    d3_style_prototype.setProperty = function(name, value, priority) {\n      d3_style_setProperty.call(this, name, value + \"\", priority);\n    };\n  }\n  d3.ascending = function(a, b) {\n    return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;\n  };\n  d3.descending = function(a, b) {\n    return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;\n  };\n  d3.min = function(array, f) {\n    var i = -1, n = array.length, a, b;\n    if (arguments.length === 1) {\n      while (++i < n && ((a = array[i]) == null || a != a)) a = undefined;\n      while (++i < n) if ((b = array[i]) != null && a > b) a = b;\n    } else {\n      while (++i < n && ((a = f.call(array, array[i], i)) == null || a != a)) a = undefined;\n      while (++i < n) if ((b = f.call(array, array[i], i)) != null && a > b) a = b;\n    }\n    return a;\n  };\n  d3.max = function(array, f) {\n    var i = -1, n = array.length, a, b;\n    if (arguments.length === 1) {\n      while (++i < n && ((a = array[i]) == null || a != a)) a = undefined;\n      while (++i < n) if ((b = array[i]) != null && b > a) a = b;\n    } else {\n      while (++i < n && ((a = f.call(array, array[i], i)) == null || a != a)) a = undefined;\n      while (++i < n) if ((b = f.call(array, array[i], i)) != null && b > a) a = b;\n    }\n    return a;\n  };\n  d3.extent = function(array, f) {\n    var i = -1, n = array.length, a, b, c;\n    if (arguments.length === 1) {\n      while (++i < n && ((a = c = array[i]) == null || a != a)) a = c = undefined;\n      while (++i < n) if ((b = array[i]) != null) {\n        if (a > b) a = b;\n        if (c < b) c = b;\n      }\n    } else {\n      while (++i < n && ((a = c = f.call(array, array[i], i)) == null || a != a)) a = undefined;\n      while (++i < n) if ((b = f.call(array, array[i], i)) != null) {\n        if (a > b) a = b;\n        if (c < b) c = b;\n      }\n    }\n    return [ a, c ];\n  };\n  d3.sum = function(array, f) {\n    var s = 0, n = array.length, a, i = -1;\n    if (arguments.length === 1) {\n      while (++i < n) if (!isNaN(a = +array[i])) s += a;\n    } else {\n      while (++i < n) if (!isNaN(a = +f.call(array, array[i], i))) s += a;\n    }\n    return s;\n  };\n  function d3_number(x) {\n    return x != null && !isNaN(x);\n  }\n  d3.mean = function(array, f) {\n    var n = array.length, a, m = 0, i = -1, j = 0;\n    if (arguments.length === 1) {\n      while (++i < n) if (d3_number(a = array[i])) m += (a - m) / ++j;\n    } else {\n      while (++i < n) if (d3_number(a = f.call(array, array[i], i))) m += (a - m) / ++j;\n    }\n    return j ? m : undefined;\n  };\n  d3.quantile = function(values, p) {\n    var H = (values.length - 1) * p + 1, h = Math.floor(H), v = +values[h - 1], e = H - h;\n    return e ? v + e * (values[h] - v) : v;\n  };\n  d3.median = function(array, f) {\n    if (arguments.length > 1) array = array.map(f);\n    array = array.filter(d3_number);\n    return array.length ? d3.quantile(array.sort(d3.ascending), .5) : undefined;\n  };\n  d3.bisector = function(f) {\n    return {\n      left: function(a, x, lo, hi) {\n        if (arguments.length < 3) lo = 0;\n        if (arguments.length < 4) hi = a.length;\n        while (lo < hi) {\n          var mid = lo + hi >>> 1;\n          if (f.call(a, a[mid], mid) < x) lo = mid + 1; else hi = mid;\n        }\n        return lo;\n      },\n      right: function(a, x, lo, hi) {\n        if (arguments.length < 3) lo = 0;\n        if (arguments.length < 4) hi = a.length;\n        while (lo < hi) {\n          var mid = lo + hi >>> 1;\n          if (x < f.call(a, a[mid], mid)) hi = mid; else lo = mid + 1;\n        }\n        return lo;\n      }\n    };\n  };\n  var d3_bisector = d3.bisector(function(d) {\n    return d;\n  });\n  d3.bisectLeft = d3_bisector.left;\n  d3.bisect = d3.bisectRight = d3_bisector.right;\n  d3.shuffle = function(array) {\n    var m = array.length, t, i;\n    while (m) {\n      i = Math.random() * m-- | 0;\n      t = array[m], array[m] = array[i], array[i] = t;\n    }\n    return array;\n  };\n  d3.permute = function(array, indexes) {\n    var permutes = [], i = -1, n = indexes.length;\n    while (++i < n) permutes[i] = array[indexes[i]];\n    return permutes;\n  };\n  d3.zip = function() {\n    if (!(n = arguments.length)) return [];\n    for (var i = -1, m = d3.min(arguments, d3_zipLength), zips = new Array(m); ++i < m; ) {\n      for (var j = -1, n, zip = zips[i] = new Array(n); ++j < n; ) {\n        zip[j] = arguments[j][i];\n      }\n    }\n    return zips;\n  };\n  function d3_zipLength(d) {\n    return d.length;\n  }\n  d3.transpose = function(matrix) {\n    return d3.zip.apply(d3, matrix);\n  };\n  d3.keys = function(map) {\n    var keys = [];\n    for (var key in map) keys.push(key);\n    return keys;\n  };\n  d3.values = function(map) {\n    var values = [];\n    for (var key in map) values.push(map[key]);\n    return values;\n  };\n  d3.entries = function(map) {\n    var entries = [];\n    for (var key in map) entries.push({\n      key: key,\n      value: map[key]\n    });\n    return entries;\n  };\n  d3.merge = function(arrays) {\n    return Array.prototype.concat.apply([], arrays);\n  };\n  d3.range = function(start, stop, step) {\n    if (arguments.length < 3) {\n      step = 1;\n      if (arguments.length < 2) {\n        stop = start;\n        start = 0;\n      }\n    }\n    if ((stop - start) / step === Infinity) throw new Error(\"infinite range\");\n    var range = [], k = d3_range_integerScale(Math.abs(step)), i = -1, j;\n    start *= k, stop *= k, step *= k;\n    if (step < 0) while ((j = start + step * ++i) > stop) range.push(j / k); else while ((j = start + step * ++i) < stop) range.push(j / k);\n    return range;\n  };\n  function d3_range_integerScale(x) {\n    var k = 1;\n    while (x * k % 1) k *= 10;\n    return k;\n  }\n  function d3_class(ctor, properties) {\n    try {\n      for (var key in properties) {\n        Object.defineProperty(ctor.prototype, key, {\n          value: properties[key],\n          enumerable: false\n        });\n      }\n    } catch (e) {\n      ctor.prototype = properties;\n    }\n  }\n  d3.map = function(object) {\n    var map = new d3_Map();\n    for (var key in object) map.set(key, object[key]);\n    return map;\n  };\n  function d3_Map() {}\n  d3_class(d3_Map, {\n    has: function(key) {\n      return d3_map_prefix + key in this;\n    },\n    get: function(key) {\n      return this[d3_map_prefix + key];\n    },\n    set: function(key, value) {\n      return this[d3_map_prefix + key] = value;\n    },\n    remove: function(key) {\n      key = d3_map_prefix + key;\n      return key in this && delete this[key];\n    },\n    keys: function() {\n      var keys = [];\n      this.forEach(function(key) {\n        keys.push(key);\n      });\n      return keys;\n    },\n    values: function() {\n      var values = [];\n      this.forEach(function(key, value) {\n        values.push(value);\n      });\n      return values;\n    },\n    entries: function() {\n      var entries = [];\n      this.forEach(function(key, value) {\n        entries.push({\n          key: key,\n          value: value\n        });\n      });\n      return entries;\n    },\n    forEach: function(f) {\n      for (var key in this) {\n        if (key.charCodeAt(0) === d3_map_prefixCode) {\n          f.call(this, key.substring(1), this[key]);\n        }\n      }\n    }\n  });\n  var d3_map_prefix = \"\\0\", d3_map_prefixCode = d3_map_prefix.charCodeAt(0);\n  d3.nest = function() {\n    var nest = {}, keys = [], sortKeys = [], sortValues, rollup;\n    function map(mapType, array, depth) {\n      if (depth >= keys.length) return rollup ? rollup.call(nest, array) : sortValues ? array.sort(sortValues) : array;\n      var i = -1, n = array.length, key = keys[depth++], keyValue, object, setter, valuesByKey = new d3_Map(), values;\n      while (++i < n) {\n        if (values = valuesByKey.get(keyValue = key(object = array[i]))) {\n          values.push(object);\n        } else {\n          valuesByKey.set(keyValue, [ object ]);\n        }\n      }\n      if (mapType) {\n        object = mapType();\n        setter = function(keyValue, values) {\n          object.set(keyValue, map(mapType, values, depth));\n        };\n      } else {\n        object = {};\n        setter = function(keyValue, values) {\n          object[keyValue] = map(mapType, values, depth);\n        };\n      }\n      valuesByKey.forEach(setter);\n      return object;\n    }\n    function entries(map, depth) {\n      if (depth >= keys.length) return map;\n      var array = [], sortKey = sortKeys[depth++];\n      map.forEach(function(key, keyMap) {\n        array.push({\n          key: key,\n          values: entries(keyMap, depth)\n        });\n      });\n      return sortKey ? array.sort(function(a, b) {\n        return sortKey(a.key, b.key);\n      }) : array;\n    }\n    nest.map = function(array, mapType) {\n      return map(mapType, array, 0);\n    };\n    nest.entries = function(array) {\n      return entries(map(d3.map, array, 0), 0);\n    };\n    nest.key = function(d) {\n      keys.push(d);\n      return nest;\n    };\n    nest.sortKeys = function(order) {\n      sortKeys[keys.length - 1] = order;\n      return nest;\n    };\n    nest.sortValues = function(order) {\n      sortValues = order;\n      return nest;\n    };\n    nest.rollup = function(f) {\n      rollup = f;\n      return nest;\n    };\n    return nest;\n  };\n  d3.set = function(array) {\n    var set = new d3_Set();\n    if (array) for (var i = 0; i < array.length; i++) set.add(array[i]);\n    return set;\n  };\n  function d3_Set() {}\n  d3_class(d3_Set, {\n    has: function(value) {\n      return d3_map_prefix + value in this;\n    },\n    add: function(value) {\n      this[d3_map_prefix + value] = true;\n      return value;\n    },\n    remove: function(value) {\n      value = d3_map_prefix + value;\n      return value in this && delete this[value];\n    },\n    values: function() {\n      var values = [];\n      this.forEach(function(value) {\n        values.push(value);\n      });\n      return values;\n    },\n    forEach: function(f) {\n      for (var value in this) {\n        if (value.charCodeAt(0) === d3_map_prefixCode) {\n          f.call(this, value.substring(1));\n        }\n      }\n    }\n  });\n  d3.behavior = {};\n  d3.rebind = function(target, source) {\n    var i = 1, n = arguments.length, method;\n    while (++i < n) target[method = arguments[i]] = d3_rebind(target, source, source[method]);\n    return target;\n  };\n  function d3_rebind(target, source, method) {\n    return function() {\n      var value = method.apply(source, arguments);\n      return value === source ? target : value;\n    };\n  }\n  d3.dispatch = function() {\n    var dispatch = new d3_dispatch(), i = -1, n = arguments.length;\n    while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch);\n    return dispatch;\n  };\n  function d3_dispatch() {}\n  d3_dispatch.prototype.on = function(type, listener) {\n    var i = type.indexOf(\".\"), name = \"\";\n    if (i >= 0) {\n      name = type.substring(i + 1);\n      type = type.substring(0, i);\n    }\n    if (type) return arguments.length < 2 ? this[type].on(name) : this[type].on(name, listener);\n    if (arguments.length === 2) {\n      if (listener == null) for (type in this) {\n        if (this.hasOwnProperty(type)) this[type].on(name, null);\n      }\n      return this;\n    }\n  };\n  function d3_dispatch_event(dispatch) {\n    var listeners = [], listenerByName = new d3_Map();\n    function event() {\n      var z = listeners, i = -1, n = z.length, l;\n      while (++i < n) if (l = z[i].on) l.apply(this, arguments);\n      return dispatch;\n    }\n    event.on = function(name, listener) {\n      var l = listenerByName.get(name), i;\n      if (arguments.length < 2) return l && l.on;\n      if (l) {\n        l.on = null;\n        listeners = listeners.slice(0, i = listeners.indexOf(l)).concat(listeners.slice(i + 1));\n        listenerByName.remove(name);\n      }\n      if (listener) listeners.push(listenerByName.set(name, {\n        on: listener\n      }));\n      return dispatch;\n    };\n    return event;\n  }\n  d3.event = null;\n  function d3_eventCancel() {\n    d3.event.stopPropagation();\n    d3.event.preventDefault();\n  }\n  function d3_eventSource() {\n    var e = d3.event, s;\n    while (s = e.sourceEvent) e = s;\n    return e;\n  }\n  function d3_eventDispatch(target) {\n    var dispatch = new d3_dispatch(), i = 0, n = arguments.length;\n    while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch);\n    dispatch.of = function(thiz, argumentz) {\n      return function(e1) {\n        try {\n          var e0 = e1.sourceEvent = d3.event;\n          e1.target = target;\n          d3.event = e1;\n          dispatch[e1.type].apply(thiz, argumentz);\n        } finally {\n          d3.event = e0;\n        }\n      };\n    };\n    return dispatch;\n  }\n  d3.mouse = function(container) {\n    return d3_mousePoint(container, d3_eventSource());\n  };\n  var d3_mouse_bug44083 = /WebKit/.test(d3_window.navigator.userAgent) ? -1 : 0;\n  function d3_mousePoint(container, e) {\n    var svg = container.ownerSVGElement || container;\n    if (svg.createSVGPoint) {\n      var point = svg.createSVGPoint();\n      if (d3_mouse_bug44083 < 0 && (d3_window.scrollX || d3_window.scrollY)) {\n        svg = d3.select(d3_document.body).append(\"svg\").style(\"position\", \"absolute\").style(\"top\", 0).style(\"left\", 0);\n        var ctm = svg[0][0].getScreenCTM();\n        d3_mouse_bug44083 = !(ctm.f || ctm.e);\n        svg.remove();\n      }\n      if (d3_mouse_bug44083) {\n        point.x = e.pageX;\n        point.y = e.pageY;\n      } else {\n        point.x = e.clientX;\n        point.y = e.clientY;\n      }\n      point = point.matrixTransform(container.getScreenCTM().inverse());\n      return [ point.x, point.y ];\n    }\n    var rect = container.getBoundingClientRect();\n    return [ e.clientX - rect.left - container.clientLeft, e.clientY - rect.top - container.clientTop ];\n  }\n  var d3_array = d3_arraySlice;\n  function d3_arrayCopy(pseudoarray) {\n    var i = -1, n = pseudoarray.length, array = [];\n    while (++i < n) array.push(pseudoarray[i]);\n    return array;\n  }\n  function d3_arraySlice(pseudoarray) {\n    return Array.prototype.slice.call(pseudoarray);\n  }\n  try {\n    d3_array(d3_document.documentElement.childNodes)[0].nodeType;\n  } catch (e) {\n    d3_array = d3_arrayCopy;\n  }\n  var d3_arraySubclass = [].__proto__ ? function(array, prototype) {\n    array.__proto__ = prototype;\n  } : function(array, prototype) {\n    for (var property in prototype) array[property] = prototype[property];\n  };\n  d3.touches = function(container, touches) {\n    if (arguments.length < 2) touches = d3_eventSource().touches;\n    return touches ? d3_array(touches).map(function(touch) {\n      var point = d3_mousePoint(container, touch);\n      point.identifier = touch.identifier;\n      return point;\n    }) : [];\n  };\n  d3.behavior.drag = function() {\n    var event = d3_eventDispatch(drag, \"drag\", \"dragstart\", \"dragend\"), origin = null;\n    function drag() {\n      this.on(\"mousedown.drag\", mousedown).on(\"touchstart.drag\", mousedown);\n    }\n    function mousedown() {\n      var target = this, event_ = event.of(target, arguments), eventTarget = d3.event.target, touchId = d3.event.touches ? d3.event.changedTouches[0].identifier : null, offset, origin_ = point(), moved = 0;\n      var w = d3.select(d3_window).on(touchId != null ? \"touchmove.drag-\" + touchId : \"mousemove.drag\", dragmove).on(touchId != null ? \"touchend.drag-\" + touchId : \"mouseup.drag\", dragend, true);\n      if (origin) {\n        offset = origin.apply(target, arguments);\n        offset = [ offset.x - origin_[0], offset.y - origin_[1] ];\n      } else {\n        offset = [ 0, 0 ];\n      }\n      if (touchId == null) d3_eventCancel();\n      event_({\n        type: \"dragstart\"\n      });\n      function point() {\n        var p = target.parentNode;\n        return touchId != null ? d3.touches(p).filter(function(p) {\n          return p.identifier === touchId;\n        })[0] : d3.mouse(p);\n      }\n      function dragmove() {\n        if (!target.parentNode) return dragend();\n        var p = point(), dx = p[0] - origin_[0], dy = p[1] - origin_[1];\n        moved |= dx | dy;\n        origin_ = p;\n        d3_eventCancel();\n        event_({\n          type: \"drag\",\n          x: p[0] + offset[0],\n          y: p[1] + offset[1],\n          dx: dx,\n          dy: dy\n        });\n      }\n      function dragend() {\n        event_({\n          type: \"dragend\"\n        });\n        if (moved) {\n          d3_eventCancel();\n          if (d3.event.target === eventTarget) w.on(\"click.drag\", click, true);\n        }\n        w.on(touchId != null ? \"touchmove.drag-\" + touchId : \"mousemove.drag\", null).on(touchId != null ? \"touchend.drag-\" + touchId : \"mouseup.drag\", null);\n      }\n      function click() {\n        d3_eventCancel();\n        w.on(\"click.drag\", null);\n      }\n    }\n    drag.origin = function(x) {\n      if (!arguments.length) return origin;\n      origin = x;\n      return drag;\n    };\n    return d3.rebind(drag, event, \"on\");\n  };\n  function d3_selection(groups) {\n    d3_arraySubclass(groups, d3_selectionPrototype);\n    return groups;\n  }\n  var d3_select = function(s, n) {\n    return n.querySelector(s);\n  }, d3_selectAll = function(s, n) {\n    return n.querySelectorAll(s);\n  }, d3_selectRoot = d3_document.documentElement, d3_selectMatcher = d3_selectRoot.matchesSelector || d3_selectRoot.webkitMatchesSelector || d3_selectRoot.mozMatchesSelector || d3_selectRoot.msMatchesSelector || d3_selectRoot.oMatchesSelector, d3_selectMatches = function(n, s) {\n    return d3_selectMatcher.call(n, s);\n  };\n  if (typeof Sizzle === \"function\") {\n    d3_select = function(s, n) {\n      return Sizzle(s, n)[0] || null;\n    };\n    d3_selectAll = function(s, n) {\n      return Sizzle.uniqueSort(Sizzle(s, n));\n    };\n    d3_selectMatches = Sizzle.matchesSelector;\n  }\n  var d3_selectionPrototype = [];\n  d3.selection = function() {\n    return d3_selectionRoot;\n  };\n  d3.selection.prototype = d3_selectionPrototype;\n  d3_selectionPrototype.select = function(selector) {\n    var subgroups = [], subgroup, subnode, group, node;\n    if (typeof selector !== \"function\") selector = d3_selection_selector(selector);\n    for (var j = -1, m = this.length; ++j < m; ) {\n      subgroups.push(subgroup = []);\n      subgroup.parentNode = (group = this[j]).parentNode;\n      for (var i = -1, n = group.length; ++i < n; ) {\n        if (node = group[i]) {\n          subgroup.push(subnode = selector.call(node, node.__data__, i));\n          if (subnode && \"__data__\" in node) subnode.__data__ = node.__data__;\n        } else {\n          subgroup.push(null);\n        }\n      }\n    }\n    return d3_selection(subgroups);\n  };\n  function d3_selection_selector(selector) {\n    return function() {\n      return d3_select(selector, this);\n    };\n  }\n  d3_selectionPrototype.selectAll = function(selector) {\n    var subgroups = [], subgroup, node;\n    if (typeof selector !== \"function\") selector = d3_selection_selectorAll(selector);\n    for (var j = -1, m = this.length; ++j < m; ) {\n      for (var group = this[j], i = -1, n = group.length; ++i < n; ) {\n        if (node = group[i]) {\n          subgroups.push(subgroup = d3_array(selector.call(node, node.__data__, i)));\n          subgroup.parentNode = node;\n        }\n      }\n    }\n    return d3_selection(subgroups);\n  };\n  function d3_selection_selectorAll(selector) {\n    return function() {\n      return d3_selectAll(selector, this);\n    };\n  }\n  var d3_nsPrefix = {\n    svg: \"http://www.w3.org/2000/svg\",\n    xhtml: \"http://www.w3.org/1999/xhtml\",\n    xlink: \"http://www.w3.org/1999/xlink\",\n    xml: \"http://www.w3.org/XML/1998/namespace\",\n    xmlns: \"http://www.w3.org/2000/xmlns/\"\n  };\n  d3.ns = {\n    prefix: d3_nsPrefix,\n    qualify: function(name) {\n      var i = name.indexOf(\":\"), prefix = name;\n      if (i >= 0) {\n        prefix = name.substring(0, i);\n        name = name.substring(i + 1);\n      }\n      return d3_nsPrefix.hasOwnProperty(prefix) ? {\n        space: d3_nsPrefix[prefix],\n        local: name\n      } : name;\n    }\n  };\n  d3_selectionPrototype.attr = function(name, value) {\n    if (arguments.length < 2) {\n      if (typeof name === \"string\") {\n        var node = this.node();\n        name = d3.ns.qualify(name);\n        return name.local ? node.getAttributeNS(name.space, name.local) : node.getAttribute(name);\n      }\n      for (value in name) this.each(d3_selection_attr(value, name[value]));\n      return this;\n    }\n    return this.each(d3_selection_attr(name, value));\n  };\n  function d3_selection_attr(name, value) {\n    name = d3.ns.qualify(name);\n    function attrNull() {\n      this.removeAttribute(name);\n    }\n    function attrNullNS() {\n      this.removeAttributeNS(name.space, name.local);\n    }\n    function attrConstant() {\n      this.setAttribute(name, value);\n    }\n    function attrConstantNS() {\n      this.setAttributeNS(name.space, name.local, value);\n    }\n    function attrFunction() {\n      var x = value.apply(this, arguments);\n      if (x == null) this.removeAttribute(name); else this.setAttribute(name, x);\n    }\n    function attrFunctionNS() {\n      var x = value.apply(this, arguments);\n      if (x == null) this.removeAttributeNS(name.space, name.local); else this.setAttributeNS(name.space, name.local, x);\n    }\n    return value == null ? name.local ? attrNullNS : attrNull : typeof value === \"function\" ? name.local ? attrFunctionNS : attrFunction : name.local ? attrConstantNS : attrConstant;\n  }\n  function d3_collapse(s) {\n    return s.trim().replace(/\\s+/g, \" \");\n  }\n  d3.requote = function(s) {\n    return s.replace(d3_requote_re, \"\\\\$&\");\n  };\n  var d3_requote_re = /[\\\\\\^\\$\\*\\+\\?\\|\\[\\]\\(\\)\\.\\{\\}]/g;\n  d3_selectionPrototype.classed = function(name, value) {\n    if (arguments.length < 2) {\n      if (typeof name === \"string\") {\n        var node = this.node(), n = (name = name.trim().split(/^|\\s+/g)).length, i = -1;\n        if (value = node.classList) {\n          while (++i < n) if (!value.contains(name[i])) return false;\n        } else {\n          value = node.getAttribute(\"class\");\n          while (++i < n) if (!d3_selection_classedRe(name[i]).test(value)) return false;\n        }\n        return true;\n      }\n      for (value in name) this.each(d3_selection_classed(value, name[value]));\n      return this;\n    }\n    return this.each(d3_selection_classed(name, value));\n  };\n  function d3_selection_classedRe(name) {\n    return new RegExp(\"(?:^|\\\\s+)\" + d3.requote(name) + \"(?:\\\\s+|$)\", \"g\");\n  }\n  function d3_selection_classed(name, value) {\n    name = name.trim().split(/\\s+/).map(d3_selection_classedName);\n    var n = name.length;\n    function classedConstant() {\n      var i = -1;\n      while (++i < n) name[i](this, value);\n    }\n    function classedFunction() {\n      var i = -1, x = value.apply(this, arguments);\n      while (++i < n) name[i](this, x);\n    }\n    return typeof value === \"function\" ? classedFunction : classedConstant;\n  }\n  function d3_selection_classedName(name) {\n    var re = d3_selection_classedRe(name);\n    return function(node, value) {\n      if (c = node.classList) return value ? c.add(name) : c.remove(name);\n      var c = node.getAttribute(\"class\") || \"\";\n      if (value) {\n        re.lastIndex = 0;\n        if (!re.test(c)) node.setAttribute(\"class\", d3_collapse(c + \" \" + name));\n      } else {\n        node.setAttribute(\"class\", d3_collapse(c.replace(re, \" \")));\n      }\n    };\n  }\n  d3_selectionPrototype.style = function(name, value, priority) {\n    var n = arguments.length;\n    if (n < 3) {\n      if (typeof name !== \"string\") {\n        if (n < 2) value = \"\";\n        for (priority in name) this.each(d3_selection_style(priority, name[priority], value));\n        return this;\n      }\n      if (n < 2) return d3_window.getComputedStyle(this.node(), null).getPropertyValue(name);\n      priority = \"\";\n    }\n    return this.each(d3_selection_style(name, value, priority));\n  };\n  function d3_selection_style(name, value, priority) {\n    function styleNull() {\n      this.style.removeProperty(name);\n    }\n    function styleConstant() {\n      this.style.setProperty(name, value, priority);\n    }\n    function styleFunction() {\n      var x = value.apply(this, arguments);\n      if (x == null) this.style.removeProperty(name); else this.style.setProperty(name, x, priority);\n    }\n    return value == null ? styleNull : typeof value === \"function\" ? styleFunction : styleConstant;\n  }\n  d3_selectionPrototype.property = function(name, value) {\n    if (arguments.length < 2) {\n      if (typeof name === \"string\") return this.node()[name];\n      for (value in name) this.each(d3_selection_property(value, name[value]));\n      return this;\n    }\n    return this.each(d3_selection_property(name, value));\n  };\n  function d3_selection_property(name, value) {\n    function propertyNull() {\n      delete this[name];\n    }\n    function propertyConstant() {\n      this[name] = value;\n    }\n    function propertyFunction() {\n      var x = value.apply(this, arguments);\n      if (x == null) delete this[name]; else this[name] = x;\n    }\n    return value == null ? propertyNull : typeof value === \"function\" ? propertyFunction : propertyConstant;\n  }\n  d3_selectionPrototype.text = function(value) {\n    return arguments.length ? this.each(typeof value === \"function\" ? function() {\n      var v = value.apply(this, arguments);\n      this.textContent = v == null ? \"\" : v;\n    } : value == null ? function() {\n      this.textContent = \"\";\n    } : function() {\n      this.textContent = value;\n    }) : this.node().textContent;\n  };\n  d3_selectionPrototype.html = function(value) {\n    return arguments.length ? this.each(typeof value === \"function\" ? function() {\n      var v = value.apply(this, arguments);\n      this.innerHTML = v == null ? \"\" : v;\n    } : value == null ? function() {\n      this.innerHTML = \"\";\n    } : function() {\n      this.innerHTML = value;\n    }) : this.node().innerHTML;\n  };\n  d3_selectionPrototype.append = function(name) {\n    name = d3.ns.qualify(name);\n    function append() {\n      return this.appendChild(d3_document.createElementNS(this.namespaceURI, name));\n    }\n    function appendNS() {\n      return this.appendChild(d3_document.createElementNS(name.space, name.local));\n    }\n    return this.select(name.local ? appendNS : append);\n  };\n  d3_selectionPrototype.insert = function(name, before) {\n    name = d3.ns.qualify(name);\n    if (typeof before !== \"function\") before = d3_selection_selector(before);\n    function insert(d, i) {\n      return this.insertBefore(d3_document.createElementNS(this.namespaceURI, name), before.call(this, d, i));\n    }\n    function insertNS(d, i) {\n      return this.insertBefore(d3_document.createElementNS(name.space, name.local), before.call(this, d, i));\n    }\n    return this.select(name.local ? insertNS : insert);\n  };\n  d3_selectionPrototype.remove = function() {\n    return this.each(function() {\n      var parent = this.parentNode;\n      if (parent) parent.removeChild(this);\n    });\n  };\n  d3_selectionPrototype.data = function(value, key) {\n    var i = -1, n = this.length, group, node;\n    if (!arguments.length) {\n      value = new Array(n = (group = this[0]).length);\n      while (++i < n) {\n        if (node = group[i]) {\n          value[i] = node.__data__;\n        }\n      }\n      return value;\n    }\n    function bind(group, groupData) {\n      var i, n = group.length, m = groupData.length, n0 = Math.min(n, m), updateNodes = new Array(m), enterNodes = new Array(m), exitNodes = new Array(n), node, nodeData;\n      if (key) {\n        var nodeByKeyValue = new d3_Map(), dataByKeyValue = new d3_Map(), keyValues = [], keyValue;\n        for (i = -1; ++i < n; ) {\n          keyValue = key.call(node = group[i], node.__data__, i);\n          if (nodeByKeyValue.has(keyValue)) {\n            exitNodes[i] = node;\n          } else {\n            nodeByKeyValue.set(keyValue, node);\n          }\n          keyValues.push(keyValue);\n        }\n        for (i = -1; ++i < m; ) {\n          keyValue = key.call(groupData, nodeData = groupData[i], i);\n          if (node = nodeByKeyValue.get(keyValue)) {\n            updateNodes[i] = node;\n            node.__data__ = nodeData;\n          } else if (!dataByKeyValue.has(keyValue)) {\n            enterNodes[i] = d3_selection_dataNode(nodeData);\n          }\n          dataByKeyValue.set(keyValue, nodeData);\n          nodeByKeyValue.remove(keyValue);\n        }\n        for (i = -1; ++i < n; ) {\n          if (nodeByKeyValue.has(keyValues[i])) {\n            exitNodes[i] = group[i];\n          }\n        }\n      } else {\n        for (i = -1; ++i < n0; ) {\n          node = group[i];\n          nodeData = groupData[i];\n          if (node) {\n            node.__data__ = nodeData;\n            updateNodes[i] = node;\n          } else {\n            enterNodes[i] = d3_selection_dataNode(nodeData);\n          }\n        }\n        for (;i < m; ++i) {\n          enterNodes[i] = d3_selection_dataNode(groupData[i]);\n        }\n        for (;i < n; ++i) {\n          exitNodes[i] = group[i];\n        }\n      }\n      enterNodes.update = updateNodes;\n      enterNodes.parentNode = updateNodes.parentNode = exitNodes.parentNode = group.parentNode;\n      enter.push(enterNodes);\n      update.push(updateNodes);\n      exit.push(exitNodes);\n    }\n    var enter = d3_selection_enter([]), update = d3_selection([]), exit = d3_selection([]);\n    if (typeof value === \"function\") {\n      while (++i < n) {\n        bind(group = this[i], value.call(group, group.parentNode.__data__, i));\n      }\n    } else {\n      while (++i < n) {\n        bind(group = this[i], value);\n      }\n    }\n    update.enter = function() {\n      return enter;\n    };\n    update.exit = function() {\n      return exit;\n    };\n    return update;\n  };\n  function d3_selection_dataNode(data) {\n    return {\n      __data__: data\n    };\n  }\n  d3_selectionPrototype.datum = function(value) {\n    return arguments.length ? this.property(\"__data__\", value) : this.property(\"__data__\");\n  };\n  d3_selectionPrototype.filter = function(filter) {\n    var subgroups = [], subgroup, group, node;\n    if (typeof filter !== \"function\") filter = d3_selection_filter(filter);\n    for (var j = 0, m = this.length; j < m; j++) {\n      subgroups.push(subgroup = []);\n      subgroup.parentNode = (group = this[j]).parentNode;\n      for (var i = 0, n = group.length; i < n; i++) {\n        if ((node = group[i]) && filter.call(node, node.__data__, i)) {\n          subgroup.push(node);\n        }\n      }\n    }\n    return d3_selection(subgroups);\n  };\n  function d3_selection_filter(selector) {\n    return function() {\n      return d3_selectMatches(this, selector);\n    };\n  }\n  d3_selectionPrototype.order = function() {\n    for (var j = -1, m = this.length; ++j < m; ) {\n      for (var group = this[j], i = group.length - 1, next = group[i], node; --i >= 0; ) {\n        if (node = group[i]) {\n          if (next && next !== node.nextSibling) next.parentNode.insertBefore(node, next);\n          next = node;\n        }\n      }\n    }\n    return this;\n  };\n  d3_selectionPrototype.sort = function(comparator) {\n    comparator = d3_selection_sortComparator.apply(this, arguments);\n    for (var j = -1, m = this.length; ++j < m; ) this[j].sort(comparator);\n    return this.order();\n  };\n  function d3_selection_sortComparator(comparator) {\n    if (!arguments.length) comparator = d3.ascending;\n    return function(a, b) {\n      return !a - !b || comparator(a.__data__, b.__data__);\n    };\n  }\n  function d3_noop() {}\n  d3_selectionPrototype.on = function(type, listener, capture) {\n    var n = arguments.length;\n    if (n < 3) {\n      if (typeof type !== \"string\") {\n        if (n < 2) listener = false;\n        for (capture in type) this.each(d3_selection_on(capture, type[capture], listener));\n        return this;\n      }\n      if (n < 2) return (n = this.node()[\"__on\" + type]) && n._;\n      capture = false;\n    }\n    return this.each(d3_selection_on(type, listener, capture));\n  };\n  function d3_selection_on(type, listener, capture) {\n    var name = \"__on\" + type, i = type.indexOf(\".\"), wrap = d3_selection_onListener;\n    if (i > 0) type = type.substring(0, i);\n    var filter = d3_selection_onFilters.get(type);\n    if (filter) type = filter, wrap = d3_selection_onFilter;\n    function onRemove() {\n      var l = this[name];\n      if (l) {\n        this.removeEventListener(type, l, l.$);\n        delete this[name];\n      }\n    }\n    function onAdd() {\n      var l = wrap(listener, d3_array(arguments));\n      onRemove.call(this);\n      this.addEventListener(type, this[name] = l, l.$ = capture);\n      l._ = listener;\n    }\n    function removeAll() {\n      var re = new RegExp(\"^__on([^.]+)\" + d3.requote(type) + \"$\"), match;\n      for (var name in this) {\n        if (match = name.match(re)) {\n          var l = this[name];\n          this.removeEventListener(match[1], l, l.$);\n          delete this[name];\n        }\n      }\n    }\n    return i ? listener ? onAdd : onRemove : listener ? d3_noop : removeAll;\n  }\n  var d3_selection_onFilters = d3.map({\n    mouseenter: \"mouseover\",\n    mouseleave: \"mouseout\"\n  });\n  d3_selection_onFilters.forEach(function(k) {\n    if (\"on\" + k in d3_document) d3_selection_onFilters.remove(k);\n  });\n  function d3_selection_onListener(listener, argumentz) {\n    return function(e) {\n      var o = d3.event;\n      d3.event = e;\n      argumentz[0] = this.__data__;\n      try {\n        listener.apply(this, argumentz);\n      } finally {\n        d3.event = o;\n      }\n    };\n  }\n  function d3_selection_onFilter(listener, argumentz) {\n    var l = d3_selection_onListener(listener, argumentz);\n    return function(e) {\n      var target = this, related = e.relatedTarget;\n      if (!related || related !== target && !(related.compareDocumentPosition(target) & 8)) {\n        l.call(target, e);\n      }\n    };\n  }\n  d3_selectionPrototype.each = function(callback) {\n    return d3_selection_each(this, function(node, i, j) {\n      callback.call(node, node.__data__, i, j);\n    });\n  };\n  function d3_selection_each(groups, callback) {\n    for (var j = 0, m = groups.length; j < m; j++) {\n      for (var group = groups[j], i = 0, n = group.length, node; i < n; i++) {\n        if (node = group[i]) callback(node, i, j);\n      }\n    }\n    return groups;\n  }\n  d3_selectionPrototype.call = function(callback) {\n    var args = d3_array(arguments);\n    callback.apply(args[0] = this, args);\n    return this;\n  };\n  d3_selectionPrototype.empty = function() {\n    return !this.node();\n  };\n  d3_selectionPrototype.node = function() {\n    for (var j = 0, m = this.length; j < m; j++) {\n      for (var group = this[j], i = 0, n = group.length; i < n; i++) {\n        var node = group[i];\n        if (node) return node;\n      }\n    }\n    return null;\n  };\n  function d3_selection_enter(selection) {\n    d3_arraySubclass(selection, d3_selection_enterPrototype);\n    return selection;\n  }\n  var d3_selection_enterPrototype = [];\n  d3.selection.enter = d3_selection_enter;\n  d3.selection.enter.prototype = d3_selection_enterPrototype;\n  d3_selection_enterPrototype.append = d3_selectionPrototype.append;\n  d3_selection_enterPrototype.insert = d3_selectionPrototype.insert;\n  d3_selection_enterPrototype.empty = d3_selectionPrototype.empty;\n  d3_selection_enterPrototype.node = d3_selectionPrototype.node;\n  d3_selection_enterPrototype.select = function(selector) {\n    var subgroups = [], subgroup, subnode, upgroup, group, node;\n    for (var j = -1, m = this.length; ++j < m; ) {\n      upgroup = (group = this[j]).update;\n      subgroups.push(subgroup = []);\n      subgroup.parentNode = group.parentNode;\n      for (var i = -1, n = group.length; ++i < n; ) {\n        if (node = group[i]) {\n          subgroup.push(upgroup[i] = subnode = selector.call(group.parentNode, node.__data__, i));\n          subnode.__data__ = node.__data__;\n        } else {\n          subgroup.push(null);\n        }\n      }\n    }\n    return d3_selection(subgroups);\n  };\n  d3_selectionPrototype.transition = function() {\n    var id = d3_transitionInheritId || ++d3_transitionId, subgroups = [], subgroup, node, transition = Object.create(d3_transitionInherit);\n    transition.time = Date.now();\n    for (var j = -1, m = this.length; ++j < m; ) {\n      subgroups.push(subgroup = []);\n      for (var group = this[j], i = -1, n = group.length; ++i < n; ) {\n        if (node = group[i]) d3_transitionNode(node, i, id, transition);\n        subgroup.push(node);\n      }\n    }\n    return d3_transition(subgroups, id);\n  };\n  var d3_selectionRoot = d3_selection([ [ d3_document ] ]);\n  d3_selectionRoot[0].parentNode = d3_selectRoot;\n  d3.select = function(selector) {\n    return typeof selector === \"string\" ? d3_selectionRoot.select(selector) : d3_selection([ [ selector ] ]);\n  };\n  d3.selectAll = function(selector) {\n    return typeof selector === \"string\" ? d3_selectionRoot.selectAll(selector) : d3_selection([ d3_array(selector) ]);\n  };\n  d3.behavior.zoom = function() {\n    var translate = [ 0, 0 ], translate0, scale = 1, scale0, scaleExtent = d3_behavior_zoomInfinity, event = d3_eventDispatch(zoom, \"zoom\"), x0, x1, y0, y1, touchtime;\n    function zoom() {\n      this.on(\"mousedown.zoom\", mousedown).on(\"mousemove.zoom\", mousemove).on(d3_behavior_zoomWheel + \".zoom\", mousewheel).on(\"dblclick.zoom\", dblclick).on(\"touchstart.zoom\", touchstart).on(\"touchmove.zoom\", touchmove).on(\"touchend.zoom\", touchstart);\n    }\n    zoom.translate = function(x) {\n      if (!arguments.length) return translate;\n      translate = x.map(Number);\n      rescale();\n      return zoom;\n    };\n    zoom.scale = function(x) {\n      if (!arguments.length) return scale;\n      scale = +x;\n      rescale();\n      return zoom;\n    };\n    zoom.scaleExtent = function(x) {\n      if (!arguments.length) return scaleExtent;\n      scaleExtent = x == null ? d3_behavior_zoomInfinity : x.map(Number);\n      return zoom;\n    };\n    zoom.x = function(z) {\n      if (!arguments.length) return x1;\n      x1 = z;\n      x0 = z.copy();\n      translate = [ 0, 0 ];\n      scale = 1;\n      return zoom;\n    };\n    zoom.y = function(z) {\n      if (!arguments.length) return y1;\n      y1 = z;\n      y0 = z.copy();\n      translate = [ 0, 0 ];\n      scale = 1;\n      return zoom;\n    };\n    function location(p) {\n      return [ (p[0] - translate[0]) / scale, (p[1] - translate[1]) / scale ];\n    }\n    function point(l) {\n      return [ l[0] * scale + translate[0], l[1] * scale + translate[1] ];\n    }\n    function scaleTo(s) {\n      scale = Math.max(scaleExtent[0], Math.min(scaleExtent[1], s));\n    }\n    function translateTo(p, l) {\n      l = point(l);\n      translate[0] += p[0] - l[0];\n      translate[1] += p[1] - l[1];\n    }\n    function rescale() {\n      if (x1) x1.domain(x0.range().map(function(x) {\n        return (x - translate[0]) / scale;\n      }).map(x0.invert));\n      if (y1) y1.domain(y0.range().map(function(y) {\n        return (y - translate[1]) / scale;\n      }).map(y0.invert));\n    }\n    function dispatch(event) {\n      rescale();\n      d3.event.preventDefault();\n      event({\n        type: \"zoom\",\n        scale: scale,\n        translate: translate\n      });\n    }\n    function mousedown() {\n      var target = this, event_ = event.of(target, arguments), eventTarget = d3.event.target, moved = 0, w = d3.select(d3_window).on(\"mousemove.zoom\", mousemove).on(\"mouseup.zoom\", mouseup), l = location(d3.mouse(target));\n      d3_window.focus();\n      d3_eventCancel();\n      function mousemove() {\n        moved = 1;\n        translateTo(d3.mouse(target), l);\n        dispatch(event_);\n      }\n      function mouseup() {\n        if (moved) d3_eventCancel();\n        w.on(\"mousemove.zoom\", null).on(\"mouseup.zoom\", null);\n        if (moved && d3.event.target === eventTarget) w.on(\"click.zoom\", click, true);\n      }\n      function click() {\n        d3_eventCancel();\n        w.on(\"click.zoom\", null);\n      }\n    }\n    function mousewheel() {\n      if (!translate0) translate0 = location(d3.mouse(this));\n      scaleTo(Math.pow(2, d3_behavior_zoomDelta() * .002) * scale);\n      translateTo(d3.mouse(this), translate0);\n      dispatch(event.of(this, arguments));\n    }\n    function mousemove() {\n      translate0 = null;\n    }\n    function dblclick() {\n      var p = d3.mouse(this), l = location(p), k = Math.log(scale) / Math.LN2;\n      scaleTo(Math.pow(2, d3.event.shiftKey ? Math.ceil(k) - 1 : Math.floor(k) + 1));\n      translateTo(p, l);\n      dispatch(event.of(this, arguments));\n    }\n    function touchstart() {\n      var touches = d3.touches(this), now = Date.now();\n      scale0 = scale;\n      translate0 = {};\n      touches.forEach(function(t) {\n        translate0[t.identifier] = location(t);\n      });\n      d3_eventCancel();\n      if (touches.length === 1) {\n        if (now - touchtime < 500) {\n          var p = touches[0], l = location(touches[0]);\n          scaleTo(scale * 2);\n          translateTo(p, l);\n          dispatch(event.of(this, arguments));\n        }\n        touchtime = now;\n      }\n    }\n    function touchmove() {\n      var touches = d3.touches(this), p0 = touches[0], l0 = translate0[p0.identifier];\n      if (p1 = touches[1]) {\n        var p1, l1 = translate0[p1.identifier];\n        p0 = [ (p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2 ];\n        l0 = [ (l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2 ];\n        scaleTo(d3.event.scale * scale0);\n      }\n      translateTo(p0, l0);\n      touchtime = null;\n      dispatch(event.of(this, arguments));\n    }\n    return d3.rebind(zoom, event, \"on\");\n  };\n  var d3_behavior_zoomInfinity = [ 0, Infinity ];\n  var d3_behavior_zoomDelta, d3_behavior_zoomWheel = \"onwheel\" in d3_document ? (d3_behavior_zoomDelta = function() {\n    return -d3.event.deltaY * (d3.event.deltaMode ? 120 : 1);\n  }, \"wheel\") : \"onmousewheel\" in d3_document ? (d3_behavior_zoomDelta = function() {\n    return d3.event.wheelDelta;\n  }, \"mousewheel\") : (d3_behavior_zoomDelta = function() {\n    return -d3.event.detail;\n  }, \"MozMousePixelScroll\");\n  function d3_Color() {}\n  d3_Color.prototype.toString = function() {\n    return this.rgb() + \"\";\n  };\n  d3.hsl = function(h, s, l) {\n    return arguments.length === 1 ? h instanceof d3_Hsl ? d3_hsl(h.h, h.s, h.l) : d3_rgb_parse(\"\" + h, d3_rgb_hsl, d3_hsl) : d3_hsl(+h, +s, +l);\n  };\n  function d3_hsl(h, s, l) {\n    return new d3_Hsl(h, s, l);\n  }\n  function d3_Hsl(h, s, l) {\n    this.h = h;\n    this.s = s;\n    this.l = l;\n  }\n  var d3_hslPrototype = d3_Hsl.prototype = new d3_Color();\n  d3_hslPrototype.brighter = function(k) {\n    k = Math.pow(.7, arguments.length ? k : 1);\n    return d3_hsl(this.h, this.s, this.l / k);\n  };\n  d3_hslPrototype.darker = function(k) {\n    k = Math.pow(.7, arguments.length ? k : 1);\n    return d3_hsl(this.h, this.s, k * this.l);\n  };\n  d3_hslPrototype.rgb = function() {\n    return d3_hsl_rgb(this.h, this.s, this.l);\n  };\n  function d3_hsl_rgb(h, s, l) {\n    var m1, m2;\n    h = h % 360;\n    if (h < 0) h += 360;\n    s = s < 0 ? 0 : s > 1 ? 1 : s;\n    l = l < 0 ? 0 : l > 1 ? 1 : l;\n    m2 = l <= .5 ? l * (1 + s) : l + s - l * s;\n    m1 = 2 * l - m2;\n    function v(h) {\n      if (h > 360) h -= 360; else if (h < 0) h += 360;\n      if (h < 60) return m1 + (m2 - m1) * h / 60;\n      if (h < 180) return m2;\n      if (h < 240) return m1 + (m2 - m1) * (240 - h) / 60;\n      return m1;\n    }\n    function vv(h) {\n      return Math.round(v(h) * 255);\n    }\n    return d3_rgb(vv(h + 120), vv(h), vv(h - 120));\n  }\n  var π = Math.PI, ε = 1e-6, d3_radians = π / 180, d3_degrees = 180 / π;\n  function d3_sgn(x) {\n    return x > 0 ? 1 : x < 0 ? -1 : 0;\n  }\n  function d3_acos(x) {\n    return Math.acos(Math.max(-1, Math.min(1, x)));\n  }\n  function d3_asin(x) {\n    return x > 1 ? π / 2 : x < -1 ? -π / 2 : Math.asin(x);\n  }\n  function d3_sinh(x) {\n    return (Math.exp(x) - Math.exp(-x)) / 2;\n  }\n  function d3_cosh(x) {\n    return (Math.exp(x) + Math.exp(-x)) / 2;\n  }\n  function d3_haversin(x) {\n    return (x = Math.sin(x / 2)) * x;\n  }\n  d3.hcl = function(h, c, l) {\n    return arguments.length === 1 ? h instanceof d3_Hcl ? d3_hcl(h.h, h.c, h.l) : h instanceof d3_Lab ? d3_lab_hcl(h.l, h.a, h.b) : d3_lab_hcl((h = d3_rgb_lab((h = d3.rgb(h)).r, h.g, h.b)).l, h.a, h.b) : d3_hcl(+h, +c, +l);\n  };\n  function d3_hcl(h, c, l) {\n    return new d3_Hcl(h, c, l);\n  }\n  function d3_Hcl(h, c, l) {\n    this.h = h;\n    this.c = c;\n    this.l = l;\n  }\n  var d3_hclPrototype = d3_Hcl.prototype = new d3_Color();\n  d3_hclPrototype.brighter = function(k) {\n    return d3_hcl(this.h, this.c, Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1)));\n  };\n  d3_hclPrototype.darker = function(k) {\n    return d3_hcl(this.h, this.c, Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1)));\n  };\n  d3_hclPrototype.rgb = function() {\n    return d3_hcl_lab(this.h, this.c, this.l).rgb();\n  };\n  function d3_hcl_lab(h, c, l) {\n    return d3_lab(l, Math.cos(h *= d3_radians) * c, Math.sin(h) * c);\n  }\n  d3.lab = function(l, a, b) {\n    return arguments.length === 1 ? l instanceof d3_Lab ? d3_lab(l.l, l.a, l.b) : l instanceof d3_Hcl ? d3_hcl_lab(l.l, l.c, l.h) : d3_rgb_lab((l = d3.rgb(l)).r, l.g, l.b) : d3_lab(+l, +a, +b);\n  };\n  function d3_lab(l, a, b) {\n    return new d3_Lab(l, a, b);\n  }\n  function d3_Lab(l, a, b) {\n    this.l = l;\n    this.a = a;\n    this.b = b;\n  }\n  var d3_lab_K = 18;\n  var d3_lab_X = .95047, d3_lab_Y = 1, d3_lab_Z = 1.08883;\n  var d3_labPrototype = d3_Lab.prototype = new d3_Color();\n  d3_labPrototype.brighter = function(k) {\n    return d3_lab(Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1)), this.a, this.b);\n  };\n  d3_labPrototype.darker = function(k) {\n    return d3_lab(Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1)), this.a, this.b);\n  };\n  d3_labPrototype.rgb = function() {\n    return d3_lab_rgb(this.l, this.a, this.b);\n  };\n  function d3_lab_rgb(l, a, b) {\n    var y = (l + 16) / 116, x = y + a / 500, z = y - b / 200;\n    x = d3_lab_xyz(x) * d3_lab_X;\n    y = d3_lab_xyz(y) * d3_lab_Y;\n    z = d3_lab_xyz(z) * d3_lab_Z;\n    return d3_rgb(d3_xyz_rgb(3.2404542 * x - 1.5371385 * y - .4985314 * z), d3_xyz_rgb(-.969266 * x + 1.8760108 * y + .041556 * z), d3_xyz_rgb(.0556434 * x - .2040259 * y + 1.0572252 * z));\n  }\n  function d3_lab_hcl(l, a, b) {\n    return d3_hcl(Math.atan2(b, a) * d3_degrees, Math.sqrt(a * a + b * b), l);\n  }\n  function d3_lab_xyz(x) {\n    return x > .206893034 ? x * x * x : (x - 4 / 29) / 7.787037;\n  }\n  function d3_xyz_lab(x) {\n    return x > .008856 ? Math.pow(x, 1 / 3) : 7.787037 * x + 4 / 29;\n  }\n  function d3_xyz_rgb(r) {\n    return Math.round(255 * (r <= .00304 ? 12.92 * r : 1.055 * Math.pow(r, 1 / 2.4) - .055));\n  }\n  d3.rgb = function(r, g, b) {\n    return arguments.length === 1 ? r instanceof d3_Rgb ? d3_rgb(r.r, r.g, r.b) : d3_rgb_parse(\"\" + r, d3_rgb, d3_hsl_rgb) : d3_rgb(~~r, ~~g, ~~b);\n  };\n  function d3_rgb(r, g, b) {\n    return new d3_Rgb(r, g, b);\n  }\n  function d3_Rgb(r, g, b) {\n    this.r = r;\n    this.g = g;\n    this.b = b;\n  }\n  var d3_rgbPrototype = d3_Rgb.prototype = new d3_Color();\n  d3_rgbPrototype.brighter = function(k) {\n    k = Math.pow(.7, arguments.length ? k : 1);\n    var r = this.r, g = this.g, b = this.b, i = 30;\n    if (!r && !g && !b) return d3_rgb(i, i, i);\n    if (r && r < i) r = i;\n    if (g && g < i) g = i;\n    if (b && b < i) b = i;\n    return d3_rgb(Math.min(255, Math.floor(r / k)), Math.min(255, Math.floor(g / k)), Math.min(255, Math.floor(b / k)));\n  };\n  d3_rgbPrototype.darker = function(k) {\n    k = Math.pow(.7, arguments.length ? k : 1);\n    return d3_rgb(Math.floor(k * this.r), Math.floor(k * this.g), Math.floor(k * this.b));\n  };\n  d3_rgbPrototype.hsl = function() {\n    return d3_rgb_hsl(this.r, this.g, this.b);\n  };\n  d3_rgbPrototype.toString = function() {\n    return \"#\" + d3_rgb_hex(this.r) + d3_rgb_hex(this.g) + d3_rgb_hex(this.b);\n  };\n  function d3_rgb_hex(v) {\n    return v < 16 ? \"0\" + Math.max(0, v).toString(16) : Math.min(255, v).toString(16);\n  }\n  function d3_rgb_parse(format, rgb, hsl) {\n    var r = 0, g = 0, b = 0, m1, m2, name;\n    m1 = /([a-z]+)\\((.*)\\)/i.exec(format);\n    if (m1) {\n      m2 = m1[2].split(\",\");\n      switch (m1[1]) {\n       case \"hsl\":\n        {\n          return hsl(parseFloat(m2[0]), parseFloat(m2[1]) / 100, parseFloat(m2[2]) / 100);\n        }\n\n       case \"rgb\":\n        {\n          return rgb(d3_rgb_parseNumber(m2[0]), d3_rgb_parseNumber(m2[1]), d3_rgb_parseNumber(m2[2]));\n        }\n      }\n    }\n    if (name = d3_rgb_names.get(format)) return rgb(name.r, name.g, name.b);\n    if (format != null && format.charAt(0) === \"#\") {\n      if (format.length === 4) {\n        r = format.charAt(1);\n        r += r;\n        g = format.charAt(2);\n        g += g;\n        b = format.charAt(3);\n        b += b;\n      } else if (format.length === 7) {\n        r = format.substring(1, 3);\n        g = format.substring(3, 5);\n        b = format.substring(5, 7);\n      }\n      r = parseInt(r, 16);\n      g = parseInt(g, 16);\n      b = parseInt(b, 16);\n    }\n    return rgb(r, g, b);\n  }\n  function d3_rgb_hsl(r, g, b) {\n    var min = Math.min(r /= 255, g /= 255, b /= 255), max = Math.max(r, g, b), d = max - min, h, s, l = (max + min) / 2;\n    if (d) {\n      s = l < .5 ? d / (max + min) : d / (2 - max - min);\n      if (r == max) h = (g - b) / d + (g < b ? 6 : 0); else if (g == max) h = (b - r) / d + 2; else h = (r - g) / d + 4;\n      h *= 60;\n    } else {\n      s = h = 0;\n    }\n    return d3_hsl(h, s, l);\n  }\n  function d3_rgb_lab(r, g, b) {\n    r = d3_rgb_xyz(r);\n    g = d3_rgb_xyz(g);\n    b = d3_rgb_xyz(b);\n    var x = d3_xyz_lab((.4124564 * r + .3575761 * g + .1804375 * b) / d3_lab_X), y = d3_xyz_lab((.2126729 * r + .7151522 * g + .072175 * b) / d3_lab_Y), z = d3_xyz_lab((.0193339 * r + .119192 * g + .9503041 * b) / d3_lab_Z);\n    return d3_lab(116 * y - 16, 500 * (x - y), 200 * (y - z));\n  }\n  function d3_rgb_xyz(r) {\n    return (r /= 255) <= .04045 ? r / 12.92 : Math.pow((r + .055) / 1.055, 2.4);\n  }\n  function d3_rgb_parseNumber(c) {\n    var f = parseFloat(c);\n    return c.charAt(c.length - 1) === \"%\" ? Math.round(f * 2.55) : f;\n  }\n  var d3_rgb_names = d3.map({\n    aliceblue: \"#f0f8ff\",\n    antiquewhite: \"#faebd7\",\n    aqua: \"#00ffff\",\n    aquamarine: \"#7fffd4\",\n    azure: \"#f0ffff\",\n    beige: \"#f5f5dc\",\n    bisque: \"#ffe4c4\",\n    black: \"#000000\",\n    blanchedalmond: \"#ffebcd\",\n    blue: \"#0000ff\",\n    blueviolet: \"#8a2be2\",\n    brown: \"#a52a2a\",\n    burlywood: \"#deb887\",\n    cadetblue: \"#5f9ea0\",\n    chartreuse: \"#7fff00\",\n    chocolate: \"#d2691e\",\n    coral: \"#ff7f50\",\n    cornflowerblue: \"#6495ed\",\n    cornsilk: \"#fff8dc\",\n    crimson: \"#dc143c\",\n    cyan: \"#00ffff\",\n    darkblue: \"#00008b\",\n    darkcyan: \"#008b8b\",\n    darkgoldenrod: \"#b8860b\",\n    darkgray: \"#a9a9a9\",\n    darkgreen: \"#006400\",\n    darkgrey: \"#a9a9a9\",\n    darkkhaki: \"#bdb76b\",\n    darkmagenta: \"#8b008b\",\n    darkolivegreen: \"#556b2f\",\n    darkorange: \"#ff8c00\",\n    darkorchid: \"#9932cc\",\n    darkred: \"#8b0000\",\n    darksalmon: \"#e9967a\",\n    darkseagreen: \"#8fbc8f\",\n    darkslateblue: \"#483d8b\",\n    darkslategray: \"#2f4f4f\",\n    darkslategrey: \"#2f4f4f\",\n    darkturquoise: \"#00ced1\",\n    darkviolet: \"#9400d3\",\n    deeppink: \"#ff1493\",\n    deepskyblue: \"#00bfff\",\n    dimgray: \"#696969\",\n    dimgrey: \"#696969\",\n    dodgerblue: \"#1e90ff\",\n    firebrick: \"#b22222\",\n    floralwhite: \"#fffaf0\",\n    forestgreen: \"#228b22\",\n    fuchsia: \"#ff00ff\",\n    gainsboro: \"#dcdcdc\",\n    ghostwhite: \"#f8f8ff\",\n    gold: \"#ffd700\",\n    goldenrod: \"#daa520\",\n    gray: \"#808080\",\n    green: \"#008000\",\n    greenyellow: \"#adff2f\",\n    grey: \"#808080\",\n    honeydew: \"#f0fff0\",\n    hotpink: \"#ff69b4\",\n    indianred: \"#cd5c5c\",\n    indigo: \"#4b0082\",\n    ivory: \"#fffff0\",\n    khaki: \"#f0e68c\",\n    lavender: \"#e6e6fa\",\n    lavenderblush: \"#fff0f5\",\n    lawngreen: \"#7cfc00\",\n    lemonchiffon: \"#fffacd\",\n    lightblue: \"#add8e6\",\n    lightcoral: \"#f08080\",\n    lightcyan: \"#e0ffff\",\n    lightgoldenrodyellow: \"#fafad2\",\n    lightgray: \"#d3d3d3\",\n    lightgreen: \"#90ee90\",\n    lightgrey: \"#d3d3d3\",\n    lightpink: \"#ffb6c1\",\n    lightsalmon: \"#ffa07a\",\n    lightseagreen: \"#20b2aa\",\n    lightskyblue: \"#87cefa\",\n    lightslategray: \"#778899\",\n    lightslategrey: \"#778899\",\n    lightsteelblue: \"#b0c4de\",\n    lightyellow: \"#ffffe0\",\n    lime: \"#00ff00\",\n    limegreen: \"#32cd32\",\n    linen: \"#faf0e6\",\n    magenta: \"#ff00ff\",\n    maroon: \"#800000\",\n    mediumaquamarine: \"#66cdaa\",\n    mediumblue: \"#0000cd\",\n    mediumorchid: \"#ba55d3\",\n    mediumpurple: \"#9370db\",\n    mediumseagreen: \"#3cb371\",\n    mediumslateblue: \"#7b68ee\",\n    mediumspringgreen: \"#00fa9a\",\n    mediumturquoise: \"#48d1cc\",\n    mediumvioletred: \"#c71585\",\n    midnightblue: \"#191970\",\n    mintcream: \"#f5fffa\",\n    mistyrose: \"#ffe4e1\",\n    moccasin: \"#ffe4b5\",\n    navajowhite: \"#ffdead\",\n    navy: \"#000080\",\n    oldlace: \"#fdf5e6\",\n    olive: \"#808000\",\n    olivedrab: \"#6b8e23\",\n    orange: \"#ffa500\",\n    orangered: \"#ff4500\",\n    orchid: \"#da70d6\",\n    palegoldenrod: \"#eee8aa\",\n    palegreen: \"#98fb98\",\n    paleturquoise: \"#afeeee\",\n    palevioletred: \"#db7093\",\n    papayawhip: \"#ffefd5\",\n    peachpuff: \"#ffdab9\",\n    peru: \"#cd853f\",\n    pink: \"#ffc0cb\",\n    plum: \"#dda0dd\",\n    powderblue: \"#b0e0e6\",\n    purple: \"#800080\",\n    red: \"#ff0000\",\n    rosybrown: \"#bc8f8f\",\n    royalblue: \"#4169e1\",\n    saddlebrown: \"#8b4513\",\n    salmon: \"#fa8072\",\n    sandybrown: \"#f4a460\",\n    seagreen: \"#2e8b57\",\n    seashell: \"#fff5ee\",\n    sienna: \"#a0522d\",\n    silver: \"#c0c0c0\",\n    skyblue: \"#87ceeb\",\n    slateblue: \"#6a5acd\",\n    slategray: \"#708090\",\n    slategrey: \"#708090\",\n    snow: \"#fffafa\",\n    springgreen: \"#00ff7f\",\n    steelblue: \"#4682b4\",\n    tan: \"#d2b48c\",\n    teal: \"#008080\",\n    thistle: \"#d8bfd8\",\n    tomato: \"#ff6347\",\n    turquoise: \"#40e0d0\",\n    violet: \"#ee82ee\",\n    wheat: \"#f5deb3\",\n    white: \"#ffffff\",\n    whitesmoke: \"#f5f5f5\",\n    yellow: \"#ffff00\",\n    yellowgreen: \"#9acd32\"\n  });\n  d3_rgb_names.forEach(function(key, value) {\n    d3_rgb_names.set(key, d3_rgb_parse(value, d3_rgb, d3_hsl_rgb));\n  });\n  function d3_functor(v) {\n    return typeof v === \"function\" ? v : function() {\n      return v;\n    };\n  }\n  d3.functor = d3_functor;\n  function d3_identity(d) {\n    return d;\n  }\n  d3.xhr = function(url, mimeType, callback) {\n    var xhr = {}, dispatch = d3.dispatch(\"progress\", \"load\", \"error\"), headers = {}, response = d3_identity, request = new (d3_window.XDomainRequest && /^(http(s)?:)?\\/\\//.test(url) ? XDomainRequest : XMLHttpRequest)();\n    \"onload\" in request ? request.onload = request.onerror = respond : request.onreadystatechange = function() {\n      request.readyState > 3 && respond();\n    };\n    function respond() {\n      var s = request.status;\n      !s && request.responseText || s >= 200 && s < 300 || s === 304 ? dispatch.load.call(xhr, response.call(xhr, request)) : dispatch.error.call(xhr, request);\n    }\n    request.onprogress = function(event) {\n      var o = d3.event;\n      d3.event = event;\n      try {\n        dispatch.progress.call(xhr, request);\n      } finally {\n        d3.event = o;\n      }\n    };\n    xhr.header = function(name, value) {\n      name = (name + \"\").toLowerCase();\n      if (arguments.length < 2) return headers[name];\n      if (value == null) delete headers[name]; else headers[name] = value + \"\";\n      return xhr;\n    };\n    xhr.mimeType = function(value) {\n      if (!arguments.length) return mimeType;\n      mimeType = value == null ? null : value + \"\";\n      return xhr;\n    };\n    xhr.response = function(value) {\n      response = value;\n      return xhr;\n    };\n    [ \"get\", \"post\" ].forEach(function(method) {\n      xhr[method] = function() {\n        return xhr.send.apply(xhr, [ method ].concat(d3_array(arguments)));\n      };\n    });\n    xhr.send = function(method, data, callback) {\n      if (arguments.length === 2 && typeof data === \"function\") callback = data, data = null;\n      request.open(method, url, true);\n      if (mimeType != null && !(\"accept\" in headers)) headers[\"accept\"] = mimeType + \",*/*\";\n      if (request.setRequestHeader) for (var name in headers) request.setRequestHeader(name, headers[name]);\n      if (mimeType != null && request.overrideMimeType) request.overrideMimeType(mimeType);\n      if (callback != null) xhr.on(\"error\", callback).on(\"load\", function(request) {\n        callback(null, request);\n      });\n      request.send(data == null ? null : data);\n      return xhr;\n    };\n    xhr.abort = function() {\n      request.abort();\n      return xhr;\n    };\n    d3.rebind(xhr, dispatch, \"on\");\n    if (arguments.length === 2 && typeof mimeType === \"function\") callback = mimeType, \n    mimeType = null;\n    return callback == null ? xhr : xhr.get(d3_xhr_fixCallback(callback));\n  };\n  function d3_xhr_fixCallback(callback) {\n    return callback.length === 1 ? function(error, request) {\n      callback(error == null ? request : null);\n    } : callback;\n  }\n  function d3_dsv(delimiter, mimeType) {\n    var reFormat = new RegExp('[\"' + delimiter + \"\\n]\"), delimiterCode = delimiter.charCodeAt(0);\n    function dsv(url, row, callback) {\n      if (arguments.length < 3) callback = row, row = null;\n      var xhr = d3.xhr(url, mimeType, callback);\n      xhr.row = function(_) {\n        return arguments.length ? xhr.response((row = _) == null ? response : typedResponse(_)) : row;\n      };\n      return xhr.row(row);\n    }\n    function response(request) {\n      return dsv.parse(request.responseText);\n    }\n    function typedResponse(f) {\n      return function(request) {\n        return dsv.parse(request.responseText, f);\n      };\n    }\n    dsv.parse = function(text, f) {\n      var o;\n      return dsv.parseRows(text, function(row, i) {\n        if (o) return o(row, i - 1);\n        var a = new Function(\"d\", \"return {\" + row.map(function(name, i) {\n          return JSON.stringify(name) + \": d[\" + i + \"]\";\n        }).join(\",\") + \"}\");\n        o = f ? function(row, i) {\n          return f(a(row), i);\n        } : a;\n      });\n    };\n    dsv.parseRows = function(text, f) {\n      var EOL = {}, EOF = {}, rows = [], N = text.length, I = 0, n = 0, t, eol;\n      function token() {\n        if (I >= N) return EOF;\n        if (eol) return eol = false, EOL;\n        var j = I;\n        if (text.charCodeAt(j) === 34) {\n          var i = j;\n          while (i++ < N) {\n            if (text.charCodeAt(i) === 34) {\n              if (text.charCodeAt(i + 1) !== 34) break;\n              ++i;\n            }\n          }\n          I = i + 2;\n          var c = text.charCodeAt(i + 1);\n          if (c === 13) {\n            eol = true;\n            if (text.charCodeAt(i + 2) === 10) ++I;\n          } else if (c === 10) {\n            eol = true;\n          }\n          return text.substring(j + 1, i).replace(/\"\"/g, '\"');\n        }\n        while (I < N) {\n          var c = text.charCodeAt(I++), k = 1;\n          if (c === 10) eol = true; else if (c === 13) {\n            eol = true;\n            if (text.charCodeAt(I) === 10) ++I, ++k;\n          } else if (c !== delimiterCode) continue;\n          return text.substring(j, I - k);\n        }\n        return text.substring(j);\n      }\n      while ((t = token()) !== EOF) {\n        var a = [];\n        while (t !== EOL && t !== EOF) {\n          a.push(t);\n          t = token();\n        }\n        if (f && !(a = f(a, n++))) continue;\n        rows.push(a);\n      }\n      return rows;\n    };\n    dsv.format = function(rows) {\n      if (Array.isArray(rows[0])) return dsv.formatRows(rows);\n      var fieldSet = new d3_Set(), fields = [];\n      rows.forEach(function(row) {\n        for (var field in row) {\n          if (!fieldSet.has(field)) {\n            fields.push(fieldSet.add(field));\n          }\n        }\n      });\n      return [ fields.map(formatValue).join(delimiter) ].concat(rows.map(function(row) {\n        return fields.map(function(field) {\n          return formatValue(row[field]);\n        }).join(delimiter);\n      })).join(\"\\n\");\n    };\n    dsv.formatRows = function(rows) {\n      return rows.map(formatRow).join(\"\\n\");\n    };\n    function formatRow(row) {\n      return row.map(formatValue).join(delimiter);\n    }\n    function formatValue(text) {\n      return reFormat.test(text) ? '\"' + text.replace(/\\\"/g, '\"\"') + '\"' : text;\n    }\n    return dsv;\n  }\n  d3.csv = d3_dsv(\",\", \"text/csv\");\n  d3.tsv = d3_dsv(\"\t\", \"text/tab-separated-values\");\n  var d3_timer_id = 0, d3_timer_byId = {}, d3_timer_queue = null, d3_timer_interval, d3_timer_timeout;\n  d3.timer = function(callback, delay, then) {\n    if (arguments.length < 3) {\n      if (arguments.length < 2) delay = 0; else if (!isFinite(delay)) return;\n      then = Date.now();\n    }\n    var timer = d3_timer_byId[callback.id];\n    if (timer && timer.callback === callback) {\n      timer.then = then;\n      timer.delay = delay;\n    } else d3_timer_byId[callback.id = ++d3_timer_id] = d3_timer_queue = {\n      callback: callback,\n      then: then,\n      delay: delay,\n      next: d3_timer_queue\n    };\n    if (!d3_timer_interval) {\n      d3_timer_timeout = clearTimeout(d3_timer_timeout);\n      d3_timer_interval = 1;\n      d3_timer_frame(d3_timer_step);\n    }\n  };\n  function d3_timer_step() {\n    var elapsed, now = Date.now(), t1 = d3_timer_queue;\n    while (t1) {\n      elapsed = now - t1.then;\n      if (elapsed >= t1.delay) t1.flush = t1.callback(elapsed);\n      t1 = t1.next;\n    }\n    var delay = d3_timer_flush() - now;\n    if (delay > 24) {\n      if (isFinite(delay)) {\n        clearTimeout(d3_timer_timeout);\n        d3_timer_timeout = setTimeout(d3_timer_step, delay);\n      }\n      d3_timer_interval = 0;\n    } else {\n      d3_timer_interval = 1;\n      d3_timer_frame(d3_timer_step);\n    }\n  }\n  d3.timer.flush = function() {\n    var elapsed, now = Date.now(), t1 = d3_timer_queue;\n    while (t1) {\n      elapsed = now - t1.then;\n      if (!t1.delay) t1.flush = t1.callback(elapsed);\n      t1 = t1.next;\n    }\n    d3_timer_flush();\n  };\n  function d3_timer_flush() {\n    var t0 = null, t1 = d3_timer_queue, then = Infinity;\n    while (t1) {\n      if (t1.flush) {\n        delete d3_timer_byId[t1.callback.id];\n        t1 = t0 ? t0.next = t1.next : d3_timer_queue = t1.next;\n      } else {\n        then = Math.min(then, t1.then + t1.delay);\n        t1 = (t0 = t1).next;\n      }\n    }\n    return then;\n  }\n  var d3_timer_frame = d3_window.requestAnimationFrame || d3_window.webkitRequestAnimationFrame || d3_window.mozRequestAnimationFrame || d3_window.oRequestAnimationFrame || d3_window.msRequestAnimationFrame || function(callback) {\n    setTimeout(callback, 17);\n  };\n  var d3_format_decimalPoint = \".\", d3_format_thousandsSeparator = \",\", d3_format_grouping = [ 3, 3 ];\n  var d3_formatPrefixes = [ \"y\", \"z\", \"a\", \"f\", \"p\", \"n\", \"µ\", \"m\", \"\", \"k\", \"M\", \"G\", \"T\", \"P\", \"E\", \"Z\", \"Y\" ].map(d3_formatPrefix);\n  d3.formatPrefix = function(value, precision) {\n    var i = 0;\n    if (value) {\n      if (value < 0) value *= -1;\n      if (precision) value = d3.round(value, d3_format_precision(value, precision));\n      i = 1 + Math.floor(1e-12 + Math.log(value) / Math.LN10);\n      i = Math.max(-24, Math.min(24, Math.floor((i <= 0 ? i + 1 : i - 1) / 3) * 3));\n    }\n    return d3_formatPrefixes[8 + i / 3];\n  };\n  function d3_formatPrefix(d, i) {\n    var k = Math.pow(10, Math.abs(8 - i) * 3);\n    return {\n      scale: i > 8 ? function(d) {\n        return d / k;\n      } : function(d) {\n        return d * k;\n      },\n      symbol: d\n    };\n  }\n  d3.round = function(x, n) {\n    return n ? Math.round(x * (n = Math.pow(10, n))) / n : Math.round(x);\n  };\n  d3.format = function(specifier) {\n    var match = d3_format_re.exec(specifier), fill = match[1] || \" \", align = match[2] || \">\", sign = match[3] || \"\", basePrefix = match[4] || \"\", zfill = match[5], width = +match[6], comma = match[7], precision = match[8], type = match[9], scale = 1, suffix = \"\", integer = false;\n    if (precision) precision = +precision.substring(1);\n    if (zfill || fill === \"0\" && align === \"=\") {\n      zfill = fill = \"0\";\n      align = \"=\";\n      if (comma) width -= Math.floor((width - 1) / 4);\n    }\n    switch (type) {\n     case \"n\":\n      comma = true;\n      type = \"g\";\n      break;\n\n     case \"%\":\n      scale = 100;\n      suffix = \"%\";\n      type = \"f\";\n      break;\n\n     case \"p\":\n      scale = 100;\n      suffix = \"%\";\n      type = \"r\";\n      break;\n\n     case \"b\":\n     case \"o\":\n     case \"x\":\n     case \"X\":\n      if (basePrefix) basePrefix = \"0\" + type.toLowerCase();\n\n     case \"c\":\n     case \"d\":\n      integer = true;\n      precision = 0;\n      break;\n\n     case \"s\":\n      scale = -1;\n      type = \"r\";\n      break;\n    }\n    if (basePrefix === \"#\") basePrefix = \"\";\n    if (type == \"r\" && !precision) type = \"g\";\n    if (precision != null) {\n      if (type == \"g\") precision = Math.max(1, Math.min(21, precision)); else if (type == \"e\" || type == \"f\") precision = Math.max(0, Math.min(20, precision));\n    }\n    type = d3_format_types.get(type) || d3_format_typeDefault;\n    var zcomma = zfill && comma;\n    return function(value) {\n      if (integer && value % 1) return \"\";\n      var negative = value < 0 || value === 0 && 1 / value < 0 ? (value = -value, \"-\") : sign;\n      if (scale < 0) {\n        var prefix = d3.formatPrefix(value, precision);\n        value = prefix.scale(value);\n        suffix = prefix.symbol;\n      } else {\n        value *= scale;\n      }\n      value = type(value, precision);\n      if (!zfill && comma) value = d3_format_group(value);\n      var length = basePrefix.length + value.length + (zcomma ? 0 : negative.length), padding = length < width ? new Array(length = width - length + 1).join(fill) : \"\";\n      if (zcomma) value = d3_format_group(padding + value);\n      if (d3_format_decimalPoint) value.replace(\".\", d3_format_decimalPoint);\n      negative += basePrefix;\n      return (align === \"<\" ? negative + value + padding : align === \">\" ? padding + negative + value : align === \"^\" ? padding.substring(0, length >>= 1) + negative + value + padding.substring(length) : negative + (zcomma ? value : padding + value)) + suffix;\n    };\n  };\n  var d3_format_re = /(?:([^{])?([<>=^]))?([+\\- ])?(#)?(0)?(\\d+)?(,)?(\\.-?\\d+)?([a-z%])?/i;\n  var d3_format_types = d3.map({\n    b: function(x) {\n      return x.toString(2);\n    },\n    c: function(x) {\n      return String.fromCharCode(x);\n    },\n    o: function(x) {\n      return x.toString(8);\n    },\n    x: function(x) {\n      return x.toString(16);\n    },\n    X: function(x) {\n      return x.toString(16).toUpperCase();\n    },\n    g: function(x, p) {\n      return x.toPrecision(p);\n    },\n    e: function(x, p) {\n      return x.toExponential(p);\n    },\n    f: function(x, p) {\n      return x.toFixed(p);\n    },\n    r: function(x, p) {\n      return (x = d3.round(x, d3_format_precision(x, p))).toFixed(Math.max(0, Math.min(20, d3_format_precision(x * (1 + 1e-15), p))));\n    }\n  });\n  function d3_format_precision(x, p) {\n    return p - (x ? Math.ceil(Math.log(x) / Math.LN10) : 1);\n  }\n  function d3_format_typeDefault(x) {\n    return x + \"\";\n  }\n  var d3_format_group = d3_identity;\n  if (d3_format_grouping) {\n    var d3_format_groupingLength = d3_format_grouping.length;\n    d3_format_group = function(value) {\n      var i = value.lastIndexOf(\".\"), f = i >= 0 ? \".\" + value.substring(i + 1) : (i = value.length, \n      \"\"), t = [], j = 0, g = d3_format_grouping[0];\n      while (i > 0 && g > 0) {\n        t.push(value.substring(i -= g, i + g));\n        g = d3_format_grouping[j = (j + 1) % d3_format_groupingLength];\n      }\n      return t.reverse().join(d3_format_thousandsSeparator || \"\") + f;\n    };\n  }\n  d3.geo = {};\n  d3.geo.stream = function(object, listener) {\n    if (d3_geo_streamObjectType.hasOwnProperty(object.type)) {\n      d3_geo_streamObjectType[object.type](object, listener);\n    } else {\n      d3_geo_streamGeometry(object, listener);\n    }\n  };\n  function d3_geo_streamGeometry(geometry, listener) {\n    if (d3_geo_streamGeometryType.hasOwnProperty(geometry.type)) {\n      d3_geo_streamGeometryType[geometry.type](geometry, listener);\n    }\n  }\n  var d3_geo_streamObjectType = {\n    Feature: function(feature, listener) {\n      d3_geo_streamGeometry(feature.geometry, listener);\n    },\n    FeatureCollection: function(object, listener) {\n      var features = object.features, i = -1, n = features.length;\n      while (++i < n) d3_geo_streamGeometry(features[i].geometry, listener);\n    }\n  };\n  var d3_geo_streamGeometryType = {\n    Sphere: function(object, listener) {\n      listener.sphere();\n    },\n    Point: function(object, listener) {\n      var coordinate = object.coordinates;\n      listener.point(coordinate[0], coordinate[1]);\n    },\n    MultiPoint: function(object, listener) {\n      var coordinates = object.coordinates, i = -1, n = coordinates.length, coordinate;\n      while (++i < n) coordinate = coordinates[i], listener.point(coordinate[0], coordinate[1]);\n    },\n    LineString: function(object, listener) {\n      d3_geo_streamLine(object.coordinates, listener, 0);\n    },\n    MultiLineString: function(object, listener) {\n      var coordinates = object.coordinates, i = -1, n = coordinates.length;\n      while (++i < n) d3_geo_streamLine(coordinates[i], listener, 0);\n    },\n    Polygon: function(object, listener) {\n      d3_geo_streamPolygon(object.coordinates, listener);\n    },\n    MultiPolygon: function(object, listener) {\n      var coordinates = object.coordinates, i = -1, n = coordinates.length;\n      while (++i < n) d3_geo_streamPolygon(coordinates[i], listener);\n    },\n    GeometryCollection: function(object, listener) {\n      var geometries = object.geometries, i = -1, n = geometries.length;\n      while (++i < n) d3_geo_streamGeometry(geometries[i], listener);\n    }\n  };\n  function d3_geo_streamLine(coordinates, listener, closed) {\n    var i = -1, n = coordinates.length - closed, coordinate;\n    listener.lineStart();\n    while (++i < n) coordinate = coordinates[i], listener.point(coordinate[0], coordinate[1]);\n    listener.lineEnd();\n  }\n  function d3_geo_streamPolygon(coordinates, listener) {\n    var i = -1, n = coordinates.length;\n    listener.polygonStart();\n    while (++i < n) d3_geo_streamLine(coordinates[i], listener, 1);\n    listener.polygonEnd();\n  }\n  d3.geo.area = function(object) {\n    d3_geo_areaSum = 0;\n    d3.geo.stream(object, d3_geo_area);\n    return d3_geo_areaSum;\n  };\n  var d3_geo_areaSum, d3_geo_areaRingU, d3_geo_areaRingV;\n  var d3_geo_area = {\n    sphere: function() {\n      d3_geo_areaSum += 4 * π;\n    },\n    point: d3_noop,\n    lineStart: d3_noop,\n    lineEnd: d3_noop,\n    polygonStart: function() {\n      d3_geo_areaRingU = 1, d3_geo_areaRingV = 0;\n      d3_geo_area.lineStart = d3_geo_areaRingStart;\n    },\n    polygonEnd: function() {\n      var area = 2 * Math.atan2(d3_geo_areaRingV, d3_geo_areaRingU);\n      d3_geo_areaSum += area < 0 ? 4 * π + area : area;\n      d3_geo_area.lineStart = d3_geo_area.lineEnd = d3_geo_area.point = d3_noop;\n    }\n  };\n  function d3_geo_areaRingStart() {\n    var λ00, φ00, λ0, cosφ0, sinφ0;\n    d3_geo_area.point = function(λ, φ) {\n      d3_geo_area.point = nextPoint;\n      λ0 = (λ00 = λ) * d3_radians, cosφ0 = Math.cos(φ = (φ00 = φ) * d3_radians / 2 + π / 4), \n      sinφ0 = Math.sin(φ);\n    };\n    function nextPoint(λ, φ) {\n      λ *= d3_radians;\n      φ = φ * d3_radians / 2 + π / 4;\n      var dλ = λ - λ0, cosφ = Math.cos(φ), sinφ = Math.sin(φ), k = sinφ0 * sinφ, u0 = d3_geo_areaRingU, v0 = d3_geo_areaRingV, u = cosφ0 * cosφ + k * Math.cos(dλ), v = k * Math.sin(dλ);\n      d3_geo_areaRingU = u0 * u - v0 * v;\n      d3_geo_areaRingV = v0 * u + u0 * v;\n      λ0 = λ, cosφ0 = cosφ, sinφ0 = sinφ;\n    }\n    d3_geo_area.lineEnd = function() {\n      nextPoint(λ00, φ00);\n    };\n  }\n  d3.geo.bounds = d3_geo_bounds(d3_identity);\n  function d3_geo_bounds(projectStream) {\n    var x0, y0, x1, y1;\n    var bound = {\n      point: boundPoint,\n      lineStart: d3_noop,\n      lineEnd: d3_noop,\n      polygonStart: function() {\n        bound.lineEnd = boundPolygonLineEnd;\n      },\n      polygonEnd: function() {\n        bound.point = boundPoint;\n      }\n    };\n    function boundPoint(x, y) {\n      if (x < x0) x0 = x;\n      if (x > x1) x1 = x;\n      if (y < y0) y0 = y;\n      if (y > y1) y1 = y;\n    }\n    function boundPolygonLineEnd() {\n      bound.point = bound.lineEnd = d3_noop;\n    }\n    return function(feature) {\n      y1 = x1 = -(x0 = y0 = Infinity);\n      d3.geo.stream(feature, projectStream(bound));\n      return [ [ x0, y0 ], [ x1, y1 ] ];\n    };\n  }\n  d3.geo.centroid = function(object) {\n    d3_geo_centroidDimension = d3_geo_centroidW = d3_geo_centroidX = d3_geo_centroidY = d3_geo_centroidZ = 0;\n    d3.geo.stream(object, d3_geo_centroid);\n    var m;\n    if (d3_geo_centroidW && Math.abs(m = Math.sqrt(d3_geo_centroidX * d3_geo_centroidX + d3_geo_centroidY * d3_geo_centroidY + d3_geo_centroidZ * d3_geo_centroidZ)) > ε) {\n      return [ Math.atan2(d3_geo_centroidY, d3_geo_centroidX) * d3_degrees, Math.asin(Math.max(-1, Math.min(1, d3_geo_centroidZ / m))) * d3_degrees ];\n    }\n  };\n  var d3_geo_centroidDimension, d3_geo_centroidW, d3_geo_centroidX, d3_geo_centroidY, d3_geo_centroidZ;\n  var d3_geo_centroid = {\n    sphere: function() {\n      if (d3_geo_centroidDimension < 2) {\n        d3_geo_centroidDimension = 2;\n        d3_geo_centroidW = d3_geo_centroidX = d3_geo_centroidY = d3_geo_centroidZ = 0;\n      }\n    },\n    point: d3_geo_centroidPoint,\n    lineStart: d3_geo_centroidLineStart,\n    lineEnd: d3_geo_centroidLineEnd,\n    polygonStart: function() {\n      if (d3_geo_centroidDimension < 2) {\n        d3_geo_centroidDimension = 2;\n        d3_geo_centroidW = d3_geo_centroidX = d3_geo_centroidY = d3_geo_centroidZ = 0;\n      }\n      d3_geo_centroid.lineStart = d3_geo_centroidRingStart;\n    },\n    polygonEnd: function() {\n      d3_geo_centroid.lineStart = d3_geo_centroidLineStart;\n    }\n  };\n  function d3_geo_centroidPoint(λ, φ) {\n    if (d3_geo_centroidDimension) return;\n    ++d3_geo_centroidW;\n    λ *= d3_radians;\n    var cosφ = Math.cos(φ *= d3_radians);\n    d3_geo_centroidX += (cosφ * Math.cos(λ) - d3_geo_centroidX) / d3_geo_centroidW;\n    d3_geo_centroidY += (cosφ * Math.sin(λ) - d3_geo_centroidY) / d3_geo_centroidW;\n    d3_geo_centroidZ += (Math.sin(φ) - d3_geo_centroidZ) / d3_geo_centroidW;\n  }\n  function d3_geo_centroidRingStart() {\n    var λ00, φ00;\n    d3_geo_centroidDimension = 1;\n    d3_geo_centroidLineStart();\n    d3_geo_centroidDimension = 2;\n    var linePoint = d3_geo_centroid.point;\n    d3_geo_centroid.point = function(λ, φ) {\n      linePoint(λ00 = λ, φ00 = φ);\n    };\n    d3_geo_centroid.lineEnd = function() {\n      d3_geo_centroid.point(λ00, φ00);\n      d3_geo_centroidLineEnd();\n      d3_geo_centroid.lineEnd = d3_geo_centroidLineEnd;\n    };\n  }\n  function d3_geo_centroidLineStart() {\n    var x0, y0, z0;\n    if (d3_geo_centroidDimension > 1) return;\n    if (d3_geo_centroidDimension < 1) {\n      d3_geo_centroidDimension = 1;\n      d3_geo_centroidW = d3_geo_centroidX = d3_geo_centroidY = d3_geo_centroidZ = 0;\n    }\n    d3_geo_centroid.point = function(λ, φ) {\n      λ *= d3_radians;\n      var cosφ = Math.cos(φ *= d3_radians);\n      x0 = cosφ * Math.cos(λ);\n      y0 = cosφ * Math.sin(λ);\n      z0 = Math.sin(φ);\n      d3_geo_centroid.point = nextPoint;\n    };\n    function nextPoint(λ, φ) {\n      λ *= d3_radians;\n      var cosφ = Math.cos(φ *= d3_radians), x = cosφ * Math.cos(λ), y = cosφ * Math.sin(λ), z = Math.sin(φ), w = Math.atan2(Math.sqrt((w = y0 * z - z0 * y) * w + (w = z0 * x - x0 * z) * w + (w = x0 * y - y0 * x) * w), x0 * x + y0 * y + z0 * z);\n      d3_geo_centroidW += w;\n      d3_geo_centroidX += w * (x0 + (x0 = x));\n      d3_geo_centroidY += w * (y0 + (y0 = y));\n      d3_geo_centroidZ += w * (z0 + (z0 = z));\n    }\n  }\n  function d3_geo_centroidLineEnd() {\n    d3_geo_centroid.point = d3_geo_centroidPoint;\n  }\n  function d3_geo_cartesian(spherical) {\n    var λ = spherical[0], φ = spherical[1], cosφ = Math.cos(φ);\n    return [ cosφ * Math.cos(λ), cosφ * Math.sin(λ), Math.sin(φ) ];\n  }\n  function d3_geo_cartesianDot(a, b) {\n    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];\n  }\n  function d3_geo_cartesianCross(a, b) {\n    return [ a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0] ];\n  }\n  function d3_geo_cartesianAdd(a, b) {\n    a[0] += b[0];\n    a[1] += b[1];\n    a[2] += b[2];\n  }\n  function d3_geo_cartesianScale(vector, k) {\n    return [ vector[0] * k, vector[1] * k, vector[2] * k ];\n  }\n  function d3_geo_cartesianNormalize(d) {\n    var l = Math.sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]);\n    d[0] /= l;\n    d[1] /= l;\n    d[2] /= l;\n  }\n  function d3_true() {\n    return true;\n  }\n  function d3_geo_spherical(cartesian) {\n    return [ Math.atan2(cartesian[1], cartesian[0]), Math.asin(Math.max(-1, Math.min(1, cartesian[2]))) ];\n  }\n  function d3_geo_sphericalEqual(a, b) {\n    return Math.abs(a[0] - b[0]) < ε && Math.abs(a[1] - b[1]) < ε;\n  }\n  function d3_geo_clipPolygon(segments, compare, inside, interpolate, listener) {\n    var subject = [], clip = [];\n    segments.forEach(function(segment) {\n      if ((n = segment.length - 1) <= 0) return;\n      var n, p0 = segment[0], p1 = segment[n];\n      if (d3_geo_sphericalEqual(p0, p1)) {\n        listener.lineStart();\n        for (var i = 0; i < n; ++i) listener.point((p0 = segment[i])[0], p0[1]);\n        listener.lineEnd();\n        return;\n      }\n      var a = {\n        point: p0,\n        points: segment,\n        other: null,\n        visited: false,\n        entry: true,\n        subject: true\n      }, b = {\n        point: p0,\n        points: [ p0 ],\n        other: a,\n        visited: false,\n        entry: false,\n        subject: false\n      };\n      a.other = b;\n      subject.push(a);\n      clip.push(b);\n      a = {\n        point: p1,\n        points: [ p1 ],\n        other: null,\n        visited: false,\n        entry: false,\n        subject: true\n      };\n      b = {\n        point: p1,\n        points: [ p1 ],\n        other: a,\n        visited: false,\n        entry: true,\n        subject: false\n      };\n      a.other = b;\n      subject.push(a);\n      clip.push(b);\n    });\n    clip.sort(compare);\n    d3_geo_clipPolygonLinkCircular(subject);\n    d3_geo_clipPolygonLinkCircular(clip);\n    if (!subject.length) return;\n    if (inside) for (var i = 1, e = !inside(clip[0].point), n = clip.length; i < n; ++i) {\n      clip[i].entry = e = !e;\n    }\n    var start = subject[0], current, points, point;\n    while (1) {\n      current = start;\n      while (current.visited) if ((current = current.next) === start) return;\n      points = current.points;\n      listener.lineStart();\n      do {\n        current.visited = current.other.visited = true;\n        if (current.entry) {\n          if (current.subject) {\n            for (var i = 0; i < points.length; i++) listener.point((point = points[i])[0], point[1]);\n          } else {\n            interpolate(current.point, current.next.point, 1, listener);\n          }\n          current = current.next;\n        } else {\n          if (current.subject) {\n            points = current.prev.points;\n            for (var i = points.length; --i >= 0; ) listener.point((point = points[i])[0], point[1]);\n          } else {\n            interpolate(current.point, current.prev.point, -1, listener);\n          }\n          current = current.prev;\n        }\n        current = current.other;\n        points = current.points;\n      } while (!current.visited);\n      listener.lineEnd();\n    }\n  }\n  function d3_geo_clipPolygonLinkCircular(array) {\n    if (!(n = array.length)) return;\n    var n, i = 0, a = array[0], b;\n    while (++i < n) {\n      a.next = b = array[i];\n      b.prev = a;\n      a = b;\n    }\n    a.next = b = array[0];\n    b.prev = a;\n  }\n  function d3_geo_clip(pointVisible, clipLine, interpolate) {\n    return function(listener) {\n      var line = clipLine(listener);\n      var clip = {\n        point: point,\n        lineStart: lineStart,\n        lineEnd: lineEnd,\n        polygonStart: function() {\n          clip.point = pointRing;\n          clip.lineStart = ringStart;\n          clip.lineEnd = ringEnd;\n          invisible = false;\n          invisibleArea = visibleArea = 0;\n          segments = [];\n          listener.polygonStart();\n        },\n        polygonEnd: function() {\n          clip.point = point;\n          clip.lineStart = lineStart;\n          clip.lineEnd = lineEnd;\n          segments = d3.merge(segments);\n          if (segments.length) {\n            d3_geo_clipPolygon(segments, d3_geo_clipSort, null, interpolate, listener);\n          } else if (visibleArea < -ε || invisible && invisibleArea < -ε) {\n            listener.lineStart();\n            interpolate(null, null, 1, listener);\n            listener.lineEnd();\n          }\n          listener.polygonEnd();\n          segments = null;\n        },\n        sphere: function() {\n          listener.polygonStart();\n          listener.lineStart();\n          interpolate(null, null, 1, listener);\n          listener.lineEnd();\n          listener.polygonEnd();\n        }\n      };\n      function point(λ, φ) {\n        if (pointVisible(λ, φ)) listener.point(λ, φ);\n      }\n      function pointLine(λ, φ) {\n        line.point(λ, φ);\n      }\n      function lineStart() {\n        clip.point = pointLine;\n        line.lineStart();\n      }\n      function lineEnd() {\n        clip.point = point;\n        line.lineEnd();\n      }\n      var segments, visibleArea, invisibleArea, invisible;\n      var buffer = d3_geo_clipBufferListener(), ringListener = clipLine(buffer), ring;\n      function pointRing(λ, φ) {\n        ringListener.point(λ, φ);\n        ring.push([ λ, φ ]);\n      }\n      function ringStart() {\n        ringListener.lineStart();\n        ring = [];\n      }\n      function ringEnd() {\n        pointRing(ring[0][0], ring[0][1]);\n        ringListener.lineEnd();\n        var clean = ringListener.clean(), ringSegments = buffer.buffer(), segment, n = ringSegments.length;\n        if (!n) {\n          invisible = true;\n          invisibleArea += d3_geo_clipAreaRing(ring, -1);\n          ring = null;\n          return;\n        }\n        ring = null;\n        if (clean & 1) {\n          segment = ringSegments[0];\n          visibleArea += d3_geo_clipAreaRing(segment, 1);\n          var n = segment.length - 1, i = -1, point;\n          listener.lineStart();\n          while (++i < n) listener.point((point = segment[i])[0], point[1]);\n          listener.lineEnd();\n          return;\n        }\n        if (n > 1 && clean & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift()));\n        segments.push(ringSegments.filter(d3_geo_clipSegmentLength1));\n      }\n      return clip;\n    };\n  }\n  function d3_geo_clipSegmentLength1(segment) {\n    return segment.length > 1;\n  }\n  function d3_geo_clipBufferListener() {\n    var lines = [], line;\n    return {\n      lineStart: function() {\n        lines.push(line = []);\n      },\n      point: function(λ, φ) {\n        line.push([ λ, φ ]);\n      },\n      lineEnd: d3_noop,\n      buffer: function() {\n        var buffer = lines;\n        lines = [];\n        line = null;\n        return buffer;\n      },\n      rejoin: function() {\n        if (lines.length > 1) lines.push(lines.pop().concat(lines.shift()));\n      }\n    };\n  }\n  function d3_geo_clipAreaRing(ring, invisible) {\n    if (!(n = ring.length)) return 0;\n    var n, i = 0, area = 0, p = ring[0], λ = p[0], φ = p[1], cosφ = Math.cos(φ), x0 = Math.atan2(invisible * Math.sin(λ) * cosφ, Math.sin(φ)), y0 = 1 - invisible * Math.cos(λ) * cosφ, x1 = x0, x, y;\n    while (++i < n) {\n      p = ring[i];\n      cosφ = Math.cos(φ = p[1]);\n      x = Math.atan2(invisible * Math.sin(λ = p[0]) * cosφ, Math.sin(φ));\n      y = 1 - invisible * Math.cos(λ) * cosφ;\n      if (Math.abs(y0 - 2) < ε && Math.abs(y - 2) < ε) continue;\n      if (Math.abs(y) < ε || Math.abs(y0) < ε) {} else if (Math.abs(Math.abs(x - x0) - π) < ε) {\n        if (y + y0 > 2) area += 4 * (x - x0);\n      } else if (Math.abs(y0 - 2) < ε) area += 4 * (x - x1); else area += ((3 * π + x - x0) % (2 * π) - π) * (y0 + y);\n      x1 = x0, x0 = x, y0 = y;\n    }\n    return area;\n  }\n  function d3_geo_clipSort(a, b) {\n    return ((a = a.point)[0] < 0 ? a[1] - π / 2 - ε : π / 2 - a[1]) - ((b = b.point)[0] < 0 ? b[1] - π / 2 - ε : π / 2 - b[1]);\n  }\n  var d3_geo_clipAntimeridian = d3_geo_clip(d3_true, d3_geo_clipAntimeridianLine, d3_geo_clipAntimeridianInterpolate);\n  function d3_geo_clipAntimeridianLine(listener) {\n    var λ0 = NaN, φ0 = NaN, sλ0 = NaN, clean;\n    return {\n      lineStart: function() {\n        listener.lineStart();\n        clean = 1;\n      },\n      point: function(λ1, φ1) {\n        var sλ1 = λ1 > 0 ? π : -π, dλ = Math.abs(λ1 - λ0);\n        if (Math.abs(dλ - π) < ε) {\n          listener.point(λ0, φ0 = (φ0 + φ1) / 2 > 0 ? π / 2 : -π / 2);\n          listener.point(sλ0, φ0);\n          listener.lineEnd();\n          listener.lineStart();\n          listener.point(sλ1, φ0);\n          listener.point(λ1, φ0);\n          clean = 0;\n        } else if (sλ0 !== sλ1 && dλ >= π) {\n          if (Math.abs(λ0 - sλ0) < ε) λ0 -= sλ0 * ε;\n          if (Math.abs(λ1 - sλ1) < ε) λ1 -= sλ1 * ε;\n          φ0 = d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1);\n          listener.point(sλ0, φ0);\n          listener.lineEnd();\n          listener.lineStart();\n          listener.point(sλ1, φ0);\n          clean = 0;\n        }\n        listener.point(λ0 = λ1, φ0 = φ1);\n        sλ0 = sλ1;\n      },\n      lineEnd: function() {\n        listener.lineEnd();\n        λ0 = φ0 = NaN;\n      },\n      clean: function() {\n        return 2 - clean;\n      }\n    };\n  }\n  function d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1) {\n    var cosφ0, cosφ1, sinλ0_λ1 = Math.sin(λ0 - λ1);\n    return Math.abs(sinλ0_λ1) > ε ? Math.atan((Math.sin(φ0) * (cosφ1 = Math.cos(φ1)) * Math.sin(λ1) - Math.sin(φ1) * (cosφ0 = Math.cos(φ0)) * Math.sin(λ0)) / (cosφ0 * cosφ1 * sinλ0_λ1)) : (φ0 + φ1) / 2;\n  }\n  function d3_geo_clipAntimeridianInterpolate(from, to, direction, listener) {\n    var φ;\n    if (from == null) {\n      φ = direction * π / 2;\n      listener.point(-π, φ);\n      listener.point(0, φ);\n      listener.point(π, φ);\n      listener.point(π, 0);\n      listener.point(π, -φ);\n      listener.point(0, -φ);\n      listener.point(-π, -φ);\n      listener.point(-π, 0);\n      listener.point(-π, φ);\n    } else if (Math.abs(from[0] - to[0]) > ε) {\n      var s = (from[0] < to[0] ? 1 : -1) * π;\n      φ = direction * s / 2;\n      listener.point(-s, φ);\n      listener.point(0, φ);\n      listener.point(s, φ);\n    } else {\n      listener.point(to[0], to[1]);\n    }\n  }\n  function d3_geo_clipCircle(radius) {\n    var cr = Math.cos(radius), smallRadius = cr > 0, notHemisphere = Math.abs(cr) > ε, interpolate = d3_geo_circleInterpolate(radius, 6 * d3_radians);\n    return d3_geo_clip(visible, clipLine, interpolate);\n    function visible(λ, φ) {\n      return Math.cos(λ) * Math.cos(φ) > cr;\n    }\n    function clipLine(listener) {\n      var point0, c0, v0, v00, clean;\n      return {\n        lineStart: function() {\n          v00 = v0 = false;\n          clean = 1;\n        },\n        point: function(λ, φ) {\n          var point1 = [ λ, φ ], point2, v = visible(λ, φ), c = smallRadius ? v ? 0 : code(λ, φ) : v ? code(λ + (λ < 0 ? π : -π), φ) : 0;\n          if (!point0 && (v00 = v0 = v)) listener.lineStart();\n          if (v !== v0) {\n            point2 = intersect(point0, point1);\n            if (d3_geo_sphericalEqual(point0, point2) || d3_geo_sphericalEqual(point1, point2)) {\n              point1[0] += ε;\n              point1[1] += ε;\n              v = visible(point1[0], point1[1]);\n            }\n          }\n          if (v !== v0) {\n            clean = 0;\n            if (v) {\n              listener.lineStart();\n              point2 = intersect(point1, point0);\n              listener.point(point2[0], point2[1]);\n            } else {\n              point2 = intersect(point0, point1);\n              listener.point(point2[0], point2[1]);\n              listener.lineEnd();\n            }\n            point0 = point2;\n          } else if (notHemisphere && point0 && smallRadius ^ v) {\n            var t;\n            if (!(c & c0) && (t = intersect(point1, point0, true))) {\n              clean = 0;\n              if (smallRadius) {\n                listener.lineStart();\n                listener.point(t[0][0], t[0][1]);\n                listener.point(t[1][0], t[1][1]);\n                listener.lineEnd();\n              } else {\n                listener.point(t[1][0], t[1][1]);\n                listener.lineEnd();\n                listener.lineStart();\n                listener.point(t[0][0], t[0][1]);\n              }\n            }\n          }\n          if (v && (!point0 || !d3_geo_sphericalEqual(point0, point1))) {\n            listener.point(point1[0], point1[1]);\n          }\n          point0 = point1, v0 = v, c0 = c;\n        },\n        lineEnd: function() {\n          if (v0) listener.lineEnd();\n          point0 = null;\n        },\n        clean: function() {\n          return clean | (v00 && v0) << 1;\n        }\n      };\n    }\n    function intersect(a, b, two) {\n      var pa = d3_geo_cartesian(a), pb = d3_geo_cartesian(b);\n      var n1 = [ 1, 0, 0 ], n2 = d3_geo_cartesianCross(pa, pb), n2n2 = d3_geo_cartesianDot(n2, n2), n1n2 = n2[0], determinant = n2n2 - n1n2 * n1n2;\n      if (!determinant) return !two && a;\n      var c1 = cr * n2n2 / determinant, c2 = -cr * n1n2 / determinant, n1xn2 = d3_geo_cartesianCross(n1, n2), A = d3_geo_cartesianScale(n1, c1), B = d3_geo_cartesianScale(n2, c2);\n      d3_geo_cartesianAdd(A, B);\n      var u = n1xn2, w = d3_geo_cartesianDot(A, u), uu = d3_geo_cartesianDot(u, u), t2 = w * w - uu * (d3_geo_cartesianDot(A, A) - 1);\n      if (t2 < 0) return;\n      var t = Math.sqrt(t2), q = d3_geo_cartesianScale(u, (-w - t) / uu);\n      d3_geo_cartesianAdd(q, A);\n      q = d3_geo_spherical(q);\n      if (!two) return q;\n      var λ0 = a[0], λ1 = b[0], φ0 = a[1], φ1 = b[1], z;\n      if (λ1 < λ0) z = λ0, λ0 = λ1, λ1 = z;\n      var δλ = λ1 - λ0, polar = Math.abs(δλ - π) < ε, meridian = polar || δλ < ε;\n      if (!polar && φ1 < φ0) z = φ0, φ0 = φ1, φ1 = z;\n      if (meridian ? polar ? φ0 + φ1 > 0 ^ q[1] < (Math.abs(q[0] - λ0) < ε ? φ0 : φ1) : φ0 <= q[1] && q[1] <= φ1 : δλ > π ^ (λ0 <= q[0] && q[0] <= λ1)) {\n        var q1 = d3_geo_cartesianScale(u, (-w + t) / uu);\n        d3_geo_cartesianAdd(q1, A);\n        return [ q, d3_geo_spherical(q1) ];\n      }\n    }\n    function code(λ, φ) {\n      var r = smallRadius ? radius : π - radius, code = 0;\n      if (λ < -r) code |= 1; else if (λ > r) code |= 2;\n      if (φ < -r) code |= 4; else if (φ > r) code |= 8;\n      return code;\n    }\n  }\n  var d3_geo_clipViewMAX = 1e9;\n  function d3_geo_clipView(x0, y0, x1, y1) {\n    return function(listener) {\n      var listener_ = listener, bufferListener = d3_geo_clipBufferListener(), segments, polygon, ring;\n      var clip = {\n        point: point,\n        lineStart: lineStart,\n        lineEnd: lineEnd,\n        polygonStart: function() {\n          listener = bufferListener;\n          segments = [];\n          polygon = [];\n        },\n        polygonEnd: function() {\n          listener = listener_;\n          if ((segments = d3.merge(segments)).length) {\n            listener.polygonStart();\n            d3_geo_clipPolygon(segments, compare, inside, interpolate, listener);\n            listener.polygonEnd();\n          } else if (insidePolygon([ x0, y0 ])) {\n            listener.polygonStart(), listener.lineStart();\n            interpolate(null, null, 1, listener);\n            listener.lineEnd(), listener.polygonEnd();\n          }\n          segments = polygon = ring = null;\n        }\n      };\n      function inside(point) {\n        var a = corner(point, -1), i = insidePolygon([ a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0 ]);\n        return i;\n      }\n      function insidePolygon(p) {\n        var wn = 0, n = polygon.length, y = p[1];\n        for (var i = 0; i < n; ++i) {\n          for (var j = 1, v = polygon[i], m = v.length, a = v[0]; j < m; ++j) {\n            b = v[j];\n            if (a[1] <= y) {\n              if (b[1] > y && isLeft(a, b, p) > 0) ++wn;\n            } else {\n              if (b[1] <= y && isLeft(a, b, p) < 0) --wn;\n            }\n            a = b;\n          }\n        }\n        return wn !== 0;\n      }\n      function isLeft(a, b, c) {\n        return (b[0] - a[0]) * (c[1] - a[1]) - (c[0] - a[0]) * (b[1] - a[1]);\n      }\n      function interpolate(from, to, direction, listener) {\n        var a = 0, a1 = 0;\n        if (from == null || (a = corner(from, direction)) !== (a1 = corner(to, direction)) || comparePoints(from, to) < 0 ^ direction > 0) {\n          do {\n            listener.point(a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0);\n          } while ((a = (a + direction + 4) % 4) !== a1);\n        } else {\n          listener.point(to[0], to[1]);\n        }\n      }\n      function visible(x, y) {\n        return x0 <= x && x <= x1 && y0 <= y && y <= y1;\n      }\n      function point(x, y) {\n        if (visible(x, y)) listener.point(x, y);\n      }\n      var x__, y__, v__, x_, y_, v_, first;\n      function lineStart() {\n        clip.point = linePoint;\n        if (polygon) polygon.push(ring = []);\n        first = true;\n        v_ = false;\n        x_ = y_ = NaN;\n      }\n      function lineEnd() {\n        if (segments) {\n          linePoint(x__, y__);\n          if (v__ && v_) bufferListener.rejoin();\n          segments.push(bufferListener.buffer());\n        }\n        clip.point = point;\n        if (v_) listener.lineEnd();\n      }\n      function linePoint(x, y) {\n        x = Math.max(-d3_geo_clipViewMAX, Math.min(d3_geo_clipViewMAX, x));\n        y = Math.max(-d3_geo_clipViewMAX, Math.min(d3_geo_clipViewMAX, y));\n        var v = visible(x, y);\n        if (polygon) ring.push([ x, y ]);\n        if (first) {\n          x__ = x, y__ = y, v__ = v;\n          first = false;\n          if (v) {\n            listener.lineStart();\n            listener.point(x, y);\n          }\n        } else {\n          if (v && v_) listener.point(x, y); else {\n            var a = [ x_, y_ ], b = [ x, y ];\n            if (clipLine(a, b)) {\n              if (!v_) {\n                listener.lineStart();\n                listener.point(a[0], a[1]);\n              }\n              listener.point(b[0], b[1]);\n              if (!v) listener.lineEnd();\n            } else {\n              listener.lineStart();\n              listener.point(x, y);\n            }\n          }\n        }\n        x_ = x, y_ = y, v_ = v;\n      }\n      return clip;\n    };\n    function corner(p, direction) {\n      return Math.abs(p[0] - x0) < ε ? direction > 0 ? 0 : 3 : Math.abs(p[0] - x1) < ε ? direction > 0 ? 2 : 1 : Math.abs(p[1] - y0) < ε ? direction > 0 ? 1 : 0 : direction > 0 ? 3 : 2;\n    }\n    function compare(a, b) {\n      return comparePoints(a.point, b.point);\n    }\n    function comparePoints(a, b) {\n      var ca = corner(a, 1), cb = corner(b, 1);\n      return ca !== cb ? ca - cb : ca === 0 ? b[1] - a[1] : ca === 1 ? a[0] - b[0] : ca === 2 ? a[1] - b[1] : b[0] - a[0];\n    }\n    function clipLine(a, b) {\n      var dx = b[0] - a[0], dy = b[1] - a[1], t = [ 0, 1 ];\n      if (Math.abs(dx) < ε && Math.abs(dy) < ε) return x0 <= a[0] && a[0] <= x1 && y0 <= a[1] && a[1] <= y1;\n      if (d3_geo_clipViewT(x0 - a[0], dx, t) && d3_geo_clipViewT(a[0] - x1, -dx, t) && d3_geo_clipViewT(y0 - a[1], dy, t) && d3_geo_clipViewT(a[1] - y1, -dy, t)) {\n        if (t[1] < 1) {\n          b[0] = a[0] + t[1] * dx;\n          b[1] = a[1] + t[1] * dy;\n        }\n        if (t[0] > 0) {\n          a[0] += t[0] * dx;\n          a[1] += t[0] * dy;\n        }\n        return true;\n      }\n      return false;\n    }\n  }\n  function d3_geo_clipViewT(num, denominator, t) {\n    if (Math.abs(denominator) < ε) return num <= 0;\n    var u = num / denominator;\n    if (denominator > 0) {\n      if (u > t[1]) return false;\n      if (u > t[0]) t[0] = u;\n    } else {\n      if (u < t[0]) return false;\n      if (u < t[1]) t[1] = u;\n    }\n    return true;\n  }\n  function d3_geo_compose(a, b) {\n    function compose(x, y) {\n      return x = a(x, y), b(x[0], x[1]);\n    }\n    if (a.invert && b.invert) compose.invert = function(x, y) {\n      return x = b.invert(x, y), x && a.invert(x[0], x[1]);\n    };\n    return compose;\n  }\n  function d3_geo_resample(project) {\n    var δ2 = .5, maxDepth = 16;\n    function resample(stream) {\n      var λ0, x0, y0, a0, b0, c0;\n      var resample = {\n        point: point,\n        lineStart: lineStart,\n        lineEnd: lineEnd,\n        polygonStart: function() {\n          stream.polygonStart();\n          resample.lineStart = polygonLineStart;\n        },\n        polygonEnd: function() {\n          stream.polygonEnd();\n          resample.lineStart = lineStart;\n        }\n      };\n      function point(x, y) {\n        x = project(x, y);\n        stream.point(x[0], x[1]);\n      }\n      function lineStart() {\n        x0 = NaN;\n        resample.point = linePoint;\n        stream.lineStart();\n      }\n      function linePoint(λ, φ) {\n        var c = d3_geo_cartesian([ λ, φ ]), p = project(λ, φ);\n        resampleLineTo(x0, y0, λ0, a0, b0, c0, x0 = p[0], y0 = p[1], λ0 = λ, a0 = c[0], b0 = c[1], c0 = c[2], maxDepth, stream);\n        stream.point(x0, y0);\n      }\n      function lineEnd() {\n        resample.point = point;\n        stream.lineEnd();\n      }\n      function polygonLineStart() {\n        var λ00, φ00, x00, y00, a00, b00, c00;\n        lineStart();\n        resample.point = function(λ, φ) {\n          linePoint(λ00 = λ, φ00 = φ), x00 = x0, y00 = y0, a00 = a0, b00 = b0, c00 = c0;\n          resample.point = linePoint;\n        };\n        resample.lineEnd = function() {\n          resampleLineTo(x0, y0, λ0, a0, b0, c0, x00, y00, λ00, a00, b00, c00, maxDepth, stream);\n          resample.lineEnd = lineEnd;\n          lineEnd();\n        };\n      }\n      return resample;\n    }\n    function resampleLineTo(x0, y0, λ0, a0, b0, c0, x1, y1, λ1, a1, b1, c1, depth, stream) {\n      var dx = x1 - x0, dy = y1 - y0, d2 = dx * dx + dy * dy;\n      if (d2 > 4 * δ2 && depth--) {\n        var a = a0 + a1, b = b0 + b1, c = c0 + c1, m = Math.sqrt(a * a + b * b + c * c), φ2 = Math.asin(c /= m), λ2 = Math.abs(Math.abs(c) - 1) < ε ? (λ0 + λ1) / 2 : Math.atan2(b, a), p = project(λ2, φ2), x2 = p[0], y2 = p[1], dx2 = x2 - x0, dy2 = y2 - y0, dz = dy * dx2 - dx * dy2;\n        if (dz * dz / d2 > δ2 || Math.abs((dx * dx2 + dy * dy2) / d2 - .5) > .3) {\n          resampleLineTo(x0, y0, λ0, a0, b0, c0, x2, y2, λ2, a /= m, b /= m, c, depth, stream);\n          stream.point(x2, y2);\n          resampleLineTo(x2, y2, λ2, a, b, c, x1, y1, λ1, a1, b1, c1, depth, stream);\n        }\n      }\n    }\n    resample.precision = function(_) {\n      if (!arguments.length) return Math.sqrt(δ2);\n      maxDepth = (δ2 = _ * _) > 0 && 16;\n      return resample;\n    };\n    return resample;\n  }\n  d3.geo.projection = d3_geo_projection;\n  d3.geo.projectionMutator = d3_geo_projectionMutator;\n  function d3_geo_projection(project) {\n    return d3_geo_projectionMutator(function() {\n      return project;\n    })();\n  }\n  function d3_geo_projectionMutator(projectAt) {\n    var project, rotate, projectRotate, projectResample = d3_geo_resample(function(x, y) {\n      x = project(x, y);\n      return [ x[0] * k + δx, δy - x[1] * k ];\n    }), k = 150, x = 480, y = 250, λ = 0, φ = 0, δλ = 0, δφ = 0, δγ = 0, δx, δy, preclip = d3_geo_clipAntimeridian, postclip = d3_identity, clipAngle = null, clipExtent = null;\n    function projection(point) {\n      point = projectRotate(point[0] * d3_radians, point[1] * d3_radians);\n      return [ point[0] * k + δx, δy - point[1] * k ];\n    }\n    function invert(point) {\n      point = projectRotate.invert((point[0] - δx) / k, (δy - point[1]) / k);\n      return point && [ point[0] * d3_degrees, point[1] * d3_degrees ];\n    }\n    projection.stream = function(stream) {\n      return d3_geo_projectionRadiansRotate(rotate, preclip(projectResample(postclip(stream))));\n    };\n    projection.clipAngle = function(_) {\n      if (!arguments.length) return clipAngle;\n      preclip = _ == null ? (clipAngle = _, d3_geo_clipAntimeridian) : d3_geo_clipCircle((clipAngle = +_) * d3_radians);\n      return projection;\n    };\n    projection.clipExtent = function(_) {\n      if (!arguments.length) return clipExtent;\n      clipExtent = _;\n      postclip = _ == null ? d3_identity : d3_geo_clipView(_[0][0], _[0][1], _[1][0], _[1][1]);\n      return projection;\n    };\n    projection.scale = function(_) {\n      if (!arguments.length) return k;\n      k = +_;\n      return reset();\n    };\n    projection.translate = function(_) {\n      if (!arguments.length) return [ x, y ];\n      x = +_[0];\n      y = +_[1];\n      return reset();\n    };\n    projection.center = function(_) {\n      if (!arguments.length) return [ λ * d3_degrees, φ * d3_degrees ];\n      λ = _[0] % 360 * d3_radians;\n      φ = _[1] % 360 * d3_radians;\n      return reset();\n    };\n    projection.rotate = function(_) {\n      if (!arguments.length) return [ δλ * d3_degrees, δφ * d3_degrees, δγ * d3_degrees ];\n      δλ = _[0] % 360 * d3_radians;\n      δφ = _[1] % 360 * d3_radians;\n      δγ = _.length > 2 ? _[2] % 360 * d3_radians : 0;\n      return reset();\n    };\n    d3.rebind(projection, projectResample, \"precision\");\n    function reset() {\n      projectRotate = d3_geo_compose(rotate = d3_geo_rotation(δλ, δφ, δγ), project);\n      var center = project(λ, φ);\n      δx = x - center[0] * k;\n      δy = y + center[1] * k;\n      return projection;\n    }\n    return function() {\n      project = projectAt.apply(this, arguments);\n      projection.invert = project.invert && invert;\n      return reset();\n    };\n  }\n  function d3_geo_projectionRadiansRotate(rotate, stream) {\n    return {\n      point: function(x, y) {\n        y = rotate(x * d3_radians, y * d3_radians), x = y[0];\n        stream.point(x > π ? x - 2 * π : x < -π ? x + 2 * π : x, y[1]);\n      },\n      sphere: function() {\n        stream.sphere();\n      },\n      lineStart: function() {\n        stream.lineStart();\n      },\n      lineEnd: function() {\n        stream.lineEnd();\n      },\n      polygonStart: function() {\n        stream.polygonStart();\n      },\n      polygonEnd: function() {\n        stream.polygonEnd();\n      }\n    };\n  }\n  function d3_geo_equirectangular(λ, φ) {\n    return [ λ, φ ];\n  }\n  (d3.geo.equirectangular = function() {\n    return d3_geo_projection(d3_geo_equirectangular);\n  }).raw = d3_geo_equirectangular.invert = d3_geo_equirectangular;\n  d3.geo.rotation = function(rotate) {\n    rotate = d3_geo_rotation(rotate[0] % 360 * d3_radians, rotate[1] * d3_radians, rotate.length > 2 ? rotate[2] * d3_radians : 0);\n    function forward(coordinates) {\n      coordinates = rotate(coordinates[0] * d3_radians, coordinates[1] * d3_radians);\n      return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates;\n    }\n    forward.invert = function(coordinates) {\n      coordinates = rotate.invert(coordinates[0] * d3_radians, coordinates[1] * d3_radians);\n      return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates;\n    };\n    return forward;\n  };\n  function d3_geo_rotation(δλ, δφ, δγ) {\n    return δλ ? δφ || δγ ? d3_geo_compose(d3_geo_rotationλ(δλ), d3_geo_rotationφγ(δφ, δγ)) : d3_geo_rotationλ(δλ) : δφ || δγ ? d3_geo_rotationφγ(δφ, δγ) : d3_geo_equirectangular;\n  }\n  function d3_geo_forwardRotationλ(δλ) {\n    return function(λ, φ) {\n      return λ += δλ, [ λ > π ? λ - 2 * π : λ < -π ? λ + 2 * π : λ, φ ];\n    };\n  }\n  function d3_geo_rotationλ(δλ) {\n    var rotation = d3_geo_forwardRotationλ(δλ);\n    rotation.invert = d3_geo_forwardRotationλ(-δλ);\n    return rotation;\n  }\n  function d3_geo_rotationφγ(δφ, δγ) {\n    var cosδφ = Math.cos(δφ), sinδφ = Math.sin(δφ), cosδγ = Math.cos(δγ), sinδγ = Math.sin(δγ);\n    function rotation(λ, φ) {\n      var cosφ = Math.cos(φ), x = Math.cos(λ) * cosφ, y = Math.sin(λ) * cosφ, z = Math.sin(φ), k = z * cosδφ + x * sinδφ;\n      return [ Math.atan2(y * cosδγ - k * sinδγ, x * cosδφ - z * sinδφ), Math.asin(Math.max(-1, Math.min(1, k * cosδγ + y * sinδγ))) ];\n    }\n    rotation.invert = function(λ, φ) {\n      var cosφ = Math.cos(φ), x = Math.cos(λ) * cosφ, y = Math.sin(λ) * cosφ, z = Math.sin(φ), k = z * cosδγ - y * sinδγ;\n      return [ Math.atan2(y * cosδγ + z * sinδγ, x * cosδφ + k * sinδφ), Math.asin(Math.max(-1, Math.min(1, k * cosδφ - x * sinδφ))) ];\n    };\n    return rotation;\n  }\n  d3.geo.circle = function() {\n    var origin = [ 0, 0 ], angle, precision = 6, interpolate;\n    function circle() {\n      var center = typeof origin === \"function\" ? origin.apply(this, arguments) : origin, rotate = d3_geo_rotation(-center[0] * d3_radians, -center[1] * d3_radians, 0).invert, ring = [];\n      interpolate(null, null, 1, {\n        point: function(x, y) {\n          ring.push(x = rotate(x, y));\n          x[0] *= d3_degrees, x[1] *= d3_degrees;\n        }\n      });\n      return {\n        type: \"Polygon\",\n        coordinates: [ ring ]\n      };\n    }\n    circle.origin = function(x) {\n      if (!arguments.length) return origin;\n      origin = x;\n      return circle;\n    };\n    circle.angle = function(x) {\n      if (!arguments.length) return angle;\n      interpolate = d3_geo_circleInterpolate((angle = +x) * d3_radians, precision * d3_radians);\n      return circle;\n    };\n    circle.precision = function(_) {\n      if (!arguments.length) return precision;\n      interpolate = d3_geo_circleInterpolate(angle * d3_radians, (precision = +_) * d3_radians);\n      return circle;\n    };\n    return circle.angle(90);\n  };\n  function d3_geo_circleInterpolate(radius, precision) {\n    var cr = Math.cos(radius), sr = Math.sin(radius);\n    return function(from, to, direction, listener) {\n      if (from != null) {\n        from = d3_geo_circleAngle(cr, from);\n        to = d3_geo_circleAngle(cr, to);\n        if (direction > 0 ? from < to : from > to) from += direction * 2 * π;\n      } else {\n        from = radius + direction * 2 * π;\n        to = radius;\n      }\n      var point;\n      for (var step = direction * precision, t = from; direction > 0 ? t > to : t < to; t -= step) {\n        listener.point((point = d3_geo_spherical([ cr, -sr * Math.cos(t), -sr * Math.sin(t) ]))[0], point[1]);\n      }\n    };\n  }\n  function d3_geo_circleAngle(cr, point) {\n    var a = d3_geo_cartesian(point);\n    a[0] -= cr;\n    d3_geo_cartesianNormalize(a);\n    var angle = d3_acos(-a[1]);\n    return ((-a[2] < 0 ? -angle : angle) + 2 * Math.PI - ε) % (2 * Math.PI);\n  }\n  d3.geo.distance = function(a, b) {\n    var Δλ = (b[0] - a[0]) * d3_radians, φ0 = a[1] * d3_radians, φ1 = b[1] * d3_radians, sinΔλ = Math.sin(Δλ), cosΔλ = Math.cos(Δλ), sinφ0 = Math.sin(φ0), cosφ0 = Math.cos(φ0), sinφ1 = Math.sin(φ1), cosφ1 = Math.cos(φ1), t;\n    return Math.atan2(Math.sqrt((t = cosφ1 * sinΔλ) * t + (t = cosφ0 * sinφ1 - sinφ0 * cosφ1 * cosΔλ) * t), sinφ0 * sinφ1 + cosφ0 * cosφ1 * cosΔλ);\n  };\n  d3.geo.graticule = function() {\n    var x1, x0, X1, X0, y1, y0, Y1, Y0, dx = 10, dy = dx, DX = 90, DY = 360, x, y, X, Y, precision = 2.5;\n    function graticule() {\n      return {\n        type: \"MultiLineString\",\n        coordinates: lines()\n      };\n    }\n    function lines() {\n      return d3.range(Math.ceil(X0 / DX) * DX, X1, DX).map(X).concat(d3.range(Math.ceil(Y0 / DY) * DY, Y1, DY).map(Y)).concat(d3.range(Math.ceil(x0 / dx) * dx, x1, dx).filter(function(x) {\n        return Math.abs(x % DX) > ε;\n      }).map(x)).concat(d3.range(Math.ceil(y0 / dy) * dy, y1, dy).filter(function(y) {\n        return Math.abs(y % DY) > ε;\n      }).map(y));\n    }\n    graticule.lines = function() {\n      return lines().map(function(coordinates) {\n        return {\n          type: \"LineString\",\n          coordinates: coordinates\n        };\n      });\n    };\n    graticule.outline = function() {\n      return {\n        type: \"Polygon\",\n        coordinates: [ X(X0).concat(Y(Y1).slice(1), X(X1).reverse().slice(1), Y(Y0).reverse().slice(1)) ]\n      };\n    };\n    graticule.extent = function(_) {\n      if (!arguments.length) return graticule.minorExtent();\n      return graticule.majorExtent(_).minorExtent(_);\n    };\n    graticule.majorExtent = function(_) {\n      if (!arguments.length) return [ [ X0, Y0 ], [ X1, Y1 ] ];\n      X0 = +_[0][0], X1 = +_[1][0];\n      Y0 = +_[0][1], Y1 = +_[1][1];\n      if (X0 > X1) _ = X0, X0 = X1, X1 = _;\n      if (Y0 > Y1) _ = Y0, Y0 = Y1, Y1 = _;\n      return graticule.precision(precision);\n    };\n    graticule.minorExtent = function(_) {\n      if (!arguments.length) return [ [ x0, y0 ], [ x1, y1 ] ];\n      x0 = +_[0][0], x1 = +_[1][0];\n      y0 = +_[0][1], y1 = +_[1][1];\n      if (x0 > x1) _ = x0, x0 = x1, x1 = _;\n      if (y0 > y1) _ = y0, y0 = y1, y1 = _;\n      return graticule.precision(precision);\n    };\n    graticule.step = function(_) {\n      if (!arguments.length) return graticule.minorStep();\n      return graticule.majorStep(_).minorStep(_);\n    };\n    graticule.majorStep = function(_) {\n      if (!arguments.length) return [ DX, DY ];\n      DX = +_[0], DY = +_[1];\n      return graticule;\n    };\n    graticule.minorStep = function(_) {\n      if (!arguments.length) return [ dx, dy ];\n      dx = +_[0], dy = +_[1];\n      return graticule;\n    };\n    graticule.precision = function(_) {\n      if (!arguments.length) return precision;\n      precision = +_;\n      x = d3_geo_graticuleX(y0, y1, 90);\n      y = d3_geo_graticuleY(x0, x1, precision);\n      X = d3_geo_graticuleX(Y0, Y1, 90);\n      Y = d3_geo_graticuleY(X0, X1, precision);\n      return graticule;\n    };\n    return graticule.majorExtent([ [ -180, -90 + ε ], [ 180, 90 - ε ] ]).minorExtent([ [ -180, -80 - ε ], [ 180, 80 + ε ] ]);\n  };\n  function d3_geo_graticuleX(y0, y1, dy) {\n    var y = d3.range(y0, y1 - ε, dy).concat(y1);\n    return function(x) {\n      return y.map(function(y) {\n        return [ x, y ];\n      });\n    };\n  }\n  function d3_geo_graticuleY(x0, x1, dx) {\n    var x = d3.range(x0, x1 - ε, dx).concat(x1);\n    return function(y) {\n      return x.map(function(x) {\n        return [ x, y ];\n      });\n    };\n  }\n  function d3_source(d) {\n    return d.source;\n  }\n  function d3_target(d) {\n    return d.target;\n  }\n  d3.geo.greatArc = function() {\n    var source = d3_source, source_, target = d3_target, target_;\n    function greatArc() {\n      return {\n        type: \"LineString\",\n        coordinates: [ source_ || source.apply(this, arguments), target_ || target.apply(this, arguments) ]\n      };\n    }\n    greatArc.distance = function() {\n      return d3.geo.distance(source_ || source.apply(this, arguments), target_ || target.apply(this, arguments));\n    };\n    greatArc.source = function(_) {\n      if (!arguments.length) return source;\n      source = _, source_ = typeof _ === \"function\" ? null : _;\n      return greatArc;\n    };\n    greatArc.target = function(_) {\n      if (!arguments.length) return target;\n      target = _, target_ = typeof _ === \"function\" ? null : _;\n      return greatArc;\n    };\n    greatArc.precision = function() {\n      return arguments.length ? greatArc : 0;\n    };\n    return greatArc;\n  };\n  d3.geo.interpolate = function(source, target) {\n    return d3_geo_interpolate(source[0] * d3_radians, source[1] * d3_radians, target[0] * d3_radians, target[1] * d3_radians);\n  };\n  function d3_geo_interpolate(x0, y0, x1, y1) {\n    var cy0 = Math.cos(y0), sy0 = Math.sin(y0), cy1 = Math.cos(y1), sy1 = Math.sin(y1), kx0 = cy0 * Math.cos(x0), ky0 = cy0 * Math.sin(x0), kx1 = cy1 * Math.cos(x1), ky1 = cy1 * Math.sin(x1), d = 2 * Math.asin(Math.sqrt(d3_haversin(y1 - y0) + cy0 * cy1 * d3_haversin(x1 - x0))), k = 1 / Math.sin(d);\n    var interpolate = d ? function(t) {\n      var B = Math.sin(t *= d) * k, A = Math.sin(d - t) * k, x = A * kx0 + B * kx1, y = A * ky0 + B * ky1, z = A * sy0 + B * sy1;\n      return [ Math.atan2(y, x) * d3_degrees, Math.atan2(z, Math.sqrt(x * x + y * y)) * d3_degrees ];\n    } : function() {\n      return [ x0 * d3_degrees, y0 * d3_degrees ];\n    };\n    interpolate.distance = d;\n    return interpolate;\n  }\n  d3.geo.length = function(object) {\n    d3_geo_lengthSum = 0;\n    d3.geo.stream(object, d3_geo_length);\n    return d3_geo_lengthSum;\n  };\n  var d3_geo_lengthSum;\n  var d3_geo_length = {\n    sphere: d3_noop,\n    point: d3_noop,\n    lineStart: d3_geo_lengthLineStart,\n    lineEnd: d3_noop,\n    polygonStart: d3_noop,\n    polygonEnd: d3_noop\n  };\n  function d3_geo_lengthLineStart() {\n    var λ0, sinφ0, cosφ0;\n    d3_geo_length.point = function(λ, φ) {\n      λ0 = λ * d3_radians, sinφ0 = Math.sin(φ *= d3_radians), cosφ0 = Math.cos(φ);\n      d3_geo_length.point = nextPoint;\n    };\n    d3_geo_length.lineEnd = function() {\n      d3_geo_length.point = d3_geo_length.lineEnd = d3_noop;\n    };\n    function nextPoint(λ, φ) {\n      var sinφ = Math.sin(φ *= d3_radians), cosφ = Math.cos(φ), t = Math.abs((λ *= d3_radians) - λ0), cosΔλ = Math.cos(t);\n      d3_geo_lengthSum += Math.atan2(Math.sqrt((t = cosφ * Math.sin(t)) * t + (t = cosφ0 * sinφ - sinφ0 * cosφ * cosΔλ) * t), sinφ0 * sinφ + cosφ0 * cosφ * cosΔλ);\n      λ0 = λ, sinφ0 = sinφ, cosφ0 = cosφ;\n    }\n  }\n  function d3_geo_conic(projectAt) {\n    var φ0 = 0, φ1 = π / 3, m = d3_geo_projectionMutator(projectAt), p = m(φ0, φ1);\n    p.parallels = function(_) {\n      if (!arguments.length) return [ φ0 / π * 180, φ1 / π * 180 ];\n      return m(φ0 = _[0] * π / 180, φ1 = _[1] * π / 180);\n    };\n    return p;\n  }\n  function d3_geo_conicEqualArea(φ0, φ1) {\n    var sinφ0 = Math.sin(φ0), n = (sinφ0 + Math.sin(φ1)) / 2, C = 1 + sinφ0 * (2 * n - sinφ0), ρ0 = Math.sqrt(C) / n;\n    function forward(λ, φ) {\n      var ρ = Math.sqrt(C - 2 * n * Math.sin(φ)) / n;\n      return [ ρ * Math.sin(λ *= n), ρ0 - ρ * Math.cos(λ) ];\n    }\n    forward.invert = function(x, y) {\n      var ρ0_y = ρ0 - y;\n      return [ Math.atan2(x, ρ0_y) / n, Math.asin((C - (x * x + ρ0_y * ρ0_y) * n * n) / (2 * n)) ];\n    };\n    return forward;\n  }\n  (d3.geo.conicEqualArea = function() {\n    return d3_geo_conic(d3_geo_conicEqualArea);\n  }).raw = d3_geo_conicEqualArea;\n  d3.geo.albersUsa = function() {\n    var lower48 = d3.geo.conicEqualArea().rotate([ 98, 0 ]).center([ 0, 38 ]).parallels([ 29.5, 45.5 ]);\n    var alaska = d3.geo.conicEqualArea().rotate([ 160, 0 ]).center([ 0, 60 ]).parallels([ 55, 65 ]);\n    var hawaii = d3.geo.conicEqualArea().rotate([ 160, 0 ]).center([ 0, 20 ]).parallels([ 8, 18 ]);\n    var puertoRico = d3.geo.conicEqualArea().rotate([ 60, 0 ]).center([ 0, 10 ]).parallels([ 8, 18 ]);\n    var alaskaInvert, hawaiiInvert, puertoRicoInvert;\n    function albersUsa(coordinates) {\n      return projection(coordinates)(coordinates);\n    }\n    function projection(point) {\n      var lon = point[0], lat = point[1];\n      return lat > 50 ? alaska : lon < -140 ? hawaii : lat < 21 ? puertoRico : lower48;\n    }\n    albersUsa.invert = function(coordinates) {\n      return alaskaInvert(coordinates) || hawaiiInvert(coordinates) || puertoRicoInvert(coordinates) || lower48.invert(coordinates);\n    };\n    albersUsa.scale = function(x) {\n      if (!arguments.length) return lower48.scale();\n      lower48.scale(x);\n      alaska.scale(x * .6);\n      hawaii.scale(x);\n      puertoRico.scale(x * 1.5);\n      return albersUsa.translate(lower48.translate());\n    };\n    albersUsa.translate = function(x) {\n      if (!arguments.length) return lower48.translate();\n      var dz = lower48.scale(), dx = x[0], dy = x[1];\n      lower48.translate(x);\n      alaska.translate([ dx - .4 * dz, dy + .17 * dz ]);\n      hawaii.translate([ dx - .19 * dz, dy + .2 * dz ]);\n      puertoRico.translate([ dx + .58 * dz, dy + .43 * dz ]);\n      alaskaInvert = d3_geo_albersUsaInvert(alaska, [ [ -180, 50 ], [ -130, 72 ] ]);\n      hawaiiInvert = d3_geo_albersUsaInvert(hawaii, [ [ -164, 18 ], [ -154, 24 ] ]);\n      puertoRicoInvert = d3_geo_albersUsaInvert(puertoRico, [ [ -67.5, 17.5 ], [ -65, 19 ] ]);\n      return albersUsa;\n    };\n    return albersUsa.scale(1e3);\n  };\n  function d3_geo_albersUsaInvert(projection, extent) {\n    var a = projection(extent[0]), b = projection([ .5 * (extent[0][0] + extent[1][0]), extent[0][1] ]), c = projection([ extent[1][0], extent[0][1] ]), d = projection(extent[1]);\n    var dya = b[1] - a[1], dxa = b[0] - a[0], dyb = c[1] - b[1], dxb = c[0] - b[0];\n    var ma = dya / dxa, mb = dyb / dxb;\n    var cx = .5 * (ma * mb * (a[1] - c[1]) + mb * (a[0] + b[0]) - ma * (b[0] + c[0])) / (mb - ma), cy = (.5 * (a[0] + b[0]) - cx) / ma + .5 * (a[1] + b[1]);\n    var dx0 = d[0] - cx, dy0 = d[1] - cy, dx1 = a[0] - cx, dy1 = a[1] - cy, r0 = dx0 * dx0 + dy0 * dy0, r1 = dx1 * dx1 + dy1 * dy1;\n    var a0 = Math.atan2(dy0, dx0), a1 = Math.atan2(dy1, dx1);\n    return function(coordinates) {\n      var dx = coordinates[0] - cx, dy = coordinates[1] - cy, r = dx * dx + dy * dy, a = Math.atan2(dy, dx);\n      if (r0 < r && r < r1 && a0 < a && a < a1) return projection.invert(coordinates);\n    };\n  }\n  var d3_geo_pathAreaSum, d3_geo_pathAreaPolygon, d3_geo_pathArea = {\n    point: d3_noop,\n    lineStart: d3_noop,\n    lineEnd: d3_noop,\n    polygonStart: function() {\n      d3_geo_pathAreaPolygon = 0;\n      d3_geo_pathArea.lineStart = d3_geo_pathAreaRingStart;\n    },\n    polygonEnd: function() {\n      d3_geo_pathArea.lineStart = d3_geo_pathArea.lineEnd = d3_geo_pathArea.point = d3_noop;\n      d3_geo_pathAreaSum += Math.abs(d3_geo_pathAreaPolygon / 2);\n    }\n  };\n  function d3_geo_pathAreaRingStart() {\n    var x00, y00, x0, y0;\n    d3_geo_pathArea.point = function(x, y) {\n      d3_geo_pathArea.point = nextPoint;\n      x00 = x0 = x, y00 = y0 = y;\n    };\n    function nextPoint(x, y) {\n      d3_geo_pathAreaPolygon += y0 * x - x0 * y;\n      x0 = x, y0 = y;\n    }\n    d3_geo_pathArea.lineEnd = function() {\n      nextPoint(x00, y00);\n    };\n  }\n  function d3_geo_pathBuffer() {\n    var pointCircle = d3_geo_pathCircle(4.5), buffer = [];\n    var stream = {\n      point: point,\n      lineStart: function() {\n        stream.point = pointLineStart;\n      },\n      lineEnd: lineEnd,\n      polygonStart: function() {\n        stream.lineEnd = lineEndPolygon;\n      },\n      polygonEnd: function() {\n        stream.lineEnd = lineEnd;\n        stream.point = point;\n      },\n      pointRadius: function(_) {\n        pointCircle = d3_geo_pathCircle(_);\n        return stream;\n      },\n      result: function() {\n        if (buffer.length) {\n          var result = buffer.join(\"\");\n          buffer = [];\n          return result;\n        }\n      }\n    };\n    function point(x, y) {\n      buffer.push(\"M\", x, \",\", y, pointCircle);\n    }\n    function pointLineStart(x, y) {\n      buffer.push(\"M\", x, \",\", y);\n      stream.point = pointLine;\n    }\n    function pointLine(x, y) {\n      buffer.push(\"L\", x, \",\", y);\n    }\n    function lineEnd() {\n      stream.point = point;\n    }\n    function lineEndPolygon() {\n      buffer.push(\"Z\");\n    }\n    return stream;\n  }\n  var d3_geo_pathCentroid = {\n    point: d3_geo_pathCentroidPoint,\n    lineStart: d3_geo_pathCentroidLineStart,\n    lineEnd: d3_geo_pathCentroidLineEnd,\n    polygonStart: function() {\n      d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidRingStart;\n    },\n    polygonEnd: function() {\n      d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint;\n      d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidLineStart;\n      d3_geo_pathCentroid.lineEnd = d3_geo_pathCentroidLineEnd;\n    }\n  };\n  function d3_geo_pathCentroidPoint(x, y) {\n    if (d3_geo_centroidDimension) return;\n    d3_geo_centroidX += x;\n    d3_geo_centroidY += y;\n    ++d3_geo_centroidZ;\n  }\n  function d3_geo_pathCentroidLineStart() {\n    var x0, y0;\n    if (d3_geo_centroidDimension !== 1) {\n      if (d3_geo_centroidDimension < 1) {\n        d3_geo_centroidDimension = 1;\n        d3_geo_centroidX = d3_geo_centroidY = d3_geo_centroidZ = 0;\n      } else return;\n    }\n    d3_geo_pathCentroid.point = function(x, y) {\n      d3_geo_pathCentroid.point = nextPoint;\n      x0 = x, y0 = y;\n    };\n    function nextPoint(x, y) {\n      var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy);\n      d3_geo_centroidX += z * (x0 + x) / 2;\n      d3_geo_centroidY += z * (y0 + y) / 2;\n      d3_geo_centroidZ += z;\n      x0 = x, y0 = y;\n    }\n  }\n  function d3_geo_pathCentroidLineEnd() {\n    d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint;\n  }\n  function d3_geo_pathCentroidRingStart() {\n    var x00, y00, x0, y0;\n    if (d3_geo_centroidDimension < 2) {\n      d3_geo_centroidDimension = 2;\n      d3_geo_centroidX = d3_geo_centroidY = d3_geo_centroidZ = 0;\n    }\n    d3_geo_pathCentroid.point = function(x, y) {\n      d3_geo_pathCentroid.point = nextPoint;\n      x00 = x0 = x, y00 = y0 = y;\n    };\n    function nextPoint(x, y) {\n      var z = y0 * x - x0 * y;\n      d3_geo_centroidX += z * (x0 + x);\n      d3_geo_centroidY += z * (y0 + y);\n      d3_geo_centroidZ += z * 3;\n      x0 = x, y0 = y;\n    }\n    d3_geo_pathCentroid.lineEnd = function() {\n      nextPoint(x00, y00);\n    };\n  }\n  function d3_geo_pathContext(context) {\n    var pointRadius = 4.5;\n    var stream = {\n      point: point,\n      lineStart: function() {\n        stream.point = pointLineStart;\n      },\n      lineEnd: lineEnd,\n      polygonStart: function() {\n        stream.lineEnd = lineEndPolygon;\n      },\n      polygonEnd: function() {\n        stream.lineEnd = lineEnd;\n        stream.point = point;\n      },\n      pointRadius: function(_) {\n        pointRadius = _;\n        return stream;\n      },\n      result: d3_noop\n    };\n    function point(x, y) {\n      context.moveTo(x, y);\n      context.arc(x, y, pointRadius, 0, 2 * π);\n    }\n    function pointLineStart(x, y) {\n      context.moveTo(x, y);\n      stream.point = pointLine;\n    }\n    function pointLine(x, y) {\n      context.lineTo(x, y);\n    }\n    function lineEnd() {\n      stream.point = point;\n    }\n    function lineEndPolygon() {\n      context.closePath();\n    }\n    return stream;\n  }\n  d3.geo.path = function() {\n    var pointRadius = 4.5, projection, context, projectStream, contextStream;\n    function path(object) {\n      if (object) d3.geo.stream(object, projectStream(contextStream.pointRadius(typeof pointRadius === \"function\" ? +pointRadius.apply(this, arguments) : pointRadius)));\n      return contextStream.result();\n    }\n    path.area = function(object) {\n      d3_geo_pathAreaSum = 0;\n      d3.geo.stream(object, projectStream(d3_geo_pathArea));\n      return d3_geo_pathAreaSum;\n    };\n    path.centroid = function(object) {\n      d3_geo_centroidDimension = d3_geo_centroidX = d3_geo_centroidY = d3_geo_centroidZ = 0;\n      d3.geo.stream(object, projectStream(d3_geo_pathCentroid));\n      return d3_geo_centroidZ ? [ d3_geo_centroidX / d3_geo_centroidZ, d3_geo_centroidY / d3_geo_centroidZ ] : undefined;\n    };\n    path.bounds = function(object) {\n      return d3_geo_bounds(projectStream)(object);\n    };\n    path.projection = function(_) {\n      if (!arguments.length) return projection;\n      projectStream = (projection = _) ? _.stream || d3_geo_pathProjectStream(_) : d3_identity;\n      return path;\n    };\n    path.context = function(_) {\n      if (!arguments.length) return context;\n      contextStream = (context = _) == null ? new d3_geo_pathBuffer() : new d3_geo_pathContext(_);\n      return path;\n    };\n    path.pointRadius = function(_) {\n      if (!arguments.length) return pointRadius;\n      pointRadius = typeof _ === \"function\" ? _ : +_;\n      return path;\n    };\n    return path.projection(d3.geo.albersUsa()).context(null);\n  };\n  function d3_geo_pathCircle(radius) {\n    return \"m0,\" + radius + \"a\" + radius + \",\" + radius + \" 0 1,1 0,\" + -2 * radius + \"a\" + radius + \",\" + radius + \" 0 1,1 0,\" + +2 * radius + \"z\";\n  }\n  function d3_geo_pathProjectStream(project) {\n    var resample = d3_geo_resample(function(λ, φ) {\n      return project([ λ * d3_degrees, φ * d3_degrees ]);\n    });\n    return function(stream) {\n      stream = resample(stream);\n      return {\n        point: function(λ, φ) {\n          stream.point(λ * d3_radians, φ * d3_radians);\n        },\n        sphere: function() {\n          stream.sphere();\n        },\n        lineStart: function() {\n          stream.lineStart();\n        },\n        lineEnd: function() {\n          stream.lineEnd();\n        },\n        polygonStart: function() {\n          stream.polygonStart();\n        },\n        polygonEnd: function() {\n          stream.polygonEnd();\n        }\n      };\n    };\n  }\n  d3.geo.albers = function() {\n    return d3.geo.conicEqualArea().parallels([ 29.5, 45.5 ]).rotate([ 98, 0 ]).center([ 0, 38 ]).scale(1e3);\n  };\n  function d3_geo_azimuthal(scale, angle) {\n    function azimuthal(λ, φ) {\n      var cosλ = Math.cos(λ), cosφ = Math.cos(φ), k = scale(cosλ * cosφ);\n      return [ k * cosφ * Math.sin(λ), k * Math.sin(φ) ];\n    }\n    azimuthal.invert = function(x, y) {\n      var ρ = Math.sqrt(x * x + y * y), c = angle(ρ), sinc = Math.sin(c), cosc = Math.cos(c);\n      return [ Math.atan2(x * sinc, ρ * cosc), Math.asin(ρ && y * sinc / ρ) ];\n    };\n    return azimuthal;\n  }\n  var d3_geo_azimuthalEqualArea = d3_geo_azimuthal(function(cosλcosφ) {\n    return Math.sqrt(2 / (1 + cosλcosφ));\n  }, function(ρ) {\n    return 2 * Math.asin(ρ / 2);\n  });\n  (d3.geo.azimuthalEqualArea = function() {\n    return d3_geo_projection(d3_geo_azimuthalEqualArea);\n  }).raw = d3_geo_azimuthalEqualArea;\n  var d3_geo_azimuthalEquidistant = d3_geo_azimuthal(function(cosλcosφ) {\n    var c = Math.acos(cosλcosφ);\n    return c && c / Math.sin(c);\n  }, d3_identity);\n  (d3.geo.azimuthalEquidistant = function() {\n    return d3_geo_projection(d3_geo_azimuthalEquidistant);\n  }).raw = d3_geo_azimuthalEquidistant;\n  function d3_geo_conicConformal(φ0, φ1) {\n    var cosφ0 = Math.cos(φ0), t = function(φ) {\n      return Math.tan(π / 4 + φ / 2);\n    }, n = φ0 === φ1 ? Math.sin(φ0) : Math.log(cosφ0 / Math.cos(φ1)) / Math.log(t(φ1) / t(φ0)), F = cosφ0 * Math.pow(t(φ0), n) / n;\n    if (!n) return d3_geo_mercator;\n    function forward(λ, φ) {\n      var ρ = Math.abs(Math.abs(φ) - π / 2) < ε ? 0 : F / Math.pow(t(φ), n);\n      return [ ρ * Math.sin(n * λ), F - ρ * Math.cos(n * λ) ];\n    }\n    forward.invert = function(x, y) {\n      var ρ0_y = F - y, ρ = d3_sgn(n) * Math.sqrt(x * x + ρ0_y * ρ0_y);\n      return [ Math.atan2(x, ρ0_y) / n, 2 * Math.atan(Math.pow(F / ρ, 1 / n)) - π / 2 ];\n    };\n    return forward;\n  }\n  (d3.geo.conicConformal = function() {\n    return d3_geo_conic(d3_geo_conicConformal);\n  }).raw = d3_geo_conicConformal;\n  function d3_geo_conicEquidistant(φ0, φ1) {\n    var cosφ0 = Math.cos(φ0), n = φ0 === φ1 ? Math.sin(φ0) : (cosφ0 - Math.cos(φ1)) / (φ1 - φ0), G = cosφ0 / n + φ0;\n    if (Math.abs(n) < ε) return d3_geo_equirectangular;\n    function forward(λ, φ) {\n      var ρ = G - φ;\n      return [ ρ * Math.sin(n * λ), G - ρ * Math.cos(n * λ) ];\n    }\n    forward.invert = function(x, y) {\n      var ρ0_y = G - y;\n      return [ Math.atan2(x, ρ0_y) / n, G - d3_sgn(n) * Math.sqrt(x * x + ρ0_y * ρ0_y) ];\n    };\n    return forward;\n  }\n  (d3.geo.conicEquidistant = function() {\n    return d3_geo_conic(d3_geo_conicEquidistant);\n  }).raw = d3_geo_conicEquidistant;\n  var d3_geo_gnomonic = d3_geo_azimuthal(function(cosλcosφ) {\n    return 1 / cosλcosφ;\n  }, Math.atan);\n  (d3.geo.gnomonic = function() {\n    return d3_geo_projection(d3_geo_gnomonic);\n  }).raw = d3_geo_gnomonic;\n  function d3_geo_mercator(λ, φ) {\n    return [ λ, Math.log(Math.tan(π / 4 + φ / 2)) ];\n  }\n  d3_geo_mercator.invert = function(x, y) {\n    return [ x, 2 * Math.atan(Math.exp(y)) - π / 2 ];\n  };\n  function d3_geo_mercatorProjection(project) {\n    var m = d3_geo_projection(project), scale = m.scale, translate = m.translate, clipExtent = m.clipExtent, clipAuto;\n    m.scale = function() {\n      var v = scale.apply(m, arguments);\n      return v === m ? clipAuto ? m.clipExtent(null) : m : v;\n    };\n    m.translate = function() {\n      var v = translate.apply(m, arguments);\n      return v === m ? clipAuto ? m.clipExtent(null) : m : v;\n    };\n    m.clipExtent = function(_) {\n      var v = clipExtent.apply(m, arguments);\n      if (v === m) {\n        if (clipAuto = _ == null) {\n          var k = π * scale(), t = translate();\n          clipExtent([ [ t[0] - k, t[1] - k ], [ t[0] + k, t[1] + k ] ]);\n        }\n      } else if (clipAuto) {\n        v = null;\n      }\n      return v;\n    };\n    return m.clipExtent(null);\n  }\n  (d3.geo.mercator = function() {\n    return d3_geo_mercatorProjection(d3_geo_mercator);\n  }).raw = d3_geo_mercator;\n  var d3_geo_orthographic = d3_geo_azimuthal(function() {\n    return 1;\n  }, Math.asin);\n  (d3.geo.orthographic = function() {\n    return d3_geo_projection(d3_geo_orthographic);\n  }).raw = d3_geo_orthographic;\n  var d3_geo_stereographic = d3_geo_azimuthal(function(cosλcosφ) {\n    return 1 / (1 + cosλcosφ);\n  }, function(ρ) {\n    return 2 * Math.atan(ρ);\n  });\n  (d3.geo.stereographic = function() {\n    return d3_geo_projection(d3_geo_stereographic);\n  }).raw = d3_geo_stereographic;\n  function d3_geo_transverseMercator(λ, φ) {\n    var B = Math.cos(φ) * Math.sin(λ);\n    return [ Math.log((1 + B) / (1 - B)) / 2, Math.atan2(Math.tan(φ), Math.cos(λ)) ];\n  }\n  d3_geo_transverseMercator.invert = function(x, y) {\n    return [ Math.atan2(d3_sinh(x), Math.cos(y)), d3_asin(Math.sin(y) / d3_cosh(x)) ];\n  };\n  (d3.geo.transverseMercator = function() {\n    return d3_geo_mercatorProjection(d3_geo_transverseMercator);\n  }).raw = d3_geo_transverseMercator;\n  d3.geom = {};\n  d3.svg = {};\n  function d3_svg_line(projection) {\n    var x = d3_svg_lineX, y = d3_svg_lineY, defined = d3_true, interpolate = d3_svg_lineLinear, interpolateKey = interpolate.key, tension = .7;\n    function line(data) {\n      var segments = [], points = [], i = -1, n = data.length, d, fx = d3_functor(x), fy = d3_functor(y);\n      function segment() {\n        segments.push(\"M\", interpolate(projection(points), tension));\n      }\n      while (++i < n) {\n        if (defined.call(this, d = data[i], i)) {\n          points.push([ +fx.call(this, d, i), +fy.call(this, d, i) ]);\n        } else if (points.length) {\n          segment();\n          points = [];\n        }\n      }\n      if (points.length) segment();\n      return segments.length ? segments.join(\"\") : null;\n    }\n    line.x = function(_) {\n      if (!arguments.length) return x;\n      x = _;\n      return line;\n    };\n    line.y = function(_) {\n      if (!arguments.length) return y;\n      y = _;\n      return line;\n    };\n    line.defined = function(_) {\n      if (!arguments.length) return defined;\n      defined = _;\n      return line;\n    };\n    line.interpolate = function(_) {\n      if (!arguments.length) return interpolateKey;\n      if (typeof _ === \"function\") interpolateKey = interpolate = _; else interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) || d3_svg_lineLinear).key;\n      return line;\n    };\n    line.tension = function(_) {\n      if (!arguments.length) return tension;\n      tension = _;\n      return line;\n    };\n    return line;\n  }\n  d3.svg.line = function() {\n    return d3_svg_line(d3_identity);\n  };\n  function d3_svg_lineX(d) {\n    return d[0];\n  }\n  function d3_svg_lineY(d) {\n    return d[1];\n  }\n  var d3_svg_lineInterpolators = d3.map({\n    linear: d3_svg_lineLinear,\n    \"linear-closed\": d3_svg_lineLinearClosed,\n    \"step-before\": d3_svg_lineStepBefore,\n    \"step-after\": d3_svg_lineStepAfter,\n    basis: d3_svg_lineBasis,\n    \"basis-open\": d3_svg_lineBasisOpen,\n    \"basis-closed\": d3_svg_lineBasisClosed,\n    bundle: d3_svg_lineBundle,\n    cardinal: d3_svg_lineCardinal,\n    \"cardinal-open\": d3_svg_lineCardinalOpen,\n    \"cardinal-closed\": d3_svg_lineCardinalClosed,\n    monotone: d3_svg_lineMonotone\n  });\n  d3_svg_lineInterpolators.forEach(function(key, value) {\n    value.key = key;\n    value.closed = /-closed$/.test(key);\n  });\n  function d3_svg_lineLinear(points) {\n    return points.join(\"L\");\n  }\n  function d3_svg_lineLinearClosed(points) {\n    return d3_svg_lineLinear(points) + \"Z\";\n  }\n  function d3_svg_lineStepBefore(points) {\n    var i = 0, n = points.length, p = points[0], path = [ p[0], \",\", p[1] ];\n    while (++i < n) path.push(\"V\", (p = points[i])[1], \"H\", p[0]);\n    return path.join(\"\");\n  }\n  function d3_svg_lineStepAfter(points) {\n    var i = 0, n = points.length, p = points[0], path = [ p[0], \",\", p[1] ];\n    while (++i < n) path.push(\"H\", (p = points[i])[0], \"V\", p[1]);\n    return path.join(\"\");\n  }\n  function d3_svg_lineCardinalOpen(points, tension) {\n    return points.length < 4 ? d3_svg_lineLinear(points) : points[1] + d3_svg_lineHermite(points.slice(1, points.length - 1), d3_svg_lineCardinalTangents(points, tension));\n  }\n  function d3_svg_lineCardinalClosed(points, tension) {\n    return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite((points.push(points[0]), \n    points), d3_svg_lineCardinalTangents([ points[points.length - 2] ].concat(points, [ points[1] ]), tension));\n  }\n  function d3_svg_lineCardinal(points, tension) {\n    return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite(points, d3_svg_lineCardinalTangents(points, tension));\n  }\n  function d3_svg_lineHermite(points, tangents) {\n    if (tangents.length < 1 || points.length != tangents.length && points.length != tangents.length + 2) {\n      return d3_svg_lineLinear(points);\n    }\n    var quad = points.length != tangents.length, path = \"\", p0 = points[0], p = points[1], t0 = tangents[0], t = t0, pi = 1;\n    if (quad) {\n      path += \"Q\" + (p[0] - t0[0] * 2 / 3) + \",\" + (p[1] - t0[1] * 2 / 3) + \",\" + p[0] + \",\" + p[1];\n      p0 = points[1];\n      pi = 2;\n    }\n    if (tangents.length > 1) {\n      t = tangents[1];\n      p = points[pi];\n      pi++;\n      path += \"C\" + (p0[0] + t0[0]) + \",\" + (p0[1] + t0[1]) + \",\" + (p[0] - t[0]) + \",\" + (p[1] - t[1]) + \",\" + p[0] + \",\" + p[1];\n      for (var i = 2; i < tangents.length; i++, pi++) {\n        p = points[pi];\n        t = tangents[i];\n        path += \"S\" + (p[0] - t[0]) + \",\" + (p[1] - t[1]) + \",\" + p[0] + \",\" + p[1];\n      }\n    }\n    if (quad) {\n      var lp = points[pi];\n      path += \"Q\" + (p[0] + t[0] * 2 / 3) + \",\" + (p[1] + t[1] * 2 / 3) + \",\" + lp[0] + \",\" + lp[1];\n    }\n    return path;\n  }\n  function d3_svg_lineCardinalTangents(points, tension) {\n    var tangents = [], a = (1 - tension) / 2, p0, p1 = points[0], p2 = points[1], i = 1, n = points.length;\n    while (++i < n) {\n      p0 = p1;\n      p1 = p2;\n      p2 = points[i];\n      tangents.push([ a * (p2[0] - p0[0]), a * (p2[1] - p0[1]) ]);\n    }\n    return tangents;\n  }\n  function d3_svg_lineBasis(points) {\n    if (points.length < 3) return d3_svg_lineLinear(points);\n    var i = 1, n = points.length, pi = points[0], x0 = pi[0], y0 = pi[1], px = [ x0, x0, x0, (pi = points[1])[0] ], py = [ y0, y0, y0, pi[1] ], path = [ x0, \",\", y0 ];\n    d3_svg_lineBasisBezier(path, px, py);\n    while (++i < n) {\n      pi = points[i];\n      px.shift();\n      px.push(pi[0]);\n      py.shift();\n      py.push(pi[1]);\n      d3_svg_lineBasisBezier(path, px, py);\n    }\n    i = -1;\n    while (++i < 2) {\n      px.shift();\n      px.push(pi[0]);\n      py.shift();\n      py.push(pi[1]);\n      d3_svg_lineBasisBezier(path, px, py);\n    }\n    return path.join(\"\");\n  }\n  function d3_svg_lineBasisOpen(points) {\n    if (points.length < 4) return d3_svg_lineLinear(points);\n    var path = [], i = -1, n = points.length, pi, px = [ 0 ], py = [ 0 ];\n    while (++i < 3) {\n      pi = points[i];\n      px.push(pi[0]);\n      py.push(pi[1]);\n    }\n    path.push(d3_svg_lineDot4(d3_svg_lineBasisBezier3, px) + \",\" + d3_svg_lineDot4(d3_svg_lineBasisBezier3, py));\n    --i;\n    while (++i < n) {\n      pi = points[i];\n      px.shift();\n      px.push(pi[0]);\n      py.shift();\n      py.push(pi[1]);\n      d3_svg_lineBasisBezier(path, px, py);\n    }\n    return path.join(\"\");\n  }\n  function d3_svg_lineBasisClosed(points) {\n    var path, i = -1, n = points.length, m = n + 4, pi, px = [], py = [];\n    while (++i < 4) {\n      pi = points[i % n];\n      px.push(pi[0]);\n      py.push(pi[1]);\n    }\n    path = [ d3_svg_lineDot4(d3_svg_lineBasisBezier3, px), \",\", d3_svg_lineDot4(d3_svg_lineBasisBezier3, py) ];\n    --i;\n    while (++i < m) {\n      pi = points[i % n];\n      px.shift();\n      px.push(pi[0]);\n      py.shift();\n      py.push(pi[1]);\n      d3_svg_lineBasisBezier(path, px, py);\n    }\n    return path.join(\"\");\n  }\n  function d3_svg_lineBundle(points, tension) {\n    var n = points.length - 1;\n    if (n) {\n      var x0 = points[0][0], y0 = points[0][1], dx = points[n][0] - x0, dy = points[n][1] - y0, i = -1, p, t;\n      while (++i <= n) {\n        p = points[i];\n        t = i / n;\n        p[0] = tension * p[0] + (1 - tension) * (x0 + t * dx);\n        p[1] = tension * p[1] + (1 - tension) * (y0 + t * dy);\n      }\n    }\n    return d3_svg_lineBasis(points);\n  }\n  function d3_svg_lineDot4(a, b) {\n    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];\n  }\n  var d3_svg_lineBasisBezier1 = [ 0, 2 / 3, 1 / 3, 0 ], d3_svg_lineBasisBezier2 = [ 0, 1 / 3, 2 / 3, 0 ], d3_svg_lineBasisBezier3 = [ 0, 1 / 6, 2 / 3, 1 / 6 ];\n  function d3_svg_lineBasisBezier(path, x, y) {\n    path.push(\"C\", d3_svg_lineDot4(d3_svg_lineBasisBezier1, x), \",\", d3_svg_lineDot4(d3_svg_lineBasisBezier1, y), \",\", d3_svg_lineDot4(d3_svg_lineBasisBezier2, x), \",\", d3_svg_lineDot4(d3_svg_lineBasisBezier2, y), \",\", d3_svg_lineDot4(d3_svg_lineBasisBezier3, x), \",\", d3_svg_lineDot4(d3_svg_lineBasisBezier3, y));\n  }\n  function d3_svg_lineSlope(p0, p1) {\n    return (p1[1] - p0[1]) / (p1[0] - p0[0]);\n  }\n  function d3_svg_lineFiniteDifferences(points) {\n    var i = 0, j = points.length - 1, m = [], p0 = points[0], p1 = points[1], d = m[0] = d3_svg_lineSlope(p0, p1);\n    while (++i < j) {\n      m[i] = (d + (d = d3_svg_lineSlope(p0 = p1, p1 = points[i + 1]))) / 2;\n    }\n    m[i] = d;\n    return m;\n  }\n  function d3_svg_lineMonotoneTangents(points) {\n    var tangents = [], d, a, b, s, m = d3_svg_lineFiniteDifferences(points), i = -1, j = points.length - 1;\n    while (++i < j) {\n      d = d3_svg_lineSlope(points[i], points[i + 1]);\n      if (Math.abs(d) < 1e-6) {\n        m[i] = m[i + 1] = 0;\n      } else {\n        a = m[i] / d;\n        b = m[i + 1] / d;\n        s = a * a + b * b;\n        if (s > 9) {\n          s = d * 3 / Math.sqrt(s);\n          m[i] = s * a;\n          m[i + 1] = s * b;\n        }\n      }\n    }\n    i = -1;\n    while (++i <= j) {\n      s = (points[Math.min(j, i + 1)][0] - points[Math.max(0, i - 1)][0]) / (6 * (1 + m[i] * m[i]));\n      tangents.push([ s || 0, m[i] * s || 0 ]);\n    }\n    return tangents;\n  }\n  function d3_svg_lineMonotone(points) {\n    return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite(points, d3_svg_lineMonotoneTangents(points));\n  }\n  d3.geom.hull = function(vertices) {\n    var x = d3_svg_lineX, y = d3_svg_lineY;\n    if (arguments.length) return hull(vertices);\n    function hull(data) {\n      if (data.length < 3) return [];\n      var fx = d3_functor(x), fy = d3_functor(y), n = data.length, vertices, plen = n - 1, points = [], stack = [], d, i, j, h = 0, x1, y1, x2, y2, u, v, a, sp;\n      if (fx === d3_svg_lineX && y === d3_svg_lineY) vertices = data; else for (i = 0, \n      vertices = []; i < n; ++i) {\n        vertices.push([ +fx.call(this, d = data[i], i), +fy.call(this, d, i) ]);\n      }\n      for (i = 1; i < n; ++i) {\n        if (vertices[i][1] < vertices[h][1]) {\n          h = i;\n        } else if (vertices[i][1] == vertices[h][1]) {\n          h = vertices[i][0] < vertices[h][0] ? i : h;\n        }\n      }\n      for (i = 0; i < n; ++i) {\n        if (i === h) continue;\n        y1 = vertices[i][1] - vertices[h][1];\n        x1 = vertices[i][0] - vertices[h][0];\n        points.push({\n          angle: Math.atan2(y1, x1),\n          index: i\n        });\n      }\n      points.sort(function(a, b) {\n        return a.angle - b.angle;\n      });\n      a = points[0].angle;\n      v = points[0].index;\n      u = 0;\n      for (i = 1; i < plen; ++i) {\n        j = points[i].index;\n        if (a == points[i].angle) {\n          x1 = vertices[v][0] - vertices[h][0];\n          y1 = vertices[v][1] - vertices[h][1];\n          x2 = vertices[j][0] - vertices[h][0];\n          y2 = vertices[j][1] - vertices[h][1];\n          if (x1 * x1 + y1 * y1 >= x2 * x2 + y2 * y2) {\n            points[i].index = -1;\n          } else {\n            points[u].index = -1;\n            a = points[i].angle;\n            u = i;\n            v = j;\n          }\n        } else {\n          a = points[i].angle;\n          u = i;\n          v = j;\n        }\n      }\n      stack.push(h);\n      for (i = 0, j = 0; i < 2; ++j) {\n        if (points[j].index !== -1) {\n          stack.push(points[j].index);\n          i++;\n        }\n      }\n      sp = stack.length;\n      for (;j < plen; ++j) {\n        if (points[j].index === -1) continue;\n        while (!d3_geom_hullCCW(stack[sp - 2], stack[sp - 1], points[j].index, vertices)) {\n          --sp;\n        }\n        stack[sp++] = points[j].index;\n      }\n      var poly = [];\n      for (i = 0; i < sp; ++i) {\n        poly.push(data[stack[i]]);\n      }\n      return poly;\n    }\n    hull.x = function(_) {\n      return arguments.length ? (x = _, hull) : x;\n    };\n    hull.y = function(_) {\n      return arguments.length ? (y = _, hull) : y;\n    };\n    return hull;\n  };\n  function d3_geom_hullCCW(i1, i2, i3, v) {\n    var t, a, b, c, d, e, f;\n    t = v[i1];\n    a = t[0];\n    b = t[1];\n    t = v[i2];\n    c = t[0];\n    d = t[1];\n    t = v[i3];\n    e = t[0];\n    f = t[1];\n    return (f - b) * (c - a) - (d - b) * (e - a) > 0;\n  }\n  d3.geom.polygon = function(coordinates) {\n    coordinates.area = function() {\n      var i = 0, n = coordinates.length, area = coordinates[n - 1][1] * coordinates[0][0] - coordinates[n - 1][0] * coordinates[0][1];\n      while (++i < n) {\n        area += coordinates[i - 1][1] * coordinates[i][0] - coordinates[i - 1][0] * coordinates[i][1];\n      }\n      return area * .5;\n    };\n    coordinates.centroid = function(k) {\n      var i = -1, n = coordinates.length, x = 0, y = 0, a, b = coordinates[n - 1], c;\n      if (!arguments.length) k = -1 / (6 * coordinates.area());\n      while (++i < n) {\n        a = b;\n        b = coordinates[i];\n        c = a[0] * b[1] - b[0] * a[1];\n        x += (a[0] + b[0]) * c;\n        y += (a[1] + b[1]) * c;\n      }\n      return [ x * k, y * k ];\n    };\n    coordinates.clip = function(subject) {\n      var input, i = -1, n = coordinates.length, j, m, a = coordinates[n - 1], b, c, d;\n      while (++i < n) {\n        input = subject.slice();\n        subject.length = 0;\n        b = coordinates[i];\n        c = input[(m = input.length) - 1];\n        j = -1;\n        while (++j < m) {\n          d = input[j];\n          if (d3_geom_polygonInside(d, a, b)) {\n            if (!d3_geom_polygonInside(c, a, b)) {\n              subject.push(d3_geom_polygonIntersect(c, d, a, b));\n            }\n            subject.push(d);\n          } else if (d3_geom_polygonInside(c, a, b)) {\n            subject.push(d3_geom_polygonIntersect(c, d, a, b));\n          }\n          c = d;\n        }\n        a = b;\n      }\n      return subject;\n    };\n    return coordinates;\n  };\n  function d3_geom_polygonInside(p, a, b) {\n    return (b[0] - a[0]) * (p[1] - a[1]) < (b[1] - a[1]) * (p[0] - a[0]);\n  }\n  function d3_geom_polygonIntersect(c, d, a, b) {\n    var x1 = c[0], x3 = a[0], x21 = d[0] - x1, x43 = b[0] - x3, y1 = c[1], y3 = a[1], y21 = d[1] - y1, y43 = b[1] - y3, ua = (x43 * (y1 - y3) - y43 * (x1 - x3)) / (y43 * x21 - x43 * y21);\n    return [ x1 + ua * x21, y1 + ua * y21 ];\n  }\n  d3.geom.delaunay = function(vertices) {\n    var edges = vertices.map(function() {\n      return [];\n    }), triangles = [];\n    d3_geom_voronoiTessellate(vertices, function(e) {\n      edges[e.region.l.index].push(vertices[e.region.r.index]);\n    });\n    edges.forEach(function(edge, i) {\n      var v = vertices[i], cx = v[0], cy = v[1];\n      edge.forEach(function(v) {\n        v.angle = Math.atan2(v[0] - cx, v[1] - cy);\n      });\n      edge.sort(function(a, b) {\n        return a.angle - b.angle;\n      });\n      for (var j = 0, m = edge.length - 1; j < m; j++) {\n        triangles.push([ v, edge[j], edge[j + 1] ]);\n      }\n    });\n    return triangles;\n  };\n  d3.geom.voronoi = function(points) {\n    var size = null, x = d3_svg_lineX, y = d3_svg_lineY, clip;\n    if (arguments.length) return voronoi(points);\n    function voronoi(data) {\n      var points, polygons = data.map(function() {\n        return [];\n      }), fx = d3_functor(x), fy = d3_functor(y), d, i, n = data.length, Z = 1e6;\n      if (fx === d3_svg_lineX && fy === d3_svg_lineY) points = data; else for (points = [], \n      i = 0; i < n; ++i) {\n        points.push([ +fx.call(this, d = data[i], i), +fy.call(this, d, i) ]);\n      }\n      d3_geom_voronoiTessellate(points, function(e) {\n        var s1, s2, x1, x2, y1, y2;\n        if (e.a === 1 && e.b >= 0) {\n          s1 = e.ep.r;\n          s2 = e.ep.l;\n        } else {\n          s1 = e.ep.l;\n          s2 = e.ep.r;\n        }\n        if (e.a === 1) {\n          y1 = s1 ? s1.y : -Z;\n          x1 = e.c - e.b * y1;\n          y2 = s2 ? s2.y : Z;\n          x2 = e.c - e.b * y2;\n        } else {\n          x1 = s1 ? s1.x : -Z;\n          y1 = e.c - e.a * x1;\n          x2 = s2 ? s2.x : Z;\n          y2 = e.c - e.a * x2;\n        }\n        var v1 = [ x1, y1 ], v2 = [ x2, y2 ];\n        polygons[e.region.l.index].push(v1, v2);\n        polygons[e.region.r.index].push(v1, v2);\n      });\n      polygons = polygons.map(function(polygon, i) {\n        var cx = points[i][0], cy = points[i][1], angle = polygon.map(function(v) {\n          return Math.atan2(v[0] - cx, v[1] - cy);\n        }), order = d3.range(polygon.length).sort(function(a, b) {\n          return angle[a] - angle[b];\n        });\n        return order.filter(function(d, i) {\n          return !i || angle[d] - angle[order[i - 1]] > ε;\n        }).map(function(d) {\n          return polygon[d];\n        });\n      });\n      polygons.forEach(function(polygon, i) {\n        var n = polygon.length;\n        if (!n) return polygon.push([ -Z, -Z ], [ -Z, Z ], [ Z, Z ], [ Z, -Z ]);\n        if (n > 2) return;\n        var p0 = points[i], p1 = polygon[0], p2 = polygon[1], x0 = p0[0], y0 = p0[1], x1 = p1[0], y1 = p1[1], x2 = p2[0], y2 = p2[1], dx = Math.abs(x2 - x1), dy = y2 - y1;\n        if (Math.abs(dy) < ε) {\n          var y = y0 < y1 ? -Z : Z;\n          polygon.push([ -Z, y ], [ Z, y ]);\n        } else if (dx < ε) {\n          var x = x0 < x1 ? -Z : Z;\n          polygon.push([ x, -Z ], [ x, Z ]);\n        } else {\n          var y = (x2 - x1) * (y1 - y0) < (x1 - x0) * (y2 - y1) ? Z : -Z, z = Math.abs(dy) - dx;\n          if (Math.abs(z) < ε) {\n            polygon.push([ dy < 0 ? y : -y, y ]);\n          } else {\n            if (z > 0) y *= -1;\n            polygon.push([ -Z, y ], [ Z, y ]);\n          }\n        }\n      });\n      if (clip) for (i = 0; i < n; ++i) clip(polygons[i]);\n      for (i = 0; i < n; ++i) polygons[i].point = data[i];\n      return polygons;\n    }\n    voronoi.x = function(_) {\n      return arguments.length ? (x = _, voronoi) : x;\n    };\n    voronoi.y = function(_) {\n      return arguments.length ? (y = _, voronoi) : y;\n    };\n    voronoi.size = function(_) {\n      if (!arguments.length) return size;\n      if (_ == null) {\n        clip = null;\n      } else {\n        size = [ +_[0], +_[1] ];\n        clip = d3.geom.polygon([ [ 0, 0 ], [ 0, size[1] ], size, [ size[0], 0 ] ]).clip;\n      }\n      return voronoi;\n    };\n    voronoi.links = function(data) {\n      var points, graph = data.map(function() {\n        return [];\n      }), links = [], fx = d3_functor(x), fy = d3_functor(y), d, i, n = data.length;\n      if (fx === d3_svg_lineX && fy === d3_svg_lineY) points = data; else for (i = 0; i < n; ++i) {\n        points.push([ +fx.call(this, d = data[i], i), +fy.call(this, d, i) ]);\n      }\n      d3_geom_voronoiTessellate(points, function(e) {\n        var l = e.region.l.index, r = e.region.r.index;\n        if (graph[l][r]) return;\n        graph[l][r] = graph[r][l] = true;\n        links.push({\n          source: data[l],\n          target: data[r]\n        });\n      });\n      return links;\n    };\n    voronoi.triangles = function(data) {\n      if (x === d3_svg_lineX && y === d3_svg_lineY) return d3.geom.delaunay(data);\n      var points, point, fx = d3_functor(x), fy = d3_functor(y), d, i, n;\n      for (i = 0, points = [], n = data.length; i < n; ++i) {\n        point = [ +fx.call(this, d = data[i], i), +fy.call(this, d, i) ];\n        point.data = d;\n        points.push(point);\n      }\n      return d3.geom.delaunay(points).map(function(triangle) {\n        return triangle.map(function(point) {\n          return point.data;\n        });\n      });\n    };\n    return voronoi;\n  };\n  var d3_geom_voronoiOpposite = {\n    l: \"r\",\n    r: \"l\"\n  };\n  function d3_geom_voronoiTessellate(points, callback) {\n    var Sites = {\n      list: points.map(function(v, i) {\n        return {\n          index: i,\n          x: v[0],\n          y: v[1]\n        };\n      }).sort(function(a, b) {\n        return a.y < b.y ? -1 : a.y > b.y ? 1 : a.x < b.x ? -1 : a.x > b.x ? 1 : 0;\n      }),\n      bottomSite: null\n    };\n    var EdgeList = {\n      list: [],\n      leftEnd: null,\n      rightEnd: null,\n      init: function() {\n        EdgeList.leftEnd = EdgeList.createHalfEdge(null, \"l\");\n        EdgeList.rightEnd = EdgeList.createHalfEdge(null, \"l\");\n        EdgeList.leftEnd.r = EdgeList.rightEnd;\n        EdgeList.rightEnd.l = EdgeList.leftEnd;\n        EdgeList.list.unshift(EdgeList.leftEnd, EdgeList.rightEnd);\n      },\n      createHalfEdge: function(edge, side) {\n        return {\n          edge: edge,\n          side: side,\n          vertex: null,\n          l: null,\n          r: null\n        };\n      },\n      insert: function(lb, he) {\n        he.l = lb;\n        he.r = lb.r;\n        lb.r.l = he;\n        lb.r = he;\n      },\n      leftBound: function(p) {\n        var he = EdgeList.leftEnd;\n        do {\n          he = he.r;\n        } while (he != EdgeList.rightEnd && Geom.rightOf(he, p));\n        he = he.l;\n        return he;\n      },\n      del: function(he) {\n        he.l.r = he.r;\n        he.r.l = he.l;\n        he.edge = null;\n      },\n      right: function(he) {\n        return he.r;\n      },\n      left: function(he) {\n        return he.l;\n      },\n      leftRegion: function(he) {\n        return he.edge == null ? Sites.bottomSite : he.edge.region[he.side];\n      },\n      rightRegion: function(he) {\n        return he.edge == null ? Sites.bottomSite : he.edge.region[d3_geom_voronoiOpposite[he.side]];\n      }\n    };\n    var Geom = {\n      bisect: function(s1, s2) {\n        var newEdge = {\n          region: {\n            l: s1,\n            r: s2\n          },\n          ep: {\n            l: null,\n            r: null\n          }\n        };\n        var dx = s2.x - s1.x, dy = s2.y - s1.y, adx = dx > 0 ? dx : -dx, ady = dy > 0 ? dy : -dy;\n        newEdge.c = s1.x * dx + s1.y * dy + (dx * dx + dy * dy) * .5;\n        if (adx > ady) {\n          newEdge.a = 1;\n          newEdge.b = dy / dx;\n          newEdge.c /= dx;\n        } else {\n          newEdge.b = 1;\n          newEdge.a = dx / dy;\n          newEdge.c /= dy;\n        }\n        return newEdge;\n      },\n      intersect: function(el1, el2) {\n        var e1 = el1.edge, e2 = el2.edge;\n        if (!e1 || !e2 || e1.region.r == e2.region.r) {\n          return null;\n        }\n        var d = e1.a * e2.b - e1.b * e2.a;\n        if (Math.abs(d) < 1e-10) {\n          return null;\n        }\n        var xint = (e1.c * e2.b - e2.c * e1.b) / d, yint = (e2.c * e1.a - e1.c * e2.a) / d, e1r = e1.region.r, e2r = e2.region.r, el, e;\n        if (e1r.y < e2r.y || e1r.y == e2r.y && e1r.x < e2r.x) {\n          el = el1;\n          e = e1;\n        } else {\n          el = el2;\n          e = e2;\n        }\n        var rightOfSite = xint >= e.region.r.x;\n        if (rightOfSite && el.side === \"l\" || !rightOfSite && el.side === \"r\") {\n          return null;\n        }\n        return {\n          x: xint,\n          y: yint\n        };\n      },\n      rightOf: function(he, p) {\n        var e = he.edge, topsite = e.region.r, rightOfSite = p.x > topsite.x;\n        if (rightOfSite && he.side === \"l\") {\n          return 1;\n        }\n        if (!rightOfSite && he.side === \"r\") {\n          return 0;\n        }\n        if (e.a === 1) {\n          var dyp = p.y - topsite.y, dxp = p.x - topsite.x, fast = 0, above = 0;\n          if (!rightOfSite && e.b < 0 || rightOfSite && e.b >= 0) {\n            above = fast = dyp >= e.b * dxp;\n          } else {\n            above = p.x + p.y * e.b > e.c;\n            if (e.b < 0) {\n              above = !above;\n            }\n            if (!above) {\n              fast = 1;\n            }\n          }\n          if (!fast) {\n            var dxs = topsite.x - e.region.l.x;\n            above = e.b * (dxp * dxp - dyp * dyp) < dxs * dyp * (1 + 2 * dxp / dxs + e.b * e.b);\n            if (e.b < 0) {\n              above = !above;\n            }\n          }\n        } else {\n          var yl = e.c - e.a * p.x, t1 = p.y - yl, t2 = p.x - topsite.x, t3 = yl - topsite.y;\n          above = t1 * t1 > t2 * t2 + t3 * t3;\n        }\n        return he.side === \"l\" ? above : !above;\n      },\n      endPoint: function(edge, side, site) {\n        edge.ep[side] = site;\n        if (!edge.ep[d3_geom_voronoiOpposite[side]]) return;\n        callback(edge);\n      },\n      distance: function(s, t) {\n        var dx = s.x - t.x, dy = s.y - t.y;\n        return Math.sqrt(dx * dx + dy * dy);\n      }\n    };\n    var EventQueue = {\n      list: [],\n      insert: function(he, site, offset) {\n        he.vertex = site;\n        he.ystar = site.y + offset;\n        for (var i = 0, list = EventQueue.list, l = list.length; i < l; i++) {\n          var next = list[i];\n          if (he.ystar > next.ystar || he.ystar == next.ystar && site.x > next.vertex.x) {\n            continue;\n          } else {\n            break;\n          }\n        }\n        list.splice(i, 0, he);\n      },\n      del: function(he) {\n        for (var i = 0, ls = EventQueue.list, l = ls.length; i < l && ls[i] != he; ++i) {}\n        ls.splice(i, 1);\n      },\n      empty: function() {\n        return EventQueue.list.length === 0;\n      },\n      nextEvent: function(he) {\n        for (var i = 0, ls = EventQueue.list, l = ls.length; i < l; ++i) {\n          if (ls[i] == he) return ls[i + 1];\n        }\n        return null;\n      },\n      min: function() {\n        var elem = EventQueue.list[0];\n        return {\n          x: elem.vertex.x,\n          y: elem.ystar\n        };\n      },\n      extractMin: function() {\n        return EventQueue.list.shift();\n      }\n    };\n    EdgeList.init();\n    Sites.bottomSite = Sites.list.shift();\n    var newSite = Sites.list.shift(), newIntStar;\n    var lbnd, rbnd, llbnd, rrbnd, bisector;\n    var bot, top, temp, p, v;\n    var e, pm;\n    while (true) {\n      if (!EventQueue.empty()) {\n        newIntStar = EventQueue.min();\n      }\n      if (newSite && (EventQueue.empty() || newSite.y < newIntStar.y || newSite.y == newIntStar.y && newSite.x < newIntStar.x)) {\n        lbnd = EdgeList.leftBound(newSite);\n        rbnd = EdgeList.right(lbnd);\n        bot = EdgeList.rightRegion(lbnd);\n        e = Geom.bisect(bot, newSite);\n        bisector = EdgeList.createHalfEdge(e, \"l\");\n        EdgeList.insert(lbnd, bisector);\n        p = Geom.intersect(lbnd, bisector);\n        if (p) {\n          EventQueue.del(lbnd);\n          EventQueue.insert(lbnd, p, Geom.distance(p, newSite));\n        }\n        lbnd = bisector;\n        bisector = EdgeList.createHalfEdge(e, \"r\");\n        EdgeList.insert(lbnd, bisector);\n        p = Geom.intersect(bisector, rbnd);\n        if (p) {\n          EventQueue.insert(bisector, p, Geom.distance(p, newSite));\n        }\n        newSite = Sites.list.shift();\n      } else if (!EventQueue.empty()) {\n        lbnd = EventQueue.extractMin();\n        llbnd = EdgeList.left(lbnd);\n        rbnd = EdgeList.right(lbnd);\n        rrbnd = EdgeList.right(rbnd);\n        bot = EdgeList.leftRegion(lbnd);\n        top = EdgeList.rightRegion(rbnd);\n        v = lbnd.vertex;\n        Geom.endPoint(lbnd.edge, lbnd.side, v);\n        Geom.endPoint(rbnd.edge, rbnd.side, v);\n        EdgeList.del(lbnd);\n        EventQueue.del(rbnd);\n        EdgeList.del(rbnd);\n        pm = \"l\";\n        if (bot.y > top.y) {\n          temp = bot;\n          bot = top;\n          top = temp;\n          pm = \"r\";\n        }\n        e = Geom.bisect(bot, top);\n        bisector = EdgeList.createHalfEdge(e, pm);\n        EdgeList.insert(llbnd, bisector);\n        Geom.endPoint(e, d3_geom_voronoiOpposite[pm], v);\n        p = Geom.intersect(llbnd, bisector);\n        if (p) {\n          EventQueue.del(llbnd);\n          EventQueue.insert(llbnd, p, Geom.distance(p, bot));\n        }\n        p = Geom.intersect(bisector, rrbnd);\n        if (p) {\n          EventQueue.insert(bisector, p, Geom.distance(p, bot));\n        }\n      } else {\n        break;\n      }\n    }\n    for (lbnd = EdgeList.right(EdgeList.leftEnd); lbnd != EdgeList.rightEnd; lbnd = EdgeList.right(lbnd)) {\n      callback(lbnd.edge);\n    }\n  }\n  d3.geom.quadtree = function(points, x1, y1, x2, y2) {\n    var x = d3_svg_lineX, y = d3_svg_lineY, compat;\n    if (compat = arguments.length) {\n      x = d3_geom_quadtreeCompatX;\n      y = d3_geom_quadtreeCompatY;\n      if (compat === 3) {\n        y2 = y1;\n        x2 = x1;\n        y1 = x1 = 0;\n      }\n      return quadtree(points);\n    }\n    function quadtree(data) {\n      var d, fx = d3_functor(x), fy = d3_functor(y), xs, ys, i, n, x1_, y1_, x2_, y2_;\n      if (x1 != null) {\n        x1_ = x1, y1_ = y1, x2_ = x2, y2_ = y2;\n      } else {\n        x2_ = y2_ = -(x1_ = y1_ = Infinity);\n        xs = [], ys = [];\n        n = data.length;\n        if (compat) for (i = 0; i < n; ++i) {\n          d = data[i];\n          if (d.x < x1_) x1_ = d.x;\n          if (d.y < y1_) y1_ = d.y;\n          if (d.x > x2_) x2_ = d.x;\n          if (d.y > y2_) y2_ = d.y;\n          xs.push(d.x);\n          ys.push(d.y);\n        } else for (i = 0; i < n; ++i) {\n          var x_ = +fx(d = data[i], i), y_ = +fy(d, i);\n          if (x_ < x1_) x1_ = x_;\n          if (y_ < y1_) y1_ = y_;\n          if (x_ > x2_) x2_ = x_;\n          if (y_ > y2_) y2_ = y_;\n          xs.push(x_);\n          ys.push(y_);\n        }\n      }\n      var dx = x2_ - x1_, dy = y2_ - y1_;\n      if (dx > dy) y2_ = y1_ + dx; else x2_ = x1_ + dy;\n      function insert(n, d, x, y, x1, y1, x2, y2) {\n        if (isNaN(x) || isNaN(y)) return;\n        if (n.leaf) {\n          var nx = n.x, ny = n.y;\n          if (nx != null) {\n            if (Math.abs(nx - x) + Math.abs(ny - y) < .01) {\n              insertChild(n, d, x, y, x1, y1, x2, y2);\n            } else {\n              var nPoint = n.point;\n              n.x = n.y = n.point = null;\n              insertChild(n, nPoint, nx, ny, x1, y1, x2, y2);\n              insertChild(n, d, x, y, x1, y1, x2, y2);\n            }\n          } else {\n            n.x = x, n.y = y, n.point = d;\n          }\n        } else {\n          insertChild(n, d, x, y, x1, y1, x2, y2);\n        }\n      }\n      function insertChild(n, d, x, y, x1, y1, x2, y2) {\n        var sx = (x1 + x2) * .5, sy = (y1 + y2) * .5, right = x >= sx, bottom = y >= sy, i = (bottom << 1) + right;\n        n.leaf = false;\n        n = n.nodes[i] || (n.nodes[i] = d3_geom_quadtreeNode());\n        if (right) x1 = sx; else x2 = sx;\n        if (bottom) y1 = sy; else y2 = sy;\n        insert(n, d, x, y, x1, y1, x2, y2);\n      }\n      var root = d3_geom_quadtreeNode();\n      root.add = function(d) {\n        insert(root, d, +fx(d, ++i), +fy(d, i), x1_, y1_, x2_, y2_);\n      };\n      root.visit = function(f) {\n        d3_geom_quadtreeVisit(f, root, x1_, y1_, x2_, y2_);\n      };\n      i = -1;\n      if (x1 == null) {\n        while (++i < n) {\n          insert(root, data[i], xs[i], ys[i], x1_, y1_, x2_, y2_);\n        }\n        --i;\n      } else data.forEach(root.add);\n      xs = ys = data = d = null;\n      return root;\n    }\n    quadtree.x = function(_) {\n      return arguments.length ? (x = _, quadtree) : x;\n    };\n    quadtree.y = function(_) {\n      return arguments.length ? (y = _, quadtree) : y;\n    };\n    quadtree.size = function(_) {\n      if (!arguments.length) return x1 == null ? null : [ x2, y2 ];\n      if (_ == null) {\n        x1 = y1 = x2 = y2 = null;\n      } else {\n        x1 = y1 = 0;\n        x2 = +_[0], y2 = +_[1];\n      }\n      return quadtree;\n    };\n    return quadtree;\n  };\n  function d3_geom_quadtreeCompatX(d) {\n    return d.x;\n  }\n  function d3_geom_quadtreeCompatY(d) {\n    return d.y;\n  }\n  function d3_geom_quadtreeNode() {\n    return {\n      leaf: true,\n      nodes: [],\n      point: null,\n      x: null,\n      y: null\n    };\n  }\n  function d3_geom_quadtreeVisit(f, node, x1, y1, x2, y2) {\n    if (!f(node, x1, y1, x2, y2)) {\n      var sx = (x1 + x2) * .5, sy = (y1 + y2) * .5, children = node.nodes;\n      if (children[0]) d3_geom_quadtreeVisit(f, children[0], x1, y1, sx, sy);\n      if (children[1]) d3_geom_quadtreeVisit(f, children[1], sx, y1, x2, sy);\n      if (children[2]) d3_geom_quadtreeVisit(f, children[2], x1, sy, sx, y2);\n      if (children[3]) d3_geom_quadtreeVisit(f, children[3], sx, sy, x2, y2);\n    }\n  }\n  d3.interpolateRgb = d3_interpolateRgb;\n  function d3_interpolateRgb(a, b) {\n    a = d3.rgb(a);\n    b = d3.rgb(b);\n    var ar = a.r, ag = a.g, ab = a.b, br = b.r - ar, bg = b.g - ag, bb = b.b - ab;\n    return function(t) {\n      return \"#\" + d3_rgb_hex(Math.round(ar + br * t)) + d3_rgb_hex(Math.round(ag + bg * t)) + d3_rgb_hex(Math.round(ab + bb * t));\n    };\n  }\n  d3.transform = function(string) {\n    var g = d3_document.createElementNS(d3.ns.prefix.svg, \"g\");\n    return (d3.transform = function(string) {\n      g.setAttribute(\"transform\", string);\n      var t = g.transform.baseVal.consolidate();\n      return new d3_transform(t ? t.matrix : d3_transformIdentity);\n    })(string);\n  };\n  function d3_transform(m) {\n    var r0 = [ m.a, m.b ], r1 = [ m.c, m.d ], kx = d3_transformNormalize(r0), kz = d3_transformDot(r0, r1), ky = d3_transformNormalize(d3_transformCombine(r1, r0, -kz)) || 0;\n    if (r0[0] * r1[1] < r1[0] * r0[1]) {\n      r0[0] *= -1;\n      r0[1] *= -1;\n      kx *= -1;\n      kz *= -1;\n    }\n    this.rotate = (kx ? Math.atan2(r0[1], r0[0]) : Math.atan2(-r1[0], r1[1])) * d3_degrees;\n    this.translate = [ m.e, m.f ];\n    this.scale = [ kx, ky ];\n    this.skew = ky ? Math.atan2(kz, ky) * d3_degrees : 0;\n  }\n  d3_transform.prototype.toString = function() {\n    return \"translate(\" + this.translate + \")rotate(\" + this.rotate + \")skewX(\" + this.skew + \")scale(\" + this.scale + \")\";\n  };\n  function d3_transformDot(a, b) {\n    return a[0] * b[0] + a[1] * b[1];\n  }\n  function d3_transformNormalize(a) {\n    var k = Math.sqrt(d3_transformDot(a, a));\n    if (k) {\n      a[0] /= k;\n      a[1] /= k;\n    }\n    return k;\n  }\n  function d3_transformCombine(a, b, k) {\n    a[0] += k * b[0];\n    a[1] += k * b[1];\n    return a;\n  }\n  var d3_transformIdentity = {\n    a: 1,\n    b: 0,\n    c: 0,\n    d: 1,\n    e: 0,\n    f: 0\n  };\n  d3.interpolateNumber = d3_interpolateNumber;\n  function d3_interpolateNumber(a, b) {\n    b -= a;\n    return function(t) {\n      return a + b * t;\n    };\n  }\n  d3.interpolateTransform = d3_interpolateTransform;\n  function d3_interpolateTransform(a, b) {\n    var s = [], q = [], n, A = d3.transform(a), B = d3.transform(b), ta = A.translate, tb = B.translate, ra = A.rotate, rb = B.rotate, wa = A.skew, wb = B.skew, ka = A.scale, kb = B.scale;\n    if (ta[0] != tb[0] || ta[1] != tb[1]) {\n      s.push(\"translate(\", null, \",\", null, \")\");\n      q.push({\n        i: 1,\n        x: d3_interpolateNumber(ta[0], tb[0])\n      }, {\n        i: 3,\n        x: d3_interpolateNumber(ta[1], tb[1])\n      });\n    } else if (tb[0] || tb[1]) {\n      s.push(\"translate(\" + tb + \")\");\n    } else {\n      s.push(\"\");\n    }\n    if (ra != rb) {\n      if (ra - rb > 180) rb += 360; else if (rb - ra > 180) ra += 360;\n      q.push({\n        i: s.push(s.pop() + \"rotate(\", null, \")\") - 2,\n        x: d3_interpolateNumber(ra, rb)\n      });\n    } else if (rb) {\n      s.push(s.pop() + \"rotate(\" + rb + \")\");\n    }\n    if (wa != wb) {\n      q.push({\n        i: s.push(s.pop() + \"skewX(\", null, \")\") - 2,\n        x: d3_interpolateNumber(wa, wb)\n      });\n    } else if (wb) {\n      s.push(s.pop() + \"skewX(\" + wb + \")\");\n    }\n    if (ka[0] != kb[0] || ka[1] != kb[1]) {\n      n = s.push(s.pop() + \"scale(\", null, \",\", null, \")\");\n      q.push({\n        i: n - 4,\n        x: d3_interpolateNumber(ka[0], kb[0])\n      }, {\n        i: n - 2,\n        x: d3_interpolateNumber(ka[1], kb[1])\n      });\n    } else if (kb[0] != 1 || kb[1] != 1) {\n      s.push(s.pop() + \"scale(\" + kb + \")\");\n    }\n    n = q.length;\n    return function(t) {\n      var i = -1, o;\n      while (++i < n) s[(o = q[i]).i] = o.x(t);\n      return s.join(\"\");\n    };\n  }\n  d3.interpolateObject = d3_interpolateObject;\n  function d3_interpolateObject(a, b) {\n    var i = {}, c = {}, k;\n    for (k in a) {\n      if (k in b) {\n        i[k] = d3_interpolateByName(k)(a[k], b[k]);\n      } else {\n        c[k] = a[k];\n      }\n    }\n    for (k in b) {\n      if (!(k in a)) {\n        c[k] = b[k];\n      }\n    }\n    return function(t) {\n      for (k in i) c[k] = i[k](t);\n      return c;\n    };\n  }\n  d3.interpolateString = d3_interpolateString;\n  function d3_interpolateString(a, b) {\n    var m, i, j, s0 = 0, s1 = 0, s = [], q = [], n, o;\n    d3_interpolate_number.lastIndex = 0;\n    for (i = 0; m = d3_interpolate_number.exec(b); ++i) {\n      if (m.index) s.push(b.substring(s0, s1 = m.index));\n      q.push({\n        i: s.length,\n        x: m[0]\n      });\n      s.push(null);\n      s0 = d3_interpolate_number.lastIndex;\n    }\n    if (s0 < b.length) s.push(b.substring(s0));\n    for (i = 0, n = q.length; (m = d3_interpolate_number.exec(a)) && i < n; ++i) {\n      o = q[i];\n      if (o.x == m[0]) {\n        if (o.i) {\n          if (s[o.i + 1] == null) {\n            s[o.i - 1] += o.x;\n            s.splice(o.i, 1);\n            for (j = i + 1; j < n; ++j) q[j].i--;\n          } else {\n            s[o.i - 1] += o.x + s[o.i + 1];\n            s.splice(o.i, 2);\n            for (j = i + 1; j < n; ++j) q[j].i -= 2;\n          }\n        } else {\n          if (s[o.i + 1] == null) {\n            s[o.i] = o.x;\n          } else {\n            s[o.i] = o.x + s[o.i + 1];\n            s.splice(o.i + 1, 1);\n            for (j = i + 1; j < n; ++j) q[j].i--;\n          }\n        }\n        q.splice(i, 1);\n        n--;\n        i--;\n      } else {\n        o.x = d3_interpolateNumber(parseFloat(m[0]), parseFloat(o.x));\n      }\n    }\n    while (i < n) {\n      o = q.pop();\n      if (s[o.i + 1] == null) {\n        s[o.i] = o.x;\n      } else {\n        s[o.i] = o.x + s[o.i + 1];\n        s.splice(o.i + 1, 1);\n      }\n      n--;\n    }\n    if (s.length === 1) {\n      return s[0] == null ? q[0].x : function() {\n        return b;\n      };\n    }\n    return function(t) {\n      for (i = 0; i < n; ++i) s[(o = q[i]).i] = o.x(t);\n      return s.join(\"\");\n    };\n  }\n  var d3_interpolate_number = /[-+]?(?:\\d+\\.?\\d*|\\.?\\d+)(?:[eE][-+]?\\d+)?/g;\n  d3.interpolate = d3_interpolate;\n  function d3_interpolate(a, b) {\n    var i = d3.interpolators.length, f;\n    while (--i >= 0 && !(f = d3.interpolators[i](a, b))) ;\n    return f;\n  }\n  function d3_interpolateByName(name) {\n    return name == \"transform\" ? d3_interpolateTransform : d3_interpolate;\n  }\n  d3.interpolators = [ d3_interpolateObject, function(a, b) {\n    return Array.isArray(b) && d3_interpolateArray(a, b);\n  }, function(a, b) {\n    return (typeof a === \"string\" || typeof b === \"string\") && d3_interpolateString(a + \"\", b + \"\");\n  }, function(a, b) {\n    return (typeof b === \"string\" ? d3_rgb_names.has(b) || /^(#|rgb\\(|hsl\\()/.test(b) : b instanceof d3_Color) && d3_interpolateRgb(a, b);\n  }, function(a, b) {\n    return !isNaN(a = +a) && !isNaN(b = +b) && d3_interpolateNumber(a, b);\n  } ];\n  d3.interpolateArray = d3_interpolateArray;\n  function d3_interpolateArray(a, b) {\n    var x = [], c = [], na = a.length, nb = b.length, n0 = Math.min(a.length, b.length), i;\n    for (i = 0; i < n0; ++i) x.push(d3_interpolate(a[i], b[i]));\n    for (;i < na; ++i) c[i] = a[i];\n    for (;i < nb; ++i) c[i] = b[i];\n    return function(t) {\n      for (i = 0; i < n0; ++i) c[i] = x[i](t);\n      return c;\n    };\n  }\n  var d3_ease_default = function() {\n    return d3_identity;\n  };\n  var d3_ease = d3.map({\n    linear: d3_ease_default,\n    poly: d3_ease_poly,\n    quad: function() {\n      return d3_ease_quad;\n    },\n    cubic: function() {\n      return d3_ease_cubic;\n    },\n    sin: function() {\n      return d3_ease_sin;\n    },\n    exp: function() {\n      return d3_ease_exp;\n    },\n    circle: function() {\n      return d3_ease_circle;\n    },\n    elastic: d3_ease_elastic,\n    back: d3_ease_back,\n    bounce: function() {\n      return d3_ease_bounce;\n    }\n  });\n  var d3_ease_mode = d3.map({\n    \"in\": d3_identity,\n    out: d3_ease_reverse,\n    \"in-out\": d3_ease_reflect,\n    \"out-in\": function(f) {\n      return d3_ease_reflect(d3_ease_reverse(f));\n    }\n  });\n  d3.ease = function(name) {\n    var i = name.indexOf(\"-\"), t = i >= 0 ? name.substring(0, i) : name, m = i >= 0 ? name.substring(i + 1) : \"in\";\n    t = d3_ease.get(t) || d3_ease_default;\n    m = d3_ease_mode.get(m) || d3_identity;\n    return d3_ease_clamp(m(t.apply(null, Array.prototype.slice.call(arguments, 1))));\n  };\n  function d3_ease_clamp(f) {\n    return function(t) {\n      return t <= 0 ? 0 : t >= 1 ? 1 : f(t);\n    };\n  }\n  function d3_ease_reverse(f) {\n    return function(t) {\n      return 1 - f(1 - t);\n    };\n  }\n  function d3_ease_reflect(f) {\n    return function(t) {\n      return .5 * (t < .5 ? f(2 * t) : 2 - f(2 - 2 * t));\n    };\n  }\n  function d3_ease_quad(t) {\n    return t * t;\n  }\n  function d3_ease_cubic(t) {\n    return t * t * t;\n  }\n  function d3_ease_cubicInOut(t) {\n    if (t <= 0) return 0;\n    if (t >= 1) return 1;\n    var t2 = t * t, t3 = t2 * t;\n    return 4 * (t < .5 ? t3 : 3 * (t - t2) + t3 - .75);\n  }\n  function d3_ease_poly(e) {\n    return function(t) {\n      return Math.pow(t, e);\n    };\n  }\n  function d3_ease_sin(t) {\n    return 1 - Math.cos(t * π / 2);\n  }\n  function d3_ease_exp(t) {\n    return Math.pow(2, 10 * (t - 1));\n  }\n  function d3_ease_circle(t) {\n    return 1 - Math.sqrt(1 - t * t);\n  }\n  function d3_ease_elastic(a, p) {\n    var s;\n    if (arguments.length < 2) p = .45;\n    if (arguments.length) s = p / (2 * π) * Math.asin(1 / a); else a = 1, s = p / 4;\n    return function(t) {\n      return 1 + a * Math.pow(2, 10 * -t) * Math.sin((t - s) * 2 * π / p);\n    };\n  }\n  function d3_ease_back(s) {\n    if (!s) s = 1.70158;\n    return function(t) {\n      return t * t * ((s + 1) * t - s);\n    };\n  }\n  function d3_ease_bounce(t) {\n    return t < 1 / 2.75 ? 7.5625 * t * t : t < 2 / 2.75 ? 7.5625 * (t -= 1.5 / 2.75) * t + .75 : t < 2.5 / 2.75 ? 7.5625 * (t -= 2.25 / 2.75) * t + .9375 : 7.5625 * (t -= 2.625 / 2.75) * t + .984375;\n  }\n  d3.interpolateHcl = d3_interpolateHcl;\n  function d3_interpolateHcl(a, b) {\n    a = d3.hcl(a);\n    b = d3.hcl(b);\n    var ah = a.h, ac = a.c, al = a.l, bh = b.h - ah, bc = b.c - ac, bl = b.l - al;\n    if (bh > 180) bh -= 360; else if (bh < -180) bh += 360;\n    return function(t) {\n      return d3_hcl_lab(ah + bh * t, ac + bc * t, al + bl * t) + \"\";\n    };\n  }\n  d3.interpolateHsl = d3_interpolateHsl;\n  function d3_interpolateHsl(a, b) {\n    a = d3.hsl(a);\n    b = d3.hsl(b);\n    var h0 = a.h, s0 = a.s, l0 = a.l, h1 = b.h - h0, s1 = b.s - s0, l1 = b.l - l0;\n    if (h1 > 180) h1 -= 360; else if (h1 < -180) h1 += 360;\n    return function(t) {\n      return d3_hsl_rgb(h0 + h1 * t, s0 + s1 * t, l0 + l1 * t) + \"\";\n    };\n  }\n  d3.interpolateLab = d3_interpolateLab;\n  function d3_interpolateLab(a, b) {\n    a = d3.lab(a);\n    b = d3.lab(b);\n    var al = a.l, aa = a.a, ab = a.b, bl = b.l - al, ba = b.a - aa, bb = b.b - ab;\n    return function(t) {\n      return d3_lab_rgb(al + bl * t, aa + ba * t, ab + bb * t) + \"\";\n    };\n  }\n  d3.interpolateRound = d3_interpolateRound;\n  function d3_interpolateRound(a, b) {\n    b -= a;\n    return function(t) {\n      return Math.round(a + b * t);\n    };\n  }\n  function d3_uninterpolateNumber(a, b) {\n    b = b - (a = +a) ? 1 / (b - a) : 0;\n    return function(x) {\n      return (x - a) * b;\n    };\n  }\n  function d3_uninterpolateClamp(a, b) {\n    b = b - (a = +a) ? 1 / (b - a) : 0;\n    return function(x) {\n      return Math.max(0, Math.min(1, (x - a) * b));\n    };\n  }\n  d3.layout = {};\n  d3.layout.bundle = function() {\n    return function(links) {\n      var paths = [], i = -1, n = links.length;\n      while (++i < n) paths.push(d3_layout_bundlePath(links[i]));\n      return paths;\n    };\n  };\n  function d3_layout_bundlePath(link) {\n    var start = link.source, end = link.target, lca = d3_layout_bundleLeastCommonAncestor(start, end), points = [ start ];\n    while (start !== lca) {\n      start = start.parent;\n      points.push(start);\n    }\n    var k = points.length;\n    while (end !== lca) {\n      points.splice(k, 0, end);\n      end = end.parent;\n    }\n    return points;\n  }\n  function d3_layout_bundleAncestors(node) {\n    var ancestors = [], parent = node.parent;\n    while (parent != null) {\n      ancestors.push(node);\n      node = parent;\n      parent = parent.parent;\n    }\n    ancestors.push(node);\n    return ancestors;\n  }\n  function d3_layout_bundleLeastCommonAncestor(a, b) {\n    if (a === b) return a;\n    var aNodes = d3_layout_bundleAncestors(a), bNodes = d3_layout_bundleAncestors(b), aNode = aNodes.pop(), bNode = bNodes.pop(), sharedNode = null;\n    while (aNode === bNode) {\n      sharedNode = aNode;\n      aNode = aNodes.pop();\n      bNode = bNodes.pop();\n    }\n    return sharedNode;\n  }\n  d3.layout.chord = function() {\n    var chord = {}, chords, groups, matrix, n, padding = 0, sortGroups, sortSubgroups, sortChords;\n    function relayout() {\n      var subgroups = {}, groupSums = [], groupIndex = d3.range(n), subgroupIndex = [], k, x, x0, i, j;\n      chords = [];\n      groups = [];\n      k = 0, i = -1;\n      while (++i < n) {\n        x = 0, j = -1;\n        while (++j < n) {\n          x += matrix[i][j];\n        }\n        groupSums.push(x);\n        subgroupIndex.push(d3.range(n));\n        k += x;\n      }\n      if (sortGroups) {\n        groupIndex.sort(function(a, b) {\n          return sortGroups(groupSums[a], groupSums[b]);\n        });\n      }\n      if (sortSubgroups) {\n        subgroupIndex.forEach(function(d, i) {\n          d.sort(function(a, b) {\n            return sortSubgroups(matrix[i][a], matrix[i][b]);\n          });\n        });\n      }\n      k = (2 * π - padding * n) / k;\n      x = 0, i = -1;\n      while (++i < n) {\n        x0 = x, j = -1;\n        while (++j < n) {\n          var di = groupIndex[i], dj = subgroupIndex[di][j], v = matrix[di][dj], a0 = x, a1 = x += v * k;\n          subgroups[di + \"-\" + dj] = {\n            index: di,\n            subindex: dj,\n            startAngle: a0,\n            endAngle: a1,\n            value: v\n          };\n        }\n        groups[di] = {\n          index: di,\n          startAngle: x0,\n          endAngle: x,\n          value: (x - x0) / k\n        };\n        x += padding;\n      }\n      i = -1;\n      while (++i < n) {\n        j = i - 1;\n        while (++j < n) {\n          var source = subgroups[i + \"-\" + j], target = subgroups[j + \"-\" + i];\n          if (source.value || target.value) {\n            chords.push(source.value < target.value ? {\n              source: target,\n              target: source\n            } : {\n              source: source,\n              target: target\n            });\n          }\n        }\n      }\n      if (sortChords) resort();\n    }\n    function resort() {\n      chords.sort(function(a, b) {\n        return sortChords((a.source.value + a.target.value) / 2, (b.source.value + b.target.value) / 2);\n      });\n    }\n    chord.matrix = function(x) {\n      if (!arguments.length) return matrix;\n      n = (matrix = x) && matrix.length;\n      chords = groups = null;\n      return chord;\n    };\n    chord.padding = function(x) {\n      if (!arguments.length) return padding;\n      padding = x;\n      chords = groups = null;\n      return chord;\n    };\n    chord.sortGroups = function(x) {\n      if (!arguments.length) return sortGroups;\n      sortGroups = x;\n      chords = groups = null;\n      return chord;\n    };\n    chord.sortSubgroups = function(x) {\n      if (!arguments.length) return sortSubgroups;\n      sortSubgroups = x;\n      chords = null;\n      return chord;\n    };\n    chord.sortChords = function(x) {\n      if (!arguments.length) return sortChords;\n      sortChords = x;\n      if (chords) resort();\n      return chord;\n    };\n    chord.chords = function() {\n      if (!chords) relayout();\n      return chords;\n    };\n    chord.groups = function() {\n      if (!groups) relayout();\n      return groups;\n    };\n    return chord;\n  };\n  d3.layout.force = function() {\n    var force = {}, event = d3.dispatch(\"start\", \"tick\", \"end\"), size = [ 1, 1 ], drag, alpha, friction = .9, linkDistance = d3_layout_forceLinkDistance, linkStrength = d3_layout_forceLinkStrength, charge = -30, gravity = .1, theta = .8, nodes = [], links = [], distances, strengths, charges;\n    function repulse(node) {\n      return function(quad, x1, _, x2) {\n        if (quad.point !== node) {\n          var dx = quad.cx - node.x, dy = quad.cy - node.y, dn = 1 / Math.sqrt(dx * dx + dy * dy);\n          if ((x2 - x1) * dn < theta) {\n            var k = quad.charge * dn * dn;\n            node.px -= dx * k;\n            node.py -= dy * k;\n            return true;\n          }\n          if (quad.point && isFinite(dn)) {\n            var k = quad.pointCharge * dn * dn;\n            node.px -= dx * k;\n            node.py -= dy * k;\n          }\n        }\n        return !quad.charge;\n      };\n    }\n    force.tick = function() {\n      if ((alpha *= .99) < .005) {\n        event.end({\n          type: \"end\",\n          alpha: alpha = 0\n        });\n        return true;\n      }\n      var n = nodes.length, m = links.length, q, i, o, s, t, l, k, x, y;\n      for (i = 0; i < m; ++i) {\n        o = links[i];\n        s = o.source;\n        t = o.target;\n        x = t.x - s.x;\n        y = t.y - s.y;\n        if (l = x * x + y * y) {\n          l = alpha * strengths[i] * ((l = Math.sqrt(l)) - distances[i]) / l;\n          x *= l;\n          y *= l;\n          t.x -= x * (k = s.weight / (t.weight + s.weight));\n          t.y -= y * k;\n          s.x += x * (k = 1 - k);\n          s.y += y * k;\n        }\n      }\n      if (k = alpha * gravity) {\n        x = size[0] / 2;\n        y = size[1] / 2;\n        i = -1;\n        if (k) while (++i < n) {\n          o = nodes[i];\n          o.x += (x - o.x) * k;\n          o.y += (y - o.y) * k;\n        }\n      }\n      if (charge) {\n        d3_layout_forceAccumulate(q = d3.geom.quadtree(nodes), alpha, charges);\n        i = -1;\n        while (++i < n) {\n          if (!(o = nodes[i]).fixed) {\n            q.visit(repulse(o));\n          }\n        }\n      }\n      i = -1;\n      while (++i < n) {\n        o = nodes[i];\n        if (o.fixed) {\n          o.x = o.px;\n          o.y = o.py;\n        } else {\n          o.x -= (o.px - (o.px = o.x)) * friction;\n          o.y -= (o.py - (o.py = o.y)) * friction;\n        }\n      }\n      event.tick({\n        type: \"tick\",\n        alpha: alpha\n      });\n    };\n    force.nodes = function(x) {\n      if (!arguments.length) return nodes;\n      nodes = x;\n      return force;\n    };\n    force.links = function(x) {\n      if (!arguments.length) return links;\n      links = x;\n      return force;\n    };\n    force.size = function(x) {\n      if (!arguments.length) return size;\n      size = x;\n      return force;\n    };\n    force.linkDistance = function(x) {\n      if (!arguments.length) return linkDistance;\n      linkDistance = typeof x === \"function\" ? x : +x;\n      return force;\n    };\n    force.distance = force.linkDistance;\n    force.linkStrength = function(x) {\n      if (!arguments.length) return linkStrength;\n      linkStrength = typeof x === \"function\" ? x : +x;\n      return force;\n    };\n    force.friction = function(x) {\n      if (!arguments.length) return friction;\n      friction = +x;\n      return force;\n    };\n    force.charge = function(x) {\n      if (!arguments.length) return charge;\n      charge = typeof x === \"function\" ? x : +x;\n      return force;\n    };\n    force.gravity = function(x) {\n      if (!arguments.length) return gravity;\n      gravity = +x;\n      return force;\n    };\n    force.theta = function(x) {\n      if (!arguments.length) return theta;\n      theta = +x;\n      return force;\n    };\n    force.alpha = function(x) {\n      if (!arguments.length) return alpha;\n      x = +x;\n      if (alpha) {\n        if (x > 0) alpha = x; else alpha = 0;\n      } else if (x > 0) {\n        event.start({\n          type: \"start\",\n          alpha: alpha = x\n        });\n        d3.timer(force.tick);\n      }\n      return force;\n    };\n    force.start = function() {\n      var i, j, n = nodes.length, m = links.length, w = size[0], h = size[1], neighbors, o;\n      for (i = 0; i < n; ++i) {\n        (o = nodes[i]).index = i;\n        o.weight = 0;\n      }\n      for (i = 0; i < m; ++i) {\n        o = links[i];\n        if (typeof o.source == \"number\") o.source = nodes[o.source];\n        if (typeof o.target == \"number\") o.target = nodes[o.target];\n        ++o.source.weight;\n        ++o.target.weight;\n      }\n      for (i = 0; i < n; ++i) {\n        o = nodes[i];\n        if (isNaN(o.x)) o.x = position(\"x\", w);\n        if (isNaN(o.y)) o.y = position(\"y\", h);\n        if (isNaN(o.px)) o.px = o.x;\n        if (isNaN(o.py)) o.py = o.y;\n      }\n      distances = [];\n      if (typeof linkDistance === \"function\") for (i = 0; i < m; ++i) distances[i] = +linkDistance.call(this, links[i], i); else for (i = 0; i < m; ++i) distances[i] = linkDistance;\n      strengths = [];\n      if (typeof linkStrength === \"function\") for (i = 0; i < m; ++i) strengths[i] = +linkStrength.call(this, links[i], i); else for (i = 0; i < m; ++i) strengths[i] = linkStrength;\n      charges = [];\n      if (typeof charge === \"function\") for (i = 0; i < n; ++i) charges[i] = +charge.call(this, nodes[i], i); else for (i = 0; i < n; ++i) charges[i] = charge;\n      function position(dimension, size) {\n        var neighbors = neighbor(i), j = -1, m = neighbors.length, x;\n        while (++j < m) if (!isNaN(x = neighbors[j][dimension])) return x;\n        return Math.random() * size;\n      }\n      function neighbor() {\n        if (!neighbors) {\n          neighbors = [];\n          for (j = 0; j < n; ++j) {\n            neighbors[j] = [];\n          }\n          for (j = 0; j < m; ++j) {\n            var o = links[j];\n            neighbors[o.source.index].push(o.target);\n            neighbors[o.target.index].push(o.source);\n          }\n        }\n        return neighbors[i];\n      }\n      return force.resume();\n    };\n    force.resume = function() {\n      return force.alpha(.1);\n    };\n    force.stop = function() {\n      return force.alpha(0);\n    };\n    force.drag = function() {\n      if (!drag) drag = d3.behavior.drag().origin(d3_identity).on(\"dragstart.force\", d3_layout_forceDragstart).on(\"drag.force\", dragmove).on(\"dragend.force\", d3_layout_forceDragend);\n      if (!arguments.length) return drag;\n      this.on(\"mouseover.force\", d3_layout_forceMouseover).on(\"mouseout.force\", d3_layout_forceMouseout).call(drag);\n    };\n    function dragmove(d) {\n      d.px = d3.event.x, d.py = d3.event.y;\n      force.resume();\n    }\n    return d3.rebind(force, event, \"on\");\n  };\n  function d3_layout_forceDragstart(d) {\n    d.fixed |= 2;\n  }\n  function d3_layout_forceDragend(d) {\n    d.fixed &= ~6;\n  }\n  function d3_layout_forceMouseover(d) {\n    d.fixed |= 4;\n    d.px = d.x, d.py = d.y;\n  }\n  function d3_layout_forceMouseout(d) {\n    d.fixed &= ~4;\n  }\n  function d3_layout_forceAccumulate(quad, alpha, charges) {\n    var cx = 0, cy = 0;\n    quad.charge = 0;\n    if (!quad.leaf) {\n      var nodes = quad.nodes, n = nodes.length, i = -1, c;\n      while (++i < n) {\n        c = nodes[i];\n        if (c == null) continue;\n        d3_layout_forceAccumulate(c, alpha, charges);\n        quad.charge += c.charge;\n        cx += c.charge * c.cx;\n        cy += c.charge * c.cy;\n      }\n    }\n    if (quad.point) {\n      if (!quad.leaf) {\n        quad.point.x += Math.random() - .5;\n        quad.point.y += Math.random() - .5;\n      }\n      var k = alpha * charges[quad.point.index];\n      quad.charge += quad.pointCharge = k;\n      cx += k * quad.point.x;\n      cy += k * quad.point.y;\n    }\n    quad.cx = cx / quad.charge;\n    quad.cy = cy / quad.charge;\n  }\n  var d3_layout_forceLinkDistance = 20, d3_layout_forceLinkStrength = 1;\n  d3.layout.hierarchy = function() {\n    var sort = d3_layout_hierarchySort, children = d3_layout_hierarchyChildren, value = d3_layout_hierarchyValue;\n    function recurse(node, depth, nodes) {\n      var childs = children.call(hierarchy, node, depth);\n      node.depth = depth;\n      nodes.push(node);\n      if (childs && (n = childs.length)) {\n        var i = -1, n, c = node.children = [], v = 0, j = depth + 1, d;\n        while (++i < n) {\n          d = recurse(childs[i], j, nodes);\n          d.parent = node;\n          c.push(d);\n          v += d.value;\n        }\n        if (sort) c.sort(sort);\n        if (value) node.value = v;\n      } else if (value) {\n        node.value = +value.call(hierarchy, node, depth) || 0;\n      }\n      return node;\n    }\n    function revalue(node, depth) {\n      var children = node.children, v = 0;\n      if (children && (n = children.length)) {\n        var i = -1, n, j = depth + 1;\n        while (++i < n) v += revalue(children[i], j);\n      } else if (value) {\n        v = +value.call(hierarchy, node, depth) || 0;\n      }\n      if (value) node.value = v;\n      return v;\n    }\n    function hierarchy(d) {\n      var nodes = [];\n      recurse(d, 0, nodes);\n      return nodes;\n    }\n    hierarchy.sort = function(x) {\n      if (!arguments.length) return sort;\n      sort = x;\n      return hierarchy;\n    };\n    hierarchy.children = function(x) {\n      if (!arguments.length) return children;\n      children = x;\n      return hierarchy;\n    };\n    hierarchy.value = function(x) {\n      if (!arguments.length) return value;\n      value = x;\n      return hierarchy;\n    };\n    hierarchy.revalue = function(root) {\n      revalue(root, 0);\n      return root;\n    };\n    return hierarchy;\n  };\n  function d3_layout_hierarchyRebind(object, hierarchy) {\n    d3.rebind(object, hierarchy, \"sort\", \"children\", \"value\");\n    object.nodes = object;\n    object.links = d3_layout_hierarchyLinks;\n    return object;\n  }\n  function d3_layout_hierarchyChildren(d) {\n    return d.children;\n  }\n  function d3_layout_hierarchyValue(d) {\n    return d.value;\n  }\n  function d3_layout_hierarchySort(a, b) {\n    return b.value - a.value;\n  }\n  function d3_layout_hierarchyLinks(nodes) {\n    return d3.merge(nodes.map(function(parent) {\n      return (parent.children || []).map(function(child) {\n        return {\n          source: parent,\n          target: child\n        };\n      });\n    }));\n  }\n  d3.layout.partition = function() {\n    var hierarchy = d3.layout.hierarchy(), size = [ 1, 1 ];\n    function position(node, x, dx, dy) {\n      var children = node.children;\n      node.x = x;\n      node.y = node.depth * dy;\n      node.dx = dx;\n      node.dy = dy;\n      if (children && (n = children.length)) {\n        var i = -1, n, c, d;\n        dx = node.value ? dx / node.value : 0;\n        while (++i < n) {\n          position(c = children[i], x, d = c.value * dx, dy);\n          x += d;\n        }\n      }\n    }\n    function depth(node) {\n      var children = node.children, d = 0;\n      if (children && (n = children.length)) {\n        var i = -1, n;\n        while (++i < n) d = Math.max(d, depth(children[i]));\n      }\n      return 1 + d;\n    }\n    function partition(d, i) {\n      var nodes = hierarchy.call(this, d, i);\n      position(nodes[0], 0, size[0], size[1] / depth(nodes[0]));\n      return nodes;\n    }\n    partition.size = function(x) {\n      if (!arguments.length) return size;\n      size = x;\n      return partition;\n    };\n    return d3_layout_hierarchyRebind(partition, hierarchy);\n  };\n  d3.layout.pie = function() {\n    var value = Number, sort = d3_layout_pieSortByValue, startAngle = 0, endAngle = 2 * π;\n    function pie(data) {\n      var values = data.map(function(d, i) {\n        return +value.call(pie, d, i);\n      });\n      var a = +(typeof startAngle === \"function\" ? startAngle.apply(this, arguments) : startAngle);\n      var k = ((typeof endAngle === \"function\" ? endAngle.apply(this, arguments) : endAngle) - a) / d3.sum(values);\n      var index = d3.range(data.length);\n      if (sort != null) index.sort(sort === d3_layout_pieSortByValue ? function(i, j) {\n        return values[j] - values[i];\n      } : function(i, j) {\n        return sort(data[i], data[j]);\n      });\n      var arcs = [];\n      index.forEach(function(i) {\n        var d;\n        arcs[i] = {\n          data: data[i],\n          value: d = values[i],\n          startAngle: a,\n          endAngle: a += d * k\n        };\n      });\n      return arcs;\n    }\n    pie.value = function(x) {\n      if (!arguments.length) return value;\n      value = x;\n      return pie;\n    };\n    pie.sort = function(x) {\n      if (!arguments.length) return sort;\n      sort = x;\n      return pie;\n    };\n    pie.startAngle = function(x) {\n      if (!arguments.length) return startAngle;\n      startAngle = x;\n      return pie;\n    };\n    pie.endAngle = function(x) {\n      if (!arguments.length) return endAngle;\n      endAngle = x;\n      return pie;\n    };\n    return pie;\n  };\n  var d3_layout_pieSortByValue = {};\n  d3.layout.stack = function() {\n    var values = d3_identity, order = d3_layout_stackOrderDefault, offset = d3_layout_stackOffsetZero, out = d3_layout_stackOut, x = d3_layout_stackX, y = d3_layout_stackY;\n    function stack(data, index) {\n      var series = data.map(function(d, i) {\n        return values.call(stack, d, i);\n      });\n      var points = series.map(function(d) {\n        return d.map(function(v, i) {\n          return [ x.call(stack, v, i), y.call(stack, v, i) ];\n        });\n      });\n      var orders = order.call(stack, points, index);\n      series = d3.permute(series, orders);\n      points = d3.permute(points, orders);\n      var offsets = offset.call(stack, points, index);\n      var n = series.length, m = series[0].length, i, j, o;\n      for (j = 0; j < m; ++j) {\n        out.call(stack, series[0][j], o = offsets[j], points[0][j][1]);\n        for (i = 1; i < n; ++i) {\n          out.call(stack, series[i][j], o += points[i - 1][j][1], points[i][j][1]);\n        }\n      }\n      return data;\n    }\n    stack.values = function(x) {\n      if (!arguments.length) return values;\n      values = x;\n      return stack;\n    };\n    stack.order = function(x) {\n      if (!arguments.length) return order;\n      order = typeof x === \"function\" ? x : d3_layout_stackOrders.get(x) || d3_layout_stackOrderDefault;\n      return stack;\n    };\n    stack.offset = function(x) {\n      if (!arguments.length) return offset;\n      offset = typeof x === \"function\" ? x : d3_layout_stackOffsets.get(x) || d3_layout_stackOffsetZero;\n      return stack;\n    };\n    stack.x = function(z) {\n      if (!arguments.length) return x;\n      x = z;\n      return stack;\n    };\n    stack.y = function(z) {\n      if (!arguments.length) return y;\n      y = z;\n      return stack;\n    };\n    stack.out = function(z) {\n      if (!arguments.length) return out;\n      out = z;\n      return stack;\n    };\n    return stack;\n  };\n  function d3_layout_stackX(d) {\n    return d.x;\n  }\n  function d3_layout_stackY(d) {\n    return d.y;\n  }\n  function d3_layout_stackOut(d, y0, y) {\n    d.y0 = y0;\n    d.y = y;\n  }\n  var d3_layout_stackOrders = d3.map({\n    \"inside-out\": function(data) {\n      var n = data.length, i, j, max = data.map(d3_layout_stackMaxIndex), sums = data.map(d3_layout_stackReduceSum), index = d3.range(n).sort(function(a, b) {\n        return max[a] - max[b];\n      }), top = 0, bottom = 0, tops = [], bottoms = [];\n      for (i = 0; i < n; ++i) {\n        j = index[i];\n        if (top < bottom) {\n          top += sums[j];\n          tops.push(j);\n        } else {\n          bottom += sums[j];\n          bottoms.push(j);\n        }\n      }\n      return bottoms.reverse().concat(tops);\n    },\n    reverse: function(data) {\n      return d3.range(data.length).reverse();\n    },\n    \"default\": d3_layout_stackOrderDefault\n  });\n  var d3_layout_stackOffsets = d3.map({\n    silhouette: function(data) {\n      var n = data.length, m = data[0].length, sums = [], max = 0, i, j, o, y0 = [];\n      for (j = 0; j < m; ++j) {\n        for (i = 0, o = 0; i < n; i++) o += data[i][j][1];\n        if (o > max) max = o;\n        sums.push(o);\n      }\n      for (j = 0; j < m; ++j) {\n        y0[j] = (max - sums[j]) / 2;\n      }\n      return y0;\n    },\n    wiggle: function(data) {\n      var n = data.length, x = data[0], m = x.length, i, j, k, s1, s2, s3, dx, o, o0, y0 = [];\n      y0[0] = o = o0 = 0;\n      for (j = 1; j < m; ++j) {\n        for (i = 0, s1 = 0; i < n; ++i) s1 += data[i][j][1];\n        for (i = 0, s2 = 0, dx = x[j][0] - x[j - 1][0]; i < n; ++i) {\n          for (k = 0, s3 = (data[i][j][1] - data[i][j - 1][1]) / (2 * dx); k < i; ++k) {\n            s3 += (data[k][j][1] - data[k][j - 1][1]) / dx;\n          }\n          s2 += s3 * data[i][j][1];\n        }\n        y0[j] = o -= s1 ? s2 / s1 * dx : 0;\n        if (o < o0) o0 = o;\n      }\n      for (j = 0; j < m; ++j) y0[j] -= o0;\n      return y0;\n    },\n    expand: function(data) {\n      var n = data.length, m = data[0].length, k = 1 / n, i, j, o, y0 = [];\n      for (j = 0; j < m; ++j) {\n        for (i = 0, o = 0; i < n; i++) o += data[i][j][1];\n        if (o) for (i = 0; i < n; i++) data[i][j][1] /= o; else for (i = 0; i < n; i++) data[i][j][1] = k;\n      }\n      for (j = 0; j < m; ++j) y0[j] = 0;\n      return y0;\n    },\n    zero: d3_layout_stackOffsetZero\n  });\n  function d3_layout_stackOrderDefault(data) {\n    return d3.range(data.length);\n  }\n  function d3_layout_stackOffsetZero(data) {\n    var j = -1, m = data[0].length, y0 = [];\n    while (++j < m) y0[j] = 0;\n    return y0;\n  }\n  function d3_layout_stackMaxIndex(array) {\n    var i = 1, j = 0, v = array[0][1], k, n = array.length;\n    for (;i < n; ++i) {\n      if ((k = array[i][1]) > v) {\n        j = i;\n        v = k;\n      }\n    }\n    return j;\n  }\n  function d3_layout_stackReduceSum(d) {\n    return d.reduce(d3_layout_stackSum, 0);\n  }\n  function d3_layout_stackSum(p, d) {\n    return p + d[1];\n  }\n  d3.layout.histogram = function() {\n    var frequency = true, valuer = Number, ranger = d3_layout_histogramRange, binner = d3_layout_histogramBinSturges;\n    function histogram(data, i) {\n      var bins = [], values = data.map(valuer, this), range = ranger.call(this, values, i), thresholds = binner.call(this, range, values, i), bin, i = -1, n = values.length, m = thresholds.length - 1, k = frequency ? 1 : 1 / n, x;\n      while (++i < m) {\n        bin = bins[i] = [];\n        bin.dx = thresholds[i + 1] - (bin.x = thresholds[i]);\n        bin.y = 0;\n      }\n      if (m > 0) {\n        i = -1;\n        while (++i < n) {\n          x = values[i];\n          if (x >= range[0] && x <= range[1]) {\n            bin = bins[d3.bisect(thresholds, x, 1, m) - 1];\n            bin.y += k;\n            bin.push(data[i]);\n          }\n        }\n      }\n      return bins;\n    }\n    histogram.value = function(x) {\n      if (!arguments.length) return valuer;\n      valuer = x;\n      return histogram;\n    };\n    histogram.range = function(x) {\n      if (!arguments.length) return ranger;\n      ranger = d3_functor(x);\n      return histogram;\n    };\n    histogram.bins = function(x) {\n      if (!arguments.length) return binner;\n      binner = typeof x === \"number\" ? function(range) {\n        return d3_layout_histogramBinFixed(range, x);\n      } : d3_functor(x);\n      return histogram;\n    };\n    histogram.frequency = function(x) {\n      if (!arguments.length) return frequency;\n      frequency = !!x;\n      return histogram;\n    };\n    return histogram;\n  };\n  function d3_layout_histogramBinSturges(range, values) {\n    return d3_layout_histogramBinFixed(range, Math.ceil(Math.log(values.length) / Math.LN2 + 1));\n  }\n  function d3_layout_histogramBinFixed(range, n) {\n    var x = -1, b = +range[0], m = (range[1] - b) / n, f = [];\n    while (++x <= n) f[x] = m * x + b;\n    return f;\n  }\n  function d3_layout_histogramRange(values) {\n    return [ d3.min(values), d3.max(values) ];\n  }\n  d3.layout.tree = function() {\n    var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ];\n    function tree(d, i) {\n      var nodes = hierarchy.call(this, d, i), root = nodes[0];\n      function firstWalk(node, previousSibling) {\n        var children = node.children, layout = node._tree;\n        if (children && (n = children.length)) {\n          var n, firstChild = children[0], previousChild, ancestor = firstChild, child, i = -1;\n          while (++i < n) {\n            child = children[i];\n            firstWalk(child, previousChild);\n            ancestor = apportion(child, previousChild, ancestor);\n            previousChild = child;\n          }\n          d3_layout_treeShift(node);\n          var midpoint = .5 * (firstChild._tree.prelim + child._tree.prelim);\n          if (previousSibling) {\n            layout.prelim = previousSibling._tree.prelim + separation(node, previousSibling);\n            layout.mod = layout.prelim - midpoint;\n          } else {\n            layout.prelim = midpoint;\n          }\n        } else {\n          if (previousSibling) {\n            layout.prelim = previousSibling._tree.prelim + separation(node, previousSibling);\n          }\n        }\n      }\n      function secondWalk(node, x) {\n        node.x = node._tree.prelim + x;\n        var children = node.children;\n        if (children && (n = children.length)) {\n          var i = -1, n;\n          x += node._tree.mod;\n          while (++i < n) {\n            secondWalk(children[i], x);\n          }\n        }\n      }\n      function apportion(node, previousSibling, ancestor) {\n        if (previousSibling) {\n          var vip = node, vop = node, vim = previousSibling, vom = node.parent.children[0], sip = vip._tree.mod, sop = vop._tree.mod, sim = vim._tree.mod, som = vom._tree.mod, shift;\n          while (vim = d3_layout_treeRight(vim), vip = d3_layout_treeLeft(vip), vim && vip) {\n            vom = d3_layout_treeLeft(vom);\n            vop = d3_layout_treeRight(vop);\n            vop._tree.ancestor = node;\n            shift = vim._tree.prelim + sim - vip._tree.prelim - sip + separation(vim, vip);\n            if (shift > 0) {\n              d3_layout_treeMove(d3_layout_treeAncestor(vim, node, ancestor), node, shift);\n              sip += shift;\n              sop += shift;\n            }\n            sim += vim._tree.mod;\n            sip += vip._tree.mod;\n            som += vom._tree.mod;\n            sop += vop._tree.mod;\n          }\n          if (vim && !d3_layout_treeRight(vop)) {\n            vop._tree.thread = vim;\n            vop._tree.mod += sim - sop;\n          }\n          if (vip && !d3_layout_treeLeft(vom)) {\n            vom._tree.thread = vip;\n            vom._tree.mod += sip - som;\n            ancestor = node;\n          }\n        }\n        return ancestor;\n      }\n      d3_layout_treeVisitAfter(root, function(node, previousSibling) {\n        node._tree = {\n          ancestor: node,\n          prelim: 0,\n          mod: 0,\n          change: 0,\n          shift: 0,\n          number: previousSibling ? previousSibling._tree.number + 1 : 0\n        };\n      });\n      firstWalk(root);\n      secondWalk(root, -root._tree.prelim);\n      var left = d3_layout_treeSearch(root, d3_layout_treeLeftmost), right = d3_layout_treeSearch(root, d3_layout_treeRightmost), deep = d3_layout_treeSearch(root, d3_layout_treeDeepest), x0 = left.x - separation(left, right) / 2, x1 = right.x + separation(right, left) / 2, y1 = deep.depth || 1;\n      d3_layout_treeVisitAfter(root, function(node) {\n        node.x = (node.x - x0) / (x1 - x0) * size[0];\n        node.y = node.depth / y1 * size[1];\n        delete node._tree;\n      });\n      return nodes;\n    }\n    tree.separation = function(x) {\n      if (!arguments.length) return separation;\n      separation = x;\n      return tree;\n    };\n    tree.size = function(x) {\n      if (!arguments.length) return size;\n      size = x;\n      return tree;\n    };\n    return d3_layout_hierarchyRebind(tree, hierarchy);\n  };\n  function d3_layout_treeSeparation(a, b) {\n    return a.parent == b.parent ? 1 : 2;\n  }\n  function d3_layout_treeLeft(node) {\n    var children = node.children;\n    return children && children.length ? children[0] : node._tree.thread;\n  }\n  function d3_layout_treeRight(node) {\n    var children = node.children, n;\n    return children && (n = children.length) ? children[n - 1] : node._tree.thread;\n  }\n  function d3_layout_treeSearch(node, compare) {\n    var children = node.children;\n    if (children && (n = children.length)) {\n      var child, n, i = -1;\n      while (++i < n) {\n        if (compare(child = d3_layout_treeSearch(children[i], compare), node) > 0) {\n          node = child;\n        }\n      }\n    }\n    return node;\n  }\n  function d3_layout_treeRightmost(a, b) {\n    return a.x - b.x;\n  }\n  function d3_layout_treeLeftmost(a, b) {\n    return b.x - a.x;\n  }\n  function d3_layout_treeDeepest(a, b) {\n    return a.depth - b.depth;\n  }\n  function d3_layout_treeVisitAfter(node, callback) {\n    function visit(node, previousSibling) {\n      var children = node.children;\n      if (children && (n = children.length)) {\n        var child, previousChild = null, i = -1, n;\n        while (++i < n) {\n          child = children[i];\n          visit(child, previousChild);\n          previousChild = child;\n        }\n      }\n      callback(node, previousSibling);\n    }\n    visit(node, null);\n  }\n  function d3_layout_treeShift(node) {\n    var shift = 0, change = 0, children = node.children, i = children.length, child;\n    while (--i >= 0) {\n      child = children[i]._tree;\n      child.prelim += shift;\n      child.mod += shift;\n      shift += child.shift + (change += child.change);\n    }\n  }\n  function d3_layout_treeMove(ancestor, node, shift) {\n    ancestor = ancestor._tree;\n    node = node._tree;\n    var change = shift / (node.number - ancestor.number);\n    ancestor.change += change;\n    node.change -= change;\n    node.shift += shift;\n    node.prelim += shift;\n    node.mod += shift;\n  }\n  function d3_layout_treeAncestor(vim, node, ancestor) {\n    return vim._tree.ancestor.parent == node.parent ? vim._tree.ancestor : ancestor;\n  }\n  d3.layout.pack = function() {\n    var hierarchy = d3.layout.hierarchy().sort(d3_layout_packSort), padding = 0, size = [ 1, 1 ];\n    function pack(d, i) {\n      var nodes = hierarchy.call(this, d, i), root = nodes[0];\n      root.x = 0;\n      root.y = 0;\n      d3_layout_treeVisitAfter(root, function(d) {\n        d.r = Math.sqrt(d.value);\n      });\n      d3_layout_treeVisitAfter(root, d3_layout_packSiblings);\n      var w = size[0], h = size[1], k = Math.max(2 * root.r / w, 2 * root.r / h);\n      if (padding > 0) {\n        var dr = padding * k / 2;\n        d3_layout_treeVisitAfter(root, function(d) {\n          d.r += dr;\n        });\n        d3_layout_treeVisitAfter(root, d3_layout_packSiblings);\n        d3_layout_treeVisitAfter(root, function(d) {\n          d.r -= dr;\n        });\n        k = Math.max(2 * root.r / w, 2 * root.r / h);\n      }\n      d3_layout_packTransform(root, w / 2, h / 2, 1 / k);\n      return nodes;\n    }\n    pack.size = function(x) {\n      if (!arguments.length) return size;\n      size = x;\n      return pack;\n    };\n    pack.padding = function(_) {\n      if (!arguments.length) return padding;\n      padding = +_;\n      return pack;\n    };\n    return d3_layout_hierarchyRebind(pack, hierarchy);\n  };\n  function d3_layout_packSort(a, b) {\n    return a.value - b.value;\n  }\n  function d3_layout_packInsert(a, b) {\n    var c = a._pack_next;\n    a._pack_next = b;\n    b._pack_prev = a;\n    b._pack_next = c;\n    c._pack_prev = b;\n  }\n  function d3_layout_packSplice(a, b) {\n    a._pack_next = b;\n    b._pack_prev = a;\n  }\n  function d3_layout_packIntersects(a, b) {\n    var dx = b.x - a.x, dy = b.y - a.y, dr = a.r + b.r;\n    return dr * dr - dx * dx - dy * dy > .001;\n  }\n  function d3_layout_packSiblings(node) {\n    if (!(nodes = node.children) || !(n = nodes.length)) return;\n    var nodes, xMin = Infinity, xMax = -Infinity, yMin = Infinity, yMax = -Infinity, a, b, c, i, j, k, n;\n    function bound(node) {\n      xMin = Math.min(node.x - node.r, xMin);\n      xMax = Math.max(node.x + node.r, xMax);\n      yMin = Math.min(node.y - node.r, yMin);\n      yMax = Math.max(node.y + node.r, yMax);\n    }\n    nodes.forEach(d3_layout_packLink);\n    a = nodes[0];\n    a.x = -a.r;\n    a.y = 0;\n    bound(a);\n    if (n > 1) {\n      b = nodes[1];\n      b.x = b.r;\n      b.y = 0;\n      bound(b);\n      if (n > 2) {\n        c = nodes[2];\n        d3_layout_packPlace(a, b, c);\n        bound(c);\n        d3_layout_packInsert(a, c);\n        a._pack_prev = c;\n        d3_layout_packInsert(c, b);\n        b = a._pack_next;\n        for (i = 3; i < n; i++) {\n          d3_layout_packPlace(a, b, c = nodes[i]);\n          var isect = 0, s1 = 1, s2 = 1;\n          for (j = b._pack_next; j !== b; j = j._pack_next, s1++) {\n            if (d3_layout_packIntersects(j, c)) {\n              isect = 1;\n              break;\n            }\n          }\n          if (isect == 1) {\n            for (k = a._pack_prev; k !== j._pack_prev; k = k._pack_prev, s2++) {\n              if (d3_layout_packIntersects(k, c)) {\n                break;\n              }\n            }\n          }\n          if (isect) {\n            if (s1 < s2 || s1 == s2 && b.r < a.r) d3_layout_packSplice(a, b = j); else d3_layout_packSplice(a = k, b);\n            i--;\n          } else {\n            d3_layout_packInsert(a, c);\n            b = c;\n            bound(c);\n          }\n        }\n      }\n    }\n    var cx = (xMin + xMax) / 2, cy = (yMin + yMax) / 2, cr = 0;\n    for (i = 0; i < n; i++) {\n      c = nodes[i];\n      c.x -= cx;\n      c.y -= cy;\n      cr = Math.max(cr, c.r + Math.sqrt(c.x * c.x + c.y * c.y));\n    }\n    node.r = cr;\n    nodes.forEach(d3_layout_packUnlink);\n  }\n  function d3_layout_packLink(node) {\n    node._pack_next = node._pack_prev = node;\n  }\n  function d3_layout_packUnlink(node) {\n    delete node._pack_next;\n    delete node._pack_prev;\n  }\n  function d3_layout_packTransform(node, x, y, k) {\n    var children = node.children;\n    node.x = x += k * node.x;\n    node.y = y += k * node.y;\n    node.r *= k;\n    if (children) {\n      var i = -1, n = children.length;\n      while (++i < n) d3_layout_packTransform(children[i], x, y, k);\n    }\n  }\n  function d3_layout_packPlace(a, b, c) {\n    var db = a.r + c.r, dx = b.x - a.x, dy = b.y - a.y;\n    if (db && (dx || dy)) {\n      var da = b.r + c.r, dc = dx * dx + dy * dy;\n      da *= da;\n      db *= db;\n      var x = .5 + (db - da) / (2 * dc), y = Math.sqrt(Math.max(0, 2 * da * (db + dc) - (db -= dc) * db - da * da)) / (2 * dc);\n      c.x = a.x + x * dx + y * dy;\n      c.y = a.y + x * dy - y * dx;\n    } else {\n      c.x = a.x + db;\n      c.y = a.y;\n    }\n  }\n  d3.layout.cluster = function() {\n    var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ];\n    function cluster(d, i) {\n      var nodes = hierarchy.call(this, d, i), root = nodes[0], previousNode, x = 0;\n      d3_layout_treeVisitAfter(root, function(node) {\n        var children = node.children;\n        if (children && children.length) {\n          node.x = d3_layout_clusterX(children);\n          node.y = d3_layout_clusterY(children);\n        } else {\n          node.x = previousNode ? x += separation(node, previousNode) : 0;\n          node.y = 0;\n          previousNode = node;\n        }\n      });\n      var left = d3_layout_clusterLeft(root), right = d3_layout_clusterRight(root), x0 = left.x - separation(left, right) / 2, x1 = right.x + separation(right, left) / 2;\n      d3_layout_treeVisitAfter(root, function(node) {\n        node.x = (node.x - x0) / (x1 - x0) * size[0];\n        node.y = (1 - (root.y ? node.y / root.y : 1)) * size[1];\n      });\n      return nodes;\n    }\n    cluster.separation = function(x) {\n      if (!arguments.length) return separation;\n      separation = x;\n      return cluster;\n    };\n    cluster.size = function(x) {\n      if (!arguments.length) return size;\n      size = x;\n      return cluster;\n    };\n    return d3_layout_hierarchyRebind(cluster, hierarchy);\n  };\n  function d3_layout_clusterY(children) {\n    return 1 + d3.max(children, function(child) {\n      return child.y;\n    });\n  }\n  function d3_layout_clusterX(children) {\n    return children.reduce(function(x, child) {\n      return x + child.x;\n    }, 0) / children.length;\n  }\n  function d3_layout_clusterLeft(node) {\n    var children = node.children;\n    return children && children.length ? d3_layout_clusterLeft(children[0]) : node;\n  }\n  function d3_layout_clusterRight(node) {\n    var children = node.children, n;\n    return children && (n = children.length) ? d3_layout_clusterRight(children[n - 1]) : node;\n  }\n  d3.layout.treemap = function() {\n    var hierarchy = d3.layout.hierarchy(), round = Math.round, size = [ 1, 1 ], padding = null, pad = d3_layout_treemapPadNull, sticky = false, stickies, mode = \"squarify\", ratio = .5 * (1 + Math.sqrt(5));\n    function scale(children, k) {\n      var i = -1, n = children.length, child, area;\n      while (++i < n) {\n        area = (child = children[i]).value * (k < 0 ? 0 : k);\n        child.area = isNaN(area) || area <= 0 ? 0 : area;\n      }\n    }\n    function squarify(node) {\n      var children = node.children;\n      if (children && children.length) {\n        var rect = pad(node), row = [], remaining = children.slice(), child, best = Infinity, score, u = mode === \"slice\" ? rect.dx : mode === \"dice\" ? rect.dy : mode === \"slice-dice\" ? node.depth & 1 ? rect.dy : rect.dx : Math.min(rect.dx, rect.dy), n;\n        scale(remaining, rect.dx * rect.dy / node.value);\n        row.area = 0;\n        while ((n = remaining.length) > 0) {\n          row.push(child = remaining[n - 1]);\n          row.area += child.area;\n          if (mode !== \"squarify\" || (score = worst(row, u)) <= best) {\n            remaining.pop();\n            best = score;\n          } else {\n            row.area -= row.pop().area;\n            position(row, u, rect, false);\n            u = Math.min(rect.dx, rect.dy);\n            row.length = row.area = 0;\n            best = Infinity;\n          }\n        }\n        if (row.length) {\n          position(row, u, rect, true);\n          row.length = row.area = 0;\n        }\n        children.forEach(squarify);\n      }\n    }\n    function stickify(node) {\n      var children = node.children;\n      if (children && children.length) {\n        var rect = pad(node), remaining = children.slice(), child, row = [];\n        scale(remaining, rect.dx * rect.dy / node.value);\n        row.area = 0;\n        while (child = remaining.pop()) {\n          row.push(child);\n          row.area += child.area;\n          if (child.z != null) {\n            position(row, child.z ? rect.dx : rect.dy, rect, !remaining.length);\n            row.length = row.area = 0;\n          }\n        }\n        children.forEach(stickify);\n      }\n    }\n    function worst(row, u) {\n      var s = row.area, r, rmax = 0, rmin = Infinity, i = -1, n = row.length;\n      while (++i < n) {\n        if (!(r = row[i].area)) continue;\n        if (r < rmin) rmin = r;\n        if (r > rmax) rmax = r;\n      }\n      s *= s;\n      u *= u;\n      return s ? Math.max(u * rmax * ratio / s, s / (u * rmin * ratio)) : Infinity;\n    }\n    function position(row, u, rect, flush) {\n      var i = -1, n = row.length, x = rect.x, y = rect.y, v = u ? round(row.area / u) : 0, o;\n      if (u == rect.dx) {\n        if (flush || v > rect.dy) v = rect.dy;\n        while (++i < n) {\n          o = row[i];\n          o.x = x;\n          o.y = y;\n          o.dy = v;\n          x += o.dx = Math.min(rect.x + rect.dx - x, v ? round(o.area / v) : 0);\n        }\n        o.z = true;\n        o.dx += rect.x + rect.dx - x;\n        rect.y += v;\n        rect.dy -= v;\n      } else {\n        if (flush || v > rect.dx) v = rect.dx;\n        while (++i < n) {\n          o = row[i];\n          o.x = x;\n          o.y = y;\n          o.dx = v;\n          y += o.dy = Math.min(rect.y + rect.dy - y, v ? round(o.area / v) : 0);\n        }\n        o.z = false;\n        o.dy += rect.y + rect.dy - y;\n        rect.x += v;\n        rect.dx -= v;\n      }\n    }\n    function treemap(d) {\n      var nodes = stickies || hierarchy(d), root = nodes[0];\n      root.x = 0;\n      root.y = 0;\n      root.dx = size[0];\n      root.dy = size[1];\n      if (stickies) hierarchy.revalue(root);\n      scale([ root ], root.dx * root.dy / root.value);\n      (stickies ? stickify : squarify)(root);\n      if (sticky) stickies = nodes;\n      return nodes;\n    }\n    treemap.size = function(x) {\n      if (!arguments.length) return size;\n      size = x;\n      return treemap;\n    };\n    treemap.padding = function(x) {\n      if (!arguments.length) return padding;\n      function padFunction(node) {\n        var p = x.call(treemap, node, node.depth);\n        return p == null ? d3_layout_treemapPadNull(node) : d3_layout_treemapPad(node, typeof p === \"number\" ? [ p, p, p, p ] : p);\n      }\n      function padConstant(node) {\n        return d3_layout_treemapPad(node, x);\n      }\n      var type;\n      pad = (padding = x) == null ? d3_layout_treemapPadNull : (type = typeof x) === \"function\" ? padFunction : type === \"number\" ? (x = [ x, x, x, x ], \n      padConstant) : padConstant;\n      return treemap;\n    };\n    treemap.round = function(x) {\n      if (!arguments.length) return round != Number;\n      round = x ? Math.round : Number;\n      return treemap;\n    };\n    treemap.sticky = function(x) {\n      if (!arguments.length) return sticky;\n      sticky = x;\n      stickies = null;\n      return treemap;\n    };\n    treemap.ratio = function(x) {\n      if (!arguments.length) return ratio;\n      ratio = x;\n      return treemap;\n    };\n    treemap.mode = function(x) {\n      if (!arguments.length) return mode;\n      mode = x + \"\";\n      return treemap;\n    };\n    return d3_layout_hierarchyRebind(treemap, hierarchy);\n  };\n  function d3_layout_treemapPadNull(node) {\n    return {\n      x: node.x,\n      y: node.y,\n      dx: node.dx,\n      dy: node.dy\n    };\n  }\n  function d3_layout_treemapPad(node, padding) {\n    var x = node.x + padding[3], y = node.y + padding[0], dx = node.dx - padding[1] - padding[3], dy = node.dy - padding[0] - padding[2];\n    if (dx < 0) {\n      x += dx / 2;\n      dx = 0;\n    }\n    if (dy < 0) {\n      y += dy / 2;\n      dy = 0;\n    }\n    return {\n      x: x,\n      y: y,\n      dx: dx,\n      dy: dy\n    };\n  }\n  d3.random = {\n    normal: function(µ, σ) {\n      var n = arguments.length;\n      if (n < 2) σ = 1;\n      if (n < 1) µ = 0;\n      return function() {\n        var x, y, r;\n        do {\n          x = Math.random() * 2 - 1;\n          y = Math.random() * 2 - 1;\n          r = x * x + y * y;\n        } while (!r || r > 1);\n        return µ + σ * x * Math.sqrt(-2 * Math.log(r) / r);\n      };\n    },\n    logNormal: function() {\n      var random = d3.random.normal.apply(d3, arguments);\n      return function() {\n        return Math.exp(random());\n      };\n    },\n    irwinHall: function(m) {\n      return function() {\n        for (var s = 0, j = 0; j < m; j++) s += Math.random();\n        return s / m;\n      };\n    }\n  };\n  d3.scale = {};\n  function d3_scaleExtent(domain) {\n    var start = domain[0], stop = domain[domain.length - 1];\n    return start < stop ? [ start, stop ] : [ stop, start ];\n  }\n  function d3_scaleRange(scale) {\n    return scale.rangeExtent ? scale.rangeExtent() : d3_scaleExtent(scale.range());\n  }\n  function d3_scale_bilinear(domain, range, uninterpolate, interpolate) {\n    var u = uninterpolate(domain[0], domain[1]), i = interpolate(range[0], range[1]);\n    return function(x) {\n      return i(u(x));\n    };\n  }\n  function d3_scale_nice(domain, nice) {\n    var i0 = 0, i1 = domain.length - 1, x0 = domain[i0], x1 = domain[i1], dx;\n    if (x1 < x0) {\n      dx = i0, i0 = i1, i1 = dx;\n      dx = x0, x0 = x1, x1 = dx;\n    }\n    if (nice = nice(x1 - x0)) {\n      domain[i0] = nice.floor(x0);\n      domain[i1] = nice.ceil(x1);\n    }\n    return domain;\n  }\n  function d3_scale_polylinear(domain, range, uninterpolate, interpolate) {\n    var u = [], i = [], j = 0, k = Math.min(domain.length, range.length) - 1;\n    if (domain[k] < domain[0]) {\n      domain = domain.slice().reverse();\n      range = range.slice().reverse();\n    }\n    while (++j <= k) {\n      u.push(uninterpolate(domain[j - 1], domain[j]));\n      i.push(interpolate(range[j - 1], range[j]));\n    }\n    return function(x) {\n      var j = d3.bisect(domain, x, 1, k) - 1;\n      return i[j](u[j](x));\n    };\n  }\n  d3.scale.linear = function() {\n    return d3_scale_linear([ 0, 1 ], [ 0, 1 ], d3_interpolate, false);\n  };\n  function d3_scale_linear(domain, range, interpolate, clamp) {\n    var output, input;\n    function rescale() {\n      var linear = Math.min(domain.length, range.length) > 2 ? d3_scale_polylinear : d3_scale_bilinear, uninterpolate = clamp ? d3_uninterpolateClamp : d3_uninterpolateNumber;\n      output = linear(domain, range, uninterpolate, interpolate);\n      input = linear(range, domain, uninterpolate, d3_interpolate);\n      return scale;\n    }\n    function scale(x) {\n      return output(x);\n    }\n    scale.invert = function(y) {\n      return input(y);\n    };\n    scale.domain = function(x) {\n      if (!arguments.length) return domain;\n      domain = x.map(Number);\n      return rescale();\n    };\n    scale.range = function(x) {\n      if (!arguments.length) return range;\n      range = x;\n      return rescale();\n    };\n    scale.rangeRound = function(x) {\n      return scale.range(x).interpolate(d3_interpolateRound);\n    };\n    scale.clamp = function(x) {\n      if (!arguments.length) return clamp;\n      clamp = x;\n      return rescale();\n    };\n    scale.interpolate = function(x) {\n      if (!arguments.length) return interpolate;\n      interpolate = x;\n      return rescale();\n    };\n    scale.ticks = function(m) {\n      return d3_scale_linearTicks(domain, m);\n    };\n    scale.tickFormat = function(m, format) {\n      return d3_scale_linearTickFormat(domain, m, format);\n    };\n    scale.nice = function() {\n      d3_scale_nice(domain, d3_scale_linearNice);\n      return rescale();\n    };\n    scale.copy = function() {\n      return d3_scale_linear(domain, range, interpolate, clamp);\n    };\n    return rescale();\n  }\n  function d3_scale_linearRebind(scale, linear) {\n    return d3.rebind(scale, linear, \"range\", \"rangeRound\", \"interpolate\", \"clamp\");\n  }\n  function d3_scale_linearNice(dx) {\n    dx = Math.pow(10, Math.round(Math.log(dx) / Math.LN10) - 1);\n    return dx && {\n      floor: function(x) {\n        return Math.floor(x / dx) * dx;\n      },\n      ceil: function(x) {\n        return Math.ceil(x / dx) * dx;\n      }\n    };\n  }\n  function d3_scale_linearTickRange(domain, m) {\n    var extent = d3_scaleExtent(domain), span = extent[1] - extent[0], step = Math.pow(10, Math.floor(Math.log(span / m) / Math.LN10)), err = m / span * step;\n    if (err <= .15) step *= 10; else if (err <= .35) step *= 5; else if (err <= .75) step *= 2;\n    extent[0] = Math.ceil(extent[0] / step) * step;\n    extent[1] = Math.floor(extent[1] / step) * step + step * .5;\n    extent[2] = step;\n    return extent;\n  }\n  function d3_scale_linearTicks(domain, m) {\n    return d3.range.apply(d3, d3_scale_linearTickRange(domain, m));\n  }\n  function d3_scale_linearTickFormat(domain, m, format) {\n    var precision = -Math.floor(Math.log(d3_scale_linearTickRange(domain, m)[2]) / Math.LN10 + .01);\n    return d3.format(format ? format.replace(d3_format_re, function(a, b, c, d, e, f, g, h, i, j) {\n      return [ b, c, d, e, f, g, h, i || \".\" + (precision - (j === \"%\") * 2), j ].join(\"\");\n    }) : \",.\" + precision + \"f\");\n  }\n  d3.scale.log = function() {\n    return d3_scale_log(d3.scale.linear().domain([ 0, Math.LN10 ]), 10, d3_scale_logp, d3_scale_powp);\n  };\n  function d3_scale_log(linear, base, log, pow) {\n    function scale(x) {\n      return linear(log(x));\n    }\n    scale.invert = function(x) {\n      return pow(linear.invert(x));\n    };\n    scale.domain = function(x) {\n      if (!arguments.length) return linear.domain().map(pow);\n      if (x[0] < 0) log = d3_scale_logn, pow = d3_scale_pown; else log = d3_scale_logp, \n      pow = d3_scale_powp;\n      linear.domain(x.map(log));\n      return scale;\n    };\n    scale.base = function(_) {\n      if (!arguments.length) return base;\n      base = +_;\n      return scale;\n    };\n    scale.nice = function() {\n      linear.domain(d3_scale_nice(linear.domain(), d3_scale_logNice(base)));\n      return scale;\n    };\n    scale.ticks = function() {\n      var extent = d3_scaleExtent(linear.domain()), ticks = [];\n      if (extent.every(isFinite)) {\n        var b = Math.log(base), i = Math.floor(extent[0] / b), j = Math.ceil(extent[1] / b), u = pow(extent[0]), v = pow(extent[1]), n = base % 1 ? 2 : base;\n        if (log === d3_scale_logn) {\n          ticks.push(-Math.pow(base, -i));\n          for (;i++ < j; ) for (var k = n - 1; k > 0; k--) ticks.push(-Math.pow(base, -i) * k);\n        } else {\n          for (;i < j; i++) for (var k = 1; k < n; k++) ticks.push(Math.pow(base, i) * k);\n          ticks.push(Math.pow(base, i));\n        }\n        for (i = 0; ticks[i] < u; i++) {}\n        for (j = ticks.length; ticks[j - 1] > v; j--) {}\n        ticks = ticks.slice(i, j);\n      }\n      return ticks;\n    };\n    scale.tickFormat = function(n, format) {\n      if (arguments.length < 2) format = d3_scale_logFormat;\n      if (!arguments.length) return format;\n      var b = Math.log(base), k = Math.max(.1, n / scale.ticks().length), f = log === d3_scale_logn ? (e = -1e-12, \n      Math.floor) : (e = 1e-12, Math.ceil), e;\n      return function(d) {\n        return d / pow(b * f(log(d) / b + e)) <= k ? format(d) : \"\";\n      };\n    };\n    scale.copy = function() {\n      return d3_scale_log(linear.copy(), base, log, pow);\n    };\n    return d3_scale_linearRebind(scale, linear);\n  }\n  var d3_scale_logFormat = d3.format(\".0e\");\n  function d3_scale_logp(x) {\n    return Math.log(x < 0 ? 0 : x);\n  }\n  function d3_scale_powp(x) {\n    return Math.exp(x);\n  }\n  function d3_scale_logn(x) {\n    return -Math.log(x > 0 ? 0 : -x);\n  }\n  function d3_scale_pown(x) {\n    return -Math.exp(-x);\n  }\n  function d3_scale_logNice(base) {\n    base = Math.log(base);\n    var nice = {\n      floor: function(x) {\n        return Math.floor(x / base) * base;\n      },\n      ceil: function(x) {\n        return Math.ceil(x / base) * base;\n      }\n    };\n    return function() {\n      return nice;\n    };\n  }\n  d3.scale.pow = function() {\n    return d3_scale_pow(d3.scale.linear(), 1);\n  };\n  function d3_scale_pow(linear, exponent) {\n    var powp = d3_scale_powPow(exponent), powb = d3_scale_powPow(1 / exponent);\n    function scale(x) {\n      return linear(powp(x));\n    }\n    scale.invert = function(x) {\n      return powb(linear.invert(x));\n    };\n    scale.domain = function(x) {\n      if (!arguments.length) return linear.domain().map(powb);\n      linear.domain(x.map(powp));\n      return scale;\n    };\n    scale.ticks = function(m) {\n      return d3_scale_linearTicks(scale.domain(), m);\n    };\n    scale.tickFormat = function(m, format) {\n      return d3_scale_linearTickFormat(scale.domain(), m, format);\n    };\n    scale.nice = function() {\n      return scale.domain(d3_scale_nice(scale.domain(), d3_scale_linearNice));\n    };\n    scale.exponent = function(x) {\n      if (!arguments.length) return exponent;\n      var domain = scale.domain();\n      powp = d3_scale_powPow(exponent = x);\n      powb = d3_scale_powPow(1 / exponent);\n      return scale.domain(domain);\n    };\n    scale.copy = function() {\n      return d3_scale_pow(linear.copy(), exponent);\n    };\n    return d3_scale_linearRebind(scale, linear);\n  }\n  function d3_scale_powPow(e) {\n    return function(x) {\n      return x < 0 ? -Math.pow(-x, e) : Math.pow(x, e);\n    };\n  }\n  d3.scale.sqrt = function() {\n    return d3.scale.pow().exponent(.5);\n  };\n  d3.scale.ordinal = function() {\n    return d3_scale_ordinal([], {\n      t: \"range\",\n      a: [ [] ]\n    });\n  };\n  function d3_scale_ordinal(domain, ranger) {\n    var index, range, rangeBand;\n    function scale(x) {\n      return range[((index.get(x) || index.set(x, domain.push(x))) - 1) % range.length];\n    }\n    function steps(start, step) {\n      return d3.range(domain.length).map(function(i) {\n        return start + step * i;\n      });\n    }\n    scale.domain = function(x) {\n      if (!arguments.length) return domain;\n      domain = [];\n      index = new d3_Map();\n      var i = -1, n = x.length, xi;\n      while (++i < n) if (!index.has(xi = x[i])) index.set(xi, domain.push(xi));\n      return scale[ranger.t].apply(scale, ranger.a);\n    };\n    scale.range = function(x) {\n      if (!arguments.length) return range;\n      range = x;\n      rangeBand = 0;\n      ranger = {\n        t: \"range\",\n        a: arguments\n      };\n      return scale;\n    };\n    scale.rangePoints = function(x, padding) {\n      if (arguments.length < 2) padding = 0;\n      var start = x[0], stop = x[1], step = (stop - start) / (Math.max(1, domain.length - 1) + padding);\n      range = steps(domain.length < 2 ? (start + stop) / 2 : start + step * padding / 2, step);\n      rangeBand = 0;\n      ranger = {\n        t: \"rangePoints\",\n        a: arguments\n      };\n      return scale;\n    };\n    scale.rangeBands = function(x, padding, outerPadding) {\n      if (arguments.length < 2) padding = 0;\n      if (arguments.length < 3) outerPadding = padding;\n      var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step = (stop - start) / (domain.length - padding + 2 * outerPadding);\n      range = steps(start + step * outerPadding, step);\n      if (reverse) range.reverse();\n      rangeBand = step * (1 - padding);\n      ranger = {\n        t: \"rangeBands\",\n        a: arguments\n      };\n      return scale;\n    };\n    scale.rangeRoundBands = function(x, padding, outerPadding) {\n      if (arguments.length < 2) padding = 0;\n      if (arguments.length < 3) outerPadding = padding;\n      var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step = Math.floor((stop - start) / (domain.length - padding + 2 * outerPadding)), error = stop - start - (domain.length - padding) * step;\n      range = steps(start + Math.round(error / 2), step);\n      if (reverse) range.reverse();\n      rangeBand = Math.round(step * (1 - padding));\n      ranger = {\n        t: \"rangeRoundBands\",\n        a: arguments\n      };\n      return scale;\n    };\n    scale.rangeBand = function() {\n      return rangeBand;\n    };\n    scale.rangeExtent = function() {\n      return d3_scaleExtent(ranger.a[0]);\n    };\n    scale.copy = function() {\n      return d3_scale_ordinal(domain, ranger);\n    };\n    return scale.domain(domain);\n  }\n  d3.scale.category10 = function() {\n    return d3.scale.ordinal().range(d3_category10);\n  };\n  d3.scale.category20 = function() {\n    return d3.scale.ordinal().range(d3_category20);\n  };\n  d3.scale.category20b = function() {\n    return d3.scale.ordinal().range(d3_category20b);\n  };\n  d3.scale.category20c = function() {\n    return d3.scale.ordinal().range(d3_category20c);\n  };\n  var d3_category10 = [ \"#1f77b4\", \"#ff7f0e\", \"#2ca02c\", \"#d62728\", \"#9467bd\", \"#8c564b\", \"#e377c2\", \"#7f7f7f\", \"#bcbd22\", \"#17becf\" ];\n  var d3_category20 = [ \"#1f77b4\", \"#aec7e8\", \"#ff7f0e\", \"#ffbb78\", \"#2ca02c\", \"#98df8a\", \"#d62728\", \"#ff9896\", \"#9467bd\", \"#c5b0d5\", \"#8c564b\", \"#c49c94\", \"#e377c2\", \"#f7b6d2\", \"#7f7f7f\", \"#c7c7c7\", \"#bcbd22\", \"#dbdb8d\", \"#17becf\", \"#9edae5\" ];\n  var d3_category20b = [ \"#393b79\", \"#5254a3\", \"#6b6ecf\", \"#9c9ede\", \"#637939\", \"#8ca252\", \"#b5cf6b\", \"#cedb9c\", \"#8c6d31\", \"#bd9e39\", \"#e7ba52\", \"#e7cb94\", \"#843c39\", \"#ad494a\", \"#d6616b\", \"#e7969c\", \"#7b4173\", \"#a55194\", \"#ce6dbd\", \"#de9ed6\" ];\n  var d3_category20c = [ \"#3182bd\", \"#6baed6\", \"#9ecae1\", \"#c6dbef\", \"#e6550d\", \"#fd8d3c\", \"#fdae6b\", \"#fdd0a2\", \"#31a354\", \"#74c476\", \"#a1d99b\", \"#c7e9c0\", \"#756bb1\", \"#9e9ac8\", \"#bcbddc\", \"#dadaeb\", \"#636363\", \"#969696\", \"#bdbdbd\", \"#d9d9d9\" ];\n  d3.scale.quantile = function() {\n    return d3_scale_quantile([], []);\n  };\n  function d3_scale_quantile(domain, range) {\n    var thresholds;\n    function rescale() {\n      var k = 0, q = range.length;\n      thresholds = [];\n      while (++k < q) thresholds[k - 1] = d3.quantile(domain, k / q);\n      return scale;\n    }\n    function scale(x) {\n      if (isNaN(x = +x)) return NaN;\n      return range[d3.bisect(thresholds, x)];\n    }\n    scale.domain = function(x) {\n      if (!arguments.length) return domain;\n      domain = x.filter(function(d) {\n        return !isNaN(d);\n      }).sort(d3.ascending);\n      return rescale();\n    };\n    scale.range = function(x) {\n      if (!arguments.length) return range;\n      range = x;\n      return rescale();\n    };\n    scale.quantiles = function() {\n      return thresholds;\n    };\n    scale.copy = function() {\n      return d3_scale_quantile(domain, range);\n    };\n    return rescale();\n  }\n  d3.scale.quantize = function() {\n    return d3_scale_quantize(0, 1, [ 0, 1 ]);\n  };\n  function d3_scale_quantize(x0, x1, range) {\n    var kx, i;\n    function scale(x) {\n      return range[Math.max(0, Math.min(i, Math.floor(kx * (x - x0))))];\n    }\n    function rescale() {\n      kx = range.length / (x1 - x0);\n      i = range.length - 1;\n      return scale;\n    }\n    scale.domain = function(x) {\n      if (!arguments.length) return [ x0, x1 ];\n      x0 = +x[0];\n      x1 = +x[x.length - 1];\n      return rescale();\n    };\n    scale.range = function(x) {\n      if (!arguments.length) return range;\n      range = x;\n      return rescale();\n    };\n    scale.copy = function() {\n      return d3_scale_quantize(x0, x1, range);\n    };\n    return rescale();\n  }\n  d3.scale.threshold = function() {\n    return d3_scale_threshold([ .5 ], [ 0, 1 ]);\n  };\n  function d3_scale_threshold(domain, range) {\n    function scale(x) {\n      return range[d3.bisect(domain, x)];\n    }\n    scale.domain = function(_) {\n      if (!arguments.length) return domain;\n      domain = _;\n      return scale;\n    };\n    scale.range = function(_) {\n      if (!arguments.length) return range;\n      range = _;\n      return scale;\n    };\n    scale.copy = function() {\n      return d3_scale_threshold(domain, range);\n    };\n    return scale;\n  }\n  d3.scale.identity = function() {\n    return d3_scale_identity([ 0, 1 ]);\n  };\n  function d3_scale_identity(domain) {\n    function identity(x) {\n      return +x;\n    }\n    identity.invert = identity;\n    identity.domain = identity.range = function(x) {\n      if (!arguments.length) return domain;\n      domain = x.map(identity);\n      return identity;\n    };\n    identity.ticks = function(m) {\n      return d3_scale_linearTicks(domain, m);\n    };\n    identity.tickFormat = function(m, format) {\n      return d3_scale_linearTickFormat(domain, m, format);\n    };\n    identity.copy = function() {\n      return d3_scale_identity(domain);\n    };\n    return identity;\n  }\n  d3.svg.arc = function() {\n    var innerRadius = d3_svg_arcInnerRadius, outerRadius = d3_svg_arcOuterRadius, startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle;\n    function arc() {\n      var r0 = innerRadius.apply(this, arguments), r1 = outerRadius.apply(this, arguments), a0 = startAngle.apply(this, arguments) + d3_svg_arcOffset, a1 = endAngle.apply(this, arguments) + d3_svg_arcOffset, da = (a1 < a0 && (da = a0, \n      a0 = a1, a1 = da), a1 - a0), df = da < π ? \"0\" : \"1\", c0 = Math.cos(a0), s0 = Math.sin(a0), c1 = Math.cos(a1), s1 = Math.sin(a1);\n      return da >= d3_svg_arcMax ? r0 ? \"M0,\" + r1 + \"A\" + r1 + \",\" + r1 + \" 0 1,1 0,\" + -r1 + \"A\" + r1 + \",\" + r1 + \" 0 1,1 0,\" + r1 + \"M0,\" + r0 + \"A\" + r0 + \",\" + r0 + \" 0 1,0 0,\" + -r0 + \"A\" + r0 + \",\" + r0 + \" 0 1,0 0,\" + r0 + \"Z\" : \"M0,\" + r1 + \"A\" + r1 + \",\" + r1 + \" 0 1,1 0,\" + -r1 + \"A\" + r1 + \",\" + r1 + \" 0 1,1 0,\" + r1 + \"Z\" : r0 ? \"M\" + r1 * c0 + \",\" + r1 * s0 + \"A\" + r1 + \",\" + r1 + \" 0 \" + df + \",1 \" + r1 * c1 + \",\" + r1 * s1 + \"L\" + r0 * c1 + \",\" + r0 * s1 + \"A\" + r0 + \",\" + r0 + \" 0 \" + df + \",0 \" + r0 * c0 + \",\" + r0 * s0 + \"Z\" : \"M\" + r1 * c0 + \",\" + r1 * s0 + \"A\" + r1 + \",\" + r1 + \" 0 \" + df + \",1 \" + r1 * c1 + \",\" + r1 * s1 + \"L0,0\" + \"Z\";\n    }\n    arc.innerRadius = function(v) {\n      if (!arguments.length) return innerRadius;\n      innerRadius = d3_functor(v);\n      return arc;\n    };\n    arc.outerRadius = function(v) {\n      if (!arguments.length) return outerRadius;\n      outerRadius = d3_functor(v);\n      return arc;\n    };\n    arc.startAngle = function(v) {\n      if (!arguments.length) return startAngle;\n      startAngle = d3_functor(v);\n      return arc;\n    };\n    arc.endAngle = function(v) {\n      if (!arguments.length) return endAngle;\n      endAngle = d3_functor(v);\n      return arc;\n    };\n    arc.centroid = function() {\n      var r = (innerRadius.apply(this, arguments) + outerRadius.apply(this, arguments)) / 2, a = (startAngle.apply(this, arguments) + endAngle.apply(this, arguments)) / 2 + d3_svg_arcOffset;\n      return [ Math.cos(a) * r, Math.sin(a) * r ];\n    };\n    return arc;\n  };\n  var d3_svg_arcOffset = -π / 2, d3_svg_arcMax = 2 * π - 1e-6;\n  function d3_svg_arcInnerRadius(d) {\n    return d.innerRadius;\n  }\n  function d3_svg_arcOuterRadius(d) {\n    return d.outerRadius;\n  }\n  function d3_svg_arcStartAngle(d) {\n    return d.startAngle;\n  }\n  function d3_svg_arcEndAngle(d) {\n    return d.endAngle;\n  }\n  d3.svg.line.radial = function() {\n    var line = d3_svg_line(d3_svg_lineRadial);\n    line.radius = line.x, delete line.x;\n    line.angle = line.y, delete line.y;\n    return line;\n  };\n  function d3_svg_lineRadial(points) {\n    var point, i = -1, n = points.length, r, a;\n    while (++i < n) {\n      point = points[i];\n      r = point[0];\n      a = point[1] + d3_svg_arcOffset;\n      point[0] = r * Math.cos(a);\n      point[1] = r * Math.sin(a);\n    }\n    return points;\n  }\n  function d3_svg_area(projection) {\n    var x0 = d3_svg_lineX, x1 = d3_svg_lineX, y0 = 0, y1 = d3_svg_lineY, defined = d3_true, interpolate = d3_svg_lineLinear, interpolateKey = interpolate.key, interpolateReverse = interpolate, L = \"L\", tension = .7;\n    function area(data) {\n      var segments = [], points0 = [], points1 = [], i = -1, n = data.length, d, fx0 = d3_functor(x0), fy0 = d3_functor(y0), fx1 = x0 === x1 ? function() {\n        return x;\n      } : d3_functor(x1), fy1 = y0 === y1 ? function() {\n        return y;\n      } : d3_functor(y1), x, y;\n      function segment() {\n        segments.push(\"M\", interpolate(projection(points1), tension), L, interpolateReverse(projection(points0.reverse()), tension), \"Z\");\n      }\n      while (++i < n) {\n        if (defined.call(this, d = data[i], i)) {\n          points0.push([ x = +fx0.call(this, d, i), y = +fy0.call(this, d, i) ]);\n          points1.push([ +fx1.call(this, d, i), +fy1.call(this, d, i) ]);\n        } else if (points0.length) {\n          segment();\n          points0 = [];\n          points1 = [];\n        }\n      }\n      if (points0.length) segment();\n      return segments.length ? segments.join(\"\") : null;\n    }\n    area.x = function(_) {\n      if (!arguments.length) return x1;\n      x0 = x1 = _;\n      return area;\n    };\n    area.x0 = function(_) {\n      if (!arguments.length) return x0;\n      x0 = _;\n      return area;\n    };\n    area.x1 = function(_) {\n      if (!arguments.length) return x1;\n      x1 = _;\n      return area;\n    };\n    area.y = function(_) {\n      if (!arguments.length) return y1;\n      y0 = y1 = _;\n      return area;\n    };\n    area.y0 = function(_) {\n      if (!arguments.length) return y0;\n      y0 = _;\n      return area;\n    };\n    area.y1 = function(_) {\n      if (!arguments.length) return y1;\n      y1 = _;\n      return area;\n    };\n    area.defined = function(_) {\n      if (!arguments.length) return defined;\n      defined = _;\n      return area;\n    };\n    area.interpolate = function(_) {\n      if (!arguments.length) return interpolateKey;\n      if (typeof _ === \"function\") interpolateKey = interpolate = _; else interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) || d3_svg_lineLinear).key;\n      interpolateReverse = interpolate.reverse || interpolate;\n      L = interpolate.closed ? \"M\" : \"L\";\n      return area;\n    };\n    area.tension = function(_) {\n      if (!arguments.length) return tension;\n      tension = _;\n      return area;\n    };\n    return area;\n  }\n  d3_svg_lineStepBefore.reverse = d3_svg_lineStepAfter;\n  d3_svg_lineStepAfter.reverse = d3_svg_lineStepBefore;\n  d3.svg.area = function() {\n    return d3_svg_area(d3_identity);\n  };\n  d3.svg.area.radial = function() {\n    var area = d3_svg_area(d3_svg_lineRadial);\n    area.radius = area.x, delete area.x;\n    area.innerRadius = area.x0, delete area.x0;\n    area.outerRadius = area.x1, delete area.x1;\n    area.angle = area.y, delete area.y;\n    area.startAngle = area.y0, delete area.y0;\n    area.endAngle = area.y1, delete area.y1;\n    return area;\n  };\n  d3.svg.chord = function() {\n    var source = d3_source, target = d3_target, radius = d3_svg_chordRadius, startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle;\n    function chord(d, i) {\n      var s = subgroup(this, source, d, i), t = subgroup(this, target, d, i);\n      return \"M\" + s.p0 + arc(s.r, s.p1, s.a1 - s.a0) + (equals(s, t) ? curve(s.r, s.p1, s.r, s.p0) : curve(s.r, s.p1, t.r, t.p0) + arc(t.r, t.p1, t.a1 - t.a0) + curve(t.r, t.p1, s.r, s.p0)) + \"Z\";\n    }\n    function subgroup(self, f, d, i) {\n      var subgroup = f.call(self, d, i), r = radius.call(self, subgroup, i), a0 = startAngle.call(self, subgroup, i) + d3_svg_arcOffset, a1 = endAngle.call(self, subgroup, i) + d3_svg_arcOffset;\n      return {\n        r: r,\n        a0: a0,\n        a1: a1,\n        p0: [ r * Math.cos(a0), r * Math.sin(a0) ],\n        p1: [ r * Math.cos(a1), r * Math.sin(a1) ]\n      };\n    }\n    function equals(a, b) {\n      return a.a0 == b.a0 && a.a1 == b.a1;\n    }\n    function arc(r, p, a) {\n      return \"A\" + r + \",\" + r + \" 0 \" + +(a > π) + \",1 \" + p;\n    }\n    function curve(r0, p0, r1, p1) {\n      return \"Q 0,0 \" + p1;\n    }\n    chord.radius = function(v) {\n      if (!arguments.length) return radius;\n      radius = d3_functor(v);\n      return chord;\n    };\n    chord.source = function(v) {\n      if (!arguments.length) return source;\n      source = d3_functor(v);\n      return chord;\n    };\n    chord.target = function(v) {\n      if (!arguments.length) return target;\n      target = d3_functor(v);\n      return chord;\n    };\n    chord.startAngle = function(v) {\n      if (!arguments.length) return startAngle;\n      startAngle = d3_functor(v);\n      return chord;\n    };\n    chord.endAngle = function(v) {\n      if (!arguments.length) return endAngle;\n      endAngle = d3_functor(v);\n      return chord;\n    };\n    return chord;\n  };\n  function d3_svg_chordRadius(d) {\n    return d.radius;\n  }\n  d3.svg.diagonal = function() {\n    var source = d3_source, target = d3_target, projection = d3_svg_diagonalProjection;\n    function diagonal(d, i) {\n      var p0 = source.call(this, d, i), p3 = target.call(this, d, i), m = (p0.y + p3.y) / 2, p = [ p0, {\n        x: p0.x,\n        y: m\n      }, {\n        x: p3.x,\n        y: m\n      }, p3 ];\n      p = p.map(projection);\n      return \"M\" + p[0] + \"C\" + p[1] + \" \" + p[2] + \" \" + p[3];\n    }\n    diagonal.source = function(x) {\n      if (!arguments.length) return source;\n      source = d3_functor(x);\n      return diagonal;\n    };\n    diagonal.target = function(x) {\n      if (!arguments.length) return target;\n      target = d3_functor(x);\n      return diagonal;\n    };\n    diagonal.projection = function(x) {\n      if (!arguments.length) return projection;\n      projection = x;\n      return diagonal;\n    };\n    return diagonal;\n  };\n  function d3_svg_diagonalProjection(d) {\n    return [ d.x, d.y ];\n  }\n  d3.svg.diagonal.radial = function() {\n    var diagonal = d3.svg.diagonal(), projection = d3_svg_diagonalProjection, projection_ = diagonal.projection;\n    diagonal.projection = function(x) {\n      return arguments.length ? projection_(d3_svg_diagonalRadialProjection(projection = x)) : projection;\n    };\n    return diagonal;\n  };\n  function d3_svg_diagonalRadialProjection(projection) {\n    return function() {\n      var d = projection.apply(this, arguments), r = d[0], a = d[1] + d3_svg_arcOffset;\n      return [ r * Math.cos(a), r * Math.sin(a) ];\n    };\n  }\n  d3.svg.symbol = function() {\n    var type = d3_svg_symbolType, size = d3_svg_symbolSize;\n    function symbol(d, i) {\n      return (d3_svg_symbols.get(type.call(this, d, i)) || d3_svg_symbolCircle)(size.call(this, d, i));\n    }\n    symbol.type = function(x) {\n      if (!arguments.length) return type;\n      type = d3_functor(x);\n      return symbol;\n    };\n    symbol.size = function(x) {\n      if (!arguments.length) return size;\n      size = d3_functor(x);\n      return symbol;\n    };\n    return symbol;\n  };\n  function d3_svg_symbolSize() {\n    return 64;\n  }\n  function d3_svg_symbolType() {\n    return \"circle\";\n  }\n  function d3_svg_symbolCircle(size) {\n    var r = Math.sqrt(size / π);\n    return \"M0,\" + r + \"A\" + r + \",\" + r + \" 0 1,1 0,\" + -r + \"A\" + r + \",\" + r + \" 0 1,1 0,\" + r + \"Z\";\n  }\n  var d3_svg_symbols = d3.map({\n    circle: d3_svg_symbolCircle,\n    cross: function(size) {\n      var r = Math.sqrt(size / 5) / 2;\n      return \"M\" + -3 * r + \",\" + -r + \"H\" + -r + \"V\" + -3 * r + \"H\" + r + \"V\" + -r + \"H\" + 3 * r + \"V\" + r + \"H\" + r + \"V\" + 3 * r + \"H\" + -r + \"V\" + r + \"H\" + -3 * r + \"Z\";\n    },\n    diamond: function(size) {\n      var ry = Math.sqrt(size / (2 * d3_svg_symbolTan30)), rx = ry * d3_svg_symbolTan30;\n      return \"M0,\" + -ry + \"L\" + rx + \",0\" + \" 0,\" + ry + \" \" + -rx + \",0\" + \"Z\";\n    },\n    square: function(size) {\n      var r = Math.sqrt(size) / 2;\n      return \"M\" + -r + \",\" + -r + \"L\" + r + \",\" + -r + \" \" + r + \",\" + r + \" \" + -r + \",\" + r + \"Z\";\n    },\n    \"triangle-down\": function(size) {\n      var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2;\n      return \"M0,\" + ry + \"L\" + rx + \",\" + -ry + \" \" + -rx + \",\" + -ry + \"Z\";\n    },\n    \"triangle-up\": function(size) {\n      var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2;\n      return \"M0,\" + -ry + \"L\" + rx + \",\" + ry + \" \" + -rx + \",\" + ry + \"Z\";\n    }\n  });\n  d3.svg.symbolTypes = d3_svg_symbols.keys();\n  var d3_svg_symbolSqrt3 = Math.sqrt(3), d3_svg_symbolTan30 = Math.tan(30 * d3_radians);\n  function d3_transition(groups, id) {\n    d3_arraySubclass(groups, d3_transitionPrototype);\n    groups.id = id;\n    return groups;\n  }\n  var d3_transitionPrototype = [], d3_transitionId = 0, d3_transitionInheritId, d3_transitionInherit = {\n    ease: d3_ease_cubicInOut,\n    delay: 0,\n    duration: 250\n  };\n  d3_transitionPrototype.call = d3_selectionPrototype.call;\n  d3_transitionPrototype.empty = d3_selectionPrototype.empty;\n  d3_transitionPrototype.node = d3_selectionPrototype.node;\n  d3.transition = function(selection) {\n    return arguments.length ? d3_transitionInheritId ? selection.transition() : selection : d3_selectionRoot.transition();\n  };\n  d3.transition.prototype = d3_transitionPrototype;\n  d3_transitionPrototype.select = function(selector) {\n    var id = this.id, subgroups = [], subgroup, subnode, node;\n    if (typeof selector !== \"function\") selector = d3_selection_selector(selector);\n    for (var j = -1, m = this.length; ++j < m; ) {\n      subgroups.push(subgroup = []);\n      for (var group = this[j], i = -1, n = group.length; ++i < n; ) {\n        if ((node = group[i]) && (subnode = selector.call(node, node.__data__, i))) {\n          if (\"__data__\" in node) subnode.__data__ = node.__data__;\n          d3_transitionNode(subnode, i, id, node.__transition__[id]);\n          subgroup.push(subnode);\n        } else {\n          subgroup.push(null);\n        }\n      }\n    }\n    return d3_transition(subgroups, id);\n  };\n  d3_transitionPrototype.selectAll = function(selector) {\n    var id = this.id, subgroups = [], subgroup, subnodes, node, subnode, transition;\n    if (typeof selector !== \"function\") selector = d3_selection_selectorAll(selector);\n    for (var j = -1, m = this.length; ++j < m; ) {\n      for (var group = this[j], i = -1, n = group.length; ++i < n; ) {\n        if (node = group[i]) {\n          transition = node.__transition__[id];\n          subnodes = selector.call(node, node.__data__, i);\n          subgroups.push(subgroup = []);\n          for (var k = -1, o = subnodes.length; ++k < o; ) {\n            d3_transitionNode(subnode = subnodes[k], k, id, transition);\n            subgroup.push(subnode);\n          }\n        }\n      }\n    }\n    return d3_transition(subgroups, id);\n  };\n  d3_transitionPrototype.filter = function(filter) {\n    var subgroups = [], subgroup, group, node;\n    if (typeof filter !== \"function\") filter = d3_selection_filter(filter);\n    for (var j = 0, m = this.length; j < m; j++) {\n      subgroups.push(subgroup = []);\n      for (var group = this[j], i = 0, n = group.length; i < n; i++) {\n        if ((node = group[i]) && filter.call(node, node.__data__, i)) {\n          subgroup.push(node);\n        }\n      }\n    }\n    return d3_transition(subgroups, this.id, this.time).ease(this.ease());\n  };\n  d3_transitionPrototype.tween = function(name, tween) {\n    var id = this.id;\n    if (arguments.length < 2) return this.node().__transition__[id].tween.get(name);\n    return d3_selection_each(this, tween == null ? function(node) {\n      node.__transition__[id].tween.remove(name);\n    } : function(node) {\n      node.__transition__[id].tween.set(name, tween);\n    });\n  };\n  function d3_transition_tween(groups, name, value, tween) {\n    var id = groups.id;\n    return d3_selection_each(groups, typeof value === \"function\" ? function(node, i, j) {\n      node.__transition__[id].tween.set(name, tween(value.call(node, node.__data__, i, j)));\n    } : (value = tween(value), function(node) {\n      node.__transition__[id].tween.set(name, value);\n    }));\n  }\n  d3_transitionPrototype.attr = function(nameNS, value) {\n    if (arguments.length < 2) {\n      for (value in nameNS) this.attr(value, nameNS[value]);\n      return this;\n    }\n    var interpolate = d3_interpolateByName(nameNS), name = d3.ns.qualify(nameNS);\n    function attrNull() {\n      this.removeAttribute(name);\n    }\n    function attrNullNS() {\n      this.removeAttributeNS(name.space, name.local);\n    }\n    return d3_transition_tween(this, \"attr.\" + nameNS, value, function(b) {\n      function attrString() {\n        var a = this.getAttribute(name), i;\n        return a !== b && (i = interpolate(a, b), function(t) {\n          this.setAttribute(name, i(t));\n        });\n      }\n      function attrStringNS() {\n        var a = this.getAttributeNS(name.space, name.local), i;\n        return a !== b && (i = interpolate(a, b), function(t) {\n          this.setAttributeNS(name.space, name.local, i(t));\n        });\n      }\n      return b == null ? name.local ? attrNullNS : attrNull : (b += \"\", name.local ? attrStringNS : attrString);\n    });\n  };\n  d3_transitionPrototype.attrTween = function(nameNS, tween) {\n    var name = d3.ns.qualify(nameNS);\n    function attrTween(d, i) {\n      var f = tween.call(this, d, i, this.getAttribute(name));\n      return f && function(t) {\n        this.setAttribute(name, f(t));\n      };\n    }\n    function attrTweenNS(d, i) {\n      var f = tween.call(this, d, i, this.getAttributeNS(name.space, name.local));\n      return f && function(t) {\n        this.setAttributeNS(name.space, name.local, f(t));\n      };\n    }\n    return this.tween(\"attr.\" + nameNS, name.local ? attrTweenNS : attrTween);\n  };\n  d3_transitionPrototype.style = function(name, value, priority) {\n    var n = arguments.length;\n    if (n < 3) {\n      if (typeof name !== \"string\") {\n        if (n < 2) value = \"\";\n        for (priority in name) this.style(priority, name[priority], value);\n        return this;\n      }\n      priority = \"\";\n    }\n    var interpolate = d3_interpolateByName(name);\n    function styleNull() {\n      this.style.removeProperty(name);\n    }\n    return d3_transition_tween(this, \"style.\" + name, value, function(b) {\n      function styleString() {\n        var a = d3_window.getComputedStyle(this, null).getPropertyValue(name), i;\n        return a !== b && (i = interpolate(a, b), function(t) {\n          this.style.setProperty(name, i(t), priority);\n        });\n      }\n      return b == null ? styleNull : (b += \"\", styleString);\n    });\n  };\n  d3_transitionPrototype.styleTween = function(name, tween, priority) {\n    if (arguments.length < 3) priority = \"\";\n    return this.tween(\"style.\" + name, function(d, i) {\n      var f = tween.call(this, d, i, d3_window.getComputedStyle(this, null).getPropertyValue(name));\n      return f && function(t) {\n        this.style.setProperty(name, f(t), priority);\n      };\n    });\n  };\n  d3_transitionPrototype.text = function(value) {\n    return d3_transition_tween(this, \"text\", value, d3_transition_text);\n  };\n  function d3_transition_text(b) {\n    if (b == null) b = \"\";\n    return function() {\n      this.textContent = b;\n    };\n  }\n  d3_transitionPrototype.remove = function() {\n    return this.each(\"end.transition\", function() {\n      var p;\n      if (!this.__transition__ && (p = this.parentNode)) p.removeChild(this);\n    });\n  };\n  d3_transitionPrototype.ease = function(value) {\n    var id = this.id;\n    if (arguments.length < 1) return this.node().__transition__[id].ease;\n    if (typeof value !== \"function\") value = d3.ease.apply(d3, arguments);\n    return d3_selection_each(this, function(node) {\n      node.__transition__[id].ease = value;\n    });\n  };\n  d3_transitionPrototype.delay = function(value) {\n    var id = this.id;\n    return d3_selection_each(this, typeof value === \"function\" ? function(node, i, j) {\n      node.__transition__[id].delay = value.call(node, node.__data__, i, j) | 0;\n    } : (value |= 0, function(node) {\n      node.__transition__[id].delay = value;\n    }));\n  };\n  d3_transitionPrototype.duration = function(value) {\n    var id = this.id;\n    return d3_selection_each(this, typeof value === \"function\" ? function(node, i, j) {\n      node.__transition__[id].duration = Math.max(1, value.call(node, node.__data__, i, j) | 0);\n    } : (value = Math.max(1, value | 0), function(node) {\n      node.__transition__[id].duration = value;\n    }));\n  };\n  d3_transitionPrototype.each = function(type, listener) {\n    var id = this.id;\n    if (arguments.length < 2) {\n      var inherit = d3_transitionInherit, inheritId = d3_transitionInheritId;\n      d3_transitionInheritId = id;\n      d3_selection_each(this, function(node, i, j) {\n        d3_transitionInherit = node.__transition__[id];\n        type.call(node, node.__data__, i, j);\n      });\n      d3_transitionInherit = inherit;\n      d3_transitionInheritId = inheritId;\n    } else {\n      d3_selection_each(this, function(node) {\n        node.__transition__[id].event.on(type, listener);\n      });\n    }\n    return this;\n  };\n  d3_transitionPrototype.transition = function() {\n    var id0 = this.id, id1 = ++d3_transitionId, subgroups = [], subgroup, group, node, transition;\n    for (var j = 0, m = this.length; j < m; j++) {\n      subgroups.push(subgroup = []);\n      for (var group = this[j], i = 0, n = group.length; i < n; i++) {\n        if (node = group[i]) {\n          transition = Object.create(node.__transition__[id0]);\n          transition.delay += transition.duration;\n          d3_transitionNode(node, i, id1, transition);\n        }\n        subgroup.push(node);\n      }\n    }\n    return d3_transition(subgroups, id1);\n  };\n  function d3_transitionNode(node, i, id, inherit) {\n    var lock = node.__transition__ || (node.__transition__ = {\n      active: 0,\n      count: 0\n    }), transition = lock[id];\n    if (!transition) {\n      var time = inherit.time;\n      transition = lock[id] = {\n        tween: new d3_Map(),\n        event: d3.dispatch(\"start\", \"end\"),\n        time: time,\n        ease: inherit.ease,\n        delay: inherit.delay,\n        duration: inherit.duration\n      };\n      ++lock.count;\n      d3.timer(function(elapsed) {\n        var d = node.__data__, ease = transition.ease, event = transition.event, delay = transition.delay, duration = transition.duration, tweened = [];\n        return delay <= elapsed ? start(elapsed) : d3.timer(start, delay, time), 1;\n        function start(elapsed) {\n          if (lock.active > id) return stop();\n          lock.active = id;\n          event.start.call(node, d, i);\n          transition.tween.forEach(function(key, value) {\n            if (value = value.call(node, d, i)) {\n              tweened.push(value);\n            }\n          });\n          if (!tick(elapsed)) d3.timer(tick, 0, time);\n          return 1;\n        }\n        function tick(elapsed) {\n          if (lock.active !== id) return stop();\n          var t = (elapsed - delay) / duration, e = ease(t), n = tweened.length;\n          while (n > 0) {\n            tweened[--n].call(node, e);\n          }\n          if (t >= 1) {\n            stop();\n            event.end.call(node, d, i);\n            return 1;\n          }\n        }\n        function stop() {\n          if (--lock.count) delete lock[id]; else delete node.__transition__;\n          return 1;\n        }\n      }, 0, time);\n      return transition;\n    }\n  }\n  d3.svg.axis = function() {\n    var scale = d3.scale.linear(), orient = d3_svg_axisDefaultOrient, tickMajorSize = 6, tickMinorSize = 6, tickEndSize = 6, tickPadding = 3, tickArguments_ = [ 10 ], tickValues = null, tickFormat_, tickSubdivide = 0;\n    function axis(g) {\n      g.each(function() {\n        var g = d3.select(this);\n        var ticks = tickValues == null ? scale.ticks ? scale.ticks.apply(scale, tickArguments_) : scale.domain() : tickValues, tickFormat = tickFormat_ == null ? scale.tickFormat ? scale.tickFormat.apply(scale, tickArguments_) : String : tickFormat_;\n        var subticks = d3_svg_axisSubdivide(scale, ticks, tickSubdivide), subtick = g.selectAll(\".tick.minor\").data(subticks, String), subtickEnter = subtick.enter().insert(\"line\", \".tick\").attr(\"class\", \"tick minor\").style(\"opacity\", 1e-6), subtickExit = d3.transition(subtick.exit()).style(\"opacity\", 1e-6).remove(), subtickUpdate = d3.transition(subtick).style(\"opacity\", 1);\n        var tick = g.selectAll(\".tick.major\").data(ticks, String), tickEnter = tick.enter().insert(\"g\", \"path\").attr(\"class\", \"tick major\").style(\"opacity\", 1e-6), tickExit = d3.transition(tick.exit()).style(\"opacity\", 1e-6).remove(), tickUpdate = d3.transition(tick).style(\"opacity\", 1), tickTransform;\n        var range = d3_scaleRange(scale), path = g.selectAll(\".domain\").data([ 0 ]), pathUpdate = (path.enter().append(\"path\").attr(\"class\", \"domain\"), \n        d3.transition(path));\n        var scale1 = scale.copy(), scale0 = this.__chart__ || scale1;\n        this.__chart__ = scale1;\n        tickEnter.append(\"line\");\n        tickEnter.append(\"text\");\n        var lineEnter = tickEnter.select(\"line\"), lineUpdate = tickUpdate.select(\"line\"), text = tick.select(\"text\").text(tickFormat), textEnter = tickEnter.select(\"text\"), textUpdate = tickUpdate.select(\"text\");\n        switch (orient) {\n         case \"bottom\":\n          {\n            tickTransform = d3_svg_axisX;\n            subtickEnter.attr(\"y2\", tickMinorSize);\n            subtickUpdate.attr(\"x2\", 0).attr(\"y2\", tickMinorSize);\n            lineEnter.attr(\"y2\", tickMajorSize);\n            textEnter.attr(\"y\", Math.max(tickMajorSize, 0) + tickPadding);\n            lineUpdate.attr(\"x2\", 0).attr(\"y2\", tickMajorSize);\n            textUpdate.attr(\"x\", 0).attr(\"y\", Math.max(tickMajorSize, 0) + tickPadding);\n            text.attr(\"dy\", \".71em\").style(\"text-anchor\", \"middle\");\n            pathUpdate.attr(\"d\", \"M\" + range[0] + \",\" + tickEndSize + \"V0H\" + range[1] + \"V\" + tickEndSize);\n            break;\n          }\n\n         case \"top\":\n          {\n            tickTransform = d3_svg_axisX;\n            subtickEnter.attr(\"y2\", -tickMinorSize);\n            subtickUpdate.attr(\"x2\", 0).attr(\"y2\", -tickMinorSize);\n            lineEnter.attr(\"y2\", -tickMajorSize);\n            textEnter.attr(\"y\", -(Math.max(tickMajorSize, 0) + tickPadding));\n            lineUpdate.attr(\"x2\", 0).attr(\"y2\", -tickMajorSize);\n            textUpdate.attr(\"x\", 0).attr(\"y\", -(Math.max(tickMajorSize, 0) + tickPadding));\n            text.attr(\"dy\", \"0em\").style(\"text-anchor\", \"middle\");\n            pathUpdate.attr(\"d\", \"M\" + range[0] + \",\" + -tickEndSize + \"V0H\" + range[1] + \"V\" + -tickEndSize);\n            break;\n          }\n\n         case \"left\":\n          {\n            tickTransform = d3_svg_axisY;\n            subtickEnter.attr(\"x2\", -tickMinorSize);\n            subtickUpdate.attr(\"x2\", -tickMinorSize).attr(\"y2\", 0);\n            lineEnter.attr(\"x2\", -tickMajorSize);\n            textEnter.attr(\"x\", -(Math.max(tickMajorSize, 0) + tickPadding));\n            lineUpdate.attr(\"x2\", -tickMajorSize).attr(\"y2\", 0);\n            textUpdate.attr(\"x\", -(Math.max(tickMajorSize, 0) + tickPadding)).attr(\"y\", 0);\n            text.attr(\"dy\", \".32em\").style(\"text-anchor\", \"end\");\n            pathUpdate.attr(\"d\", \"M\" + -tickEndSize + \",\" + range[0] + \"H0V\" + range[1] + \"H\" + -tickEndSize);\n            break;\n          }\n\n         case \"right\":\n          {\n            tickTransform = d3_svg_axisY;\n            subtickEnter.attr(\"x2\", tickMinorSize);\n            subtickUpdate.attr(\"x2\", tickMinorSize).attr(\"y2\", 0);\n            lineEnter.attr(\"x2\", tickMajorSize);\n            textEnter.attr(\"x\", Math.max(tickMajorSize, 0) + tickPadding);\n            lineUpdate.attr(\"x2\", tickMajorSize).attr(\"y2\", 0);\n            textUpdate.attr(\"x\", Math.max(tickMajorSize, 0) + tickPadding).attr(\"y\", 0);\n            text.attr(\"dy\", \".32em\").style(\"text-anchor\", \"start\");\n            pathUpdate.attr(\"d\", \"M\" + tickEndSize + \",\" + range[0] + \"H0V\" + range[1] + \"H\" + tickEndSize);\n            break;\n          }\n        }\n        if (scale.ticks) {\n          tickEnter.call(tickTransform, scale0);\n          tickUpdate.call(tickTransform, scale1);\n          tickExit.call(tickTransform, scale1);\n          subtickEnter.call(tickTransform, scale0);\n          subtickUpdate.call(tickTransform, scale1);\n          subtickExit.call(tickTransform, scale1);\n        } else {\n          var dx = scale1.rangeBand() / 2, x = function(d) {\n            return scale1(d) + dx;\n          };\n          tickEnter.call(tickTransform, x);\n          tickUpdate.call(tickTransform, x);\n        }\n      });\n    }\n    axis.scale = function(x) {\n      if (!arguments.length) return scale;\n      scale = x;\n      return axis;\n    };\n    axis.orient = function(x) {\n      if (!arguments.length) return orient;\n      orient = x in d3_svg_axisOrients ? x + \"\" : d3_svg_axisDefaultOrient;\n      return axis;\n    };\n    axis.ticks = function() {\n      if (!arguments.length) return tickArguments_;\n      tickArguments_ = arguments;\n      return axis;\n    };\n    axis.tickValues = function(x) {\n      if (!arguments.length) return tickValues;\n      tickValues = x;\n      return axis;\n    };\n    axis.tickFormat = function(x) {\n      if (!arguments.length) return tickFormat_;\n      tickFormat_ = x;\n      return axis;\n    };\n    axis.tickSize = function(x, y) {\n      if (!arguments.length) return tickMajorSize;\n      var n = arguments.length - 1;\n      tickMajorSize = +x;\n      tickMinorSize = n > 1 ? +y : tickMajorSize;\n      tickEndSize = n > 0 ? +arguments[n] : tickMajorSize;\n      return axis;\n    };\n    axis.tickPadding = function(x) {\n      if (!arguments.length) return tickPadding;\n      tickPadding = +x;\n      return axis;\n    };\n    axis.tickSubdivide = function(x) {\n      if (!arguments.length) return tickSubdivide;\n      tickSubdivide = +x;\n      return axis;\n    };\n    return axis;\n  };\n  var d3_svg_axisDefaultOrient = \"bottom\", d3_svg_axisOrients = {\n    top: 1,\n    right: 1,\n    bottom: 1,\n    left: 1\n  };\n  function d3_svg_axisX(selection, x) {\n    selection.attr(\"transform\", function(d) {\n      return \"translate(\" + x(d) + \",0)\";\n    });\n  }\n  function d3_svg_axisY(selection, y) {\n    selection.attr(\"transform\", function(d) {\n      return \"translate(0,\" + y(d) + \")\";\n    });\n  }\n  function d3_svg_axisSubdivide(scale, ticks, m) {\n    subticks = [];\n    if (m && ticks.length > 1) {\n      var extent = d3_scaleExtent(scale.domain()), subticks, i = -1, n = ticks.length, d = (ticks[1] - ticks[0]) / ++m, j, v;\n      while (++i < n) {\n        for (j = m; --j > 0; ) {\n          if ((v = +ticks[i] - j * d) >= extent[0]) {\n            subticks.push(v);\n          }\n        }\n      }\n      for (--i, j = 0; ++j < m && (v = +ticks[i] + j * d) < extent[1]; ) {\n        subticks.push(v);\n      }\n    }\n    return subticks;\n  }\n  d3.svg.brush = function() {\n    var event = d3_eventDispatch(brush, \"brushstart\", \"brush\", \"brushend\"), x = null, y = null, resizes = d3_svg_brushResizes[0], extent = [ [ 0, 0 ], [ 0, 0 ] ], extentDomain;\n    function brush(g) {\n      g.each(function() {\n        var g = d3.select(this), bg = g.selectAll(\".background\").data([ 0 ]), fg = g.selectAll(\".extent\").data([ 0 ]), tz = g.selectAll(\".resize\").data(resizes, String), e;\n        g.style(\"pointer-events\", \"all\").on(\"mousedown.brush\", brushstart).on(\"touchstart.brush\", brushstart);\n        bg.enter().append(\"rect\").attr(\"class\", \"background\").style(\"visibility\", \"hidden\").style(\"cursor\", \"crosshair\");\n        fg.enter().append(\"rect\").attr(\"class\", \"extent\").style(\"cursor\", \"move\");\n        tz.enter().append(\"g\").attr(\"class\", function(d) {\n          return \"resize \" + d;\n        }).style(\"cursor\", function(d) {\n          return d3_svg_brushCursor[d];\n        }).append(\"rect\").attr(\"x\", function(d) {\n          return /[ew]$/.test(d) ? -3 : null;\n        }).attr(\"y\", function(d) {\n          return /^[ns]/.test(d) ? -3 : null;\n        }).attr(\"width\", 6).attr(\"height\", 6).style(\"visibility\", \"hidden\");\n        tz.style(\"display\", brush.empty() ? \"none\" : null);\n        tz.exit().remove();\n        if (x) {\n          e = d3_scaleRange(x);\n          bg.attr(\"x\", e[0]).attr(\"width\", e[1] - e[0]);\n          redrawX(g);\n        }\n        if (y) {\n          e = d3_scaleRange(y);\n          bg.attr(\"y\", e[0]).attr(\"height\", e[1] - e[0]);\n          redrawY(g);\n        }\n        redraw(g);\n      });\n    }\n    function redraw(g) {\n      g.selectAll(\".resize\").attr(\"transform\", function(d) {\n        return \"translate(\" + extent[+/e$/.test(d)][0] + \",\" + extent[+/^s/.test(d)][1] + \")\";\n      });\n    }\n    function redrawX(g) {\n      g.select(\".extent\").attr(\"x\", extent[0][0]);\n      g.selectAll(\".extent,.n>rect,.s>rect\").attr(\"width\", extent[1][0] - extent[0][0]);\n    }\n    function redrawY(g) {\n      g.select(\".extent\").attr(\"y\", extent[0][1]);\n      g.selectAll(\".extent,.e>rect,.w>rect\").attr(\"height\", extent[1][1] - extent[0][1]);\n    }\n    function brushstart() {\n      var target = this, eventTarget = d3.select(d3.event.target), event_ = event.of(target, arguments), g = d3.select(target), resizing = eventTarget.datum(), resizingX = !/^(n|s)$/.test(resizing) && x, resizingY = !/^(e|w)$/.test(resizing) && y, dragging = eventTarget.classed(\"extent\"), center, origin = mouse(), offset;\n      var w = d3.select(d3_window).on(\"mousemove.brush\", brushmove).on(\"mouseup.brush\", brushend).on(\"touchmove.brush\", brushmove).on(\"touchend.brush\", brushend).on(\"keydown.brush\", keydown).on(\"keyup.brush\", keyup);\n      if (dragging) {\n        origin[0] = extent[0][0] - origin[0];\n        origin[1] = extent[0][1] - origin[1];\n      } else if (resizing) {\n        var ex = +/w$/.test(resizing), ey = +/^n/.test(resizing);\n        offset = [ extent[1 - ex][0] - origin[0], extent[1 - ey][1] - origin[1] ];\n        origin[0] = extent[ex][0];\n        origin[1] = extent[ey][1];\n      } else if (d3.event.altKey) center = origin.slice();\n      g.style(\"pointer-events\", \"none\").selectAll(\".resize\").style(\"display\", null);\n      d3.select(\"body\").style(\"cursor\", eventTarget.style(\"cursor\"));\n      event_({\n        type: \"brushstart\"\n      });\n      brushmove();\n      d3_eventCancel();\n      function mouse() {\n        var touches = d3.event.changedTouches;\n        return touches ? d3.touches(target, touches)[0] : d3.mouse(target);\n      }\n      function keydown() {\n        if (d3.event.keyCode == 32) {\n          if (!dragging) {\n            center = null;\n            origin[0] -= extent[1][0];\n            origin[1] -= extent[1][1];\n            dragging = 2;\n          }\n          d3_eventCancel();\n        }\n      }\n      function keyup() {\n        if (d3.event.keyCode == 32 && dragging == 2) {\n          origin[0] += extent[1][0];\n          origin[1] += extent[1][1];\n          dragging = 0;\n          d3_eventCancel();\n        }\n      }\n      function brushmove() {\n        var point = mouse(), moved = false;\n        if (offset) {\n          point[0] += offset[0];\n          point[1] += offset[1];\n        }\n        if (!dragging) {\n          if (d3.event.altKey) {\n            if (!center) center = [ (extent[0][0] + extent[1][0]) / 2, (extent[0][1] + extent[1][1]) / 2 ];\n            origin[0] = extent[+(point[0] < center[0])][0];\n            origin[1] = extent[+(point[1] < center[1])][1];\n          } else center = null;\n        }\n        if (resizingX && move1(point, x, 0)) {\n          redrawX(g);\n          moved = true;\n        }\n        if (resizingY && move1(point, y, 1)) {\n          redrawY(g);\n          moved = true;\n        }\n        if (moved) {\n          redraw(g);\n          event_({\n            type: \"brush\",\n            mode: dragging ? \"move\" : \"resize\"\n          });\n        }\n      }\n      function move1(point, scale, i) {\n        var range = d3_scaleRange(scale), r0 = range[0], r1 = range[1], position = origin[i], size = extent[1][i] - extent[0][i], min, max;\n        if (dragging) {\n          r0 -= position;\n          r1 -= size + position;\n        }\n        min = Math.max(r0, Math.min(r1, point[i]));\n        if (dragging) {\n          max = (min += position) + size;\n        } else {\n          if (center) position = Math.max(r0, Math.min(r1, 2 * center[i] - min));\n          if (position < min) {\n            max = min;\n            min = position;\n          } else {\n            max = position;\n          }\n        }\n        if (extent[0][i] !== min || extent[1][i] !== max) {\n          extentDomain = null;\n          extent[0][i] = min;\n          extent[1][i] = max;\n          return true;\n        }\n      }\n      function brushend() {\n        brushmove();\n        g.style(\"pointer-events\", \"all\").selectAll(\".resize\").style(\"display\", brush.empty() ? \"none\" : null);\n        d3.select(\"body\").style(\"cursor\", null);\n        w.on(\"mousemove.brush\", null).on(\"mouseup.brush\", null).on(\"touchmove.brush\", null).on(\"touchend.brush\", null).on(\"keydown.brush\", null).on(\"keyup.brush\", null);\n        event_({\n          type: \"brushend\"\n        });\n        d3_eventCancel();\n      }\n    }\n    brush.x = function(z) {\n      if (!arguments.length) return x;\n      x = z;\n      resizes = d3_svg_brushResizes[!x << 1 | !y];\n      return brush;\n    };\n    brush.y = function(z) {\n      if (!arguments.length) return y;\n      y = z;\n      resizes = d3_svg_brushResizes[!x << 1 | !y];\n      return brush;\n    };\n    brush.extent = function(z) {\n      var x0, x1, y0, y1, t;\n      if (!arguments.length) {\n        z = extentDomain || extent;\n        if (x) {\n          x0 = z[0][0], x1 = z[1][0];\n          if (!extentDomain) {\n            x0 = extent[0][0], x1 = extent[1][0];\n            if (x.invert) x0 = x.invert(x0), x1 = x.invert(x1);\n            if (x1 < x0) t = x0, x0 = x1, x1 = t;\n          }\n        }\n        if (y) {\n          y0 = z[0][1], y1 = z[1][1];\n          if (!extentDomain) {\n            y0 = extent[0][1], y1 = extent[1][1];\n            if (y.invert) y0 = y.invert(y0), y1 = y.invert(y1);\n            if (y1 < y0) t = y0, y0 = y1, y1 = t;\n          }\n        }\n        return x && y ? [ [ x0, y0 ], [ x1, y1 ] ] : x ? [ x0, x1 ] : y && [ y0, y1 ];\n      }\n      extentDomain = [ [ 0, 0 ], [ 0, 0 ] ];\n      if (x) {\n        x0 = z[0], x1 = z[1];\n        if (y) x0 = x0[0], x1 = x1[0];\n        extentDomain[0][0] = x0, extentDomain[1][0] = x1;\n        if (x.invert) x0 = x(x0), x1 = x(x1);\n        if (x1 < x0) t = x0, x0 = x1, x1 = t;\n        extent[0][0] = x0 | 0, extent[1][0] = x1 | 0;\n      }\n      if (y) {\n        y0 = z[0], y1 = z[1];\n        if (x) y0 = y0[1], y1 = y1[1];\n        extentDomain[0][1] = y0, extentDomain[1][1] = y1;\n        if (y.invert) y0 = y(y0), y1 = y(y1);\n        if (y1 < y0) t = y0, y0 = y1, y1 = t;\n        extent[0][1] = y0 | 0, extent[1][1] = y1 | 0;\n      }\n      return brush;\n    };\n    brush.clear = function() {\n      extentDomain = null;\n      extent[0][0] = extent[0][1] = extent[1][0] = extent[1][1] = 0;\n      return brush;\n    };\n    brush.empty = function() {\n      return x && extent[0][0] === extent[1][0] || y && extent[0][1] === extent[1][1];\n    };\n    return d3.rebind(brush, event, \"on\");\n  };\n  var d3_svg_brushCursor = {\n    n: \"ns-resize\",\n    e: \"ew-resize\",\n    s: \"ns-resize\",\n    w: \"ew-resize\",\n    nw: \"nwse-resize\",\n    ne: \"nesw-resize\",\n    se: \"nwse-resize\",\n    sw: \"nesw-resize\"\n  };\n  var d3_svg_brushResizes = [ [ \"n\", \"e\", \"s\", \"w\", \"nw\", \"ne\", \"se\", \"sw\" ], [ \"e\", \"w\" ], [ \"n\", \"s\" ], [] ];\n  d3.time = {};\n  var d3_time = Date, d3_time_daySymbols = [ \"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\" ];\n  function d3_time_utc() {\n    this._ = new Date(arguments.length > 1 ? Date.UTC.apply(this, arguments) : arguments[0]);\n  }\n  d3_time_utc.prototype = {\n    getDate: function() {\n      return this._.getUTCDate();\n    },\n    getDay: function() {\n      return this._.getUTCDay();\n    },\n    getFullYear: function() {\n      return this._.getUTCFullYear();\n    },\n    getHours: function() {\n      return this._.getUTCHours();\n    },\n    getMilliseconds: function() {\n      return this._.getUTCMilliseconds();\n    },\n    getMinutes: function() {\n      return this._.getUTCMinutes();\n    },\n    getMonth: function() {\n      return this._.getUTCMonth();\n    },\n    getSeconds: function() {\n      return this._.getUTCSeconds();\n    },\n    getTime: function() {\n      return this._.getTime();\n    },\n    getTimezoneOffset: function() {\n      return 0;\n    },\n    valueOf: function() {\n      return this._.valueOf();\n    },\n    setDate: function() {\n      d3_time_prototype.setUTCDate.apply(this._, arguments);\n    },\n    setDay: function() {\n      d3_time_prototype.setUTCDay.apply(this._, arguments);\n    },\n    setFullYear: function() {\n      d3_time_prototype.setUTCFullYear.apply(this._, arguments);\n    },\n    setHours: function() {\n      d3_time_prototype.setUTCHours.apply(this._, arguments);\n    },\n    setMilliseconds: function() {\n      d3_time_prototype.setUTCMilliseconds.apply(this._, arguments);\n    },\n    setMinutes: function() {\n      d3_time_prototype.setUTCMinutes.apply(this._, arguments);\n    },\n    setMonth: function() {\n      d3_time_prototype.setUTCMonth.apply(this._, arguments);\n    },\n    setSeconds: function() {\n      d3_time_prototype.setUTCSeconds.apply(this._, arguments);\n    },\n    setTime: function() {\n      d3_time_prototype.setTime.apply(this._, arguments);\n    }\n  };\n  var d3_time_prototype = Date.prototype;\n  var d3_time_formatDateTime = \"%a %b %e %X %Y\", d3_time_formatDate = \"%m/%d/%Y\", d3_time_formatTime = \"%H:%M:%S\";\n  var d3_time_days = [ \"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\" ], d3_time_dayAbbreviations = [ \"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\" ], d3_time_months = [ \"January\", \"February\", \"March\", \"April\", \"May\", \"June\", \"July\", \"August\", \"September\", \"October\", \"November\", \"December\" ], d3_time_monthAbbreviations = [ \"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\" ];\n  function d3_time_interval(local, step, number) {\n    function round(date) {\n      var d0 = local(date), d1 = offset(d0, 1);\n      return date - d0 < d1 - date ? d0 : d1;\n    }\n    function ceil(date) {\n      step(date = local(new d3_time(date - 1)), 1);\n      return date;\n    }\n    function offset(date, k) {\n      step(date = new d3_time(+date), k);\n      return date;\n    }\n    function range(t0, t1, dt) {\n      var time = ceil(t0), times = [];\n      if (dt > 1) {\n        while (time < t1) {\n          if (!(number(time) % dt)) times.push(new Date(+time));\n          step(time, 1);\n        }\n      } else {\n        while (time < t1) times.push(new Date(+time)), step(time, 1);\n      }\n      return times;\n    }\n    function range_utc(t0, t1, dt) {\n      try {\n        d3_time = d3_time_utc;\n        var utc = new d3_time_utc();\n        utc._ = t0;\n        return range(utc, t1, dt);\n      } finally {\n        d3_time = Date;\n      }\n    }\n    local.floor = local;\n    local.round = round;\n    local.ceil = ceil;\n    local.offset = offset;\n    local.range = range;\n    var utc = local.utc = d3_time_interval_utc(local);\n    utc.floor = utc;\n    utc.round = d3_time_interval_utc(round);\n    utc.ceil = d3_time_interval_utc(ceil);\n    utc.offset = d3_time_interval_utc(offset);\n    utc.range = range_utc;\n    return local;\n  }\n  function d3_time_interval_utc(method) {\n    return function(date, k) {\n      try {\n        d3_time = d3_time_utc;\n        var utc = new d3_time_utc();\n        utc._ = date;\n        return method(utc, k)._;\n      } finally {\n        d3_time = Date;\n      }\n    };\n  }\n  d3.time.year = d3_time_interval(function(date) {\n    date = d3.time.day(date);\n    date.setMonth(0, 1);\n    return date;\n  }, function(date, offset) {\n    date.setFullYear(date.getFullYear() + offset);\n  }, function(date) {\n    return date.getFullYear();\n  });\n  d3.time.years = d3.time.year.range;\n  d3.time.years.utc = d3.time.year.utc.range;\n  d3.time.day = d3_time_interval(function(date) {\n    var day = new d3_time(1970, 0);\n    day.setFullYear(date.getFullYear(), date.getMonth(), date.getDate());\n    return day;\n  }, function(date, offset) {\n    date.setDate(date.getDate() + offset);\n  }, function(date) {\n    return date.getDate() - 1;\n  });\n  d3.time.days = d3.time.day.range;\n  d3.time.days.utc = d3.time.day.utc.range;\n  d3.time.dayOfYear = function(date) {\n    var year = d3.time.year(date);\n    return Math.floor((date - year - (date.getTimezoneOffset() - year.getTimezoneOffset()) * 6e4) / 864e5);\n  };\n  d3_time_daySymbols.forEach(function(day, i) {\n    day = day.toLowerCase();\n    i = 7 - i;\n    var interval = d3.time[day] = d3_time_interval(function(date) {\n      (date = d3.time.day(date)).setDate(date.getDate() - (date.getDay() + i) % 7);\n      return date;\n    }, function(date, offset) {\n      date.setDate(date.getDate() + Math.floor(offset) * 7);\n    }, function(date) {\n      var day = d3.time.year(date).getDay();\n      return Math.floor((d3.time.dayOfYear(date) + (day + i) % 7) / 7) - (day !== i);\n    });\n    d3.time[day + \"s\"] = interval.range;\n    d3.time[day + \"s\"].utc = interval.utc.range;\n    d3.time[day + \"OfYear\"] = function(date) {\n      var day = d3.time.year(date).getDay();\n      return Math.floor((d3.time.dayOfYear(date) + (day + i) % 7) / 7);\n    };\n  });\n  d3.time.week = d3.time.sunday;\n  d3.time.weeks = d3.time.sunday.range;\n  d3.time.weeks.utc = d3.time.sunday.utc.range;\n  d3.time.weekOfYear = d3.time.sundayOfYear;\n  d3.time.format = function(template) {\n    var n = template.length;\n    function format(date) {\n      var string = [], i = -1, j = 0, c, p, f;\n      while (++i < n) {\n        if (template.charCodeAt(i) === 37) {\n          string.push(template.substring(j, i));\n          if ((p = d3_time_formatPads[c = template.charAt(++i)]) != null) c = template.charAt(++i);\n          if (f = d3_time_formats[c]) c = f(date, p == null ? c === \"e\" ? \" \" : \"0\" : p);\n          string.push(c);\n          j = i + 1;\n        }\n      }\n      string.push(template.substring(j, i));\n      return string.join(\"\");\n    }\n    format.parse = function(string) {\n      var d = {\n        y: 1900,\n        m: 0,\n        d: 1,\n        H: 0,\n        M: 0,\n        S: 0,\n        L: 0\n      }, i = d3_time_parse(d, template, string, 0);\n      if (i != string.length) return null;\n      if (\"p\" in d) d.H = d.H % 12 + d.p * 12;\n      var date = new d3_time();\n      date.setFullYear(d.y, d.m, d.d);\n      date.setHours(d.H, d.M, d.S, d.L);\n      return date;\n    };\n    format.toString = function() {\n      return template;\n    };\n    return format;\n  };\n  function d3_time_parse(date, template, string, j) {\n    var c, p, i = 0, n = template.length, m = string.length;\n    while (i < n) {\n      if (j >= m) return -1;\n      c = template.charCodeAt(i++);\n      if (c === 37) {\n        p = d3_time_parsers[template.charAt(i++)];\n        if (!p || (j = p(date, string, j)) < 0) return -1;\n      } else if (c != string.charCodeAt(j++)) {\n        return -1;\n      }\n    }\n    return j;\n  }\n  function d3_time_formatRe(names) {\n    return new RegExp(\"^(?:\" + names.map(d3.requote).join(\"|\") + \")\", \"i\");\n  }\n  function d3_time_formatLookup(names) {\n    var map = new d3_Map(), i = -1, n = names.length;\n    while (++i < n) map.set(names[i].toLowerCase(), i);\n    return map;\n  }\n  function d3_time_formatPad(value, fill, width) {\n    value += \"\";\n    var length = value.length;\n    return length < width ? new Array(width - length + 1).join(fill) + value : value;\n  }\n  var d3_time_dayRe = d3_time_formatRe(d3_time_days), d3_time_dayAbbrevRe = d3_time_formatRe(d3_time_dayAbbreviations), d3_time_monthRe = d3_time_formatRe(d3_time_months), d3_time_monthLookup = d3_time_formatLookup(d3_time_months), d3_time_monthAbbrevRe = d3_time_formatRe(d3_time_monthAbbreviations), d3_time_monthAbbrevLookup = d3_time_formatLookup(d3_time_monthAbbreviations);\n  var d3_time_formatPads = {\n    \"-\": \"\",\n    _: \" \",\n    \"0\": \"0\"\n  };\n  var d3_time_formats = {\n    a: function(d) {\n      return d3_time_dayAbbreviations[d.getDay()];\n    },\n    A: function(d) {\n      return d3_time_days[d.getDay()];\n    },\n    b: function(d) {\n      return d3_time_monthAbbreviations[d.getMonth()];\n    },\n    B: function(d) {\n      return d3_time_months[d.getMonth()];\n    },\n    c: d3.time.format(d3_time_formatDateTime),\n    d: function(d, p) {\n      return d3_time_formatPad(d.getDate(), p, 2);\n    },\n    e: function(d, p) {\n      return d3_time_formatPad(d.getDate(), p, 2);\n    },\n    H: function(d, p) {\n      return d3_time_formatPad(d.getHours(), p, 2);\n    },\n    I: function(d, p) {\n      return d3_time_formatPad(d.getHours() % 12 || 12, p, 2);\n    },\n    j: function(d, p) {\n      return d3_time_formatPad(1 + d3.time.dayOfYear(d), p, 3);\n    },\n    L: function(d, p) {\n      return d3_time_formatPad(d.getMilliseconds(), p, 3);\n    },\n    m: function(d, p) {\n      return d3_time_formatPad(d.getMonth() + 1, p, 2);\n    },\n    M: function(d, p) {\n      return d3_time_formatPad(d.getMinutes(), p, 2);\n    },\n    p: function(d) {\n      return d.getHours() >= 12 ? \"PM\" : \"AM\";\n    },\n    S: function(d, p) {\n      return d3_time_formatPad(d.getSeconds(), p, 2);\n    },\n    U: function(d, p) {\n      return d3_time_formatPad(d3.time.sundayOfYear(d), p, 2);\n    },\n    w: function(d) {\n      return d.getDay();\n    },\n    W: function(d, p) {\n      return d3_time_formatPad(d3.time.mondayOfYear(d), p, 2);\n    },\n    x: d3.time.format(d3_time_formatDate),\n    X: d3.time.format(d3_time_formatTime),\n    y: function(d, p) {\n      return d3_time_formatPad(d.getFullYear() % 100, p, 2);\n    },\n    Y: function(d, p) {\n      return d3_time_formatPad(d.getFullYear() % 1e4, p, 4);\n    },\n    Z: d3_time_zone,\n    \"%\": function() {\n      return \"%\";\n    }\n  };\n  var d3_time_parsers = {\n    a: d3_time_parseWeekdayAbbrev,\n    A: d3_time_parseWeekday,\n    b: d3_time_parseMonthAbbrev,\n    B: d3_time_parseMonth,\n    c: d3_time_parseLocaleFull,\n    d: d3_time_parseDay,\n    e: d3_time_parseDay,\n    H: d3_time_parseHour24,\n    I: d3_time_parseHour24,\n    L: d3_time_parseMilliseconds,\n    m: d3_time_parseMonthNumber,\n    M: d3_time_parseMinutes,\n    p: d3_time_parseAmPm,\n    S: d3_time_parseSeconds,\n    x: d3_time_parseLocaleDate,\n    X: d3_time_parseLocaleTime,\n    y: d3_time_parseYear,\n    Y: d3_time_parseFullYear\n  };\n  function d3_time_parseWeekdayAbbrev(date, string, i) {\n    d3_time_dayAbbrevRe.lastIndex = 0;\n    var n = d3_time_dayAbbrevRe.exec(string.substring(i));\n    return n ? i += n[0].length : -1;\n  }\n  function d3_time_parseWeekday(date, string, i) {\n    d3_time_dayRe.lastIndex = 0;\n    var n = d3_time_dayRe.exec(string.substring(i));\n    return n ? i += n[0].length : -1;\n  }\n  function d3_time_parseMonthAbbrev(date, string, i) {\n    d3_time_monthAbbrevRe.lastIndex = 0;\n    var n = d3_time_monthAbbrevRe.exec(string.substring(i));\n    return n ? (date.m = d3_time_monthAbbrevLookup.get(n[0].toLowerCase()), i += n[0].length) : -1;\n  }\n  function d3_time_parseMonth(date, string, i) {\n    d3_time_monthRe.lastIndex = 0;\n    var n = d3_time_monthRe.exec(string.substring(i));\n    return n ? (date.m = d3_time_monthLookup.get(n[0].toLowerCase()), i += n[0].length) : -1;\n  }\n  function d3_time_parseLocaleFull(date, string, i) {\n    return d3_time_parse(date, d3_time_formats.c.toString(), string, i);\n  }\n  function d3_time_parseLocaleDate(date, string, i) {\n    return d3_time_parse(date, d3_time_formats.x.toString(), string, i);\n  }\n  function d3_time_parseLocaleTime(date, string, i) {\n    return d3_time_parse(date, d3_time_formats.X.toString(), string, i);\n  }\n  function d3_time_parseFullYear(date, string, i) {\n    d3_time_numberRe.lastIndex = 0;\n    var n = d3_time_numberRe.exec(string.substring(i, i + 4));\n    return n ? (date.y = +n[0], i += n[0].length) : -1;\n  }\n  function d3_time_parseYear(date, string, i) {\n    d3_time_numberRe.lastIndex = 0;\n    var n = d3_time_numberRe.exec(string.substring(i, i + 2));\n    return n ? (date.y = d3_time_expandYear(+n[0]), i += n[0].length) : -1;\n  }\n  function d3_time_expandYear(d) {\n    return d + (d > 68 ? 1900 : 2e3);\n  }\n  function d3_time_parseMonthNumber(date, string, i) {\n    d3_time_numberRe.lastIndex = 0;\n    var n = d3_time_numberRe.exec(string.substring(i, i + 2));\n    return n ? (date.m = n[0] - 1, i += n[0].length) : -1;\n  }\n  function d3_time_parseDay(date, string, i) {\n    d3_time_numberRe.lastIndex = 0;\n    var n = d3_time_numberRe.exec(string.substring(i, i + 2));\n    return n ? (date.d = +n[0], i += n[0].length) : -1;\n  }\n  function d3_time_parseHour24(date, string, i) {\n    d3_time_numberRe.lastIndex = 0;\n    var n = d3_time_numberRe.exec(string.substring(i, i + 2));\n    return n ? (date.H = +n[0], i += n[0].length) : -1;\n  }\n  function d3_time_parseMinutes(date, string, i) {\n    d3_time_numberRe.lastIndex = 0;\n    var n = d3_time_numberRe.exec(string.substring(i, i + 2));\n    return n ? (date.M = +n[0], i += n[0].length) : -1;\n  }\n  function d3_time_parseSeconds(date, string, i) {\n    d3_time_numberRe.lastIndex = 0;\n    var n = d3_time_numberRe.exec(string.substring(i, i + 2));\n    return n ? (date.S = +n[0], i += n[0].length) : -1;\n  }\n  function d3_time_parseMilliseconds(date, string, i) {\n    d3_time_numberRe.lastIndex = 0;\n    var n = d3_time_numberRe.exec(string.substring(i, i + 3));\n    return n ? (date.L = +n[0], i += n[0].length) : -1;\n  }\n  var d3_time_numberRe = /^\\s*\\d+/;\n  function d3_time_parseAmPm(date, string, i) {\n    var n = d3_time_amPmLookup.get(string.substring(i, i += 2).toLowerCase());\n    return n == null ? -1 : (date.p = n, i);\n  }\n  var d3_time_amPmLookup = d3.map({\n    am: 0,\n    pm: 1\n  });\n  function d3_time_zone(d) {\n    var z = d.getTimezoneOffset(), zs = z > 0 ? \"-\" : \"+\", zh = ~~(Math.abs(z) / 60), zm = Math.abs(z) % 60;\n    return zs + d3_time_formatPad(zh, \"0\", 2) + d3_time_formatPad(zm, \"0\", 2);\n  }\n  d3.time.format.utc = function(template) {\n    var local = d3.time.format(template);\n    function format(date) {\n      try {\n        d3_time = d3_time_utc;\n        var utc = new d3_time();\n        utc._ = date;\n        return local(utc);\n      } finally {\n        d3_time = Date;\n      }\n    }\n    format.parse = function(string) {\n      try {\n        d3_time = d3_time_utc;\n        var date = local.parse(string);\n        return date && date._;\n      } finally {\n        d3_time = Date;\n      }\n    };\n    format.toString = local.toString;\n    return format;\n  };\n  var d3_time_formatIso = d3.time.format.utc(\"%Y-%m-%dT%H:%M:%S.%LZ\");\n  d3.time.format.iso = Date.prototype.toISOString && +new Date(\"2000-01-01T00:00:00.000Z\") ? d3_time_formatIsoNative : d3_time_formatIso;\n  function d3_time_formatIsoNative(date) {\n    return date.toISOString();\n  }\n  d3_time_formatIsoNative.parse = function(string) {\n    var date = new Date(string);\n    return isNaN(date) ? null : date;\n  };\n  d3_time_formatIsoNative.toString = d3_time_formatIso.toString;\n  d3.time.second = d3_time_interval(function(date) {\n    return new d3_time(Math.floor(date / 1e3) * 1e3);\n  }, function(date, offset) {\n    date.setTime(date.getTime() + Math.floor(offset) * 1e3);\n  }, function(date) {\n    return date.getSeconds();\n  });\n  d3.time.seconds = d3.time.second.range;\n  d3.time.seconds.utc = d3.time.second.utc.range;\n  d3.time.minute = d3_time_interval(function(date) {\n    return new d3_time(Math.floor(date / 6e4) * 6e4);\n  }, function(date, offset) {\n    date.setTime(date.getTime() + Math.floor(offset) * 6e4);\n  }, function(date) {\n    return date.getMinutes();\n  });\n  d3.time.minutes = d3.time.minute.range;\n  d3.time.minutes.utc = d3.time.minute.utc.range;\n  d3.time.hour = d3_time_interval(function(date) {\n    var timezone = date.getTimezoneOffset() / 60;\n    return new d3_time((Math.floor(date / 36e5 - timezone) + timezone) * 36e5);\n  }, function(date, offset) {\n    date.setTime(date.getTime() + Math.floor(offset) * 36e5);\n  }, function(date) {\n    return date.getHours();\n  });\n  d3.time.hours = d3.time.hour.range;\n  d3.time.hours.utc = d3.time.hour.utc.range;\n  d3.time.month = d3_time_interval(function(date) {\n    date = d3.time.day(date);\n    date.setDate(1);\n    return date;\n  }, function(date, offset) {\n    date.setMonth(date.getMonth() + offset);\n  }, function(date) {\n    return date.getMonth();\n  });\n  d3.time.months = d3.time.month.range;\n  d3.time.months.utc = d3.time.month.utc.range;\n  function d3_time_scale(linear, methods, format) {\n    function scale(x) {\n      return linear(x);\n    }\n    scale.invert = function(x) {\n      return d3_time_scaleDate(linear.invert(x));\n    };\n    scale.domain = function(x) {\n      if (!arguments.length) return linear.domain().map(d3_time_scaleDate);\n      linear.domain(x);\n      return scale;\n    };\n    scale.nice = function(m) {\n      return scale.domain(d3_scale_nice(scale.domain(), function() {\n        return m;\n      }));\n    };\n    scale.ticks = function(m, k) {\n      var extent = d3_time_scaleExtent(scale.domain());\n      if (typeof m !== \"function\") {\n        var span = extent[1] - extent[0], target = span / m, i = d3.bisect(d3_time_scaleSteps, target);\n        if (i == d3_time_scaleSteps.length) return methods.year(extent, m);\n        if (!i) return linear.ticks(m).map(d3_time_scaleDate);\n        if (Math.log(target / d3_time_scaleSteps[i - 1]) < Math.log(d3_time_scaleSteps[i] / target)) --i;\n        m = methods[i];\n        k = m[1];\n        m = m[0].range;\n      }\n      return m(extent[0], new Date(+extent[1] + 1), k);\n    };\n    scale.tickFormat = function() {\n      return format;\n    };\n    scale.copy = function() {\n      return d3_time_scale(linear.copy(), methods, format);\n    };\n    return d3.rebind(scale, linear, \"range\", \"rangeRound\", \"interpolate\", \"clamp\");\n  }\n  function d3_time_scaleExtent(domain) {\n    var start = domain[0], stop = domain[domain.length - 1];\n    return start < stop ? [ start, stop ] : [ stop, start ];\n  }\n  function d3_time_scaleDate(t) {\n    return new Date(t);\n  }\n  function d3_time_scaleFormat(formats) {\n    return function(date) {\n      var i = formats.length - 1, f = formats[i];\n      while (!f[1](date)) f = formats[--i];\n      return f[0](date);\n    };\n  }\n  function d3_time_scaleSetYear(y) {\n    var d = new Date(y, 0, 1);\n    d.setFullYear(y);\n    return d;\n  }\n  function d3_time_scaleGetYear(d) {\n    var y = d.getFullYear(), d0 = d3_time_scaleSetYear(y), d1 = d3_time_scaleSetYear(y + 1);\n    return y + (d - d0) / (d1 - d0);\n  }\n  var d3_time_scaleSteps = [ 1e3, 5e3, 15e3, 3e4, 6e4, 3e5, 9e5, 18e5, 36e5, 108e5, 216e5, 432e5, 864e5, 1728e5, 6048e5, 2592e6, 7776e6, 31536e6 ];\n  var d3_time_scaleLocalMethods = [ [ d3.time.second, 1 ], [ d3.time.second, 5 ], [ d3.time.second, 15 ], [ d3.time.second, 30 ], [ d3.time.minute, 1 ], [ d3.time.minute, 5 ], [ d3.time.minute, 15 ], [ d3.time.minute, 30 ], [ d3.time.hour, 1 ], [ d3.time.hour, 3 ], [ d3.time.hour, 6 ], [ d3.time.hour, 12 ], [ d3.time.day, 1 ], [ d3.time.day, 2 ], [ d3.time.week, 1 ], [ d3.time.month, 1 ], [ d3.time.month, 3 ], [ d3.time.year, 1 ] ];\n  var d3_time_scaleLocalFormats = [ [ d3.time.format(\"%Y\"), d3_true ], [ d3.time.format(\"%B\"), function(d) {\n    return d.getMonth();\n  } ], [ d3.time.format(\"%b %d\"), function(d) {\n    return d.getDate() != 1;\n  } ], [ d3.time.format(\"%a %d\"), function(d) {\n    return d.getDay() && d.getDate() != 1;\n  } ], [ d3.time.format(\"%I %p\"), function(d) {\n    return d.getHours();\n  } ], [ d3.time.format(\"%I:%M\"), function(d) {\n    return d.getMinutes();\n  } ], [ d3.time.format(\":%S\"), function(d) {\n    return d.getSeconds();\n  } ], [ d3.time.format(\".%L\"), function(d) {\n    return d.getMilliseconds();\n  } ] ];\n  var d3_time_scaleLinear = d3.scale.linear(), d3_time_scaleLocalFormat = d3_time_scaleFormat(d3_time_scaleLocalFormats);\n  d3_time_scaleLocalMethods.year = function(extent, m) {\n    return d3_time_scaleLinear.domain(extent.map(d3_time_scaleGetYear)).ticks(m).map(d3_time_scaleSetYear);\n  };\n  d3.time.scale = function() {\n    return d3_time_scale(d3.scale.linear(), d3_time_scaleLocalMethods, d3_time_scaleLocalFormat);\n  };\n  var d3_time_scaleUTCMethods = d3_time_scaleLocalMethods.map(function(m) {\n    return [ m[0].utc, m[1] ];\n  });\n  var d3_time_scaleUTCFormats = [ [ d3.time.format.utc(\"%Y\"), d3_true ], [ d3.time.format.utc(\"%B\"), function(d) {\n    return d.getUTCMonth();\n  } ], [ d3.time.format.utc(\"%b %d\"), function(d) {\n    return d.getUTCDate() != 1;\n  } ], [ d3.time.format.utc(\"%a %d\"), function(d) {\n    return d.getUTCDay() && d.getUTCDate() != 1;\n  } ], [ d3.time.format.utc(\"%I %p\"), function(d) {\n    return d.getUTCHours();\n  } ], [ d3.time.format.utc(\"%I:%M\"), function(d) {\n    return d.getUTCMinutes();\n  } ], [ d3.time.format.utc(\":%S\"), function(d) {\n    return d.getUTCSeconds();\n  } ], [ d3.time.format.utc(\".%L\"), function(d) {\n    return d.getUTCMilliseconds();\n  } ] ];\n  var d3_time_scaleUTCFormat = d3_time_scaleFormat(d3_time_scaleUTCFormats);\n  function d3_time_scaleUTCSetYear(y) {\n    var d = new Date(Date.UTC(y, 0, 1));\n    d.setUTCFullYear(y);\n    return d;\n  }\n  function d3_time_scaleUTCGetYear(d) {\n    var y = d.getUTCFullYear(), d0 = d3_time_scaleUTCSetYear(y), d1 = d3_time_scaleUTCSetYear(y + 1);\n    return y + (d - d0) / (d1 - d0);\n  }\n  d3_time_scaleUTCMethods.year = function(extent, m) {\n    return d3_time_scaleLinear.domain(extent.map(d3_time_scaleUTCGetYear)).ticks(m).map(d3_time_scaleUTCSetYear);\n  };\n  d3.time.scale.utc = function() {\n    return d3_time_scale(d3.scale.linear(), d3_time_scaleUTCMethods, d3_time_scaleUTCFormat);\n  };\n  d3.text = function() {\n    return d3.xhr.apply(d3, arguments).response(d3_text);\n  };\n  function d3_text(request) {\n    return request.responseText;\n  }\n  d3.json = function(url, callback) {\n    return d3.xhr(url, \"application/json\", callback).response(d3_json);\n  };\n  function d3_json(request) {\n    return JSON.parse(request.responseText);\n  }\n  d3.html = function(url, callback) {\n    return d3.xhr(url, \"text/html\", callback).response(d3_html);\n  };\n  function d3_html(request) {\n    var range = d3_document.createRange();\n    range.selectNode(d3_document.body);\n    return range.createContextualFragment(request.responseText);\n  }\n  d3.xml = function() {\n    return d3.xhr.apply(d3, arguments).response(d3_xml);\n  };\n  function d3_xml(request) {\n    return request.responseXML;\n  }\n  return d3;\n}();"
  },
  {
    "path": "explainshell/web/static/js/es.js",
    "content": "jQuery.fn.reverse = [].reverse;\n\nvar debug = false;\n\nvar themeCookieName = 'theme';\n\nif (!debug) {\n    console = console || {};\n    console.log = function(){};\n}\n\n// a list of colors to use for the lines\nvar colors = ['#3182bd', '#6baed6', '#9ecae1', '#c6dbef', '#e6550d', '#fd8d3c', '#fdae6b', '#fdd0a2', '#31a354', '#74c476', '#a1d99b', '#c7e9c0', '#756bb1', '#9e9ac8', '#bcbddc', '#dadaeb', '#636363', '#969696', '#bdbdbd', '#d9d9d9'];\n\n// the urls of the themes\nvar themes = {\n    default: '//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.1/css/bootstrap.min.css',\n    dark: '//maxcdn.bootstrapcdn.com/bootswatch/2.3.1/cyborg/bootstrap.min.css'\n};\nif (debug){\n    themes = {\n        default: '/static/css/bootstrap.min.css',\n        dark: '/static/css/bootstrap-cyborg.min.css'\n    };\n}\n\nvar assignedcolors = {};\n\nvar vtimeout,\n    changewait = 250;\n\n\n// From MDN's Library\nvar docCookies = {\n    getItem: function (sKey) {\n      if (!sKey) { return null; }\n      return decodeURIComponent(document.cookie.replace(new RegExp(\"(?:(?:^|.*;)\\\\s*\" + encodeURIComponent(sKey).replace(/[\\-\\.\\+\\*]/g, \"\\\\$&\") + \"\\\\s*\\\\=\\\\s*([^;]*).*$)|^.*$\"), \"$1\")) || null;\n    },\n    setItem: function (sKey, sValue, vEnd, sPath, sDomain, bSecure) {\n      if (!sKey || /^(?:expires|max\\-age|path|domain|secure)$/i.test(sKey)) { return false; }\n      var sExpires = \"\";\n      if (vEnd) {\n        switch (vEnd.constructor) {\n          case Number:\n            sExpires = vEnd === Infinity ? \"; expires=Fri, 31 Dec 9999 23:59:59 GMT\" : \"; max-age=\" + vEnd;\n            break;\n          case String:\n            sExpires = \"; expires=\" + vEnd;\n            break;\n          case Date:\n            sExpires = \"; expires=\" + vEnd.toUTCString();\n            break;\n        }\n      }\n      document.cookie = encodeURIComponent(sKey) + \"=\" + encodeURIComponent(sValue) + sExpires + (sDomain ? \"; domain=\" + sDomain : \"\") + (sPath ? \"; path=\" + sPath : \"\") + (bSecure ? \"; secure\" : \"\");\n      return true;\n    },\n    removeItem: function (sKey, sPath, sDomain) {\n      if (!this.hasItem(sKey)) { return false; }\n      document.cookie = encodeURIComponent(sKey) + \"=; expires=Thu, 01 Jan 1970 00:00:00 GMT\" + (sDomain ? \"; domain=\" + sDomain : \"\") + (sPath ? \"; path=\" + sPath : \"\");\n      return true;\n    },\n    hasItem: function (sKey) {\n      if (!sKey || /^(?:expires|max\\-age|path|domain|secure)$/i.test(sKey)) { return false; }\n      return (new RegExp(\"(?:^|;\\\\s*)\" + encodeURIComponent(sKey).replace(/[\\-\\.\\+\\*]/g, \"\\\\$&\") + \"\\\\s*\\\\=\")).test(document.cookie);\n    },\n    keys: function () {\n      var aKeys = document.cookie.replace(/((?:^|\\s*;)[^\\=]+)(?=;|$)|^\\s*|\\s*(?:\\=[^;]*)?(?:\\1|$)/g, \"\").split(/\\s*(?:\\=[^;]*)?;\\s*/);\n      for (var nLen = aKeys.length, nIdx = 0; nIdx < nLen; nIdx++) { aKeys[nIdx] = decodeURIComponent(aKeys[nIdx]); }\n      return aKeys;\n    }\n  };\n\nfunction specialparam(text) {\n    return {\n        title: \"Special Parameters\",\n        content:\n            '<p>The shell treats several parameters specially. These parameters ' +\n            'may only be referenced; assignment to them is not allowed.</p>' +\n            text\n    };\n}\nvar expansions = {\n    tilde: {\n        title: \"Tilde Expansion\",\n        content:\n            'If a word begins with an unquoted tilde character ' +\n            '(’<b>~</b>’), all of the characters preceding ' +\n            'the first unquoted slash (or all characters, if there is no ' +\n            'unquoted slash) are considered a <i>tilde-prefix</i>. If ' +\n            'none of the characters in the tilde-prefix are quoted, the ' +\n            'characters in the tilde-prefix following the tilde are ' +\n            'treated as a possible <i>login name</i>. If this login name ' +\n            'is the null string, the tilde is replaced with the value of ' +\n            'the shell parameter ' +\n            '<b><small>HOME</small></b><small>.</small> If ' +\n            '<b><small>HOME</small></b> is unset, the home directory of ' +\n            'the user executing the shell is substituted instead. ' +\n            'Otherwise, the tilde-prefix is replaced with the home ' +\n            'directory associated with the specified login name.'\n    },\n    \"parameter-param\": {\n        title: \"Parameter Expansion\",\n        content:\n            'The ’<b>$</b>’ character introduces parameter expansion, command ' +\n            'substitution, or arithmetic expansion.  The parameter name or ' +\n            'symbol to be expanded may be enclosed in braces, which are optional ' +\n            'but serve to protect the variable to be expanded from characters ' +\n            'immediately following it which could be interpreted as part of the ' +\n            'name.'\n    },\n    \"parameter-digits\": {\n        title: \"Positional Parameters\",\n        content:\n            'A <i>positional parameter</i> is a parameter denoted by one or more ' +\n            'digits, other than the single digit 0. Positional parameters are ' +\n            'assigned from the shell’s arguments when it is invoked, and may be ' +\n            'reassigned using the <b>set</b> builtin command. Positional ' +\n            'parameters may not be assigned to with assignment statements. The ' +\n            'positional parameters are temporarily replaced when a shell ' +\n            'function is executed (see <b><small>FUNCTIONS</small></b> below). '\n    },\n    \"parameter-star\": specialparam(\n            'Expands to the positional parameters, starting from one. When the ' +\n            'expansion occurs within double quotes, it expands to a single word ' +\n            'with the value of each parameter separated by the first character ' +\n            'of the <b><small>IFS</small></b> special variable. That is, ' +\n            '\"<b>$*</b>\" is equivalent to ' +\n            '\"<b>$1</b><i>c</i><b>$2</b><i>c</i><b>...</b>\", where <i>c</i> is ' +\n            'the first character of the value of the <b><small>IFS</small></b> ' +\n            'variable. If <b><small>IFS</small></b> is unset, the parameters are ' +\n            'separated by spaces. If <b><small>IFS</small></b> is null, the ' +\n            'parameters are joined without intervening separators.'\n    ),\n    \"parameter-at\": specialparam(\n            'Expands to the positional parameters, starting from one. ' +\n            'When the expansion occurs within double quotes, each ' +\n            'parameter expands to a separate word. That is, ' +\n            '\"<b>$@</b>\" is equivalent to \"<b>$1</b>\" ' +\n            '\"<b>$2</b>\" ... If the double-quoted expansion ' +\n            'occurs within a word, the expansion of the first parameter ' +\n            'is joined with the beginning part of the original word, and ' +\n            'the expansion of the last parameter is joined with the last ' +\n            'part of the original word. When there are no positional ' +\n            'parameters, \"<b>$@</b>\" and <b>$@</b> expand to ' +\n            'nothing (i.e., they are removed).'\n    ),\n    \"parameter-pound\": specialparam(\n            'Expands to the number of positional parameters in'\n    ),\n    \"parameter-question\": specialparam(\n            'Expands to the exit status of the most recently executed ' +\n            'foreground pipeline.'\n    ),\n    \"parameter-hyphen\": specialparam(\n            'Expands to the current option flags as specified upon invocation, ' +\n            'by the <b>set</b> builtin command, or those set by the shell ' +\n            'itself (such as the <b>−i</b> option).'\n    ),\n    \"parameter-dollar\": specialparam(\n            'Expands to the process ID of the shell. In a () subshell, it '+\n            'expands to the process ID of the current shell, not the ' +\n            'subshell.'\n    ),\n    \"parameter-exclamation\": specialparam(\n            'Expands to the process ID of the most recently executed background ' +\n            '(asynchronous) command.'\n    ),\n    \"parameter-zero\": specialparam(\n            'Expands to the name of the shell or shell script. This is set at ' +\n            'shell initialization. If <b>bash</b> is invoked with a file of ' +\n            'commands, <b>$0</b> is set to the name of that file. If <b>bash</b> ' +\n            'is started with the <b>−c</b> option, then <b>$0</b> is set to the ' +\n            'first argument after the string to be executed, if one is present. ' +\n            'Otherwise, it is set to the file name used to invoke <b>bash</b>, ' +\n            'as given by argument zero.'\n    ),\n    \"parameter-underscore\": specialparam(\n            'At shell startup, set to the absolute pathname used to invoke the ' +\n            'shell or shell script being executed as passed in the environment ' +\n            'or argument list. Subsequently, expands to the last argument to the ' +\n            'previous command, after expansion.  Also set to the full pathname ' +\n            'used to invoke each command executed and placed in the environment ' +\n            'exported to that command. When checking mail, this parameter holds ' +\n            'the name of the mail file currently being checked.'\n    ),\n};\n\n// a class that represents a group of eslink\nfunction eslinkgroup(clazz, options, mid) {\n    var color = assignedcolors[clazz];\n    this.links = options.map(function(option) { return new eslink(clazz, option, mid, color); });\n    this.options = _.pluck(this.links, 'option');\n    this.help = _.pluck(this.links, 'help');\n}\n\n// this class represents a link (visualized by a line) between a span (option)\n// in .command that needs to be connected to a corresponding <pre> in .help\nfunction eslink(clazz, option, mid, color) {\n    this.option = option;       // a span from .command\n    this.color = color;         // the color chosen for this link\n    this.paths = [];            // a list of d3 paths to draw for this link\n    this.lines = [];            // a list of d3 lines to draw for this link\n    this.circle = null;         // circle data to draw, if any (used by unknowns)\n    this.text = null;           // the text to draw in the circle (always '?')\n    this.group = null;          // the group this link is a part of\n\n    // unknown links have no corresponding <pre> in .help, they simply show up\n    // with a '?' connected to them\n    this.unknown = false;\n\n    // unknown links can go either down or up\n    this.directiondown = true;\n\n    // clazz is the name of the current group (shell, command0, command1..)\n    if (clazz) {\n        // the matching <pre> in .help\n        this.help = $(\"#\" + clazz)[0];\n\n        // each link can go either left or right, we decide where by\n        // calculating its middle and comparing it to the middle of .command\n        var rr = option.getBoundingClientRect();\n        var rrmid = rr.left + rr.width / 2;\n        this.goingleft = rrmid <= mid;\n\n        $(this.help).css(\"border-color\", this.color);\n    }\n}\n\neslink.prototype.leftmost = function() {\n    for (var i = 0; i < this.group.links.length; i++) {\n        if (this.group.links[i].goingleft)\n            return this.group.links[i];\n    }\n\n    return null;\n};\n\neslink.prototype.rightmost = function() {\n    for (var i = this.group.links.length-1; i >= 0; i--) {\n        if (!this.group.links[i].goingleft)\n            return this.group.links[i];\n    }\n\n    return null;\n};\n\n// return true if this eslink is 'close' to other by looking at their bounding\n// rects\n//\n// we use this when deciding which direction an 'unknown' link should go\neslink.prototype.nearby = function(other) {\n    var closeness = 5,\n        r = this.option.getBoundingClientRect(), rr = other.option.getBoundingClientRect();\n\n    return Math.abs(r.right - rr.left) <= closeness || Math.abs(r.left - rr.right) <= closeness;\n};\n\n// a conveninent wrapper around an array of points that allows to chain appends\nfunction espath() {\n    this.points = [];\n}\n\nespath.prototype.addpoint = function(x, y) {\n    this.points.push({\"x\": d3.round(x), \"y\": d3.round(y)});\n    return this;\n};\n\n// swap the position of two nodes in the DOM\nfunction swapNodes(a, b) {\n    var aparent = a.parentNode;\n    var asibling = a.nextSibling === b ? a : a.nextSibling;\n    b.parentNode.insertBefore(a, b);\n    aparent.insertBefore(b, asibling);\n}\n\n// reorder the help <pre>'s of all links that go left\nfunction reorder(lefteslinks) {\n    var help = _.pluck(lefteslinks, 'help'),\n        visiblehelp = $(\"#help pre:visible\");\n\n    // check the indices of the first and last help boxes. if the first is\n    // greater than the last, then it appears later in the DOM which means\n    // we've already reordered this set of boxes and they're in the correct\n    // order\n    if (visiblehelp.index($(help[0])) >= visiblehelp.index($(help[help.length - 1])))\n        return;\n\n    for (var i = 0, j = help.length - 1; i < Math.floor(help.length / 2) && i != j; i++, j = help.length - 1 - i) {\n        var h = help[i],\n            hh = help[j];\n\n        swapNodes(h, hh);\n    }\n}\n\n// return the matching <pre> in .help for each item in commandselector\nfunction helpselector(commandselector) {\n    return commandselector.map(function(span) {\n        return $(\"#\" + $(this).attr('helpref'))[0];\n    });\n}\n\n// return the <span>'s in #command that are linked to each <pre> in pres\nfunction optionsselector(pres, spans) {\n    var ids = pres.map(function() {\n        return $(this).attr('id');\n    });\n\n    var s = $(\"#command span.unknown\");\n    var r = _.reduce(ids, function(s, id) { return s.add(\"#command span[helpref^=\" + id + \"]\"); }, s);\n\n    if (typeof spans == 'object') {\n        return (r.filter(spans));\n    } else {\n        return r;\n    }\n}\n\n// initialize the lines logic, deciding which group of elements should be displayed\n//\n// returns the name of the group (with 'all' meaning draw everything) and two\n// selectors: one selects which spans in .command and the other selects their\n// matching help text in .help\nfunction initialize() {\n    var head = {'name' : 'all'},\n        prev = head,\n        groupcount = 0,\n        s = $(\"#command span[class^=shell]\"),\n        curr;\n\n    if (s.length) {\n        var shell = {'name' : 'shell', 'commandselector' : s, 'prev' : head};\n        head.next = shell;\n        prev = shell;\n        groupcount += 1;\n    }\n\n    // construct a doubly linked list of previous/next groups. this is used\n    // by the navigation buttons to move between groups\n    var i = 0,\n        g = \"command\" + i;\n\n    s = $(\"#command span[class^=\" + g + \"]\");\n\n    var unknownsselector = $();\n\n    while (s.length > 0) {\n        curr = {'name' : g, 'commandselector' : s};\n\n        // add this group to the linked list only if it's not full of unknowns\n        if (s.filter(':not(.unknown)').length > 0) {\n            curr.prev = prev;\n            prev.next = curr;\n            prev = curr;\n            groupcount += 1;\n        }\n        else {\n            unknownsselector = unknownsselector.add(s);\n        }\n\n        i++;\n        g = \"command\" + i;\n        s = $(\"#command span[class^=\" + g + \"]\");\n    }\n\n    if (groupcount == 1) {\n        // if we have a single group, get rid of 'all' and remove the prev/next\n        // links\n        head = head.next;\n\n        delete head.next;\n        delete head.prev;\n\n        // if we have 1 group and it's the shell, all other commands in there\n        // are unknowns, add them to the selector so they show up as unknowns\n        // in the UI\n        if (head.name == 'shell') {\n            head.commandselector = head.commandselector.add(unknownsselector);\n        }\n    }\n    else {\n        // add a group for all spans at the start\n        // select spans that start with command or shell to filter out\n        // the dropdown for a command start and expansions in words\n        head.commandselector = $(\"#command span[class^=command]\")\n                            .add(\"#command span[class^=shell]\");\n\n        // fix the prev/next links of the head/tail\n        head.prev = prev;\n        prev.next = head;\n    }\n\n    curr = head;\n\n    // look for expansions in the groups we've created, for each one create\n    // a popover with the help text\n    while (curr) {\n        if (curr.name != 'all') {\n            $(\"span[class^=expansion]\", curr.commandselector).each(function() {\n                var kind = $(this).attr(\"class\").slice(10);\n\n                if (_.has(expansions, kind)) {\n                    console.log(\"adding\", kind, \"popover to\", $(this));\n\n                    var expansion = expansions[kind];\n\n                    $(this).popover({\n                        html: true,\n                        placement: 'bottom',\n                        trigger: 'hover',\n                        title: expansion.title,\n                        content: expansion.content\n                    });\n                }\n                else {\n                    console.log(\"kind\", kind, \"has no help text!\");\n                }\n            }).css('color', 'red');\n        }\n\n        curr = curr.next;\n        if (curr === head)\n            break;\n    }\n\n    commandunknowns();\n    assigncolors();\n    handlesynopsis();\n\n    return head;\n}\n\n// add the help-synopsis class to all <pre>'s that are\n// connected to a .simplecommandstart <span>\nfunction handlesynopsis() {\n    helppres.each(function() {\n        spans = optionsselector($(this)).not(\".unknown\");\n\n        if (spans.is(\".simplecommandstart\")) {\n            $(this).addClass(\"help-synopsis\");\n        }\n    });\n}\n\nfunction assigncolors() {\n    var shuffledcolors = _.shuffle(colors);\n\n    $(\"#help pre\").each(function() {\n        color = shuffledcolors.shift();\n        shuffledcolors.push(color);\n\n        assignedcolors[$(this).attr('id')] = color;\n    });\n\n    assignedcolors[null] = shuffledcolors.shift();\n}\n\n// handle unknowns in #command\nfunction commandunknowns() {\n    $(\"#command span.unknown\").each(function(span) {\n        $this = $(this);\n\n        // add tooltips\n        if ($this.hasClass('simplecommandstart')) {\n            this.title = \"This man page seems to be missing...\";\n\n            // only add the link to the missing man page issue if we haven't\n            // had any expansions in this group (since those might already contain\n            // links)\n            // if (!$this.hasClass('hasexpansion')) {\n            //     var link = $(\"<a/>\").text($this.text())\n            //                         .attr('href', 'https://github.com/idank/explainshell/issues/1');\n            //     $this.html(link);\n            // }\n        }\n        else\n            this.title = \"No matching help text found for this argument\";\n    });\n}\n\nfunction affixon() {\n    return $(\"#command-wrapper\").hasClass(\"affix\");\n}\n\n// this is where the magic happens!  we create a connecting line between each\n// <span> in the commandselector and its matching <pre> in helpselector.\n// for <span>'s that have no help text (such as unrecognized arguments), we attach\n// a small '?' to them and refer to them as unknowns\nfunction drawgrouplines(commandselector, options) {\n    if (prevselector !== null) {\n        clear();\n    }\n\n    var defaults = {\n        topheight: -1,\n        hidepres: true\n    };\n\n    if (typeof options == 'object') {\n        options = $.extend(defaults, options);\n    } else {\n        options = defaults;\n    }\n\n    // define a couple of parameters that control the spacing/padding\n    // of various areas in the links\n    var sidespace = 20, toppadding = 25, sidepadding = 15, edgedistance = 5,\n        unknownlinelength = 15, strokewidth = 1;\n\n    var canvas = d3.select(\"#canvas\"),\n        canvasTop = $(\"#canvas\")[0].getBoundingClientRect().top;\n\n    // if the current group isn't 'all', hide the rest of the help <pre>'s, and show\n    // the <pre>'s help of the current group\n    if (options.hidepres) {\n        if (currentgroup.name != 'all') {\n            $(\"#help pre\").not(helpselector(commandselector)).parent().parent().hide();\n            helpselector(commandselector).parent().parent().show();\n\n            // the first item in a non-shell group is always the synopsis of the\n            // command (unless it's unknown). we display it at the top without a\n            // connecting line, so remove it from the selectors (unless it's the\n            // only one)\n            //if (currentgroup.name != 'shell' && !$(commandselector[0]).hasClass('unknown') &&\n            //    commandselector.filter(':not(.unknown)').length > 1) {\n            //    console.log('slicing command selector');\n            //    commandselector = commandselector.slice(1);\n            //}\n        }\n        else {\n            // 'all' group, show everything\n            helpselector(commandselector).parent().parent().show();\n        }\n    }\n\n    if (helpselector(commandselector).length > 0) {\n        // the height of the canvas is determined by the bottom of the last visible <pre>\n        // in #help\n        $(\"#canvas\").height($(\"#help pre:visible\").last()[0].getBoundingClientRect().bottom - canvasTop);\n\n        // need to recompute the top of the canvas after height change\n        canvasTop = $(\"#canvas\")[0].getBoundingClientRect().top;\n    }\n\n    var commandWrapperRect = $(\"#command\")[0].getBoundingClientRect(),\n        mid = commandWrapperRect.left + commandWrapperRect.width / 2,\n        helprect = $(\"#help\")[0].getBoundingClientRect();\n\n    // the bounds of the area we plan to draw lines in .help\n    var top = helprect.top - toppadding,\n        left = helprect.left - sidepadding,\n        right = helprect.right + sidepadding,\n        topheight = options.topheight;\n\n    if (topheight == -1) {\n        topheight = Math.abs(commandWrapperRect.bottom - top);\n    }\n\n    // select all spans in our commandselector, and group them by their class\n    // attribute. different spans share the same class when they should be\n    // linked to the same <pre> in .help\n    var groupedoptions = _.groupBy(commandselector.filter(\":not(.unknown)\"), function(span) { return $(span).attr('helpref'); });\n\n    // create an eslinkgroup for every group of <span>'s, these will be linked together to\n    // the same <pre> in .help.\n    var linkgroups = _.map(groupedoptions, function(spans, clazz) {\n            var esg = new eslinkgroup(clazz, spans, mid);\n            _.each(esg.links, function(l) {\n                l.group = esg;\n            });\n\n            return esg;\n    });\n\n    // an array of all the links we need to make, ungrouped\n    var links = _.flatten(_.pluck(linkgroups, 'links'), true),\n        // the upper bounds of our drawing area\n        marginBetweenCommandAndCanvas = commandWrapperRect.bottom - canvasTop,\n        startytop = commandWrapperRect.top - canvasTop;\n\n    // links that are going left and right, in the order we'd like to process\n    // them. we reverse right going links so we handle them right-to-left.\n    var l = _.filter(links, function(l) { return l.goingleft; }),\n        r = _.filter(links, function(l) { return !l.goingleft; }).reverse();\n\n    // cheat a little: if all our links happen to go left, take half of them\n    // to the right (this can happen if the last link happens to strech from\n    // before the cutting point all the way to the end)\n    if (r.length === 0) {\n        var midarr = d3.round(l.length / 2);\n        r = l.slice(midarr).reverse();\n        l = l.slice(0, midarr);\n        _.each(r, function(l) { l.goingleft = false; });\n    }\n\n    // we keep track of how many have gone right/left to calculate\n    // the spacing distance between the lines\n    var goingleft = 0, goingright = 0, goneleft = 0, goneright = 0;\n\n    _.each(linkgroups, function(esg) {\n        // multiple links in a group count as one in the goingleft/right\n        if (_.some(esg.links, function(l) { return l.goingleft; }))\n            goingleft++;\n\n        if (_.some(esg.links, function(l) { return !l.goingleft; }))\n            goingright++;\n    });\n\n    links = l.concat(r);\n\n    // the left going links have their <pre>'s help ordered in the order the\n    // <span>'s appear in .command, so the first <span> goes to\n    // the first <pre>, and so on. but that means that the links are going to\n    // cross each other. swapping the first and last <pre>'s will prevent that\n    // (note that links can still cross each other since multiple <span>'s can\n    // be linked to the same <pre>).\n    //reorder(l);\n\n    // handle all links that are not unknowns (have a <pre> in .help)\n    //\n    // this is hard to explain without an accompanying drawing (TODO)\n    for (var i = 0; i < links.length; i++) {\n        var link = links[i];\n\n        console.log('handling', $(link.option).text());\n        var commandRect = link.option.getBoundingClientRect(),\n            spanmid = commandRect.left + commandRect.width / 2,\n            commandRight = commandRect.right - strokewidth;\n\n        link.starty = commandRect.bottom - commandWrapperRect.top + 1;\n        var commandOffsetToCanvas = marginBetweenCommandAndCanvas - link.starty\n\n        // points for marker under command\n        link.paths.push(new espath()\n          .addpoint(commandRect.left, 0)\n          .addpoint(commandRect.left, 5)\n          .addpoint(commandRight, 5)\n          .addpoint(commandRight, 0)\n        );\n\n        var path = new espath();\n        path.addpoint(spanmid, 5); // 3\n\n        var topskip, y, p, pp;\n\n\n        if (link.goingleft) {\n            var leftmost = link.leftmost();\n\n            // check if this is the leftmost link of the current group; for\n            // those we add a line from the option to the help box. the rest of\n            // the left going links in this group will connect to the top of\n            // this line\n            if (link == leftmost) {\n                topskip = topheight / goingleft;\n                y = topskip * goneleft + topskip + commandOffsetToCanvas;\n                path.addpoint(left - ((goingleft - goneleft) * sidespace), y); // 4\n                helprect = link.help.getBoundingClientRect();\n                y = (helprect.top - commandWrapperRect.bottom + helprect.height / 2) + commandOffsetToCanvas;\n                path.addpoint(left, y);\n\n                link.circle = {x: left+3, y: y, r: 4};\n\n                goneleft++;\n            }\n            else {\n                var leftmostpath = leftmost.paths[leftmost.paths.length-1];\n\n                p = leftmostpath.points[0];\n                pp = leftmostpath.points[1];\n\n                // zero or minus to alight with the same flag\n                startyDifferace = leftmost.starty - link.starty\n                path.addpoint(p.x, pp.y + startyDifferace);\n            }\n        }\n        else {\n            // handle right going links, similarly to left\n            var rightmost = link.rightmost();\n\n            if (link == rightmost) {\n                topskip = topheight / goingright;\n                y = topskip * goneright + topskip + commandOffsetToCanvas;\n                path.addpoint(right + ((goingright - goneright) * sidespace), y); // 4\n                helprect = link.help.getBoundingClientRect();\n                y = (helprect.top - commandWrapperRect.bottom + helprect.height / 2) + commandOffsetToCanvas;\n                path.addpoint(right, y);\n\n                link.circle = {x: right-3, y: y, r: 4};\n\n                goneright++;\n            }\n            else {\n                var rightmostpath = rightmost.paths[rightmost.paths.length-1];\n\n                p = rightmostpath.points[0];\n                pp = rightmostpath.points[1];\n\n                // zero or minus to alight with the same flag\n                startyDifferace = leftmost.starty - link.starty\n                path.addpoint(p.x, pp.y + startyDifferace);\n            }\n        }\n\n        link.paths.push(path);\n    }\n\n    // create a group for all the unknowns\n    var unknowngroup = new eslinkgroup(null, commandselector.filter(\".unknown\").toArray(), mid);\n    var linkslengthnounknown = links.length;\n\n    $.each(unknowngroup.links, function(i, link) {\n        var rr = link.option.getBoundingClientRect(),\n            rrright = rr.right - strokewidth,\n            nextspan = link.option.nextElementSibling,\n            nextlink = _.find(links, function(l) { return l.option == nextspan; }),\n            prevspan = link.option.previousElementSibling,\n            prevlink = _.find(links, function(l) { return l.option == prevspan; });\n\n        link.starty = link.option.getBoundingClientRect().bottom - link.option.parentElement.getBoundingClientRect().top + 1;\n        var commandOffsetToCanvas = marginBetweenCommandAndCanvas - link.starty\n        link.unknown = true;\n        link.text = \"?\";\n\n        // if there's a close link nearby to this one and it's going down, we\n        // draw the this link facing up\n        //if ((prevlink && prevlink.directiondown && link.nearby(prevlink)) || (nextlink && nextlink.directiondown && link.nearby(nextlink))) {\n        //    link.directiondown = false;\n\n        //    link.paths.push(new espath().addpoint(rr.left, startytop).addpoint(rrright, startytop-5));\n        //    link.paths.push(new espath().addpoint(rrright, startytop-5).addpoint(rrright, startytop));\n        //    var rrmid = d3.round(rr.left + rr.width / 2);\n        //    link.lines.push({x1: rrmid, y1: startytop-6, x2: rrmid, y2: startytop-5-unknownlinelength});\n        //    link.circle = {x: rrmid, y: startytop-5-unknownlinelength-3, r: 8};\n        //}\n        //else {\n            link.paths.push(new espath()\n                .addpoint(rr.left, 0)\n                .addpoint(rr.left, 5)\n                .addpoint(rrright, 5)\n                .addpoint(rrright, 0)\n            );\n            var rrmid = d3.round(rr.left + rr.width / 2);\n            link.paths.push(new espath()\n                .addpoint(rrmid, 5 + strokewidth)\n                .addpoint(rrmid, 5 + strokewidth + unknownlinelength + commandOffsetToCanvas)\n            );\n            link.circle = {x: rrmid, y: 5+unknownlinelength+3+commandOffsetToCanvas, r: 8};\n        //}\n\n        links.push(link);\n    });\n\n    if (unknowngroup.links.length > 0)\n        linkgroups.push(unknowngroup);\n\n    // d3 magic starts here\n    var fline = d3.svg.line()\n        .x(function(d) { return d.x; })\n        .y(function(d) { return d.y; })\n        .interpolate(\"step-before\");\n\n    // create an svg <g> for every linkgroup\n    var groups = canvas.selectAll(\"g\")\n        .data(linkgroups)\n        .enter().append(\"g\");\n\n    // create an svg <g> for every link\n    var moregroups = groups.selectAll(\"g\")\n        .data(function(esg) { return esg.links; })\n        .enter().append(\"g\");\n\n    // actually draw the lines we defined above\n    moregroups.each(function(link) {\n        var g = d3.select(this);\n\n        if (link.directiondown)\n            g.attr('transform', 'translate(0, ' + link.starty + ')');\n\n        var paths = g.selectAll('path')\n            .data(link.paths)\n            .enter().append(\"path\")\n                .attr(\"d\", function(path) { return fline(path.points); })\n                .attr(\"stroke\", link.color)\n                .attr(\"stroke-width\", strokewidth)\n                .attr(\"fill\", \"none\");\n\n        var lines = g.selectAll('line')\n            .data(link.lines)\n            .enter().append('line')\n            .attr(\"x1\", function(line) { return line.x1; })\n            .attr(\"y1\", function(line) { return line.y1; })\n            .attr(\"x2\", function(line) { return line.x2; })\n            .attr(\"y2\", function(line) { return line.y2; })\n            .attr(\"stroke\", link.color)\n            .attr(\"stroke-width\", strokewidth)\n            .attr(\"fill\", \"none\");\n\n        if (link.circle) {\n            var gg = g.append('g')\n                .attr(\"transform\", \"translate(\" + link.circle.x + \", \" + link.circle.y + \")\");\n\n            gg.append('circle')\n                .attr(\"r\", link.circle.r)\n                .attr(\"fill\", link.color);\n\n            if (link.text) {\n                gg.append(\"text\")\n                    .attr(\"fill\", 'white')\n                    .attr(\"text-anchor\", \"middle\")\n                    .attr(\"y\", \".35em\")\n                    .attr(\"font-family\", \"Arial\")\n                    .text(link.text);\n            }\n        }\n    });\n\n    // add hover effects for the linkgroups, if we have at least one line that\n    // isn't unknown\n    if (linkslengthnounknown > 1) {\n        var groupsnounknowns = groups.filter(function(g) { return !g.links[0].unknown; });\n        groupsnounknowns.each(function(linkgroup) {\n            var othergroups = groups.filter(function(other) { return linkgroup != other; });\n\n            var s = $(linkgroup.help).add(linkgroup.options);\n            console.log('s=', s);\n            s.hover(\n                function() {\n                    /*\n                     * we're highlighting a new block,\n                     * disable timeout to make all blocks visible\n                     **/\n                    console.log('entering link group =', linkgroup, 'clearTimeout =', vtimeout);\n                    clearTimeout(vtimeout);\n\n                    // highlight all the <span>'s of the current group\n                    $(linkgroup.options).css({'font-weight':'bold'});\n\n                    // and disable highlighting for substitutions that might\n                    // be in there\n                    $(\"span[class$=substitution]\", linkgroup.options).css({'font-weight':'normal'});\n                    // and disable transparency\n                    $(linkgroup.help).add(linkgroup.options).css({opacity: 1.0});\n\n                    // hide the lines of all other groups\n                    groups.attr('visibility', function(other) {\n                        return linkgroup != other ? 'hidden' : null; });\n\n                    // and make their <span> and <pre>'s slightly transparent\n                    othergroups.each(function(other) {\n                        $(other.help).add(other.options).css({opacity: 0.4});\n                        $(other.help).add(other.options).css({'font-weight':'normal'});\n                    });\n                },\n                function() {\n                    /*\n                     * we're leaving a block,\n                     * make all blocks visible unless we enter a\n                     * new block within changewait ms\n                     **/\n                    vtimeout = setTimeout(function(){\n                        $(linkgroup.options).css({'font-weight':'normal'});\n\n                        groups.attr('visibility', function(other) {\n                            return linkgroup != other ? 'visible' : null; });\n\n                        othergroups.each(function(other) {\n                            $(other.help).add(other.options).css({opacity: 1});\n                        });\n                    }, changewait);\n\n                    console.log('leaving link group =', linkgroup, 'setTimeout =', vtimeout);\n                }\n            );\n        });\n    }\n\n    prevselector = commandselector;\n}\n\nvar prevselector = null;\n\n// clear the canvas of all lines and unbind any hover events\n// previously set for oldgroup\nfunction clear() {\n    $(\"#canvas\").empty();\n\n    if (prevselector) {\n        prevselector.add(helpselector(prevselector)).unbind('mouseenter mouseleave');\n        prevselector = null;\n    }\n}\n\nfunction commandlinetourl(s) {\n    if (!$.trim(s))\n        return '/';\n\n    q = $.trim(s).split(' ');\n    loc = '/explain/' + q.shift();\n    if (q.length)\n        loc += '?' + $('<input/>', {type: 'hidden', name: 'args', value: q.join(' ')}).serialize();\n    return loc;\n}\n\n// very simple adjustment of the command div font size so it doesn't overflow\nfunction adjustcommandfontsize() {\n    var commandlength = $.trim($(\"#command span[class^=command]\").add(\"#command span[class^=shell]\").text()).length,\n        commandfontsize;\n\n    if (commandlength > 105)\n        commandfontsize = '10px';\n    else if (commandlength > 95)\n        commandfontsize = '12px';\n    else if (commandlength > 70)\n        commandfontsize = '14px';\n    else if (commandlength > 60)\n        commandfontsize = '16px';\n\n    if (commandfontsize) {\n        console.log('command length', commandlength, ', adjusting font size to', commandfontsize);\n        $(\"#command\").css('font-size', commandfontsize);\n    }\n}\n\nvar ignorekeydown = false;\n\nfunction navigation() {\n    // if we have more groups, show the prev/next buttons\n    if (currentgroup.next) {\n        var prev = $('<li><i class=\"icon-arrow-left icon-2\"></i><span></span></li>');\n        var next = $('<li><i class=\"icon-arrow-right icon-2\"></i><span></span></li>');\n        var prevnext = $('<ul class=\"inline\" id=\"prevnext\"><li>showing <u>all</u>, navigate:</li></ul>');\n        prevnext.append(prev).append(next);\n        $(\"#navigate\").css('height', 'auto').append(prevnext);\n\n        var nextext = next.find(\"span\"),\n            prevtext = prev.find(\"span\"),\n            currentext = prevnext.find(\"u\");\n\n        var grouptext = function(group) {\n            if (group.name == 'shell')\n                return 'shell syntax';\n            else if (group.name != 'all')\n                return group.commandselector.first().text();\n            return 'all';\n        };\n\n        nextext.text(\" explain \" + grouptext(currentgroup.next));\n        prevtext.text(\" explain \" + grouptext(currentgroup.prev));\n\n        prev.click(function() {\n            if (affixon())\n                return;\n            if (currentgroup.prev) {\n                console.log('moving to the previous group (%s), current group is %s', currentgroup.prev.name, currentgroup.name);\n                var oldgroup = currentgroup;\n                currentgroup = currentgroup.prev;\n                currentext.text(grouptext(currentgroup));\n\n                // no need to potentically call drawvisible() here since for now\n                // we don't allow clicking when scrolling\n                drawgrouplines(currentgroup.commandselector);\n\n                if (!currentgroup.prev) {\n                    console.log(\"new current group is the first group, disabling prev button\");\n                    prev.css({'display': 'none'});\n                    prevtext.text('');\n                }\n                else {\n                    console.log(\"setting prev button text to new current group prev %s\", currentgroup.prev.name);\n\n                    prevtext.text(\" explain \" + grouptext(currentgroup.prev));\n                }\n\n                if (currentgroup.next) {\n                    next.css({'display': ''});\n                    nextext.text(\" explain \" + grouptext(currentgroup.next));\n                    console.log(\"setting next button text to new current group next %s\", currentgroup.next.name);\n                }\n            }\n        });\n\n        next.click(function() {\n            if (affixon())\n                return;\n            if (currentgroup.next) {\n                console.log('moving to the next group (%s), current group is %s', currentgroup.next.name, currentgroup.name);\n                var oldgroup = currentgroup;\n                currentgroup = currentgroup.next;\n                currentext.text(grouptext(currentgroup));\n\n                // no need to potentically call drawvisible() here since for now\n                // we don't allow clicking when scrolling\n                drawgrouplines(currentgroup.commandselector);\n\n                if (!currentgroup.next) {\n                    console.log(\"new current group is the last group, disabling next button\");\n                    next.css({'display': 'none'});\n                    nextext.text('');\n                }\n                else {\n                    console.log(\"setting next button text to new current group next %s\", currentgroup.next.name);\n                    nextext.text(\" explain \" + grouptext(currentgroup.next));\n                }\n\n                if (currentgroup.prev) {\n                    prev.css({'display': ''});\n                    prevtext.text(\" explain \" + grouptext(currentgroup.prev));\n                    console.log(\"setting prev button text to new current group prev %s\", currentgroup.prev.name);\n                }\n            }\n        });\n\n\t\t// disable key navigation when the user focuses on the search box\n\t\t$(\"#top-search\").focus(function() {\n\t\t\tignorekeydown = true;\n\t\t});\n\n\t\t$(\"#top-search\").blur(function() {\n\t\t\tignorekeydown = false;\n\t\t});\n\n        // bind left/right arrows as well\n        $(document).keydown(function(e) {\n\t\t\tif (!ignorekeydown) {\n\t\t\t\tswitch(e.which) {\n\t\t\t\t\tcase 37: // left\n\t\t\t\t\t\tprev.click();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 39: // right\n\t\t\t\t\t\tnext.click();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault: return;\n\t\t\t\t}\n\n\t\t\t\te.preventDefault();\n\t\t\t}\n        });\n    }\n}\n\nfunction inview(viewtop, viewbottom, $el) {\n    var elemtop = $el.offset().top,\n        elembottom = elemtop + $el.height(),\n        elemmiddle = elemtop + ($el.height() / 2),\n        elemarea = $el.width() * $el.height(),\n        overlaparea = 0;\n\n    // we consider the element to be in view when its middle is\n    // within the viewport\n    return (viewtop < elemmiddle && viewbottom > elemmiddle);\n\n    /*\n    // is the element completely outside the viewport?\n    if (elembottom < viewtop || elemtop > viewbottom) {\n        overlaparea = 0;\n    }\n    else {\n        var w = $el.width(),\n            h;\n\n        // check for complete overlap\n        if ((elembottom >= viewtop) && (elemtop <= viewbottom)\n            && (elembottom <= viewbottom) && (elemtop >= viewtop)) {\n            h = $el.height();\n        }\n        // check if the viewport is entirely within the element\n        else if (viewtop > elemtop && viewbottom < elembottom) {\n            // is the middle of the element visible?\n            return (viewtop < elemmiddle && viewbottom > elemmiddle);\n        }\n        // check if the bottom of the element is below the viewport bottom\n        else if (elembottom > viewbottom) {\n            h = viewbottom - elemtop;\n        }\n        // the top of the element is above the viewport top\n        else {\n            h = elembottom - viewtop;\n        }\n\n        overlaparea = w * h;\n    }\n\n    var ratio = overlaparea / elemarea;\n\n    //$(\"#coords\").html(\"top=\" + viewtop + \" bottom=\"+viewbottom);\n    //console.log($el, \"top=\"+elemtop+\" bottom=\"+elembottom+\" area=\"+elemarea+\" overlap=\"+overlaparea+\" ratio=\"+ratio+\" i=\"+i);\n    //$(\"#coords\").html(i+\" top=\"+elemtop+\" bottom=\"+elembottom+\" area=\"+elemarea+\" overlap=\"+overlaparea+\" ratio=\"+ratio.toFixed(2));\n\n    return (ratio >= 0.5)*/\n}\n\nfunction drawvisible() {\n    var viewtop = $window.scrollTop(),\n        viewbottom = viewtop + $window.height(),\n        topspace = 80;\n\n    viewtop += topspace;\n\n    var visible = $(\"#help pre:visible\").filter(function() {\n        return (inview(viewtop, viewbottom, $(this)));\n    });\n\n    if (visible.length > 0) {\n        //var ids = visible.map(function() { return $(this).attr('id'); });\n        //$('#scroller').html(ids.toArray().join(','));\n\n        var commandselector = optionsselector(visible, currentgroup.commandselector);\n        drawgrouplines(commandselector, {topheight: 50, hidepres: false});\n    }\n    else {\n        //$('#scroller').html(\"nothing visible\");\n        clear();\n    }\n}\n\nfunction draw() {\n    if (affixon())\n        drawvisible();\n    else {\n        drawgrouplines(currentgroup.commandselector);\n    }\n}\n\nfunction setTheme(theme) {\n    console.log('setting theme to', theme);\n\n    $(\"#bootstrapCSS\").attr('href', themes[theme]);\n    $(document.body).attr('data-theme', theme);\n    docCookies.setItem(themeCookieName, theme, Infinity, '/');\n}\n\n\n// Theme-related stuff\n$(document).ready(function() {\n    if (!docCookies.getItem(themeCookieName)) {\n        var selectedTheme = 'default';\n        setTheme(selectedTheme); // to set the correct css file and data-theme\n    }\n\n    $(\"#themeContainer .dropdown-menu a\").click(function() {\n        setTheme($(this).attr('data-theme-name'));\n    });\n});\n"
  },
  {
    "path": "explainshell/web/static/js/jquery.js",
    "content": "/*!\n * jQuery JavaScript Library v1.9.1\n * http://jquery.com/\n *\n * Includes Sizzle.js\n * http://sizzlejs.com/\n *\n * Copyright 2005, 2012 jQuery Foundation, Inc. and other contributors\n * Released under the MIT license\n * http://jquery.org/license\n *\n * Date: 2013-2-4\n */\n(function( window, undefined ) {\n\n// Can't do this because several apps including ASP.NET trace\n// the stack via arguments.caller.callee and Firefox dies if\n// you try to trace through \"use strict\" call chains. (#13335)\n// Support: Firefox 18+\n//\"use strict\";\nvar\n\t// The deferred used on DOM ready\n\treadyList,\n\n\t// A central reference to the root jQuery(document)\n\trootjQuery,\n\n\t// Support: IE<9\n\t// For `typeof node.method` instead of `node.method !== undefined`\n\tcore_strundefined = typeof undefined,\n\n\t// Use the correct document accordingly with window argument (sandbox)\n\tdocument = window.document,\n\tlocation = window.location,\n\n\t// Map over jQuery in case of overwrite\n\t_jQuery = window.jQuery,\n\n\t// Map over the $ in case of overwrite\n\t_$ = window.$,\n\n\t// [[Class]] -> type pairs\n\tclass2type = {},\n\n\t// List of deleted data cache ids, so we can reuse them\n\tcore_deletedIds = [],\n\n\tcore_version = \"1.9.1\",\n\n\t// Save a reference to some core methods\n\tcore_concat = core_deletedIds.concat,\n\tcore_push = core_deletedIds.push,\n\tcore_slice = core_deletedIds.slice,\n\tcore_indexOf = core_deletedIds.indexOf,\n\tcore_toString = class2type.toString,\n\tcore_hasOwn = class2type.hasOwnProperty,\n\tcore_trim = core_version.trim,\n\n\t// Define a local copy of jQuery\n\tjQuery = function( selector, context ) {\n\t\t// The jQuery object is actually just the init constructor 'enhanced'\n\t\treturn new jQuery.fn.init( selector, context, rootjQuery );\n\t},\n\n\t// Used for matching numbers\n\tcore_pnum = /[+-]?(?:\\d*\\.|)\\d+(?:[eE][+-]?\\d+|)/.source,\n\n\t// Used for splitting on whitespace\n\tcore_rnotwhite = /\\S+/g,\n\n\t// Make sure we trim BOM and NBSP (here's looking at you, Safari 5.0 and IE)\n\trtrim = /^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g,\n\n\t// A simple way to check for HTML strings\n\t// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)\n\t// Strict HTML recognition (#11290: must start with <)\n\trquickExpr = /^(?:(<[\\w\\W]+>)[^>]*|#([\\w-]*))$/,\n\n\t// Match a standalone tag\n\trsingleTag = /^<(\\w+)\\s*\\/?>(?:<\\/\\1>|)$/,\n\n\t// JSON RegExp\n\trvalidchars = /^[\\],:{}\\s]*$/,\n\trvalidbraces = /(?:^|:|,)(?:\\s*\\[)+/g,\n\trvalidescape = /\\\\(?:[\"\\\\\\/bfnrt]|u[\\da-fA-F]{4})/g,\n\trvalidtokens = /\"[^\"\\\\\\r\\n]*\"|true|false|null|-?(?:\\d+\\.|)\\d+(?:[eE][+-]?\\d+|)/g,\n\n\t// Matches dashed string for camelizing\n\trmsPrefix = /^-ms-/,\n\trdashAlpha = /-([\\da-z])/gi,\n\n\t// Used by jQuery.camelCase as callback to replace()\n\tfcamelCase = function( all, letter ) {\n\t\treturn letter.toUpperCase();\n\t},\n\n\t// The ready event handler\n\tcompleted = function( event ) {\n\n\t\t// readyState === \"complete\" is good enough for us to call the dom ready in oldIE\n\t\tif ( document.addEventListener || event.type === \"load\" || document.readyState === \"complete\" ) {\n\t\t\tdetach();\n\t\t\tjQuery.ready();\n\t\t}\n\t},\n\t// Clean-up method for dom ready events\n\tdetach = function() {\n\t\tif ( document.addEventListener ) {\n\t\t\tdocument.removeEventListener( \"DOMContentLoaded\", completed, false );\n\t\t\twindow.removeEventListener( \"load\", completed, false );\n\n\t\t} else {\n\t\t\tdocument.detachEvent( \"onreadystatechange\", completed );\n\t\t\twindow.detachEvent( \"onload\", completed );\n\t\t}\n\t};\n\njQuery.fn = jQuery.prototype = {\n\t// The current version of jQuery being used\n\tjquery: core_version,\n\n\tconstructor: jQuery,\n\tinit: function( selector, context, rootjQuery ) {\n\t\tvar match, elem;\n\n\t\t// HANDLE: $(\"\"), $(null), $(undefined), $(false)\n\t\tif ( !selector ) {\n\t\t\treturn this;\n\t\t}\n\n\t\t// Handle HTML strings\n\t\tif ( typeof selector === \"string\" ) {\n\t\t\tif ( selector.charAt(0) === \"<\" && selector.charAt( selector.length - 1 ) === \">\" && selector.length >= 3 ) {\n\t\t\t\t// Assume that strings that start and end with <> are HTML and skip the regex check\n\t\t\t\tmatch = [ null, selector, null ];\n\n\t\t\t} else {\n\t\t\t\tmatch = rquickExpr.exec( selector );\n\t\t\t}\n\n\t\t\t// Match html or make sure no context is specified for #id\n\t\t\tif ( match && (match[1] || !context) ) {\n\n\t\t\t\t// HANDLE: $(html) -> $(array)\n\t\t\t\tif ( match[1] ) {\n\t\t\t\t\tcontext = context instanceof jQuery ? context[0] : context;\n\n\t\t\t\t\t// scripts is true for back-compat\n\t\t\t\t\tjQuery.merge( this, jQuery.parseHTML(\n\t\t\t\t\t\tmatch[1],\n\t\t\t\t\t\tcontext && context.nodeType ? context.ownerDocument || context : document,\n\t\t\t\t\t\ttrue\n\t\t\t\t\t) );\n\n\t\t\t\t\t// HANDLE: $(html, props)\n\t\t\t\t\tif ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {\n\t\t\t\t\t\tfor ( match in context ) {\n\t\t\t\t\t\t\t// Properties of context are called as methods if possible\n\t\t\t\t\t\t\tif ( jQuery.isFunction( this[ match ] ) ) {\n\t\t\t\t\t\t\t\tthis[ match ]( context[ match ] );\n\n\t\t\t\t\t\t\t// ...and otherwise set as attributes\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tthis.attr( match, context[ match ] );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn this;\n\n\t\t\t\t// HANDLE: $(#id)\n\t\t\t\t} else {\n\t\t\t\t\telem = document.getElementById( match[2] );\n\n\t\t\t\t\t// Check parentNode to catch when Blackberry 4.6 returns\n\t\t\t\t\t// nodes that are no longer in the document #6963\n\t\t\t\t\tif ( elem && elem.parentNode ) {\n\t\t\t\t\t\t// Handle the case where IE and Opera return items\n\t\t\t\t\t\t// by name instead of ID\n\t\t\t\t\t\tif ( elem.id !== match[2] ) {\n\t\t\t\t\t\t\treturn rootjQuery.find( selector );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Otherwise, we inject the element directly into the jQuery object\n\t\t\t\t\t\tthis.length = 1;\n\t\t\t\t\t\tthis[0] = elem;\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.context = document;\n\t\t\t\t\tthis.selector = selector;\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\n\t\t\t// HANDLE: $(expr, $(...))\n\t\t\t} else if ( !context || context.jquery ) {\n\t\t\t\treturn ( context || rootjQuery ).find( selector );\n\n\t\t\t// HANDLE: $(expr, context)\n\t\t\t// (which is just equivalent to: $(context).find(expr)\n\t\t\t} else {\n\t\t\t\treturn this.constructor( context ).find( selector );\n\t\t\t}\n\n\t\t// HANDLE: $(DOMElement)\n\t\t} else if ( selector.nodeType ) {\n\t\t\tthis.context = this[0] = selector;\n\t\t\tthis.length = 1;\n\t\t\treturn this;\n\n\t\t// HANDLE: $(function)\n\t\t// Shortcut for document ready\n\t\t} else if ( jQuery.isFunction( selector ) ) {\n\t\t\treturn rootjQuery.ready( selector );\n\t\t}\n\n\t\tif ( selector.selector !== undefined ) {\n\t\t\tthis.selector = selector.selector;\n\t\t\tthis.context = selector.context;\n\t\t}\n\n\t\treturn jQuery.makeArray( selector, this );\n\t},\n\n\t// Start with an empty selector\n\tselector: \"\",\n\n\t// The default length of a jQuery object is 0\n\tlength: 0,\n\n\t// The number of elements contained in the matched element set\n\tsize: function() {\n\t\treturn this.length;\n\t},\n\n\ttoArray: function() {\n\t\treturn core_slice.call( this );\n\t},\n\n\t// Get the Nth element in the matched element set OR\n\t// Get the whole matched element set as a clean array\n\tget: function( num ) {\n\t\treturn num == null ?\n\n\t\t\t// Return a 'clean' array\n\t\t\tthis.toArray() :\n\n\t\t\t// Return just the object\n\t\t\t( num < 0 ? this[ this.length + num ] : this[ num ] );\n\t},\n\n\t// Take an array of elements and push it onto the stack\n\t// (returning the new matched element set)\n\tpushStack: function( elems ) {\n\n\t\t// Build a new jQuery matched element set\n\t\tvar ret = jQuery.merge( this.constructor(), elems );\n\n\t\t// Add the old object onto the stack (as a reference)\n\t\tret.prevObject = this;\n\t\tret.context = this.context;\n\n\t\t// Return the newly-formed element set\n\t\treturn ret;\n\t},\n\n\t// Execute a callback for every element in the matched set.\n\t// (You can seed the arguments with an array of args, but this is\n\t// only used internally.)\n\teach: function( callback, args ) {\n\t\treturn jQuery.each( this, callback, args );\n\t},\n\n\tready: function( fn ) {\n\t\t// Add the callback\n\t\tjQuery.ready.promise().done( fn );\n\n\t\treturn this;\n\t},\n\n\tslice: function() {\n\t\treturn this.pushStack( core_slice.apply( this, arguments ) );\n\t},\n\n\tfirst: function() {\n\t\treturn this.eq( 0 );\n\t},\n\n\tlast: function() {\n\t\treturn this.eq( -1 );\n\t},\n\n\teq: function( i ) {\n\t\tvar len = this.length,\n\t\t\tj = +i + ( i < 0 ? len : 0 );\n\t\treturn this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );\n\t},\n\n\tmap: function( callback ) {\n\t\treturn this.pushStack( jQuery.map(this, function( elem, i ) {\n\t\t\treturn callback.call( elem, i, elem );\n\t\t}));\n\t},\n\n\tend: function() {\n\t\treturn this.prevObject || this.constructor(null);\n\t},\n\n\t// For internal use only.\n\t// Behaves like an Array's method, not like a jQuery method.\n\tpush: core_push,\n\tsort: [].sort,\n\tsplice: [].splice\n};\n\n// Give the init function the jQuery prototype for later instantiation\njQuery.fn.init.prototype = jQuery.fn;\n\njQuery.extend = jQuery.fn.extend = function() {\n\tvar src, copyIsArray, copy, name, options, clone,\n\t\ttarget = arguments[0] || {},\n\t\ti = 1,\n\t\tlength = arguments.length,\n\t\tdeep = false;\n\n\t// Handle a deep copy situation\n\tif ( typeof target === \"boolean\" ) {\n\t\tdeep = target;\n\t\ttarget = arguments[1] || {};\n\t\t// skip the boolean and the target\n\t\ti = 2;\n\t}\n\n\t// Handle case when target is a string or something (possible in deep copy)\n\tif ( typeof target !== \"object\" && !jQuery.isFunction(target) ) {\n\t\ttarget = {};\n\t}\n\n\t// extend jQuery itself if only one argument is passed\n\tif ( length === i ) {\n\t\ttarget = this;\n\t\t--i;\n\t}\n\n\tfor ( ; i < length; i++ ) {\n\t\t// Only deal with non-null/undefined values\n\t\tif ( (options = arguments[ i ]) != null ) {\n\t\t\t// Extend the base object\n\t\t\tfor ( name in options ) {\n\t\t\t\tsrc = target[ name ];\n\t\t\t\tcopy = options[ name ];\n\n\t\t\t\t// Prevent never-ending loop\n\t\t\t\tif ( target === copy ) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Recurse if we're merging plain objects or arrays\n\t\t\t\tif ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {\n\t\t\t\t\tif ( copyIsArray ) {\n\t\t\t\t\t\tcopyIsArray = false;\n\t\t\t\t\t\tclone = src && jQuery.isArray(src) ? src : [];\n\n\t\t\t\t\t} else {\n\t\t\t\t\t\tclone = src && jQuery.isPlainObject(src) ? src : {};\n\t\t\t\t\t}\n\n\t\t\t\t\t// Never move original objects, clone them\n\t\t\t\t\ttarget[ name ] = jQuery.extend( deep, clone, copy );\n\n\t\t\t\t// Don't bring in undefined values\n\t\t\t\t} else if ( copy !== undefined ) {\n\t\t\t\t\ttarget[ name ] = copy;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Return the modified object\n\treturn target;\n};\n\njQuery.extend({\n\tnoConflict: function( deep ) {\n\t\tif ( window.$ === jQuery ) {\n\t\t\twindow.$ = _$;\n\t\t}\n\n\t\tif ( deep && window.jQuery === jQuery ) {\n\t\t\twindow.jQuery = _jQuery;\n\t\t}\n\n\t\treturn jQuery;\n\t},\n\n\t// Is the DOM ready to be used? Set to true once it occurs.\n\tisReady: false,\n\n\t// A counter to track how many items to wait for before\n\t// the ready event fires. See #6781\n\treadyWait: 1,\n\n\t// Hold (or release) the ready event\n\tholdReady: function( hold ) {\n\t\tif ( hold ) {\n\t\t\tjQuery.readyWait++;\n\t\t} else {\n\t\t\tjQuery.ready( true );\n\t\t}\n\t},\n\n\t// Handle when the DOM is ready\n\tready: function( wait ) {\n\n\t\t// Abort if there are pending holds or we're already ready\n\t\tif ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).\n\t\tif ( !document.body ) {\n\t\t\treturn setTimeout( jQuery.ready );\n\t\t}\n\n\t\t// Remember that the DOM is ready\n\t\tjQuery.isReady = true;\n\n\t\t// If a normal DOM Ready event fired, decrement, and wait if need be\n\t\tif ( wait !== true && --jQuery.readyWait > 0 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If there are functions bound, to execute\n\t\treadyList.resolveWith( document, [ jQuery ] );\n\n\t\t// Trigger any bound ready events\n\t\tif ( jQuery.fn.trigger ) {\n\t\t\tjQuery( document ).trigger(\"ready\").off(\"ready\");\n\t\t}\n\t},\n\n\t// See test/unit/core.js for details concerning isFunction.\n\t// Since version 1.3, DOM methods and functions like alert\n\t// aren't supported. They return false on IE (#2968).\n\tisFunction: function( obj ) {\n\t\treturn jQuery.type(obj) === \"function\";\n\t},\n\n\tisArray: Array.isArray || function( obj ) {\n\t\treturn jQuery.type(obj) === \"array\";\n\t},\n\n\tisWindow: function( obj ) {\n\t\treturn obj != null && obj == obj.window;\n\t},\n\n\tisNumeric: function( obj ) {\n\t\treturn !isNaN( parseFloat(obj) ) && isFinite( obj );\n\t},\n\n\ttype: function( obj ) {\n\t\tif ( obj == null ) {\n\t\t\treturn String( obj );\n\t\t}\n\t\treturn typeof obj === \"object\" || typeof obj === \"function\" ?\n\t\t\tclass2type[ core_toString.call(obj) ] || \"object\" :\n\t\t\ttypeof obj;\n\t},\n\n\tisPlainObject: function( obj ) {\n\t\t// Must be an Object.\n\t\t// Because of IE, we also have to check the presence of the constructor property.\n\t\t// Make sure that DOM nodes and window objects don't pass through, as well\n\t\tif ( !obj || jQuery.type(obj) !== \"object\" || obj.nodeType || jQuery.isWindow( obj ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\ttry {\n\t\t\t// Not own constructor property must be Object\n\t\t\tif ( obj.constructor &&\n\t\t\t\t!core_hasOwn.call(obj, \"constructor\") &&\n\t\t\t\t!core_hasOwn.call(obj.constructor.prototype, \"isPrototypeOf\") ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t} catch ( e ) {\n\t\t\t// IE8,9 Will throw exceptions on certain host objects #9897\n\t\t\treturn false;\n\t\t}\n\n\t\t// Own properties are enumerated firstly, so to speed up,\n\t\t// if last one is own, then all properties are own.\n\n\t\tvar key;\n\t\tfor ( key in obj ) {}\n\n\t\treturn key === undefined || core_hasOwn.call( obj, key );\n\t},\n\n\tisEmptyObject: function( obj ) {\n\t\tvar name;\n\t\tfor ( name in obj ) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t},\n\n\terror: function( msg ) {\n\t\tthrow new Error( msg );\n\t},\n\n\t// data: string of html\n\t// context (optional): If specified, the fragment will be created in this context, defaults to document\n\t// keepScripts (optional): If true, will include scripts passed in the html string\n\tparseHTML: function( data, context, keepScripts ) {\n\t\tif ( !data || typeof data !== \"string\" ) {\n\t\t\treturn null;\n\t\t}\n\t\tif ( typeof context === \"boolean\" ) {\n\t\t\tkeepScripts = context;\n\t\t\tcontext = false;\n\t\t}\n\t\tcontext = context || document;\n\n\t\tvar parsed = rsingleTag.exec( data ),\n\t\t\tscripts = !keepScripts && [];\n\n\t\t// Single tag\n\t\tif ( parsed ) {\n\t\t\treturn [ context.createElement( parsed[1] ) ];\n\t\t}\n\n\t\tparsed = jQuery.buildFragment( [ data ], context, scripts );\n\t\tif ( scripts ) {\n\t\t\tjQuery( scripts ).remove();\n\t\t}\n\t\treturn jQuery.merge( [], parsed.childNodes );\n\t},\n\n\tparseJSON: function( data ) {\n\t\t// Attempt to parse using the native JSON parser first\n\t\tif ( window.JSON && window.JSON.parse ) {\n\t\t\treturn window.JSON.parse( data );\n\t\t}\n\n\t\tif ( data === null ) {\n\t\t\treturn data;\n\t\t}\n\n\t\tif ( typeof data === \"string\" ) {\n\n\t\t\t// Make sure leading/trailing whitespace is removed (IE can't handle it)\n\t\t\tdata = jQuery.trim( data );\n\n\t\t\tif ( data ) {\n\t\t\t\t// Make sure the incoming data is actual JSON\n\t\t\t\t// Logic borrowed from http://json.org/json2.js\n\t\t\t\tif ( rvalidchars.test( data.replace( rvalidescape, \"@\" )\n\t\t\t\t\t.replace( rvalidtokens, \"]\" )\n\t\t\t\t\t.replace( rvalidbraces, \"\")) ) {\n\n\t\t\t\t\treturn ( new Function( \"return \" + data ) )();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tjQuery.error( \"Invalid JSON: \" + data );\n\t},\n\n\t// Cross-browser xml parsing\n\tparseXML: function( data ) {\n\t\tvar xml, tmp;\n\t\tif ( !data || typeof data !== \"string\" ) {\n\t\t\treturn null;\n\t\t}\n\t\ttry {\n\t\t\tif ( window.DOMParser ) { // Standard\n\t\t\t\ttmp = new DOMParser();\n\t\t\t\txml = tmp.parseFromString( data , \"text/xml\" );\n\t\t\t} else { // IE\n\t\t\t\txml = new ActiveXObject( \"Microsoft.XMLDOM\" );\n\t\t\t\txml.async = \"false\";\n\t\t\t\txml.loadXML( data );\n\t\t\t}\n\t\t} catch( e ) {\n\t\t\txml = undefined;\n\t\t}\n\t\tif ( !xml || !xml.documentElement || xml.getElementsByTagName( \"parsererror\" ).length ) {\n\t\t\tjQuery.error( \"Invalid XML: \" + data );\n\t\t}\n\t\treturn xml;\n\t},\n\n\tnoop: function() {},\n\n\t// Evaluates a script in a global context\n\t// Workarounds based on findings by Jim Driscoll\n\t// http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context\n\tglobalEval: function( data ) {\n\t\tif ( data && jQuery.trim( data ) ) {\n\t\t\t// We use execScript on Internet Explorer\n\t\t\t// We use an anonymous function so that context is window\n\t\t\t// rather than jQuery in Firefox\n\t\t\t( window.execScript || function( data ) {\n\t\t\t\twindow[ \"eval\" ].call( window, data );\n\t\t\t} )( data );\n\t\t}\n\t},\n\n\t// Convert dashed to camelCase; used by the css and data modules\n\t// Microsoft forgot to hump their vendor prefix (#9572)\n\tcamelCase: function( string ) {\n\t\treturn string.replace( rmsPrefix, \"ms-\" ).replace( rdashAlpha, fcamelCase );\n\t},\n\n\tnodeName: function( elem, name ) {\n\t\treturn elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();\n\t},\n\n\t// args is for internal usage only\n\teach: function( obj, callback, args ) {\n\t\tvar value,\n\t\t\ti = 0,\n\t\t\tlength = obj.length,\n\t\t\tisArray = isArraylike( obj );\n\n\t\tif ( args ) {\n\t\t\tif ( isArray ) {\n\t\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\t\tvalue = callback.apply( obj[ i ], args );\n\n\t\t\t\t\tif ( value === false ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor ( i in obj ) {\n\t\t\t\t\tvalue = callback.apply( obj[ i ], args );\n\n\t\t\t\t\tif ( value === false ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t// A special, fast, case for the most common use of each\n\t\t} else {\n\t\t\tif ( isArray ) {\n\t\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\t\tvalue = callback.call( obj[ i ], i, obj[ i ] );\n\n\t\t\t\t\tif ( value === false ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor ( i in obj ) {\n\t\t\t\t\tvalue = callback.call( obj[ i ], i, obj[ i ] );\n\n\t\t\t\t\tif ( value === false ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn obj;\n\t},\n\n\t// Use native String.trim function wherever possible\n\ttrim: core_trim && !core_trim.call(\"\\uFEFF\\xA0\") ?\n\t\tfunction( text ) {\n\t\t\treturn text == null ?\n\t\t\t\t\"\" :\n\t\t\t\tcore_trim.call( text );\n\t\t} :\n\n\t\t// Otherwise use our own trimming functionality\n\t\tfunction( text ) {\n\t\t\treturn text == null ?\n\t\t\t\t\"\" :\n\t\t\t\t( text + \"\" ).replace( rtrim, \"\" );\n\t\t},\n\n\t// results is for internal usage only\n\tmakeArray: function( arr, results ) {\n\t\tvar ret = results || [];\n\n\t\tif ( arr != null ) {\n\t\t\tif ( isArraylike( Object(arr) ) ) {\n\t\t\t\tjQuery.merge( ret,\n\t\t\t\t\ttypeof arr === \"string\" ?\n\t\t\t\t\t[ arr ] : arr\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tcore_push.call( ret, arr );\n\t\t\t}\n\t\t}\n\n\t\treturn ret;\n\t},\n\n\tinArray: function( elem, arr, i ) {\n\t\tvar len;\n\n\t\tif ( arr ) {\n\t\t\tif ( core_indexOf ) {\n\t\t\t\treturn core_indexOf.call( arr, elem, i );\n\t\t\t}\n\n\t\t\tlen = arr.length;\n\t\t\ti = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;\n\n\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\t// Skip accessing in sparse arrays\n\t\t\t\tif ( i in arr && arr[ i ] === elem ) {\n\t\t\t\t\treturn i;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn -1;\n\t},\n\n\tmerge: function( first, second ) {\n\t\tvar l = second.length,\n\t\t\ti = first.length,\n\t\t\tj = 0;\n\n\t\tif ( typeof l === \"number\" ) {\n\t\t\tfor ( ; j < l; j++ ) {\n\t\t\t\tfirst[ i++ ] = second[ j ];\n\t\t\t}\n\t\t} else {\n\t\t\twhile ( second[j] !== undefined ) {\n\t\t\t\tfirst[ i++ ] = second[ j++ ];\n\t\t\t}\n\t\t}\n\n\t\tfirst.length = i;\n\n\t\treturn first;\n\t},\n\n\tgrep: function( elems, callback, inv ) {\n\t\tvar retVal,\n\t\t\tret = [],\n\t\t\ti = 0,\n\t\t\tlength = elems.length;\n\t\tinv = !!inv;\n\n\t\t// Go through the array, only saving the items\n\t\t// that pass the validator function\n\t\tfor ( ; i < length; i++ ) {\n\t\t\tretVal = !!callback( elems[ i ], i );\n\t\t\tif ( inv !== retVal ) {\n\t\t\t\tret.push( elems[ i ] );\n\t\t\t}\n\t\t}\n\n\t\treturn ret;\n\t},\n\n\t// arg is for internal usage only\n\tmap: function( elems, callback, arg ) {\n\t\tvar value,\n\t\t\ti = 0,\n\t\t\tlength = elems.length,\n\t\t\tisArray = isArraylike( elems ),\n\t\t\tret = [];\n\n\t\t// Go through the array, translating each of the items to their\n\t\tif ( isArray ) {\n\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\tvalue = callback( elems[ i ], i, arg );\n\n\t\t\t\tif ( value != null ) {\n\t\t\t\t\tret[ ret.length ] = value;\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Go through every key on the object,\n\t\t} else {\n\t\t\tfor ( i in elems ) {\n\t\t\t\tvalue = callback( elems[ i ], i, arg );\n\n\t\t\t\tif ( value != null ) {\n\t\t\t\t\tret[ ret.length ] = value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Flatten any nested arrays\n\t\treturn core_concat.apply( [], ret );\n\t},\n\n\t// A global GUID counter for objects\n\tguid: 1,\n\n\t// Bind a function to a context, optionally partially applying any\n\t// arguments.\n\tproxy: function( fn, context ) {\n\t\tvar args, proxy, tmp;\n\n\t\tif ( typeof context === \"string\" ) {\n\t\t\ttmp = fn[ context ];\n\t\t\tcontext = fn;\n\t\t\tfn = tmp;\n\t\t}\n\n\t\t// Quick check to determine if target is callable, in the spec\n\t\t// this throws a TypeError, but we will just return undefined.\n\t\tif ( !jQuery.isFunction( fn ) ) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\t// Simulated bind\n\t\targs = core_slice.call( arguments, 2 );\n\t\tproxy = function() {\n\t\t\treturn fn.apply( context || this, args.concat( core_slice.call( arguments ) ) );\n\t\t};\n\n\t\t// Set the guid of unique handler to the same of original handler, so it can be removed\n\t\tproxy.guid = fn.guid = fn.guid || jQuery.guid++;\n\n\t\treturn proxy;\n\t},\n\n\t// Multifunctional method to get and set values of a collection\n\t// The value/s can optionally be executed if it's a function\n\taccess: function( elems, fn, key, value, chainable, emptyGet, raw ) {\n\t\tvar i = 0,\n\t\t\tlength = elems.length,\n\t\t\tbulk = key == null;\n\n\t\t// Sets many values\n\t\tif ( jQuery.type( key ) === \"object\" ) {\n\t\t\tchainable = true;\n\t\t\tfor ( i in key ) {\n\t\t\t\tjQuery.access( elems, fn, i, key[i], true, emptyGet, raw );\n\t\t\t}\n\n\t\t// Sets one value\n\t\t} else if ( value !== undefined ) {\n\t\t\tchainable = true;\n\n\t\t\tif ( !jQuery.isFunction( value ) ) {\n\t\t\t\traw = true;\n\t\t\t}\n\n\t\t\tif ( bulk ) {\n\t\t\t\t// Bulk operations run against the entire set\n\t\t\t\tif ( raw ) {\n\t\t\t\t\tfn.call( elems, value );\n\t\t\t\t\tfn = null;\n\n\t\t\t\t// ...except when executing function values\n\t\t\t\t} else {\n\t\t\t\t\tbulk = fn;\n\t\t\t\t\tfn = function( elem, key, value ) {\n\t\t\t\t\t\treturn bulk.call( jQuery( elem ), value );\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( fn ) {\n\t\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\t\tfn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn chainable ?\n\t\t\telems :\n\n\t\t\t// Gets\n\t\t\tbulk ?\n\t\t\t\tfn.call( elems ) :\n\t\t\t\tlength ? fn( elems[0], key ) : emptyGet;\n\t},\n\n\tnow: function() {\n\t\treturn ( new Date() ).getTime();\n\t}\n});\n\njQuery.ready.promise = function( obj ) {\n\tif ( !readyList ) {\n\n\t\treadyList = jQuery.Deferred();\n\n\t\t// Catch cases where $(document).ready() is called after the browser event has already occurred.\n\t\t// we once tried to use readyState \"interactive\" here, but it caused issues like the one\n\t\t// discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15\n\t\tif ( document.readyState === \"complete\" ) {\n\t\t\t// Handle it asynchronously to allow scripts the opportunity to delay ready\n\t\t\tsetTimeout( jQuery.ready );\n\n\t\t// Standards-based browsers support DOMContentLoaded\n\t\t} else if ( document.addEventListener ) {\n\t\t\t// Use the handy event callback\n\t\t\tdocument.addEventListener( \"DOMContentLoaded\", completed, false );\n\n\t\t\t// A fallback to window.onload, that will always work\n\t\t\twindow.addEventListener( \"load\", completed, false );\n\n\t\t// If IE event model is used\n\t\t} else {\n\t\t\t// Ensure firing before onload, maybe late but safe also for iframes\n\t\t\tdocument.attachEvent( \"onreadystatechange\", completed );\n\n\t\t\t// A fallback to window.onload, that will always work\n\t\t\twindow.attachEvent( \"onload\", completed );\n\n\t\t\t// If IE and not a frame\n\t\t\t// continually check to see if the document is ready\n\t\t\tvar top = false;\n\n\t\t\ttry {\n\t\t\t\ttop = window.frameElement == null && document.documentElement;\n\t\t\t} catch(e) {}\n\n\t\t\tif ( top && top.doScroll ) {\n\t\t\t\t(function doScrollCheck() {\n\t\t\t\t\tif ( !jQuery.isReady ) {\n\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t// Use the trick by Diego Perini\n\t\t\t\t\t\t\t// http://javascript.nwbox.com/IEContentLoaded/\n\t\t\t\t\t\t\ttop.doScroll(\"left\");\n\t\t\t\t\t\t} catch(e) {\n\t\t\t\t\t\t\treturn setTimeout( doScrollCheck, 50 );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// detach all dom ready events\n\t\t\t\t\t\tdetach();\n\n\t\t\t\t\t\t// and execute any waiting functions\n\t\t\t\t\t\tjQuery.ready();\n\t\t\t\t\t}\n\t\t\t\t})();\n\t\t\t}\n\t\t}\n\t}\n\treturn readyList.promise( obj );\n};\n\n// Populate the class2type map\njQuery.each(\"Boolean Number String Function Array Date RegExp Object Error\".split(\" \"), function(i, name) {\n\tclass2type[ \"[object \" + name + \"]\" ] = name.toLowerCase();\n});\n\nfunction isArraylike( obj ) {\n\tvar length = obj.length,\n\t\ttype = jQuery.type( obj );\n\n\tif ( jQuery.isWindow( obj ) ) {\n\t\treturn false;\n\t}\n\n\tif ( obj.nodeType === 1 && length ) {\n\t\treturn true;\n\t}\n\n\treturn type === \"array\" || type !== \"function\" &&\n\t\t( length === 0 ||\n\t\ttypeof length === \"number\" && length > 0 && ( length - 1 ) in obj );\n}\n\n// All jQuery objects should point back to these\nrootjQuery = jQuery(document);\n// String to Object options format cache\nvar optionsCache = {};\n\n// Convert String-formatted options into Object-formatted ones and store in cache\nfunction createOptions( options ) {\n\tvar object = optionsCache[ options ] = {};\n\tjQuery.each( options.match( core_rnotwhite ) || [], function( _, flag ) {\n\t\tobject[ flag ] = true;\n\t});\n\treturn object;\n}\n\n/*\n * Create a callback list using the following parameters:\n *\n *\toptions: an optional list of space-separated options that will change how\n *\t\t\tthe callback list behaves or a more traditional option object\n *\n * By default a callback list will act like an event callback list and can be\n * \"fired\" multiple times.\n *\n * Possible options:\n *\n *\tonce:\t\t\twill ensure the callback list can only be fired once (like a Deferred)\n *\n *\tmemory:\t\t\twill keep track of previous values and will call any callback added\n *\t\t\t\t\tafter the list has been fired right away with the latest \"memorized\"\n *\t\t\t\t\tvalues (like a Deferred)\n *\n *\tunique:\t\t\twill ensure a callback can only be added once (no duplicate in the list)\n *\n *\tstopOnFalse:\tinterrupt callings when a callback returns false\n *\n */\njQuery.Callbacks = function( options ) {\n\n\t// Convert options from String-formatted to Object-formatted if needed\n\t// (we check in cache first)\n\toptions = typeof options === \"string\" ?\n\t\t( optionsCache[ options ] || createOptions( options ) ) :\n\t\tjQuery.extend( {}, options );\n\n\tvar // Flag to know if list is currently firing\n\t\tfiring,\n\t\t// Last fire value (for non-forgettable lists)\n\t\tmemory,\n\t\t// Flag to know if list was already fired\n\t\tfired,\n\t\t// End of the loop when firing\n\t\tfiringLength,\n\t\t// Index of currently firing callback (modified by remove if needed)\n\t\tfiringIndex,\n\t\t// First callback to fire (used internally by add and fireWith)\n\t\tfiringStart,\n\t\t// Actual callback list\n\t\tlist = [],\n\t\t// Stack of fire calls for repeatable lists\n\t\tstack = !options.once && [],\n\t\t// Fire callbacks\n\t\tfire = function( data ) {\n\t\t\tmemory = options.memory && data;\n\t\t\tfired = true;\n\t\t\tfiringIndex = firingStart || 0;\n\t\t\tfiringStart = 0;\n\t\t\tfiringLength = list.length;\n\t\t\tfiring = true;\n\t\t\tfor ( ; list && firingIndex < firingLength; firingIndex++ ) {\n\t\t\t\tif ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {\n\t\t\t\t\tmemory = false; // To prevent further calls using add\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tfiring = false;\n\t\t\tif ( list ) {\n\t\t\t\tif ( stack ) {\n\t\t\t\t\tif ( stack.length ) {\n\t\t\t\t\t\tfire( stack.shift() );\n\t\t\t\t\t}\n\t\t\t\t} else if ( memory ) {\n\t\t\t\t\tlist = [];\n\t\t\t\t} else {\n\t\t\t\t\tself.disable();\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t// Actual Callbacks object\n\t\tself = {\n\t\t\t// Add a callback or a collection of callbacks to the list\n\t\t\tadd: function() {\n\t\t\t\tif ( list ) {\n\t\t\t\t\t// First, we save the current length\n\t\t\t\t\tvar start = list.length;\n\t\t\t\t\t(function add( args ) {\n\t\t\t\t\t\tjQuery.each( args, function( _, arg ) {\n\t\t\t\t\t\t\tvar type = jQuery.type( arg );\n\t\t\t\t\t\t\tif ( type === \"function\" ) {\n\t\t\t\t\t\t\t\tif ( !options.unique || !self.has( arg ) ) {\n\t\t\t\t\t\t\t\t\tlist.push( arg );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else if ( arg && arg.length && type !== \"string\" ) {\n\t\t\t\t\t\t\t\t// Inspect recursively\n\t\t\t\t\t\t\t\tadd( arg );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t})( arguments );\n\t\t\t\t\t// Do we need to add the callbacks to the\n\t\t\t\t\t// current firing batch?\n\t\t\t\t\tif ( firing ) {\n\t\t\t\t\t\tfiringLength = list.length;\n\t\t\t\t\t// With memory, if we're not firing then\n\t\t\t\t\t// we should call right away\n\t\t\t\t\t} else if ( memory ) {\n\t\t\t\t\t\tfiringStart = start;\n\t\t\t\t\t\tfire( memory );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// Remove a callback from the list\n\t\t\tremove: function() {\n\t\t\t\tif ( list ) {\n\t\t\t\t\tjQuery.each( arguments, function( _, arg ) {\n\t\t\t\t\t\tvar index;\n\t\t\t\t\t\twhile( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {\n\t\t\t\t\t\t\tlist.splice( index, 1 );\n\t\t\t\t\t\t\t// Handle firing indexes\n\t\t\t\t\t\t\tif ( firing ) {\n\t\t\t\t\t\t\t\tif ( index <= firingLength ) {\n\t\t\t\t\t\t\t\t\tfiringLength--;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif ( index <= firingIndex ) {\n\t\t\t\t\t\t\t\t\tfiringIndex--;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// Check if a given callback is in the list.\n\t\t\t// If no argument is given, return whether or not list has callbacks attached.\n\t\t\thas: function( fn ) {\n\t\t\t\treturn fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );\n\t\t\t},\n\t\t\t// Remove all callbacks from the list\n\t\t\tempty: function() {\n\t\t\t\tlist = [];\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// Have the list do nothing anymore\n\t\t\tdisable: function() {\n\t\t\t\tlist = stack = memory = undefined;\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// Is it disabled?\n\t\t\tdisabled: function() {\n\t\t\t\treturn !list;\n\t\t\t},\n\t\t\t// Lock the list in its current state\n\t\t\tlock: function() {\n\t\t\t\tstack = undefined;\n\t\t\t\tif ( !memory ) {\n\t\t\t\t\tself.disable();\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// Is it locked?\n\t\t\tlocked: function() {\n\t\t\t\treturn !stack;\n\t\t\t},\n\t\t\t// Call all callbacks with the given context and arguments\n\t\t\tfireWith: function( context, args ) {\n\t\t\t\targs = args || [];\n\t\t\t\targs = [ context, args.slice ? args.slice() : args ];\n\t\t\t\tif ( list && ( !fired || stack ) ) {\n\t\t\t\t\tif ( firing ) {\n\t\t\t\t\t\tstack.push( args );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tfire( args );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// Call all the callbacks with the given arguments\n\t\t\tfire: function() {\n\t\t\t\tself.fireWith( this, arguments );\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// To know if the callbacks have already been called at least once\n\t\t\tfired: function() {\n\t\t\t\treturn !!fired;\n\t\t\t}\n\t\t};\n\n\treturn self;\n};\njQuery.extend({\n\n\tDeferred: function( func ) {\n\t\tvar tuples = [\n\t\t\t\t// action, add listener, listener list, final state\n\t\t\t\t[ \"resolve\", \"done\", jQuery.Callbacks(\"once memory\"), \"resolved\" ],\n\t\t\t\t[ \"reject\", \"fail\", jQuery.Callbacks(\"once memory\"), \"rejected\" ],\n\t\t\t\t[ \"notify\", \"progress\", jQuery.Callbacks(\"memory\") ]\n\t\t\t],\n\t\t\tstate = \"pending\",\n\t\t\tpromise = {\n\t\t\t\tstate: function() {\n\t\t\t\t\treturn state;\n\t\t\t\t},\n\t\t\t\talways: function() {\n\t\t\t\t\tdeferred.done( arguments ).fail( arguments );\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\t\t\t\tthen: function( /* fnDone, fnFail, fnProgress */ ) {\n\t\t\t\t\tvar fns = arguments;\n\t\t\t\t\treturn jQuery.Deferred(function( newDefer ) {\n\t\t\t\t\t\tjQuery.each( tuples, function( i, tuple ) {\n\t\t\t\t\t\t\tvar action = tuple[ 0 ],\n\t\t\t\t\t\t\t\tfn = jQuery.isFunction( fns[ i ] ) && fns[ i ];\n\t\t\t\t\t\t\t// deferred[ done | fail | progress ] for forwarding actions to newDefer\n\t\t\t\t\t\t\tdeferred[ tuple[1] ](function() {\n\t\t\t\t\t\t\t\tvar returned = fn && fn.apply( this, arguments );\n\t\t\t\t\t\t\t\tif ( returned && jQuery.isFunction( returned.promise ) ) {\n\t\t\t\t\t\t\t\t\treturned.promise()\n\t\t\t\t\t\t\t\t\t\t.done( newDefer.resolve )\n\t\t\t\t\t\t\t\t\t\t.fail( newDefer.reject )\n\t\t\t\t\t\t\t\t\t\t.progress( newDefer.notify );\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tnewDefer[ action + \"With\" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t});\n\t\t\t\t\t\tfns = null;\n\t\t\t\t\t}).promise();\n\t\t\t\t},\n\t\t\t\t// Get a promise for this deferred\n\t\t\t\t// If obj is provided, the promise aspect is added to the object\n\t\t\t\tpromise: function( obj ) {\n\t\t\t\t\treturn obj != null ? jQuery.extend( obj, promise ) : promise;\n\t\t\t\t}\n\t\t\t},\n\t\t\tdeferred = {};\n\n\t\t// Keep pipe for back-compat\n\t\tpromise.pipe = promise.then;\n\n\t\t// Add list-specific methods\n\t\tjQuery.each( tuples, function( i, tuple ) {\n\t\t\tvar list = tuple[ 2 ],\n\t\t\t\tstateString = tuple[ 3 ];\n\n\t\t\t// promise[ done | fail | progress ] = list.add\n\t\t\tpromise[ tuple[1] ] = list.add;\n\n\t\t\t// Handle state\n\t\t\tif ( stateString ) {\n\t\t\t\tlist.add(function() {\n\t\t\t\t\t// state = [ resolved | rejected ]\n\t\t\t\t\tstate = stateString;\n\n\t\t\t\t// [ reject_list | resolve_list ].disable; progress_list.lock\n\t\t\t\t}, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );\n\t\t\t}\n\n\t\t\t// deferred[ resolve | reject | notify ]\n\t\t\tdeferred[ tuple[0] ] = function() {\n\t\t\t\tdeferred[ tuple[0] + \"With\" ]( this === deferred ? promise : this, arguments );\n\t\t\t\treturn this;\n\t\t\t};\n\t\t\tdeferred[ tuple[0] + \"With\" ] = list.fireWith;\n\t\t});\n\n\t\t// Make the deferred a promise\n\t\tpromise.promise( deferred );\n\n\t\t// Call given func if any\n\t\tif ( func ) {\n\t\t\tfunc.call( deferred, deferred );\n\t\t}\n\n\t\t// All done!\n\t\treturn deferred;\n\t},\n\n\t// Deferred helper\n\twhen: function( subordinate /* , ..., subordinateN */ ) {\n\t\tvar i = 0,\n\t\t\tresolveValues = core_slice.call( arguments ),\n\t\t\tlength = resolveValues.length,\n\n\t\t\t// the count of uncompleted subordinates\n\t\t\tremaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,\n\n\t\t\t// the master Deferred. If resolveValues consist of only a single Deferred, just use that.\n\t\t\tdeferred = remaining === 1 ? subordinate : jQuery.Deferred(),\n\n\t\t\t// Update function for both resolve and progress values\n\t\t\tupdateFunc = function( i, contexts, values ) {\n\t\t\t\treturn function( value ) {\n\t\t\t\t\tcontexts[ i ] = this;\n\t\t\t\t\tvalues[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value;\n\t\t\t\t\tif( values === progressValues ) {\n\t\t\t\t\t\tdeferred.notifyWith( contexts, values );\n\t\t\t\t\t} else if ( !( --remaining ) ) {\n\t\t\t\t\t\tdeferred.resolveWith( contexts, values );\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t},\n\n\t\t\tprogressValues, progressContexts, resolveContexts;\n\n\t\t// add listeners to Deferred subordinates; treat others as resolved\n\t\tif ( length > 1 ) {\n\t\t\tprogressValues = new Array( length );\n\t\t\tprogressContexts = new Array( length );\n\t\t\tresolveContexts = new Array( length );\n\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\tif ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {\n\t\t\t\t\tresolveValues[ i ].promise()\n\t\t\t\t\t\t.done( updateFunc( i, resolveContexts, resolveValues ) )\n\t\t\t\t\t\t.fail( deferred.reject )\n\t\t\t\t\t\t.progress( updateFunc( i, progressContexts, progressValues ) );\n\t\t\t\t} else {\n\t\t\t\t\t--remaining;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// if we're not waiting on anything, resolve the master\n\t\tif ( !remaining ) {\n\t\t\tdeferred.resolveWith( resolveContexts, resolveValues );\n\t\t}\n\n\t\treturn deferred.promise();\n\t}\n});\njQuery.support = (function() {\n\n\tvar support, all, a,\n\t\tinput, select, fragment,\n\t\topt, eventName, isSupported, i,\n\t\tdiv = document.createElement(\"div\");\n\n\t// Setup\n\tdiv.setAttribute( \"className\", \"t\" );\n\tdiv.innerHTML = \"  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>\";\n\n\t// Support tests won't run in some limited or non-browser environments\n\tall = div.getElementsByTagName(\"*\");\n\ta = div.getElementsByTagName(\"a\")[ 0 ];\n\tif ( !all || !a || !all.length ) {\n\t\treturn {};\n\t}\n\n\t// First batch of tests\n\tselect = document.createElement(\"select\");\n\topt = select.appendChild( document.createElement(\"option\") );\n\tinput = div.getElementsByTagName(\"input\")[ 0 ];\n\n\ta.style.cssText = \"top:1px;float:left;opacity:.5\";\n\tsupport = {\n\t\t// Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)\n\t\tgetSetAttribute: div.className !== \"t\",\n\n\t\t// IE strips leading whitespace when .innerHTML is used\n\t\tleadingWhitespace: div.firstChild.nodeType === 3,\n\n\t\t// Make sure that tbody elements aren't automatically inserted\n\t\t// IE will insert them into empty tables\n\t\ttbody: !div.getElementsByTagName(\"tbody\").length,\n\n\t\t// Make sure that link elements get serialized correctly by innerHTML\n\t\t// This requires a wrapper element in IE\n\t\thtmlSerialize: !!div.getElementsByTagName(\"link\").length,\n\n\t\t// Get the style information from getAttribute\n\t\t// (IE uses .cssText instead)\n\t\tstyle: /top/.test( a.getAttribute(\"style\") ),\n\n\t\t// Make sure that URLs aren't manipulated\n\t\t// (IE normalizes it by default)\n\t\threfNormalized: a.getAttribute(\"href\") === \"/a\",\n\n\t\t// Make sure that element opacity exists\n\t\t// (IE uses filter instead)\n\t\t// Use a regex to work around a WebKit issue. See #5145\n\t\topacity: /^0.5/.test( a.style.opacity ),\n\n\t\t// Verify style float existence\n\t\t// (IE uses styleFloat instead of cssFloat)\n\t\tcssFloat: !!a.style.cssFloat,\n\n\t\t// Check the default checkbox/radio value (\"\" on WebKit; \"on\" elsewhere)\n\t\tcheckOn: !!input.value,\n\n\t\t// Make sure that a selected-by-default option has a working selected property.\n\t\t// (WebKit defaults to false instead of true, IE too, if it's in an optgroup)\n\t\toptSelected: opt.selected,\n\n\t\t// Tests for enctype support on a form (#6743)\n\t\tenctype: !!document.createElement(\"form\").enctype,\n\n\t\t// Makes sure cloning an html5 element does not cause problems\n\t\t// Where outerHTML is undefined, this still works\n\t\thtml5Clone: document.createElement(\"nav\").cloneNode( true ).outerHTML !== \"<:nav></:nav>\",\n\n\t\t// jQuery.support.boxModel DEPRECATED in 1.8 since we don't support Quirks Mode\n\t\tboxModel: document.compatMode === \"CSS1Compat\",\n\n\t\t// Will be defined later\n\t\tdeleteExpando: true,\n\t\tnoCloneEvent: true,\n\t\tinlineBlockNeedsLayout: false,\n\t\tshrinkWrapBlocks: false,\n\t\treliableMarginRight: true,\n\t\tboxSizingReliable: true,\n\t\tpixelPosition: false\n\t};\n\n\t// Make sure checked status is properly cloned\n\tinput.checked = true;\n\tsupport.noCloneChecked = input.cloneNode( true ).checked;\n\n\t// Make sure that the options inside disabled selects aren't marked as disabled\n\t// (WebKit marks them as disabled)\n\tselect.disabled = true;\n\tsupport.optDisabled = !opt.disabled;\n\n\t// Support: IE<9\n\ttry {\n\t\tdelete div.test;\n\t} catch( e ) {\n\t\tsupport.deleteExpando = false;\n\t}\n\n\t// Check if we can trust getAttribute(\"value\")\n\tinput = document.createElement(\"input\");\n\tinput.setAttribute( \"value\", \"\" );\n\tsupport.input = input.getAttribute( \"value\" ) === \"\";\n\n\t// Check if an input maintains its value after becoming a radio\n\tinput.value = \"t\";\n\tinput.setAttribute( \"type\", \"radio\" );\n\tsupport.radioValue = input.value === \"t\";\n\n\t// #11217 - WebKit loses check when the name is after the checked attribute\n\tinput.setAttribute( \"checked\", \"t\" );\n\tinput.setAttribute( \"name\", \"t\" );\n\n\tfragment = document.createDocumentFragment();\n\tfragment.appendChild( input );\n\n\t// Check if a disconnected checkbox will retain its checked\n\t// value of true after appended to the DOM (IE6/7)\n\tsupport.appendChecked = input.checked;\n\n\t// WebKit doesn't clone checked state correctly in fragments\n\tsupport.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;\n\n\t// Support: IE<9\n\t// Opera does not clone events (and typeof div.attachEvent === undefined).\n\t// IE9-10 clones events bound via attachEvent, but they don't trigger with .click()\n\tif ( div.attachEvent ) {\n\t\tdiv.attachEvent( \"onclick\", function() {\n\t\t\tsupport.noCloneEvent = false;\n\t\t});\n\n\t\tdiv.cloneNode( true ).click();\n\t}\n\n\t// Support: IE<9 (lack submit/change bubble), Firefox 17+ (lack focusin event)\n\t// Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP), test/csp.php\n\tfor ( i in { submit: true, change: true, focusin: true }) {\n\t\tdiv.setAttribute( eventName = \"on\" + i, \"t\" );\n\n\t\tsupport[ i + \"Bubbles\" ] = eventName in window || div.attributes[ eventName ].expando === false;\n\t}\n\n\tdiv.style.backgroundClip = \"content-box\";\n\tdiv.cloneNode( true ).style.backgroundClip = \"\";\n\tsupport.clearCloneStyle = div.style.backgroundClip === \"content-box\";\n\n\t// Run tests that need a body at doc ready\n\tjQuery(function() {\n\t\tvar container, marginDiv, tds,\n\t\t\tdivReset = \"padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;\",\n\t\t\tbody = document.getElementsByTagName(\"body\")[0];\n\n\t\tif ( !body ) {\n\t\t\t// Return for frameset docs that don't have a body\n\t\t\treturn;\n\t\t}\n\n\t\tcontainer = document.createElement(\"div\");\n\t\tcontainer.style.cssText = \"border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px\";\n\n\t\tbody.appendChild( container ).appendChild( div );\n\n\t\t// Support: IE8\n\t\t// Check if table cells still have offsetWidth/Height when they are set\n\t\t// to display:none and there are still other visible table cells in a\n\t\t// table row; if so, offsetWidth/Height are not reliable for use when\n\t\t// determining if an element has been hidden directly using\n\t\t// display:none (it is still safe to use offsets if a parent element is\n\t\t// hidden; don safety goggles and see bug #4512 for more information).\n\t\tdiv.innerHTML = \"<table><tr><td></td><td>t</td></tr></table>\";\n\t\ttds = div.getElementsByTagName(\"td\");\n\t\ttds[ 0 ].style.cssText = \"padding:0;margin:0;border:0;display:none\";\n\t\tisSupported = ( tds[ 0 ].offsetHeight === 0 );\n\n\t\ttds[ 0 ].style.display = \"\";\n\t\ttds[ 1 ].style.display = \"none\";\n\n\t\t// Support: IE8\n\t\t// Check if empty table cells still have offsetWidth/Height\n\t\tsupport.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );\n\n\t\t// Check box-sizing and margin behavior\n\t\tdiv.innerHTML = \"\";\n\t\tdiv.style.cssText = \"box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;\";\n\t\tsupport.boxSizing = ( div.offsetWidth === 4 );\n\t\tsupport.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== 1 );\n\n\t\t// Use window.getComputedStyle because jsdom on node.js will break without it.\n\t\tif ( window.getComputedStyle ) {\n\t\t\tsupport.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== \"1%\";\n\t\t\tsupport.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: \"4px\" } ).width === \"4px\";\n\n\t\t\t// Check if div with explicit width and no margin-right incorrectly\n\t\t\t// gets computed margin-right based on width of container. (#3333)\n\t\t\t// Fails in WebKit before Feb 2011 nightlies\n\t\t\t// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right\n\t\t\tmarginDiv = div.appendChild( document.createElement(\"div\") );\n\t\t\tmarginDiv.style.cssText = div.style.cssText = divReset;\n\t\t\tmarginDiv.style.marginRight = marginDiv.style.width = \"0\";\n\t\t\tdiv.style.width = \"1px\";\n\n\t\t\tsupport.reliableMarginRight =\n\t\t\t\t!parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight );\n\t\t}\n\n\t\tif ( typeof div.style.zoom !== core_strundefined ) {\n\t\t\t// Support: IE<8\n\t\t\t// Check if natively block-level elements act like inline-block\n\t\t\t// elements when setting their display to 'inline' and giving\n\t\t\t// them layout\n\t\t\tdiv.innerHTML = \"\";\n\t\t\tdiv.style.cssText = divReset + \"width:1px;padding:1px;display:inline;zoom:1\";\n\t\t\tsupport.inlineBlockNeedsLayout = ( div.offsetWidth === 3 );\n\n\t\t\t// Support: IE6\n\t\t\t// Check if elements with layout shrink-wrap their children\n\t\t\tdiv.style.display = \"block\";\n\t\t\tdiv.innerHTML = \"<div></div>\";\n\t\t\tdiv.firstChild.style.width = \"5px\";\n\t\t\tsupport.shrinkWrapBlocks = ( div.offsetWidth !== 3 );\n\n\t\t\tif ( support.inlineBlockNeedsLayout ) {\n\t\t\t\t// Prevent IE 6 from affecting layout for positioned elements #11048\n\t\t\t\t// Prevent IE from shrinking the body in IE 7 mode #12869\n\t\t\t\t// Support: IE<8\n\t\t\t\tbody.style.zoom = 1;\n\t\t\t}\n\t\t}\n\n\t\tbody.removeChild( container );\n\n\t\t// Null elements to avoid leaks in IE\n\t\tcontainer = div = tds = marginDiv = null;\n\t});\n\n\t// Null elements to avoid leaks in IE\n\tall = select = fragment = opt = a = input = null;\n\n\treturn support;\n})();\n\nvar rbrace = /(?:\\{[\\s\\S]*\\}|\\[[\\s\\S]*\\])$/,\n\trmultiDash = /([A-Z])/g;\n\nfunction internalData( elem, name, data, pvt /* Internal Use Only */ ){\n\tif ( !jQuery.acceptData( elem ) ) {\n\t\treturn;\n\t}\n\n\tvar thisCache, ret,\n\t\tinternalKey = jQuery.expando,\n\t\tgetByName = typeof name === \"string\",\n\n\t\t// We have to handle DOM nodes and JS objects differently because IE6-7\n\t\t// can't GC object references properly across the DOM-JS boundary\n\t\tisNode = elem.nodeType,\n\n\t\t// Only DOM nodes need the global jQuery cache; JS object data is\n\t\t// attached directly to the object so GC can occur automatically\n\t\tcache = isNode ? jQuery.cache : elem,\n\n\t\t// Only defining an ID for JS objects if its cache already exists allows\n\t\t// the code to shortcut on the same path as a DOM node with no cache\n\t\tid = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey;\n\n\t// Avoid doing any more work than we need to when trying to get data on an\n\t// object that has no data at all\n\tif ( (!id || !cache[id] || (!pvt && !cache[id].data)) && getByName && data === undefined ) {\n\t\treturn;\n\t}\n\n\tif ( !id ) {\n\t\t// Only DOM nodes need a new unique ID for each element since their data\n\t\t// ends up in the global cache\n\t\tif ( isNode ) {\n\t\t\telem[ internalKey ] = id = core_deletedIds.pop() || jQuery.guid++;\n\t\t} else {\n\t\t\tid = internalKey;\n\t\t}\n\t}\n\n\tif ( !cache[ id ] ) {\n\t\tcache[ id ] = {};\n\n\t\t// Avoids exposing jQuery metadata on plain JS objects when the object\n\t\t// is serialized using JSON.stringify\n\t\tif ( !isNode ) {\n\t\t\tcache[ id ].toJSON = jQuery.noop;\n\t\t}\n\t}\n\n\t// An object can be passed to jQuery.data instead of a key/value pair; this gets\n\t// shallow copied over onto the existing cache\n\tif ( typeof name === \"object\" || typeof name === \"function\" ) {\n\t\tif ( pvt ) {\n\t\t\tcache[ id ] = jQuery.extend( cache[ id ], name );\n\t\t} else {\n\t\t\tcache[ id ].data = jQuery.extend( cache[ id ].data, name );\n\t\t}\n\t}\n\n\tthisCache = cache[ id ];\n\n\t// jQuery data() is stored in a separate object inside the object's internal data\n\t// cache in order to avoid key collisions between internal data and user-defined\n\t// data.\n\tif ( !pvt ) {\n\t\tif ( !thisCache.data ) {\n\t\t\tthisCache.data = {};\n\t\t}\n\n\t\tthisCache = thisCache.data;\n\t}\n\n\tif ( data !== undefined ) {\n\t\tthisCache[ jQuery.camelCase( name ) ] = data;\n\t}\n\n\t// Check for both converted-to-camel and non-converted data property names\n\t// If a data property was specified\n\tif ( getByName ) {\n\n\t\t// First Try to find as-is property data\n\t\tret = thisCache[ name ];\n\n\t\t// Test for null|undefined property data\n\t\tif ( ret == null ) {\n\n\t\t\t// Try to find the camelCased property\n\t\t\tret = thisCache[ jQuery.camelCase( name ) ];\n\t\t}\n\t} else {\n\t\tret = thisCache;\n\t}\n\n\treturn ret;\n}\n\nfunction internalRemoveData( elem, name, pvt ) {\n\tif ( !jQuery.acceptData( elem ) ) {\n\t\treturn;\n\t}\n\n\tvar i, l, thisCache,\n\t\tisNode = elem.nodeType,\n\n\t\t// See jQuery.data for more information\n\t\tcache = isNode ? jQuery.cache : elem,\n\t\tid = isNode ? elem[ jQuery.expando ] : jQuery.expando;\n\n\t// If there is already no cache entry for this object, there is no\n\t// purpose in continuing\n\tif ( !cache[ id ] ) {\n\t\treturn;\n\t}\n\n\tif ( name ) {\n\n\t\tthisCache = pvt ? cache[ id ] : cache[ id ].data;\n\n\t\tif ( thisCache ) {\n\n\t\t\t// Support array or space separated string names for data keys\n\t\t\tif ( !jQuery.isArray( name ) ) {\n\n\t\t\t\t// try the string as a key before any manipulation\n\t\t\t\tif ( name in thisCache ) {\n\t\t\t\t\tname = [ name ];\n\t\t\t\t} else {\n\n\t\t\t\t\t// split the camel cased version by spaces unless a key with the spaces exists\n\t\t\t\t\tname = jQuery.camelCase( name );\n\t\t\t\t\tif ( name in thisCache ) {\n\t\t\t\t\t\tname = [ name ];\n\t\t\t\t\t} else {\n\t\t\t\t\t\tname = name.split(\" \");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// If \"name\" is an array of keys...\n\t\t\t\t// When data is initially created, via (\"key\", \"val\") signature,\n\t\t\t\t// keys will be converted to camelCase.\n\t\t\t\t// Since there is no way to tell _how_ a key was added, remove\n\t\t\t\t// both plain key and camelCase key. #12786\n\t\t\t\t// This will only penalize the array argument path.\n\t\t\t\tname = name.concat( jQuery.map( name, jQuery.camelCase ) );\n\t\t\t}\n\n\t\t\tfor ( i = 0, l = name.length; i < l; i++ ) {\n\t\t\t\tdelete thisCache[ name[i] ];\n\t\t\t}\n\n\t\t\t// If there is no data left in the cache, we want to continue\n\t\t\t// and let the cache object itself get destroyed\n\t\t\tif ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\t// See jQuery.data for more information\n\tif ( !pvt ) {\n\t\tdelete cache[ id ].data;\n\n\t\t// Don't destroy the parent cache unless the internal data object\n\t\t// had been the only thing left in it\n\t\tif ( !isEmptyDataObject( cache[ id ] ) ) {\n\t\t\treturn;\n\t\t}\n\t}\n\n\t// Destroy the cache\n\tif ( isNode ) {\n\t\tjQuery.cleanData( [ elem ], true );\n\n\t// Use delete when supported for expandos or `cache` is not a window per isWindow (#10080)\n\t} else if ( jQuery.support.deleteExpando || cache != cache.window ) {\n\t\tdelete cache[ id ];\n\n\t// When all else fails, null\n\t} else {\n\t\tcache[ id ] = null;\n\t}\n}\n\njQuery.extend({\n\tcache: {},\n\n\t// Unique for each copy of jQuery on the page\n\t// Non-digits removed to match rinlinejQuery\n\texpando: \"jQuery\" + ( core_version + Math.random() ).replace( /\\D/g, \"\" ),\n\n\t// The following elements throw uncatchable exceptions if you\n\t// attempt to add expando properties to them.\n\tnoData: {\n\t\t\"embed\": true,\n\t\t// Ban all objects except for Flash (which handle expandos)\n\t\t\"object\": \"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\",\n\t\t\"applet\": true\n\t},\n\n\thasData: function( elem ) {\n\t\telem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];\n\t\treturn !!elem && !isEmptyDataObject( elem );\n\t},\n\n\tdata: function( elem, name, data ) {\n\t\treturn internalData( elem, name, data );\n\t},\n\n\tremoveData: function( elem, name ) {\n\t\treturn internalRemoveData( elem, name );\n\t},\n\n\t// For internal use only.\n\t_data: function( elem, name, data ) {\n\t\treturn internalData( elem, name, data, true );\n\t},\n\n\t_removeData: function( elem, name ) {\n\t\treturn internalRemoveData( elem, name, true );\n\t},\n\n\t// A method for determining if a DOM node can handle the data expando\n\tacceptData: function( elem ) {\n\t\t// Do not set data on non-element because it will not be cleared (#8335).\n\t\tif ( elem.nodeType && elem.nodeType !== 1 && elem.nodeType !== 9 ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tvar noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ];\n\n\t\t// nodes accept data unless otherwise specified; rejection can be conditional\n\t\treturn !noData || noData !== true && elem.getAttribute(\"classid\") === noData;\n\t}\n});\n\njQuery.fn.extend({\n\tdata: function( key, value ) {\n\t\tvar attrs, name,\n\t\t\telem = this[0],\n\t\t\ti = 0,\n\t\t\tdata = null;\n\n\t\t// Gets all values\n\t\tif ( key === undefined ) {\n\t\t\tif ( this.length ) {\n\t\t\t\tdata = jQuery.data( elem );\n\n\t\t\t\tif ( elem.nodeType === 1 && !jQuery._data( elem, \"parsedAttrs\" ) ) {\n\t\t\t\t\tattrs = elem.attributes;\n\t\t\t\t\tfor ( ; i < attrs.length; i++ ) {\n\t\t\t\t\t\tname = attrs[i].name;\n\n\t\t\t\t\t\tif ( !name.indexOf( \"data-\" ) ) {\n\t\t\t\t\t\t\tname = jQuery.camelCase( name.slice(5) );\n\n\t\t\t\t\t\t\tdataAttr( elem, name, data[ name ] );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tjQuery._data( elem, \"parsedAttrs\", true );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn data;\n\t\t}\n\n\t\t// Sets multiple values\n\t\tif ( typeof key === \"object\" ) {\n\t\t\treturn this.each(function() {\n\t\t\t\tjQuery.data( this, key );\n\t\t\t});\n\t\t}\n\n\t\treturn jQuery.access( this, function( value ) {\n\n\t\t\tif ( value === undefined ) {\n\t\t\t\t// Try to fetch any internally stored data first\n\t\t\t\treturn elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : null;\n\t\t\t}\n\n\t\t\tthis.each(function() {\n\t\t\t\tjQuery.data( this, key, value );\n\t\t\t});\n\t\t}, null, value, arguments.length > 1, null, true );\n\t},\n\n\tremoveData: function( key ) {\n\t\treturn this.each(function() {\n\t\t\tjQuery.removeData( this, key );\n\t\t});\n\t}\n});\n\nfunction dataAttr( elem, key, data ) {\n\t// If nothing was found internally, try to fetch any\n\t// data from the HTML5 data-* attribute\n\tif ( data === undefined && elem.nodeType === 1 ) {\n\n\t\tvar name = \"data-\" + key.replace( rmultiDash, \"-$1\" ).toLowerCase();\n\n\t\tdata = elem.getAttribute( name );\n\n\t\tif ( typeof data === \"string\" ) {\n\t\t\ttry {\n\t\t\t\tdata = data === \"true\" ? true :\n\t\t\t\t\tdata === \"false\" ? false :\n\t\t\t\t\tdata === \"null\" ? null :\n\t\t\t\t\t// Only convert to a number if it doesn't change the string\n\t\t\t\t\t+data + \"\" === data ? +data :\n\t\t\t\t\trbrace.test( data ) ? jQuery.parseJSON( data ) :\n\t\t\t\t\t\tdata;\n\t\t\t} catch( e ) {}\n\n\t\t\t// Make sure we set the data so it isn't changed later\n\t\t\tjQuery.data( elem, key, data );\n\n\t\t} else {\n\t\t\tdata = undefined;\n\t\t}\n\t}\n\n\treturn data;\n}\n\n// checks a cache object for emptiness\nfunction isEmptyDataObject( obj ) {\n\tvar name;\n\tfor ( name in obj ) {\n\n\t\t// if the public data object is empty, the private is still empty\n\t\tif ( name === \"data\" && jQuery.isEmptyObject( obj[name] ) ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( name !== \"toJSON\" ) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\treturn true;\n}\njQuery.extend({\n\tqueue: function( elem, type, data ) {\n\t\tvar queue;\n\n\t\tif ( elem ) {\n\t\t\ttype = ( type || \"fx\" ) + \"queue\";\n\t\t\tqueue = jQuery._data( elem, type );\n\n\t\t\t// Speed up dequeue by getting out quickly if this is just a lookup\n\t\t\tif ( data ) {\n\t\t\t\tif ( !queue || jQuery.isArray(data) ) {\n\t\t\t\t\tqueue = jQuery._data( elem, type, jQuery.makeArray(data) );\n\t\t\t\t} else {\n\t\t\t\t\tqueue.push( data );\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn queue || [];\n\t\t}\n\t},\n\n\tdequeue: function( elem, type ) {\n\t\ttype = type || \"fx\";\n\n\t\tvar queue = jQuery.queue( elem, type ),\n\t\t\tstartLength = queue.length,\n\t\t\tfn = queue.shift(),\n\t\t\thooks = jQuery._queueHooks( elem, type ),\n\t\t\tnext = function() {\n\t\t\t\tjQuery.dequeue( elem, type );\n\t\t\t};\n\n\t\t// If the fx queue is dequeued, always remove the progress sentinel\n\t\tif ( fn === \"inprogress\" ) {\n\t\t\tfn = queue.shift();\n\t\t\tstartLength--;\n\t\t}\n\n\t\thooks.cur = fn;\n\t\tif ( fn ) {\n\n\t\t\t// Add a progress sentinel to prevent the fx queue from being\n\t\t\t// automatically dequeued\n\t\t\tif ( type === \"fx\" ) {\n\t\t\t\tqueue.unshift( \"inprogress\" );\n\t\t\t}\n\n\t\t\t// clear up the last queue stop function\n\t\t\tdelete hooks.stop;\n\t\t\tfn.call( elem, next, hooks );\n\t\t}\n\n\t\tif ( !startLength && hooks ) {\n\t\t\thooks.empty.fire();\n\t\t}\n\t},\n\n\t// not intended for public consumption - generates a queueHooks object, or returns the current one\n\t_queueHooks: function( elem, type ) {\n\t\tvar key = type + \"queueHooks\";\n\t\treturn jQuery._data( elem, key ) || jQuery._data( elem, key, {\n\t\t\tempty: jQuery.Callbacks(\"once memory\").add(function() {\n\t\t\t\tjQuery._removeData( elem, type + \"queue\" );\n\t\t\t\tjQuery._removeData( elem, key );\n\t\t\t})\n\t\t});\n\t}\n});\n\njQuery.fn.extend({\n\tqueue: function( type, data ) {\n\t\tvar setter = 2;\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tdata = type;\n\t\t\ttype = \"fx\";\n\t\t\tsetter--;\n\t\t}\n\n\t\tif ( arguments.length < setter ) {\n\t\t\treturn jQuery.queue( this[0], type );\n\t\t}\n\n\t\treturn data === undefined ?\n\t\t\tthis :\n\t\t\tthis.each(function() {\n\t\t\t\tvar queue = jQuery.queue( this, type, data );\n\n\t\t\t\t// ensure a hooks for this queue\n\t\t\t\tjQuery._queueHooks( this, type );\n\n\t\t\t\tif ( type === \"fx\" && queue[0] !== \"inprogress\" ) {\n\t\t\t\t\tjQuery.dequeue( this, type );\n\t\t\t\t}\n\t\t\t});\n\t},\n\tdequeue: function( type ) {\n\t\treturn this.each(function() {\n\t\t\tjQuery.dequeue( this, type );\n\t\t});\n\t},\n\t// Based off of the plugin by Clint Helfers, with permission.\n\t// http://blindsignals.com/index.php/2009/07/jquery-delay/\n\tdelay: function( time, type ) {\n\t\ttime = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;\n\t\ttype = type || \"fx\";\n\n\t\treturn this.queue( type, function( next, hooks ) {\n\t\t\tvar timeout = setTimeout( next, time );\n\t\t\thooks.stop = function() {\n\t\t\t\tclearTimeout( timeout );\n\t\t\t};\n\t\t});\n\t},\n\tclearQueue: function( type ) {\n\t\treturn this.queue( type || \"fx\", [] );\n\t},\n\t// Get a promise resolved when queues of a certain type\n\t// are emptied (fx is the type by default)\n\tpromise: function( type, obj ) {\n\t\tvar tmp,\n\t\t\tcount = 1,\n\t\t\tdefer = jQuery.Deferred(),\n\t\t\telements = this,\n\t\t\ti = this.length,\n\t\t\tresolve = function() {\n\t\t\t\tif ( !( --count ) ) {\n\t\t\t\t\tdefer.resolveWith( elements, [ elements ] );\n\t\t\t\t}\n\t\t\t};\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tobj = type;\n\t\t\ttype = undefined;\n\t\t}\n\t\ttype = type || \"fx\";\n\n\t\twhile( i-- ) {\n\t\t\ttmp = jQuery._data( elements[ i ], type + \"queueHooks\" );\n\t\t\tif ( tmp && tmp.empty ) {\n\t\t\t\tcount++;\n\t\t\t\ttmp.empty.add( resolve );\n\t\t\t}\n\t\t}\n\t\tresolve();\n\t\treturn defer.promise( obj );\n\t}\n});\nvar nodeHook, boolHook,\n\trclass = /[\\t\\r\\n]/g,\n\trreturn = /\\r/g,\n\trfocusable = /^(?:input|select|textarea|button|object)$/i,\n\trclickable = /^(?:a|area)$/i,\n\trboolean = /^(?:checked|selected|autofocus|autoplay|async|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped)$/i,\n\truseDefault = /^(?:checked|selected)$/i,\n\tgetSetAttribute = jQuery.support.getSetAttribute,\n\tgetSetInput = jQuery.support.input;\n\njQuery.fn.extend({\n\tattr: function( name, value ) {\n\t\treturn jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );\n\t},\n\n\tremoveAttr: function( name ) {\n\t\treturn this.each(function() {\n\t\t\tjQuery.removeAttr( this, name );\n\t\t});\n\t},\n\n\tprop: function( name, value ) {\n\t\treturn jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );\n\t},\n\n\tremoveProp: function( name ) {\n\t\tname = jQuery.propFix[ name ] || name;\n\t\treturn this.each(function() {\n\t\t\t// try/catch handles cases where IE balks (such as removing a property on window)\n\t\t\ttry {\n\t\t\t\tthis[ name ] = undefined;\n\t\t\t\tdelete this[ name ];\n\t\t\t} catch( e ) {}\n\t\t});\n\t},\n\n\taddClass: function( value ) {\n\t\tvar classes, elem, cur, clazz, j,\n\t\t\ti = 0,\n\t\t\tlen = this.length,\n\t\t\tproceed = typeof value === \"string\" && value;\n\n\t\tif ( jQuery.isFunction( value ) ) {\n\t\t\treturn this.each(function( j ) {\n\t\t\t\tjQuery( this ).addClass( value.call( this, j, this.className ) );\n\t\t\t});\n\t\t}\n\n\t\tif ( proceed ) {\n\t\t\t// The disjunction here is for better compressibility (see removeClass)\n\t\t\tclasses = ( value || \"\" ).match( core_rnotwhite ) || [];\n\n\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\telem = this[ i ];\n\t\t\t\tcur = elem.nodeType === 1 && ( elem.className ?\n\t\t\t\t\t( \" \" + elem.className + \" \" ).replace( rclass, \" \" ) :\n\t\t\t\t\t\" \"\n\t\t\t\t);\n\n\t\t\t\tif ( cur ) {\n\t\t\t\t\tj = 0;\n\t\t\t\t\twhile ( (clazz = classes[j++]) ) {\n\t\t\t\t\t\tif ( cur.indexOf( \" \" + clazz + \" \" ) < 0 ) {\n\t\t\t\t\t\t\tcur += clazz + \" \";\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telem.className = jQuery.trim( cur );\n\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tremoveClass: function( value ) {\n\t\tvar classes, elem, cur, clazz, j,\n\t\t\ti = 0,\n\t\t\tlen = this.length,\n\t\t\tproceed = arguments.length === 0 || typeof value === \"string\" && value;\n\n\t\tif ( jQuery.isFunction( value ) ) {\n\t\t\treturn this.each(function( j ) {\n\t\t\t\tjQuery( this ).removeClass( value.call( this, j, this.className ) );\n\t\t\t});\n\t\t}\n\t\tif ( proceed ) {\n\t\t\tclasses = ( value || \"\" ).match( core_rnotwhite ) || [];\n\n\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\telem = this[ i ];\n\t\t\t\t// This expression is here for better compressibility (see addClass)\n\t\t\t\tcur = elem.nodeType === 1 && ( elem.className ?\n\t\t\t\t\t( \" \" + elem.className + \" \" ).replace( rclass, \" \" ) :\n\t\t\t\t\t\"\"\n\t\t\t\t);\n\n\t\t\t\tif ( cur ) {\n\t\t\t\t\tj = 0;\n\t\t\t\t\twhile ( (clazz = classes[j++]) ) {\n\t\t\t\t\t\t// Remove *all* instances\n\t\t\t\t\t\twhile ( cur.indexOf( \" \" + clazz + \" \" ) >= 0 ) {\n\t\t\t\t\t\t\tcur = cur.replace( \" \" + clazz + \" \", \" \" );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telem.className = value ? jQuery.trim( cur ) : \"\";\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\ttoggleClass: function( value, stateVal ) {\n\t\tvar type = typeof value,\n\t\t\tisBool = typeof stateVal === \"boolean\";\n\n\t\tif ( jQuery.isFunction( value ) ) {\n\t\t\treturn this.each(function( i ) {\n\t\t\t\tjQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );\n\t\t\t});\n\t\t}\n\n\t\treturn this.each(function() {\n\t\t\tif ( type === \"string\" ) {\n\t\t\t\t// toggle individual class names\n\t\t\t\tvar className,\n\t\t\t\t\ti = 0,\n\t\t\t\t\tself = jQuery( this ),\n\t\t\t\t\tstate = stateVal,\n\t\t\t\t\tclassNames = value.match( core_rnotwhite ) || [];\n\n\t\t\t\twhile ( (className = classNames[ i++ ]) ) {\n\t\t\t\t\t// check each className given, space separated list\n\t\t\t\t\tstate = isBool ? state : !self.hasClass( className );\n\t\t\t\t\tself[ state ? \"addClass\" : \"removeClass\" ]( className );\n\t\t\t\t}\n\n\t\t\t// Toggle whole class name\n\t\t\t} else if ( type === core_strundefined || type === \"boolean\" ) {\n\t\t\t\tif ( this.className ) {\n\t\t\t\t\t// store className if set\n\t\t\t\t\tjQuery._data( this, \"__className__\", this.className );\n\t\t\t\t}\n\n\t\t\t\t// If the element has a class name or if we're passed \"false\",\n\t\t\t\t// then remove the whole classname (if there was one, the above saved it).\n\t\t\t\t// Otherwise bring back whatever was previously saved (if anything),\n\t\t\t\t// falling back to the empty string if nothing was stored.\n\t\t\t\tthis.className = this.className || value === false ? \"\" : jQuery._data( this, \"__className__\" ) || \"\";\n\t\t\t}\n\t\t});\n\t},\n\n\thasClass: function( selector ) {\n\t\tvar className = \" \" + selector + \" \",\n\t\t\ti = 0,\n\t\t\tl = this.length;\n\t\tfor ( ; i < l; i++ ) {\n\t\t\tif ( this[i].nodeType === 1 && (\" \" + this[i].className + \" \").replace(rclass, \" \").indexOf( className ) >= 0 ) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t},\n\n\tval: function( value ) {\n\t\tvar ret, hooks, isFunction,\n\t\t\telem = this[0];\n\n\t\tif ( !arguments.length ) {\n\t\t\tif ( elem ) {\n\t\t\t\thooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];\n\n\t\t\t\tif ( hooks && \"get\" in hooks && (ret = hooks.get( elem, \"value\" )) !== undefined ) {\n\t\t\t\t\treturn ret;\n\t\t\t\t}\n\n\t\t\t\tret = elem.value;\n\n\t\t\t\treturn typeof ret === \"string\" ?\n\t\t\t\t\t// handle most common string cases\n\t\t\t\t\tret.replace(rreturn, \"\") :\n\t\t\t\t\t// handle cases where value is null/undef or number\n\t\t\t\t\tret == null ? \"\" : ret;\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tisFunction = jQuery.isFunction( value );\n\n\t\treturn this.each(function( i ) {\n\t\t\tvar val,\n\t\t\t\tself = jQuery(this);\n\n\t\t\tif ( this.nodeType !== 1 ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( isFunction ) {\n\t\t\t\tval = value.call( this, i, self.val() );\n\t\t\t} else {\n\t\t\t\tval = value;\n\t\t\t}\n\n\t\t\t// Treat null/undefined as \"\"; convert numbers to string\n\t\t\tif ( val == null ) {\n\t\t\t\tval = \"\";\n\t\t\t} else if ( typeof val === \"number\" ) {\n\t\t\t\tval += \"\";\n\t\t\t} else if ( jQuery.isArray( val ) ) {\n\t\t\t\tval = jQuery.map(val, function ( value ) {\n\t\t\t\t\treturn value == null ? \"\" : value + \"\";\n\t\t\t\t});\n\t\t\t}\n\n\t\t\thooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];\n\n\t\t\t// If set returns undefined, fall back to normal setting\n\t\t\tif ( !hooks || !(\"set\" in hooks) || hooks.set( this, val, \"value\" ) === undefined ) {\n\t\t\t\tthis.value = val;\n\t\t\t}\n\t\t});\n\t}\n});\n\njQuery.extend({\n\tvalHooks: {\n\t\toption: {\n\t\t\tget: function( elem ) {\n\t\t\t\t// attributes.value is undefined in Blackberry 4.7 but\n\t\t\t\t// uses .value. See #6932\n\t\t\t\tvar val = elem.attributes.value;\n\t\t\t\treturn !val || val.specified ? elem.value : elem.text;\n\t\t\t}\n\t\t},\n\t\tselect: {\n\t\t\tget: function( elem ) {\n\t\t\t\tvar value, option,\n\t\t\t\t\toptions = elem.options,\n\t\t\t\t\tindex = elem.selectedIndex,\n\t\t\t\t\tone = elem.type === \"select-one\" || index < 0,\n\t\t\t\t\tvalues = one ? null : [],\n\t\t\t\t\tmax = one ? index + 1 : options.length,\n\t\t\t\t\ti = index < 0 ?\n\t\t\t\t\t\tmax :\n\t\t\t\t\t\tone ? index : 0;\n\n\t\t\t\t// Loop through all the selected options\n\t\t\t\tfor ( ; i < max; i++ ) {\n\t\t\t\t\toption = options[ i ];\n\n\t\t\t\t\t// oldIE doesn't update selected after form reset (#2551)\n\t\t\t\t\tif ( ( option.selected || i === index ) &&\n\t\t\t\t\t\t\t// Don't return options that are disabled or in a disabled optgroup\n\t\t\t\t\t\t\t( jQuery.support.optDisabled ? !option.disabled : option.getAttribute(\"disabled\") === null ) &&\n\t\t\t\t\t\t\t( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, \"optgroup\" ) ) ) {\n\n\t\t\t\t\t\t// Get the specific value for the option\n\t\t\t\t\t\tvalue = jQuery( option ).val();\n\n\t\t\t\t\t\t// We don't need an array for one selects\n\t\t\t\t\t\tif ( one ) {\n\t\t\t\t\t\t\treturn value;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Multi-Selects return an array\n\t\t\t\t\t\tvalues.push( value );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn values;\n\t\t\t},\n\n\t\t\tset: function( elem, value ) {\n\t\t\t\tvar values = jQuery.makeArray( value );\n\n\t\t\t\tjQuery(elem).find(\"option\").each(function() {\n\t\t\t\t\tthis.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;\n\t\t\t\t});\n\n\t\t\t\tif ( !values.length ) {\n\t\t\t\t\telem.selectedIndex = -1;\n\t\t\t\t}\n\t\t\t\treturn values;\n\t\t\t}\n\t\t}\n\t},\n\n\tattr: function( elem, name, value ) {\n\t\tvar hooks, notxml, ret,\n\t\t\tnType = elem.nodeType;\n\n\t\t// don't get/set attributes on text, comment and attribute nodes\n\t\tif ( !elem || nType === 3 || nType === 8 || nType === 2 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Fallback to prop when attributes are not supported\n\t\tif ( typeof elem.getAttribute === core_strundefined ) {\n\t\t\treturn jQuery.prop( elem, name, value );\n\t\t}\n\n\t\tnotxml = nType !== 1 || !jQuery.isXMLDoc( elem );\n\n\t\t// All attributes are lowercase\n\t\t// Grab necessary hook if one is defined\n\t\tif ( notxml ) {\n\t\t\tname = name.toLowerCase();\n\t\t\thooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook );\n\t\t}\n\n\t\tif ( value !== undefined ) {\n\n\t\t\tif ( value === null ) {\n\t\t\t\tjQuery.removeAttr( elem, name );\n\n\t\t\t} else if ( hooks && notxml && \"set\" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {\n\t\t\t\treturn ret;\n\n\t\t\t} else {\n\t\t\t\telem.setAttribute( name, value + \"\" );\n\t\t\t\treturn value;\n\t\t\t}\n\n\t\t} else if ( hooks && notxml && \"get\" in hooks && (ret = hooks.get( elem, name )) !== null ) {\n\t\t\treturn ret;\n\n\t\t} else {\n\n\t\t\t// In IE9+, Flash objects don't have .getAttribute (#12945)\n\t\t\t// Support: IE9+\n\t\t\tif ( typeof elem.getAttribute !== core_strundefined ) {\n\t\t\t\tret =  elem.getAttribute( name );\n\t\t\t}\n\n\t\t\t// Non-existent attributes return null, we normalize to undefined\n\t\t\treturn ret == null ?\n\t\t\t\tundefined :\n\t\t\t\tret;\n\t\t}\n\t},\n\n\tremoveAttr: function( elem, value ) {\n\t\tvar name, propName,\n\t\t\ti = 0,\n\t\t\tattrNames = value && value.match( core_rnotwhite );\n\n\t\tif ( attrNames && elem.nodeType === 1 ) {\n\t\t\twhile ( (name = attrNames[i++]) ) {\n\t\t\t\tpropName = jQuery.propFix[ name ] || name;\n\n\t\t\t\t// Boolean attributes get special treatment (#10870)\n\t\t\t\tif ( rboolean.test( name ) ) {\n\t\t\t\t\t// Set corresponding property to false for boolean attributes\n\t\t\t\t\t// Also clear defaultChecked/defaultSelected (if appropriate) for IE<8\n\t\t\t\t\tif ( !getSetAttribute && ruseDefault.test( name ) ) {\n\t\t\t\t\t\telem[ jQuery.camelCase( \"default-\" + name ) ] =\n\t\t\t\t\t\t\telem[ propName ] = false;\n\t\t\t\t\t} else {\n\t\t\t\t\t\telem[ propName ] = false;\n\t\t\t\t\t}\n\n\t\t\t\t// See #9699 for explanation of this approach (setting first, then removal)\n\t\t\t\t} else {\n\t\t\t\t\tjQuery.attr( elem, name, \"\" );\n\t\t\t\t}\n\n\t\t\t\telem.removeAttribute( getSetAttribute ? name : propName );\n\t\t\t}\n\t\t}\n\t},\n\n\tattrHooks: {\n\t\ttype: {\n\t\t\tset: function( elem, value ) {\n\t\t\t\tif ( !jQuery.support.radioValue && value === \"radio\" && jQuery.nodeName(elem, \"input\") ) {\n\t\t\t\t\t// Setting the type on a radio button after the value resets the value in IE6-9\n\t\t\t\t\t// Reset value to default in case type is set after value during creation\n\t\t\t\t\tvar val = elem.value;\n\t\t\t\t\telem.setAttribute( \"type\", value );\n\t\t\t\t\tif ( val ) {\n\t\t\t\t\t\telem.value = val;\n\t\t\t\t\t}\n\t\t\t\t\treturn value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\tpropFix: {\n\t\ttabindex: \"tabIndex\",\n\t\treadonly: \"readOnly\",\n\t\t\"for\": \"htmlFor\",\n\t\t\"class\": \"className\",\n\t\tmaxlength: \"maxLength\",\n\t\tcellspacing: \"cellSpacing\",\n\t\tcellpadding: \"cellPadding\",\n\t\trowspan: \"rowSpan\",\n\t\tcolspan: \"colSpan\",\n\t\tusemap: \"useMap\",\n\t\tframeborder: \"frameBorder\",\n\t\tcontenteditable: \"contentEditable\"\n\t},\n\n\tprop: function( elem, name, value ) {\n\t\tvar ret, hooks, notxml,\n\t\t\tnType = elem.nodeType;\n\n\t\t// don't get/set properties on text, comment and attribute nodes\n\t\tif ( !elem || nType === 3 || nType === 8 || nType === 2 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tnotxml = nType !== 1 || !jQuery.isXMLDoc( elem );\n\n\t\tif ( notxml ) {\n\t\t\t// Fix name and attach hooks\n\t\t\tname = jQuery.propFix[ name ] || name;\n\t\t\thooks = jQuery.propHooks[ name ];\n\t\t}\n\n\t\tif ( value !== undefined ) {\n\t\t\tif ( hooks && \"set\" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {\n\t\t\t\treturn ret;\n\n\t\t\t} else {\n\t\t\t\treturn ( elem[ name ] = value );\n\t\t\t}\n\n\t\t} else {\n\t\t\tif ( hooks && \"get\" in hooks && (ret = hooks.get( elem, name )) !== null ) {\n\t\t\t\treturn ret;\n\n\t\t\t} else {\n\t\t\t\treturn elem[ name ];\n\t\t\t}\n\t\t}\n\t},\n\n\tpropHooks: {\n\t\ttabIndex: {\n\t\t\tget: function( elem ) {\n\t\t\t\t// elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set\n\t\t\t\t// http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/\n\t\t\t\tvar attributeNode = elem.getAttributeNode(\"tabindex\");\n\n\t\t\t\treturn attributeNode && attributeNode.specified ?\n\t\t\t\t\tparseInt( attributeNode.value, 10 ) :\n\t\t\t\t\trfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?\n\t\t\t\t\t\t0 :\n\t\t\t\t\t\tundefined;\n\t\t\t}\n\t\t}\n\t}\n});\n\n// Hook for boolean attributes\nboolHook = {\n\tget: function( elem, name ) {\n\t\tvar\n\t\t\t// Use .prop to determine if this attribute is understood as boolean\n\t\t\tprop = jQuery.prop( elem, name ),\n\n\t\t\t// Fetch it accordingly\n\t\t\tattr = typeof prop === \"boolean\" && elem.getAttribute( name ),\n\t\t\tdetail = typeof prop === \"boolean\" ?\n\n\t\t\t\tgetSetInput && getSetAttribute ?\n\t\t\t\t\tattr != null :\n\t\t\t\t\t// oldIE fabricates an empty string for missing boolean attributes\n\t\t\t\t\t// and conflates checked/selected into attroperties\n\t\t\t\t\truseDefault.test( name ) ?\n\t\t\t\t\t\telem[ jQuery.camelCase( \"default-\" + name ) ] :\n\t\t\t\t\t\t!!attr :\n\n\t\t\t\t// fetch an attribute node for properties not recognized as boolean\n\t\t\t\telem.getAttributeNode( name );\n\n\t\treturn detail && detail.value !== false ?\n\t\t\tname.toLowerCase() :\n\t\t\tundefined;\n\t},\n\tset: function( elem, value, name ) {\n\t\tif ( value === false ) {\n\t\t\t// Remove boolean attributes when set to false\n\t\t\tjQuery.removeAttr( elem, name );\n\t\t} else if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {\n\t\t\t// IE<8 needs the *property* name\n\t\t\telem.setAttribute( !getSetAttribute && jQuery.propFix[ name ] || name, name );\n\n\t\t// Use defaultChecked and defaultSelected for oldIE\n\t\t} else {\n\t\t\telem[ jQuery.camelCase( \"default-\" + name ) ] = elem[ name ] = true;\n\t\t}\n\n\t\treturn name;\n\t}\n};\n\n// fix oldIE value attroperty\nif ( !getSetInput || !getSetAttribute ) {\n\tjQuery.attrHooks.value = {\n\t\tget: function( elem, name ) {\n\t\t\tvar ret = elem.getAttributeNode( name );\n\t\t\treturn jQuery.nodeName( elem, \"input\" ) ?\n\n\t\t\t\t// Ignore the value *property* by using defaultValue\n\t\t\t\telem.defaultValue :\n\n\t\t\t\tret && ret.specified ? ret.value : undefined;\n\t\t},\n\t\tset: function( elem, value, name ) {\n\t\t\tif ( jQuery.nodeName( elem, \"input\" ) ) {\n\t\t\t\t// Does not return so that setAttribute is also used\n\t\t\t\telem.defaultValue = value;\n\t\t\t} else {\n\t\t\t\t// Use nodeHook if defined (#1954); otherwise setAttribute is fine\n\t\t\t\treturn nodeHook && nodeHook.set( elem, value, name );\n\t\t\t}\n\t\t}\n\t};\n}\n\n// IE6/7 do not support getting/setting some attributes with get/setAttribute\nif ( !getSetAttribute ) {\n\n\t// Use this for any attribute in IE6/7\n\t// This fixes almost every IE6/7 issue\n\tnodeHook = jQuery.valHooks.button = {\n\t\tget: function( elem, name ) {\n\t\t\tvar ret = elem.getAttributeNode( name );\n\t\t\treturn ret && ( name === \"id\" || name === \"name\" || name === \"coords\" ? ret.value !== \"\" : ret.specified ) ?\n\t\t\t\tret.value :\n\t\t\t\tundefined;\n\t\t},\n\t\tset: function( elem, value, name ) {\n\t\t\t// Set the existing or create a new attribute node\n\t\t\tvar ret = elem.getAttributeNode( name );\n\t\t\tif ( !ret ) {\n\t\t\t\telem.setAttributeNode(\n\t\t\t\t\t(ret = elem.ownerDocument.createAttribute( name ))\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tret.value = value += \"\";\n\n\t\t\t// Break association with cloned elements by also using setAttribute (#9646)\n\t\t\treturn name === \"value\" || value === elem.getAttribute( name ) ?\n\t\t\t\tvalue :\n\t\t\t\tundefined;\n\t\t}\n\t};\n\n\t// Set contenteditable to false on removals(#10429)\n\t// Setting to empty string throws an error as an invalid value\n\tjQuery.attrHooks.contenteditable = {\n\t\tget: nodeHook.get,\n\t\tset: function( elem, value, name ) {\n\t\t\tnodeHook.set( elem, value === \"\" ? false : value, name );\n\t\t}\n\t};\n\n\t// Set width and height to auto instead of 0 on empty string( Bug #8150 )\n\t// This is for removals\n\tjQuery.each([ \"width\", \"height\" ], function( i, name ) {\n\t\tjQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {\n\t\t\tset: function( elem, value ) {\n\t\t\t\tif ( value === \"\" ) {\n\t\t\t\t\telem.setAttribute( name, \"auto\" );\n\t\t\t\t\treturn value;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t});\n}\n\n\n// Some attributes require a special call on IE\n// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx\nif ( !jQuery.support.hrefNormalized ) {\n\tjQuery.each([ \"href\", \"src\", \"width\", \"height\" ], function( i, name ) {\n\t\tjQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {\n\t\t\tget: function( elem ) {\n\t\t\t\tvar ret = elem.getAttribute( name, 2 );\n\t\t\t\treturn ret == null ? undefined : ret;\n\t\t\t}\n\t\t});\n\t});\n\n\t// href/src property should get the full normalized URL (#10299/#12915)\n\tjQuery.each([ \"href\", \"src\" ], function( i, name ) {\n\t\tjQuery.propHooks[ name ] = {\n\t\t\tget: function( elem ) {\n\t\t\t\treturn elem.getAttribute( name, 4 );\n\t\t\t}\n\t\t};\n\t});\n}\n\nif ( !jQuery.support.style ) {\n\tjQuery.attrHooks.style = {\n\t\tget: function( elem ) {\n\t\t\t// Return undefined in the case of empty string\n\t\t\t// Note: IE uppercases css property names, but if we were to .toLowerCase()\n\t\t\t// .cssText, that would destroy case senstitivity in URL's, like in \"background\"\n\t\t\treturn elem.style.cssText || undefined;\n\t\t},\n\t\tset: function( elem, value ) {\n\t\t\treturn ( elem.style.cssText = value + \"\" );\n\t\t}\n\t};\n}\n\n// Safari mis-reports the default selected property of an option\n// Accessing the parent's selectedIndex property fixes it\nif ( !jQuery.support.optSelected ) {\n\tjQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, {\n\t\tget: function( elem ) {\n\t\t\tvar parent = elem.parentNode;\n\n\t\t\tif ( parent ) {\n\t\t\t\tparent.selectedIndex;\n\n\t\t\t\t// Make sure that it also works with optgroups, see #5701\n\t\t\t\tif ( parent.parentNode ) {\n\t\t\t\t\tparent.parentNode.selectedIndex;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\t});\n}\n\n// IE6/7 call enctype encoding\nif ( !jQuery.support.enctype ) {\n\tjQuery.propFix.enctype = \"encoding\";\n}\n\n// Radios and checkboxes getter/setter\nif ( !jQuery.support.checkOn ) {\n\tjQuery.each([ \"radio\", \"checkbox\" ], function() {\n\t\tjQuery.valHooks[ this ] = {\n\t\t\tget: function( elem ) {\n\t\t\t\t// Handle the case where in Webkit \"\" is returned instead of \"on\" if a value isn't specified\n\t\t\t\treturn elem.getAttribute(\"value\") === null ? \"on\" : elem.value;\n\t\t\t}\n\t\t};\n\t});\n}\njQuery.each([ \"radio\", \"checkbox\" ], function() {\n\tjQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], {\n\t\tset: function( elem, value ) {\n\t\t\tif ( jQuery.isArray( value ) ) {\n\t\t\t\treturn ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );\n\t\t\t}\n\t\t}\n\t});\n});\nvar rformElems = /^(?:input|select|textarea)$/i,\n\trkeyEvent = /^key/,\n\trmouseEvent = /^(?:mouse|contextmenu)|click/,\n\trfocusMorph = /^(?:focusinfocus|focusoutblur)$/,\n\trtypenamespace = /^([^.]*)(?:\\.(.+)|)$/;\n\nfunction returnTrue() {\n\treturn true;\n}\n\nfunction returnFalse() {\n\treturn false;\n}\n\n/*\n * Helper functions for managing events -- not part of the public interface.\n * Props to Dean Edwards' addEvent library for many of the ideas.\n */\njQuery.event = {\n\n\tglobal: {},\n\n\tadd: function( elem, types, handler, data, selector ) {\n\t\tvar tmp, events, t, handleObjIn,\n\t\t\tspecial, eventHandle, handleObj,\n\t\t\thandlers, type, namespaces, origType,\n\t\t\telemData = jQuery._data( elem );\n\n\t\t// Don't attach events to noData or text/comment nodes (but allow plain objects)\n\t\tif ( !elemData ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Caller can pass in an object of custom data in lieu of the handler\n\t\tif ( handler.handler ) {\n\t\t\thandleObjIn = handler;\n\t\t\thandler = handleObjIn.handler;\n\t\t\tselector = handleObjIn.selector;\n\t\t}\n\n\t\t// Make sure that the handler has a unique ID, used to find/remove it later\n\t\tif ( !handler.guid ) {\n\t\t\thandler.guid = jQuery.guid++;\n\t\t}\n\n\t\t// Init the element's event structure and main handler, if this is the first\n\t\tif ( !(events = elemData.events) ) {\n\t\t\tevents = elemData.events = {};\n\t\t}\n\t\tif ( !(eventHandle = elemData.handle) ) {\n\t\t\teventHandle = elemData.handle = function( e ) {\n\t\t\t\t// Discard the second event of a jQuery.event.trigger() and\n\t\t\t\t// when an event is called after a page has unloaded\n\t\t\t\treturn typeof jQuery !== core_strundefined && (!e || jQuery.event.triggered !== e.type) ?\n\t\t\t\t\tjQuery.event.dispatch.apply( eventHandle.elem, arguments ) :\n\t\t\t\t\tundefined;\n\t\t\t};\n\t\t\t// Add elem as a property of the handle fn to prevent a memory leak with IE non-native events\n\t\t\teventHandle.elem = elem;\n\t\t}\n\n\t\t// Handle multiple events separated by a space\n\t\t// jQuery(...).bind(\"mouseover mouseout\", fn);\n\t\ttypes = ( types || \"\" ).match( core_rnotwhite ) || [\"\"];\n\t\tt = types.length;\n\t\twhile ( t-- ) {\n\t\t\ttmp = rtypenamespace.exec( types[t] ) || [];\n\t\t\ttype = origType = tmp[1];\n\t\t\tnamespaces = ( tmp[2] || \"\" ).split( \".\" ).sort();\n\n\t\t\t// If event changes its type, use the special event handlers for the changed type\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\n\t\t\t// If selector defined, determine special event api type, otherwise given type\n\t\t\ttype = ( selector ? special.delegateType : special.bindType ) || type;\n\n\t\t\t// Update special based on newly reset type\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\n\t\t\t// handleObj is passed to all event handlers\n\t\t\thandleObj = jQuery.extend({\n\t\t\t\ttype: type,\n\t\t\t\torigType: origType,\n\t\t\t\tdata: data,\n\t\t\t\thandler: handler,\n\t\t\t\tguid: handler.guid,\n\t\t\t\tselector: selector,\n\t\t\t\tneedsContext: selector && jQuery.expr.match.needsContext.test( selector ),\n\t\t\t\tnamespace: namespaces.join(\".\")\n\t\t\t}, handleObjIn );\n\n\t\t\t// Init the event handler queue if we're the first\n\t\t\tif ( !(handlers = events[ type ]) ) {\n\t\t\t\thandlers = events[ type ] = [];\n\t\t\t\thandlers.delegateCount = 0;\n\n\t\t\t\t// Only use addEventListener/attachEvent if the special events handler returns false\n\t\t\t\tif ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {\n\t\t\t\t\t// Bind the global event handler to the element\n\t\t\t\t\tif ( elem.addEventListener ) {\n\t\t\t\t\t\telem.addEventListener( type, eventHandle, false );\n\n\t\t\t\t\t} else if ( elem.attachEvent ) {\n\t\t\t\t\t\telem.attachEvent( \"on\" + type, eventHandle );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( special.add ) {\n\t\t\t\tspecial.add.call( elem, handleObj );\n\n\t\t\t\tif ( !handleObj.handler.guid ) {\n\t\t\t\t\thandleObj.handler.guid = handler.guid;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Add to the element's handler list, delegates in front\n\t\t\tif ( selector ) {\n\t\t\t\thandlers.splice( handlers.delegateCount++, 0, handleObj );\n\t\t\t} else {\n\t\t\t\thandlers.push( handleObj );\n\t\t\t}\n\n\t\t\t// Keep track of which events have ever been used, for event optimization\n\t\t\tjQuery.event.global[ type ] = true;\n\t\t}\n\n\t\t// Nullify elem to prevent memory leaks in IE\n\t\telem = null;\n\t},\n\n\t// Detach an event or set of events from an element\n\tremove: function( elem, types, handler, selector, mappedTypes ) {\n\t\tvar j, handleObj, tmp,\n\t\t\torigCount, t, events,\n\t\t\tspecial, handlers, type,\n\t\t\tnamespaces, origType,\n\t\t\telemData = jQuery.hasData( elem ) && jQuery._data( elem );\n\n\t\tif ( !elemData || !(events = elemData.events) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Once for each type.namespace in types; type may be omitted\n\t\ttypes = ( types || \"\" ).match( core_rnotwhite ) || [\"\"];\n\t\tt = types.length;\n\t\twhile ( t-- ) {\n\t\t\ttmp = rtypenamespace.exec( types[t] ) || [];\n\t\t\ttype = origType = tmp[1];\n\t\t\tnamespaces = ( tmp[2] || \"\" ).split( \".\" ).sort();\n\n\t\t\t// Unbind all events (on this namespace, if provided) for the element\n\t\t\tif ( !type ) {\n\t\t\t\tfor ( type in events ) {\n\t\t\t\t\tjQuery.event.remove( elem, type + types[ t ], handler, selector, true );\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\t\t\ttype = ( selector ? special.delegateType : special.bindType ) || type;\n\t\t\thandlers = events[ type ] || [];\n\t\t\ttmp = tmp[2] && new RegExp( \"(^|\\\\.)\" + namespaces.join(\"\\\\.(?:.*\\\\.|)\") + \"(\\\\.|$)\" );\n\n\t\t\t// Remove matching events\n\t\t\torigCount = j = handlers.length;\n\t\t\twhile ( j-- ) {\n\t\t\t\thandleObj = handlers[ j ];\n\n\t\t\t\tif ( ( mappedTypes || origType === handleObj.origType ) &&\n\t\t\t\t\t( !handler || handler.guid === handleObj.guid ) &&\n\t\t\t\t\t( !tmp || tmp.test( handleObj.namespace ) ) &&\n\t\t\t\t\t( !selector || selector === handleObj.selector || selector === \"**\" && handleObj.selector ) ) {\n\t\t\t\t\thandlers.splice( j, 1 );\n\n\t\t\t\t\tif ( handleObj.selector ) {\n\t\t\t\t\t\thandlers.delegateCount--;\n\t\t\t\t\t}\n\t\t\t\t\tif ( special.remove ) {\n\t\t\t\t\t\tspecial.remove.call( elem, handleObj );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Remove generic event handler if we removed something and no more handlers exist\n\t\t\t// (avoids potential for endless recursion during removal of special event handlers)\n\t\t\tif ( origCount && !handlers.length ) {\n\t\t\t\tif ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {\n\t\t\t\t\tjQuery.removeEvent( elem, type, elemData.handle );\n\t\t\t\t}\n\n\t\t\t\tdelete events[ type ];\n\t\t\t}\n\t\t}\n\n\t\t// Remove the expando if it's no longer used\n\t\tif ( jQuery.isEmptyObject( events ) ) {\n\t\t\tdelete elemData.handle;\n\n\t\t\t// removeData also checks for emptiness and clears the expando if empty\n\t\t\t// so use it instead of delete\n\t\t\tjQuery._removeData( elem, \"events\" );\n\t\t}\n\t},\n\n\ttrigger: function( event, data, elem, onlyHandlers ) {\n\t\tvar handle, ontype, cur,\n\t\t\tbubbleType, special, tmp, i,\n\t\t\teventPath = [ elem || document ],\n\t\t\ttype = core_hasOwn.call( event, \"type\" ) ? event.type : event,\n\t\t\tnamespaces = core_hasOwn.call( event, \"namespace\" ) ? event.namespace.split(\".\") : [];\n\n\t\tcur = tmp = elem = elem || document;\n\n\t\t// Don't do events on text and comment nodes\n\t\tif ( elem.nodeType === 3 || elem.nodeType === 8 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// focus/blur morphs to focusin/out; ensure we're not firing them right now\n\t\tif ( rfocusMorph.test( type + jQuery.event.triggered ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( type.indexOf(\".\") >= 0 ) {\n\t\t\t// Namespaced trigger; create a regexp to match event type in handle()\n\t\t\tnamespaces = type.split(\".\");\n\t\t\ttype = namespaces.shift();\n\t\t\tnamespaces.sort();\n\t\t}\n\t\tontype = type.indexOf(\":\") < 0 && \"on\" + type;\n\n\t\t// Caller can pass in a jQuery.Event object, Object, or just an event type string\n\t\tevent = event[ jQuery.expando ] ?\n\t\t\tevent :\n\t\t\tnew jQuery.Event( type, typeof event === \"object\" && event );\n\n\t\tevent.isTrigger = true;\n\t\tevent.namespace = namespaces.join(\".\");\n\t\tevent.namespace_re = event.namespace ?\n\t\t\tnew RegExp( \"(^|\\\\.)\" + namespaces.join(\"\\\\.(?:.*\\\\.|)\") + \"(\\\\.|$)\" ) :\n\t\t\tnull;\n\n\t\t// Clean up the event in case it is being reused\n\t\tevent.result = undefined;\n\t\tif ( !event.target ) {\n\t\t\tevent.target = elem;\n\t\t}\n\n\t\t// Clone any incoming data and prepend the event, creating the handler arg list\n\t\tdata = data == null ?\n\t\t\t[ event ] :\n\t\t\tjQuery.makeArray( data, [ event ] );\n\n\t\t// Allow special events to draw outside the lines\n\t\tspecial = jQuery.event.special[ type ] || {};\n\t\tif ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Determine event propagation path in advance, per W3C events spec (#9951)\n\t\t// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)\n\t\tif ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {\n\n\t\t\tbubbleType = special.delegateType || type;\n\t\t\tif ( !rfocusMorph.test( bubbleType + type ) ) {\n\t\t\t\tcur = cur.parentNode;\n\t\t\t}\n\t\t\tfor ( ; cur; cur = cur.parentNode ) {\n\t\t\t\teventPath.push( cur );\n\t\t\t\ttmp = cur;\n\t\t\t}\n\n\t\t\t// Only add window if we got to document (e.g., not plain obj or detached DOM)\n\t\t\tif ( tmp === (elem.ownerDocument || document) ) {\n\t\t\t\teventPath.push( tmp.defaultView || tmp.parentWindow || window );\n\t\t\t}\n\t\t}\n\n\t\t// Fire handlers on the event path\n\t\ti = 0;\n\t\twhile ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) {\n\n\t\t\tevent.type = i > 1 ?\n\t\t\t\tbubbleType :\n\t\t\t\tspecial.bindType || type;\n\n\t\t\t// jQuery handler\n\t\t\thandle = ( jQuery._data( cur, \"events\" ) || {} )[ event.type ] && jQuery._data( cur, \"handle\" );\n\t\t\tif ( handle ) {\n\t\t\t\thandle.apply( cur, data );\n\t\t\t}\n\n\t\t\t// Native handler\n\t\t\thandle = ontype && cur[ ontype ];\n\t\t\tif ( handle && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === false ) {\n\t\t\t\tevent.preventDefault();\n\t\t\t}\n\t\t}\n\t\tevent.type = type;\n\n\t\t// If nobody prevented the default action, do it now\n\t\tif ( !onlyHandlers && !event.isDefaultPrevented() ) {\n\n\t\t\tif ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) &&\n\t\t\t\t!(type === \"click\" && jQuery.nodeName( elem, \"a\" )) && jQuery.acceptData( elem ) ) {\n\n\t\t\t\t// Call a native DOM method on the target with the same name name as the event.\n\t\t\t\t// Can't use an .isFunction() check here because IE6/7 fails that test.\n\t\t\t\t// Don't do default actions on window, that's where global variables be (#6170)\n\t\t\t\tif ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) {\n\n\t\t\t\t\t// Don't re-trigger an onFOO event when we call its FOO() method\n\t\t\t\t\ttmp = elem[ ontype ];\n\n\t\t\t\t\tif ( tmp ) {\n\t\t\t\t\t\telem[ ontype ] = null;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Prevent re-triggering of the same event, since we already bubbled it above\n\t\t\t\t\tjQuery.event.triggered = type;\n\t\t\t\t\ttry {\n\t\t\t\t\t\telem[ type ]();\n\t\t\t\t\t} catch ( e ) {\n\t\t\t\t\t\t// IE<9 dies on focus/blur to hidden element (#1486,#12518)\n\t\t\t\t\t\t// only reproducible on winXP IE8 native, not IE9 in IE8 mode\n\t\t\t\t\t}\n\t\t\t\t\tjQuery.event.triggered = undefined;\n\n\t\t\t\t\tif ( tmp ) {\n\t\t\t\t\t\telem[ ontype ] = tmp;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn event.result;\n\t},\n\n\tdispatch: function( event ) {\n\n\t\t// Make a writable jQuery.Event from the native event object\n\t\tevent = jQuery.event.fix( event );\n\n\t\tvar i, ret, handleObj, matched, j,\n\t\t\thandlerQueue = [],\n\t\t\targs = core_slice.call( arguments ),\n\t\t\thandlers = ( jQuery._data( this, \"events\" ) || {} )[ event.type ] || [],\n\t\t\tspecial = jQuery.event.special[ event.type ] || {};\n\n\t\t// Use the fix-ed jQuery.Event rather than the (read-only) native event\n\t\targs[0] = event;\n\t\tevent.delegateTarget = this;\n\n\t\t// Call the preDispatch hook for the mapped type, and let it bail if desired\n\t\tif ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Determine handlers\n\t\thandlerQueue = jQuery.event.handlers.call( this, event, handlers );\n\n\t\t// Run delegates first; they may want to stop propagation beneath us\n\t\ti = 0;\n\t\twhile ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) {\n\t\t\tevent.currentTarget = matched.elem;\n\n\t\t\tj = 0;\n\t\t\twhile ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) {\n\n\t\t\t\t// Triggered event must either 1) have no namespace, or\n\t\t\t\t// 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).\n\t\t\t\tif ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) {\n\n\t\t\t\t\tevent.handleObj = handleObj;\n\t\t\t\t\tevent.data = handleObj.data;\n\n\t\t\t\t\tret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )\n\t\t\t\t\t\t\t.apply( matched.elem, args );\n\n\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\tif ( (event.result = ret) === false ) {\n\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t\tevent.stopPropagation();\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// Call the postDispatch hook for the mapped type\n\t\tif ( special.postDispatch ) {\n\t\t\tspecial.postDispatch.call( this, event );\n\t\t}\n\n\t\treturn event.result;\n\t},\n\n\thandlers: function( event, handlers ) {\n\t\tvar sel, handleObj, matches, i,\n\t\t\thandlerQueue = [],\n\t\t\tdelegateCount = handlers.delegateCount,\n\t\t\tcur = event.target;\n\n\t\t// Find delegate handlers\n\t\t// Black-hole SVG <use> instance trees (#13180)\n\t\t// Avoid non-left-click bubbling in Firefox (#3861)\n\t\tif ( delegateCount && cur.nodeType && (!event.button || event.type !== \"click\") ) {\n\n\t\t\tfor ( ; cur != this; cur = cur.parentNode || this ) {\n\n\t\t\t\t// Don't check non-elements (#13208)\n\t\t\t\t// Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)\n\t\t\t\tif ( cur.nodeType === 1 && (cur.disabled !== true || event.type !== \"click\") ) {\n\t\t\t\t\tmatches = [];\n\t\t\t\t\tfor ( i = 0; i < delegateCount; i++ ) {\n\t\t\t\t\t\thandleObj = handlers[ i ];\n\n\t\t\t\t\t\t// Don't conflict with Object.prototype properties (#13203)\n\t\t\t\t\t\tsel = handleObj.selector + \" \";\n\n\t\t\t\t\t\tif ( matches[ sel ] === undefined ) {\n\t\t\t\t\t\t\tmatches[ sel ] = handleObj.needsContext ?\n\t\t\t\t\t\t\t\tjQuery( sel, this ).index( cur ) >= 0 :\n\t\t\t\t\t\t\t\tjQuery.find( sel, this, null, [ cur ] ).length;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ( matches[ sel ] ) {\n\t\t\t\t\t\t\tmatches.push( handleObj );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif ( matches.length ) {\n\t\t\t\t\t\thandlerQueue.push({ elem: cur, handlers: matches });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Add the remaining (directly-bound) handlers\n\t\tif ( delegateCount < handlers.length ) {\n\t\t\thandlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) });\n\t\t}\n\n\t\treturn handlerQueue;\n\t},\n\n\tfix: function( event ) {\n\t\tif ( event[ jQuery.expando ] ) {\n\t\t\treturn event;\n\t\t}\n\n\t\t// Create a writable copy of the event object and normalize some properties\n\t\tvar i, prop, copy,\n\t\t\ttype = event.type,\n\t\t\toriginalEvent = event,\n\t\t\tfixHook = this.fixHooks[ type ];\n\n\t\tif ( !fixHook ) {\n\t\t\tthis.fixHooks[ type ] = fixHook =\n\t\t\t\trmouseEvent.test( type ) ? this.mouseHooks :\n\t\t\t\trkeyEvent.test( type ) ? this.keyHooks :\n\t\t\t\t{};\n\t\t}\n\t\tcopy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;\n\n\t\tevent = new jQuery.Event( originalEvent );\n\n\t\ti = copy.length;\n\t\twhile ( i-- ) {\n\t\t\tprop = copy[ i ];\n\t\t\tevent[ prop ] = originalEvent[ prop ];\n\t\t}\n\n\t\t// Support: IE<9\n\t\t// Fix target property (#1925)\n\t\tif ( !event.target ) {\n\t\t\tevent.target = originalEvent.srcElement || document;\n\t\t}\n\n\t\t// Support: Chrome 23+, Safari?\n\t\t// Target should not be a text node (#504, #13143)\n\t\tif ( event.target.nodeType === 3 ) {\n\t\t\tevent.target = event.target.parentNode;\n\t\t}\n\n\t\t// Support: IE<9\n\t\t// For mouse/key events, metaKey==false if it's undefined (#3368, #11328)\n\t\tevent.metaKey = !!event.metaKey;\n\n\t\treturn fixHook.filter ? fixHook.filter( event, originalEvent ) : event;\n\t},\n\n\t// Includes some event props shared by KeyEvent and MouseEvent\n\tprops: \"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which\".split(\" \"),\n\n\tfixHooks: {},\n\n\tkeyHooks: {\n\t\tprops: \"char charCode key keyCode\".split(\" \"),\n\t\tfilter: function( event, original ) {\n\n\t\t\t// Add which for key events\n\t\t\tif ( event.which == null ) {\n\t\t\t\tevent.which = original.charCode != null ? original.charCode : original.keyCode;\n\t\t\t}\n\n\t\t\treturn event;\n\t\t}\n\t},\n\n\tmouseHooks: {\n\t\tprops: \"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement\".split(\" \"),\n\t\tfilter: function( event, original ) {\n\t\t\tvar body, eventDoc, doc,\n\t\t\t\tbutton = original.button,\n\t\t\t\tfromElement = original.fromElement;\n\n\t\t\t// Calculate pageX/Y if missing and clientX/Y available\n\t\t\tif ( event.pageX == null && original.clientX != null ) {\n\t\t\t\teventDoc = event.target.ownerDocument || document;\n\t\t\t\tdoc = eventDoc.documentElement;\n\t\t\t\tbody = eventDoc.body;\n\n\t\t\t\tevent.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );\n\t\t\t\tevent.pageY = original.clientY + ( doc && doc.scrollTop  || body && body.scrollTop  || 0 ) - ( doc && doc.clientTop  || body && body.clientTop  || 0 );\n\t\t\t}\n\n\t\t\t// Add relatedTarget, if necessary\n\t\t\tif ( !event.relatedTarget && fromElement ) {\n\t\t\t\tevent.relatedTarget = fromElement === event.target ? original.toElement : fromElement;\n\t\t\t}\n\n\t\t\t// Add which for click: 1 === left; 2 === middle; 3 === right\n\t\t\t// Note: button is not normalized, so don't use it\n\t\t\tif ( !event.which && button !== undefined ) {\n\t\t\t\tevent.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );\n\t\t\t}\n\n\t\t\treturn event;\n\t\t}\n\t},\n\n\tspecial: {\n\t\tload: {\n\t\t\t// Prevent triggered image.load events from bubbling to window.load\n\t\t\tnoBubble: true\n\t\t},\n\t\tclick: {\n\t\t\t// For checkbox, fire native event so checked state will be right\n\t\t\ttrigger: function() {\n\t\t\t\tif ( jQuery.nodeName( this, \"input\" ) && this.type === \"checkbox\" && this.click ) {\n\t\t\t\t\tthis.click();\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tfocus: {\n\t\t\t// Fire native event if possible so blur/focus sequence is correct\n\t\t\ttrigger: function() {\n\t\t\t\tif ( this !== document.activeElement && this.focus ) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tthis.focus();\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t} catch ( e ) {\n\t\t\t\t\t\t// Support: IE<9\n\t\t\t\t\t\t// If we error on focus to hidden element (#1486, #12518),\n\t\t\t\t\t\t// let .trigger() run the handlers\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\tdelegateType: \"focusin\"\n\t\t},\n\t\tblur: {\n\t\t\ttrigger: function() {\n\t\t\t\tif ( this === document.activeElement && this.blur ) {\n\t\t\t\t\tthis.blur();\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t},\n\t\t\tdelegateType: \"focusout\"\n\t\t},\n\n\t\tbeforeunload: {\n\t\t\tpostDispatch: function( event ) {\n\n\t\t\t\t// Even when returnValue equals to undefined Firefox will still show alert\n\t\t\t\tif ( event.result !== undefined ) {\n\t\t\t\t\tevent.originalEvent.returnValue = event.result;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\tsimulate: function( type, elem, event, bubble ) {\n\t\t// Piggyback on a donor event to simulate a different one.\n\t\t// Fake originalEvent to avoid donor's stopPropagation, but if the\n\t\t// simulated event prevents default then we do the same on the donor.\n\t\tvar e = jQuery.extend(\n\t\t\tnew jQuery.Event(),\n\t\t\tevent,\n\t\t\t{ type: type,\n\t\t\t\tisSimulated: true,\n\t\t\t\toriginalEvent: {}\n\t\t\t}\n\t\t);\n\t\tif ( bubble ) {\n\t\t\tjQuery.event.trigger( e, null, elem );\n\t\t} else {\n\t\t\tjQuery.event.dispatch.call( elem, e );\n\t\t}\n\t\tif ( e.isDefaultPrevented() ) {\n\t\t\tevent.preventDefault();\n\t\t}\n\t}\n};\n\njQuery.removeEvent = document.removeEventListener ?\n\tfunction( elem, type, handle ) {\n\t\tif ( elem.removeEventListener ) {\n\t\t\telem.removeEventListener( type, handle, false );\n\t\t}\n\t} :\n\tfunction( elem, type, handle ) {\n\t\tvar name = \"on\" + type;\n\n\t\tif ( elem.detachEvent ) {\n\n\t\t\t// #8545, #7054, preventing memory leaks for custom events in IE6-8\n\t\t\t// detachEvent needed property on element, by name of that event, to properly expose it to GC\n\t\t\tif ( typeof elem[ name ] === core_strundefined ) {\n\t\t\t\telem[ name ] = null;\n\t\t\t}\n\n\t\t\telem.detachEvent( name, handle );\n\t\t}\n\t};\n\njQuery.Event = function( src, props ) {\n\t// Allow instantiation without the 'new' keyword\n\tif ( !(this instanceof jQuery.Event) ) {\n\t\treturn new jQuery.Event( src, props );\n\t}\n\n\t// Event object\n\tif ( src && src.type ) {\n\t\tthis.originalEvent = src;\n\t\tthis.type = src.type;\n\n\t\t// Events bubbling up the document may have been marked as prevented\n\t\t// by a handler lower down the tree; reflect the correct value.\n\t\tthis.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false ||\n\t\t\tsrc.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse;\n\n\t// Event type\n\t} else {\n\t\tthis.type = src;\n\t}\n\n\t// Put explicitly provided properties onto the event object\n\tif ( props ) {\n\t\tjQuery.extend( this, props );\n\t}\n\n\t// Create a timestamp if incoming event doesn't have one\n\tthis.timeStamp = src && src.timeStamp || jQuery.now();\n\n\t// Mark it as fixed\n\tthis[ jQuery.expando ] = true;\n};\n\n// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding\n// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html\njQuery.Event.prototype = {\n\tisDefaultPrevented: returnFalse,\n\tisPropagationStopped: returnFalse,\n\tisImmediatePropagationStopped: returnFalse,\n\n\tpreventDefault: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isDefaultPrevented = returnTrue;\n\t\tif ( !e ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If preventDefault exists, run it on the original event\n\t\tif ( e.preventDefault ) {\n\t\t\te.preventDefault();\n\n\t\t// Support: IE\n\t\t// Otherwise set the returnValue property of the original event to false\n\t\t} else {\n\t\t\te.returnValue = false;\n\t\t}\n\t},\n\tstopPropagation: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isPropagationStopped = returnTrue;\n\t\tif ( !e ) {\n\t\t\treturn;\n\t\t}\n\t\t// If stopPropagation exists, run it on the original event\n\t\tif ( e.stopPropagation ) {\n\t\t\te.stopPropagation();\n\t\t}\n\n\t\t// Support: IE\n\t\t// Set the cancelBubble property of the original event to true\n\t\te.cancelBubble = true;\n\t},\n\tstopImmediatePropagation: function() {\n\t\tthis.isImmediatePropagationStopped = returnTrue;\n\t\tthis.stopPropagation();\n\t}\n};\n\n// Create mouseenter/leave events using mouseover/out and event-time checks\njQuery.each({\n\tmouseenter: \"mouseover\",\n\tmouseleave: \"mouseout\"\n}, function( orig, fix ) {\n\tjQuery.event.special[ orig ] = {\n\t\tdelegateType: fix,\n\t\tbindType: fix,\n\n\t\thandle: function( event ) {\n\t\t\tvar ret,\n\t\t\t\ttarget = this,\n\t\t\t\trelated = event.relatedTarget,\n\t\t\t\thandleObj = event.handleObj;\n\n\t\t\t// For mousenter/leave call the handler if related is outside the target.\n\t\t\t// NB: No relatedTarget if the mouse left/entered the browser window\n\t\t\tif ( !related || (related !== target && !jQuery.contains( target, related )) ) {\n\t\t\t\tevent.type = handleObj.origType;\n\t\t\t\tret = handleObj.handler.apply( this, arguments );\n\t\t\t\tevent.type = fix;\n\t\t\t}\n\t\t\treturn ret;\n\t\t}\n\t};\n});\n\n// IE submit delegation\nif ( !jQuery.support.submitBubbles ) {\n\n\tjQuery.event.special.submit = {\n\t\tsetup: function() {\n\t\t\t// Only need this for delegated form submit events\n\t\t\tif ( jQuery.nodeName( this, \"form\" ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// Lazy-add a submit handler when a descendant form may potentially be submitted\n\t\t\tjQuery.event.add( this, \"click._submit keypress._submit\", function( e ) {\n\t\t\t\t// Node name check avoids a VML-related crash in IE (#9807)\n\t\t\t\tvar elem = e.target,\n\t\t\t\t\tform = jQuery.nodeName( elem, \"input\" ) || jQuery.nodeName( elem, \"button\" ) ? elem.form : undefined;\n\t\t\t\tif ( form && !jQuery._data( form, \"submitBubbles\" ) ) {\n\t\t\t\t\tjQuery.event.add( form, \"submit._submit\", function( event ) {\n\t\t\t\t\t\tevent._submit_bubble = true;\n\t\t\t\t\t});\n\t\t\t\t\tjQuery._data( form, \"submitBubbles\", true );\n\t\t\t\t}\n\t\t\t});\n\t\t\t// return undefined since we don't need an event listener\n\t\t},\n\n\t\tpostDispatch: function( event ) {\n\t\t\t// If form was submitted by the user, bubble the event up the tree\n\t\t\tif ( event._submit_bubble ) {\n\t\t\t\tdelete event._submit_bubble;\n\t\t\t\tif ( this.parentNode && !event.isTrigger ) {\n\t\t\t\t\tjQuery.event.simulate( \"submit\", this.parentNode, event, true );\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\tteardown: function() {\n\t\t\t// Only need this for delegated form submit events\n\t\t\tif ( jQuery.nodeName( this, \"form\" ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// Remove delegated handlers; cleanData eventually reaps submit handlers attached above\n\t\t\tjQuery.event.remove( this, \"._submit\" );\n\t\t}\n\t};\n}\n\n// IE change delegation and checkbox/radio fix\nif ( !jQuery.support.changeBubbles ) {\n\n\tjQuery.event.special.change = {\n\n\t\tsetup: function() {\n\n\t\t\tif ( rformElems.test( this.nodeName ) ) {\n\t\t\t\t// IE doesn't fire change on a check/radio until blur; trigger it on click\n\t\t\t\t// after a propertychange. Eat the blur-change in special.change.handle.\n\t\t\t\t// This still fires onchange a second time for check/radio after blur.\n\t\t\t\tif ( this.type === \"checkbox\" || this.type === \"radio\" ) {\n\t\t\t\t\tjQuery.event.add( this, \"propertychange._change\", function( event ) {\n\t\t\t\t\t\tif ( event.originalEvent.propertyName === \"checked\" ) {\n\t\t\t\t\t\t\tthis._just_changed = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t\tjQuery.event.add( this, \"click._change\", function( event ) {\n\t\t\t\t\t\tif ( this._just_changed && !event.isTrigger ) {\n\t\t\t\t\t\t\tthis._just_changed = false;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Allow triggered, simulated change events (#11500)\n\t\t\t\t\t\tjQuery.event.simulate( \"change\", this, event, true );\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t// Delegated event; lazy-add a change handler on descendant inputs\n\t\t\tjQuery.event.add( this, \"beforeactivate._change\", function( e ) {\n\t\t\t\tvar elem = e.target;\n\n\t\t\t\tif ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, \"changeBubbles\" ) ) {\n\t\t\t\t\tjQuery.event.add( elem, \"change._change\", function( event ) {\n\t\t\t\t\t\tif ( this.parentNode && !event.isSimulated && !event.isTrigger ) {\n\t\t\t\t\t\t\tjQuery.event.simulate( \"change\", this.parentNode, event, true );\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t\tjQuery._data( elem, \"changeBubbles\", true );\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\n\t\thandle: function( event ) {\n\t\t\tvar elem = event.target;\n\n\t\t\t// Swallow native change events from checkbox/radio, we already triggered them above\n\t\t\tif ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== \"radio\" && elem.type !== \"checkbox\") ) {\n\t\t\t\treturn event.handleObj.handler.apply( this, arguments );\n\t\t\t}\n\t\t},\n\n\t\tteardown: function() {\n\t\t\tjQuery.event.remove( this, \"._change\" );\n\n\t\t\treturn !rformElems.test( this.nodeName );\n\t\t}\n\t};\n}\n\n// Create \"bubbling\" focus and blur events\nif ( !jQuery.support.focusinBubbles ) {\n\tjQuery.each({ focus: \"focusin\", blur: \"focusout\" }, function( orig, fix ) {\n\n\t\t// Attach a single capturing handler while someone wants focusin/focusout\n\t\tvar attaches = 0,\n\t\t\thandler = function( event ) {\n\t\t\t\tjQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );\n\t\t\t};\n\n\t\tjQuery.event.special[ fix ] = {\n\t\t\tsetup: function() {\n\t\t\t\tif ( attaches++ === 0 ) {\n\t\t\t\t\tdocument.addEventListener( orig, handler, true );\n\t\t\t\t}\n\t\t\t},\n\t\t\tteardown: function() {\n\t\t\t\tif ( --attaches === 0 ) {\n\t\t\t\t\tdocument.removeEventListener( orig, handler, true );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t});\n}\n\njQuery.fn.extend({\n\n\ton: function( types, selector, data, fn, /*INTERNAL*/ one ) {\n\t\tvar type, origFn;\n\n\t\t// Types can be a map of types/handlers\n\t\tif ( typeof types === \"object\" ) {\n\t\t\t// ( types-Object, selector, data )\n\t\t\tif ( typeof selector !== \"string\" ) {\n\t\t\t\t// ( types-Object, data )\n\t\t\t\tdata = data || selector;\n\t\t\t\tselector = undefined;\n\t\t\t}\n\t\t\tfor ( type in types ) {\n\t\t\t\tthis.on( type, selector, data, types[ type ], one );\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\n\t\tif ( data == null && fn == null ) {\n\t\t\t// ( types, fn )\n\t\t\tfn = selector;\n\t\t\tdata = selector = undefined;\n\t\t} else if ( fn == null ) {\n\t\t\tif ( typeof selector === \"string\" ) {\n\t\t\t\t// ( types, selector, fn )\n\t\t\t\tfn = data;\n\t\t\t\tdata = undefined;\n\t\t\t} else {\n\t\t\t\t// ( types, data, fn )\n\t\t\t\tfn = data;\n\t\t\t\tdata = selector;\n\t\t\t\tselector = undefined;\n\t\t\t}\n\t\t}\n\t\tif ( fn === false ) {\n\t\t\tfn = returnFalse;\n\t\t} else if ( !fn ) {\n\t\t\treturn this;\n\t\t}\n\n\t\tif ( one === 1 ) {\n\t\t\torigFn = fn;\n\t\t\tfn = function( event ) {\n\t\t\t\t// Can use an empty set, since event contains the info\n\t\t\t\tjQuery().off( event );\n\t\t\t\treturn origFn.apply( this, arguments );\n\t\t\t};\n\t\t\t// Use same guid so caller can remove using origFn\n\t\t\tfn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );\n\t\t}\n\t\treturn this.each( function() {\n\t\t\tjQuery.event.add( this, types, fn, data, selector );\n\t\t});\n\t},\n\tone: function( types, selector, data, fn ) {\n\t\treturn this.on( types, selector, data, fn, 1 );\n\t},\n\toff: function( types, selector, fn ) {\n\t\tvar handleObj, type;\n\t\tif ( types && types.preventDefault && types.handleObj ) {\n\t\t\t// ( event )  dispatched jQuery.Event\n\t\t\thandleObj = types.handleObj;\n\t\t\tjQuery( types.delegateTarget ).off(\n\t\t\t\thandleObj.namespace ? handleObj.origType + \".\" + handleObj.namespace : handleObj.origType,\n\t\t\t\thandleObj.selector,\n\t\t\t\thandleObj.handler\n\t\t\t);\n\t\t\treturn this;\n\t\t}\n\t\tif ( typeof types === \"object\" ) {\n\t\t\t// ( types-object [, selector] )\n\t\t\tfor ( type in types ) {\n\t\t\t\tthis.off( type, selector, types[ type ] );\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\t\tif ( selector === false || typeof selector === \"function\" ) {\n\t\t\t// ( types [, fn] )\n\t\t\tfn = selector;\n\t\t\tselector = undefined;\n\t\t}\n\t\tif ( fn === false ) {\n\t\t\tfn = returnFalse;\n\t\t}\n\t\treturn this.each(function() {\n\t\t\tjQuery.event.remove( this, types, fn, selector );\n\t\t});\n\t},\n\n\tbind: function( types, data, fn ) {\n\t\treturn this.on( types, null, data, fn );\n\t},\n\tunbind: function( types, fn ) {\n\t\treturn this.off( types, null, fn );\n\t},\n\n\tdelegate: function( selector, types, data, fn ) {\n\t\treturn this.on( types, selector, data, fn );\n\t},\n\tundelegate: function( selector, types, fn ) {\n\t\t// ( namespace ) or ( selector, types [, fn] )\n\t\treturn arguments.length === 1 ? this.off( selector, \"**\" ) : this.off( types, selector || \"**\", fn );\n\t},\n\n\ttrigger: function( type, data ) {\n\t\treturn this.each(function() {\n\t\t\tjQuery.event.trigger( type, data, this );\n\t\t});\n\t},\n\ttriggerHandler: function( type, data ) {\n\t\tvar elem = this[0];\n\t\tif ( elem ) {\n\t\t\treturn jQuery.event.trigger( type, data, elem, true );\n\t\t}\n\t}\n});\n/*!\n * Sizzle CSS Selector Engine\n * Copyright 2012 jQuery Foundation and other contributors\n * Released under the MIT license\n * http://sizzlejs.com/\n */\n(function( window, undefined ) {\n\nvar i,\n\tcachedruns,\n\tExpr,\n\tgetText,\n\tisXML,\n\tcompile,\n\thasDuplicate,\n\toutermostContext,\n\n\t// Local document vars\n\tsetDocument,\n\tdocument,\n\tdocElem,\n\tdocumentIsXML,\n\trbuggyQSA,\n\trbuggyMatches,\n\tmatches,\n\tcontains,\n\tsortOrder,\n\n\t// Instance-specific data\n\texpando = \"sizzle\" + -(new Date()),\n\tpreferredDoc = window.document,\n\tsupport = {},\n\tdirruns = 0,\n\tdone = 0,\n\tclassCache = createCache(),\n\ttokenCache = createCache(),\n\tcompilerCache = createCache(),\n\n\t// General-purpose constants\n\tstrundefined = typeof undefined,\n\tMAX_NEGATIVE = 1 << 31,\n\n\t// Array methods\n\tarr = [],\n\tpop = arr.pop,\n\tpush = arr.push,\n\tslice = arr.slice,\n\t// Use a stripped-down indexOf if we can't use a native one\n\tindexOf = arr.indexOf || function( elem ) {\n\t\tvar i = 0,\n\t\t\tlen = this.length;\n\t\tfor ( ; i < len; i++ ) {\n\t\t\tif ( this[i] === elem ) {\n\t\t\t\treturn i;\n\t\t\t}\n\t\t}\n\t\treturn -1;\n\t},\n\n\n\t// Regular expressions\n\n\t// Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace\n\twhitespace = \"[\\\\x20\\\\t\\\\r\\\\n\\\\f]\",\n\t// http://www.w3.org/TR/css3-syntax/#characters\n\tcharacterEncoding = \"(?:\\\\\\\\.|[\\\\w-]|[^\\\\x00-\\\\xa0])+\",\n\n\t// Loosely modeled on CSS identifier characters\n\t// An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors\n\t// Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier\n\tidentifier = characterEncoding.replace( \"w\", \"w#\" ),\n\n\t// Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors\n\toperators = \"([*^$|!~]?=)\",\n\tattributes = \"\\\\[\" + whitespace + \"*(\" + characterEncoding + \")\" + whitespace +\n\t\t\"*(?:\" + operators + whitespace + \"*(?:(['\\\"])((?:\\\\\\\\.|[^\\\\\\\\])*?)\\\\3|(\" + identifier + \")|)|)\" + whitespace + \"*\\\\]\",\n\n\t// Prefer arguments quoted,\n\t//   then not containing pseudos/brackets,\n\t//   then attribute selectors/non-parenthetical expressions,\n\t//   then anything else\n\t// These preferences are here to reduce the number of selectors\n\t//   needing tokenize in the PSEUDO preFilter\n\tpseudos = \":(\" + characterEncoding + \")(?:\\\\(((['\\\"])((?:\\\\\\\\.|[^\\\\\\\\])*?)\\\\3|((?:\\\\\\\\.|[^\\\\\\\\()[\\\\]]|\" + attributes.replace( 3, 8 ) + \")*)|.*)\\\\)|)\",\n\n\t// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter\n\trtrim = new RegExp( \"^\" + whitespace + \"+|((?:^|[^\\\\\\\\])(?:\\\\\\\\.)*)\" + whitespace + \"+$\", \"g\" ),\n\n\trcomma = new RegExp( \"^\" + whitespace + \"*,\" + whitespace + \"*\" ),\n\trcombinators = new RegExp( \"^\" + whitespace + \"*([\\\\x20\\\\t\\\\r\\\\n\\\\f>+~])\" + whitespace + \"*\" ),\n\trpseudo = new RegExp( pseudos ),\n\tridentifier = new RegExp( \"^\" + identifier + \"$\" ),\n\n\tmatchExpr = {\n\t\t\"ID\": new RegExp( \"^#(\" + characterEncoding + \")\" ),\n\t\t\"CLASS\": new RegExp( \"^\\\\.(\" + characterEncoding + \")\" ),\n\t\t\"NAME\": new RegExp( \"^\\\\[name=['\\\"]?(\" + characterEncoding + \")['\\\"]?\\\\]\" ),\n\t\t\"TAG\": new RegExp( \"^(\" + characterEncoding.replace( \"w\", \"w*\" ) + \")\" ),\n\t\t\"ATTR\": new RegExp( \"^\" + attributes ),\n\t\t\"PSEUDO\": new RegExp( \"^\" + pseudos ),\n\t\t\"CHILD\": new RegExp( \"^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\\\(\" + whitespace +\n\t\t\t\"*(even|odd|(([+-]|)(\\\\d*)n|)\" + whitespace + \"*(?:([+-]|)\" + whitespace +\n\t\t\t\"*(\\\\d+)|))\" + whitespace + \"*\\\\)|)\", \"i\" ),\n\t\t// For use in libraries implementing .is()\n\t\t// We use this for POS matching in `select`\n\t\t\"needsContext\": new RegExp( \"^\" + whitespace + \"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\\\(\" +\n\t\t\twhitespace + \"*((?:-\\\\d)?\\\\d*)\" + whitespace + \"*\\\\)|)(?=[^-]|$)\", \"i\" )\n\t},\n\n\trsibling = /[\\x20\\t\\r\\n\\f]*[+~]/,\n\n\trnative = /^[^{]+\\{\\s*\\[native code/,\n\n\t// Easily-parseable/retrievable ID or TAG or CLASS selectors\n\trquickExpr = /^(?:#([\\w-]+)|(\\w+)|\\.([\\w-]+))$/,\n\n\trinputs = /^(?:input|select|textarea|button)$/i,\n\trheader = /^h\\d$/i,\n\n\trescape = /'|\\\\/g,\n\trattributeQuotes = /\\=[\\x20\\t\\r\\n\\f]*([^'\"\\]]*)[\\x20\\t\\r\\n\\f]*\\]/g,\n\n\t// CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters\n\trunescape = /\\\\([\\da-fA-F]{1,6}[\\x20\\t\\r\\n\\f]?|.)/g,\n\tfunescape = function( _, escaped ) {\n\t\tvar high = \"0x\" + escaped - 0x10000;\n\t\t// NaN means non-codepoint\n\t\treturn high !== high ?\n\t\t\tescaped :\n\t\t\t// BMP codepoint\n\t\t\thigh < 0 ?\n\t\t\t\tString.fromCharCode( high + 0x10000 ) :\n\t\t\t\t// Supplemental Plane codepoint (surrogate pair)\n\t\t\t\tString.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );\n\t};\n\n// Use a stripped-down slice if we can't use a native one\ntry {\n\tslice.call( preferredDoc.documentElement.childNodes, 0 )[0].nodeType;\n} catch ( e ) {\n\tslice = function( i ) {\n\t\tvar elem,\n\t\t\tresults = [];\n\t\twhile ( (elem = this[i++]) ) {\n\t\t\tresults.push( elem );\n\t\t}\n\t\treturn results;\n\t};\n}\n\n/**\n * For feature detection\n * @param {Function} fn The function to test for native support\n */\nfunction isNative( fn ) {\n\treturn rnative.test( fn + \"\" );\n}\n\n/**\n * Create key-value caches of limited size\n * @returns {Function(string, Object)} Returns the Object data after storing it on itself with\n *\tproperty name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)\n *\tdeleting the oldest entry\n */\nfunction createCache() {\n\tvar cache,\n\t\tkeys = [];\n\n\treturn (cache = function( key, value ) {\n\t\t// Use (key + \" \") to avoid collision with native prototype properties (see Issue #157)\n\t\tif ( keys.push( key += \" \" ) > Expr.cacheLength ) {\n\t\t\t// Only keep the most recent entries\n\t\t\tdelete cache[ keys.shift() ];\n\t\t}\n\t\treturn (cache[ key ] = value);\n\t});\n}\n\n/**\n * Mark a function for special use by Sizzle\n * @param {Function} fn The function to mark\n */\nfunction markFunction( fn ) {\n\tfn[ expando ] = true;\n\treturn fn;\n}\n\n/**\n * Support testing using an element\n * @param {Function} fn Passed the created div and expects a boolean result\n */\nfunction assert( fn ) {\n\tvar div = document.createElement(\"div\");\n\n\ttry {\n\t\treturn fn( div );\n\t} catch (e) {\n\t\treturn false;\n\t} finally {\n\t\t// release memory in IE\n\t\tdiv = null;\n\t}\n}\n\nfunction Sizzle( selector, context, results, seed ) {\n\tvar match, elem, m, nodeType,\n\t\t// QSA vars\n\t\ti, groups, old, nid, newContext, newSelector;\n\n\tif ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {\n\t\tsetDocument( context );\n\t}\n\n\tcontext = context || document;\n\tresults = results || [];\n\n\tif ( !selector || typeof selector !== \"string\" ) {\n\t\treturn results;\n\t}\n\n\tif ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {\n\t\treturn [];\n\t}\n\n\tif ( !documentIsXML && !seed ) {\n\n\t\t// Shortcuts\n\t\tif ( (match = rquickExpr.exec( selector )) ) {\n\t\t\t// Speed-up: Sizzle(\"#ID\")\n\t\t\tif ( (m = match[1]) ) {\n\t\t\t\tif ( nodeType === 9 ) {\n\t\t\t\t\telem = context.getElementById( m );\n\t\t\t\t\t// Check parentNode to catch when Blackberry 4.6 returns\n\t\t\t\t\t// nodes that are no longer in the document #6963\n\t\t\t\t\tif ( elem && elem.parentNode ) {\n\t\t\t\t\t\t// Handle the case where IE, Opera, and Webkit return items\n\t\t\t\t\t\t// by name instead of ID\n\t\t\t\t\t\tif ( elem.id === m ) {\n\t\t\t\t\t\t\tresults.push( elem );\n\t\t\t\t\t\t\treturn results;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn results;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Context is not a document\n\t\t\t\t\tif ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&\n\t\t\t\t\t\tcontains( context, elem ) && elem.id === m ) {\n\t\t\t\t\t\tresults.push( elem );\n\t\t\t\t\t\treturn results;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t// Speed-up: Sizzle(\"TAG\")\n\t\t\t} else if ( match[2] ) {\n\t\t\t\tpush.apply( results, slice.call(context.getElementsByTagName( selector ), 0) );\n\t\t\t\treturn results;\n\n\t\t\t// Speed-up: Sizzle(\".CLASS\")\n\t\t\t} else if ( (m = match[3]) && support.getByClassName && context.getElementsByClassName ) {\n\t\t\t\tpush.apply( results, slice.call(context.getElementsByClassName( m ), 0) );\n\t\t\t\treturn results;\n\t\t\t}\n\t\t}\n\n\t\t// QSA path\n\t\tif ( support.qsa && !rbuggyQSA.test(selector) ) {\n\t\t\told = true;\n\t\t\tnid = expando;\n\t\t\tnewContext = context;\n\t\t\tnewSelector = nodeType === 9 && selector;\n\n\t\t\t// qSA works strangely on Element-rooted queries\n\t\t\t// We can work around this by specifying an extra ID on the root\n\t\t\t// and working up from there (Thanks to Andrew Dupont for the technique)\n\t\t\t// IE 8 doesn't work on object elements\n\t\t\tif ( nodeType === 1 && context.nodeName.toLowerCase() !== \"object\" ) {\n\t\t\t\tgroups = tokenize( selector );\n\n\t\t\t\tif ( (old = context.getAttribute(\"id\")) ) {\n\t\t\t\t\tnid = old.replace( rescape, \"\\\\$&\" );\n\t\t\t\t} else {\n\t\t\t\t\tcontext.setAttribute( \"id\", nid );\n\t\t\t\t}\n\t\t\t\tnid = \"[id='\" + nid + \"'] \";\n\n\t\t\t\ti = groups.length;\n\t\t\t\twhile ( i-- ) {\n\t\t\t\t\tgroups[i] = nid + toSelector( groups[i] );\n\t\t\t\t}\n\t\t\t\tnewContext = rsibling.test( selector ) && context.parentNode || context;\n\t\t\t\tnewSelector = groups.join(\",\");\n\t\t\t}\n\n\t\t\tif ( newSelector ) {\n\t\t\t\ttry {\n\t\t\t\t\tpush.apply( results, slice.call( newContext.querySelectorAll(\n\t\t\t\t\t\tnewSelector\n\t\t\t\t\t), 0 ) );\n\t\t\t\t\treturn results;\n\t\t\t\t} catch(qsaError) {\n\t\t\t\t} finally {\n\t\t\t\t\tif ( !old ) {\n\t\t\t\t\t\tcontext.removeAttribute(\"id\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// All others\n\treturn select( selector.replace( rtrim, \"$1\" ), context, results, seed );\n}\n\n/**\n * Detect xml\n * @param {Element|Object} elem An element or a document\n */\nisXML = Sizzle.isXML = function( elem ) {\n\t// documentElement is verified for cases where it doesn't yet exist\n\t// (such as loading iframes in IE - #4833)\n\tvar documentElement = elem && (elem.ownerDocument || elem).documentElement;\n\treturn documentElement ? documentElement.nodeName !== \"HTML\" : false;\n};\n\n/**\n * Sets document-related variables once based on the current document\n * @param {Element|Object} [doc] An element or document object to use to set the document\n * @returns {Object} Returns the current document\n */\nsetDocument = Sizzle.setDocument = function( node ) {\n\tvar doc = node ? node.ownerDocument || node : preferredDoc;\n\n\t// If no document and documentElement is available, return\n\tif ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {\n\t\treturn document;\n\t}\n\n\t// Set our document\n\tdocument = doc;\n\tdocElem = doc.documentElement;\n\n\t// Support tests\n\tdocumentIsXML = isXML( doc );\n\n\t// Check if getElementsByTagName(\"*\") returns only elements\n\tsupport.tagNameNoComments = assert(function( div ) {\n\t\tdiv.appendChild( doc.createComment(\"\") );\n\t\treturn !div.getElementsByTagName(\"*\").length;\n\t});\n\n\t// Check if attributes should be retrieved by attribute nodes\n\tsupport.attributes = assert(function( div ) {\n\t\tdiv.innerHTML = \"<select></select>\";\n\t\tvar type = typeof div.lastChild.getAttribute(\"multiple\");\n\t\t// IE8 returns a string for some attributes even when not present\n\t\treturn type !== \"boolean\" && type !== \"string\";\n\t});\n\n\t// Check if getElementsByClassName can be trusted\n\tsupport.getByClassName = assert(function( div ) {\n\t\t// Opera can't find a second classname (in 9.6)\n\t\tdiv.innerHTML = \"<div class='hidden e'></div><div class='hidden'></div>\";\n\t\tif ( !div.getElementsByClassName || !div.getElementsByClassName(\"e\").length ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Safari 3.2 caches class attributes and doesn't catch changes\n\t\tdiv.lastChild.className = \"e\";\n\t\treturn div.getElementsByClassName(\"e\").length === 2;\n\t});\n\n\t// Check if getElementById returns elements by name\n\t// Check if getElementsByName privileges form controls or returns elements by ID\n\tsupport.getByName = assert(function( div ) {\n\t\t// Inject content\n\t\tdiv.id = expando + 0;\n\t\tdiv.innerHTML = \"<a name='\" + expando + \"'></a><div name='\" + expando + \"'></div>\";\n\t\tdocElem.insertBefore( div, docElem.firstChild );\n\n\t\t// Test\n\t\tvar pass = doc.getElementsByName &&\n\t\t\t// buggy browsers will return fewer than the correct 2\n\t\t\tdoc.getElementsByName( expando ).length === 2 +\n\t\t\t// buggy browsers will return more than the correct 0\n\t\t\tdoc.getElementsByName( expando + 0 ).length;\n\t\tsupport.getIdNotName = !doc.getElementById( expando );\n\n\t\t// Cleanup\n\t\tdocElem.removeChild( div );\n\n\t\treturn pass;\n\t});\n\n\t// IE6/7 return modified attributes\n\tExpr.attrHandle = assert(function( div ) {\n\t\tdiv.innerHTML = \"<a href='#'></a>\";\n\t\treturn div.firstChild && typeof div.firstChild.getAttribute !== strundefined &&\n\t\t\tdiv.firstChild.getAttribute(\"href\") === \"#\";\n\t}) ?\n\t\t{} :\n\t\t{\n\t\t\t\"href\": function( elem ) {\n\t\t\t\treturn elem.getAttribute( \"href\", 2 );\n\t\t\t},\n\t\t\t\"type\": function( elem ) {\n\t\t\t\treturn elem.getAttribute(\"type\");\n\t\t\t}\n\t\t};\n\n\t// ID find and filter\n\tif ( support.getIdNotName ) {\n\t\tExpr.find[\"ID\"] = function( id, context ) {\n\t\t\tif ( typeof context.getElementById !== strundefined && !documentIsXML ) {\n\t\t\t\tvar m = context.getElementById( id );\n\t\t\t\t// Check parentNode to catch when Blackberry 4.6 returns\n\t\t\t\t// nodes that are no longer in the document #6963\n\t\t\t\treturn m && m.parentNode ? [m] : [];\n\t\t\t}\n\t\t};\n\t\tExpr.filter[\"ID\"] = function( id ) {\n\t\t\tvar attrId = id.replace( runescape, funescape );\n\t\t\treturn function( elem ) {\n\t\t\t\treturn elem.getAttribute(\"id\") === attrId;\n\t\t\t};\n\t\t};\n\t} else {\n\t\tExpr.find[\"ID\"] = function( id, context ) {\n\t\t\tif ( typeof context.getElementById !== strundefined && !documentIsXML ) {\n\t\t\t\tvar m = context.getElementById( id );\n\n\t\t\t\treturn m ?\n\t\t\t\t\tm.id === id || typeof m.getAttributeNode !== strundefined && m.getAttributeNode(\"id\").value === id ?\n\t\t\t\t\t\t[m] :\n\t\t\t\t\t\tundefined :\n\t\t\t\t\t[];\n\t\t\t}\n\t\t};\n\t\tExpr.filter[\"ID\"] =  function( id ) {\n\t\t\tvar attrId = id.replace( runescape, funescape );\n\t\t\treturn function( elem ) {\n\t\t\t\tvar node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode(\"id\");\n\t\t\t\treturn node && node.value === attrId;\n\t\t\t};\n\t\t};\n\t}\n\n\t// Tag\n\tExpr.find[\"TAG\"] = support.tagNameNoComments ?\n\t\tfunction( tag, context ) {\n\t\t\tif ( typeof context.getElementsByTagName !== strundefined ) {\n\t\t\t\treturn context.getElementsByTagName( tag );\n\t\t\t}\n\t\t} :\n\t\tfunction( tag, context ) {\n\t\t\tvar elem,\n\t\t\t\ttmp = [],\n\t\t\t\ti = 0,\n\t\t\t\tresults = context.getElementsByTagName( tag );\n\n\t\t\t// Filter out possible comments\n\t\t\tif ( tag === \"*\" ) {\n\t\t\t\twhile ( (elem = results[i++]) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\t\t\ttmp.push( elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn tmp;\n\t\t\t}\n\t\t\treturn results;\n\t\t};\n\n\t// Name\n\tExpr.find[\"NAME\"] = support.getByName && function( tag, context ) {\n\t\tif ( typeof context.getElementsByName !== strundefined ) {\n\t\t\treturn context.getElementsByName( name );\n\t\t}\n\t};\n\n\t// Class\n\tExpr.find[\"CLASS\"] = support.getByClassName && function( className, context ) {\n\t\tif ( typeof context.getElementsByClassName !== strundefined && !documentIsXML ) {\n\t\t\treturn context.getElementsByClassName( className );\n\t\t}\n\t};\n\n\t// QSA and matchesSelector support\n\n\t// matchesSelector(:active) reports false when true (IE9/Opera 11.5)\n\trbuggyMatches = [];\n\n\t// qSa(:focus) reports false when true (Chrome 21),\n\t// no need to also add to buggyMatches since matches checks buggyQSA\n\t// A support test would require too much code (would include document ready)\n\trbuggyQSA = [ \":focus\" ];\n\n\tif ( (support.qsa = isNative(doc.querySelectorAll)) ) {\n\t\t// Build QSA regex\n\t\t// Regex strategy adopted from Diego Perini\n\t\tassert(function( div ) {\n\t\t\t// Select is set to empty string on purpose\n\t\t\t// This is to test IE's treatment of not explictly\n\t\t\t// setting a boolean content attribute,\n\t\t\t// since its presence should be enough\n\t\t\t// http://bugs.jquery.com/ticket/12359\n\t\t\tdiv.innerHTML = \"<select><option selected=''></option></select>\";\n\n\t\t\t// IE8 - Some boolean attributes are not treated correctly\n\t\t\tif ( !div.querySelectorAll(\"[selected]\").length ) {\n\t\t\t\trbuggyQSA.push( \"\\\\[\" + whitespace + \"*(?:checked|disabled|ismap|multiple|readonly|selected|value)\" );\n\t\t\t}\n\n\t\t\t// Webkit/Opera - :checked should return selected option elements\n\t\t\t// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked\n\t\t\t// IE8 throws error here and will not see later tests\n\t\t\tif ( !div.querySelectorAll(\":checked\").length ) {\n\t\t\t\trbuggyQSA.push(\":checked\");\n\t\t\t}\n\t\t});\n\n\t\tassert(function( div ) {\n\n\t\t\t// Opera 10-12/IE8 - ^= $= *= and empty values\n\t\t\t// Should not select anything\n\t\t\tdiv.innerHTML = \"<input type='hidden' i=''/>\";\n\t\t\tif ( div.querySelectorAll(\"[i^='']\").length ) {\n\t\t\t\trbuggyQSA.push( \"[*^$]=\" + whitespace + \"*(?:\\\"\\\"|'')\" );\n\t\t\t}\n\n\t\t\t// FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)\n\t\t\t// IE8 throws error here and will not see later tests\n\t\t\tif ( !div.querySelectorAll(\":enabled\").length ) {\n\t\t\t\trbuggyQSA.push( \":enabled\", \":disabled\" );\n\t\t\t}\n\n\t\t\t// Opera 10-11 does not throw on post-comma invalid pseudos\n\t\t\tdiv.querySelectorAll(\"*,:x\");\n\t\t\trbuggyQSA.push(\",.*:\");\n\t\t});\n\t}\n\n\tif ( (support.matchesSelector = isNative( (matches = docElem.matchesSelector ||\n\t\tdocElem.mozMatchesSelector ||\n\t\tdocElem.webkitMatchesSelector ||\n\t\tdocElem.oMatchesSelector ||\n\t\tdocElem.msMatchesSelector) )) ) {\n\n\t\tassert(function( div ) {\n\t\t\t// Check to see if it's possible to do matchesSelector\n\t\t\t// on a disconnected node (IE 9)\n\t\t\tsupport.disconnectedMatch = matches.call( div, \"div\" );\n\n\t\t\t// This should fail with an exception\n\t\t\t// Gecko does not error, returns false instead\n\t\t\tmatches.call( div, \"[s!='']:x\" );\n\t\t\trbuggyMatches.push( \"!=\", pseudos );\n\t\t});\n\t}\n\n\trbuggyQSA = new RegExp( rbuggyQSA.join(\"|\") );\n\trbuggyMatches = new RegExp( rbuggyMatches.join(\"|\") );\n\n\t// Element contains another\n\t// Purposefully does not implement inclusive descendent\n\t// As in, an element does not contain itself\n\tcontains = isNative(docElem.contains) || docElem.compareDocumentPosition ?\n\t\tfunction( a, b ) {\n\t\t\tvar adown = a.nodeType === 9 ? a.documentElement : a,\n\t\t\t\tbup = b && b.parentNode;\n\t\t\treturn a === bup || !!( bup && bup.nodeType === 1 && (\n\t\t\t\tadown.contains ?\n\t\t\t\t\tadown.contains( bup ) :\n\t\t\t\t\ta.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16\n\t\t\t));\n\t\t} :\n\t\tfunction( a, b ) {\n\t\t\tif ( b ) {\n\t\t\t\twhile ( (b = b.parentNode) ) {\n\t\t\t\t\tif ( b === a ) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t};\n\n\t// Document order sorting\n\tsortOrder = docElem.compareDocumentPosition ?\n\tfunction( a, b ) {\n\t\tvar compare;\n\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t\treturn 0;\n\t\t}\n\n\t\tif ( (compare = b.compareDocumentPosition && a.compareDocumentPosition && a.compareDocumentPosition( b )) ) {\n\t\t\tif ( compare & 1 || a.parentNode && a.parentNode.nodeType === 11 ) {\n\t\t\t\tif ( a === doc || contains( preferredDoc, a ) ) {\n\t\t\t\t\treturn -1;\n\t\t\t\t}\n\t\t\t\tif ( b === doc || contains( preferredDoc, b ) ) {\n\t\t\t\t\treturn 1;\n\t\t\t\t}\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\treturn compare & 4 ? -1 : 1;\n\t\t}\n\n\t\treturn a.compareDocumentPosition ? -1 : 1;\n\t} :\n\tfunction( a, b ) {\n\t\tvar cur,\n\t\t\ti = 0,\n\t\t\taup = a.parentNode,\n\t\t\tbup = b.parentNode,\n\t\t\tap = [ a ],\n\t\t\tbp = [ b ];\n\n\t\t// Exit early if the nodes are identical\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t\treturn 0;\n\n\t\t// Parentless nodes are either documents or disconnected\n\t\t} else if ( !aup || !bup ) {\n\t\t\treturn a === doc ? -1 :\n\t\t\t\tb === doc ? 1 :\n\t\t\t\taup ? -1 :\n\t\t\t\tbup ? 1 :\n\t\t\t\t0;\n\n\t\t// If the nodes are siblings, we can do a quick check\n\t\t} else if ( aup === bup ) {\n\t\t\treturn siblingCheck( a, b );\n\t\t}\n\n\t\t// Otherwise we need full lists of their ancestors for comparison\n\t\tcur = a;\n\t\twhile ( (cur = cur.parentNode) ) {\n\t\t\tap.unshift( cur );\n\t\t}\n\t\tcur = b;\n\t\twhile ( (cur = cur.parentNode) ) {\n\t\t\tbp.unshift( cur );\n\t\t}\n\n\t\t// Walk down the tree looking for a discrepancy\n\t\twhile ( ap[i] === bp[i] ) {\n\t\t\ti++;\n\t\t}\n\n\t\treturn i ?\n\t\t\t// Do a sibling check if the nodes have a common ancestor\n\t\t\tsiblingCheck( ap[i], bp[i] ) :\n\n\t\t\t// Otherwise nodes in our document sort first\n\t\t\tap[i] === preferredDoc ? -1 :\n\t\t\tbp[i] === preferredDoc ? 1 :\n\t\t\t0;\n\t};\n\n\t// Always assume the presence of duplicates if sort doesn't\n\t// pass them to our comparison function (as in Google Chrome).\n\thasDuplicate = false;\n\t[0, 0].sort( sortOrder );\n\tsupport.detectDuplicates = hasDuplicate;\n\n\treturn document;\n};\n\nSizzle.matches = function( expr, elements ) {\n\treturn Sizzle( expr, null, null, elements );\n};\n\nSizzle.matchesSelector = function( elem, expr ) {\n\t// Set document vars if needed\n\tif ( ( elem.ownerDocument || elem ) !== document ) {\n\t\tsetDocument( elem );\n\t}\n\n\t// Make sure that attribute selectors are quoted\n\texpr = expr.replace( rattributeQuotes, \"='$1']\" );\n\n\t// rbuggyQSA always contains :focus, so no need for an existence check\n\tif ( support.matchesSelector && !documentIsXML && (!rbuggyMatches || !rbuggyMatches.test(expr)) && !rbuggyQSA.test(expr) ) {\n\t\ttry {\n\t\t\tvar ret = matches.call( elem, expr );\n\n\t\t\t// IE 9's matchesSelector returns false on disconnected nodes\n\t\t\tif ( ret || support.disconnectedMatch ||\n\t\t\t\t\t// As well, disconnected nodes are said to be in a document\n\t\t\t\t\t// fragment in IE 9\n\t\t\t\t\telem.document && elem.document.nodeType !== 11 ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\t\t} catch(e) {}\n\t}\n\n\treturn Sizzle( expr, document, null, [elem] ).length > 0;\n};\n\nSizzle.contains = function( context, elem ) {\n\t// Set document vars if needed\n\tif ( ( context.ownerDocument || context ) !== document ) {\n\t\tsetDocument( context );\n\t}\n\treturn contains( context, elem );\n};\n\nSizzle.attr = function( elem, name ) {\n\tvar val;\n\n\t// Set document vars if needed\n\tif ( ( elem.ownerDocument || elem ) !== document ) {\n\t\tsetDocument( elem );\n\t}\n\n\tif ( !documentIsXML ) {\n\t\tname = name.toLowerCase();\n\t}\n\tif ( (val = Expr.attrHandle[ name ]) ) {\n\t\treturn val( elem );\n\t}\n\tif ( documentIsXML || support.attributes ) {\n\t\treturn elem.getAttribute( name );\n\t}\n\treturn ( (val = elem.getAttributeNode( name )) || elem.getAttribute( name ) ) && elem[ name ] === true ?\n\t\tname :\n\t\tval && val.specified ? val.value : null;\n};\n\nSizzle.error = function( msg ) {\n\tthrow new Error( \"Syntax error, unrecognized expression: \" + msg );\n};\n\n// Document sorting and removing duplicates\nSizzle.uniqueSort = function( results ) {\n\tvar elem,\n\t\tduplicates = [],\n\t\ti = 1,\n\t\tj = 0;\n\n\t// Unless we *know* we can detect duplicates, assume their presence\n\thasDuplicate = !support.detectDuplicates;\n\tresults.sort( sortOrder );\n\n\tif ( hasDuplicate ) {\n\t\tfor ( ; (elem = results[i]); i++ ) {\n\t\t\tif ( elem === results[ i - 1 ] ) {\n\t\t\t\tj = duplicates.push( i );\n\t\t\t}\n\t\t}\n\t\twhile ( j-- ) {\n\t\t\tresults.splice( duplicates[ j ], 1 );\n\t\t}\n\t}\n\n\treturn results;\n};\n\nfunction siblingCheck( a, b ) {\n\tvar cur = b && a,\n\t\tdiff = cur && ( ~b.sourceIndex || MAX_NEGATIVE ) - ( ~a.sourceIndex || MAX_NEGATIVE );\n\n\t// Use IE sourceIndex if available on both nodes\n\tif ( diff ) {\n\t\treturn diff;\n\t}\n\n\t// Check if b follows a\n\tif ( cur ) {\n\t\twhile ( (cur = cur.nextSibling) ) {\n\t\t\tif ( cur === b ) {\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn a ? 1 : -1;\n}\n\n// Returns a function to use in pseudos for input types\nfunction createInputPseudo( type ) {\n\treturn function( elem ) {\n\t\tvar name = elem.nodeName.toLowerCase();\n\t\treturn name === \"input\" && elem.type === type;\n\t};\n}\n\n// Returns a function to use in pseudos for buttons\nfunction createButtonPseudo( type ) {\n\treturn function( elem ) {\n\t\tvar name = elem.nodeName.toLowerCase();\n\t\treturn (name === \"input\" || name === \"button\") && elem.type === type;\n\t};\n}\n\n// Returns a function to use in pseudos for positionals\nfunction createPositionalPseudo( fn ) {\n\treturn markFunction(function( argument ) {\n\t\targument = +argument;\n\t\treturn markFunction(function( seed, matches ) {\n\t\t\tvar j,\n\t\t\t\tmatchIndexes = fn( [], seed.length, argument ),\n\t\t\t\ti = matchIndexes.length;\n\n\t\t\t// Match elements found at the specified indexes\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( seed[ (j = matchIndexes[i]) ] ) {\n\t\t\t\t\tseed[j] = !(matches[j] = seed[j]);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t});\n}\n\n/**\n * Utility function for retrieving the text value of an array of DOM nodes\n * @param {Array|Element} elem\n */\ngetText = Sizzle.getText = function( elem ) {\n\tvar node,\n\t\tret = \"\",\n\t\ti = 0,\n\t\tnodeType = elem.nodeType;\n\n\tif ( !nodeType ) {\n\t\t// If no nodeType, this is expected to be an array\n\t\tfor ( ; (node = elem[i]); i++ ) {\n\t\t\t// Do not traverse comment nodes\n\t\t\tret += getText( node );\n\t\t}\n\t} else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {\n\t\t// Use textContent for elements\n\t\t// innerText usage removed for consistency of new lines (see #11153)\n\t\tif ( typeof elem.textContent === \"string\" ) {\n\t\t\treturn elem.textContent;\n\t\t} else {\n\t\t\t// Traverse its children\n\t\t\tfor ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {\n\t\t\t\tret += getText( elem );\n\t\t\t}\n\t\t}\n\t} else if ( nodeType === 3 || nodeType === 4 ) {\n\t\treturn elem.nodeValue;\n\t}\n\t// Do not include comment or processing instruction nodes\n\n\treturn ret;\n};\n\nExpr = Sizzle.selectors = {\n\n\t// Can be adjusted by the user\n\tcacheLength: 50,\n\n\tcreatePseudo: markFunction,\n\n\tmatch: matchExpr,\n\n\tfind: {},\n\n\trelative: {\n\t\t\">\": { dir: \"parentNode\", first: true },\n\t\t\" \": { dir: \"parentNode\" },\n\t\t\"+\": { dir: \"previousSibling\", first: true },\n\t\t\"~\": { dir: \"previousSibling\" }\n\t},\n\n\tpreFilter: {\n\t\t\"ATTR\": function( match ) {\n\t\t\tmatch[1] = match[1].replace( runescape, funescape );\n\n\t\t\t// Move the given value to match[3] whether quoted or unquoted\n\t\t\tmatch[3] = ( match[4] || match[5] || \"\" ).replace( runescape, funescape );\n\n\t\t\tif ( match[2] === \"~=\" ) {\n\t\t\t\tmatch[3] = \" \" + match[3] + \" \";\n\t\t\t}\n\n\t\t\treturn match.slice( 0, 4 );\n\t\t},\n\n\t\t\"CHILD\": function( match ) {\n\t\t\t/* matches from matchExpr[\"CHILD\"]\n\t\t\t\t1 type (only|nth|...)\n\t\t\t\t2 what (child|of-type)\n\t\t\t\t3 argument (even|odd|\\d*|\\d*n([+-]\\d+)?|...)\n\t\t\t\t4 xn-component of xn+y argument ([+-]?\\d*n|)\n\t\t\t\t5 sign of xn-component\n\t\t\t\t6 x of xn-component\n\t\t\t\t7 sign of y-component\n\t\t\t\t8 y of y-component\n\t\t\t*/\n\t\t\tmatch[1] = match[1].toLowerCase();\n\n\t\t\tif ( match[1].slice( 0, 3 ) === \"nth\" ) {\n\t\t\t\t// nth-* requires argument\n\t\t\t\tif ( !match[3] ) {\n\t\t\t\t\tSizzle.error( match[0] );\n\t\t\t\t}\n\n\t\t\t\t// numeric x and y parameters for Expr.filter.CHILD\n\t\t\t\t// remember that false/true cast respectively to 0/1\n\t\t\t\tmatch[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === \"even\" || match[3] === \"odd\" ) );\n\t\t\t\tmatch[5] = +( ( match[7] + match[8] ) || match[3] === \"odd\" );\n\n\t\t\t// other types prohibit arguments\n\t\t\t} else if ( match[3] ) {\n\t\t\t\tSizzle.error( match[0] );\n\t\t\t}\n\n\t\t\treturn match;\n\t\t},\n\n\t\t\"PSEUDO\": function( match ) {\n\t\t\tvar excess,\n\t\t\t\tunquoted = !match[5] && match[2];\n\n\t\t\tif ( matchExpr[\"CHILD\"].test( match[0] ) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\t// Accept quoted arguments as-is\n\t\t\tif ( match[4] ) {\n\t\t\t\tmatch[2] = match[4];\n\n\t\t\t// Strip excess characters from unquoted arguments\n\t\t\t} else if ( unquoted && rpseudo.test( unquoted ) &&\n\t\t\t\t// Get excess from tokenize (recursively)\n\t\t\t\t(excess = tokenize( unquoted, true )) &&\n\t\t\t\t// advance to the next closing parenthesis\n\t\t\t\t(excess = unquoted.indexOf( \")\", unquoted.length - excess ) - unquoted.length) ) {\n\n\t\t\t\t// excess is a negative index\n\t\t\t\tmatch[0] = match[0].slice( 0, excess );\n\t\t\t\tmatch[2] = unquoted.slice( 0, excess );\n\t\t\t}\n\n\t\t\t// Return only captures needed by the pseudo filter method (type and argument)\n\t\t\treturn match.slice( 0, 3 );\n\t\t}\n\t},\n\n\tfilter: {\n\n\t\t\"TAG\": function( nodeName ) {\n\t\t\tif ( nodeName === \"*\" ) {\n\t\t\t\treturn function() { return true; };\n\t\t\t}\n\n\t\t\tnodeName = nodeName.replace( runescape, funescape ).toLowerCase();\n\t\t\treturn function( elem ) {\n\t\t\t\treturn elem.nodeName && elem.nodeName.toLowerCase() === nodeName;\n\t\t\t};\n\t\t},\n\n\t\t\"CLASS\": function( className ) {\n\t\t\tvar pattern = classCache[ className + \" \" ];\n\n\t\t\treturn pattern ||\n\t\t\t\t(pattern = new RegExp( \"(^|\" + whitespace + \")\" + className + \"(\" + whitespace + \"|$)\" )) &&\n\t\t\t\tclassCache( className, function( elem ) {\n\t\t\t\t\treturn pattern.test( elem.className || (typeof elem.getAttribute !== strundefined && elem.getAttribute(\"class\")) || \"\" );\n\t\t\t\t});\n\t\t},\n\n\t\t\"ATTR\": function( name, operator, check ) {\n\t\t\treturn function( elem ) {\n\t\t\t\tvar result = Sizzle.attr( elem, name );\n\n\t\t\t\tif ( result == null ) {\n\t\t\t\t\treturn operator === \"!=\";\n\t\t\t\t}\n\t\t\t\tif ( !operator ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tresult += \"\";\n\n\t\t\t\treturn operator === \"=\" ? result === check :\n\t\t\t\t\toperator === \"!=\" ? result !== check :\n\t\t\t\t\toperator === \"^=\" ? check && result.indexOf( check ) === 0 :\n\t\t\t\t\toperator === \"*=\" ? check && result.indexOf( check ) > -1 :\n\t\t\t\t\toperator === \"$=\" ? check && result.slice( -check.length ) === check :\n\t\t\t\t\toperator === \"~=\" ? ( \" \" + result + \" \" ).indexOf( check ) > -1 :\n\t\t\t\t\toperator === \"|=\" ? result === check || result.slice( 0, check.length + 1 ) === check + \"-\" :\n\t\t\t\t\tfalse;\n\t\t\t};\n\t\t},\n\n\t\t\"CHILD\": function( type, what, argument, first, last ) {\n\t\t\tvar simple = type.slice( 0, 3 ) !== \"nth\",\n\t\t\t\tforward = type.slice( -4 ) !== \"last\",\n\t\t\t\tofType = what === \"of-type\";\n\n\t\t\treturn first === 1 && last === 0 ?\n\n\t\t\t\t// Shortcut for :nth-*(n)\n\t\t\t\tfunction( elem ) {\n\t\t\t\t\treturn !!elem.parentNode;\n\t\t\t\t} :\n\n\t\t\t\tfunction( elem, context, xml ) {\n\t\t\t\t\tvar cache, outerCache, node, diff, nodeIndex, start,\n\t\t\t\t\t\tdir = simple !== forward ? \"nextSibling\" : \"previousSibling\",\n\t\t\t\t\t\tparent = elem.parentNode,\n\t\t\t\t\t\tname = ofType && elem.nodeName.toLowerCase(),\n\t\t\t\t\t\tuseCache = !xml && !ofType;\n\n\t\t\t\t\tif ( parent ) {\n\n\t\t\t\t\t\t// :(first|last|only)-(child|of-type)\n\t\t\t\t\t\tif ( simple ) {\n\t\t\t\t\t\t\twhile ( dir ) {\n\t\t\t\t\t\t\t\tnode = elem;\n\t\t\t\t\t\t\t\twhile ( (node = node[ dir ]) ) {\n\t\t\t\t\t\t\t\t\tif ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {\n\t\t\t\t\t\t\t\t\t\treturn false;\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\t// Reverse direction for :only-* (if we haven't yet done so)\n\t\t\t\t\t\t\t\tstart = dir = type === \"only\" && !start && \"nextSibling\";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tstart = [ forward ? parent.firstChild : parent.lastChild ];\n\n\t\t\t\t\t\t// non-xml :nth-child(...) stores cache data on `parent`\n\t\t\t\t\t\tif ( forward && useCache ) {\n\t\t\t\t\t\t\t// Seek `elem` from a previously-cached index\n\t\t\t\t\t\t\touterCache = parent[ expando ] || (parent[ expando ] = {});\n\t\t\t\t\t\t\tcache = outerCache[ type ] || [];\n\t\t\t\t\t\t\tnodeIndex = cache[0] === dirruns && cache[1];\n\t\t\t\t\t\t\tdiff = cache[0] === dirruns && cache[2];\n\t\t\t\t\t\t\tnode = nodeIndex && parent.childNodes[ nodeIndex ];\n\n\t\t\t\t\t\t\twhile ( (node = ++nodeIndex && node && node[ dir ] ||\n\n\t\t\t\t\t\t\t\t// Fallback to seeking `elem` from the start\n\t\t\t\t\t\t\t\t(diff = nodeIndex = 0) || start.pop()) ) {\n\n\t\t\t\t\t\t\t\t// When found, cache indexes on `parent` and break\n\t\t\t\t\t\t\t\tif ( node.nodeType === 1 && ++diff && node === elem ) {\n\t\t\t\t\t\t\t\t\touterCache[ type ] = [ dirruns, nodeIndex, diff ];\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Use previously-cached element index if available\n\t\t\t\t\t\t} else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {\n\t\t\t\t\t\t\tdiff = cache[1];\n\n\t\t\t\t\t\t// xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Use the same loop as above to seek `elem` from the start\n\t\t\t\t\t\t\twhile ( (node = ++nodeIndex && node && node[ dir ] ||\n\t\t\t\t\t\t\t\t(diff = nodeIndex = 0) || start.pop()) ) {\n\n\t\t\t\t\t\t\t\tif ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {\n\t\t\t\t\t\t\t\t\t// Cache the index of each encountered element\n\t\t\t\t\t\t\t\t\tif ( useCache ) {\n\t\t\t\t\t\t\t\t\t\t(node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tif ( node === elem ) {\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Incorporate the offset, then check against cycle size\n\t\t\t\t\t\tdiff -= last;\n\t\t\t\t\t\treturn diff === first || ( diff % first === 0 && diff / first >= 0 );\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t},\n\n\t\t\"PSEUDO\": function( pseudo, argument ) {\n\t\t\t// pseudo-class names are case-insensitive\n\t\t\t// http://www.w3.org/TR/selectors/#pseudo-classes\n\t\t\t// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters\n\t\t\t// Remember that setFilters inherits from pseudos\n\t\t\tvar args,\n\t\t\t\tfn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||\n\t\t\t\t\tSizzle.error( \"unsupported pseudo: \" + pseudo );\n\n\t\t\t// The user may use createPseudo to indicate that\n\t\t\t// arguments are needed to create the filter function\n\t\t\t// just as Sizzle does\n\t\t\tif ( fn[ expando ] ) {\n\t\t\t\treturn fn( argument );\n\t\t\t}\n\n\t\t\t// But maintain support for old signatures\n\t\t\tif ( fn.length > 1 ) {\n\t\t\t\targs = [ pseudo, pseudo, \"\", argument ];\n\t\t\t\treturn Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?\n\t\t\t\t\tmarkFunction(function( seed, matches ) {\n\t\t\t\t\t\tvar idx,\n\t\t\t\t\t\t\tmatched = fn( seed, argument ),\n\t\t\t\t\t\t\ti = matched.length;\n\t\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\t\tidx = indexOf.call( seed, matched[i] );\n\t\t\t\t\t\t\tseed[ idx ] = !( matches[ idx ] = matched[i] );\n\t\t\t\t\t\t}\n\t\t\t\t\t}) :\n\t\t\t\t\tfunction( elem ) {\n\t\t\t\t\t\treturn fn( elem, 0, args );\n\t\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn fn;\n\t\t}\n\t},\n\n\tpseudos: {\n\t\t// Potentially complex pseudos\n\t\t\"not\": markFunction(function( selector ) {\n\t\t\t// Trim the selector passed to compile\n\t\t\t// to avoid treating leading and trailing\n\t\t\t// spaces as combinators\n\t\t\tvar input = [],\n\t\t\t\tresults = [],\n\t\t\t\tmatcher = compile( selector.replace( rtrim, \"$1\" ) );\n\n\t\t\treturn matcher[ expando ] ?\n\t\t\t\tmarkFunction(function( seed, matches, context, xml ) {\n\t\t\t\t\tvar elem,\n\t\t\t\t\t\tunmatched = matcher( seed, null, xml, [] ),\n\t\t\t\t\t\ti = seed.length;\n\n\t\t\t\t\t// Match elements unmatched by `matcher`\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tif ( (elem = unmatched[i]) ) {\n\t\t\t\t\t\t\tseed[i] = !(matches[i] = elem);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}) :\n\t\t\t\tfunction( elem, context, xml ) {\n\t\t\t\t\tinput[0] = elem;\n\t\t\t\t\tmatcher( input, null, xml, results );\n\t\t\t\t\treturn !results.pop();\n\t\t\t\t};\n\t\t}),\n\n\t\t\"has\": markFunction(function( selector ) {\n\t\t\treturn function( elem ) {\n\t\t\t\treturn Sizzle( selector, elem ).length > 0;\n\t\t\t};\n\t\t}),\n\n\t\t\"contains\": markFunction(function( text ) {\n\t\t\treturn function( elem ) {\n\t\t\t\treturn ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;\n\t\t\t};\n\t\t}),\n\n\t\t// \"Whether an element is represented by a :lang() selector\n\t\t// is based solely on the element's language value\n\t\t// being equal to the identifier C,\n\t\t// or beginning with the identifier C immediately followed by \"-\".\n\t\t// The matching of C against the element's language value is performed case-insensitively.\n\t\t// The identifier C does not have to be a valid language name.\"\n\t\t// http://www.w3.org/TR/selectors/#lang-pseudo\n\t\t\"lang\": markFunction( function( lang ) {\n\t\t\t// lang value must be a valid identifider\n\t\t\tif ( !ridentifier.test(lang || \"\") ) {\n\t\t\t\tSizzle.error( \"unsupported lang: \" + lang );\n\t\t\t}\n\t\t\tlang = lang.replace( runescape, funescape ).toLowerCase();\n\t\t\treturn function( elem ) {\n\t\t\t\tvar elemLang;\n\t\t\t\tdo {\n\t\t\t\t\tif ( (elemLang = documentIsXML ?\n\t\t\t\t\t\telem.getAttribute(\"xml:lang\") || elem.getAttribute(\"lang\") :\n\t\t\t\t\t\telem.lang) ) {\n\n\t\t\t\t\t\telemLang = elemLang.toLowerCase();\n\t\t\t\t\t\treturn elemLang === lang || elemLang.indexOf( lang + \"-\" ) === 0;\n\t\t\t\t\t}\n\t\t\t\t} while ( (elem = elem.parentNode) && elem.nodeType === 1 );\n\t\t\t\treturn false;\n\t\t\t};\n\t\t}),\n\n\t\t// Miscellaneous\n\t\t\"target\": function( elem ) {\n\t\t\tvar hash = window.location && window.location.hash;\n\t\t\treturn hash && hash.slice( 1 ) === elem.id;\n\t\t},\n\n\t\t\"root\": function( elem ) {\n\t\t\treturn elem === docElem;\n\t\t},\n\n\t\t\"focus\": function( elem ) {\n\t\t\treturn elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);\n\t\t},\n\n\t\t// Boolean properties\n\t\t\"enabled\": function( elem ) {\n\t\t\treturn elem.disabled === false;\n\t\t},\n\n\t\t\"disabled\": function( elem ) {\n\t\t\treturn elem.disabled === true;\n\t\t},\n\n\t\t\"checked\": function( elem ) {\n\t\t\t// In CSS3, :checked should return both checked and selected elements\n\t\t\t// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked\n\t\t\tvar nodeName = elem.nodeName.toLowerCase();\n\t\t\treturn (nodeName === \"input\" && !!elem.checked) || (nodeName === \"option\" && !!elem.selected);\n\t\t},\n\n\t\t\"selected\": function( elem ) {\n\t\t\t// Accessing this property makes selected-by-default\n\t\t\t// options in Safari work properly\n\t\t\tif ( elem.parentNode ) {\n\t\t\t\telem.parentNode.selectedIndex;\n\t\t\t}\n\n\t\t\treturn elem.selected === true;\n\t\t},\n\n\t\t// Contents\n\t\t\"empty\": function( elem ) {\n\t\t\t// http://www.w3.org/TR/selectors/#empty-pseudo\n\t\t\t// :empty is only affected by element nodes and content nodes(including text(3), cdata(4)),\n\t\t\t//   not comment, processing instructions, or others\n\t\t\t// Thanks to Diego Perini for the nodeName shortcut\n\t\t\t//   Greater than \"@\" means alpha characters (specifically not starting with \"#\" or \"?\")\n\t\t\tfor ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {\n\t\t\t\tif ( elem.nodeName > \"@\" || elem.nodeType === 3 || elem.nodeType === 4 ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t},\n\n\t\t\"parent\": function( elem ) {\n\t\t\treturn !Expr.pseudos[\"empty\"]( elem );\n\t\t},\n\n\t\t// Element/input types\n\t\t\"header\": function( elem ) {\n\t\t\treturn rheader.test( elem.nodeName );\n\t\t},\n\n\t\t\"input\": function( elem ) {\n\t\t\treturn rinputs.test( elem.nodeName );\n\t\t},\n\n\t\t\"button\": function( elem ) {\n\t\t\tvar name = elem.nodeName.toLowerCase();\n\t\t\treturn name === \"input\" && elem.type === \"button\" || name === \"button\";\n\t\t},\n\n\t\t\"text\": function( elem ) {\n\t\t\tvar attr;\n\t\t\t// IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)\n\t\t\t// use getAttribute instead to test this case\n\t\t\treturn elem.nodeName.toLowerCase() === \"input\" &&\n\t\t\t\telem.type === \"text\" &&\n\t\t\t\t( (attr = elem.getAttribute(\"type\")) == null || attr.toLowerCase() === elem.type );\n\t\t},\n\n\t\t// Position-in-collection\n\t\t\"first\": createPositionalPseudo(function() {\n\t\t\treturn [ 0 ];\n\t\t}),\n\n\t\t\"last\": createPositionalPseudo(function( matchIndexes, length ) {\n\t\t\treturn [ length - 1 ];\n\t\t}),\n\n\t\t\"eq\": createPositionalPseudo(function( matchIndexes, length, argument ) {\n\t\t\treturn [ argument < 0 ? argument + length : argument ];\n\t\t}),\n\n\t\t\"even\": createPositionalPseudo(function( matchIndexes, length ) {\n\t\t\tvar i = 0;\n\t\t\tfor ( ; i < length; i += 2 ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t}),\n\n\t\t\"odd\": createPositionalPseudo(function( matchIndexes, length ) {\n\t\t\tvar i = 1;\n\t\t\tfor ( ; i < length; i += 2 ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t}),\n\n\t\t\"lt\": createPositionalPseudo(function( matchIndexes, length, argument ) {\n\t\t\tvar i = argument < 0 ? argument + length : argument;\n\t\t\tfor ( ; --i >= 0; ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t}),\n\n\t\t\"gt\": createPositionalPseudo(function( matchIndexes, length, argument ) {\n\t\t\tvar i = argument < 0 ? argument + length : argument;\n\t\t\tfor ( ; ++i < length; ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t})\n\t}\n};\n\n// Add button/input type pseudos\nfor ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {\n\tExpr.pseudos[ i ] = createInputPseudo( i );\n}\nfor ( i in { submit: true, reset: true } ) {\n\tExpr.pseudos[ i ] = createButtonPseudo( i );\n}\n\nfunction tokenize( selector, parseOnly ) {\n\tvar matched, match, tokens, type,\n\t\tsoFar, groups, preFilters,\n\t\tcached = tokenCache[ selector + \" \" ];\n\n\tif ( cached ) {\n\t\treturn parseOnly ? 0 : cached.slice( 0 );\n\t}\n\n\tsoFar = selector;\n\tgroups = [];\n\tpreFilters = Expr.preFilter;\n\n\twhile ( soFar ) {\n\n\t\t// Comma and first run\n\t\tif ( !matched || (match = rcomma.exec( soFar )) ) {\n\t\t\tif ( match ) {\n\t\t\t\t// Don't consume trailing commas as valid\n\t\t\t\tsoFar = soFar.slice( match[0].length ) || soFar;\n\t\t\t}\n\t\t\tgroups.push( tokens = [] );\n\t\t}\n\n\t\tmatched = false;\n\n\t\t// Combinators\n\t\tif ( (match = rcombinators.exec( soFar )) ) {\n\t\t\tmatched = match.shift();\n\t\t\ttokens.push( {\n\t\t\t\tvalue: matched,\n\t\t\t\t// Cast descendant combinators to space\n\t\t\t\ttype: match[0].replace( rtrim, \" \" )\n\t\t\t} );\n\t\t\tsoFar = soFar.slice( matched.length );\n\t\t}\n\n\t\t// Filters\n\t\tfor ( type in Expr.filter ) {\n\t\t\tif ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||\n\t\t\t\t(match = preFilters[ type ]( match ))) ) {\n\t\t\t\tmatched = match.shift();\n\t\t\t\ttokens.push( {\n\t\t\t\t\tvalue: matched,\n\t\t\t\t\ttype: type,\n\t\t\t\t\tmatches: match\n\t\t\t\t} );\n\t\t\t\tsoFar = soFar.slice( matched.length );\n\t\t\t}\n\t\t}\n\n\t\tif ( !matched ) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Return the length of the invalid excess\n\t// if we're just parsing\n\t// Otherwise, throw an error or return tokens\n\treturn parseOnly ?\n\t\tsoFar.length :\n\t\tsoFar ?\n\t\t\tSizzle.error( selector ) :\n\t\t\t// Cache the tokens\n\t\t\ttokenCache( selector, groups ).slice( 0 );\n}\n\nfunction toSelector( tokens ) {\n\tvar i = 0,\n\t\tlen = tokens.length,\n\t\tselector = \"\";\n\tfor ( ; i < len; i++ ) {\n\t\tselector += tokens[i].value;\n\t}\n\treturn selector;\n}\n\nfunction addCombinator( matcher, combinator, base ) {\n\tvar dir = combinator.dir,\n\t\tcheckNonElements = base && dir === \"parentNode\",\n\t\tdoneName = done++;\n\n\treturn combinator.first ?\n\t\t// Check against closest ancestor/preceding element\n\t\tfunction( elem, context, xml ) {\n\t\t\twhile ( (elem = elem[ dir ]) ) {\n\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\treturn matcher( elem, context, xml );\n\t\t\t\t}\n\t\t\t}\n\t\t} :\n\n\t\t// Check against all ancestor/preceding elements\n\t\tfunction( elem, context, xml ) {\n\t\t\tvar data, cache, outerCache,\n\t\t\t\tdirkey = dirruns + \" \" + doneName;\n\n\t\t\t// We can't set arbitrary data on XML nodes, so they don't benefit from dir caching\n\t\t\tif ( xml ) {\n\t\t\t\twhile ( (elem = elem[ dir ]) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\t\tif ( matcher( elem, context, xml ) ) {\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\twhile ( (elem = elem[ dir ]) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\t\touterCache = elem[ expando ] || (elem[ expando ] = {});\n\t\t\t\t\t\tif ( (cache = outerCache[ dir ]) && cache[0] === dirkey ) {\n\t\t\t\t\t\t\tif ( (data = cache[1]) === true || data === cachedruns ) {\n\t\t\t\t\t\t\t\treturn data === true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tcache = outerCache[ dir ] = [ dirkey ];\n\t\t\t\t\t\t\tcache[1] = matcher( elem, context, xml ) || cachedruns;\n\t\t\t\t\t\t\tif ( cache[1] === true ) {\n\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n}\n\nfunction elementMatcher( matchers ) {\n\treturn matchers.length > 1 ?\n\t\tfunction( elem, context, xml ) {\n\t\t\tvar i = matchers.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( !matchers[i]( elem, context, xml ) ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t} :\n\t\tmatchers[0];\n}\n\nfunction condense( unmatched, map, filter, context, xml ) {\n\tvar elem,\n\t\tnewUnmatched = [],\n\t\ti = 0,\n\t\tlen = unmatched.length,\n\t\tmapped = map != null;\n\n\tfor ( ; i < len; i++ ) {\n\t\tif ( (elem = unmatched[i]) ) {\n\t\t\tif ( !filter || filter( elem, context, xml ) ) {\n\t\t\t\tnewUnmatched.push( elem );\n\t\t\t\tif ( mapped ) {\n\t\t\t\t\tmap.push( i );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn newUnmatched;\n}\n\nfunction setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {\n\tif ( postFilter && !postFilter[ expando ] ) {\n\t\tpostFilter = setMatcher( postFilter );\n\t}\n\tif ( postFinder && !postFinder[ expando ] ) {\n\t\tpostFinder = setMatcher( postFinder, postSelector );\n\t}\n\treturn markFunction(function( seed, results, context, xml ) {\n\t\tvar temp, i, elem,\n\t\t\tpreMap = [],\n\t\t\tpostMap = [],\n\t\t\tpreexisting = results.length,\n\n\t\t\t// Get initial elements from seed or context\n\t\t\telems = seed || multipleContexts( selector || \"*\", context.nodeType ? [ context ] : context, [] ),\n\n\t\t\t// Prefilter to get matcher input, preserving a map for seed-results synchronization\n\t\t\tmatcherIn = preFilter && ( seed || !selector ) ?\n\t\t\t\tcondense( elems, preMap, preFilter, context, xml ) :\n\t\t\t\telems,\n\n\t\t\tmatcherOut = matcher ?\n\t\t\t\t// If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,\n\t\t\t\tpostFinder || ( seed ? preFilter : preexisting || postFilter ) ?\n\n\t\t\t\t\t// ...intermediate processing is necessary\n\t\t\t\t\t[] :\n\n\t\t\t\t\t// ...otherwise use results directly\n\t\t\t\t\tresults :\n\t\t\t\tmatcherIn;\n\n\t\t// Find primary matches\n\t\tif ( matcher ) {\n\t\t\tmatcher( matcherIn, matcherOut, context, xml );\n\t\t}\n\n\t\t// Apply postFilter\n\t\tif ( postFilter ) {\n\t\t\ttemp = condense( matcherOut, postMap );\n\t\t\tpostFilter( temp, [], context, xml );\n\n\t\t\t// Un-match failing elements by moving them back to matcherIn\n\t\t\ti = temp.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( (elem = temp[i]) ) {\n\t\t\t\t\tmatcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif ( seed ) {\n\t\t\tif ( postFinder || preFilter ) {\n\t\t\t\tif ( postFinder ) {\n\t\t\t\t\t// Get the final matcherOut by condensing this intermediate into postFinder contexts\n\t\t\t\t\ttemp = [];\n\t\t\t\t\ti = matcherOut.length;\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tif ( (elem = matcherOut[i]) ) {\n\t\t\t\t\t\t\t// Restore matcherIn since elem is not yet a final match\n\t\t\t\t\t\t\ttemp.push( (matcherIn[i] = elem) );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tpostFinder( null, (matcherOut = []), temp, xml );\n\t\t\t\t}\n\n\t\t\t\t// Move matched elements from seed to results to keep them synchronized\n\t\t\t\ti = matcherOut.length;\n\t\t\t\twhile ( i-- ) {\n\t\t\t\t\tif ( (elem = matcherOut[i]) &&\n\t\t\t\t\t\t(temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {\n\n\t\t\t\t\t\tseed[temp] = !(results[temp] = elem);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Add elements to results, through postFinder if defined\n\t\t} else {\n\t\t\tmatcherOut = condense(\n\t\t\t\tmatcherOut === results ?\n\t\t\t\t\tmatcherOut.splice( preexisting, matcherOut.length ) :\n\t\t\t\t\tmatcherOut\n\t\t\t);\n\t\t\tif ( postFinder ) {\n\t\t\t\tpostFinder( null, results, matcherOut, xml );\n\t\t\t} else {\n\t\t\t\tpush.apply( results, matcherOut );\n\t\t\t}\n\t\t}\n\t});\n}\n\nfunction matcherFromTokens( tokens ) {\n\tvar checkContext, matcher, j,\n\t\tlen = tokens.length,\n\t\tleadingRelative = Expr.relative[ tokens[0].type ],\n\t\timplicitRelative = leadingRelative || Expr.relative[\" \"],\n\t\ti = leadingRelative ? 1 : 0,\n\n\t\t// The foundational matcher ensures that elements are reachable from top-level context(s)\n\t\tmatchContext = addCombinator( function( elem ) {\n\t\t\treturn elem === checkContext;\n\t\t}, implicitRelative, true ),\n\t\tmatchAnyContext = addCombinator( function( elem ) {\n\t\t\treturn indexOf.call( checkContext, elem ) > -1;\n\t\t}, implicitRelative, true ),\n\t\tmatchers = [ function( elem, context, xml ) {\n\t\t\treturn ( !leadingRelative && ( xml || context !== outermostContext ) ) || (\n\t\t\t\t(checkContext = context).nodeType ?\n\t\t\t\t\tmatchContext( elem, context, xml ) :\n\t\t\t\t\tmatchAnyContext( elem, context, xml ) );\n\t\t} ];\n\n\tfor ( ; i < len; i++ ) {\n\t\tif ( (matcher = Expr.relative[ tokens[i].type ]) ) {\n\t\t\tmatchers = [ addCombinator(elementMatcher( matchers ), matcher) ];\n\t\t} else {\n\t\t\tmatcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );\n\n\t\t\t// Return special upon seeing a positional matcher\n\t\t\tif ( matcher[ expando ] ) {\n\t\t\t\t// Find the next relative operator (if any) for proper handling\n\t\t\t\tj = ++i;\n\t\t\t\tfor ( ; j < len; j++ ) {\n\t\t\t\t\tif ( Expr.relative[ tokens[j].type ] ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn setMatcher(\n\t\t\t\t\ti > 1 && elementMatcher( matchers ),\n\t\t\t\t\ti > 1 && toSelector( tokens.slice( 0, i - 1 ) ).replace( rtrim, \"$1\" ),\n\t\t\t\t\tmatcher,\n\t\t\t\t\ti < j && matcherFromTokens( tokens.slice( i, j ) ),\n\t\t\t\t\tj < len && matcherFromTokens( (tokens = tokens.slice( j )) ),\n\t\t\t\t\tj < len && toSelector( tokens )\n\t\t\t\t);\n\t\t\t}\n\t\t\tmatchers.push( matcher );\n\t\t}\n\t}\n\n\treturn elementMatcher( matchers );\n}\n\nfunction matcherFromGroupMatchers( elementMatchers, setMatchers ) {\n\t// A counter to specify which element is currently being matched\n\tvar matcherCachedRuns = 0,\n\t\tbySet = setMatchers.length > 0,\n\t\tbyElement = elementMatchers.length > 0,\n\t\tsuperMatcher = function( seed, context, xml, results, expandContext ) {\n\t\t\tvar elem, j, matcher,\n\t\t\t\tsetMatched = [],\n\t\t\t\tmatchedCount = 0,\n\t\t\t\ti = \"0\",\n\t\t\t\tunmatched = seed && [],\n\t\t\t\toutermost = expandContext != null,\n\t\t\t\tcontextBackup = outermostContext,\n\t\t\t\t// We must always have either seed elements or context\n\t\t\t\telems = seed || byElement && Expr.find[\"TAG\"]( \"*\", expandContext && context.parentNode || context ),\n\t\t\t\t// Use integer dirruns iff this is the outermost matcher\n\t\t\t\tdirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1);\n\n\t\t\tif ( outermost ) {\n\t\t\t\toutermostContext = context !== document && context;\n\t\t\t\tcachedruns = matcherCachedRuns;\n\t\t\t}\n\n\t\t\t// Add elements passing elementMatchers directly to results\n\t\t\t// Keep `i` a string if there are no elements so `matchedCount` will be \"00\" below\n\t\t\tfor ( ; (elem = elems[i]) != null; i++ ) {\n\t\t\t\tif ( byElement && elem ) {\n\t\t\t\t\tj = 0;\n\t\t\t\t\twhile ( (matcher = elementMatchers[j++]) ) {\n\t\t\t\t\t\tif ( matcher( elem, context, xml ) ) {\n\t\t\t\t\t\t\tresults.push( elem );\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif ( outermost ) {\n\t\t\t\t\t\tdirruns = dirrunsUnique;\n\t\t\t\t\t\tcachedruns = ++matcherCachedRuns;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Track unmatched elements for set filters\n\t\t\t\tif ( bySet ) {\n\t\t\t\t\t// They will have gone through all possible matchers\n\t\t\t\t\tif ( (elem = !matcher && elem) ) {\n\t\t\t\t\t\tmatchedCount--;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Lengthen the array for every element, matched or not\n\t\t\t\t\tif ( seed ) {\n\t\t\t\t\t\tunmatched.push( elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Apply set filters to unmatched elements\n\t\t\tmatchedCount += i;\n\t\t\tif ( bySet && i !== matchedCount ) {\n\t\t\t\tj = 0;\n\t\t\t\twhile ( (matcher = setMatchers[j++]) ) {\n\t\t\t\t\tmatcher( unmatched, setMatched, context, xml );\n\t\t\t\t}\n\n\t\t\t\tif ( seed ) {\n\t\t\t\t\t// Reintegrate element matches to eliminate the need for sorting\n\t\t\t\t\tif ( matchedCount > 0 ) {\n\t\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\t\tif ( !(unmatched[i] || setMatched[i]) ) {\n\t\t\t\t\t\t\t\tsetMatched[i] = pop.call( results );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Discard index placeholder values to get only actual matches\n\t\t\t\t\tsetMatched = condense( setMatched );\n\t\t\t\t}\n\n\t\t\t\t// Add matches to results\n\t\t\t\tpush.apply( results, setMatched );\n\n\t\t\t\t// Seedless set matches succeeding multiple successful matchers stipulate sorting\n\t\t\t\tif ( outermost && !seed && setMatched.length > 0 &&\n\t\t\t\t\t( matchedCount + setMatchers.length ) > 1 ) {\n\n\t\t\t\t\tSizzle.uniqueSort( results );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Override manipulation of globals by nested matchers\n\t\t\tif ( outermost ) {\n\t\t\t\tdirruns = dirrunsUnique;\n\t\t\t\toutermostContext = contextBackup;\n\t\t\t}\n\n\t\t\treturn unmatched;\n\t\t};\n\n\treturn bySet ?\n\t\tmarkFunction( superMatcher ) :\n\t\tsuperMatcher;\n}\n\ncompile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) {\n\tvar i,\n\t\tsetMatchers = [],\n\t\telementMatchers = [],\n\t\tcached = compilerCache[ selector + \" \" ];\n\n\tif ( !cached ) {\n\t\t// Generate a function of recursive functions that can be used to check each element\n\t\tif ( !group ) {\n\t\t\tgroup = tokenize( selector );\n\t\t}\n\t\ti = group.length;\n\t\twhile ( i-- ) {\n\t\t\tcached = matcherFromTokens( group[i] );\n\t\t\tif ( cached[ expando ] ) {\n\t\t\t\tsetMatchers.push( cached );\n\t\t\t} else {\n\t\t\t\telementMatchers.push( cached );\n\t\t\t}\n\t\t}\n\n\t\t// Cache the compiled function\n\t\tcached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );\n\t}\n\treturn cached;\n};\n\nfunction multipleContexts( selector, contexts, results ) {\n\tvar i = 0,\n\t\tlen = contexts.length;\n\tfor ( ; i < len; i++ ) {\n\t\tSizzle( selector, contexts[i], results );\n\t}\n\treturn results;\n}\n\nfunction select( selector, context, results, seed ) {\n\tvar i, tokens, token, type, find,\n\t\tmatch = tokenize( selector );\n\n\tif ( !seed ) {\n\t\t// Try to minimize operations if there is only one group\n\t\tif ( match.length === 1 ) {\n\n\t\t\t// Take a shortcut and set the context if the root selector is an ID\n\t\t\ttokens = match[0] = match[0].slice( 0 );\n\t\t\tif ( tokens.length > 2 && (token = tokens[0]).type === \"ID\" &&\n\t\t\t\t\tcontext.nodeType === 9 && !documentIsXML &&\n\t\t\t\t\tExpr.relative[ tokens[1].type ] ) {\n\n\t\t\t\tcontext = Expr.find[\"ID\"]( token.matches[0].replace( runescape, funescape ), context )[0];\n\t\t\t\tif ( !context ) {\n\t\t\t\t\treturn results;\n\t\t\t\t}\n\n\t\t\t\tselector = selector.slice( tokens.shift().value.length );\n\t\t\t}\n\n\t\t\t// Fetch a seed set for right-to-left matching\n\t\t\ti = matchExpr[\"needsContext\"].test( selector ) ? 0 : tokens.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\ttoken = tokens[i];\n\n\t\t\t\t// Abort if we hit a combinator\n\t\t\t\tif ( Expr.relative[ (type = token.type) ] ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif ( (find = Expr.find[ type ]) ) {\n\t\t\t\t\t// Search, expanding context for leading sibling combinators\n\t\t\t\t\tif ( (seed = find(\n\t\t\t\t\t\ttoken.matches[0].replace( runescape, funescape ),\n\t\t\t\t\t\trsibling.test( tokens[0].type ) && context.parentNode || context\n\t\t\t\t\t)) ) {\n\n\t\t\t\t\t\t// If seed is empty or no tokens remain, we can return early\n\t\t\t\t\t\ttokens.splice( i, 1 );\n\t\t\t\t\t\tselector = seed.length && toSelector( tokens );\n\t\t\t\t\t\tif ( !selector ) {\n\t\t\t\t\t\t\tpush.apply( results, slice.call( seed, 0 ) );\n\t\t\t\t\t\t\treturn results;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Compile and execute a filtering function\n\t// Provide `match` to avoid retokenization if we modified the selector above\n\tcompile( selector, match )(\n\t\tseed,\n\t\tcontext,\n\t\tdocumentIsXML,\n\t\tresults,\n\t\trsibling.test( selector )\n\t);\n\treturn results;\n}\n\n// Deprecated\nExpr.pseudos[\"nth\"] = Expr.pseudos[\"eq\"];\n\n// Easy API for creating new setFilters\nfunction setFilters() {}\nExpr.filters = setFilters.prototype = Expr.pseudos;\nExpr.setFilters = new setFilters();\n\n// Initialize with the default document\nsetDocument();\n\n// Override sizzle attribute retrieval\nSizzle.attr = jQuery.attr;\njQuery.find = Sizzle;\njQuery.expr = Sizzle.selectors;\njQuery.expr[\":\"] = jQuery.expr.pseudos;\njQuery.unique = Sizzle.uniqueSort;\njQuery.text = Sizzle.getText;\njQuery.isXMLDoc = Sizzle.isXML;\njQuery.contains = Sizzle.contains;\n\n\n})( window );\nvar runtil = /Until$/,\n\trparentsprev = /^(?:parents|prev(?:Until|All))/,\n\tisSimple = /^.[^:#\\[\\.,]*$/,\n\trneedsContext = jQuery.expr.match.needsContext,\n\t// methods guaranteed to produce a unique set when starting from a unique set\n\tguaranteedUnique = {\n\t\tchildren: true,\n\t\tcontents: true,\n\t\tnext: true,\n\t\tprev: true\n\t};\n\njQuery.fn.extend({\n\tfind: function( selector ) {\n\t\tvar i, ret, self,\n\t\t\tlen = this.length;\n\n\t\tif ( typeof selector !== \"string\" ) {\n\t\t\tself = this;\n\t\t\treturn this.pushStack( jQuery( selector ).filter(function() {\n\t\t\t\tfor ( i = 0; i < len; i++ ) {\n\t\t\t\t\tif ( jQuery.contains( self[ i ], this ) ) {\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\tret = [];\n\t\tfor ( i = 0; i < len; i++ ) {\n\t\t\tjQuery.find( selector, this[ i ], ret );\n\t\t}\n\n\t\t// Needed because $( selector, context ) becomes $( context ).find( selector )\n\t\tret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );\n\t\tret.selector = ( this.selector ? this.selector + \" \" : \"\" ) + selector;\n\t\treturn ret;\n\t},\n\n\thas: function( target ) {\n\t\tvar i,\n\t\t\ttargets = jQuery( target, this ),\n\t\t\tlen = targets.length;\n\n\t\treturn this.filter(function() {\n\t\t\tfor ( i = 0; i < len; i++ ) {\n\t\t\t\tif ( jQuery.contains( this, targets[i] ) ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t},\n\n\tnot: function( selector ) {\n\t\treturn this.pushStack( winnow(this, selector, false) );\n\t},\n\n\tfilter: function( selector ) {\n\t\treturn this.pushStack( winnow(this, selector, true) );\n\t},\n\n\tis: function( selector ) {\n\t\treturn !!selector && (\n\t\t\ttypeof selector === \"string\" ?\n\t\t\t\t// If this is a positional/relative selector, check membership in the returned set\n\t\t\t\t// so $(\"p:first\").is(\"p:last\") won't return true for a doc with two \"p\".\n\t\t\t\trneedsContext.test( selector ) ?\n\t\t\t\t\tjQuery( selector, this.context ).index( this[0] ) >= 0 :\n\t\t\t\t\tjQuery.filter( selector, this ).length > 0 :\n\t\t\t\tthis.filter( selector ).length > 0 );\n\t},\n\n\tclosest: function( selectors, context ) {\n\t\tvar cur,\n\t\t\ti = 0,\n\t\t\tl = this.length,\n\t\t\tret = [],\n\t\t\tpos = rneedsContext.test( selectors ) || typeof selectors !== \"string\" ?\n\t\t\t\tjQuery( selectors, context || this.context ) :\n\t\t\t\t0;\n\n\t\tfor ( ; i < l; i++ ) {\n\t\t\tcur = this[i];\n\n\t\t\twhile ( cur && cur.ownerDocument && cur !== context && cur.nodeType !== 11 ) {\n\t\t\t\tif ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {\n\t\t\t\t\tret.push( cur );\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcur = cur.parentNode;\n\t\t\t}\n\t\t}\n\n\t\treturn this.pushStack( ret.length > 1 ? jQuery.unique( ret ) : ret );\n\t},\n\n\t// Determine the position of an element within\n\t// the matched set of elements\n\tindex: function( elem ) {\n\n\t\t// No argument, return index in parent\n\t\tif ( !elem ) {\n\t\t\treturn ( this[0] && this[0].parentNode ) ? this.first().prevAll().length : -1;\n\t\t}\n\n\t\t// index in selector\n\t\tif ( typeof elem === \"string\" ) {\n\t\t\treturn jQuery.inArray( this[0], jQuery( elem ) );\n\t\t}\n\n\t\t// Locate the position of the desired element\n\t\treturn jQuery.inArray(\n\t\t\t// If it receives a jQuery object, the first element is used\n\t\t\telem.jquery ? elem[0] : elem, this );\n\t},\n\n\tadd: function( selector, context ) {\n\t\tvar set = typeof selector === \"string\" ?\n\t\t\t\tjQuery( selector, context ) :\n\t\t\t\tjQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),\n\t\t\tall = jQuery.merge( this.get(), set );\n\n\t\treturn this.pushStack( jQuery.unique(all) );\n\t},\n\n\taddBack: function( selector ) {\n\t\treturn this.add( selector == null ?\n\t\t\tthis.prevObject : this.prevObject.filter(selector)\n\t\t);\n\t}\n});\n\njQuery.fn.andSelf = jQuery.fn.addBack;\n\nfunction sibling( cur, dir ) {\n\tdo {\n\t\tcur = cur[ dir ];\n\t} while ( cur && cur.nodeType !== 1 );\n\n\treturn cur;\n}\n\njQuery.each({\n\tparent: function( elem ) {\n\t\tvar parent = elem.parentNode;\n\t\treturn parent && parent.nodeType !== 11 ? parent : null;\n\t},\n\tparents: function( elem ) {\n\t\treturn jQuery.dir( elem, \"parentNode\" );\n\t},\n\tparentsUntil: function( elem, i, until ) {\n\t\treturn jQuery.dir( elem, \"parentNode\", until );\n\t},\n\tnext: function( elem ) {\n\t\treturn sibling( elem, \"nextSibling\" );\n\t},\n\tprev: function( elem ) {\n\t\treturn sibling( elem, \"previousSibling\" );\n\t},\n\tnextAll: function( elem ) {\n\t\treturn jQuery.dir( elem, \"nextSibling\" );\n\t},\n\tprevAll: function( elem ) {\n\t\treturn jQuery.dir( elem, \"previousSibling\" );\n\t},\n\tnextUntil: function( elem, i, until ) {\n\t\treturn jQuery.dir( elem, \"nextSibling\", until );\n\t},\n\tprevUntil: function( elem, i, until ) {\n\t\treturn jQuery.dir( elem, \"previousSibling\", until );\n\t},\n\tsiblings: function( elem ) {\n\t\treturn jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );\n\t},\n\tchildren: function( elem ) {\n\t\treturn jQuery.sibling( elem.firstChild );\n\t},\n\tcontents: function( elem ) {\n\t\treturn jQuery.nodeName( elem, \"iframe\" ) ?\n\t\t\telem.contentDocument || elem.contentWindow.document :\n\t\t\tjQuery.merge( [], elem.childNodes );\n\t}\n}, function( name, fn ) {\n\tjQuery.fn[ name ] = function( until, selector ) {\n\t\tvar ret = jQuery.map( this, fn, until );\n\n\t\tif ( !runtil.test( name ) ) {\n\t\t\tselector = until;\n\t\t}\n\n\t\tif ( selector && typeof selector === \"string\" ) {\n\t\t\tret = jQuery.filter( selector, ret );\n\t\t}\n\n\t\tret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;\n\n\t\tif ( this.length > 1 && rparentsprev.test( name ) ) {\n\t\t\tret = ret.reverse();\n\t\t}\n\n\t\treturn this.pushStack( ret );\n\t};\n});\n\njQuery.extend({\n\tfilter: function( expr, elems, not ) {\n\t\tif ( not ) {\n\t\t\texpr = \":not(\" + expr + \")\";\n\t\t}\n\n\t\treturn elems.length === 1 ?\n\t\t\tjQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] :\n\t\t\tjQuery.find.matches(expr, elems);\n\t},\n\n\tdir: function( elem, dir, until ) {\n\t\tvar matched = [],\n\t\t\tcur = elem[ dir ];\n\n\t\twhile ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {\n\t\t\tif ( cur.nodeType === 1 ) {\n\t\t\t\tmatched.push( cur );\n\t\t\t}\n\t\t\tcur = cur[dir];\n\t\t}\n\t\treturn matched;\n\t},\n\n\tsibling: function( n, elem ) {\n\t\tvar r = [];\n\n\t\tfor ( ; n; n = n.nextSibling ) {\n\t\t\tif ( n.nodeType === 1 && n !== elem ) {\n\t\t\t\tr.push( n );\n\t\t\t}\n\t\t}\n\n\t\treturn r;\n\t}\n});\n\n// Implement the identical functionality for filter and not\nfunction winnow( elements, qualifier, keep ) {\n\n\t// Can't pass null or undefined to indexOf in Firefox 4\n\t// Set to 0 to skip string check\n\tqualifier = qualifier || 0;\n\n\tif ( jQuery.isFunction( qualifier ) ) {\n\t\treturn jQuery.grep(elements, function( elem, i ) {\n\t\t\tvar retVal = !!qualifier.call( elem, i, elem );\n\t\t\treturn retVal === keep;\n\t\t});\n\n\t} else if ( qualifier.nodeType ) {\n\t\treturn jQuery.grep(elements, function( elem ) {\n\t\t\treturn ( elem === qualifier ) === keep;\n\t\t});\n\n\t} else if ( typeof qualifier === \"string\" ) {\n\t\tvar filtered = jQuery.grep(elements, function( elem ) {\n\t\t\treturn elem.nodeType === 1;\n\t\t});\n\n\t\tif ( isSimple.test( qualifier ) ) {\n\t\t\treturn jQuery.filter(qualifier, filtered, !keep);\n\t\t} else {\n\t\t\tqualifier = jQuery.filter( qualifier, filtered );\n\t\t}\n\t}\n\n\treturn jQuery.grep(elements, function( elem ) {\n\t\treturn ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep;\n\t});\n}\nfunction createSafeFragment( document ) {\n\tvar list = nodeNames.split( \"|\" ),\n\t\tsafeFrag = document.createDocumentFragment();\n\n\tif ( safeFrag.createElement ) {\n\t\twhile ( list.length ) {\n\t\t\tsafeFrag.createElement(\n\t\t\t\tlist.pop()\n\t\t\t);\n\t\t}\n\t}\n\treturn safeFrag;\n}\n\nvar nodeNames = \"abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|\" +\n\t\t\"header|hgroup|mark|meter|nav|output|progress|section|summary|time|video\",\n\trinlinejQuery = / jQuery\\d+=\"(?:null|\\d+)\"/g,\n\trnoshimcache = new RegExp(\"<(?:\" + nodeNames + \")[\\\\s/>]\", \"i\"),\n\trleadingWhitespace = /^\\s+/,\n\trxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\\w:]+)[^>]*)\\/>/gi,\n\trtagName = /<([\\w:]+)/,\n\trtbody = /<tbody/i,\n\trhtml = /<|&#?\\w+;/,\n\trnoInnerhtml = /<(?:script|style|link)/i,\n\tmanipulation_rcheckableType = /^(?:checkbox|radio)$/i,\n\t// checked=\"checked\" or checked\n\trchecked = /checked\\s*(?:[^=]|=\\s*.checked.)/i,\n\trscriptType = /^$|\\/(?:java|ecma)script/i,\n\trscriptTypeMasked = /^true\\/(.*)/,\n\trcleanScript = /^\\s*<!(?:\\[CDATA\\[|--)|(?:\\]\\]|--)>\\s*$/g,\n\n\t// We have to close these tags to support XHTML (#13200)\n\twrapMap = {\n\t\toption: [ 1, \"<select multiple='multiple'>\", \"</select>\" ],\n\t\tlegend: [ 1, \"<fieldset>\", \"</fieldset>\" ],\n\t\tarea: [ 1, \"<map>\", \"</map>\" ],\n\t\tparam: [ 1, \"<object>\", \"</object>\" ],\n\t\tthead: [ 1, \"<table>\", \"</table>\" ],\n\t\ttr: [ 2, \"<table><tbody>\", \"</tbody></table>\" ],\n\t\tcol: [ 2, \"<table><tbody></tbody><colgroup>\", \"</colgroup></table>\" ],\n\t\ttd: [ 3, \"<table><tbody><tr>\", \"</tr></tbody></table>\" ],\n\n\t\t// IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags,\n\t\t// unless wrapped in a div with non-breaking characters in front of it.\n\t\t_default: jQuery.support.htmlSerialize ? [ 0, \"\", \"\" ] : [ 1, \"X<div>\", \"</div>\"  ]\n\t},\n\tsafeFragment = createSafeFragment( document ),\n\tfragmentDiv = safeFragment.appendChild( document.createElement(\"div\") );\n\nwrapMap.optgroup = wrapMap.option;\nwrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;\nwrapMap.th = wrapMap.td;\n\njQuery.fn.extend({\n\ttext: function( value ) {\n\t\treturn jQuery.access( this, function( value ) {\n\t\t\treturn value === undefined ?\n\t\t\t\tjQuery.text( this ) :\n\t\t\t\tthis.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) );\n\t\t}, null, value, arguments.length );\n\t},\n\n\twrapAll: function( html ) {\n\t\tif ( jQuery.isFunction( html ) ) {\n\t\t\treturn this.each(function(i) {\n\t\t\t\tjQuery(this).wrapAll( html.call(this, i) );\n\t\t\t});\n\t\t}\n\n\t\tif ( this[0] ) {\n\t\t\t// The elements to wrap the target around\n\t\t\tvar wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);\n\n\t\t\tif ( this[0].parentNode ) {\n\t\t\t\twrap.insertBefore( this[0] );\n\t\t\t}\n\n\t\t\twrap.map(function() {\n\t\t\t\tvar elem = this;\n\n\t\t\t\twhile ( elem.firstChild && elem.firstChild.nodeType === 1 ) {\n\t\t\t\t\telem = elem.firstChild;\n\t\t\t\t}\n\n\t\t\t\treturn elem;\n\t\t\t}).append( this );\n\t\t}\n\n\t\treturn this;\n\t},\n\n\twrapInner: function( html ) {\n\t\tif ( jQuery.isFunction( html ) ) {\n\t\t\treturn this.each(function(i) {\n\t\t\t\tjQuery(this).wrapInner( html.call(this, i) );\n\t\t\t});\n\t\t}\n\n\t\treturn this.each(function() {\n\t\t\tvar self = jQuery( this ),\n\t\t\t\tcontents = self.contents();\n\n\t\t\tif ( contents.length ) {\n\t\t\t\tcontents.wrapAll( html );\n\n\t\t\t} else {\n\t\t\t\tself.append( html );\n\t\t\t}\n\t\t});\n\t},\n\n\twrap: function( html ) {\n\t\tvar isFunction = jQuery.isFunction( html );\n\n\t\treturn this.each(function(i) {\n\t\t\tjQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );\n\t\t});\n\t},\n\n\tunwrap: function() {\n\t\treturn this.parent().each(function() {\n\t\t\tif ( !jQuery.nodeName( this, \"body\" ) ) {\n\t\t\t\tjQuery( this ).replaceWith( this.childNodes );\n\t\t\t}\n\t\t}).end();\n\t},\n\n\tappend: function() {\n\t\treturn this.domManip(arguments, true, function( elem ) {\n\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\tthis.appendChild( elem );\n\t\t\t}\n\t\t});\n\t},\n\n\tprepend: function() {\n\t\treturn this.domManip(arguments, true, function( elem ) {\n\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\tthis.insertBefore( elem, this.firstChild );\n\t\t\t}\n\t\t});\n\t},\n\n\tbefore: function() {\n\t\treturn this.domManip( arguments, false, function( elem ) {\n\t\t\tif ( this.parentNode ) {\n\t\t\t\tthis.parentNode.insertBefore( elem, this );\n\t\t\t}\n\t\t});\n\t},\n\n\tafter: function() {\n\t\treturn this.domManip( arguments, false, function( elem ) {\n\t\t\tif ( this.parentNode ) {\n\t\t\t\tthis.parentNode.insertBefore( elem, this.nextSibling );\n\t\t\t}\n\t\t});\n\t},\n\n\t// keepData is for internal use only--do not document\n\tremove: function( selector, keepData ) {\n\t\tvar elem,\n\t\t\ti = 0;\n\n\t\tfor ( ; (elem = this[i]) != null; i++ ) {\n\t\t\tif ( !selector || jQuery.filter( selector, [ elem ] ).length > 0 ) {\n\t\t\t\tif ( !keepData && elem.nodeType === 1 ) {\n\t\t\t\t\tjQuery.cleanData( getAll( elem ) );\n\t\t\t\t}\n\n\t\t\t\tif ( elem.parentNode ) {\n\t\t\t\t\tif ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) {\n\t\t\t\t\t\tsetGlobalEval( getAll( elem, \"script\" ) );\n\t\t\t\t\t}\n\t\t\t\t\telem.parentNode.removeChild( elem );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tempty: function() {\n\t\tvar elem,\n\t\t\ti = 0;\n\n\t\tfor ( ; (elem = this[i]) != null; i++ ) {\n\t\t\t// Remove element nodes and prevent memory leaks\n\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\tjQuery.cleanData( getAll( elem, false ) );\n\t\t\t}\n\n\t\t\t// Remove any remaining nodes\n\t\t\twhile ( elem.firstChild ) {\n\t\t\t\telem.removeChild( elem.firstChild );\n\t\t\t}\n\n\t\t\t// If this is a select, ensure that it displays empty (#12336)\n\t\t\t// Support: IE<9\n\t\t\tif ( elem.options && jQuery.nodeName( elem, \"select\" ) ) {\n\t\t\t\telem.options.length = 0;\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tclone: function( dataAndEvents, deepDataAndEvents ) {\n\t\tdataAndEvents = dataAndEvents == null ? false : dataAndEvents;\n\t\tdeepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;\n\n\t\treturn this.map( function () {\n\t\t\treturn jQuery.clone( this, dataAndEvents, deepDataAndEvents );\n\t\t});\n\t},\n\n\thtml: function( value ) {\n\t\treturn jQuery.access( this, function( value ) {\n\t\t\tvar elem = this[0] || {},\n\t\t\t\ti = 0,\n\t\t\t\tl = this.length;\n\n\t\t\tif ( value === undefined ) {\n\t\t\t\treturn elem.nodeType === 1 ?\n\t\t\t\t\telem.innerHTML.replace( rinlinejQuery, \"\" ) :\n\t\t\t\t\tundefined;\n\t\t\t}\n\n\t\t\t// See if we can take a shortcut and just use innerHTML\n\t\t\tif ( typeof value === \"string\" && !rnoInnerhtml.test( value ) &&\n\t\t\t\t( jQuery.support.htmlSerialize || !rnoshimcache.test( value )  ) &&\n\t\t\t\t( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&\n\t\t\t\t!wrapMap[ ( rtagName.exec( value ) || [\"\", \"\"] )[1].toLowerCase() ] ) {\n\n\t\t\t\tvalue = value.replace( rxhtmlTag, \"<$1></$2>\" );\n\n\t\t\t\ttry {\n\t\t\t\t\tfor (; i < l; i++ ) {\n\t\t\t\t\t\t// Remove element nodes and prevent memory leaks\n\t\t\t\t\t\telem = this[i] || {};\n\t\t\t\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\t\t\t\tjQuery.cleanData( getAll( elem, false ) );\n\t\t\t\t\t\t\telem.innerHTML = value;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\telem = 0;\n\n\t\t\t\t// If using innerHTML throws an exception, use the fallback method\n\t\t\t\t} catch(e) {}\n\t\t\t}\n\n\t\t\tif ( elem ) {\n\t\t\t\tthis.empty().append( value );\n\t\t\t}\n\t\t}, null, value, arguments.length );\n\t},\n\n\treplaceWith: function( value ) {\n\t\tvar isFunc = jQuery.isFunction( value );\n\n\t\t// Make sure that the elements are removed from the DOM before they are inserted\n\t\t// this can help fix replacing a parent with child elements\n\t\tif ( !isFunc && typeof value !== \"string\" ) {\n\t\t\tvalue = jQuery( value ).not( this ).detach();\n\t\t}\n\n\t\treturn this.domManip( [ value ], true, function( elem ) {\n\t\t\tvar next = this.nextSibling,\n\t\t\t\tparent = this.parentNode;\n\n\t\t\tif ( parent ) {\n\t\t\t\tjQuery( this ).remove();\n\t\t\t\tparent.insertBefore( elem, next );\n\t\t\t}\n\t\t});\n\t},\n\n\tdetach: function( selector ) {\n\t\treturn this.remove( selector, true );\n\t},\n\n\tdomManip: function( args, table, callback ) {\n\n\t\t// Flatten any nested arrays\n\t\targs = core_concat.apply( [], args );\n\n\t\tvar first, node, hasScripts,\n\t\t\tscripts, doc, fragment,\n\t\t\ti = 0,\n\t\t\tl = this.length,\n\t\t\tset = this,\n\t\t\tiNoClone = l - 1,\n\t\t\tvalue = args[0],\n\t\t\tisFunction = jQuery.isFunction( value );\n\n\t\t// We can't cloneNode fragments that contain checked, in WebKit\n\t\tif ( isFunction || !( l <= 1 || typeof value !== \"string\" || jQuery.support.checkClone || !rchecked.test( value ) ) ) {\n\t\t\treturn this.each(function( index ) {\n\t\t\t\tvar self = set.eq( index );\n\t\t\t\tif ( isFunction ) {\n\t\t\t\t\targs[0] = value.call( this, index, table ? self.html() : undefined );\n\t\t\t\t}\n\t\t\t\tself.domManip( args, table, callback );\n\t\t\t});\n\t\t}\n\n\t\tif ( l ) {\n\t\t\tfragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this );\n\t\t\tfirst = fragment.firstChild;\n\n\t\t\tif ( fragment.childNodes.length === 1 ) {\n\t\t\t\tfragment = first;\n\t\t\t}\n\n\t\t\tif ( first ) {\n\t\t\t\ttable = table && jQuery.nodeName( first, \"tr\" );\n\t\t\t\tscripts = jQuery.map( getAll( fragment, \"script\" ), disableScript );\n\t\t\t\thasScripts = scripts.length;\n\n\t\t\t\t// Use the original fragment for the last item instead of the first because it can end up\n\t\t\t\t// being emptied incorrectly in certain situations (#8070).\n\t\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\t\tnode = fragment;\n\n\t\t\t\t\tif ( i !== iNoClone ) {\n\t\t\t\t\t\tnode = jQuery.clone( node, true, true );\n\n\t\t\t\t\t\t// Keep references to cloned scripts for later restoration\n\t\t\t\t\t\tif ( hasScripts ) {\n\t\t\t\t\t\t\tjQuery.merge( scripts, getAll( node, \"script\" ) );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tcallback.call(\n\t\t\t\t\t\ttable && jQuery.nodeName( this[i], \"table\" ) ?\n\t\t\t\t\t\t\tfindOrAppend( this[i], \"tbody\" ) :\n\t\t\t\t\t\t\tthis[i],\n\t\t\t\t\t\tnode,\n\t\t\t\t\t\ti\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tif ( hasScripts ) {\n\t\t\t\t\tdoc = scripts[ scripts.length - 1 ].ownerDocument;\n\n\t\t\t\t\t// Reenable scripts\n\t\t\t\t\tjQuery.map( scripts, restoreScript );\n\n\t\t\t\t\t// Evaluate executable scripts on first document insertion\n\t\t\t\t\tfor ( i = 0; i < hasScripts; i++ ) {\n\t\t\t\t\t\tnode = scripts[ i ];\n\t\t\t\t\t\tif ( rscriptType.test( node.type || \"\" ) &&\n\t\t\t\t\t\t\t!jQuery._data( node, \"globalEval\" ) && jQuery.contains( doc, node ) ) {\n\n\t\t\t\t\t\t\tif ( node.src ) {\n\t\t\t\t\t\t\t\t// Hope ajax is available...\n\t\t\t\t\t\t\t\tjQuery.ajax({\n\t\t\t\t\t\t\t\t\turl: node.src,\n\t\t\t\t\t\t\t\t\ttype: \"GET\",\n\t\t\t\t\t\t\t\t\tdataType: \"script\",\n\t\t\t\t\t\t\t\t\tasync: false,\n\t\t\t\t\t\t\t\t\tglobal: false,\n\t\t\t\t\t\t\t\t\t\"throws\": true\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tjQuery.globalEval( ( node.text || node.textContent || node.innerHTML || \"\" ).replace( rcleanScript, \"\" ) );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Fix #11809: Avoid leaking memory\n\t\t\t\tfragment = first = null;\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t}\n});\n\nfunction findOrAppend( elem, tag ) {\n\treturn elem.getElementsByTagName( tag )[0] || elem.appendChild( elem.ownerDocument.createElement( tag ) );\n}\n\n// Replace/restore the type attribute of script elements for safe DOM manipulation\nfunction disableScript( elem ) {\n\tvar attr = elem.getAttributeNode(\"type\");\n\telem.type = ( attr && attr.specified ) + \"/\" + elem.type;\n\treturn elem;\n}\nfunction restoreScript( elem ) {\n\tvar match = rscriptTypeMasked.exec( elem.type );\n\tif ( match ) {\n\t\telem.type = match[1];\n\t} else {\n\t\telem.removeAttribute(\"type\");\n\t}\n\treturn elem;\n}\n\n// Mark scripts as having already been evaluated\nfunction setGlobalEval( elems, refElements ) {\n\tvar elem,\n\t\ti = 0;\n\tfor ( ; (elem = elems[i]) != null; i++ ) {\n\t\tjQuery._data( elem, \"globalEval\", !refElements || jQuery._data( refElements[i], \"globalEval\" ) );\n\t}\n}\n\nfunction cloneCopyEvent( src, dest ) {\n\n\tif ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {\n\t\treturn;\n\t}\n\n\tvar type, i, l,\n\t\toldData = jQuery._data( src ),\n\t\tcurData = jQuery._data( dest, oldData ),\n\t\tevents = oldData.events;\n\n\tif ( events ) {\n\t\tdelete curData.handle;\n\t\tcurData.events = {};\n\n\t\tfor ( type in events ) {\n\t\t\tfor ( i = 0, l = events[ type ].length; i < l; i++ ) {\n\t\t\t\tjQuery.event.add( dest, type, events[ type ][ i ] );\n\t\t\t}\n\t\t}\n\t}\n\n\t// make the cloned public data object a copy from the original\n\tif ( curData.data ) {\n\t\tcurData.data = jQuery.extend( {}, curData.data );\n\t}\n}\n\nfunction fixCloneNodeIssues( src, dest ) {\n\tvar nodeName, e, data;\n\n\t// We do not need to do anything for non-Elements\n\tif ( dest.nodeType !== 1 ) {\n\t\treturn;\n\t}\n\n\tnodeName = dest.nodeName.toLowerCase();\n\n\t// IE6-8 copies events bound via attachEvent when using cloneNode.\n\tif ( !jQuery.support.noCloneEvent && dest[ jQuery.expando ] ) {\n\t\tdata = jQuery._data( dest );\n\n\t\tfor ( e in data.events ) {\n\t\t\tjQuery.removeEvent( dest, e, data.handle );\n\t\t}\n\n\t\t// Event data gets referenced instead of copied if the expando gets copied too\n\t\tdest.removeAttribute( jQuery.expando );\n\t}\n\n\t// IE blanks contents when cloning scripts, and tries to evaluate newly-set text\n\tif ( nodeName === \"script\" && dest.text !== src.text ) {\n\t\tdisableScript( dest ).text = src.text;\n\t\trestoreScript( dest );\n\n\t// IE6-10 improperly clones children of object elements using classid.\n\t// IE10 throws NoModificationAllowedError if parent is null, #12132.\n\t} else if ( nodeName === \"object\" ) {\n\t\tif ( dest.parentNode ) {\n\t\t\tdest.outerHTML = src.outerHTML;\n\t\t}\n\n\t\t// This path appears unavoidable for IE9. When cloning an object\n\t\t// element in IE9, the outerHTML strategy above is not sufficient.\n\t\t// If the src has innerHTML and the destination does not,\n\t\t// copy the src.innerHTML into the dest.innerHTML. #10324\n\t\tif ( jQuery.support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) {\n\t\t\tdest.innerHTML = src.innerHTML;\n\t\t}\n\n\t} else if ( nodeName === \"input\" && manipulation_rcheckableType.test( src.type ) ) {\n\t\t// IE6-8 fails to persist the checked state of a cloned checkbox\n\t\t// or radio button. Worse, IE6-7 fail to give the cloned element\n\t\t// a checked appearance if the defaultChecked value isn't also set\n\n\t\tdest.defaultChecked = dest.checked = src.checked;\n\n\t\t// IE6-7 get confused and end up setting the value of a cloned\n\t\t// checkbox/radio button to an empty string instead of \"on\"\n\t\tif ( dest.value !== src.value ) {\n\t\t\tdest.value = src.value;\n\t\t}\n\n\t// IE6-8 fails to return the selected option to the default selected\n\t// state when cloning options\n\t} else if ( nodeName === \"option\" ) {\n\t\tdest.defaultSelected = dest.selected = src.defaultSelected;\n\n\t// IE6-8 fails to set the defaultValue to the correct value when\n\t// cloning other types of input fields\n\t} else if ( nodeName === \"input\" || nodeName === \"textarea\" ) {\n\t\tdest.defaultValue = src.defaultValue;\n\t}\n}\n\njQuery.each({\n\tappendTo: \"append\",\n\tprependTo: \"prepend\",\n\tinsertBefore: \"before\",\n\tinsertAfter: \"after\",\n\treplaceAll: \"replaceWith\"\n}, function( name, original ) {\n\tjQuery.fn[ name ] = function( selector ) {\n\t\tvar elems,\n\t\t\ti = 0,\n\t\t\tret = [],\n\t\t\tinsert = jQuery( selector ),\n\t\t\tlast = insert.length - 1;\n\n\t\tfor ( ; i <= last; i++ ) {\n\t\t\telems = i === last ? this : this.clone(true);\n\t\t\tjQuery( insert[i] )[ original ]( elems );\n\n\t\t\t// Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get()\n\t\t\tcore_push.apply( ret, elems.get() );\n\t\t}\n\n\t\treturn this.pushStack( ret );\n\t};\n});\n\nfunction getAll( context, tag ) {\n\tvar elems, elem,\n\t\ti = 0,\n\t\tfound = typeof context.getElementsByTagName !== core_strundefined ? context.getElementsByTagName( tag || \"*\" ) :\n\t\t\ttypeof context.querySelectorAll !== core_strundefined ? context.querySelectorAll( tag || \"*\" ) :\n\t\t\tundefined;\n\n\tif ( !found ) {\n\t\tfor ( found = [], elems = context.childNodes || context; (elem = elems[i]) != null; i++ ) {\n\t\t\tif ( !tag || jQuery.nodeName( elem, tag ) ) {\n\t\t\t\tfound.push( elem );\n\t\t\t} else {\n\t\t\t\tjQuery.merge( found, getAll( elem, tag ) );\n\t\t\t}\n\t\t}\n\t}\n\n\treturn tag === undefined || tag && jQuery.nodeName( context, tag ) ?\n\t\tjQuery.merge( [ context ], found ) :\n\t\tfound;\n}\n\n// Used in buildFragment, fixes the defaultChecked property\nfunction fixDefaultChecked( elem ) {\n\tif ( manipulation_rcheckableType.test( elem.type ) ) {\n\t\telem.defaultChecked = elem.checked;\n\t}\n}\n\njQuery.extend({\n\tclone: function( elem, dataAndEvents, deepDataAndEvents ) {\n\t\tvar destElements, node, clone, i, srcElements,\n\t\t\tinPage = jQuery.contains( elem.ownerDocument, elem );\n\n\t\tif ( jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( \"<\" + elem.nodeName + \">\" ) ) {\n\t\t\tclone = elem.cloneNode( true );\n\n\t\t// IE<=8 does not properly clone detached, unknown element nodes\n\t\t} else {\n\t\t\tfragmentDiv.innerHTML = elem.outerHTML;\n\t\t\tfragmentDiv.removeChild( clone = fragmentDiv.firstChild );\n\t\t}\n\n\t\tif ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&\n\t\t\t\t(elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {\n\n\t\t\t// We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2\n\t\t\tdestElements = getAll( clone );\n\t\t\tsrcElements = getAll( elem );\n\n\t\t\t// Fix all IE cloning issues\n\t\t\tfor ( i = 0; (node = srcElements[i]) != null; ++i ) {\n\t\t\t\t// Ensure that the destination node is not null; Fixes #9587\n\t\t\t\tif ( destElements[i] ) {\n\t\t\t\t\tfixCloneNodeIssues( node, destElements[i] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Copy the events from the original to the clone\n\t\tif ( dataAndEvents ) {\n\t\t\tif ( deepDataAndEvents ) {\n\t\t\t\tsrcElements = srcElements || getAll( elem );\n\t\t\t\tdestElements = destElements || getAll( clone );\n\n\t\t\t\tfor ( i = 0; (node = srcElements[i]) != null; i++ ) {\n\t\t\t\t\tcloneCopyEvent( node, destElements[i] );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tcloneCopyEvent( elem, clone );\n\t\t\t}\n\t\t}\n\n\t\t// Preserve script evaluation history\n\t\tdestElements = getAll( clone, \"script\" );\n\t\tif ( destElements.length > 0 ) {\n\t\t\tsetGlobalEval( destElements, !inPage && getAll( elem, \"script\" ) );\n\t\t}\n\n\t\tdestElements = srcElements = node = null;\n\n\t\t// Return the cloned set\n\t\treturn clone;\n\t},\n\n\tbuildFragment: function( elems, context, scripts, selection ) {\n\t\tvar j, elem, contains,\n\t\t\ttmp, tag, tbody, wrap,\n\t\t\tl = elems.length,\n\n\t\t\t// Ensure a safe fragment\n\t\t\tsafe = createSafeFragment( context ),\n\n\t\t\tnodes = [],\n\t\t\ti = 0;\n\n\t\tfor ( ; i < l; i++ ) {\n\t\t\telem = elems[ i ];\n\n\t\t\tif ( elem || elem === 0 ) {\n\n\t\t\t\t// Add nodes directly\n\t\t\t\tif ( jQuery.type( elem ) === \"object\" ) {\n\t\t\t\t\tjQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );\n\n\t\t\t\t// Convert non-html into a text node\n\t\t\t\t} else if ( !rhtml.test( elem ) ) {\n\t\t\t\t\tnodes.push( context.createTextNode( elem ) );\n\n\t\t\t\t// Convert html into DOM nodes\n\t\t\t\t} else {\n\t\t\t\t\ttmp = tmp || safe.appendChild( context.createElement(\"div\") );\n\n\t\t\t\t\t// Deserialize a standard representation\n\t\t\t\t\ttag = ( rtagName.exec( elem ) || [\"\", \"\"] )[1].toLowerCase();\n\t\t\t\t\twrap = wrapMap[ tag ] || wrapMap._default;\n\n\t\t\t\t\ttmp.innerHTML = wrap[1] + elem.replace( rxhtmlTag, \"<$1></$2>\" ) + wrap[2];\n\n\t\t\t\t\t// Descend through wrappers to the right content\n\t\t\t\t\tj = wrap[0];\n\t\t\t\t\twhile ( j-- ) {\n\t\t\t\t\t\ttmp = tmp.lastChild;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Manually add leading whitespace removed by IE\n\t\t\t\t\tif ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {\n\t\t\t\t\t\tnodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[0] ) );\n\t\t\t\t\t}\n\n\t\t\t\t\t// Remove IE's autoinserted <tbody> from table fragments\n\t\t\t\t\tif ( !jQuery.support.tbody ) {\n\n\t\t\t\t\t\t// String was a <table>, *may* have spurious <tbody>\n\t\t\t\t\t\telem = tag === \"table\" && !rtbody.test( elem ) ?\n\t\t\t\t\t\t\ttmp.firstChild :\n\n\t\t\t\t\t\t\t// String was a bare <thead> or <tfoot>\n\t\t\t\t\t\t\twrap[1] === \"<table>\" && !rtbody.test( elem ) ?\n\t\t\t\t\t\t\t\ttmp :\n\t\t\t\t\t\t\t\t0;\n\n\t\t\t\t\t\tj = elem && elem.childNodes.length;\n\t\t\t\t\t\twhile ( j-- ) {\n\t\t\t\t\t\t\tif ( jQuery.nodeName( (tbody = elem.childNodes[j]), \"tbody\" ) && !tbody.childNodes.length ) {\n\t\t\t\t\t\t\t\telem.removeChild( tbody );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tjQuery.merge( nodes, tmp.childNodes );\n\n\t\t\t\t\t// Fix #12392 for WebKit and IE > 9\n\t\t\t\t\ttmp.textContent = \"\";\n\n\t\t\t\t\t// Fix #12392 for oldIE\n\t\t\t\t\twhile ( tmp.firstChild ) {\n\t\t\t\t\t\ttmp.removeChild( tmp.firstChild );\n\t\t\t\t\t}\n\n\t\t\t\t\t// Remember the top-level container for proper cleanup\n\t\t\t\t\ttmp = safe.lastChild;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Fix #11356: Clear elements from fragment\n\t\tif ( tmp ) {\n\t\t\tsafe.removeChild( tmp );\n\t\t}\n\n\t\t// Reset defaultChecked for any radios and checkboxes\n\t\t// about to be appended to the DOM in IE 6/7 (#8060)\n\t\tif ( !jQuery.support.appendChecked ) {\n\t\t\tjQuery.grep( getAll( nodes, \"input\" ), fixDefaultChecked );\n\t\t}\n\n\t\ti = 0;\n\t\twhile ( (elem = nodes[ i++ ]) ) {\n\n\t\t\t// #4087 - If origin and destination elements are the same, and this is\n\t\t\t// that element, do not do anything\n\t\t\tif ( selection && jQuery.inArray( elem, selection ) !== -1 ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tcontains = jQuery.contains( elem.ownerDocument, elem );\n\n\t\t\t// Append to fragment\n\t\t\ttmp = getAll( safe.appendChild( elem ), \"script\" );\n\n\t\t\t// Preserve script evaluation history\n\t\t\tif ( contains ) {\n\t\t\t\tsetGlobalEval( tmp );\n\t\t\t}\n\n\t\t\t// Capture executables\n\t\t\tif ( scripts ) {\n\t\t\t\tj = 0;\n\t\t\t\twhile ( (elem = tmp[ j++ ]) ) {\n\t\t\t\t\tif ( rscriptType.test( elem.type || \"\" ) ) {\n\t\t\t\t\t\tscripts.push( elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\ttmp = null;\n\n\t\treturn safe;\n\t},\n\n\tcleanData: function( elems, /* internal */ acceptData ) {\n\t\tvar elem, type, id, data,\n\t\t\ti = 0,\n\t\t\tinternalKey = jQuery.expando,\n\t\t\tcache = jQuery.cache,\n\t\t\tdeleteExpando = jQuery.support.deleteExpando,\n\t\t\tspecial = jQuery.event.special;\n\n\t\tfor ( ; (elem = elems[i]) != null; i++ ) {\n\n\t\t\tif ( acceptData || jQuery.acceptData( elem ) ) {\n\n\t\t\t\tid = elem[ internalKey ];\n\t\t\t\tdata = id && cache[ id ];\n\n\t\t\t\tif ( data ) {\n\t\t\t\t\tif ( data.events ) {\n\t\t\t\t\t\tfor ( type in data.events ) {\n\t\t\t\t\t\t\tif ( special[ type ] ) {\n\t\t\t\t\t\t\t\tjQuery.event.remove( elem, type );\n\n\t\t\t\t\t\t\t// This is a shortcut to avoid jQuery.event.remove's overhead\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tjQuery.removeEvent( elem, type, data.handle );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Remove cache only if it was not already removed by jQuery.event.remove\n\t\t\t\t\tif ( cache[ id ] ) {\n\n\t\t\t\t\t\tdelete cache[ id ];\n\n\t\t\t\t\t\t// IE does not allow us to delete expando properties from nodes,\n\t\t\t\t\t\t// nor does it have a removeAttribute function on Document nodes;\n\t\t\t\t\t\t// we must handle all of these cases\n\t\t\t\t\t\tif ( deleteExpando ) {\n\t\t\t\t\t\t\tdelete elem[ internalKey ];\n\n\t\t\t\t\t\t} else if ( typeof elem.removeAttribute !== core_strundefined ) {\n\t\t\t\t\t\t\telem.removeAttribute( internalKey );\n\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\telem[ internalKey ] = null;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcore_deletedIds.push( id );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n});\nvar iframe, getStyles, curCSS,\n\tralpha = /alpha\\([^)]*\\)/i,\n\tropacity = /opacity\\s*=\\s*([^)]*)/,\n\trposition = /^(top|right|bottom|left)$/,\n\t// swappable if display is none or starts with table except \"table\", \"table-cell\", or \"table-caption\"\n\t// see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display\n\trdisplayswap = /^(none|table(?!-c[ea]).+)/,\n\trmargin = /^margin/,\n\trnumsplit = new RegExp( \"^(\" + core_pnum + \")(.*)$\", \"i\" ),\n\trnumnonpx = new RegExp( \"^(\" + core_pnum + \")(?!px)[a-z%]+$\", \"i\" ),\n\trrelNum = new RegExp( \"^([+-])=(\" + core_pnum + \")\", \"i\" ),\n\telemdisplay = { BODY: \"block\" },\n\n\tcssShow = { position: \"absolute\", visibility: \"hidden\", display: \"block\" },\n\tcssNormalTransform = {\n\t\tletterSpacing: 0,\n\t\tfontWeight: 400\n\t},\n\n\tcssExpand = [ \"Top\", \"Right\", \"Bottom\", \"Left\" ],\n\tcssPrefixes = [ \"Webkit\", \"O\", \"Moz\", \"ms\" ];\n\n// return a css property mapped to a potentially vendor prefixed property\nfunction vendorPropName( style, name ) {\n\n\t// shortcut for names that are not vendor prefixed\n\tif ( name in style ) {\n\t\treturn name;\n\t}\n\n\t// check for vendor prefixed names\n\tvar capName = name.charAt(0).toUpperCase() + name.slice(1),\n\t\torigName = name,\n\t\ti = cssPrefixes.length;\n\n\twhile ( i-- ) {\n\t\tname = cssPrefixes[ i ] + capName;\n\t\tif ( name in style ) {\n\t\t\treturn name;\n\t\t}\n\t}\n\n\treturn origName;\n}\n\nfunction isHidden( elem, el ) {\n\t// isHidden might be called from jQuery#filter function;\n\t// in that case, element will be second argument\n\telem = el || elem;\n\treturn jQuery.css( elem, \"display\" ) === \"none\" || !jQuery.contains( elem.ownerDocument, elem );\n}\n\nfunction showHide( elements, show ) {\n\tvar display, elem, hidden,\n\t\tvalues = [],\n\t\tindex = 0,\n\t\tlength = elements.length;\n\n\tfor ( ; index < length; index++ ) {\n\t\telem = elements[ index ];\n\t\tif ( !elem.style ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tvalues[ index ] = jQuery._data( elem, \"olddisplay\" );\n\t\tdisplay = elem.style.display;\n\t\tif ( show ) {\n\t\t\t// Reset the inline display of this element to learn if it is\n\t\t\t// being hidden by cascaded rules or not\n\t\t\tif ( !values[ index ] && display === \"none\" ) {\n\t\t\t\telem.style.display = \"\";\n\t\t\t}\n\n\t\t\t// Set elements which have been overridden with display: none\n\t\t\t// in a stylesheet to whatever the default browser style is\n\t\t\t// for such an element\n\t\t\tif ( elem.style.display === \"\" && isHidden( elem ) ) {\n\t\t\t\tvalues[ index ] = jQuery._data( elem, \"olddisplay\", css_defaultDisplay(elem.nodeName) );\n\t\t\t}\n\t\t} else {\n\n\t\t\tif ( !values[ index ] ) {\n\t\t\t\thidden = isHidden( elem );\n\n\t\t\t\tif ( display && display !== \"none\" || !hidden ) {\n\t\t\t\t\tjQuery._data( elem, \"olddisplay\", hidden ? display : jQuery.css( elem, \"display\" ) );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Set the display of most of the elements in a second loop\n\t// to avoid the constant reflow\n\tfor ( index = 0; index < length; index++ ) {\n\t\telem = elements[ index ];\n\t\tif ( !elem.style ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( !show || elem.style.display === \"none\" || elem.style.display === \"\" ) {\n\t\t\telem.style.display = show ? values[ index ] || \"\" : \"none\";\n\t\t}\n\t}\n\n\treturn elements;\n}\n\njQuery.fn.extend({\n\tcss: function( name, value ) {\n\t\treturn jQuery.access( this, function( elem, name, value ) {\n\t\t\tvar len, styles,\n\t\t\t\tmap = {},\n\t\t\t\ti = 0;\n\n\t\t\tif ( jQuery.isArray( name ) ) {\n\t\t\t\tstyles = getStyles( elem );\n\t\t\t\tlen = name.length;\n\n\t\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\t\tmap[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );\n\t\t\t\t}\n\n\t\t\t\treturn map;\n\t\t\t}\n\n\t\t\treturn value !== undefined ?\n\t\t\t\tjQuery.style( elem, name, value ) :\n\t\t\t\tjQuery.css( elem, name );\n\t\t}, name, value, arguments.length > 1 );\n\t},\n\tshow: function() {\n\t\treturn showHide( this, true );\n\t},\n\thide: function() {\n\t\treturn showHide( this );\n\t},\n\ttoggle: function( state ) {\n\t\tvar bool = typeof state === \"boolean\";\n\n\t\treturn this.each(function() {\n\t\t\tif ( bool ? state : isHidden( this ) ) {\n\t\t\t\tjQuery( this ).show();\n\t\t\t} else {\n\t\t\t\tjQuery( this ).hide();\n\t\t\t}\n\t\t});\n\t}\n});\n\njQuery.extend({\n\t// Add in style property hooks for overriding the default\n\t// behavior of getting and setting a style property\n\tcssHooks: {\n\t\topacity: {\n\t\t\tget: function( elem, computed ) {\n\t\t\t\tif ( computed ) {\n\t\t\t\t\t// We should always get a number back from opacity\n\t\t\t\t\tvar ret = curCSS( elem, \"opacity\" );\n\t\t\t\t\treturn ret === \"\" ? \"1\" : ret;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\t// Exclude the following css properties to add px\n\tcssNumber: {\n\t\t\"columnCount\": true,\n\t\t\"fillOpacity\": true,\n\t\t\"fontWeight\": true,\n\t\t\"lineHeight\": true,\n\t\t\"opacity\": true,\n\t\t\"orphans\": true,\n\t\t\"widows\": true,\n\t\t\"zIndex\": true,\n\t\t\"zoom\": true\n\t},\n\n\t// Add in properties whose names you wish to fix before\n\t// setting or getting the value\n\tcssProps: {\n\t\t// normalize float css property\n\t\t\"float\": jQuery.support.cssFloat ? \"cssFloat\" : \"styleFloat\"\n\t},\n\n\t// Get and set the style property on a DOM Node\n\tstyle: function( elem, name, value, extra ) {\n\t\t// Don't set styles on text and comment nodes\n\t\tif ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Make sure that we're working with the right name\n\t\tvar ret, type, hooks,\n\t\t\torigName = jQuery.camelCase( name ),\n\t\t\tstyle = elem.style;\n\n\t\tname = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );\n\n\t\t// gets hook for the prefixed version\n\t\t// followed by the unprefixed version\n\t\thooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];\n\n\t\t// Check if we're setting a value\n\t\tif ( value !== undefined ) {\n\t\t\ttype = typeof value;\n\n\t\t\t// convert relative number strings (+= or -=) to relative numbers. #7345\n\t\t\tif ( type === \"string\" && (ret = rrelNum.exec( value )) ) {\n\t\t\t\tvalue = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );\n\t\t\t\t// Fixes bug #9237\n\t\t\t\ttype = \"number\";\n\t\t\t}\n\n\t\t\t// Make sure that NaN and null values aren't set. See: #7116\n\t\t\tif ( value == null || type === \"number\" && isNaN( value ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// If a number was passed in, add 'px' to the (except for certain CSS properties)\n\t\t\tif ( type === \"number\" && !jQuery.cssNumber[ origName ] ) {\n\t\t\t\tvalue += \"px\";\n\t\t\t}\n\n\t\t\t// Fixes #8908, it can be done more correctly by specifing setters in cssHooks,\n\t\t\t// but it would mean to define eight (for every problematic property) identical functions\n\t\t\tif ( !jQuery.support.clearCloneStyle && value === \"\" && name.indexOf(\"background\") === 0 ) {\n\t\t\t\tstyle[ name ] = \"inherit\";\n\t\t\t}\n\n\t\t\t// If a hook was provided, use that value, otherwise just set the specified value\n\t\t\tif ( !hooks || !(\"set\" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {\n\n\t\t\t\t// Wrapped to prevent IE from throwing errors when 'invalid' values are provided\n\t\t\t\t// Fixes bug #5509\n\t\t\t\ttry {\n\t\t\t\t\tstyle[ name ] = value;\n\t\t\t\t} catch(e) {}\n\t\t\t}\n\n\t\t} else {\n\t\t\t// If a hook was provided get the non-computed value from there\n\t\t\tif ( hooks && \"get\" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\t// Otherwise just get the value from the style object\n\t\t\treturn style[ name ];\n\t\t}\n\t},\n\n\tcss: function( elem, name, extra, styles ) {\n\t\tvar num, val, hooks,\n\t\t\torigName = jQuery.camelCase( name );\n\n\t\t// Make sure that we're working with the right name\n\t\tname = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );\n\n\t\t// gets hook for the prefixed version\n\t\t// followed by the unprefixed version\n\t\thooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];\n\n\t\t// If a hook was provided get the computed value from there\n\t\tif ( hooks && \"get\" in hooks ) {\n\t\t\tval = hooks.get( elem, true, extra );\n\t\t}\n\n\t\t// Otherwise, if a way to get the computed value exists, use that\n\t\tif ( val === undefined ) {\n\t\t\tval = curCSS( elem, name, styles );\n\t\t}\n\n\t\t//convert \"normal\" to computed value\n\t\tif ( val === \"normal\" && name in cssNormalTransform ) {\n\t\t\tval = cssNormalTransform[ name ];\n\t\t}\n\n\t\t// Return, converting to number if forced or a qualifier was provided and val looks numeric\n\t\tif ( extra === \"\" || extra ) {\n\t\t\tnum = parseFloat( val );\n\t\t\treturn extra === true || jQuery.isNumeric( num ) ? num || 0 : val;\n\t\t}\n\t\treturn val;\n\t},\n\n\t// A method for quickly swapping in/out CSS properties to get correct calculations\n\tswap: function( elem, options, callback, args ) {\n\t\tvar ret, name,\n\t\t\told = {};\n\n\t\t// Remember the old values, and insert the new ones\n\t\tfor ( name in options ) {\n\t\t\told[ name ] = elem.style[ name ];\n\t\t\telem.style[ name ] = options[ name ];\n\t\t}\n\n\t\tret = callback.apply( elem, args || [] );\n\n\t\t// Revert the old values\n\t\tfor ( name in options ) {\n\t\t\telem.style[ name ] = old[ name ];\n\t\t}\n\n\t\treturn ret;\n\t}\n});\n\n// NOTE: we've included the \"window\" in window.getComputedStyle\n// because jsdom on node.js will break without it.\nif ( window.getComputedStyle ) {\n\tgetStyles = function( elem ) {\n\t\treturn window.getComputedStyle( elem, null );\n\t};\n\n\tcurCSS = function( elem, name, _computed ) {\n\t\tvar width, minWidth, maxWidth,\n\t\t\tcomputed = _computed || getStyles( elem ),\n\n\t\t\t// getPropertyValue is only needed for .css('filter') in IE9, see #12537\n\t\t\tret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined,\n\t\t\tstyle = elem.style;\n\n\t\tif ( computed ) {\n\n\t\t\tif ( ret === \"\" && !jQuery.contains( elem.ownerDocument, elem ) ) {\n\t\t\t\tret = jQuery.style( elem, name );\n\t\t\t}\n\n\t\t\t// A tribute to the \"awesome hack by Dean Edwards\"\n\t\t\t// Chrome < 17 and Safari 5.0 uses \"computed value\" instead of \"used value\" for margin-right\n\t\t\t// Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels\n\t\t\t// this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values\n\t\t\tif ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {\n\n\t\t\t\t// Remember the original values\n\t\t\t\twidth = style.width;\n\t\t\t\tminWidth = style.minWidth;\n\t\t\t\tmaxWidth = style.maxWidth;\n\n\t\t\t\t// Put in the new values to get a computed value out\n\t\t\t\tstyle.minWidth = style.maxWidth = style.width = ret;\n\t\t\t\tret = computed.width;\n\n\t\t\t\t// Revert the changed values\n\t\t\t\tstyle.width = width;\n\t\t\t\tstyle.minWidth = minWidth;\n\t\t\t\tstyle.maxWidth = maxWidth;\n\t\t\t}\n\t\t}\n\n\t\treturn ret;\n\t};\n} else if ( document.documentElement.currentStyle ) {\n\tgetStyles = function( elem ) {\n\t\treturn elem.currentStyle;\n\t};\n\n\tcurCSS = function( elem, name, _computed ) {\n\t\tvar left, rs, rsLeft,\n\t\t\tcomputed = _computed || getStyles( elem ),\n\t\t\tret = computed ? computed[ name ] : undefined,\n\t\t\tstyle = elem.style;\n\n\t\t// Avoid setting ret to empty string here\n\t\t// so we don't default to auto\n\t\tif ( ret == null && style && style[ name ] ) {\n\t\t\tret = style[ name ];\n\t\t}\n\n\t\t// From the awesome hack by Dean Edwards\n\t\t// http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291\n\n\t\t// If we're not dealing with a regular pixel number\n\t\t// but a number that has a weird ending, we need to convert it to pixels\n\t\t// but not position css attributes, as those are proportional to the parent element instead\n\t\t// and we can't measure the parent instead because it might trigger a \"stacking dolls\" problem\n\t\tif ( rnumnonpx.test( ret ) && !rposition.test( name ) ) {\n\n\t\t\t// Remember the original values\n\t\t\tleft = style.left;\n\t\t\trs = elem.runtimeStyle;\n\t\t\trsLeft = rs && rs.left;\n\n\t\t\t// Put in the new values to get a computed value out\n\t\t\tif ( rsLeft ) {\n\t\t\t\trs.left = elem.currentStyle.left;\n\t\t\t}\n\t\t\tstyle.left = name === \"fontSize\" ? \"1em\" : ret;\n\t\t\tret = style.pixelLeft + \"px\";\n\n\t\t\t// Revert the changed values\n\t\t\tstyle.left = left;\n\t\t\tif ( rsLeft ) {\n\t\t\t\trs.left = rsLeft;\n\t\t\t}\n\t\t}\n\n\t\treturn ret === \"\" ? \"auto\" : ret;\n\t};\n}\n\nfunction setPositiveNumber( elem, value, subtract ) {\n\tvar matches = rnumsplit.exec( value );\n\treturn matches ?\n\t\t// Guard against undefined \"subtract\", e.g., when used as in cssHooks\n\t\tMath.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || \"px\" ) :\n\t\tvalue;\n}\n\nfunction augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {\n\tvar i = extra === ( isBorderBox ? \"border\" : \"content\" ) ?\n\t\t// If we already have the right measurement, avoid augmentation\n\t\t4 :\n\t\t// Otherwise initialize for horizontal or vertical properties\n\t\tname === \"width\" ? 1 : 0,\n\n\t\tval = 0;\n\n\tfor ( ; i < 4; i += 2 ) {\n\t\t// both box models exclude margin, so add it if we want it\n\t\tif ( extra === \"margin\" ) {\n\t\t\tval += jQuery.css( elem, extra + cssExpand[ i ], true, styles );\n\t\t}\n\n\t\tif ( isBorderBox ) {\n\t\t\t// border-box includes padding, so remove it if we want content\n\t\t\tif ( extra === \"content\" ) {\n\t\t\t\tval -= jQuery.css( elem, \"padding\" + cssExpand[ i ], true, styles );\n\t\t\t}\n\n\t\t\t// at this point, extra isn't border nor margin, so remove border\n\t\t\tif ( extra !== \"margin\" ) {\n\t\t\t\tval -= jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\t\t\t}\n\t\t} else {\n\t\t\t// at this point, extra isn't content, so add padding\n\t\t\tval += jQuery.css( elem, \"padding\" + cssExpand[ i ], true, styles );\n\n\t\t\t// at this point, extra isn't content nor padding, so add border\n\t\t\tif ( extra !== \"padding\" ) {\n\t\t\t\tval += jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\t\t\t}\n\t\t}\n\t}\n\n\treturn val;\n}\n\nfunction getWidthOrHeight( elem, name, extra ) {\n\n\t// Start with offset property, which is equivalent to the border-box value\n\tvar valueIsBorderBox = true,\n\t\tval = name === \"width\" ? elem.offsetWidth : elem.offsetHeight,\n\t\tstyles = getStyles( elem ),\n\t\tisBorderBox = jQuery.support.boxSizing && jQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\";\n\n\t// some non-html elements return undefined for offsetWidth, so check for null/undefined\n\t// svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285\n\t// MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668\n\tif ( val <= 0 || val == null ) {\n\t\t// Fall back to computed then uncomputed css if necessary\n\t\tval = curCSS( elem, name, styles );\n\t\tif ( val < 0 || val == null ) {\n\t\t\tval = elem.style[ name ];\n\t\t}\n\n\t\t// Computed unit is not pixels. Stop here and return.\n\t\tif ( rnumnonpx.test(val) ) {\n\t\t\treturn val;\n\t\t}\n\n\t\t// we need the check for style in case a browser which returns unreliable values\n\t\t// for getComputedStyle silently falls back to the reliable elem.style\n\t\tvalueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] );\n\n\t\t// Normalize \"\", auto, and prepare for extra\n\t\tval = parseFloat( val ) || 0;\n\t}\n\n\t// use the active box-sizing model to add/subtract irrelevant styles\n\treturn ( val +\n\t\taugmentWidthOrHeight(\n\t\t\telem,\n\t\t\tname,\n\t\t\textra || ( isBorderBox ? \"border\" : \"content\" ),\n\t\t\tvalueIsBorderBox,\n\t\t\tstyles\n\t\t)\n\t) + \"px\";\n}\n\n// Try to determine the default display value of an element\nfunction css_defaultDisplay( nodeName ) {\n\tvar doc = document,\n\t\tdisplay = elemdisplay[ nodeName ];\n\n\tif ( !display ) {\n\t\tdisplay = actualDisplay( nodeName, doc );\n\n\t\t// If the simple way fails, read from inside an iframe\n\t\tif ( display === \"none\" || !display ) {\n\t\t\t// Use the already-created iframe if possible\n\t\t\tiframe = ( iframe ||\n\t\t\t\tjQuery(\"<iframe frameborder='0' width='0' height='0'/>\")\n\t\t\t\t.css( \"cssText\", \"display:block !important\" )\n\t\t\t).appendTo( doc.documentElement );\n\n\t\t\t// Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse\n\t\t\tdoc = ( iframe[0].contentWindow || iframe[0].contentDocument ).document;\n\t\t\tdoc.write(\"<!doctype html><html><body>\");\n\t\t\tdoc.close();\n\n\t\t\tdisplay = actualDisplay( nodeName, doc );\n\t\t\tiframe.detach();\n\t\t}\n\n\t\t// Store the correct default display\n\t\telemdisplay[ nodeName ] = display;\n\t}\n\n\treturn display;\n}\n\n// Called ONLY from within css_defaultDisplay\nfunction actualDisplay( name, doc ) {\n\tvar elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),\n\t\tdisplay = jQuery.css( elem[0], \"display\" );\n\telem.remove();\n\treturn display;\n}\n\njQuery.each([ \"height\", \"width\" ], function( i, name ) {\n\tjQuery.cssHooks[ name ] = {\n\t\tget: function( elem, computed, extra ) {\n\t\t\tif ( computed ) {\n\t\t\t\t// certain elements can have dimension info if we invisibly show them\n\t\t\t\t// however, it must have a current display style that would benefit from this\n\t\t\t\treturn elem.offsetWidth === 0 && rdisplayswap.test( jQuery.css( elem, \"display\" ) ) ?\n\t\t\t\t\tjQuery.swap( elem, cssShow, function() {\n\t\t\t\t\t\treturn getWidthOrHeight( elem, name, extra );\n\t\t\t\t\t}) :\n\t\t\t\t\tgetWidthOrHeight( elem, name, extra );\n\t\t\t}\n\t\t},\n\n\t\tset: function( elem, value, extra ) {\n\t\t\tvar styles = extra && getStyles( elem );\n\t\t\treturn setPositiveNumber( elem, value, extra ?\n\t\t\t\taugmentWidthOrHeight(\n\t\t\t\t\telem,\n\t\t\t\t\tname,\n\t\t\t\t\textra,\n\t\t\t\t\tjQuery.support.boxSizing && jQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\",\n\t\t\t\t\tstyles\n\t\t\t\t) : 0\n\t\t\t);\n\t\t}\n\t};\n});\n\nif ( !jQuery.support.opacity ) {\n\tjQuery.cssHooks.opacity = {\n\t\tget: function( elem, computed ) {\n\t\t\t// IE uses filters for opacity\n\t\t\treturn ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || \"\" ) ?\n\t\t\t\t( 0.01 * parseFloat( RegExp.$1 ) ) + \"\" :\n\t\t\t\tcomputed ? \"1\" : \"\";\n\t\t},\n\n\t\tset: function( elem, value ) {\n\t\t\tvar style = elem.style,\n\t\t\t\tcurrentStyle = elem.currentStyle,\n\t\t\t\topacity = jQuery.isNumeric( value ) ? \"alpha(opacity=\" + value * 100 + \")\" : \"\",\n\t\t\t\tfilter = currentStyle && currentStyle.filter || style.filter || \"\";\n\n\t\t\t// IE has trouble with opacity if it does not have layout\n\t\t\t// Force it by setting the zoom level\n\t\t\tstyle.zoom = 1;\n\n\t\t\t// if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652\n\t\t\t// if value === \"\", then remove inline opacity #12685\n\t\t\tif ( ( value >= 1 || value === \"\" ) &&\n\t\t\t\t\tjQuery.trim( filter.replace( ralpha, \"\" ) ) === \"\" &&\n\t\t\t\t\tstyle.removeAttribute ) {\n\n\t\t\t\t// Setting style.filter to null, \"\" & \" \" still leave \"filter:\" in the cssText\n\t\t\t\t// if \"filter:\" is present at all, clearType is disabled, we want to avoid this\n\t\t\t\t// style.removeAttribute is IE Only, but so apparently is this code path...\n\t\t\t\tstyle.removeAttribute( \"filter\" );\n\n\t\t\t\t// if there is no filter style applied in a css rule or unset inline opacity, we are done\n\t\t\t\tif ( value === \"\" || currentStyle && !currentStyle.filter ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// otherwise, set new filter values\n\t\t\tstyle.filter = ralpha.test( filter ) ?\n\t\t\t\tfilter.replace( ralpha, opacity ) :\n\t\t\t\tfilter + \" \" + opacity;\n\t\t}\n\t};\n}\n\n// These hooks cannot be added until DOM ready because the support test\n// for it is not run until after DOM ready\njQuery(function() {\n\tif ( !jQuery.support.reliableMarginRight ) {\n\t\tjQuery.cssHooks.marginRight = {\n\t\t\tget: function( elem, computed ) {\n\t\t\t\tif ( computed ) {\n\t\t\t\t\t// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right\n\t\t\t\t\t// Work around by temporarily setting element display to inline-block\n\t\t\t\t\treturn jQuery.swap( elem, { \"display\": \"inline-block\" },\n\t\t\t\t\t\tcurCSS, [ elem, \"marginRight\" ] );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n\n\t// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084\n\t// getComputedStyle returns percent when specified for top/left/bottom/right\n\t// rather than make the css module depend on the offset module, we just check for it here\n\tif ( !jQuery.support.pixelPosition && jQuery.fn.position ) {\n\t\tjQuery.each( [ \"top\", \"left\" ], function( i, prop ) {\n\t\t\tjQuery.cssHooks[ prop ] = {\n\t\t\t\tget: function( elem, computed ) {\n\t\t\t\t\tif ( computed ) {\n\t\t\t\t\t\tcomputed = curCSS( elem, prop );\n\t\t\t\t\t\t// if curCSS returns percentage, fallback to offset\n\t\t\t\t\t\treturn rnumnonpx.test( computed ) ?\n\t\t\t\t\t\t\tjQuery( elem ).position()[ prop ] + \"px\" :\n\t\t\t\t\t\t\tcomputed;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\t\t});\n\t}\n\n});\n\nif ( jQuery.expr && jQuery.expr.filters ) {\n\tjQuery.expr.filters.hidden = function( elem ) {\n\t\t// Support: Opera <= 12.12\n\t\t// Opera reports offsetWidths and offsetHeights less than zero on some elements\n\t\treturn elem.offsetWidth <= 0 && elem.offsetHeight <= 0 ||\n\t\t\t(!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || jQuery.css( elem, \"display\" )) === \"none\");\n\t};\n\n\tjQuery.expr.filters.visible = function( elem ) {\n\t\treturn !jQuery.expr.filters.hidden( elem );\n\t};\n}\n\n// These hooks are used by animate to expand properties\njQuery.each({\n\tmargin: \"\",\n\tpadding: \"\",\n\tborder: \"Width\"\n}, function( prefix, suffix ) {\n\tjQuery.cssHooks[ prefix + suffix ] = {\n\t\texpand: function( value ) {\n\t\t\tvar i = 0,\n\t\t\t\texpanded = {},\n\n\t\t\t\t// assumes a single number if not a string\n\t\t\t\tparts = typeof value === \"string\" ? value.split(\" \") : [ value ];\n\n\t\t\tfor ( ; i < 4; i++ ) {\n\t\t\t\texpanded[ prefix + cssExpand[ i ] + suffix ] =\n\t\t\t\t\tparts[ i ] || parts[ i - 2 ] || parts[ 0 ];\n\t\t\t}\n\n\t\t\treturn expanded;\n\t\t}\n\t};\n\n\tif ( !rmargin.test( prefix ) ) {\n\t\tjQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;\n\t}\n});\nvar r20 = /%20/g,\n\trbracket = /\\[\\]$/,\n\trCRLF = /\\r?\\n/g,\n\trsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,\n\trsubmittable = /^(?:input|select|textarea|keygen)/i;\n\njQuery.fn.extend({\n\tserialize: function() {\n\t\treturn jQuery.param( this.serializeArray() );\n\t},\n\tserializeArray: function() {\n\t\treturn this.map(function(){\n\t\t\t// Can add propHook for \"elements\" to filter or add form elements\n\t\t\tvar elements = jQuery.prop( this, \"elements\" );\n\t\t\treturn elements ? jQuery.makeArray( elements ) : this;\n\t\t})\n\t\t.filter(function(){\n\t\t\tvar type = this.type;\n\t\t\t// Use .is(\":disabled\") so that fieldset[disabled] works\n\t\t\treturn this.name && !jQuery( this ).is( \":disabled\" ) &&\n\t\t\t\trsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&\n\t\t\t\t( this.checked || !manipulation_rcheckableType.test( type ) );\n\t\t})\n\t\t.map(function( i, elem ){\n\t\t\tvar val = jQuery( this ).val();\n\n\t\t\treturn val == null ?\n\t\t\t\tnull :\n\t\t\t\tjQuery.isArray( val ) ?\n\t\t\t\t\tjQuery.map( val, function( val ){\n\t\t\t\t\t\treturn { name: elem.name, value: val.replace( rCRLF, \"\\r\\n\" ) };\n\t\t\t\t\t}) :\n\t\t\t\t\t{ name: elem.name, value: val.replace( rCRLF, \"\\r\\n\" ) };\n\t\t}).get();\n\t}\n});\n\n//Serialize an array of form elements or a set of\n//key/values into a query string\njQuery.param = function( a, traditional ) {\n\tvar prefix,\n\t\ts = [],\n\t\tadd = function( key, value ) {\n\t\t\t// If value is a function, invoke it and return its value\n\t\t\tvalue = jQuery.isFunction( value ) ? value() : ( value == null ? \"\" : value );\n\t\t\ts[ s.length ] = encodeURIComponent( key ) + \"=\" + encodeURIComponent( value );\n\t\t};\n\n\t// Set traditional to true for jQuery <= 1.3.2 behavior.\n\tif ( traditional === undefined ) {\n\t\ttraditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;\n\t}\n\n\t// If an array was passed in, assume that it is an array of form elements.\n\tif ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {\n\t\t// Serialize the form elements\n\t\tjQuery.each( a, function() {\n\t\t\tadd( this.name, this.value );\n\t\t});\n\n\t} else {\n\t\t// If traditional, encode the \"old\" way (the way 1.3.2 or older\n\t\t// did it), otherwise encode params recursively.\n\t\tfor ( prefix in a ) {\n\t\t\tbuildParams( prefix, a[ prefix ], traditional, add );\n\t\t}\n\t}\n\n\t// Return the resulting serialization\n\treturn s.join( \"&\" ).replace( r20, \"+\" );\n};\n\nfunction buildParams( prefix, obj, traditional, add ) {\n\tvar name;\n\n\tif ( jQuery.isArray( obj ) ) {\n\t\t// Serialize array item.\n\t\tjQuery.each( obj, function( i, v ) {\n\t\t\tif ( traditional || rbracket.test( prefix ) ) {\n\t\t\t\t// Treat each array item as a scalar.\n\t\t\t\tadd( prefix, v );\n\n\t\t\t} else {\n\t\t\t\t// Item is non-scalar (array or object), encode its numeric index.\n\t\t\t\tbuildParams( prefix + \"[\" + ( typeof v === \"object\" ? i : \"\" ) + \"]\", v, traditional, add );\n\t\t\t}\n\t\t});\n\n\t} else if ( !traditional && jQuery.type( obj ) === \"object\" ) {\n\t\t// Serialize object item.\n\t\tfor ( name in obj ) {\n\t\t\tbuildParams( prefix + \"[\" + name + \"]\", obj[ name ], traditional, add );\n\t\t}\n\n\t} else {\n\t\t// Serialize scalar item.\n\t\tadd( prefix, obj );\n\t}\n}\njQuery.each( (\"blur focus focusin focusout load resize scroll unload click dblclick \" +\n\t\"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave \" +\n\t\"change select submit keydown keypress keyup error contextmenu\").split(\" \"), function( i, name ) {\n\n\t// Handle event binding\n\tjQuery.fn[ name ] = function( data, fn ) {\n\t\treturn arguments.length > 0 ?\n\t\t\tthis.on( name, null, data, fn ) :\n\t\t\tthis.trigger( name );\n\t};\n});\n\njQuery.fn.hover = function( fnOver, fnOut ) {\n\treturn this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );\n};\nvar\n\t// Document location\n\tajaxLocParts,\n\tajaxLocation,\n\tajax_nonce = jQuery.now(),\n\n\tajax_rquery = /\\?/,\n\trhash = /#.*$/,\n\trts = /([?&])_=[^&]*/,\n\trheaders = /^(.*?):[ \\t]*([^\\r\\n]*)\\r?$/mg, // IE leaves an \\r character at EOL\n\t// #7653, #8125, #8152: local protocol detection\n\trlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,\n\trnoContent = /^(?:GET|HEAD)$/,\n\trprotocol = /^\\/\\//,\n\trurl = /^([\\w.+-]+:)(?:\\/\\/([^\\/?#:]*)(?::(\\d+)|)|)/,\n\n\t// Keep a copy of the old load method\n\t_load = jQuery.fn.load,\n\n\t/* Prefilters\n\t * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)\n\t * 2) These are called:\n\t *    - BEFORE asking for a transport\n\t *    - AFTER param serialization (s.data is a string if s.processData is true)\n\t * 3) key is the dataType\n\t * 4) the catchall symbol \"*\" can be used\n\t * 5) execution will start with transport dataType and THEN continue down to \"*\" if needed\n\t */\n\tprefilters = {},\n\n\t/* Transports bindings\n\t * 1) key is the dataType\n\t * 2) the catchall symbol \"*\" can be used\n\t * 3) selection will start with transport dataType and THEN go to \"*\" if needed\n\t */\n\ttransports = {},\n\n\t// Avoid comment-prolog char sequence (#10098); must appease lint and evade compression\n\tallTypes = \"*/\".concat(\"*\");\n\n// #8138, IE may throw an exception when accessing\n// a field from window.location if document.domain has been set\ntry {\n\tajaxLocation = location.href;\n} catch( e ) {\n\t// Use the href attribute of an A element\n\t// since IE will modify it given document.location\n\tajaxLocation = document.createElement( \"a\" );\n\tajaxLocation.href = \"\";\n\tajaxLocation = ajaxLocation.href;\n}\n\n// Segment location into parts\najaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];\n\n// Base \"constructor\" for jQuery.ajaxPrefilter and jQuery.ajaxTransport\nfunction addToPrefiltersOrTransports( structure ) {\n\n\t// dataTypeExpression is optional and defaults to \"*\"\n\treturn function( dataTypeExpression, func ) {\n\n\t\tif ( typeof dataTypeExpression !== \"string\" ) {\n\t\t\tfunc = dataTypeExpression;\n\t\t\tdataTypeExpression = \"*\";\n\t\t}\n\n\t\tvar dataType,\n\t\t\ti = 0,\n\t\t\tdataTypes = dataTypeExpression.toLowerCase().match( core_rnotwhite ) || [];\n\n\t\tif ( jQuery.isFunction( func ) ) {\n\t\t\t// For each dataType in the dataTypeExpression\n\t\t\twhile ( (dataType = dataTypes[i++]) ) {\n\t\t\t\t// Prepend if requested\n\t\t\t\tif ( dataType[0] === \"+\" ) {\n\t\t\t\t\tdataType = dataType.slice( 1 ) || \"*\";\n\t\t\t\t\t(structure[ dataType ] = structure[ dataType ] || []).unshift( func );\n\n\t\t\t\t// Otherwise append\n\t\t\t\t} else {\n\t\t\t\t\t(structure[ dataType ] = structure[ dataType ] || []).push( func );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n}\n\n// Base inspection function for prefilters and transports\nfunction inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {\n\n\tvar inspected = {},\n\t\tseekingTransport = ( structure === transports );\n\n\tfunction inspect( dataType ) {\n\t\tvar selected;\n\t\tinspected[ dataType ] = true;\n\t\tjQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {\n\t\t\tvar dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );\n\t\t\tif( typeof dataTypeOrTransport === \"string\" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) {\n\t\t\t\toptions.dataTypes.unshift( dataTypeOrTransport );\n\t\t\t\tinspect( dataTypeOrTransport );\n\t\t\t\treturn false;\n\t\t\t} else if ( seekingTransport ) {\n\t\t\t\treturn !( selected = dataTypeOrTransport );\n\t\t\t}\n\t\t});\n\t\treturn selected;\n\t}\n\n\treturn inspect( options.dataTypes[ 0 ] ) || !inspected[ \"*\" ] && inspect( \"*\" );\n}\n\n// A special extend for ajax options\n// that takes \"flat\" options (not to be deep extended)\n// Fixes #9887\nfunction ajaxExtend( target, src ) {\n\tvar deep, key,\n\t\tflatOptions = jQuery.ajaxSettings.flatOptions || {};\n\n\tfor ( key in src ) {\n\t\tif ( src[ key ] !== undefined ) {\n\t\t\t( flatOptions[ key ] ? target : ( deep || (deep = {}) ) )[ key ] = src[ key ];\n\t\t}\n\t}\n\tif ( deep ) {\n\t\tjQuery.extend( true, target, deep );\n\t}\n\n\treturn target;\n}\n\njQuery.fn.load = function( url, params, callback ) {\n\tif ( typeof url !== \"string\" && _load ) {\n\t\treturn _load.apply( this, arguments );\n\t}\n\n\tvar selector, response, type,\n\t\tself = this,\n\t\toff = url.indexOf(\" \");\n\n\tif ( off >= 0 ) {\n\t\tselector = url.slice( off, url.length );\n\t\turl = url.slice( 0, off );\n\t}\n\n\t// If it's a function\n\tif ( jQuery.isFunction( params ) ) {\n\n\t\t// We assume that it's the callback\n\t\tcallback = params;\n\t\tparams = undefined;\n\n\t// Otherwise, build a param string\n\t} else if ( params && typeof params === \"object\" ) {\n\t\ttype = \"POST\";\n\t}\n\n\t// If we have elements to modify, make the request\n\tif ( self.length > 0 ) {\n\t\tjQuery.ajax({\n\t\t\turl: url,\n\n\t\t\t// if \"type\" variable is undefined, then \"GET\" method will be used\n\t\t\ttype: type,\n\t\t\tdataType: \"html\",\n\t\t\tdata: params\n\t\t}).done(function( responseText ) {\n\n\t\t\t// Save response for use in complete callback\n\t\t\tresponse = arguments;\n\n\t\t\tself.html( selector ?\n\n\t\t\t\t// If a selector was specified, locate the right elements in a dummy div\n\t\t\t\t// Exclude scripts to avoid IE 'Permission Denied' errors\n\t\t\t\tjQuery(\"<div>\").append( jQuery.parseHTML( responseText ) ).find( selector ) :\n\n\t\t\t\t// Otherwise use the full result\n\t\t\t\tresponseText );\n\n\t\t}).complete( callback && function( jqXHR, status ) {\n\t\t\tself.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );\n\t\t});\n\t}\n\n\treturn this;\n};\n\n// Attach a bunch of functions for handling common AJAX events\njQuery.each( [ \"ajaxStart\", \"ajaxStop\", \"ajaxComplete\", \"ajaxError\", \"ajaxSuccess\", \"ajaxSend\" ], function( i, type ){\n\tjQuery.fn[ type ] = function( fn ){\n\t\treturn this.on( type, fn );\n\t};\n});\n\njQuery.each( [ \"get\", \"post\" ], function( i, method ) {\n\tjQuery[ method ] = function( url, data, callback, type ) {\n\t\t// shift arguments if data argument was omitted\n\t\tif ( jQuery.isFunction( data ) ) {\n\t\t\ttype = type || callback;\n\t\t\tcallback = data;\n\t\t\tdata = undefined;\n\t\t}\n\n\t\treturn jQuery.ajax({\n\t\t\turl: url,\n\t\t\ttype: method,\n\t\t\tdataType: type,\n\t\t\tdata: data,\n\t\t\tsuccess: callback\n\t\t});\n\t};\n});\n\njQuery.extend({\n\n\t// Counter for holding the number of active queries\n\tactive: 0,\n\n\t// Last-Modified header cache for next request\n\tlastModified: {},\n\tetag: {},\n\n\tajaxSettings: {\n\t\turl: ajaxLocation,\n\t\ttype: \"GET\",\n\t\tisLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),\n\t\tglobal: true,\n\t\tprocessData: true,\n\t\tasync: true,\n\t\tcontentType: \"application/x-www-form-urlencoded; charset=UTF-8\",\n\t\t/*\n\t\ttimeout: 0,\n\t\tdata: null,\n\t\tdataType: null,\n\t\tusername: null,\n\t\tpassword: null,\n\t\tcache: null,\n\t\tthrows: false,\n\t\ttraditional: false,\n\t\theaders: {},\n\t\t*/\n\n\t\taccepts: {\n\t\t\t\"*\": allTypes,\n\t\t\ttext: \"text/plain\",\n\t\t\thtml: \"text/html\",\n\t\t\txml: \"application/xml, text/xml\",\n\t\t\tjson: \"application/json, text/javascript\"\n\t\t},\n\n\t\tcontents: {\n\t\t\txml: /xml/,\n\t\t\thtml: /html/,\n\t\t\tjson: /json/\n\t\t},\n\n\t\tresponseFields: {\n\t\t\txml: \"responseXML\",\n\t\t\ttext: \"responseText\"\n\t\t},\n\n\t\t// Data converters\n\t\t// Keys separate source (or catchall \"*\") and destination types with a single space\n\t\tconverters: {\n\n\t\t\t// Convert anything to text\n\t\t\t\"* text\": window.String,\n\n\t\t\t// Text to html (true = no transformation)\n\t\t\t\"text html\": true,\n\n\t\t\t// Evaluate text as a json expression\n\t\t\t\"text json\": jQuery.parseJSON,\n\n\t\t\t// Parse text as xml\n\t\t\t\"text xml\": jQuery.parseXML\n\t\t},\n\n\t\t// For options that shouldn't be deep extended:\n\t\t// you can add your own custom options here if\n\t\t// and when you create one that shouldn't be\n\t\t// deep extended (see ajaxExtend)\n\t\tflatOptions: {\n\t\t\turl: true,\n\t\t\tcontext: true\n\t\t}\n\t},\n\n\t// Creates a full fledged settings object into target\n\t// with both ajaxSettings and settings fields.\n\t// If target is omitted, writes into ajaxSettings.\n\tajaxSetup: function( target, settings ) {\n\t\treturn settings ?\n\n\t\t\t// Building a settings object\n\t\t\tajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :\n\n\t\t\t// Extending ajaxSettings\n\t\t\tajaxExtend( jQuery.ajaxSettings, target );\n\t},\n\n\tajaxPrefilter: addToPrefiltersOrTransports( prefilters ),\n\tajaxTransport: addToPrefiltersOrTransports( transports ),\n\n\t// Main method\n\tajax: function( url, options ) {\n\n\t\t// If url is an object, simulate pre-1.5 signature\n\t\tif ( typeof url === \"object\" ) {\n\t\t\toptions = url;\n\t\t\turl = undefined;\n\t\t}\n\n\t\t// Force options to be an object\n\t\toptions = options || {};\n\n\t\tvar // Cross-domain detection vars\n\t\t\tparts,\n\t\t\t// Loop variable\n\t\t\ti,\n\t\t\t// URL without anti-cache param\n\t\t\tcacheURL,\n\t\t\t// Response headers as string\n\t\t\tresponseHeadersString,\n\t\t\t// timeout handle\n\t\t\ttimeoutTimer,\n\n\t\t\t// To know if global events are to be dispatched\n\t\t\tfireGlobals,\n\n\t\t\ttransport,\n\t\t\t// Response headers\n\t\t\tresponseHeaders,\n\t\t\t// Create the final options object\n\t\t\ts = jQuery.ajaxSetup( {}, options ),\n\t\t\t// Callbacks context\n\t\t\tcallbackContext = s.context || s,\n\t\t\t// Context for global events is callbackContext if it is a DOM node or jQuery collection\n\t\t\tglobalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ?\n\t\t\t\tjQuery( callbackContext ) :\n\t\t\t\tjQuery.event,\n\t\t\t// Deferreds\n\t\t\tdeferred = jQuery.Deferred(),\n\t\t\tcompleteDeferred = jQuery.Callbacks(\"once memory\"),\n\t\t\t// Status-dependent callbacks\n\t\t\tstatusCode = s.statusCode || {},\n\t\t\t// Headers (they are sent all at once)\n\t\t\trequestHeaders = {},\n\t\t\trequestHeadersNames = {},\n\t\t\t// The jqXHR state\n\t\t\tstate = 0,\n\t\t\t// Default abort message\n\t\t\tstrAbort = \"canceled\",\n\t\t\t// Fake xhr\n\t\t\tjqXHR = {\n\t\t\t\treadyState: 0,\n\n\t\t\t\t// Builds headers hashtable if needed\n\t\t\t\tgetResponseHeader: function( key ) {\n\t\t\t\t\tvar match;\n\t\t\t\t\tif ( state === 2 ) {\n\t\t\t\t\t\tif ( !responseHeaders ) {\n\t\t\t\t\t\t\tresponseHeaders = {};\n\t\t\t\t\t\t\twhile ( (match = rheaders.exec( responseHeadersString )) ) {\n\t\t\t\t\t\t\t\tresponseHeaders[ match[1].toLowerCase() ] = match[ 2 ];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tmatch = responseHeaders[ key.toLowerCase() ];\n\t\t\t\t\t}\n\t\t\t\t\treturn match == null ? null : match;\n\t\t\t\t},\n\n\t\t\t\t// Raw string\n\t\t\t\tgetAllResponseHeaders: function() {\n\t\t\t\t\treturn state === 2 ? responseHeadersString : null;\n\t\t\t\t},\n\n\t\t\t\t// Caches the header\n\t\t\t\tsetRequestHeader: function( name, value ) {\n\t\t\t\t\tvar lname = name.toLowerCase();\n\t\t\t\t\tif ( !state ) {\n\t\t\t\t\t\tname = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;\n\t\t\t\t\t\trequestHeaders[ name ] = value;\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Overrides response content-type header\n\t\t\t\toverrideMimeType: function( type ) {\n\t\t\t\t\tif ( !state ) {\n\t\t\t\t\t\ts.mimeType = type;\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Status-dependent callbacks\n\t\t\t\tstatusCode: function( map ) {\n\t\t\t\t\tvar code;\n\t\t\t\t\tif ( map ) {\n\t\t\t\t\t\tif ( state < 2 ) {\n\t\t\t\t\t\t\tfor ( code in map ) {\n\t\t\t\t\t\t\t\t// Lazy-add the new callback in a way that preserves old ones\n\t\t\t\t\t\t\t\tstatusCode[ code ] = [ statusCode[ code ], map[ code ] ];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Execute the appropriate callbacks\n\t\t\t\t\t\t\tjqXHR.always( map[ jqXHR.status ] );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Cancel the request\n\t\t\t\tabort: function( statusText ) {\n\t\t\t\t\tvar finalText = statusText || strAbort;\n\t\t\t\t\tif ( transport ) {\n\t\t\t\t\t\ttransport.abort( finalText );\n\t\t\t\t\t}\n\t\t\t\t\tdone( 0, finalText );\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\t\t\t};\n\n\t\t// Attach deferreds\n\t\tdeferred.promise( jqXHR ).complete = completeDeferred.add;\n\t\tjqXHR.success = jqXHR.done;\n\t\tjqXHR.error = jqXHR.fail;\n\n\t\t// Remove hash character (#7531: and string promotion)\n\t\t// Add protocol if not provided (#5866: IE7 issue with protocol-less urls)\n\t\t// Handle falsy url in the settings object (#10093: consistency with old signature)\n\t\t// We also use the url parameter if available\n\t\ts.url = ( ( url || s.url || ajaxLocation ) + \"\" ).replace( rhash, \"\" ).replace( rprotocol, ajaxLocParts[ 1 ] + \"//\" );\n\n\t\t// Alias method option to type as per ticket #12004\n\t\ts.type = options.method || options.type || s.method || s.type;\n\n\t\t// Extract dataTypes list\n\t\ts.dataTypes = jQuery.trim( s.dataType || \"*\" ).toLowerCase().match( core_rnotwhite ) || [\"\"];\n\n\t\t// A cross-domain request is in order when we have a protocol:host:port mismatch\n\t\tif ( s.crossDomain == null ) {\n\t\t\tparts = rurl.exec( s.url.toLowerCase() );\n\t\t\ts.crossDomain = !!( parts &&\n\t\t\t\t( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||\n\t\t\t\t\t( parts[ 3 ] || ( parts[ 1 ] === \"http:\" ? 80 : 443 ) ) !=\n\t\t\t\t\t\t( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === \"http:\" ? 80 : 443 ) ) )\n\t\t\t);\n\t\t}\n\n\t\t// Convert data if not already a string\n\t\tif ( s.data && s.processData && typeof s.data !== \"string\" ) {\n\t\t\ts.data = jQuery.param( s.data, s.traditional );\n\t\t}\n\n\t\t// Apply prefilters\n\t\tinspectPrefiltersOrTransports( prefilters, s, options, jqXHR );\n\n\t\t// If request was aborted inside a prefilter, stop there\n\t\tif ( state === 2 ) {\n\t\t\treturn jqXHR;\n\t\t}\n\n\t\t// We can fire global events as of now if asked to\n\t\tfireGlobals = s.global;\n\n\t\t// Watch for a new set of requests\n\t\tif ( fireGlobals && jQuery.active++ === 0 ) {\n\t\t\tjQuery.event.trigger(\"ajaxStart\");\n\t\t}\n\n\t\t// Uppercase the type\n\t\ts.type = s.type.toUpperCase();\n\n\t\t// Determine if request has content\n\t\ts.hasContent = !rnoContent.test( s.type );\n\n\t\t// Save the URL in case we're toying with the If-Modified-Since\n\t\t// and/or If-None-Match header later on\n\t\tcacheURL = s.url;\n\n\t\t// More options handling for requests with no content\n\t\tif ( !s.hasContent ) {\n\n\t\t\t// If data is available, append data to url\n\t\t\tif ( s.data ) {\n\t\t\t\tcacheURL = ( s.url += ( ajax_rquery.test( cacheURL ) ? \"&\" : \"?\" ) + s.data );\n\t\t\t\t// #9682: remove data so that it's not used in an eventual retry\n\t\t\t\tdelete s.data;\n\t\t\t}\n\n\t\t\t// Add anti-cache in url if needed\n\t\t\tif ( s.cache === false ) {\n\t\t\t\ts.url = rts.test( cacheURL ) ?\n\n\t\t\t\t\t// If there is already a '_' parameter, set its value\n\t\t\t\t\tcacheURL.replace( rts, \"$1_=\" + ajax_nonce++ ) :\n\n\t\t\t\t\t// Otherwise add one to the end\n\t\t\t\t\tcacheURL + ( ajax_rquery.test( cacheURL ) ? \"&\" : \"?\" ) + \"_=\" + ajax_nonce++;\n\t\t\t}\n\t\t}\n\n\t\t// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.\n\t\tif ( s.ifModified ) {\n\t\t\tif ( jQuery.lastModified[ cacheURL ] ) {\n\t\t\t\tjqXHR.setRequestHeader( \"If-Modified-Since\", jQuery.lastModified[ cacheURL ] );\n\t\t\t}\n\t\t\tif ( jQuery.etag[ cacheURL ] ) {\n\t\t\t\tjqXHR.setRequestHeader( \"If-None-Match\", jQuery.etag[ cacheURL ] );\n\t\t\t}\n\t\t}\n\n\t\t// Set the correct header, if data is being sent\n\t\tif ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {\n\t\t\tjqXHR.setRequestHeader( \"Content-Type\", s.contentType );\n\t\t}\n\n\t\t// Set the Accepts header for the server, depending on the dataType\n\t\tjqXHR.setRequestHeader(\n\t\t\t\"Accept\",\n\t\t\ts.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?\n\t\t\t\ts.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== \"*\" ? \", \" + allTypes + \"; q=0.01\" : \"\" ) :\n\t\t\t\ts.accepts[ \"*\" ]\n\t\t);\n\n\t\t// Check for headers option\n\t\tfor ( i in s.headers ) {\n\t\t\tjqXHR.setRequestHeader( i, s.headers[ i ] );\n\t\t}\n\n\t\t// Allow custom headers/mimetypes and early abort\n\t\tif ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {\n\t\t\t// Abort if not done already and return\n\t\t\treturn jqXHR.abort();\n\t\t}\n\n\t\t// aborting is no longer a cancellation\n\t\tstrAbort = \"abort\";\n\n\t\t// Install callbacks on deferreds\n\t\tfor ( i in { success: 1, error: 1, complete: 1 } ) {\n\t\t\tjqXHR[ i ]( s[ i ] );\n\t\t}\n\n\t\t// Get transport\n\t\ttransport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );\n\n\t\t// If no transport, we auto-abort\n\t\tif ( !transport ) {\n\t\t\tdone( -1, \"No Transport\" );\n\t\t} else {\n\t\t\tjqXHR.readyState = 1;\n\n\t\t\t// Send global event\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( \"ajaxSend\", [ jqXHR, s ] );\n\t\t\t}\n\t\t\t// Timeout\n\t\t\tif ( s.async && s.timeout > 0 ) {\n\t\t\t\ttimeoutTimer = setTimeout(function() {\n\t\t\t\t\tjqXHR.abort(\"timeout\");\n\t\t\t\t}, s.timeout );\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tstate = 1;\n\t\t\t\ttransport.send( requestHeaders, done );\n\t\t\t} catch ( e ) {\n\t\t\t\t// Propagate exception as error if not done\n\t\t\t\tif ( state < 2 ) {\n\t\t\t\t\tdone( -1, e );\n\t\t\t\t// Simply rethrow otherwise\n\t\t\t\t} else {\n\t\t\t\t\tthrow e;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Callback for when everything is done\n\t\tfunction done( status, nativeStatusText, responses, headers ) {\n\t\t\tvar isSuccess, success, error, response, modified,\n\t\t\t\tstatusText = nativeStatusText;\n\n\t\t\t// Called once\n\t\t\tif ( state === 2 ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// State is \"done\" now\n\t\t\tstate = 2;\n\n\t\t\t// Clear timeout if it exists\n\t\t\tif ( timeoutTimer ) {\n\t\t\t\tclearTimeout( timeoutTimer );\n\t\t\t}\n\n\t\t\t// Dereference transport for early garbage collection\n\t\t\t// (no matter how long the jqXHR object will be used)\n\t\t\ttransport = undefined;\n\n\t\t\t// Cache response headers\n\t\t\tresponseHeadersString = headers || \"\";\n\n\t\t\t// Set readyState\n\t\t\tjqXHR.readyState = status > 0 ? 4 : 0;\n\n\t\t\t// Get response data\n\t\t\tif ( responses ) {\n\t\t\t\tresponse = ajaxHandleResponses( s, jqXHR, responses );\n\t\t\t}\n\n\t\t\t// If successful, handle type chaining\n\t\t\tif ( status >= 200 && status < 300 || status === 304 ) {\n\n\t\t\t\t// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.\n\t\t\t\tif ( s.ifModified ) {\n\t\t\t\t\tmodified = jqXHR.getResponseHeader(\"Last-Modified\");\n\t\t\t\t\tif ( modified ) {\n\t\t\t\t\t\tjQuery.lastModified[ cacheURL ] = modified;\n\t\t\t\t\t}\n\t\t\t\t\tmodified = jqXHR.getResponseHeader(\"etag\");\n\t\t\t\t\tif ( modified ) {\n\t\t\t\t\t\tjQuery.etag[ cacheURL ] = modified;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// if no content\n\t\t\t\tif ( status === 204 ) {\n\t\t\t\t\tisSuccess = true;\n\t\t\t\t\tstatusText = \"nocontent\";\n\n\t\t\t\t// if not modified\n\t\t\t\t} else if ( status === 304 ) {\n\t\t\t\t\tisSuccess = true;\n\t\t\t\t\tstatusText = \"notmodified\";\n\n\t\t\t\t// If we have data, let's convert it\n\t\t\t\t} else {\n\t\t\t\t\tisSuccess = ajaxConvert( s, response );\n\t\t\t\t\tstatusText = isSuccess.state;\n\t\t\t\t\tsuccess = isSuccess.data;\n\t\t\t\t\terror = isSuccess.error;\n\t\t\t\t\tisSuccess = !error;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// We extract error from statusText\n\t\t\t\t// then normalize statusText and status for non-aborts\n\t\t\t\terror = statusText;\n\t\t\t\tif ( status || !statusText ) {\n\t\t\t\t\tstatusText = \"error\";\n\t\t\t\t\tif ( status < 0 ) {\n\t\t\t\t\t\tstatus = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Set data for the fake xhr object\n\t\t\tjqXHR.status = status;\n\t\t\tjqXHR.statusText = ( nativeStatusText || statusText ) + \"\";\n\n\t\t\t// Success/Error\n\t\t\tif ( isSuccess ) {\n\t\t\t\tdeferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );\n\t\t\t} else {\n\t\t\t\tdeferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );\n\t\t\t}\n\n\t\t\t// Status-dependent callbacks\n\t\t\tjqXHR.statusCode( statusCode );\n\t\t\tstatusCode = undefined;\n\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( isSuccess ? \"ajaxSuccess\" : \"ajaxError\",\n\t\t\t\t\t[ jqXHR, s, isSuccess ? success : error ] );\n\t\t\t}\n\n\t\t\t// Complete\n\t\t\tcompleteDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );\n\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( \"ajaxComplete\", [ jqXHR, s ] );\n\t\t\t\t// Handle the global AJAX counter\n\t\t\t\tif ( !( --jQuery.active ) ) {\n\t\t\t\t\tjQuery.event.trigger(\"ajaxStop\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn jqXHR;\n\t},\n\n\tgetScript: function( url, callback ) {\n\t\treturn jQuery.get( url, undefined, callback, \"script\" );\n\t},\n\n\tgetJSON: function( url, data, callback ) {\n\t\treturn jQuery.get( url, data, callback, \"json\" );\n\t}\n});\n\n/* Handles responses to an ajax request:\n * - sets all responseXXX fields accordingly\n * - finds the right dataType (mediates between content-type and expected dataType)\n * - returns the corresponding response\n */\nfunction ajaxHandleResponses( s, jqXHR, responses ) {\n\tvar firstDataType, ct, finalDataType, type,\n\t\tcontents = s.contents,\n\t\tdataTypes = s.dataTypes,\n\t\tresponseFields = s.responseFields;\n\n\t// Fill responseXXX fields\n\tfor ( type in responseFields ) {\n\t\tif ( type in responses ) {\n\t\t\tjqXHR[ responseFields[type] ] = responses[ type ];\n\t\t}\n\t}\n\n\t// Remove auto dataType and get content-type in the process\n\twhile( dataTypes[ 0 ] === \"*\" ) {\n\t\tdataTypes.shift();\n\t\tif ( ct === undefined ) {\n\t\t\tct = s.mimeType || jqXHR.getResponseHeader(\"Content-Type\");\n\t\t}\n\t}\n\n\t// Check if we're dealing with a known content-type\n\tif ( ct ) {\n\t\tfor ( type in contents ) {\n\t\t\tif ( contents[ type ] && contents[ type ].test( ct ) ) {\n\t\t\t\tdataTypes.unshift( type );\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Check to see if we have a response for the expected dataType\n\tif ( dataTypes[ 0 ] in responses ) {\n\t\tfinalDataType = dataTypes[ 0 ];\n\t} else {\n\t\t// Try convertible dataTypes\n\t\tfor ( type in responses ) {\n\t\t\tif ( !dataTypes[ 0 ] || s.converters[ type + \" \" + dataTypes[0] ] ) {\n\t\t\t\tfinalDataType = type;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( !firstDataType ) {\n\t\t\t\tfirstDataType = type;\n\t\t\t}\n\t\t}\n\t\t// Or just use first one\n\t\tfinalDataType = finalDataType || firstDataType;\n\t}\n\n\t// If we found a dataType\n\t// We add the dataType to the list if needed\n\t// and return the corresponding response\n\tif ( finalDataType ) {\n\t\tif ( finalDataType !== dataTypes[ 0 ] ) {\n\t\t\tdataTypes.unshift( finalDataType );\n\t\t}\n\t\treturn responses[ finalDataType ];\n\t}\n}\n\n// Chain conversions given the request and the original response\nfunction ajaxConvert( s, response ) {\n\tvar conv2, current, conv, tmp,\n\t\tconverters = {},\n\t\ti = 0,\n\t\t// Work with a copy of dataTypes in case we need to modify it for conversion\n\t\tdataTypes = s.dataTypes.slice(),\n\t\tprev = dataTypes[ 0 ];\n\n\t// Apply the dataFilter if provided\n\tif ( s.dataFilter ) {\n\t\tresponse = s.dataFilter( response, s.dataType );\n\t}\n\n\t// Create converters map with lowercased keys\n\tif ( dataTypes[ 1 ] ) {\n\t\tfor ( conv in s.converters ) {\n\t\t\tconverters[ conv.toLowerCase() ] = s.converters[ conv ];\n\t\t}\n\t}\n\n\t// Convert to each sequential dataType, tolerating list modification\n\tfor ( ; (current = dataTypes[++i]); ) {\n\n\t\t// There's only work to do if current dataType is non-auto\n\t\tif ( current !== \"*\" ) {\n\n\t\t\t// Convert response if prev dataType is non-auto and differs from current\n\t\t\tif ( prev !== \"*\" && prev !== current ) {\n\n\t\t\t\t// Seek a direct converter\n\t\t\t\tconv = converters[ prev + \" \" + current ] || converters[ \"* \" + current ];\n\n\t\t\t\t// If none found, seek a pair\n\t\t\t\tif ( !conv ) {\n\t\t\t\t\tfor ( conv2 in converters ) {\n\n\t\t\t\t\t\t// If conv2 outputs current\n\t\t\t\t\t\ttmp = conv2.split(\" \");\n\t\t\t\t\t\tif ( tmp[ 1 ] === current ) {\n\n\t\t\t\t\t\t\t// If prev can be converted to accepted input\n\t\t\t\t\t\t\tconv = converters[ prev + \" \" + tmp[ 0 ] ] ||\n\t\t\t\t\t\t\t\tconverters[ \"* \" + tmp[ 0 ] ];\n\t\t\t\t\t\t\tif ( conv ) {\n\t\t\t\t\t\t\t\t// Condense equivalence converters\n\t\t\t\t\t\t\t\tif ( conv === true ) {\n\t\t\t\t\t\t\t\t\tconv = converters[ conv2 ];\n\n\t\t\t\t\t\t\t\t// Otherwise, insert the intermediate dataType\n\t\t\t\t\t\t\t\t} else if ( converters[ conv2 ] !== true ) {\n\t\t\t\t\t\t\t\t\tcurrent = tmp[ 0 ];\n\t\t\t\t\t\t\t\t\tdataTypes.splice( i--, 0, current );\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Apply converter (if not an equivalence)\n\t\t\t\tif ( conv !== true ) {\n\n\t\t\t\t\t// Unless errors are allowed to bubble, catch and return them\n\t\t\t\t\tif ( conv && s[\"throws\"] ) {\n\t\t\t\t\t\tresponse = conv( response );\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tresponse = conv( response );\n\t\t\t\t\t\t} catch ( e ) {\n\t\t\t\t\t\t\treturn { state: \"parsererror\", error: conv ? e : \"No conversion from \" + prev + \" to \" + current };\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Update prev for next iteration\n\t\t\tprev = current;\n\t\t}\n\t}\n\n\treturn { state: \"success\", data: response };\n}\n// Install script dataType\njQuery.ajaxSetup({\n\taccepts: {\n\t\tscript: \"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript\"\n\t},\n\tcontents: {\n\t\tscript: /(?:java|ecma)script/\n\t},\n\tconverters: {\n\t\t\"text script\": function( text ) {\n\t\t\tjQuery.globalEval( text );\n\t\t\treturn text;\n\t\t}\n\t}\n});\n\n// Handle cache's special case and global\njQuery.ajaxPrefilter( \"script\", function( s ) {\n\tif ( s.cache === undefined ) {\n\t\ts.cache = false;\n\t}\n\tif ( s.crossDomain ) {\n\t\ts.type = \"GET\";\n\t\ts.global = false;\n\t}\n});\n\n// Bind script tag hack transport\njQuery.ajaxTransport( \"script\", function(s) {\n\n\t// This transport only deals with cross domain requests\n\tif ( s.crossDomain ) {\n\n\t\tvar script,\n\t\t\thead = document.head || jQuery(\"head\")[0] || document.documentElement;\n\n\t\treturn {\n\n\t\t\tsend: function( _, callback ) {\n\n\t\t\t\tscript = document.createElement(\"script\");\n\n\t\t\t\tscript.async = true;\n\n\t\t\t\tif ( s.scriptCharset ) {\n\t\t\t\t\tscript.charset = s.scriptCharset;\n\t\t\t\t}\n\n\t\t\t\tscript.src = s.url;\n\n\t\t\t\t// Attach handlers for all browsers\n\t\t\t\tscript.onload = script.onreadystatechange = function( _, isAbort ) {\n\n\t\t\t\t\tif ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {\n\n\t\t\t\t\t\t// Handle memory leak in IE\n\t\t\t\t\t\tscript.onload = script.onreadystatechange = null;\n\n\t\t\t\t\t\t// Remove the script\n\t\t\t\t\t\tif ( script.parentNode ) {\n\t\t\t\t\t\t\tscript.parentNode.removeChild( script );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Dereference the script\n\t\t\t\t\t\tscript = null;\n\n\t\t\t\t\t\t// Callback if not abort\n\t\t\t\t\t\tif ( !isAbort ) {\n\t\t\t\t\t\t\tcallback( 200, \"success\" );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\t// Circumvent IE6 bugs with base elements (#2709 and #4378) by prepending\n\t\t\t\t// Use native DOM manipulation to avoid our domManip AJAX trickery\n\t\t\t\thead.insertBefore( script, head.firstChild );\n\t\t\t},\n\n\t\t\tabort: function() {\n\t\t\t\tif ( script ) {\n\t\t\t\t\tscript.onload( undefined, true );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n});\nvar oldCallbacks = [],\n\trjsonp = /(=)\\?(?=&|$)|\\?\\?/;\n\n// Default jsonp settings\njQuery.ajaxSetup({\n\tjsonp: \"callback\",\n\tjsonpCallback: function() {\n\t\tvar callback = oldCallbacks.pop() || ( jQuery.expando + \"_\" + ( ajax_nonce++ ) );\n\t\tthis[ callback ] = true;\n\t\treturn callback;\n\t}\n});\n\n// Detect, normalize options and install callbacks for jsonp requests\njQuery.ajaxPrefilter( \"json jsonp\", function( s, originalSettings, jqXHR ) {\n\n\tvar callbackName, overwritten, responseContainer,\n\t\tjsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?\n\t\t\t\"url\" :\n\t\t\ttypeof s.data === \"string\" && !( s.contentType || \"\" ).indexOf(\"application/x-www-form-urlencoded\") && rjsonp.test( s.data ) && \"data\"\n\t\t);\n\n\t// Handle iff the expected data type is \"jsonp\" or we have a parameter to set\n\tif ( jsonProp || s.dataTypes[ 0 ] === \"jsonp\" ) {\n\n\t\t// Get callback name, remembering preexisting value associated with it\n\t\tcallbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?\n\t\t\ts.jsonpCallback() :\n\t\t\ts.jsonpCallback;\n\n\t\t// Insert callback into url or form data\n\t\tif ( jsonProp ) {\n\t\t\ts[ jsonProp ] = s[ jsonProp ].replace( rjsonp, \"$1\" + callbackName );\n\t\t} else if ( s.jsonp !== false ) {\n\t\t\ts.url += ( ajax_rquery.test( s.url ) ? \"&\" : \"?\" ) + s.jsonp + \"=\" + callbackName;\n\t\t}\n\n\t\t// Use data converter to retrieve json after script execution\n\t\ts.converters[\"script json\"] = function() {\n\t\t\tif ( !responseContainer ) {\n\t\t\t\tjQuery.error( callbackName + \" was not called\" );\n\t\t\t}\n\t\t\treturn responseContainer[ 0 ];\n\t\t};\n\n\t\t// force json dataType\n\t\ts.dataTypes[ 0 ] = \"json\";\n\n\t\t// Install callback\n\t\toverwritten = window[ callbackName ];\n\t\twindow[ callbackName ] = function() {\n\t\t\tresponseContainer = arguments;\n\t\t};\n\n\t\t// Clean-up function (fires after converters)\n\t\tjqXHR.always(function() {\n\t\t\t// Restore preexisting value\n\t\t\twindow[ callbackName ] = overwritten;\n\n\t\t\t// Save back as free\n\t\t\tif ( s[ callbackName ] ) {\n\t\t\t\t// make sure that re-using the options doesn't screw things around\n\t\t\t\ts.jsonpCallback = originalSettings.jsonpCallback;\n\n\t\t\t\t// save the callback name for future use\n\t\t\t\toldCallbacks.push( callbackName );\n\t\t\t}\n\n\t\t\t// Call if it was a function and we have a response\n\t\t\tif ( responseContainer && jQuery.isFunction( overwritten ) ) {\n\t\t\t\toverwritten( responseContainer[ 0 ] );\n\t\t\t}\n\n\t\t\tresponseContainer = overwritten = undefined;\n\t\t});\n\n\t\t// Delegate to script\n\t\treturn \"script\";\n\t}\n});\nvar xhrCallbacks, xhrSupported,\n\txhrId = 0,\n\t// #5280: Internet Explorer will keep connections alive if we don't abort on unload\n\txhrOnUnloadAbort = window.ActiveXObject && function() {\n\t\t// Abort all pending requests\n\t\tvar key;\n\t\tfor ( key in xhrCallbacks ) {\n\t\t\txhrCallbacks[ key ]( undefined, true );\n\t\t}\n\t};\n\n// Functions to create xhrs\nfunction createStandardXHR() {\n\ttry {\n\t\treturn new window.XMLHttpRequest();\n\t} catch( e ) {}\n}\n\nfunction createActiveXHR() {\n\ttry {\n\t\treturn new window.ActiveXObject(\"Microsoft.XMLHTTP\");\n\t} catch( e ) {}\n}\n\n// Create the request object\n// (This is still attached to ajaxSettings for backward compatibility)\njQuery.ajaxSettings.xhr = window.ActiveXObject ?\n\t/* Microsoft failed to properly\n\t * implement the XMLHttpRequest in IE7 (can't request local files),\n\t * so we use the ActiveXObject when it is available\n\t * Additionally XMLHttpRequest can be disabled in IE7/IE8 so\n\t * we need a fallback.\n\t */\n\tfunction() {\n\t\treturn !this.isLocal && createStandardXHR() || createActiveXHR();\n\t} :\n\t// For all other browsers, use the standard XMLHttpRequest object\n\tcreateStandardXHR;\n\n// Determine support properties\nxhrSupported = jQuery.ajaxSettings.xhr();\njQuery.support.cors = !!xhrSupported && ( \"withCredentials\" in xhrSupported );\nxhrSupported = jQuery.support.ajax = !!xhrSupported;\n\n// Create transport if the browser can provide an xhr\nif ( xhrSupported ) {\n\n\tjQuery.ajaxTransport(function( s ) {\n\t\t// Cross domain only allowed if supported through XMLHttpRequest\n\t\tif ( !s.crossDomain || jQuery.support.cors ) {\n\n\t\t\tvar callback;\n\n\t\t\treturn {\n\t\t\t\tsend: function( headers, complete ) {\n\n\t\t\t\t\t// Get a new xhr\n\t\t\t\t\tvar handle, i,\n\t\t\t\t\t\txhr = s.xhr();\n\n\t\t\t\t\t// Open the socket\n\t\t\t\t\t// Passing null username, generates a login popup on Opera (#2865)\n\t\t\t\t\tif ( s.username ) {\n\t\t\t\t\t\txhr.open( s.type, s.url, s.async, s.username, s.password );\n\t\t\t\t\t} else {\n\t\t\t\t\t\txhr.open( s.type, s.url, s.async );\n\t\t\t\t\t}\n\n\t\t\t\t\t// Apply custom fields if provided\n\t\t\t\t\tif ( s.xhrFields ) {\n\t\t\t\t\t\tfor ( i in s.xhrFields ) {\n\t\t\t\t\t\t\txhr[ i ] = s.xhrFields[ i ];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Override mime type if needed\n\t\t\t\t\tif ( s.mimeType && xhr.overrideMimeType ) {\n\t\t\t\t\t\txhr.overrideMimeType( s.mimeType );\n\t\t\t\t\t}\n\n\t\t\t\t\t// X-Requested-With header\n\t\t\t\t\t// For cross-domain requests, seeing as conditions for a preflight are\n\t\t\t\t\t// akin to a jigsaw puzzle, we simply never set it to be sure.\n\t\t\t\t\t// (it can always be set on a per-request basis or even using ajaxSetup)\n\t\t\t\t\t// For same-domain requests, won't change header if already provided.\n\t\t\t\t\tif ( !s.crossDomain && !headers[\"X-Requested-With\"] ) {\n\t\t\t\t\t\theaders[\"X-Requested-With\"] = \"XMLHttpRequest\";\n\t\t\t\t\t}\n\n\t\t\t\t\t// Need an extra try/catch for cross domain requests in Firefox 3\n\t\t\t\t\ttry {\n\t\t\t\t\t\tfor ( i in headers ) {\n\t\t\t\t\t\t\txhr.setRequestHeader( i, headers[ i ] );\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch( err ) {}\n\n\t\t\t\t\t// Do send the request\n\t\t\t\t\t// This may raise an exception which is actually\n\t\t\t\t\t// handled in jQuery.ajax (so no try/catch here)\n\t\t\t\t\txhr.send( ( s.hasContent && s.data ) || null );\n\n\t\t\t\t\t// Listener\n\t\t\t\t\tcallback = function( _, isAbort ) {\n\t\t\t\t\t\tvar status, responseHeaders, statusText, responses;\n\n\t\t\t\t\t\t// Firefox throws exceptions when accessing properties\n\t\t\t\t\t\t// of an xhr when a network error occurred\n\t\t\t\t\t\t// http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)\n\t\t\t\t\t\ttry {\n\n\t\t\t\t\t\t\t// Was never called and is aborted or complete\n\t\t\t\t\t\t\tif ( callback && ( isAbort || xhr.readyState === 4 ) ) {\n\n\t\t\t\t\t\t\t\t// Only called once\n\t\t\t\t\t\t\t\tcallback = undefined;\n\n\t\t\t\t\t\t\t\t// Do not keep as active anymore\n\t\t\t\t\t\t\t\tif ( handle ) {\n\t\t\t\t\t\t\t\t\txhr.onreadystatechange = jQuery.noop;\n\t\t\t\t\t\t\t\t\tif ( xhrOnUnloadAbort ) {\n\t\t\t\t\t\t\t\t\t\tdelete xhrCallbacks[ handle ];\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// If it's an abort\n\t\t\t\t\t\t\t\tif ( isAbort ) {\n\t\t\t\t\t\t\t\t\t// Abort it manually if needed\n\t\t\t\t\t\t\t\t\tif ( xhr.readyState !== 4 ) {\n\t\t\t\t\t\t\t\t\t\txhr.abort();\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tresponses = {};\n\t\t\t\t\t\t\t\t\tstatus = xhr.status;\n\t\t\t\t\t\t\t\t\tresponseHeaders = xhr.getAllResponseHeaders();\n\n\t\t\t\t\t\t\t\t\t// When requesting binary data, IE6-9 will throw an exception\n\t\t\t\t\t\t\t\t\t// on any attempt to access responseText (#11426)\n\t\t\t\t\t\t\t\t\tif ( typeof xhr.responseText === \"string\" ) {\n\t\t\t\t\t\t\t\t\t\tresponses.text = xhr.responseText;\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t// Firefox throws an exception when accessing\n\t\t\t\t\t\t\t\t\t// statusText for faulty cross-domain requests\n\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\tstatusText = xhr.statusText;\n\t\t\t\t\t\t\t\t\t} catch( e ) {\n\t\t\t\t\t\t\t\t\t\t// We normalize with Webkit giving an empty statusText\n\t\t\t\t\t\t\t\t\t\tstatusText = \"\";\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t// Filter status for non standard behaviors\n\n\t\t\t\t\t\t\t\t\t// If the request is local and we have data: assume a success\n\t\t\t\t\t\t\t\t\t// (success with no data won't get notified, that's the best we\n\t\t\t\t\t\t\t\t\t// can do given current implementations)\n\t\t\t\t\t\t\t\t\tif ( !status && s.isLocal && !s.crossDomain ) {\n\t\t\t\t\t\t\t\t\t\tstatus = responses.text ? 200 : 404;\n\t\t\t\t\t\t\t\t\t// IE - #1450: sometimes returns 1223 when it should be 204\n\t\t\t\t\t\t\t\t\t} else if ( status === 1223 ) {\n\t\t\t\t\t\t\t\t\t\tstatus = 204;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch( firefoxAccessException ) {\n\t\t\t\t\t\t\tif ( !isAbort ) {\n\t\t\t\t\t\t\t\tcomplete( -1, firefoxAccessException );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Call complete if needed\n\t\t\t\t\t\tif ( responses ) {\n\t\t\t\t\t\t\tcomplete( status, statusText, responses, responseHeaders );\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\n\t\t\t\t\tif ( !s.async ) {\n\t\t\t\t\t\t// if we're in sync mode we fire the callback\n\t\t\t\t\t\tcallback();\n\t\t\t\t\t} else if ( xhr.readyState === 4 ) {\n\t\t\t\t\t\t// (IE6 & IE7) if it's in cache and has been\n\t\t\t\t\t\t// retrieved directly we need to fire the callback\n\t\t\t\t\t\tsetTimeout( callback );\n\t\t\t\t\t} else {\n\t\t\t\t\t\thandle = ++xhrId;\n\t\t\t\t\t\tif ( xhrOnUnloadAbort ) {\n\t\t\t\t\t\t\t// Create the active xhrs callbacks list if needed\n\t\t\t\t\t\t\t// and attach the unload handler\n\t\t\t\t\t\t\tif ( !xhrCallbacks ) {\n\t\t\t\t\t\t\t\txhrCallbacks = {};\n\t\t\t\t\t\t\t\tjQuery( window ).unload( xhrOnUnloadAbort );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t// Add to list of active xhrs callbacks\n\t\t\t\t\t\t\txhrCallbacks[ handle ] = callback;\n\t\t\t\t\t\t}\n\t\t\t\t\t\txhr.onreadystatechange = callback;\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\tabort: function() {\n\t\t\t\t\tif ( callback ) {\n\t\t\t\t\t\tcallback( undefined, true );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t});\n}\nvar fxNow, timerId,\n\trfxtypes = /^(?:toggle|show|hide)$/,\n\trfxnum = new RegExp( \"^(?:([+-])=|)(\" + core_pnum + \")([a-z%]*)$\", \"i\" ),\n\trrun = /queueHooks$/,\n\tanimationPrefilters = [ defaultPrefilter ],\n\ttweeners = {\n\t\t\"*\": [function( prop, value ) {\n\t\t\tvar end, unit,\n\t\t\t\ttween = this.createTween( prop, value ),\n\t\t\t\tparts = rfxnum.exec( value ),\n\t\t\t\ttarget = tween.cur(),\n\t\t\t\tstart = +target || 0,\n\t\t\t\tscale = 1,\n\t\t\t\tmaxIterations = 20;\n\n\t\t\tif ( parts ) {\n\t\t\t\tend = +parts[2];\n\t\t\t\tunit = parts[3] || ( jQuery.cssNumber[ prop ] ? \"\" : \"px\" );\n\n\t\t\t\t// We need to compute starting value\n\t\t\t\tif ( unit !== \"px\" && start ) {\n\t\t\t\t\t// Iteratively approximate from a nonzero starting point\n\t\t\t\t\t// Prefer the current property, because this process will be trivial if it uses the same units\n\t\t\t\t\t// Fallback to end or a simple constant\n\t\t\t\t\tstart = jQuery.css( tween.elem, prop, true ) || end || 1;\n\n\t\t\t\t\tdo {\n\t\t\t\t\t\t// If previous iteration zeroed out, double until we get *something*\n\t\t\t\t\t\t// Use a string for doubling factor so we don't accidentally see scale as unchanged below\n\t\t\t\t\t\tscale = scale || \".5\";\n\n\t\t\t\t\t\t// Adjust and apply\n\t\t\t\t\t\tstart = start / scale;\n\t\t\t\t\t\tjQuery.style( tween.elem, prop, start + unit );\n\n\t\t\t\t\t// Update scale, tolerating zero or NaN from tween.cur()\n\t\t\t\t\t// And breaking the loop if scale is unchanged or perfect, or if we've just had enough\n\t\t\t\t\t} while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );\n\t\t\t\t}\n\n\t\t\t\ttween.unit = unit;\n\t\t\t\ttween.start = start;\n\t\t\t\t// If a +=/-= token was provided, we're doing a relative animation\n\t\t\t\ttween.end = parts[1] ? start + ( parts[1] + 1 ) * end : end;\n\t\t\t}\n\t\t\treturn tween;\n\t\t}]\n\t};\n\n// Animations created synchronously will run synchronously\nfunction createFxNow() {\n\tsetTimeout(function() {\n\t\tfxNow = undefined;\n\t});\n\treturn ( fxNow = jQuery.now() );\n}\n\nfunction createTweens( animation, props ) {\n\tjQuery.each( props, function( prop, value ) {\n\t\tvar collection = ( tweeners[ prop ] || [] ).concat( tweeners[ \"*\" ] ),\n\t\t\tindex = 0,\n\t\t\tlength = collection.length;\n\t\tfor ( ; index < length; index++ ) {\n\t\t\tif ( collection[ index ].call( animation, prop, value ) ) {\n\n\t\t\t\t// we're done with this property\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t});\n}\n\nfunction Animation( elem, properties, options ) {\n\tvar result,\n\t\tstopped,\n\t\tindex = 0,\n\t\tlength = animationPrefilters.length,\n\t\tdeferred = jQuery.Deferred().always( function() {\n\t\t\t// don't match elem in the :animated selector\n\t\t\tdelete tick.elem;\n\t\t}),\n\t\ttick = function() {\n\t\t\tif ( stopped ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tvar currentTime = fxNow || createFxNow(),\n\t\t\t\tremaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),\n\t\t\t\t// archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497)\n\t\t\t\ttemp = remaining / animation.duration || 0,\n\t\t\t\tpercent = 1 - temp,\n\t\t\t\tindex = 0,\n\t\t\t\tlength = animation.tweens.length;\n\n\t\t\tfor ( ; index < length ; index++ ) {\n\t\t\t\tanimation.tweens[ index ].run( percent );\n\t\t\t}\n\n\t\t\tdeferred.notifyWith( elem, [ animation, percent, remaining ]);\n\n\t\t\tif ( percent < 1 && length ) {\n\t\t\t\treturn remaining;\n\t\t\t} else {\n\t\t\t\tdeferred.resolveWith( elem, [ animation ] );\n\t\t\t\treturn false;\n\t\t\t}\n\t\t},\n\t\tanimation = deferred.promise({\n\t\t\telem: elem,\n\t\t\tprops: jQuery.extend( {}, properties ),\n\t\t\topts: jQuery.extend( true, { specialEasing: {} }, options ),\n\t\t\toriginalProperties: properties,\n\t\t\toriginalOptions: options,\n\t\t\tstartTime: fxNow || createFxNow(),\n\t\t\tduration: options.duration,\n\t\t\ttweens: [],\n\t\t\tcreateTween: function( prop, end ) {\n\t\t\t\tvar tween = jQuery.Tween( elem, animation.opts, prop, end,\n\t\t\t\t\t\tanimation.opts.specialEasing[ prop ] || animation.opts.easing );\n\t\t\t\tanimation.tweens.push( tween );\n\t\t\t\treturn tween;\n\t\t\t},\n\t\t\tstop: function( gotoEnd ) {\n\t\t\t\tvar index = 0,\n\t\t\t\t\t// if we are going to the end, we want to run all the tweens\n\t\t\t\t\t// otherwise we skip this part\n\t\t\t\t\tlength = gotoEnd ? animation.tweens.length : 0;\n\t\t\t\tif ( stopped ) {\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\t\t\t\tstopped = true;\n\t\t\t\tfor ( ; index < length ; index++ ) {\n\t\t\t\t\tanimation.tweens[ index ].run( 1 );\n\t\t\t\t}\n\n\t\t\t\t// resolve when we played the last frame\n\t\t\t\t// otherwise, reject\n\t\t\t\tif ( gotoEnd ) {\n\t\t\t\t\tdeferred.resolveWith( elem, [ animation, gotoEnd ] );\n\t\t\t\t} else {\n\t\t\t\t\tdeferred.rejectWith( elem, [ animation, gotoEnd ] );\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t}\n\t\t}),\n\t\tprops = animation.props;\n\n\tpropFilter( props, animation.opts.specialEasing );\n\n\tfor ( ; index < length ; index++ ) {\n\t\tresult = animationPrefilters[ index ].call( animation, elem, props, animation.opts );\n\t\tif ( result ) {\n\t\t\treturn result;\n\t\t}\n\t}\n\n\tcreateTweens( animation, props );\n\n\tif ( jQuery.isFunction( animation.opts.start ) ) {\n\t\tanimation.opts.start.call( elem, animation );\n\t}\n\n\tjQuery.fx.timer(\n\t\tjQuery.extend( tick, {\n\t\t\telem: elem,\n\t\t\tanim: animation,\n\t\t\tqueue: animation.opts.queue\n\t\t})\n\t);\n\n\t// attach callbacks from options\n\treturn animation.progress( animation.opts.progress )\n\t\t.done( animation.opts.done, animation.opts.complete )\n\t\t.fail( animation.opts.fail )\n\t\t.always( animation.opts.always );\n}\n\nfunction propFilter( props, specialEasing ) {\n\tvar value, name, index, easing, hooks;\n\n\t// camelCase, specialEasing and expand cssHook pass\n\tfor ( index in props ) {\n\t\tname = jQuery.camelCase( index );\n\t\teasing = specialEasing[ name ];\n\t\tvalue = props[ index ];\n\t\tif ( jQuery.isArray( value ) ) {\n\t\t\teasing = value[ 1 ];\n\t\t\tvalue = props[ index ] = value[ 0 ];\n\t\t}\n\n\t\tif ( index !== name ) {\n\t\t\tprops[ name ] = value;\n\t\t\tdelete props[ index ];\n\t\t}\n\n\t\thooks = jQuery.cssHooks[ name ];\n\t\tif ( hooks && \"expand\" in hooks ) {\n\t\t\tvalue = hooks.expand( value );\n\t\t\tdelete props[ name ];\n\n\t\t\t// not quite $.extend, this wont overwrite keys already present.\n\t\t\t// also - reusing 'index' from above because we have the correct \"name\"\n\t\t\tfor ( index in value ) {\n\t\t\t\tif ( !( index in props ) ) {\n\t\t\t\t\tprops[ index ] = value[ index ];\n\t\t\t\t\tspecialEasing[ index ] = easing;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tspecialEasing[ name ] = easing;\n\t\t}\n\t}\n}\n\njQuery.Animation = jQuery.extend( Animation, {\n\n\ttweener: function( props, callback ) {\n\t\tif ( jQuery.isFunction( props ) ) {\n\t\t\tcallback = props;\n\t\t\tprops = [ \"*\" ];\n\t\t} else {\n\t\t\tprops = props.split(\" \");\n\t\t}\n\n\t\tvar prop,\n\t\t\tindex = 0,\n\t\t\tlength = props.length;\n\n\t\tfor ( ; index < length ; index++ ) {\n\t\t\tprop = props[ index ];\n\t\t\ttweeners[ prop ] = tweeners[ prop ] || [];\n\t\t\ttweeners[ prop ].unshift( callback );\n\t\t}\n\t},\n\n\tprefilter: function( callback, prepend ) {\n\t\tif ( prepend ) {\n\t\t\tanimationPrefilters.unshift( callback );\n\t\t} else {\n\t\t\tanimationPrefilters.push( callback );\n\t\t}\n\t}\n});\n\nfunction defaultPrefilter( elem, props, opts ) {\n\t/*jshint validthis:true */\n\tvar prop, index, length,\n\t\tvalue, dataShow, toggle,\n\t\ttween, hooks, oldfire,\n\t\tanim = this,\n\t\tstyle = elem.style,\n\t\torig = {},\n\t\thandled = [],\n\t\thidden = elem.nodeType && isHidden( elem );\n\n\t// handle queue: false promises\n\tif ( !opts.queue ) {\n\t\thooks = jQuery._queueHooks( elem, \"fx\" );\n\t\tif ( hooks.unqueued == null ) {\n\t\t\thooks.unqueued = 0;\n\t\t\toldfire = hooks.empty.fire;\n\t\t\thooks.empty.fire = function() {\n\t\t\t\tif ( !hooks.unqueued ) {\n\t\t\t\t\toldfire();\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t\thooks.unqueued++;\n\n\t\tanim.always(function() {\n\t\t\t// doing this makes sure that the complete handler will be called\n\t\t\t// before this completes\n\t\t\tanim.always(function() {\n\t\t\t\thooks.unqueued--;\n\t\t\t\tif ( !jQuery.queue( elem, \"fx\" ).length ) {\n\t\t\t\t\thooks.empty.fire();\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t}\n\n\t// height/width overflow pass\n\tif ( elem.nodeType === 1 && ( \"height\" in props || \"width\" in props ) ) {\n\t\t// Make sure that nothing sneaks out\n\t\t// Record all 3 overflow attributes because IE does not\n\t\t// change the overflow attribute when overflowX and\n\t\t// overflowY are set to the same value\n\t\topts.overflow = [ style.overflow, style.overflowX, style.overflowY ];\n\n\t\t// Set display property to inline-block for height/width\n\t\t// animations on inline elements that are having width/height animated\n\t\tif ( jQuery.css( elem, \"display\" ) === \"inline\" &&\n\t\t\t\tjQuery.css( elem, \"float\" ) === \"none\" ) {\n\n\t\t\t// inline-level elements accept inline-block;\n\t\t\t// block-level elements need to be inline with layout\n\t\t\tif ( !jQuery.support.inlineBlockNeedsLayout || css_defaultDisplay( elem.nodeName ) === \"inline\" ) {\n\t\t\t\tstyle.display = \"inline-block\";\n\n\t\t\t} else {\n\t\t\t\tstyle.zoom = 1;\n\t\t\t}\n\t\t}\n\t}\n\n\tif ( opts.overflow ) {\n\t\tstyle.overflow = \"hidden\";\n\t\tif ( !jQuery.support.shrinkWrapBlocks ) {\n\t\t\tanim.always(function() {\n\t\t\t\tstyle.overflow = opts.overflow[ 0 ];\n\t\t\t\tstyle.overflowX = opts.overflow[ 1 ];\n\t\t\t\tstyle.overflowY = opts.overflow[ 2 ];\n\t\t\t});\n\t\t}\n\t}\n\n\n\t// show/hide pass\n\tfor ( index in props ) {\n\t\tvalue = props[ index ];\n\t\tif ( rfxtypes.exec( value ) ) {\n\t\t\tdelete props[ index ];\n\t\t\ttoggle = toggle || value === \"toggle\";\n\t\t\tif ( value === ( hidden ? \"hide\" : \"show\" ) ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\thandled.push( index );\n\t\t}\n\t}\n\n\tlength = handled.length;\n\tif ( length ) {\n\t\tdataShow = jQuery._data( elem, \"fxshow\" ) || jQuery._data( elem, \"fxshow\", {} );\n\t\tif ( \"hidden\" in dataShow ) {\n\t\t\thidden = dataShow.hidden;\n\t\t}\n\n\t\t// store state if its toggle - enables .stop().toggle() to \"reverse\"\n\t\tif ( toggle ) {\n\t\t\tdataShow.hidden = !hidden;\n\t\t}\n\t\tif ( hidden ) {\n\t\t\tjQuery( elem ).show();\n\t\t} else {\n\t\t\tanim.done(function() {\n\t\t\t\tjQuery( elem ).hide();\n\t\t\t});\n\t\t}\n\t\tanim.done(function() {\n\t\t\tvar prop;\n\t\t\tjQuery._removeData( elem, \"fxshow\" );\n\t\t\tfor ( prop in orig ) {\n\t\t\t\tjQuery.style( elem, prop, orig[ prop ] );\n\t\t\t}\n\t\t});\n\t\tfor ( index = 0 ; index < length ; index++ ) {\n\t\t\tprop = handled[ index ];\n\t\t\ttween = anim.createTween( prop, hidden ? dataShow[ prop ] : 0 );\n\t\t\torig[ prop ] = dataShow[ prop ] || jQuery.style( elem, prop );\n\n\t\t\tif ( !( prop in dataShow ) ) {\n\t\t\t\tdataShow[ prop ] = tween.start;\n\t\t\t\tif ( hidden ) {\n\t\t\t\t\ttween.end = tween.start;\n\t\t\t\t\ttween.start = prop === \"width\" || prop === \"height\" ? 1 : 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction Tween( elem, options, prop, end, easing ) {\n\treturn new Tween.prototype.init( elem, options, prop, end, easing );\n}\njQuery.Tween = Tween;\n\nTween.prototype = {\n\tconstructor: Tween,\n\tinit: function( elem, options, prop, end, easing, unit ) {\n\t\tthis.elem = elem;\n\t\tthis.prop = prop;\n\t\tthis.easing = easing || \"swing\";\n\t\tthis.options = options;\n\t\tthis.start = this.now = this.cur();\n\t\tthis.end = end;\n\t\tthis.unit = unit || ( jQuery.cssNumber[ prop ] ? \"\" : \"px\" );\n\t},\n\tcur: function() {\n\t\tvar hooks = Tween.propHooks[ this.prop ];\n\n\t\treturn hooks && hooks.get ?\n\t\t\thooks.get( this ) :\n\t\t\tTween.propHooks._default.get( this );\n\t},\n\trun: function( percent ) {\n\t\tvar eased,\n\t\t\thooks = Tween.propHooks[ this.prop ];\n\n\t\tif ( this.options.duration ) {\n\t\t\tthis.pos = eased = jQuery.easing[ this.easing ](\n\t\t\t\tpercent, this.options.duration * percent, 0, 1, this.options.duration\n\t\t\t);\n\t\t} else {\n\t\t\tthis.pos = eased = percent;\n\t\t}\n\t\tthis.now = ( this.end - this.start ) * eased + this.start;\n\n\t\tif ( this.options.step ) {\n\t\t\tthis.options.step.call( this.elem, this.now, this );\n\t\t}\n\n\t\tif ( hooks && hooks.set ) {\n\t\t\thooks.set( this );\n\t\t} else {\n\t\t\tTween.propHooks._default.set( this );\n\t\t}\n\t\treturn this;\n\t}\n};\n\nTween.prototype.init.prototype = Tween.prototype;\n\nTween.propHooks = {\n\t_default: {\n\t\tget: function( tween ) {\n\t\t\tvar result;\n\n\t\t\tif ( tween.elem[ tween.prop ] != null &&\n\t\t\t\t(!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) {\n\t\t\t\treturn tween.elem[ tween.prop ];\n\t\t\t}\n\n\t\t\t// passing an empty string as a 3rd parameter to .css will automatically\n\t\t\t// attempt a parseFloat and fallback to a string if the parse fails\n\t\t\t// so, simple values such as \"10px\" are parsed to Float.\n\t\t\t// complex values such as \"rotate(1rad)\" are returned as is.\n\t\t\tresult = jQuery.css( tween.elem, tween.prop, \"\" );\n\t\t\t// Empty strings, null, undefined and \"auto\" are converted to 0.\n\t\t\treturn !result || result === \"auto\" ? 0 : result;\n\t\t},\n\t\tset: function( tween ) {\n\t\t\t// use step hook for back compat - use cssHook if its there - use .style if its\n\t\t\t// available and use plain properties where available\n\t\t\tif ( jQuery.fx.step[ tween.prop ] ) {\n\t\t\t\tjQuery.fx.step[ tween.prop ]( tween );\n\t\t\t} else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) {\n\t\t\t\tjQuery.style( tween.elem, tween.prop, tween.now + tween.unit );\n\t\t\t} else {\n\t\t\t\ttween.elem[ tween.prop ] = tween.now;\n\t\t\t}\n\t\t}\n\t}\n};\n\n// Remove in 2.0 - this supports IE8's panic based approach\n// to setting things on disconnected nodes\n\nTween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {\n\tset: function( tween ) {\n\t\tif ( tween.elem.nodeType && tween.elem.parentNode ) {\n\t\t\ttween.elem[ tween.prop ] = tween.now;\n\t\t}\n\t}\n};\n\njQuery.each([ \"toggle\", \"show\", \"hide\" ], function( i, name ) {\n\tvar cssFn = jQuery.fn[ name ];\n\tjQuery.fn[ name ] = function( speed, easing, callback ) {\n\t\treturn speed == null || typeof speed === \"boolean\" ?\n\t\t\tcssFn.apply( this, arguments ) :\n\t\t\tthis.animate( genFx( name, true ), speed, easing, callback );\n\t};\n});\n\njQuery.fn.extend({\n\tfadeTo: function( speed, to, easing, callback ) {\n\n\t\t// show any hidden elements after setting opacity to 0\n\t\treturn this.filter( isHidden ).css( \"opacity\", 0 ).show()\n\n\t\t\t// animate to the value specified\n\t\t\t.end().animate({ opacity: to }, speed, easing, callback );\n\t},\n\tanimate: function( prop, speed, easing, callback ) {\n\t\tvar empty = jQuery.isEmptyObject( prop ),\n\t\t\toptall = jQuery.speed( speed, easing, callback ),\n\t\t\tdoAnimation = function() {\n\t\t\t\t// Operate on a copy of prop so per-property easing won't be lost\n\t\t\t\tvar anim = Animation( this, jQuery.extend( {}, prop ), optall );\n\t\t\t\tdoAnimation.finish = function() {\n\t\t\t\t\tanim.stop( true );\n\t\t\t\t};\n\t\t\t\t// Empty animations, or finishing resolves immediately\n\t\t\t\tif ( empty || jQuery._data( this, \"finish\" ) ) {\n\t\t\t\t\tanim.stop( true );\n\t\t\t\t}\n\t\t\t};\n\t\t\tdoAnimation.finish = doAnimation;\n\n\t\treturn empty || optall.queue === false ?\n\t\t\tthis.each( doAnimation ) :\n\t\t\tthis.queue( optall.queue, doAnimation );\n\t},\n\tstop: function( type, clearQueue, gotoEnd ) {\n\t\tvar stopQueue = function( hooks ) {\n\t\t\tvar stop = hooks.stop;\n\t\t\tdelete hooks.stop;\n\t\t\tstop( gotoEnd );\n\t\t};\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tgotoEnd = clearQueue;\n\t\t\tclearQueue = type;\n\t\t\ttype = undefined;\n\t\t}\n\t\tif ( clearQueue && type !== false ) {\n\t\t\tthis.queue( type || \"fx\", [] );\n\t\t}\n\n\t\treturn this.each(function() {\n\t\t\tvar dequeue = true,\n\t\t\t\tindex = type != null && type + \"queueHooks\",\n\t\t\t\ttimers = jQuery.timers,\n\t\t\t\tdata = jQuery._data( this );\n\n\t\t\tif ( index ) {\n\t\t\t\tif ( data[ index ] && data[ index ].stop ) {\n\t\t\t\t\tstopQueue( data[ index ] );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor ( index in data ) {\n\t\t\t\t\tif ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {\n\t\t\t\t\t\tstopQueue( data[ index ] );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor ( index = timers.length; index--; ) {\n\t\t\t\tif ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {\n\t\t\t\t\ttimers[ index ].anim.stop( gotoEnd );\n\t\t\t\t\tdequeue = false;\n\t\t\t\t\ttimers.splice( index, 1 );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// start the next in the queue if the last step wasn't forced\n\t\t\t// timers currently will call their complete callbacks, which will dequeue\n\t\t\t// but only if they were gotoEnd\n\t\t\tif ( dequeue || !gotoEnd ) {\n\t\t\t\tjQuery.dequeue( this, type );\n\t\t\t}\n\t\t});\n\t},\n\tfinish: function( type ) {\n\t\tif ( type !== false ) {\n\t\t\ttype = type || \"fx\";\n\t\t}\n\t\treturn this.each(function() {\n\t\t\tvar index,\n\t\t\t\tdata = jQuery._data( this ),\n\t\t\t\tqueue = data[ type + \"queue\" ],\n\t\t\t\thooks = data[ type + \"queueHooks\" ],\n\t\t\t\ttimers = jQuery.timers,\n\t\t\t\tlength = queue ? queue.length : 0;\n\n\t\t\t// enable finishing flag on private data\n\t\t\tdata.finish = true;\n\n\t\t\t// empty the queue first\n\t\t\tjQuery.queue( this, type, [] );\n\n\t\t\tif ( hooks && hooks.cur && hooks.cur.finish ) {\n\t\t\t\thooks.cur.finish.call( this );\n\t\t\t}\n\n\t\t\t// look for any active animations, and finish them\n\t\t\tfor ( index = timers.length; index--; ) {\n\t\t\t\tif ( timers[ index ].elem === this && timers[ index ].queue === type ) {\n\t\t\t\t\ttimers[ index ].anim.stop( true );\n\t\t\t\t\ttimers.splice( index, 1 );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// look for any animations in the old queue and finish them\n\t\t\tfor ( index = 0; index < length; index++ ) {\n\t\t\t\tif ( queue[ index ] && queue[ index ].finish ) {\n\t\t\t\t\tqueue[ index ].finish.call( this );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// turn off finishing flag\n\t\t\tdelete data.finish;\n\t\t});\n\t}\n});\n\n// Generate parameters to create a standard animation\nfunction genFx( type, includeWidth ) {\n\tvar which,\n\t\tattrs = { height: type },\n\t\ti = 0;\n\n\t// if we include width, step value is 1 to do all cssExpand values,\n\t// if we don't include width, step value is 2 to skip over Left and Right\n\tincludeWidth = includeWidth? 1 : 0;\n\tfor( ; i < 4 ; i += 2 - includeWidth ) {\n\t\twhich = cssExpand[ i ];\n\t\tattrs[ \"margin\" + which ] = attrs[ \"padding\" + which ] = type;\n\t}\n\n\tif ( includeWidth ) {\n\t\tattrs.opacity = attrs.width = type;\n\t}\n\n\treturn attrs;\n}\n\n// Generate shortcuts for custom animations\njQuery.each({\n\tslideDown: genFx(\"show\"),\n\tslideUp: genFx(\"hide\"),\n\tslideToggle: genFx(\"toggle\"),\n\tfadeIn: { opacity: \"show\" },\n\tfadeOut: { opacity: \"hide\" },\n\tfadeToggle: { opacity: \"toggle\" }\n}, function( name, props ) {\n\tjQuery.fn[ name ] = function( speed, easing, callback ) {\n\t\treturn this.animate( props, speed, easing, callback );\n\t};\n});\n\njQuery.speed = function( speed, easing, fn ) {\n\tvar opt = speed && typeof speed === \"object\" ? jQuery.extend( {}, speed ) : {\n\t\tcomplete: fn || !fn && easing ||\n\t\t\tjQuery.isFunction( speed ) && speed,\n\t\tduration: speed,\n\t\teasing: fn && easing || easing && !jQuery.isFunction( easing ) && easing\n\t};\n\n\topt.duration = jQuery.fx.off ? 0 : typeof opt.duration === \"number\" ? opt.duration :\n\t\topt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;\n\n\t// normalize opt.queue - true/undefined/null -> \"fx\"\n\tif ( opt.queue == null || opt.queue === true ) {\n\t\topt.queue = \"fx\";\n\t}\n\n\t// Queueing\n\topt.old = opt.complete;\n\n\topt.complete = function() {\n\t\tif ( jQuery.isFunction( opt.old ) ) {\n\t\t\topt.old.call( this );\n\t\t}\n\n\t\tif ( opt.queue ) {\n\t\t\tjQuery.dequeue( this, opt.queue );\n\t\t}\n\t};\n\n\treturn opt;\n};\n\njQuery.easing = {\n\tlinear: function( p ) {\n\t\treturn p;\n\t},\n\tswing: function( p ) {\n\t\treturn 0.5 - Math.cos( p*Math.PI ) / 2;\n\t}\n};\n\njQuery.timers = [];\njQuery.fx = Tween.prototype.init;\njQuery.fx.tick = function() {\n\tvar timer,\n\t\ttimers = jQuery.timers,\n\t\ti = 0;\n\n\tfxNow = jQuery.now();\n\n\tfor ( ; i < timers.length; i++ ) {\n\t\ttimer = timers[ i ];\n\t\t// Checks the timer has not already been removed\n\t\tif ( !timer() && timers[ i ] === timer ) {\n\t\t\ttimers.splice( i--, 1 );\n\t\t}\n\t}\n\n\tif ( !timers.length ) {\n\t\tjQuery.fx.stop();\n\t}\n\tfxNow = undefined;\n};\n\njQuery.fx.timer = function( timer ) {\n\tif ( timer() && jQuery.timers.push( timer ) ) {\n\t\tjQuery.fx.start();\n\t}\n};\n\njQuery.fx.interval = 13;\n\njQuery.fx.start = function() {\n\tif ( !timerId ) {\n\t\ttimerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );\n\t}\n};\n\njQuery.fx.stop = function() {\n\tclearInterval( timerId );\n\ttimerId = null;\n};\n\njQuery.fx.speeds = {\n\tslow: 600,\n\tfast: 200,\n\t// Default speed\n\t_default: 400\n};\n\n// Back Compat <1.8 extension point\njQuery.fx.step = {};\n\nif ( jQuery.expr && jQuery.expr.filters ) {\n\tjQuery.expr.filters.animated = function( elem ) {\n\t\treturn jQuery.grep(jQuery.timers, function( fn ) {\n\t\t\treturn elem === fn.elem;\n\t\t}).length;\n\t};\n}\njQuery.fn.offset = function( options ) {\n\tif ( arguments.length ) {\n\t\treturn options === undefined ?\n\t\t\tthis :\n\t\t\tthis.each(function( i ) {\n\t\t\t\tjQuery.offset.setOffset( this, options, i );\n\t\t\t});\n\t}\n\n\tvar docElem, win,\n\t\tbox = { top: 0, left: 0 },\n\t\telem = this[ 0 ],\n\t\tdoc = elem && elem.ownerDocument;\n\n\tif ( !doc ) {\n\t\treturn;\n\t}\n\n\tdocElem = doc.documentElement;\n\n\t// Make sure it's not a disconnected DOM node\n\tif ( !jQuery.contains( docElem, elem ) ) {\n\t\treturn box;\n\t}\n\n\t// If we don't have gBCR, just use 0,0 rather than error\n\t// BlackBerry 5, iOS 3 (original iPhone)\n\tif ( typeof elem.getBoundingClientRect !== core_strundefined ) {\n\t\tbox = elem.getBoundingClientRect();\n\t}\n\twin = getWindow( doc );\n\treturn {\n\t\ttop: box.top  + ( win.pageYOffset || docElem.scrollTop )  - ( docElem.clientTop  || 0 ),\n\t\tleft: box.left + ( win.pageXOffset || docElem.scrollLeft ) - ( docElem.clientLeft || 0 )\n\t};\n};\n\njQuery.offset = {\n\n\tsetOffset: function( elem, options, i ) {\n\t\tvar position = jQuery.css( elem, \"position\" );\n\n\t\t// set position first, in-case top/left are set even on static elem\n\t\tif ( position === \"static\" ) {\n\t\t\telem.style.position = \"relative\";\n\t\t}\n\n\t\tvar curElem = jQuery( elem ),\n\t\t\tcurOffset = curElem.offset(),\n\t\t\tcurCSSTop = jQuery.css( elem, \"top\" ),\n\t\t\tcurCSSLeft = jQuery.css( elem, \"left\" ),\n\t\t\tcalculatePosition = ( position === \"absolute\" || position === \"fixed\" ) && jQuery.inArray(\"auto\", [curCSSTop, curCSSLeft]) > -1,\n\t\t\tprops = {}, curPosition = {}, curTop, curLeft;\n\n\t\t// need to be able to calculate position if either top or left is auto and position is either absolute or fixed\n\t\tif ( calculatePosition ) {\n\t\t\tcurPosition = curElem.position();\n\t\t\tcurTop = curPosition.top;\n\t\t\tcurLeft = curPosition.left;\n\t\t} else {\n\t\t\tcurTop = parseFloat( curCSSTop ) || 0;\n\t\t\tcurLeft = parseFloat( curCSSLeft ) || 0;\n\t\t}\n\n\t\tif ( jQuery.isFunction( options ) ) {\n\t\t\toptions = options.call( elem, i, curOffset );\n\t\t}\n\n\t\tif ( options.top != null ) {\n\t\t\tprops.top = ( options.top - curOffset.top ) + curTop;\n\t\t}\n\t\tif ( options.left != null ) {\n\t\t\tprops.left = ( options.left - curOffset.left ) + curLeft;\n\t\t}\n\n\t\tif ( \"using\" in options ) {\n\t\t\toptions.using.call( elem, props );\n\t\t} else {\n\t\t\tcurElem.css( props );\n\t\t}\n\t}\n};\n\n\njQuery.fn.extend({\n\n\tposition: function() {\n\t\tif ( !this[ 0 ] ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar offsetParent, offset,\n\t\t\tparentOffset = { top: 0, left: 0 },\n\t\t\telem = this[ 0 ];\n\n\t\t// fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is it's only offset parent\n\t\tif ( jQuery.css( elem, \"position\" ) === \"fixed\" ) {\n\t\t\t// we assume that getBoundingClientRect is available when computed position is fixed\n\t\t\toffset = elem.getBoundingClientRect();\n\t\t} else {\n\t\t\t// Get *real* offsetParent\n\t\t\toffsetParent = this.offsetParent();\n\n\t\t\t// Get correct offsets\n\t\t\toffset = this.offset();\n\t\t\tif ( !jQuery.nodeName( offsetParent[ 0 ], \"html\" ) ) {\n\t\t\t\tparentOffset = offsetParent.offset();\n\t\t\t}\n\n\t\t\t// Add offsetParent borders\n\t\t\tparentOffset.top  += jQuery.css( offsetParent[ 0 ], \"borderTopWidth\", true );\n\t\t\tparentOffset.left += jQuery.css( offsetParent[ 0 ], \"borderLeftWidth\", true );\n\t\t}\n\n\t\t// Subtract parent offsets and element margins\n\t\t// note: when an element has margin: auto the offsetLeft and marginLeft\n\t\t// are the same in Safari causing offset.left to incorrectly be 0\n\t\treturn {\n\t\t\ttop:  offset.top  - parentOffset.top - jQuery.css( elem, \"marginTop\", true ),\n\t\t\tleft: offset.left - parentOffset.left - jQuery.css( elem, \"marginLeft\", true)\n\t\t};\n\t},\n\n\toffsetParent: function() {\n\t\treturn this.map(function() {\n\t\t\tvar offsetParent = this.offsetParent || document.documentElement;\n\t\t\twhile ( offsetParent && ( !jQuery.nodeName( offsetParent, \"html\" ) && jQuery.css( offsetParent, \"position\") === \"static\" ) ) {\n\t\t\t\toffsetParent = offsetParent.offsetParent;\n\t\t\t}\n\t\t\treturn offsetParent || document.documentElement;\n\t\t});\n\t}\n});\n\n\n// Create scrollLeft and scrollTop methods\njQuery.each( {scrollLeft: \"pageXOffset\", scrollTop: \"pageYOffset\"}, function( method, prop ) {\n\tvar top = /Y/.test( prop );\n\n\tjQuery.fn[ method ] = function( val ) {\n\t\treturn jQuery.access( this, function( elem, method, val ) {\n\t\t\tvar win = getWindow( elem );\n\n\t\t\tif ( val === undefined ) {\n\t\t\t\treturn win ? (prop in win) ? win[ prop ] :\n\t\t\t\t\twin.document.documentElement[ method ] :\n\t\t\t\t\telem[ method ];\n\t\t\t}\n\n\t\t\tif ( win ) {\n\t\t\t\twin.scrollTo(\n\t\t\t\t\t!top ? val : jQuery( win ).scrollLeft(),\n\t\t\t\t\ttop ? val : jQuery( win ).scrollTop()\n\t\t\t\t);\n\n\t\t\t} else {\n\t\t\t\telem[ method ] = val;\n\t\t\t}\n\t\t}, method, val, arguments.length, null );\n\t};\n});\n\nfunction getWindow( elem ) {\n\treturn jQuery.isWindow( elem ) ?\n\t\telem :\n\t\telem.nodeType === 9 ?\n\t\t\telem.defaultView || elem.parentWindow :\n\t\t\tfalse;\n}\n// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods\njQuery.each( { Height: \"height\", Width: \"width\" }, function( name, type ) {\n\tjQuery.each( { padding: \"inner\" + name, content: type, \"\": \"outer\" + name }, function( defaultExtra, funcName ) {\n\t\t// margin is only for outerHeight, outerWidth\n\t\tjQuery.fn[ funcName ] = function( margin, value ) {\n\t\t\tvar chainable = arguments.length && ( defaultExtra || typeof margin !== \"boolean\" ),\n\t\t\t\textra = defaultExtra || ( margin === true || value === true ? \"margin\" : \"border\" );\n\n\t\t\treturn jQuery.access( this, function( elem, type, value ) {\n\t\t\t\tvar doc;\n\n\t\t\t\tif ( jQuery.isWindow( elem ) ) {\n\t\t\t\t\t// As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there\n\t\t\t\t\t// isn't a whole lot we can do. See pull request at this URL for discussion:\n\t\t\t\t\t// https://github.com/jquery/jquery/pull/764\n\t\t\t\t\treturn elem.document.documentElement[ \"client\" + name ];\n\t\t\t\t}\n\n\t\t\t\t// Get document width or height\n\t\t\t\tif ( elem.nodeType === 9 ) {\n\t\t\t\t\tdoc = elem.documentElement;\n\n\t\t\t\t\t// Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], whichever is greatest\n\t\t\t\t\t// unfortunately, this causes bug #3838 in IE6/8 only, but there is currently no good, small way to fix it.\n\t\t\t\t\treturn Math.max(\n\t\t\t\t\t\telem.body[ \"scroll\" + name ], doc[ \"scroll\" + name ],\n\t\t\t\t\t\telem.body[ \"offset\" + name ], doc[ \"offset\" + name ],\n\t\t\t\t\t\tdoc[ \"client\" + name ]\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\treturn value === undefined ?\n\t\t\t\t\t// Get width or height on the element, requesting but not forcing parseFloat\n\t\t\t\t\tjQuery.css( elem, type, extra ) :\n\n\t\t\t\t\t// Set width or height on the element\n\t\t\t\t\tjQuery.style( elem, type, value, extra );\n\t\t\t}, type, chainable ? margin : undefined, chainable, null );\n\t\t};\n\t});\n});\n// Limit scope pollution from any deprecated API\n// (function() {\n\n// })();\n// Expose jQuery to the global object\nwindow.jQuery = window.$ = jQuery;\n\n// Expose jQuery as an AMD module, but only for AMD loaders that\n// understand the issues with loading multiple versions of jQuery\n// in a page that all might call define(). The loader will indicate\n// they have special allowances for multiple jQuery versions by\n// specifying define.amd.jQuery = true. Register as a named module,\n// since jQuery can be concatenated with other files that may use define,\n// but not use a proper concatenation script that understands anonymous\n// AMD modules. A named AMD is safest and most robust way to register.\n// Lowercase jquery is used because AMD module names are derived from\n// file names, and jQuery is normally delivered in a lowercase file name.\n// Do this after creating the global so that if an AMD module wants to call\n// noConflict to hide this version of jQuery, it will work.\nif ( typeof define === \"function\" && define.amd && define.amd.jQuery ) {\n\tdefine( \"jquery\", [], function () { return jQuery; } );\n}\n\n})( window );\n"
  },
  {
    "path": "explainshell/web/static/js/underscore.js",
    "content": "// Underscore.js 1.4.4\n// ===================\n\n// > http://underscorejs.org\n// > (c) 2009-2013 Jeremy Ashkenas, DocumentCloud Inc.\n// > Underscore may be freely distributed under the MIT license.\n\n// Baseline setup\n// --------------\n(function() {\n\n  // Establish the root object, `window` in the browser, or `global` on the server.\n  var root = this;\n\n  // Save the previous value of the `_` variable.\n  var previousUnderscore = root._;\n\n  // Establish the object that gets returned to break out of a loop iteration.\n  var breaker = {};\n\n  // Save bytes in the minified (but not gzipped) version:\n  var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;\n\n  // Create quick reference variables for speed access to core prototypes.\n  var push             = ArrayProto.push,\n      slice            = ArrayProto.slice,\n      concat           = ArrayProto.concat,\n      toString         = ObjProto.toString,\n      hasOwnProperty   = ObjProto.hasOwnProperty;\n\n  // All **ECMAScript 5** native function implementations that we hope to use\n  // are declared here.\n  var\n    nativeForEach      = ArrayProto.forEach,\n    nativeMap          = ArrayProto.map,\n    nativeReduce       = ArrayProto.reduce,\n    nativeReduceRight  = ArrayProto.reduceRight,\n    nativeFilter       = ArrayProto.filter,\n    nativeEvery        = ArrayProto.every,\n    nativeSome         = ArrayProto.some,\n    nativeIndexOf      = ArrayProto.indexOf,\n    nativeLastIndexOf  = ArrayProto.lastIndexOf,\n    nativeIsArray      = Array.isArray,\n    nativeKeys         = Object.keys,\n    nativeBind         = FuncProto.bind;\n\n  // Create a safe reference to the Underscore object for use below.\n  var _ = function(obj) {\n    if (obj instanceof _) return obj;\n    if (!(this instanceof _)) return new _(obj);\n    this._wrapped = obj;\n  };\n\n  // Export the Underscore object for **Node.js**, with\n  // backwards-compatibility for the old `require()` API. If we're in\n  // the browser, add `_` as a global object via a string identifier,\n  // for Closure Compiler \"advanced\" mode.\n  if (typeof exports !== 'undefined') {\n    if (typeof module !== 'undefined' && module.exports) {\n      exports = module.exports = _;\n    }\n    exports._ = _;\n  } else {\n    root._ = _;\n  }\n\n  // Current version.\n  _.VERSION = '1.4.4';\n\n  // Collection Functions\n  // --------------------\n\n  // The cornerstone, an `each` implementation, aka `forEach`.\n  // Handles objects with the built-in `forEach`, arrays, and raw objects.\n  // Delegates to **ECMAScript 5**'s native `forEach` if available.\n  var each = _.each = _.forEach = function(obj, iterator, context) {\n    if (obj == null) return;\n    if (nativeForEach && obj.forEach === nativeForEach) {\n      obj.forEach(iterator, context);\n    } else if (obj.length === +obj.length) {\n      for (var i = 0, l = obj.length; i < l; i++) {\n        if (iterator.call(context, obj[i], i, obj) === breaker) return;\n      }\n    } else {\n      for (var key in obj) {\n        if (_.has(obj, key)) {\n          if (iterator.call(context, obj[key], key, obj) === breaker) return;\n        }\n      }\n    }\n  };\n\n  // Return the results of applying the iterator to each element.\n  // Delegates to **ECMAScript 5**'s native `map` if available.\n  _.map = _.collect = function(obj, iterator, context) {\n    var results = [];\n    if (obj == null) return results;\n    if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);\n    each(obj, function(value, index, list) {\n      results[results.length] = iterator.call(context, value, index, list);\n    });\n    return results;\n  };\n\n  var reduceError = 'Reduce of empty array with no initial value';\n\n  // **Reduce** builds up a single result from a list of values, aka `inject`,\n  // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.\n  _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {\n    var initial = arguments.length > 2;\n    if (obj == null) obj = [];\n    if (nativeReduce && obj.reduce === nativeReduce) {\n      if (context) iterator = _.bind(iterator, context);\n      return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);\n    }\n    each(obj, function(value, index, list) {\n      if (!initial) {\n        memo = value;\n        initial = true;\n      } else {\n        memo = iterator.call(context, memo, value, index, list);\n      }\n    });\n    if (!initial) throw new TypeError(reduceError);\n    return memo;\n  };\n\n  // The right-associative version of reduce, also known as `foldr`.\n  // Delegates to **ECMAScript 5**'s native `reduceRight` if available.\n  _.reduceRight = _.foldr = function(obj, iterator, memo, context) {\n    var initial = arguments.length > 2;\n    if (obj == null) obj = [];\n    if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {\n      if (context) iterator = _.bind(iterator, context);\n      return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);\n    }\n    var length = obj.length;\n    if (length !== +length) {\n      var keys = _.keys(obj);\n      length = keys.length;\n    }\n    each(obj, function(value, index, list) {\n      index = keys ? keys[--length] : --length;\n      if (!initial) {\n        memo = obj[index];\n        initial = true;\n      } else {\n        memo = iterator.call(context, memo, obj[index], index, list);\n      }\n    });\n    if (!initial) throw new TypeError(reduceError);\n    return memo;\n  };\n\n  // Return the first value which passes a truth test. Aliased as `detect`.\n  _.find = _.detect = function(obj, iterator, context) {\n    var result;\n    any(obj, function(value, index, list) {\n      if (iterator.call(context, value, index, list)) {\n        result = value;\n        return true;\n      }\n    });\n    return result;\n  };\n\n  // Return all the elements that pass a truth test.\n  // Delegates to **ECMAScript 5**'s native `filter` if available.\n  // Aliased as `select`.\n  _.filter = _.select = function(obj, iterator, context) {\n    var results = [];\n    if (obj == null) return results;\n    if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);\n    each(obj, function(value, index, list) {\n      if (iterator.call(context, value, index, list)) results[results.length] = value;\n    });\n    return results;\n  };\n\n  // Return all the elements for which a truth test fails.\n  _.reject = function(obj, iterator, context) {\n    return _.filter(obj, function(value, index, list) {\n      return !iterator.call(context, value, index, list);\n    }, context);\n  };\n\n  // Determine whether all of the elements match a truth test.\n  // Delegates to **ECMAScript 5**'s native `every` if available.\n  // Aliased as `all`.\n  _.every = _.all = function(obj, iterator, context) {\n    iterator || (iterator = _.identity);\n    var result = true;\n    if (obj == null) return result;\n    if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);\n    each(obj, function(value, index, list) {\n      if (!(result = result && iterator.call(context, value, index, list))) return breaker;\n    });\n    return !!result;\n  };\n\n  // Determine if at least one element in the object matches a truth test.\n  // Delegates to **ECMAScript 5**'s native `some` if available.\n  // Aliased as `any`.\n  var any = _.some = _.any = function(obj, iterator, context) {\n    iterator || (iterator = _.identity);\n    var result = false;\n    if (obj == null) return result;\n    if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);\n    each(obj, function(value, index, list) {\n      if (result || (result = iterator.call(context, value, index, list))) return breaker;\n    });\n    return !!result;\n  };\n\n  // Determine if the array or object contains a given value (using `===`).\n  // Aliased as `include`.\n  _.contains = _.include = function(obj, target) {\n    if (obj == null) return false;\n    if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;\n    return any(obj, function(value) {\n      return value === target;\n    });\n  };\n\n  // Invoke a method (with arguments) on every item in a collection.\n  _.invoke = function(obj, method) {\n    var args = slice.call(arguments, 2);\n    var isFunc = _.isFunction(method);\n    return _.map(obj, function(value) {\n      return (isFunc ? method : value[method]).apply(value, args);\n    });\n  };\n\n  // Convenience version of a common use case of `map`: fetching a property.\n  _.pluck = function(obj, key) {\n    return _.map(obj, function(value){ return value[key]; });\n  };\n\n  // Convenience version of a common use case of `filter`: selecting only objects\n  // containing specific `key:value` pairs.\n  _.where = function(obj, attrs, first) {\n    if (_.isEmpty(attrs)) return first ? null : [];\n    return _[first ? 'find' : 'filter'](obj, function(value) {\n      for (var key in attrs) {\n        if (attrs[key] !== value[key]) return false;\n      }\n      return true;\n    });\n  };\n\n  // Convenience version of a common use case of `find`: getting the first object\n  // containing specific `key:value` pairs.\n  _.findWhere = function(obj, attrs) {\n    return _.where(obj, attrs, true);\n  };\n\n  // Return the maximum element or (element-based computation).\n  // Can't optimize arrays of integers longer than 65,535 elements.\n  // See: https://bugs.webkit.org/show_bug.cgi?id=80797\n  _.max = function(obj, iterator, context) {\n    if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {\n      return Math.max.apply(Math, obj);\n    }\n    if (!iterator && _.isEmpty(obj)) return -Infinity;\n    var result = {computed : -Infinity, value: -Infinity};\n    each(obj, function(value, index, list) {\n      var computed = iterator ? iterator.call(context, value, index, list) : value;\n      computed >= result.computed && (result = {value : value, computed : computed});\n    });\n    return result.value;\n  };\n\n  // Return the minimum element (or element-based computation).\n  _.min = function(obj, iterator, context) {\n    if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {\n      return Math.min.apply(Math, obj);\n    }\n    if (!iterator && _.isEmpty(obj)) return Infinity;\n    var result = {computed : Infinity, value: Infinity};\n    each(obj, function(value, index, list) {\n      var computed = iterator ? iterator.call(context, value, index, list) : value;\n      computed < result.computed && (result = {value : value, computed : computed});\n    });\n    return result.value;\n  };\n\n  // Shuffle an array.\n  _.shuffle = function(obj) {\n    var rand;\n    var index = 0;\n    var shuffled = [];\n    each(obj, function(value) {\n      rand = _.random(index++);\n      shuffled[index - 1] = shuffled[rand];\n      shuffled[rand] = value;\n    });\n    return shuffled;\n  };\n\n  // An internal function to generate lookup iterators.\n  var lookupIterator = function(value) {\n    return _.isFunction(value) ? value : function(obj){ return obj[value]; };\n  };\n\n  // Sort the object's values by a criterion produced by an iterator.\n  _.sortBy = function(obj, value, context) {\n    var iterator = lookupIterator(value);\n    return _.pluck(_.map(obj, function(value, index, list) {\n      return {\n        value : value,\n        index : index,\n        criteria : iterator.call(context, value, index, list)\n      };\n    }).sort(function(left, right) {\n      var a = left.criteria;\n      var b = right.criteria;\n      if (a !== b) {\n        if (a > b || a === void 0) return 1;\n        if (a < b || b === void 0) return -1;\n      }\n      return left.index < right.index ? -1 : 1;\n    }), 'value');\n  };\n\n  // An internal function used for aggregate \"group by\" operations.\n  var group = function(obj, value, context, behavior) {\n    var result = {};\n    var iterator = lookupIterator(value || _.identity);\n    each(obj, function(value, index) {\n      var key = iterator.call(context, value, index, obj);\n      behavior(result, key, value);\n    });\n    return result;\n  };\n\n  // Groups the object's values by a criterion. Pass either a string attribute\n  // to group by, or a function that returns the criterion.\n  _.groupBy = function(obj, value, context) {\n    return group(obj, value, context, function(result, key, value) {\n      (_.has(result, key) ? result[key] : (result[key] = [])).push(value);\n    });\n  };\n\n  // Counts instances of an object that group by a certain criterion. Pass\n  // either a string attribute to count by, or a function that returns the\n  // criterion.\n  _.countBy = function(obj, value, context) {\n    return group(obj, value, context, function(result, key) {\n      if (!_.has(result, key)) result[key] = 0;\n      result[key]++;\n    });\n  };\n\n  // Use a comparator function to figure out the smallest index at which\n  // an object should be inserted so as to maintain order. Uses binary search.\n  _.sortedIndex = function(array, obj, iterator, context) {\n    iterator = iterator == null ? _.identity : lookupIterator(iterator);\n    var value = iterator.call(context, obj);\n    var low = 0, high = array.length;\n    while (low < high) {\n      var mid = (low + high) >>> 1;\n      iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid;\n    }\n    return low;\n  };\n\n  // Safely convert anything iterable into a real, live array.\n  _.toArray = function(obj) {\n    if (!obj) return [];\n    if (_.isArray(obj)) return slice.call(obj);\n    if (obj.length === +obj.length) return _.map(obj, _.identity);\n    return _.values(obj);\n  };\n\n  // Return the number of elements in an object.\n  _.size = function(obj) {\n    if (obj == null) return 0;\n    return (obj.length === +obj.length) ? obj.length : _.keys(obj).length;\n  };\n\n  // Array Functions\n  // ---------------\n\n  // Get the first element of an array. Passing **n** will return the first N\n  // values in the array. Aliased as `head` and `take`. The **guard** check\n  // allows it to work with `_.map`.\n  _.first = _.head = _.take = function(array, n, guard) {\n    if (array == null) return void 0;\n    return (n != null) && !guard ? slice.call(array, 0, n) : array[0];\n  };\n\n  // Returns everything but the last entry of the array. Especially useful on\n  // the arguments object. Passing **n** will return all the values in\n  // the array, excluding the last N. The **guard** check allows it to work with\n  // `_.map`.\n  _.initial = function(array, n, guard) {\n    return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));\n  };\n\n  // Get the last element of an array. Passing **n** will return the last N\n  // values in the array. The **guard** check allows it to work with `_.map`.\n  _.last = function(array, n, guard) {\n    if (array == null) return void 0;\n    if ((n != null) && !guard) {\n      return slice.call(array, Math.max(array.length - n, 0));\n    } else {\n      return array[array.length - 1];\n    }\n  };\n\n  // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.\n  // Especially useful on the arguments object. Passing an **n** will return\n  // the rest N values in the array. The **guard**\n  // check allows it to work with `_.map`.\n  _.rest = _.tail = _.drop = function(array, n, guard) {\n    return slice.call(array, (n == null) || guard ? 1 : n);\n  };\n\n  // Trim out all falsy values from an array.\n  _.compact = function(array) {\n    return _.filter(array, _.identity);\n  };\n\n  // Internal implementation of a recursive `flatten` function.\n  var flatten = function(input, shallow, output) {\n    each(input, function(value) {\n      if (_.isArray(value)) {\n        shallow ? push.apply(output, value) : flatten(value, shallow, output);\n      } else {\n        output.push(value);\n      }\n    });\n    return output;\n  };\n\n  // Return a completely flattened version of an array.\n  _.flatten = function(array, shallow) {\n    return flatten(array, shallow, []);\n  };\n\n  // Return a version of the array that does not contain the specified value(s).\n  _.without = function(array) {\n    return _.difference(array, slice.call(arguments, 1));\n  };\n\n  // Produce a duplicate-free version of the array. If the array has already\n  // been sorted, you have the option of using a faster algorithm.\n  // Aliased as `unique`.\n  _.uniq = _.unique = function(array, isSorted, iterator, context) {\n    if (_.isFunction(isSorted)) {\n      context = iterator;\n      iterator = isSorted;\n      isSorted = false;\n    }\n    var initial = iterator ? _.map(array, iterator, context) : array;\n    var results = [];\n    var seen = [];\n    each(initial, function(value, index) {\n      if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) {\n        seen.push(value);\n        results.push(array[index]);\n      }\n    });\n    return results;\n  };\n\n  // Produce an array that contains the union: each distinct element from all of\n  // the passed-in arrays.\n  _.union = function() {\n    return _.uniq(concat.apply(ArrayProto, arguments));\n  };\n\n  // Produce an array that contains every item shared between all the\n  // passed-in arrays.\n  _.intersection = function(array) {\n    var rest = slice.call(arguments, 1);\n    return _.filter(_.uniq(array), function(item) {\n      return _.every(rest, function(other) {\n        return _.indexOf(other, item) >= 0;\n      });\n    });\n  };\n\n  // Take the difference between one array and a number of other arrays.\n  // Only the elements present in just the first array will remain.\n  _.difference = function(array) {\n    var rest = concat.apply(ArrayProto, slice.call(arguments, 1));\n    return _.filter(array, function(value){ return !_.contains(rest, value); });\n  };\n\n  // Zip together multiple lists into a single array -- elements that share\n  // an index go together.\n  _.zip = function() {\n    var args = slice.call(arguments);\n    var length = _.max(_.pluck(args, 'length'));\n    var results = new Array(length);\n    for (var i = 0; i < length; i++) {\n      results[i] = _.pluck(args, \"\" + i);\n    }\n    return results;\n  };\n\n  // Converts lists into objects. Pass either a single array of `[key, value]`\n  // pairs, or two parallel arrays of the same length -- one of keys, and one of\n  // the corresponding values.\n  _.object = function(list, values) {\n    if (list == null) return {};\n    var result = {};\n    for (var i = 0, l = list.length; i < l; i++) {\n      if (values) {\n        result[list[i]] = values[i];\n      } else {\n        result[list[i][0]] = list[i][1];\n      }\n    }\n    return result;\n  };\n\n  // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),\n  // we need this function. Return the position of the first occurrence of an\n  // item in an array, or -1 if the item is not included in the array.\n  // Delegates to **ECMAScript 5**'s native `indexOf` if available.\n  // If the array is large and already in sort order, pass `true`\n  // for **isSorted** to use binary search.\n  _.indexOf = function(array, item, isSorted) {\n    if (array == null) return -1;\n    var i = 0, l = array.length;\n    if (isSorted) {\n      if (typeof isSorted == 'number') {\n        i = (isSorted < 0 ? Math.max(0, l + isSorted) : isSorted);\n      } else {\n        i = _.sortedIndex(array, item);\n        return array[i] === item ? i : -1;\n      }\n    }\n    if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted);\n    for (; i < l; i++) if (array[i] === item) return i;\n    return -1;\n  };\n\n  // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.\n  _.lastIndexOf = function(array, item, from) {\n    if (array == null) return -1;\n    var hasIndex = from != null;\n    if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) {\n      return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item);\n    }\n    var i = (hasIndex ? from : array.length);\n    while (i--) if (array[i] === item) return i;\n    return -1;\n  };\n\n  // Generate an integer Array containing an arithmetic progression. A port of\n  // the native Python `range()` function. See\n  // [the Python documentation](http://docs.python.org/library/functions.html#range).\n  _.range = function(start, stop, step) {\n    if (arguments.length <= 1) {\n      stop = start || 0;\n      start = 0;\n    }\n    step = arguments[2] || 1;\n\n    var len = Math.max(Math.ceil((stop - start) / step), 0);\n    var idx = 0;\n    var range = new Array(len);\n\n    while(idx < len) {\n      range[idx++] = start;\n      start += step;\n    }\n\n    return range;\n  };\n\n  // Function (ahem) Functions\n  // ------------------\n\n  // Create a function bound to a given object (assigning `this`, and arguments,\n  // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if\n  // available.\n  _.bind = function(func, context) {\n    if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));\n    var args = slice.call(arguments, 2);\n    return function() {\n      return func.apply(context, args.concat(slice.call(arguments)));\n    };\n  };\n\n  // Partially apply a function by creating a version that has had some of its\n  // arguments pre-filled, without changing its dynamic `this` context.\n  _.partial = function(func) {\n    var args = slice.call(arguments, 1);\n    return function() {\n      return func.apply(this, args.concat(slice.call(arguments)));\n    };\n  };\n\n  // Bind all of an object's methods to that object. Useful for ensuring that\n  // all callbacks defined on an object belong to it.\n  _.bindAll = function(obj) {\n    var funcs = slice.call(arguments, 1);\n    if (funcs.length === 0) funcs = _.functions(obj);\n    each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });\n    return obj;\n  };\n\n  // Memoize an expensive function by storing its results.\n  _.memoize = function(func, hasher) {\n    var memo = {};\n    hasher || (hasher = _.identity);\n    return function() {\n      var key = hasher.apply(this, arguments);\n      return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));\n    };\n  };\n\n  // Delays a function for the given number of milliseconds, and then calls\n  // it with the arguments supplied.\n  _.delay = function(func, wait) {\n    var args = slice.call(arguments, 2);\n    return setTimeout(function(){ return func.apply(null, args); }, wait);\n  };\n\n  // Defers a function, scheduling it to run after the current call stack has\n  // cleared.\n  _.defer = function(func) {\n    return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));\n  };\n\n  // Returns a function, that, when invoked, will only be triggered at most once\n  // during a given window of time.\n  _.throttle = function(func, wait) {\n    var context, args, timeout, result;\n    var previous = 0;\n    var later = function() {\n      previous = new Date;\n      timeout = null;\n      result = func.apply(context, args);\n    };\n    return function() {\n      var now = new Date;\n      var remaining = wait - (now - previous);\n      context = this;\n      args = arguments;\n      if (remaining <= 0) {\n        clearTimeout(timeout);\n        timeout = null;\n        previous = now;\n        result = func.apply(context, args);\n      } else if (!timeout) {\n        timeout = setTimeout(later, remaining);\n      }\n      return result;\n    };\n  };\n\n  // Returns a function, that, as long as it continues to be invoked, will not\n  // be triggered. The function will be called after it stops being called for\n  // N milliseconds. If `immediate` is passed, trigger the function on the\n  // leading edge, instead of the trailing.\n  _.debounce = function(func, wait, immediate) {\n    var timeout, result;\n    return function() {\n      var context = this, args = arguments;\n      var later = function() {\n        timeout = null;\n        if (!immediate) result = func.apply(context, args);\n      };\n      var callNow = immediate && !timeout;\n      clearTimeout(timeout);\n      timeout = setTimeout(later, wait);\n      if (callNow) result = func.apply(context, args);\n      return result;\n    };\n  };\n\n  // Returns a function that will be executed at most one time, no matter how\n  // often you call it. Useful for lazy initialization.\n  _.once = function(func) {\n    var ran = false, memo;\n    return function() {\n      if (ran) return memo;\n      ran = true;\n      memo = func.apply(this, arguments);\n      func = null;\n      return memo;\n    };\n  };\n\n  // Returns the first function passed as an argument to the second,\n  // allowing you to adjust arguments, run code before and after, and\n  // conditionally execute the original function.\n  _.wrap = function(func, wrapper) {\n    return function() {\n      var args = [func];\n      push.apply(args, arguments);\n      return wrapper.apply(this, args);\n    };\n  };\n\n  // Returns a function that is the composition of a list of functions, each\n  // consuming the return value of the function that follows.\n  _.compose = function() {\n    var funcs = arguments;\n    return function() {\n      var args = arguments;\n      for (var i = funcs.length - 1; i >= 0; i--) {\n        args = [funcs[i].apply(this, args)];\n      }\n      return args[0];\n    };\n  };\n\n  // Returns a function that will only be executed after being called N times.\n  _.after = function(times, func) {\n    if (times <= 0) return func();\n    return function() {\n      if (--times < 1) {\n        return func.apply(this, arguments);\n      }\n    };\n  };\n\n  // Object Functions\n  // ----------------\n\n  // Retrieve the names of an object's properties.\n  // Delegates to **ECMAScript 5**'s native `Object.keys`\n  _.keys = nativeKeys || function(obj) {\n    if (obj !== Object(obj)) throw new TypeError('Invalid object');\n    var keys = [];\n    for (var key in obj) if (_.has(obj, key)) keys[keys.length] = key;\n    return keys;\n  };\n\n  // Retrieve the values of an object's properties.\n  _.values = function(obj) {\n    var values = [];\n    for (var key in obj) if (_.has(obj, key)) values.push(obj[key]);\n    return values;\n  };\n\n  // Convert an object into a list of `[key, value]` pairs.\n  _.pairs = function(obj) {\n    var pairs = [];\n    for (var key in obj) if (_.has(obj, key)) pairs.push([key, obj[key]]);\n    return pairs;\n  };\n\n  // Invert the keys and values of an object. The values must be serializable.\n  _.invert = function(obj) {\n    var result = {};\n    for (var key in obj) if (_.has(obj, key)) result[obj[key]] = key;\n    return result;\n  };\n\n  // Return a sorted list of the function names available on the object.\n  // Aliased as `methods`\n  _.functions = _.methods = function(obj) {\n    var names = [];\n    for (var key in obj) {\n      if (_.isFunction(obj[key])) names.push(key);\n    }\n    return names.sort();\n  };\n\n  // Extend a given object with all the properties in passed-in object(s).\n  _.extend = function(obj) {\n    each(slice.call(arguments, 1), function(source) {\n      if (source) {\n        for (var prop in source) {\n          obj[prop] = source[prop];\n        }\n      }\n    });\n    return obj;\n  };\n\n  // Return a copy of the object only containing the whitelisted properties.\n  _.pick = function(obj) {\n    var copy = {};\n    var keys = concat.apply(ArrayProto, slice.call(arguments, 1));\n    each(keys, function(key) {\n      if (key in obj) copy[key] = obj[key];\n    });\n    return copy;\n  };\n\n   // Return a copy of the object without the blacklisted properties.\n  _.omit = function(obj) {\n    var copy = {};\n    var keys = concat.apply(ArrayProto, slice.call(arguments, 1));\n    for (var key in obj) {\n      if (!_.contains(keys, key)) copy[key] = obj[key];\n    }\n    return copy;\n  };\n\n  // Fill in a given object with default properties.\n  _.defaults = function(obj) {\n    each(slice.call(arguments, 1), function(source) {\n      if (source) {\n        for (var prop in source) {\n          if (obj[prop] == null) obj[prop] = source[prop];\n        }\n      }\n    });\n    return obj;\n  };\n\n  // Create a (shallow-cloned) duplicate of an object.\n  _.clone = function(obj) {\n    if (!_.isObject(obj)) return obj;\n    return _.isArray(obj) ? obj.slice() : _.extend({}, obj);\n  };\n\n  // Invokes interceptor with the obj, and then returns obj.\n  // The primary purpose of this method is to \"tap into\" a method chain, in\n  // order to perform operations on intermediate results within the chain.\n  _.tap = function(obj, interceptor) {\n    interceptor(obj);\n    return obj;\n  };\n\n  // Internal recursive comparison function for `isEqual`.\n  var eq = function(a, b, aStack, bStack) {\n    // Identical objects are equal. `0 === -0`, but they aren't identical.\n    // See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal.\n    if (a === b) return a !== 0 || 1 / a == 1 / b;\n    // A strict comparison is necessary because `null == undefined`.\n    if (a == null || b == null) return a === b;\n    // Unwrap any wrapped objects.\n    if (a instanceof _) a = a._wrapped;\n    if (b instanceof _) b = b._wrapped;\n    // Compare `[[Class]]` names.\n    var className = toString.call(a);\n    if (className != toString.call(b)) return false;\n    switch (className) {\n      // Strings, numbers, dates, and booleans are compared by value.\n      case '[object String]':\n        // Primitives and their corresponding object wrappers are equivalent; thus, `\"5\"` is\n        // equivalent to `new String(\"5\")`.\n        return a == String(b);\n      case '[object Number]':\n        // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for\n        // other numeric values.\n        return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b);\n      case '[object Date]':\n      case '[object Boolean]':\n        // Coerce dates and booleans to numeric primitive values. Dates are compared by their\n        // millisecond representations. Note that invalid dates with millisecond representations\n        // of `NaN` are not equivalent.\n        return +a == +b;\n      // RegExps are compared by their source patterns and flags.\n      case '[object RegExp]':\n        return a.source == b.source &&\n               a.global == b.global &&\n               a.multiline == b.multiline &&\n               a.ignoreCase == b.ignoreCase;\n    }\n    if (typeof a != 'object' || typeof b != 'object') return false;\n    // Assume equality for cyclic structures. The algorithm for detecting cyclic\n    // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.\n    var length = aStack.length;\n    while (length--) {\n      // Linear search. Performance is inversely proportional to the number of\n      // unique nested structures.\n      if (aStack[length] == a) return bStack[length] == b;\n    }\n    // Add the first object to the stack of traversed objects.\n    aStack.push(a);\n    bStack.push(b);\n    var size = 0, result = true;\n    // Recursively compare objects and arrays.\n    if (className == '[object Array]') {\n      // Compare array lengths to determine if a deep comparison is necessary.\n      size = a.length;\n      result = size == b.length;\n      if (result) {\n        // Deep compare the contents, ignoring non-numeric properties.\n        while (size--) {\n          if (!(result = eq(a[size], b[size], aStack, bStack))) break;\n        }\n      }\n    } else {\n      // Objects with different constructors are not equivalent, but `Object`s\n      // from different frames are.\n      var aCtor = a.constructor, bCtor = b.constructor;\n      if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) &&\n                               _.isFunction(bCtor) && (bCtor instanceof bCtor))) {\n        return false;\n      }\n      // Deep compare objects.\n      for (var key in a) {\n        if (_.has(a, key)) {\n          // Count the expected number of properties.\n          size++;\n          // Deep compare each member.\n          if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;\n        }\n      }\n      // Ensure that both objects contain the same number of properties.\n      if (result) {\n        for (key in b) {\n          if (_.has(b, key) && !(size--)) break;\n        }\n        result = !size;\n      }\n    }\n    // Remove the first object from the stack of traversed objects.\n    aStack.pop();\n    bStack.pop();\n    return result;\n  };\n\n  // Perform a deep comparison to check if two objects are equal.\n  _.isEqual = function(a, b) {\n    return eq(a, b, [], []);\n  };\n\n  // Is a given array, string, or object empty?\n  // An \"empty\" object has no enumerable own-properties.\n  _.isEmpty = function(obj) {\n    if (obj == null) return true;\n    if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;\n    for (var key in obj) if (_.has(obj, key)) return false;\n    return true;\n  };\n\n  // Is a given value a DOM element?\n  _.isElement = function(obj) {\n    return !!(obj && obj.nodeType === 1);\n  };\n\n  // Is a given value an array?\n  // Delegates to ECMA5's native Array.isArray\n  _.isArray = nativeIsArray || function(obj) {\n    return toString.call(obj) == '[object Array]';\n  };\n\n  // Is a given variable an object?\n  _.isObject = function(obj) {\n    return obj === Object(obj);\n  };\n\n  // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp.\n  each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {\n    _['is' + name] = function(obj) {\n      return toString.call(obj) == '[object ' + name + ']';\n    };\n  });\n\n  // Define a fallback version of the method in browsers (ahem, IE), where\n  // there isn't any inspectable \"Arguments\" type.\n  if (!_.isArguments(arguments)) {\n    _.isArguments = function(obj) {\n      return !!(obj && _.has(obj, 'callee'));\n    };\n  }\n\n  // Optimize `isFunction` if appropriate.\n  if (typeof (/./) !== 'function') {\n    _.isFunction = function(obj) {\n      return typeof obj === 'function';\n    };\n  }\n\n  // Is a given object a finite number?\n  _.isFinite = function(obj) {\n    return isFinite(obj) && !isNaN(parseFloat(obj));\n  };\n\n  // Is the given value `NaN`? (NaN is the only number which does not equal itself).\n  _.isNaN = function(obj) {\n    return _.isNumber(obj) && obj != +obj;\n  };\n\n  // Is a given value a boolean?\n  _.isBoolean = function(obj) {\n    return obj === true || obj === false || toString.call(obj) == '[object Boolean]';\n  };\n\n  // Is a given value equal to null?\n  _.isNull = function(obj) {\n    return obj === null;\n  };\n\n  // Is a given variable undefined?\n  _.isUndefined = function(obj) {\n    return obj === void 0;\n  };\n\n  // Shortcut function for checking if an object has a given property directly\n  // on itself (in other words, not on a prototype).\n  _.has = function(obj, key) {\n    return hasOwnProperty.call(obj, key);\n  };\n\n  // Utility Functions\n  // -----------------\n\n  // Run Underscore.js in *noConflict* mode, returning the `_` variable to its\n  // previous owner. Returns a reference to the Underscore object.\n  _.noConflict = function() {\n    root._ = previousUnderscore;\n    return this;\n  };\n\n  // Keep the identity function around for default iterators.\n  _.identity = function(value) {\n    return value;\n  };\n\n  // Run a function **n** times.\n  _.times = function(n, iterator, context) {\n    var accum = Array(n);\n    for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i);\n    return accum;\n  };\n\n  // Return a random integer between min and max (inclusive).\n  _.random = function(min, max) {\n    if (max == null) {\n      max = min;\n      min = 0;\n    }\n    return min + Math.floor(Math.random() * (max - min + 1));\n  };\n\n  // List of HTML entities for escaping.\n  var entityMap = {\n    escape: {\n      '&': '&amp;',\n      '<': '&lt;',\n      '>': '&gt;',\n      '\"': '&quot;',\n      \"'\": '&#x27;',\n      '/': '&#x2F;'\n    }\n  };\n  entityMap.unescape = _.invert(entityMap.escape);\n\n  // Regexes containing the keys and values listed immediately above.\n  var entityRegexes = {\n    escape:   new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'),\n    unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g')\n  };\n\n  // Functions for escaping and unescaping strings to/from HTML interpolation.\n  _.each(['escape', 'unescape'], function(method) {\n    _[method] = function(string) {\n      if (string == null) return '';\n      return ('' + string).replace(entityRegexes[method], function(match) {\n        return entityMap[method][match];\n      });\n    };\n  });\n\n  // If the value of the named property is a function then invoke it;\n  // otherwise, return it.\n  _.result = function(object, property) {\n    if (object == null) return null;\n    var value = object[property];\n    return _.isFunction(value) ? value.call(object) : value;\n  };\n\n  // Add your own custom functions to the Underscore object.\n  _.mixin = function(obj) {\n    each(_.functions(obj), function(name){\n      var func = _[name] = obj[name];\n      _.prototype[name] = function() {\n        var args = [this._wrapped];\n        push.apply(args, arguments);\n        return result.call(this, func.apply(_, args));\n      };\n    });\n  };\n\n  // Generate a unique integer id (unique within the entire client session).\n  // Useful for temporary DOM ids.\n  var idCounter = 0;\n  _.uniqueId = function(prefix) {\n    var id = ++idCounter + '';\n    return prefix ? prefix + id : id;\n  };\n\n  // By default, Underscore uses ERB-style template delimiters, change the\n  // following template settings to use alternative delimiters.\n  _.templateSettings = {\n    evaluate    : /<%([\\s\\S]+?)%>/g,\n    interpolate : /<%=([\\s\\S]+?)%>/g,\n    escape      : /<%-([\\s\\S]+?)%>/g\n  };\n\n  // When customizing `templateSettings`, if you don't want to define an\n  // interpolation, evaluation or escaping regex, we need one that is\n  // guaranteed not to match.\n  var noMatch = /(.)^/;\n\n  // Certain characters need to be escaped so that they can be put into a\n  // string literal.\n  var escapes = {\n    \"'\":      \"'\",\n    '\\\\':     '\\\\',\n    '\\r':     'r',\n    '\\n':     'n',\n    '\\t':     't',\n    '\\u2028': 'u2028',\n    '\\u2029': 'u2029'\n  };\n\n  var escaper = /\\\\|'|\\r|\\n|\\t|\\u2028|\\u2029/g;\n\n  // JavaScript micro-templating, similar to John Resig's implementation.\n  // Underscore templating handles arbitrary delimiters, preserves whitespace,\n  // and correctly escapes quotes within interpolated code.\n  _.template = function(text, data, settings) {\n    var render;\n    settings = _.defaults({}, settings, _.templateSettings);\n\n    // Combine delimiters into one regular expression via alternation.\n    var matcher = new RegExp([\n      (settings.escape || noMatch).source,\n      (settings.interpolate || noMatch).source,\n      (settings.evaluate || noMatch).source\n    ].join('|') + '|$', 'g');\n\n    // Compile the template source, escaping string literals appropriately.\n    var index = 0;\n    var source = \"__p+='\";\n    text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {\n      source += text.slice(index, offset)\n        .replace(escaper, function(match) { return '\\\\' + escapes[match]; });\n\n      if (escape) {\n        source += \"'+\\n((__t=(\" + escape + \"))==null?'':_.escape(__t))+\\n'\";\n      }\n      if (interpolate) {\n        source += \"'+\\n((__t=(\" + interpolate + \"))==null?'':__t)+\\n'\";\n      }\n      if (evaluate) {\n        source += \"';\\n\" + evaluate + \"\\n__p+='\";\n      }\n      index = offset + match.length;\n      return match;\n    });\n    source += \"';\\n\";\n\n    // If a variable is not specified, place data values in local scope.\n    if (!settings.variable) source = 'with(obj||{}){\\n' + source + '}\\n';\n\n    source = \"var __t,__p='',__j=Array.prototype.join,\" +\n      \"print=function(){__p+=__j.call(arguments,'');};\\n\" +\n      source + \"return __p;\\n\";\n\n    try {\n      render = new Function(settings.variable || 'obj', '_', source);\n    } catch (e) {\n      e.source = source;\n      throw e;\n    }\n\n    if (data) return render(data, _);\n    var template = function(data) {\n      return render.call(this, data, _);\n    };\n\n    // Provide the compiled function source as a convenience for precompilation.\n    template.source = 'function(' + (settings.variable || 'obj') + '){\\n' + source + '}';\n\n    return template;\n  };\n\n  // Add a \"chain\" function, which will delegate to the wrapper.\n  _.chain = function(obj) {\n    return _(obj).chain();\n  };\n\n  // OOP\n  // ---------------\n  // If Underscore is called as a function, it returns a wrapped object that\n  // can be used OO-style. This wrapper holds altered versions of all the\n  // underscore functions. Wrapped objects may be chained.\n\n  // Helper function to continue chaining intermediate results.\n  var result = function(obj) {\n    return this._chain ? _(obj).chain() : obj;\n  };\n\n  // Add all of the Underscore functions to the wrapper object.\n  _.mixin(_);\n\n  // Add all mutator Array functions to the wrapper.\n  each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {\n    var method = ArrayProto[name];\n    _.prototype[name] = function() {\n      var obj = this._wrapped;\n      method.apply(obj, arguments);\n      if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0];\n      return result.call(this, obj);\n    };\n  });\n\n  // Add all accessor Array functions to the wrapper.\n  each(['concat', 'join', 'slice'], function(name) {\n    var method = ArrayProto[name];\n    _.prototype[name] = function() {\n      return result.call(this, method.apply(this._wrapped, arguments));\n    };\n  });\n\n  _.extend(_.prototype, {\n\n    // Start chaining a wrapped Underscore object.\n    chain: function() {\n      this._chain = true;\n      return this;\n    },\n\n    // Extracts the result from a wrapped and chained object.\n    value: function() {\n      return this._wrapped;\n    }\n\n  });\n\n}).call(this);\n"
  },
  {
    "path": "explainshell/web/templates/about.html",
    "content": "{% extends \"base.html\" %}\n{% block title %} - about{% endblock %}\n            {% block content -%}\n            <div id=\"about\">\n                <p>Hello,</p>\n                <p>This site contains 29761 parsed manpages from sections 1 and 8 found in\n                <a href=\"http://manpages.ubuntu.com/\">Ubuntu's manpage repository</a>.\n                A lot of heuristics were used to extract the arguments of each\n                program, and there are errors here and there, especially in\n                manpages that have a non-standard layout.</p>\n\n                <p>It is written in Python and uses <a\n                    href=\"https://github.com/idank/bashlex\">bashlex</a>, a bit\n                of NLTK (to find the interesting parts of the manpage),\n                a little d3.js (for the connecting lines graphic) and Flask. It\n                is served with uwsgi and nginx. Source code is available <a\n                href=\"https://github.com/idank/explainshell\">on github</a>.</p>\n\n                <p>My name is Idan Kamara and you can contact me at idan at explainshell dot com for any\n                questions or suggestions.</p>\n            </div>\n            {%- endblock %}\n"
  },
  {
    "path": "explainshell/web/templates/base.html",
    "content": "<!DOCTYPE html>\n<html>\n    <head>\n        <title>explainshell.com{% block title %}{% endblock %}</title>\n        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n        <!-- Bootstrap -->\n{%- if config.DEBUG %}\n    {% if request.cookies.get('theme', 'default') == 'default' %}\n        <link href=\"/static/css/bootstrap.min.css\" rel=\"stylesheet\" media=\"screen\" id=\"bootstrapCSS\">\n    {% else %}\n        <link href=\"/static/css/bootstrap-cyborg.min.css\" rel=\"stylesheet\" media=\"screen\" id=\"bootstrapCSS\">\n    {% endif %}\n        <link href=\"/static/css/font-awesome.min.css\" rel=\"stylesheet\" media=\"screen\">\n{% else %}\n    {% if request.cookies.get('theme', 'default') == 'default' %}\n        <link href=\"//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.1/css/bootstrap.min.css\" rel=\"stylesheet\" media=\"screen\" id=\"bootstrapCSS\">\n    {% else %}\n        <link href=\"//maxcdn.bootstrapcdn.com/bootswatch/2.3.1/cyborg/bootstrap.min.css\" rel=\"stylesheet\" media=\"screen\" id=\"bootstrapCSS\">\n    {% endif %}\n        <link href=\"//cdnjs.cloudflare.com/ajax/libs/font-awesome/3.2.1/css/font-awesome.min.css\" rel=\"stylesheet\">\n{%- endif %}\n        <link href=\"/static/css/es.css\" rel=\"stylesheet\" media=\"screen\">\n        <link href='//fonts.googleapis.com/css?family=Berkshire+Swash' rel='stylesheet' type='text/css'>\n        {% block head %}{% endblock %}\n    </head>\n    <body data-theme={{ request.cookies.get('theme', 'default')}}>\n        <div class=\"container\">\n            <div class=\"small-push\"></div>\n            <div class=\"header\">\n                <div class=\"text-center logo\">\n                    <a href=\"/\">\n                        explain<span class=\"shell\">shell</span>.<span class=\"dotcom\">com</span>\n                    </a>\n                </div>\n                <div style=\"position: relative;\">\n                    <ul class=\"inline menu\">\n                      <li><a href=\"/about\">about</a></li>\n                      <li><a href=\"https://github.com/idank/explainshell\"><i class=\"icon-github\"></i></a></li>\n                      {% block menu %}<li><form action='/explain' method='get'><input id=\"top-search\" name='cmd' type=\"text\" autocapitalize=\"off\" autocorrect=\"off\" placeholder=\"explain...\"></input></form></li>{% endblock %}\n                      <li id=\"themeContainer\" class=\"dropdown\">\n                        <span data-toggle=\"dropdown\">theme</span>\n                        <b class=\"caret\" data-toggle=\"dropdown\"></b>\n                        <ul class=\"dropdown-menu\" role=\"menu\" aria-labelledby=\"dropdownMenu\">\n                            <li><a tabindex=\"-1\" href=\"#\" data-theme-name=\"default\">Light</a></li>\n                            <li><a tabindex=\"-1\" href=\"#\" data-theme-name=\"dark\">Dark</a></li>\n                        </ul>\n                      </li>\n                    </ul>\n                </div>\n                <div class=\"small-push\"></div>\n                <div class=\"text-center\">\n                    {% block header %}{% endblock %}\n                </div>\n            </div>\n            {% block content %}{% endblock %}\n        </div>\n        {% block footer %}{% endblock %}\n{%- if config.DEBUG %}\n        <script src=\"/static/js/jquery.js\"></script>\n        <script src=\"/static/js/underscore.js\"></script>\n        <script src=\"/static/js/bootstrap.min.js\"></script>\n{% else %}\n        <script src=\"//cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js\"></script>\n        <script src=\"//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.4/underscore-min.js\"></script>\n        <script src=\"//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.1/js/bootstrap.min.js\"></script>\n{%- endif %}\n        <script src=\"/static/js/es.js\"></script>\n        {%- block js %}{% endblock %}\n    </body>\n</html>\n"
  },
  {
    "path": "explainshell/web/templates/debug.html",
    "content": "{% extends \"base.html\" %}\n\t{% block content %}\n            {% if d %}\n            <div class=\"small-push\"></div>\n            <div>\n                <table class=\"table table-condensed\">\n                    <thead>\n                        <tr>\n                            <th>name</th>\n                            <th>synopsis</th>\n                            <th>options</th>\n                        </tr>\n                    </thead>\n                    <tbody>\n                        {% for mp in d.manpages -%}\n                        <tr>\n                            <td><a href=\"/explain/{{ mp.name }}\">{{ mp.name }}</a></td>\n                            <td>{{ mp.synopsis }}</td>\n                            <td>{{ mp.options }}</td>\n                        </tr>\n                        {%- endfor %}\n                    </tbody>\n                </table>\n            </div>\n            {% endif %}\n{% endblock %}\n"
  },
  {
    "path": "explainshell/web/templates/errors/error.html",
    "content": "{% extends \"base.html\" %}\n            {% block content -%}\n            <div class=\"push\"></div>\n            <div class=\"row\">\n                <div class=\"span8 offset2\">\n                    <h4 style='color: #b94a48; text-transform: uppercase;'>{{ title }}</h4>\n                    {% block message %}{{ message|safe }}{% endblock %}\n                </div>\n            </div>\n            {%- endblock %}\n"
  },
  {
    "path": "explainshell/web/templates/errors/missingmanpage.html",
    "content": "{% extends \"errors/error.html\" %}\n{% block message -%}\nNo man page found for <span class=\"program-text\">{{ e|e }}</span>.\n{%- endblock %}\n"
  },
  {
    "path": "explainshell/web/templates/errors/parsingerror.html",
    "content": "{% extends \"errors/error.html\" %}\n{% block message -%}\n<div class=\"push\">{{ e }}</div>\n<pre style=\"overflow: auto; white-space: pre; word-wrap: normal;\">{{ e.s.decode('latin1')|e }}\n{{ ' '*e.position }}<b>^</b></pre>\n{%- endblock %}\n"
  },
  {
    "path": "explainshell/web/templates/explain.html",
    "content": "{% extends \"base.html\" %}\n{% block title %} - {{ getargs|e }}{% endblock %}\n\t{% block content %}\n            <div id=\"navigate\" style=\"position: relative;\" class=\"small-push\"></div>\n            <!--<span style=\"background-color:white;position: fixed; bottom:0; right:0;\" id=\"coords\"></span>-->\n            <div class=\"push\"></div>\n            <div id=\"bump-fixer\">\n                <div id=\"command-wrapper\">\n                    <svg id=\"canvas\">\n                    </svg>\n                    <div id=\"command\">\n                    {% import 'macros.html' as macros -%}\n                    {% for m in matches -%}\n                        {%- if m.name -%}\n                            {{ macros.outputcommandexplain(m) }}\n                        {%- else -%}\n                            <span {{ macros.spanclasses(m) }}>{{ m.match|safe }}</span>\n                        {%- endif -%}{{ m.spaces|safe }}\n                    {%- endfor %}\n                    </div>\n                    <div style=\"height: 5px;\"></div>\n                    <div style=\"height: 100px;\"></div>\n                </div>\n            </div>\n            <div>\n                <table id=\"help\" width=\"100%\">\n                    <tbody>\n                        {% for text, id in helptext -%}\n                        <tr>\n                            <td>\n                                <pre class=\"help-box\" id=\"{{ id }}\">{{ text|safe }}</pre>\n                            </td>\n                        </tr>\n                        {%- endfor %}\n                    </tbody>\n                </table>\n            </div>\n{% endblock %}\n{% block footer -%}\n<div class=\"push\"></div><div class=\"text-center\"><small>\n{% for m in matches if m.name %}\n{% if loop.first %}source manpages: {% endif %}\n<a href=\"http://manpages.ubuntu.com/manpages/precise/en/man{{ m.section }}/{{ m.source|e }}.html\">{{ m.name|e }}</a>{% if not loop.last %},&nbsp;{% endif %}\n{% endfor %}\n</small></div>\n{%- endblock %}\n{% block js -%}\n{% if config.DEBUG %}\n        <script src=\"/static/js/d3.v3.min.js\"></script>\n{% else %}\n        <script src=\"//cdnjs.cloudflare.com/ajax/libs/d3/3.1.6/d3.min.js\"></script>\n{%- endif %}\n        <script type=\"text/javascript\">\n            var $window = $(window),\n                helppres = $('#help pre');\n\n            adjustcommandfontsize();\n            currentgroup = initialize();\n            navigation();\n\n            $(document).ready(function() {\n                // set the query in the top search box from the url. assumes we\n                // take a single parameter.\n                if (window.location.search.split(\"&\").length == 1) {\n                    var cmdquery = window.location.search.substr(\"?cmd=\".length);\n                    $(\"#top-search\").val(decodeURIComponent(cmdquery.replace(/\\+/g, ' ')));\n                }\n\n                // when #command-wrapper position is changed to fixed, it'll be removed\n                // from the normal flow, and everything below it will up. we use this div\n                // to prevent that.\n                $('#bump-fixer').height($(\"#command-wrapper\").height());\n\n                $('#command-wrapper').affix({\n                    offset: { top: $('#command-wrapper').offset().top-10 }\n                });\n\n                drawgrouplines(currentgroup.commandselector);\n\n                var throttled = _.throttle(function() {\n                    draw()\n                }, 10);\n\n                $window.scroll(throttled);\n                $window.resize(throttled);\n            });\n        </script>\n{%- endblock %}\n"
  },
  {
    "path": "explainshell/web/templates/index.html",
    "content": "{% extends \"base.html\" %}\n{% import 'macros.html' as macros -%}\n{% block menu %}{% endblock %}\n{% block title %} - match command-line arguments to their help text{% endblock %}\n{% block head -%}\n        <meta name=\"author\" content=\"Idan Kamara\">\n        <meta name=\"description\" content=\"match command-line arguments to their help text\">\n{%- endblock %}\n        {% block header -%}\n            <div>write down a command-line to see the help text that matches each argument</div>\n            <div style=\"margin-top: 10px; font-weight: bold\">try <a href=\"http://showthedocs.com\">showthedocs</a> for explaining other languages</div>\n        {%- endblock %}\n            {% block content -%}\n            <div class=\"push\"></div>\n            <div class=\"text-center\">\n                <div class=\"input-append\">\n                    <form action='/explain' method=\"get\">\n                        <input id='explain' class=\"span10\" type=\"text\" name=\"cmd\" autocapitalize=\"off\" autocorrect=\"off\"></input>\n                        <button class=\"btn\" type=\"submit\">EXPLAIN</button>\n                    </form>\n                </div>\n            </div>\n            <div class=\"row\">\n                <div class=\"offset1 span10\" id=\"examples\">\n                    <h3>examples</h3>\n                    <ul>\n                        {{ macros.examplebullet(\":(){ :|:& };:\") }}\n                        {{ macros.examplebullet(\"for user in $(cut -f1 -d: /etc/passwd); do crontab -u $user -l 2>/dev/null; done\") }}\n                        {{ macros.examplebullet('file=$(echo `basename \"$file\"`)') }}\n                        {{ macros.examplebullet(\"true && { echo success; } || { echo failed; }\") }}\n                        {{ macros.examplebullet(\"cut -d ' ' -f 1 /var/log/apache2/access_logs | uniq -c | sort -n\") }}\n                        {{ macros.examplebullet('tar zcf - some-dir | ssh some-server \"cd /; tar xvzf -\"') }}\n                        {{ macros.examplebullet(\"tar xzvf archive.tar.gz\") }}\n                        {{ macros.examplebullet(\"find . -type f -print0\") }}\n                        {{ macros.examplebullet(\"ssh -i keyfile -f -N -L 1234:www.google.com:80 host\") }}\n                        {{ macros.examplebullet(\"git log --graph --abbrev-commit --pretty=oneline origin..mybranch\") }}\n                    </ul>\n                </div>\n            </div>\n            {%- endblock %}\n{% block js -%}\n        <script type=\"text/javascript\">\n            $(\"#explain\").focus();\n        </script>\n{%- endblock %}\n"
  },
  {
    "path": "explainshell/web/templates/macros.html",
    "content": "{% macro outputcommand(mp, suggestions) -%}\n    {% if suggestions|length == 0 %}\n    <a href=\"http://manpages.ubuntu.com/manpages/precise/en/man{{ mp.section }}/{{ mp.source }}.html\">{{ mp.program|e }}</a>\n    {% else %}\n        <span class=\"dropdown\">\n            <b class=\"caret\" data-toggle=\"dropdown\"></b>\n            <a href=\"http://manpages.ubuntu.com/manpages/precise/en/man{{ mp.section }}/{{ mp.source }}.html\">{{ mp.program|e }}</a>\n            <ul class=\"dropdown-menu\" role=\"menu\" aria-labelledby=\"dropdownMenu\">\n              <li>other manpages</li>\n              <li class=\"divider\"></li>\n            {% for d in suggestions %}\n              <li><a tabindex=\"-1\" href=\"/explain/{{ d.link }}\">{{ d.text|e }}</a></li>\n            {% endfor %}\n            </ul>\n        </span>\n    {% endif %}\n    {% if mp.synopsis %}- {{ mp.synopsis|e }}{% endif %}\n{%- endmacro %}\n\n{%- macro outputcommandexplain(d) -%}\n    {% if d.suggestions|length == 0 -%}\n    <span {{ spanclasses(d) }} style=\"word-spacing: 0px;\"><a href=\"/explain/{{ d.section }}/{{ d.source }}\">{{ d.match|safe }}</a></span>\n    {%- else -%}\n                <span class=\"dropdown\">\n                    <span style=\"word-spacing: 0px;\">\n                    <b class=\"caret\" data-toggle=\"dropdown\"></b>\n                    <span {{ spanclasses(d) }}><a href=\"/explain/{{ d.section }}/{{ d.source }}\">{{ d.match|safe }}</a></span>\n                    <ul class=\"dropdown-menu\" role=\"menu\" aria-labelledby=\"dropdownMenu\">\n                      <li>other manpages</li>\n                      <li class=\"divider\"></li>\n                      {% for dd in d.suggestions -%}\n                      <li><a tabindex=\"-1\" href=\"/explain?cmd={{ dd.cmd|urlencode }}\">{{ dd.text|e }}</a></li>\n                      {%- endfor %}\n                    </ul>\n                    </span>\n                </span>\n    {%- endif %}\n{%- endmacro %}\n\n{%- macro spanclasses(d) -%}\nclass=\"{{ d.commandclass }}\"{% if d.helpclass %} helpref=\"{{ d.helpclass }}\"{% endif %}\n{%- endmacro %}\n\n{%- macro examplebullet(cmd) -%}\n<li><a href='/explain?cmd={{ cmd|urlencode }}'>{{ cmd|e }}</a></li>\n{%- endmacro %}\n"
  },
  {
    "path": "explainshell/web/templates/options.html",
    "content": "{% extends \"base.html\" %}\n{% set t = mp.program|e %}\n{% if mp.synopsis %}\n{% set t = mp.program|e + ' - ' + mp.synopsis|e %}\n{% endif %}\n{% block title %} - {{ t }}{% endblock %}\n\t{% block content %}\n            <div class=\"small-push\"></div>\n            <div class=\"push\"></div>\n            <div id=\"command\" style=\"word-spacing: 0px;\">\n                {% import 'macros.html' as macros %}\n                {{ macros.outputcommand(mp, suggestions) }}\n            </div>\n            <div class=\"small-push\"></div>\n            <div>\n                <table id=\"help\" width=\"100%\">\n                    <tbody>\n                        {% for desc in mp.options -%}\n                        <tr>\n                            <td>\n                                <pre>{{ desc|safe }}</pre>\n                            </td>\n                        </tr>\n                        {%- endfor %}\n                    </tbody>\n                </table>\n            </div>\n{% endblock %}\n"
  },
  {
    "path": "explainshell/web/templates/tagger.html",
    "content": "{% extends \"base.html\" %}\n\t{% block content %}\n            <div class=\"small-push\"></div>\n            <div class=\"push\"></div>\n            <div id=\"command\">\n                <a href=\"http://manpages.ubuntu.com/manpages/precise/en/man1/{{ m.name }}.html\">{{ m.name|e }}</a> - {{ m.synopsis|e }}\n            </div>\n            <div class=\"small-push\"></div>\n            <div style=\"width: 1000px;\">\n                <table id=\"help\" width=\"100%\">\n                    <tbody>\n                        {% for p in m.paragraphs -%}\n                        <tr>\n                            <td>\n                                {% if p.is_option %}\n                                <pre section=\"{{ p.section }}\" paragraph-id=\"{{ p.idx }}\" class=\"taggeroption\">{{ p.text|safe }}</pre>\n                                {% else %}\n                                <pre section=\"{{ p.section }}\" paragraph-id=\"{{ p.idx }}\" class=\"taggernooption\">{{ p.text|safe }}</pre>\n                                {% endif %}\n                            <span style=\"float: right\">\n                                <input type='text' placeholder=\"short\" class='input-small' {% if p.is_option and p.short %}value=\"{{ p.short|join(', ') }}\"{% endif %}/>\n                                <input type='text' placeholder=\"long\" class='input-small' {% if p.is_option and p.long %}value=\"{{ p.long|join(', ') }}\"{% endif %}/>\n                                <input type='text' placeholder=\"expectsarg\" class='input-small' {% if p.is_option and p.expectsarg %}value=\"{{ p.expectsarg }}\"{% endif %}/>\n                                <input type='text' placeholder=\"argument\" class='input-small' {% if p.is_option and p.argument %}value=\"{{ p.argument }}\"{% endif %}/>\n                                <input type='text' placeholder=\"nested\" class='input-small' {% if p.is_option and p.nestedcommand %}value=\"{{ p.nestedcommand }}\"{% endif %}/>\n                            </span>\n                            </td>\n                        </tr>\n                        {%- endfor %}\n                    </tbody>\n                </table>\n                <form id='tagsform' method='post'>\n                    <input name='paragraphs' type='hidden' id='paragraphs'/>\n                    <div>\n                        nestedcommand: <input type='checkbox' name='nestedcommand' value='true' {% if m.nestedcommand %}checked{% endif %}/>\n                        <input type='submit' class='btn'/>\n                    </div>\n                </form>\n            </div>\n{% endblock %}\n{% block js %}\n            <script type='text/javascript'>\n                //$(\".taggeroption\").parent().find(\"i\").addClass(\"icon-ok\");\n                //$(\".taggernooption\").parent().find(\"i\").addClass(\"icon-remove\");\n                var current = $(\"[paragraph-id=0]\");\n                var timeoutId;\n\n                function select() {\n                    $(current).removeClass('taggercurrent')\n                    current = $(this);\n                    $(current).addClass('taggercurrent')\n                }\n\n                function scrollTo(elem) {\n                    if (timeoutId)\n                        clearTimeout(timeoutId);\n                    timeoutId = setTimeout(scroll, 300);\n                    function scroll() {\n                        $('html, body').scrollTop(elem.offset().top);\n                    }\n\n                    $(current).removeClass('taggercurrent')\n                    current = elem;\n                    $(current).addClass('taggercurrent')\n                }\n\n                function gotoNext() {\n                    var next = $(current).parent().parent().next().find(\"[paragraph-id]\")\n\n                    scrollTo(next);\n                }\n\n                function gotoPrev() {\n                    var prev = $(current).parent().parent().prev().find(\"[paragraph-id]\")\n\n                    scrollTo(prev);\n                }\n\n                function toggleCurrent() {\n                    $(current).toggleClass(\"taggeroption\").toggleClass(\"taggernooption\");\n                    gotoNext();\n                }\n\n                function mergeCurrent() {\n                    var next = $(current).parent().parent().next().remove();\n                    var html = $(current).html();\n                    html += '\\n\\n';\n                    html += next.find(\"[paragraph-id]\").html();\n                    $(current).html(html);\n                }\n\n                function splitCurrent() {\n                    var newelement = $(current).parent().parent().clone(true);\n                    var html = $(current).html();\n                    var splitted = html.split('\\n\\n');\n                    if (splitted.length < 2)\n                        return;\n                    html = splitted.shift();\n                    $(current).html(html);\n\n                    newelement.find(\"input\").val('');\n                    var par = newelement.find(\"[paragraph-id]\");\n                    par.removeClass('taggercurrent')\n                    par.attr('paragraph-id', parseInt($(current).attr('paragraph-id')) + 1);\n                    par.html(splitted.join('\\n\\n'));\n                    $(current).parent().parent().after(newelement);\n                }\n\n                $(\"[paragraph-id]\").click(select);\n\n                $(\"body\").keyup(function(event) {\n                    var code = event.keyCode;\n\n                    if (code == 74) // j\n                        gotoNext();\n                    else if (code == 75) // k\n                        gotoPrev();\n                    else if (code == 77) // m\n                        mergeCurrent();\n                    else if (code == 83) // s\n                        splitCurrent();\n                    else if (code == 222) // '\n                        toggleCurrent();\n                    else if (code == 68) // d\n                        $('#tagsform').submit();\n                });\n\n                function setResults() {\n                    var all = $(\"[paragraph-id]\");\n                    var p = new Array();\n\n                    all.each(function(i, e) {\n                        var id = parseInt($(e).attr('paragraph-id'));\n\n                        var d = {}\n                        d[\"idx\"] = id;\n                        d[\"section\"] = $(e).attr('section');\n                        d[\"text\"] = $(e).html();\n                        if ($(e).hasClass('taggeroption')) {\n                            d[\"is_option\"] = true;\n                        }\n                        else {\n                            d[\"is_option\"] = false;\n                        }\n\n                        var inputs = $(e).parent().find(\"input\");\n                        d[\"short\"] = inputs[0].value ? inputs[0].value.split(',') : [];\n                        d[\"long\"] = inputs[1].value ? inputs[1].value.split(',') : [];\n                        d[\"expectsarg\"] = inputs[2].value;\n                        if (d[\"expectsarg\"].indexOf(\",\") != -1)\n                            d[\"expectsarg\"] = d[\"expectsarg\"].split(\",\");\n                        d[\"argument\"] = inputs[3].value;\n                        d[\"nestedcommand\"] = inputs[4].value;\n                        if (d[\"nestedcommand\"].indexOf(\",\") != -1)\n                            d[\"nestedcommand\"] = d[\"nestedcommand\"].split(\",\");\n                        p.push(d)\n                    });\n\n                    $(\"#paragraphs\").val(JSON.stringify(p));\n                }\n                $(document).ready(function() {\n                    scrollTo(current);\n\n                    $('#tagsform').submit(function() {\n                        setResults();\n                    });\n                });\n            </script>\n{% endblock %}\n"
  },
  {
    "path": "explainshell/web/views.py",
    "content": "import logging, itertools, urllib\nimport markupsafe\n\nfrom flask import render_template, request, redirect\n\nimport bashlex.errors\n\nfrom explainshell import matcher, errors, util, store, config\nfrom explainshell.web import app, helpers\n\nlogger = logging.getLogger(__name__)\n\n@app.route('/')\ndef index():\n    return render_template('index.html')\n\n@app.route('/about')\ndef about():\n    return render_template('about.html')\n\n@app.route('/explain')\ndef explain():\n    if 'cmd' not in request.args or not request.args['cmd'].strip():\n        return redirect('/')\n    command = request.args['cmd'].strip()\n    command = command[:1000] # trim commands longer than 1000 characters\n    if '\\n' in command:\n        return render_template('errors/error.html', title='parsing error!',\n                               message='no newlines please')\n\n    s = store.store('explainshell', config.MONGO_URI)\n    try:\n        matches, helptext = explaincommand(command, s)\n        return render_template('explain.html',\n                               matches=matches,\n                               helptext=helptext,\n                               getargs=command)\n\n    except errors.ProgramDoesNotExist, e:\n        return render_template('errors/missingmanpage.html', title='missing man page', e=e)\n    except bashlex.errors.ParsingError, e:\n        logger.warn('%r parsing error: %s', command, e.message)\n        return render_template('errors/parsingerror.html', title='parsing error!', e=e)\n    except NotImplementedError, e:\n        logger.warn('not implemented error trying to explain %r', command)\n        msg = (\"the parser doesn't support %r constructs in the command you tried. you may \"\n               \"<a href='https://github.com/idank/explainshell/issues'>report a \"\n               \"bug</a> to have this added, if one doesn't already exist.\") % e.args[0]\n\n        return render_template('errors/error.html', title='error!', message=msg)\n    except:\n        logger.error('uncaught exception trying to explain %r', command, exc_info=True)\n        msg = 'something went wrong... this was logged and will be checked'\n        return render_template('errors/error.html', title='error!', message=msg)\n\n@app.route('/explain/<program>', defaults={'section' : None})\n@app.route('/explain/<section>/<program>')\ndef explainold(section, program):\n    logger.info('/explain section=%r program=%r', section, program)\n\n    s = store.store('explainshell', config.MONGO_URI)\n    if section is not None:\n        program = '%s.%s' % (program, section)\n\n    # keep links to old urls alive\n    if 'args' in request.args:\n        args = request.args['args']\n        command = '%s %s' % (program, args)\n        return redirect('/explain?cmd=%s' % urllib.quote_plus(command), 301)\n    else:\n        try:\n            mp, suggestions = explainprogram(program, s)\n            return render_template('options.html', mp=mp, suggestions=suggestions)\n        except errors.ProgramDoesNotExist, e:\n            return render_template('errors/missingmanpage.html', title='missing man page', e=e)\n\ndef explainprogram(program, store):\n    mps = store.findmanpage(program)\n    mp = mps.pop(0)\n    program = mp.namesection\n\n    synopsis = mp.synopsis\n    if synopsis:\n        synopsis = synopsis.decode('utf-8')\n\n    mp = {'source' : mp.source[:-3],\n          'section' : mp.section,\n          'program' : program,\n          'synopsis' : synopsis,\n          'options' : [o.text.decode('utf-8') for o in mp.options]}\n\n    suggestions = []\n    for othermp in mps:\n        d = {'text' : othermp.namesection,\n             'link' : '%s/%s' % (othermp.section, othermp.name)}\n        suggestions.append(d)\n    logger.info('suggestions: %s', suggestions)\n    return mp, suggestions\n\ndef _makematch(start, end, match, commandclass, helpclass):\n    return {'match' : match, 'start' : start, 'end' : end, 'spaces' : '',\n            'commandclass' : commandclass, 'helpclass' : helpclass}\n\ndef explaincommand(command, store):\n    matcher_ = matcher.matcher(command, store)\n    groups = matcher_.match()\n    expansions = matcher_.expansions\n\n    shellgroup = groups[0]\n    commandgroups = groups[1:]\n    matches = []\n\n    # save a mapping between the help text to its assigned id,\n    # we're going to reuse ids that have the same text\n    texttoid = {}\n\n    # remember where each assigned id has started in the source,\n    # we're going to use it later on to sort the help text by start\n    # position\n    idstartpos = {}\n\n    l = []\n    for m in shellgroup.results:\n        commandclass = shellgroup.name\n        helpclass = 'help-%d' % len(texttoid)\n        text = m.text\n        if text:\n            text = text.decode('utf-8')\n            helpclass = texttoid.setdefault(text, helpclass)\n        else:\n            # unknowns in the shell group are possible when our parser left\n            # an unparsed remainder, see matcher._markunparsedunknown\n            commandclass += ' unknown'\n            helpclass = ''\n        if helpclass:\n            idstartpos.setdefault(helpclass, m.start)\n\n        d = _makematch(m.start, m.end, m.match, commandclass, helpclass)\n        formatmatch(d, m, expansions)\n\n        l.append(d)\n    matches.append(l)\n\n    for commandgroup in commandgroups:\n        l = []\n        for m in commandgroup.results:\n            commandclass = commandgroup.name\n            helpclass = 'help-%d' % len(texttoid)\n            text = m.text\n            if text:\n                text = text.decode('utf-8')\n                helpclass = texttoid.setdefault(text, helpclass)\n            else:\n                commandclass += ' unknown'\n                helpclass = ''\n            if helpclass:\n                idstartpos.setdefault(helpclass, m.start)\n\n            d = _makematch(m.start, m.end, m.match, commandclass, helpclass)\n            formatmatch(d, m, expansions)\n\n            l.append(d)\n\n        d = l[0]\n        d['commandclass'] += ' simplecommandstart'\n        if commandgroup.manpage:\n            d['name'] = commandgroup.manpage.name\n            d['section'] = commandgroup.manpage.section\n            if '.' not in d['match']:\n                d['match'] = '%s(%s)' % (d['match'], d['section'])\n            d['suggestions'] = commandgroup.suggestions\n            d['source'] = commandgroup.manpage.source[:-5]\n        matches.append(l)\n\n    matches = list(itertools.chain.from_iterable(matches))\n    helpers.suggestions(matches, command)\n\n    # _checkoverlaps(matcher_.s, matches)\n    matches.sort(key=lambda d: d['start'])\n\n    it = util.peekable(iter(matches))\n    while it.hasnext():\n        m = it.next()\n        spaces = 0\n        if it.hasnext():\n            spaces = it.peek()['start'] - m['end']\n        m['spaces'] = ' ' * spaces\n\n    helptext = sorted(texttoid.iteritems(), key=lambda (k, v): idstartpos[v])\n\n    return matches, helptext\n\ndef formatmatch(d, m, expansions):\n    '''populate the match field in d by escaping m.match and generating\n    links to any command/process substitutions'''\n\n    # save us some work later: do any expansions overlap\n    # the current match?\n    hassubsinmatch = False\n\n    for start, end, kind in expansions:\n        if m.start <= start and end <= m.end:\n            hassubsinmatch = True\n            break\n\n    # if not, just escape the current match\n    if not hassubsinmatch:\n        d['match'] = markupsafe.escape(m.match)\n        return\n\n    # used in es.js\n    d['commandclass'] += ' hasexpansion'\n\n    # go over the expansions, wrapping them with a link; leave everything else\n    # untouched\n    expandedmatch = ''\n    i = 0\n    for start, end, kind in expansions:\n        if start >= m.end:\n            break\n        relativestart = start - m.start\n        relativeend = end - m.start\n\n        if i < relativestart:\n            for j in range(i, relativestart):\n                if m.match[j].isspace():\n                    expandedmatch += markupsafe.Markup('&nbsp;')\n                else:\n                    expandedmatch += markupsafe.escape(m.match[j])\n            i = relativestart + 1\n        if m.start <= start and end <= m.end:\n            s = m.match[relativestart:relativeend]\n\n            if kind == 'substitution':\n                content = markupsafe.Markup(_substitutionmarkup(s))\n            else:\n                content = s\n\n            expandedmatch += markupsafe.Markup(\n                    '<span class=\"expansion-{0}\">{1}</span>').format(kind, content)\n            i = relativeend\n\n    if i < len(m.match):\n        expandedmatch += markupsafe.escape(m.match[i:])\n\n    assert expandedmatch\n    d['match'] = expandedmatch\n\ndef _substitutionmarkup(cmd):\n    '''\n    >>> _substitutionmarkup('foo')\n    '<a href=\"/explain?cmd=foo\" title=\"Zoom in to nested command\">foo</a>'\n    >>> _substitutionmarkup('cat <&3')\n    '<a href=\"/explain?cmd=cat+%3C%263\" title=\"Zoom in to nested command\">cat <&3</a>'\n    '''\n    encoded = urllib.urlencode({'cmd': cmd})\n    return ('<a href=\"/explain?{query}\" title=\"Zoom in to nested command\">{cmd}'\n            '</a>').format(cmd=cmd, query=encoded)\n\ndef _checkoverlaps(s, matches):\n    explained = [None]*len(s)\n    for d in matches:\n        for i in range(d['start'], d['end']):\n            if explained[i]:\n                raise RuntimeError(\"explained overlap for group %s at %d with %s\" % (d, i, explained[i]))\n            explained[i] = d\n"
  },
  {
    "path": "misc/crontab",
    "content": "0 0 1,15 * * certbot renew\n"
  },
  {
    "path": "misc/logrotate/explainshell",
    "content": "/home/idan/logs/uwsgi.log {\n  copytruncate\n  daily\n  rotate 30\n  size 10M\n  compress\n  delaycompress\n  missingok\n  notifempty\n}\n\n/home/idan/logs/nginx_*.log {\n  daily\n  compress\n  delaycompress\n  rotate 30\n  size 10M\n  missingok\n  nocreate\n  sharedscripts\n  postrotate\n    test ! -f /var/run/nginx.pid || kill -USR1 `cat /var/run/nginx.pid`\n  endscript\n}\n"
  },
  {
    "path": "misc/nginx/explainshell.conf",
    "content": "log_format timed_combined '$remote_addr - $remote_user [$time_local]  '\n    '\"$request\" $status $body_bytes_sent '\n    '\"$http_referer\" \"$http_user_agent\" '\n    '$request_time';\n\nserver {\n    listen      443 ssl;\n    ssl_certificate /etc/letsencrypt/live/explainshell.com/fullchain.pem;\n    ssl_certificate_key /etc/letsencrypt/live/explainshell.com/privkey.pem;\n\n    server_name explainshell.com;\n\n    access_log  /home/idan/logs/nginx-access.log timed_combined;\n    error_log   /home/idan/logs/nginx-error.log;\n\n    gzip        on;\n    gzip_min_length 1000;\n\n    location / {\n        include uwsgi_params;\n        uwsgi_pass unix:/tmp/explainshell.sock;\n    }\n\n    location /static {\n        alias /home/idan/code/explainshell/web/static;\n        expires 1y;\n        add_header Cache-Control \"public\";\n        etag on;\n    }\n\n    location = /favicon.ico {\n        alias /home/idan/code/explainshell/web/favicon.ico;\n    }\n}\n\nserver {\n    listen 80;\n    server_name explainshell.com;\n    return 301 https://$host$request_uri;\n}\n"
  },
  {
    "path": "misc/setup.bash",
    "content": "set -e\n\n# TODO(idank): test this on a clean machine\n\nsudo apt-get install nginx git python-pip mongodb supervisor virtualenv\nsudo pip install uwsgi\n\nsudo add-apt-repository ppa:certbot/certbot\nsudo apt-get update\nsudo apt-get install certbot\n\ncd ~\ngit clone https://github.com/idank/explainshell.git code\nmkdir logs\n\nvirtualenv venv\nsource venv/bin/activate\npip install -r code/requirements.txt\n"
  },
  {
    "path": "misc/supervisord/uwsgi.conf",
    "content": "[program:explainshell]\ncommand=/usr/local/bin/uwsgi\n  --socket /tmp/explainshell.sock\n  --logto /home/idan/logs/uwsgi.log\n  --home /home/idan/venv\n  --pythonpath /home/idan/code\n  --wsgi-file /home/idan/code/runserver.py\n  --callable app\n  --max-requests 1000\n  --master\n  --processes 1\n  --chmod\ndirectory=/home/idan/code\nautostart=true\nautorestart=true\nuser=idan\n"
  },
  {
    "path": "requirements.txt",
    "content": "Flask==0.12\nnltk==3.4.5\nMarkupSafe==1.1.1\nnose==1.3.0\npymongo==3.13.0\nbashlex==0.12\n"
  },
  {
    "path": "runserver.py",
    "content": "from explainshell import config\nfrom explainshell.web import app\n\nimport logging.config\nlogging.config.dictConfig(config.LOGGING_DICT)\n\nif __name__ == '__main__':\n    if config.HOST_IP:\n        app.run(debug=config.DEBUG, host=config.HOST_IP)\n    else:\n        app.run(debug=config.DEBUG)\n"
  },
  {
    "path": "tests/__init__.py",
    "content": ""
  },
  {
    "path": "tests/helpers.py",
    "content": "from explainshell import matcher, store, errors, options, helpconstants\n\nclass mockstore(object):\n    def __init__(self):\n        sp = store.paragraph\n        so = store.option\n        sm = store.manpage\n\n        p0 = sp(0, '-a desc', '', True)\n        p1 = sp(1, '-b <arg> desc', '', True)\n        p2 = sp(2, '-? help text', '', True)\n        p3 = sp(3, '-c=one,two\\ndesc', '', True)\n        p4 = sp(4, 'FILE argument', '', True)\n        p5 = sp(5, '-exec nest', '', True)\n        opts = [so(p0, ['-a'], ['--a'], False),\n                so(p1, ['-b'], ['--b'], '<arg>'),\n                so(p2, ['-?'], [], False),\n                so(p3, ['-c'], [], ['one', 'two'])]\n        self.manpages = {\n                'bar' : sm('bar.1.gz', 'bar', 'bar synopsis', opts, [], multicommand=True),\n                'baz' : sm('baz.1.gz', 'baz', 'baz synopsis', opts, [], partialmatch=True),\n                'bar foo' : sm('bar-foo.1.gz', 'bar-foo', 'bar foo synopsis', opts, [], partialmatch=True),\n                'nosynopsis' : sm('bar.1.gz', 'bar', None, opts, [])}\n\n        self.dup = [sm('dup.1.gz', 'dup', 'dup1 synopsis', opts, []),\n                    sm('dup.2.gz', 'dup', 'dup2 synopsis', opts, [])]\n\n        opts = list(opts)\n        opts.append(so(p4, [], [], False, 'FILE'))\n        opts.append(so(p5, ['-exec'], [], True, nestedcommand=['EOF', ';']))\n        self.manpages['withargs'] = sm('withargs.1.gz', 'withargs', 'withargs synopsis',\n                                       opts, [], partialmatch=True, nestedcommand=True)\n\n    def findmanpage(self, x, section=None):\n        try:\n            if x == 'dup':\n                return self.dup\n            return [self.manpages[x]]\n        except KeyError:\n            raise errors.ProgramDoesNotExist(x)\n\ns = mockstore()\n\n"
  },
  {
    "path": "tests/test-fixer.py",
    "content": "import unittest\nimport copy\n\nfrom explainshell import fixer, options, store\n\nclass test_fixer(unittest.TestCase):\n    def setUp(self):\n        self._oldfixerscls = fixer.fixerscls[:]\n\n    def tearDown(self):\n        fixer.fixerscls = self._oldfixerscls\n\n    def test_changes(self):\n        class myfixer(fixer.basefixer):\n            def pre_get_raw_manpage(self):\n                self.mctx['foo'] = 'bar'\n\n        d = {}\n        fixer.fixerscls = [myfixer]\n        r = fixer.runner(d)\n        self.assertTrue('foo' not in d)\n        r.pre_get_raw_manpage()\n        self.assertEquals(d['foo'], 'bar')\n\n    def test_paragraphjoiner(self):\n        maxdistance = fixer.paragraphjoiner.maxdistance\n\n        paragraphs = [store.paragraph(i, chr(ord('a') + i), None, False) for i in range(26)]\n        options = [\n                store.option(paragraphs[0], [], [], False),\n                store.option(paragraphs[1], [], [], False),\n                store.option(paragraphs[5], [], [], False),\n                store.option(paragraphs[5+maxdistance-1], [], [], False),\n                store.option(paragraphs[15], [], [], False),\n                store.option(paragraphs[17], [], [], False),\n                store.option(paragraphs[-1], [], [], False)]\n\n        f = fixer.paragraphjoiner(None)\n        merged = f._join(paragraphs, options)\n\n        #self.assertEquals(merged, 7)\n        #self.assertEquals(len(paragraphs), 19)\n        self.assertEquals(options[0].text, 'a')\n        self.assertEquals(options[1].text.replace('\\n', ''), 'bcde')\n        self.assertEquals(options[2].text.replace('\\n', ''), 'fghi')\n        self.assertEquals(options[3].text, 'j')\n        self.assertEquals(options[4].text.replace('\\n', ''), 'pq')\n        self.assertEquals(options[5].text, 'r')\n        self.assertEquals(options[6].text, 'z')\n\n        # join again to make sure nothing is changed\n        oldparagraphs = copy.deepcopy(paragraphs)\n        oldoptions = copy.deepcopy(options)\n        f._join(paragraphs, options)\n        self.assertEquals(oldparagraphs, paragraphs)\n        self.assertEquals(oldoptions, options)\n"
  },
  {
    "path": "tests/test-integration.py",
    "content": "import unittest, subprocess, pymongo, os\n\nfrom explainshell import manager, config, matcher\n\n@unittest.skip(\"nltk usage is broken due to new version\")\nclass test_integration(unittest.TestCase):\n    def test(self):\n        mngr = manager.manager(config.MONGO_URI, 'explainshell_tests', [os.path.join(os.path.dirname(__file__), 'echo.1.gz')], drop=True)\n        mngr.run()\n\n        cmd = 'echo -en foobar --version'\n\n        m = matcher.matcher(cmd, mngr.store)\n        group = m.match()[1]\n        matchprog, matches = group.manpage.name, group.results\n\n        self.assertEquals(matchprog, 'echo')\n\n        #self.assertEquals(matches[0].text, 'display a line of text')\n        self.assertEquals(matches[0].match, 'echo')\n\n        self.assertEquals(matches[1].text, '<b>-e</b>     enable interpretation of backslash escapes')\n        self.assertEquals(matches[1].match, '-e')\n\n        self.assertEquals(matches[2].text, '<b>-n</b>     do not output the trailing newline')\n        self.assertEquals(matches[2].match, 'n')\n\n        self.assertEquals(matches[3].text, None)\n        self.assertEquals(matches[3].match, 'foobar')\n\n        self.assertEquals(matches[4].text, '<b>--version</b>\\n       output version information and exit')\n        self.assertEquals(matches[4].match, '--version')\n"
  },
  {
    "path": "tests/test-manager.py",
    "content": "import unittest, os\n\nfrom explainshell import manager, config, store, errors\n\n@unittest.skip(\"nltk usage is broken due to new version\")\nclass test_manager(unittest.TestCase):\n    def setUp(self):\n        store.store('explainshell_tests').drop(True)\n\n    def _getmanager(self, names, **kwargs):\n        l = []\n        for n in names:\n            l.append(os.path.join(config.MANPAGEDIR, '1', n))\n\n        m = manager.manager(config.MONGO_URI, 'explainshell_tests', l, **kwargs)\n        return m\n\n    def test(self):\n        m = self._getmanager(['tar.1.gz'])\n        m.run()\n\n        self.assertRaises(errors.ProgramDoesNotExist, m.store.findmanpage, 'tar.2')\n        mp = m.store.findmanpage('tar')[0]\n        self.assertEquals(mp.source, 'tar.1.gz')\n        self.assertEquals(mp.name, 'tar')\n        self.assertEquals(mp.aliases, [('tar', 10)])\n        self.assertEquals(len(mp.paragraphs), 154)\n        self.assertEquals(len(mp.options), 134)\n        self.assertTrue(mp.find_option('-v'))\n        self.assertEquals(mp.synopsis, 'The GNU version of the tar archiving utility')\n\n        self.assertTrue(mp.partialmatch) # fixer is working\n\n        self.assertEquals(m.run()[0], [])\n\n    def test_verify(self):\n        m = self._getmanager(['tar.1.gz'])\n        s = m.store\n\n        # invalid mapping\n        s.addmapping('foo', 'bar', 1)\n        ok, unreachable, notfound = s.verify()\n        self.assertFalse(ok)\n        self.assertEquals(list(notfound), ['bar'])\n\n        s.mapping.drop()\n        m.run()\n        ok, unreachable, notfound = s.verify()\n        self.assertTrue(ok)\n\n        s.mapping.drop()\n        ok, unreachable, notfound = s.verify()\n        self.assertEquals(list(unreachable), ['tar'])\n\n        s.addmapping('foo', 'bar', 1)\n        ok, unreachable, notfound = s.verify()\n        self.assertEquals(list(notfound), ['bar'])\n        self.assertEquals(list(unreachable), ['tar'])\n\n    @unittest.skip(\"https://github.com/idank/explainshell/pull/303#issuecomment-1272387073\")\n    def test_aliases(self):\n        m = self._getmanager(['lsbcpp.1.gz', 'tar.1.gz', 'bsdtar.1.gz', 'basket.1.gz'])\n        m.run()\n\n        mp = m.store.findmanpage('lsbcpp')\n        self.assertTrue('lsbcc' in m.store)\n        self.assertTrue('lsbc++' in m.store)\n        self.assertTrue('lsbcpp' in m.store)\n        self.assertEquals(len(mp), 1)\n\n        mp = m.store.findmanpage('tar')\n        self.assertEquals(len(mp), 2)\n        self.assertEquals(mp[0].source, 'tar.1.gz')\n        self.assertEquals(mp[1].source, 'bsdtar.1.gz')\n\n    def test_overwrite(self):\n        m = self._getmanager(['tar.1.gz'], overwrite=False)\n        self.assertEquals(len(list(m.store)), 0)\n\n        a, e = m.run()\n        self.assertTrue(a)\n        self.assertFalse(e)\n        self.assertEquals(m.store.mapping.count(), 1)\n        self.assertEquals(len(list(m.store)), 1)\n\n        a, e = m.run()\n        self.assertFalse(a)\n        self.assertTrue(e)\n        self.assertEquals(m.store.mapping.count(), 1)\n        self.assertEquals(len(list(m.store)), 1)\n\n        m = manager.manager(config.MONGO_URI, 'explainshell_tests', [os.path.join(config.MANPAGEDIR, '1', 'tar.1.gz')], overwrite=True)\n        a, e = m.run()\n        self.assertTrue(a)\n        self.assertFalse(e)\n        self.assertEquals(m.store.mapping.count(), 1)\n        self.assertEquals(len(list(m.store)), 1)\n\n        m.store.verify()\n\n    def test_multicommand(self):\n        m = self._getmanager(['git.1.gz', 'git-rebase.1.gz'])\n        m.run()\n\n        self.assertTrue(m.store.findmanpage('git')[0].multicommand)\n        self.assertTrue('git rebase' in m.store)\n\n    def test_edit(self):\n        m = self._getmanager(['tar.1.gz'], overwrite=False)\n        self.assertEquals(len(list(m.store)), 0)\n\n        a, e = m.run()\n        mp = a[0]\n        mp.synopsis = 'foo'\n        m.edit(mp)\n\n        mp = m.store.findmanpage('tar')[0]\n        self.assertEquals(mp.synopsis, 'foo')\n        self.assertTrue(m.store.verify())\n\n        mp.aliases.append(('foo', 1))\n        m.edit(mp)\n        self.assertTrue('foo' in m.store)\n        self.assertEquals(m.store.findmanpage('tar')[0].paragraphs,\n                          m.store.findmanpage('foo')[0].paragraphs)\n        self.assertTrue(m.store.verify()[0])\n\n    def test_samename(self):\n        pages = [os.path.join(config.MANPAGEDIR, '1', 'node.1.gz'), os.path.join(config.MANPAGEDIR, '8', 'node.8.gz')]\n        m = manager.manager(config.MONGO_URI, 'explainshell_tests', pages)\n        a, e = m.run()\n        self.assertEquals(len(a), 2)\n        self.assertEquals(len(m.store.findmanpage('node')), 2)\n        mps = m.store.findmanpage('node.8')\n        self.assertEquals(len(mps), 2)\n        self.assertEquals(mps[0].section, '8')\n\n    def test_samename_samesection(self):\n        m = self._getmanager(['xargs.1.gz', 'xargs.1posix.gz'])\n        a, e = m.run()\n        self.assertEquals(len(a), 2)\n        self.assertEquals(len(m.store.findmanpage('xargs')), 2)\n        mps = m.store.findmanpage('xargs.1posix')\n        self.assertEquals(len(mps), 2)\n        self.assertEquals(mps[0].section, '1posix')\n"
  },
  {
    "path": "tests/test-manpage.py",
    "content": "import unittest, os, subprocess\n\nfrom explainshell import manpage, store\n\nclass test_manpage(unittest.TestCase):\n    def test_first_paragraph_no_section(self):\n        m = 'foo\\nbar'\n        l = list(manpage._parsetext(m.splitlines()))\n        self.assertEquals(l, [store.paragraph(0, 'foo\\nbar', None, False)])\n\n    def test_sections(self):\n        m = '''<b>SECTION</b>\na\nb\n\nc\n\n<b>SECTION2</b>\na\n\n<b>WITH SPACES</b>\na\n\n<b>EMPTY SECTION SHOULD BE IGNORED</b>\n\n<b>SECTION3</b>\n\ntNOTASECTION'''\n\n        parsed = list(manpage._parsetext(m.splitlines()))\n        self.assertTrue(len(parsed) == 5)\n        self.assertEquals(parsed, [store.paragraph(0, 'a\\nb', 'SECTION', False),\n                                   store.paragraph(1, 'c', 'SECTION', False),\n                                   store.paragraph(2, 'a', 'SECTION2', False),\n                                   store.paragraph(3, 'a', 'WITH SPACES', False),\n                                   store.paragraph(4, 'tNOTASECTION', 'SECTION3', False)])\n    def test_no_synopsis(self):\n        m = manpage.manpage('foo')\n        m._text = 'a b c d e f g h i j k l'.replace(' ', '\\n')\n        m.parse()\n        self.assertEquals(m.aliases, [('foo', 10)])\n"
  },
  {
    "path": "tests/test-matcher.py",
    "content": "import unittest\n\nimport bashlex.errors, bashlex.ast\n\nfrom explainshell import matcher, errors, helpconstants\nfrom tests import helpers\n\ns = helpers.mockstore()\n\nclass test_matcher(unittest.TestCase):\n    def assertMatchSingle(self, what, expectedmanpage, expectedresults):\n        m = matcher.matcher(what, s)\n        groups = m.match()\n        self.assertEquals(len(groups), 2)\n        self.assertEquals(groups[1].manpage, expectedmanpage)\n        self.assertEquals(groups[1].results, expectedresults)\n\n    def test_unknown_prog(self):\n        self.assertRaises(errors.ProgramDoesNotExist, matcher.matcher('foo', s).match)\n\n    def test_unicode(self):\n        matchedresult = [\n            (0, 3, 'bar synopsis', 'bar'),\n            (4, 13, '-b <arg> desc', '-b uni???')]\n\n        self.assertMatchSingle(u'bar -b uni\\u05e7\\u05d5\\u05d3', s.findmanpage('bar')[0], matchedresult)\n\n    def test_no_options(self):\n        matchedresult = [(0, 3, 'bar synopsis', 'bar')]\n        self.assertMatchSingle('bar', s.findmanpage('bar')[0], matchedresult)\n\n    def test_known_arg(self):\n        matchedresult = [\n            (0, 3, 'bar synopsis', 'bar'),\n            (4, 10, '-a desc', '-a --a'),\n            (11, 13, '-? help text', '-?')]\n\n        self.assertMatchSingle('bar -a --a -?', s.findmanpage('bar')[0], matchedresult)\n\n    def test_arg_in_fuzzy_with_expected_value(self):\n        cmd = 'baz -ab arg'\n        matchedresult = [\n            (0, 3, 'baz synopsis', 'baz'),\n            (4, 6, '-a desc', '-a'),\n            (6, 11, '-b <arg> desc', 'b arg')]\n\n        self.assertMatchSingle(cmd, s.findmanpage('baz')[0], matchedresult)\n\n        cmd = 'baz -ab12'\n        matchedresult = [\n            (0, 3, 'baz synopsis', 'baz'),\n            (4, 6, '-a desc', '-a'),\n            (6, 9, '-b <arg> desc', 'b12')]\n\n        self.assertMatchSingle(cmd, s.findmanpage('baz')[0], matchedresult)\n\n    def test_partialmatch_with_arguments(self):\n        cmd = 'withargs arg'\n        matchedresult = [\n            (0, 8, 'withargs synopsis', 'withargs'),\n            (9, 12, 'FILE argument', 'arg')]\n\n        self.assertMatchSingle(cmd, s.findmanpage('withargs')[0], matchedresult)\n\n    def test_reset_current_option_if_argument_taken(self):\n        cmd = 'withargs -ab12 arg'\n        matchedresult = [\n            (0, 8, 'withargs synopsis', 'withargs'),\n            (9, 11, '-a desc', '-a'),\n            (11, 14, '-b <arg> desc', 'b12'),\n            (15, 18, 'FILE argument', 'arg')]\n\n        self.assertMatchSingle(cmd, s.findmanpage('withargs')[0], matchedresult)\n\n        cmd = 'withargs -b12 arg'\n        matchedresult = [\n            (0, 8, 'withargs synopsis', 'withargs'),\n            (9, 13, '-b <arg> desc', '-b12'),\n            (14, 17, 'FILE argument', 'arg')]\n\n        self.assertMatchSingle(cmd, s.findmanpage('withargs')[0], matchedresult)\n\n        # here we reset it implicitly by looking up '12'\n        cmd = 'withargs -b 12 arg'\n        matchedresult = [\n            (0, 8, 'withargs synopsis', 'withargs'),\n            (9, 14, '-b <arg> desc', '-b 12'),\n            (15, 18, 'FILE argument', 'arg')]\n\n        self.assertMatchSingle(cmd, s.findmanpage('withargs')[0], matchedresult)\n\n    def test_arg_with_expected_value(self):\n        cmd = 'bar -b arg --b arg'\n        matchedresult = [\n            (0, 3, 'bar synopsis', 'bar'),\n            (4, 18, '-b <arg> desc', '-b arg --b arg')]\n\n        self.assertMatchSingle(cmd, s.findmanpage('bar')[0], matchedresult)\n\n    def test_arg_with_expected_value_from_list(self):\n        cmd = 'bar -c one'\n        matchedresult = [\n            (0, 3, 'bar synopsis', 'bar'),\n            (4, 10, '-c=one,two\\ndesc', '-c one')]\n\n        self.assertMatchSingle(cmd, s.findmanpage('bar')[0], matchedresult)\n\n        cmd = 'bar -c notinlist'\n        matchedresult = [\n            (0, 3, 'bar synopsis', 'bar'),\n            (4, 6, '-c=one,two\\ndesc', '-c'),\n            (7, 16, None, 'notinlist')]\n\n        self.assertMatchSingle(cmd, s.findmanpage('bar')[0], matchedresult)\n\n    def test_arg_with_expected_value_clash(self):\n        '''the first option expects an arg but the arg is actually an option'''\n        cmd = 'bar -b -a'\n        matchedresult = [\n            (0, 3, 'bar synopsis', 'bar'),\n            (4, 6, '-b <arg> desc', '-b'),\n            (7, 9, '-a desc', '-a')]\n\n        self.assertMatchSingle(cmd, s.findmanpage('bar')[0], matchedresult)\n\n    def test_arg_with_expected_value_no_clash(self):\n        '''the first option expects an arg but the arg is not an option even though\n        it looks like one'''\n        cmd = 'bar -b -xa'\n        matchedresult = [\n            (0, 3, 'bar synopsis', 'bar'),\n            (4, 6, '-b <arg> desc', '-b'),\n            (7, 9, None, '-x'),\n            (9, 10, '-a desc', 'a')]\n\n        self.assertMatchSingle(cmd, s.findmanpage('bar')[0], matchedresult)\n\n    def test_unknown_arg(self):\n        matchedresult = [(0, 3, 'bar synopsis', 'bar'), (4, 6, None, '-x')]\n        self.assertMatchSingle('bar -x', s.findmanpage('bar')[0], matchedresult)\n\n        # merges\n        matchedresult = [(0, 3, 'bar synopsis', 'bar'), (4, 10, None, '-x --x')]\n        self.assertMatchSingle('bar -x --x', s.findmanpage('bar')[0], matchedresult)\n\n        matchedresult = [(0, 3, 'bar synopsis', 'bar'), (4, 8, None, '-xyz')]\n        self.assertMatchSingle('bar -xyz', s.findmanpage('bar')[0], matchedresult)\n\n        matchedresult = [(0, 3, 'bar synopsis', 'bar'),\n                                 (4, 6, None, '-x'),\n                                 (6, 7, '-a desc', 'a'), (7, 8, None, 'z')]\n\n        self.assertMatchSingle('bar -xaz', s.findmanpage('bar')[0], matchedresult)\n\n    def test_merge_same_match(self):\n        matchedresult = [(0, 3, 'bar synopsis', 'bar'), (4, 8, '-a desc', '-aaa')]\n        self.assertMatchSingle('bar -aaa', s.findmanpage('bar')[0], matchedresult)\n\n    def test_known_and_unknown_arg(self):\n        matchedresult = [(0, 3, 'bar synopsis', 'bar'), (4, 6, '-a desc', '-a'), (7, 9, None, '-x')]\n        self.assertMatchSingle('bar -a -x', s.findmanpage('bar')[0], matchedresult)\n\n        matchedresult = [(0, 3, 'bar synopsis', 'bar'), (4, 6, '-a desc', '-a'), (6, 7, None, 'x')]\n        self.assertMatchSingle('bar -ax', s.findmanpage('bar')[0], matchedresult)\n\n    def test_long(self):\n        cmd = 'bar --b=b foo'\n        matchedresult = [\n            (0, 3, 'bar synopsis', 'bar'),\n            (4, 9, '-b <arg> desc', '--b=b'),\n            (10, 13, None, 'foo')]\n\n        self.assertMatchSingle(cmd, s.findmanpage('bar')[0], matchedresult)\n\n    def test_arg_no_dash(self):\n        cmd = 'baz ab -x'\n        matchedresult = [\n            (0, 3, 'baz synopsis', 'baz'),\n            (4, 5, '-a desc', 'a'),\n            (5, 6, '-b <arg> desc', 'b'),\n            (7, 9, None, '-x')]\n\n        self.assertMatchSingle(cmd, s.findmanpage('baz')[0], matchedresult)\n\n    def test_multicommand(self):\n        cmd = 'bar baz --b foo'\n        matchedresult = [\n            (0, 3, 'bar synopsis', 'bar'),\n            (4, 7, None, 'baz'),\n            (8, 15, '-b <arg> desc', '--b foo')]\n\n        self.assertMatchSingle(cmd, s.findmanpage('bar')[0], matchedresult)\n\n        cmd = 'bar foo --b foo'\n        matchedresult = [\n            (0, 7, 'bar foo synopsis', 'bar foo'),\n            (8, 15, '-b <arg> desc', '--b foo')]\n\n        self.assertMatchSingle(cmd, s.findmanpage('bar foo')[0], matchedresult)\n\n    def test_multiple_matches(self):\n        cmd = 'dup -ab'\n        matchedresult = [\n            (0, 3, 'dup1 synopsis', 'dup'),\n            (4, 6, '-a desc', '-a'),\n            (6, 7, '-b <arg> desc', 'b')]\n\n        groups = matcher.matcher(cmd, s).match()\n        self.assertEquals(groups[1].results, matchedresult)\n        self.assertEquals(groups[1].suggestions[0].source, 'dup.2.gz')\n\n    def test_arguments(self):\n        cmd = 'withargs -x -b freearg freearg'\n        matchedresult = [\n            (0, 8, 'withargs synopsis', 'withargs'),\n            # tokens that look like options are still unknown\n            (9, 11, None, '-x'),\n            (12, 22, '-b <arg> desc', '-b freearg'),\n            (23, 30, 'FILE argument', 'freearg')]\n\n        self.assertMatchSingle(cmd, s.findmanpage('withargs')[0], matchedresult)\n\n    def test_arg_is_dash(self):\n        cmd = 'bar -b - -a -'\n        matchedresult = [\n            (0, 3, 'bar synopsis', 'bar'),\n            (4, 8, '-b <arg> desc', '-b -'),\n            (9, 11, '-a desc', '-a'),\n            (12, 13, None, '-')]\n\n        self.assertMatchSingle(cmd, s.findmanpage('bar')[0], matchedresult)\n\n    def test_nested_command(self):\n        cmd = 'withargs -b arg bar -a unknown'\n\n        matchedresult = [[(0, 8, 'withargs synopsis', 'withargs'),\n                          (9, 15, '-b <arg> desc', '-b arg')],\n                         [(16, 19, 'bar synopsis', 'bar'),\n                          (20, 22, '-a desc', '-a'),\n                          (23, 30, None, 'unknown')]]\n\n        groups = matcher.matcher(cmd, s).match()\n        self.assertEquals(len(groups), 3)\n        self.assertEquals(groups[0].results, [])\n        self.assertEquals(groups[1].results, matchedresult[0])\n        self.assertEquals(groups[2].results, matchedresult[1])\n\n    def test_nested_option(self):\n        cmd = 'withargs -b arg -exec bar -a EOF -b arg'\n\n        matchedresult = [[(0, 8, 'withargs synopsis', 'withargs'),\n                          (9, 15, '-b <arg> desc', '-b arg'),\n                          (16, 21, '-exec nest', '-exec'),\n                          (29, 32, '-exec nest', 'EOF'),\n                          (33, 39, '-b <arg> desc', '-b arg')],\n                         [(22, 25, 'bar synopsis', 'bar'),\n                          (26, 28, '-a desc', '-a')]]\n\n        groups = matcher.matcher(cmd, s).match()\n        self.assertEquals(len(groups), 3)\n        self.assertEquals(groups[0].results, [])\n        self.assertEquals(groups[1].results, matchedresult[0])\n        self.assertEquals(groups[2].results, matchedresult[1])\n\n        cmd = \"withargs -b arg -exec bar -a ';' -a\"\n\n        matchedresult = [[(0, 8, 'withargs synopsis', 'withargs'),\n                          (9, 15, '-b <arg> desc', '-b arg'),\n                          (16, 21, '-exec nest', '-exec'),\n                          (29, 32, '-exec nest', \"';'\"),\n                          (33, 35, '-a desc', '-a')],\n                         [(22, 25, 'bar synopsis', 'bar'),\n                          (26, 28, '-a desc', '-a')]]\n\n        groups = matcher.matcher(cmd, s).match()\n        self.assertEquals(len(groups), 3)\n        self.assertEquals(groups[0].results, [])\n        self.assertEquals(groups[1].results, matchedresult[0])\n        self.assertEquals(groups[2].results, matchedresult[1])\n\n        cmd = \"withargs -b arg -exec bar -a \\\\; -a\"\n\n        matchedresult = [[(0, 8, 'withargs synopsis', 'withargs'),\n                          (9, 15, '-b <arg> desc', '-b arg'),\n                          (16, 21, '-exec nest', '-exec'),\n                          (29, 31, '-exec nest', \"\\\\;\"),\n                          (32, 34, '-a desc', '-a')],\n                         [(22, 25, 'bar synopsis', 'bar'),\n                          (26, 28, '-a desc', '-a')]]\n\n        groups = matcher.matcher(cmd, s).match()\n        self.assertEquals(len(groups), 3)\n        self.assertEquals(groups[0].results, [])\n        self.assertEquals(groups[1].results, matchedresult[0])\n        self.assertEquals(groups[2].results, matchedresult[1])\n\n        cmd = 'withargs -exec bar -a -u'\n\n        matchedresult = [[(0, 8, 'withargs synopsis', 'withargs'),\n                          (9, 14, '-exec nest', '-exec')],\n                         [(15, 18, 'bar synopsis', 'bar'),\n                          (19, 21, '-a desc', '-a'),\n                          (22, 24, None, '-u')]]\n\n        groups = matcher.matcher(cmd, s).match()\n        self.assertEquals(len(groups), 3)\n        self.assertEquals(groups[0].results, [])\n        self.assertEquals(groups[1].results, matchedresult[0])\n        self.assertEquals(groups[2].results, matchedresult[1])\n\n    def test_multiple_nests(self):\n        cmd = 'withargs withargs -b arg bar'\n\n        matchedresult = [[(0, 8, 'withargs synopsis', 'withargs')],\n                         [(9, 17, 'withargs synopsis', 'withargs'),\n                          (18, 24, '-b <arg> desc', '-b arg')],\n                         [(25, 28, 'bar synopsis', 'bar')]]\n\n        groups = matcher.matcher(cmd, s).match()\n        self.assertEquals(len(groups), 4)\n        self.assertEquals(groups[0].results, [])\n        self.assertEquals(groups[1].results, matchedresult[0])\n        self.assertEquals(groups[2].results, matchedresult[1])\n        self.assertEquals(groups[3].results, matchedresult[2])\n\n    def test_nested_command_is_unknown(self):\n        cmd = 'withargs -b arg unknown'\n\n        matchedresult = [(0, 8, 'withargs synopsis', 'withargs'),\n                          (9, 15, '-b <arg> desc', '-b arg'),\n                          (16, 23, 'FILE argument', 'unknown')]\n\n        groups = matcher.matcher(cmd, s).match()\n        self.assertEquals(len(groups), 2)\n        self.assertEquals(groups[0].results, [])\n        self.assertEquals(groups[1].results, matchedresult)\n\n    def test_unparsed(self):\n        cmd = '(bar; bar) c'\n        self.assertRaises(bashlex.errors.ParsingError,\n                          matcher.matcher(cmd, s).match)\n\n\n    def test_known_and_unknown_program(self):\n        cmd = 'bar; foo arg >f; baz'\n        matchedresult = [[(3, 4, helpconstants.OPERATORS[';'], ';'),\n                          (13, 15, helpconstants.REDIRECTION + '\\n\\n' +\n                                   helpconstants.REDIRECTION_KIND['>'], '>f'),\n                          (15, 16, helpconstants.OPERATORS[';'], ';')],\n                         [(0, 3, 'bar synopsis', 'bar')],\n                         [(5, 12, None, 'foo arg')],\n                         [(17, 20, 'baz synopsis', 'baz')]]\n\n        groups = matcher.matcher(cmd, s).match()\n        self.assertEquals(groups[0].results, matchedresult[0])\n        self.assertEquals(groups[1].results, matchedresult[1])\n        self.assertEquals(groups[2].results, matchedresult[2])\n\n    def test_pipe(self):\n        cmd = 'bar | baz'\n        matchedresult = [[(4, 5, helpconstants.PIPELINES, '|')],\n                         [(0, 3, 'bar synopsis', 'bar')],\n                         [(6, 9, 'baz synopsis', 'baz')]]\n\n        groups = matcher.matcher(cmd, s).match()\n        self.assertEquals(groups[0].results, matchedresult[0])\n        self.assertEquals(groups[1].results, matchedresult[1])\n\n    def test_subshells(self):\n        cmd = '((bar); bar)'\n        matchedresult = [[(0, 2, helpconstants._subshell, '(('),\n                          (5, 6, helpconstants._subshell, ')'),\n                          (6, 7, helpconstants.OPERATORS[';'], ';'),\n                          (11, 12, helpconstants._subshell, ')')],\n                         [(2, 5, 'bar synopsis', 'bar')],\n                         [(8, 11, 'bar synopsis', 'bar')]]\n\n        groups = matcher.matcher(cmd, s).match()\n        self.assertEquals(groups[0].results, matchedresult[0])\n        self.assertEquals(groups[1].results, matchedresult[1])\n        self.assertEquals(groups[2].results, matchedresult[2])\n\n    def test_redirect_first_word_of_command(self):\n        cmd = '2>&1'\n        matchedresult = [(0, 4, helpconstants.REDIRECTION + '\\n\\n' +\n                                helpconstants.REDIRECTION_KIND['>'], '2>&1')]\n\n        groups = matcher.matcher(cmd, s).match()\n        self.assertEquals(len(groups), 1)\n        self.assertEquals(groups[0].results, matchedresult)\n\n        cmd = '2>&1 bar'\n        matchedresult = [[(0, 4, helpconstants.REDIRECTION + '\\n\\n' +\n                                 helpconstants.REDIRECTION_KIND['>'], '2>&1')],\n                         [(5, 8, 'bar synopsis', 'bar')]]\n\n        groups = matcher.matcher(cmd, s).match()\n        self.assertEquals(len(groups), 2)\n        self.assertEquals(groups[0].results, matchedresult[0])\n        self.assertEquals(groups[1].results, matchedresult[1])\n\n    def test_comsub(self):\n        cmd = 'bar $(a) -b \"b $(c) `c`\" \\'$(d)\\' >$(e) `f`'\n\n        matchedresult = [(0, 3, 'bar synopsis', 'bar'),\n                         (4, 8, None, '$(a)'),\n                         (9, 24, '-b <arg> desc', '-b \"b $(c) `c`\"'),\n                         (25, 31, None, \"'$(d)'\"),\n                         (38, 41, None, '`f`')]\n        shellresult = [(32, 37, helpconstants.REDIRECTION + '\\n\\n' +\n                                helpconstants.REDIRECTION_KIND['>'], '>$(e)')]\n\n        m = matcher.matcher(cmd, s)\n        groups = m.match()\n        self.assertEquals(groups[0].results, shellresult)\n        self.assertEquals(groups[1].results, matchedresult)\n\n        # check expansions\n        self.assertEquals(m.expansions, [(6, 7, 'substitution'),\n                                         (17, 18, 'substitution'),\n                                         (21, 22, 'substitution'),\n                                         (35, 36, 'substitution'),\n                                         (39, 40, 'substitution')])\n\n    def test_comsub_as_arg(self):\n        cmd = 'withargs $(a) $0'\n\n        matchedresult = [(0, 8, 'withargs synopsis', 'withargs'),\n                         (9, 16, 'FILE argument', '$(a) $0')]\n\n        m = matcher.matcher(cmd, s)\n        groups = m.match()\n        self.assertEquals(groups[0].results, [])\n        self.assertEquals(groups[1].results, matchedresult)\n\n        # check expansions\n        self.assertEquals(m.expansions, [(11, 12, 'substitution'),\n                                         (14, 16, 'parameter-digits')])\n\n    def test_comsub_as_first_word(self):\n        cmd = '$(a) b'\n\n        m = matcher.matcher(cmd, s)\n        groups = m.match()\n        self.assertEquals(len(groups), 2)\n        self.assertEquals(groups[0].results, [])\n        self.assertEquals(groups[1].results, [(0, 6, None, '$(a) b')])\n\n        # check expansions\n        self.assertEquals(m.expansions, [(2, 3, 'substitution')])\n\n    def test_procsub(self):\n        cmd = 'withargs -b <(a) >(b)'\n\n        matchedresult = [(0, 8, 'withargs synopsis', 'withargs'),\n                         (9, 16, '-b <arg> desc', '-b <(a)'),\n                         (17, 21, 'FILE argument', '>(b)')]\n\n        m = matcher.matcher(cmd, s)\n        groups = m.match()\n        self.assertEquals(groups[0].results, [])\n        self.assertEquals(groups[1].results, matchedresult)\n\n        # check expansions\n        self.assertEquals(m.expansions, [(14, 15, 'substitution'),\n                                         (19, 20, 'substitution')])\n\n    def test_if(self):\n        cmd = 'if bar -a; then b; fi'\n        shellresults = [(0, 2, helpconstants._if, 'if'),\n                        (9, 15, helpconstants._if, '; then'),\n                        (17, 21, helpconstants._if, '; fi')]\n\n        matchresults = [[(3, 6, 'bar synopsis', 'bar'), (7, 9, '-a desc', '-a')],\n                        [(16, 17, None, 'b')]]\n\n        groups = matcher.matcher(cmd, s).match()\n        self.assertEquals(len(groups), 3)\n        self.assertEquals(groups[0].results, shellresults)\n        self.assertEquals(groups[1].results, matchresults[0])\n        self.assertEquals(groups[2].results, matchresults[1])\n\n    def test_nested_controlflows(self):\n        cmd = 'for a; do while bar; do baz; done; done'\n        shellresults = [(0, 9, helpconstants._for, 'for a; do'),\n                        (10, 15, helpconstants._whileuntil, 'while'),\n                        (19, 23, helpconstants._whileuntil, '; do'),\n                        (27, 33, helpconstants._whileuntil, '; done'),\n                        (33, 39, helpconstants._for, '; done')]\n\n        matchresults = [[(16, 19, 'bar synopsis', 'bar')],\n                        [(24, 27, 'baz synopsis', 'baz')]]\n\n        groups = matcher.matcher(cmd, s).match()\n        self.assertEquals(len(groups), 3)\n        self.assertEquals(groups[0].results, shellresults)\n        self.assertEquals(groups[1].results, matchresults[0])\n        self.assertEquals(groups[2].results, matchresults[1])\n\n    def test_for_expansion(self):\n        cmd = 'for a in $(bar); do baz; done'\n        shellresults = [(0, 19, helpconstants._for, 'for a in $(bar); do'),\n                        (23, 29, helpconstants._for, '; done')]\n\n        matchresults = [(20, 23, 'baz synopsis', 'baz')]\n\n        m = matcher.matcher(cmd, s)\n        groups = m.match()\n        self.assertEquals(len(groups), 2)\n        self.assertEquals(groups[0].results, shellresults)\n        self.assertEquals(groups[1].results, matchresults)\n\n        self.assertEquals(m.expansions, [(11, 14, 'substitution')])\n\n\n    def test_assignment_with_expansion(self):\n        cmd = 'a=\"$1\" bar'\n\n        shellresults = [(0, 6, helpconstants.ASSIGNMENT, 'a=\"$1\"')]\n        matchresults = [[(7, 10, 'bar synopsis', 'bar')]]\n\n        groups = matcher.matcher(cmd, s).match()\n        self.assertEquals(len(groups), 2)\n        self.assertEquals(groups[0].results, shellresults)\n        self.assertEquals(groups[1].results, matchresults[0])\n\n    def test_assignment_as_first_word(self):\n        cmd = 'a=b bar'\n\n        shellresults = [(0, 3, helpconstants.ASSIGNMENT, 'a=b')]\n        matchresults = [(4, 7, 'bar synopsis', 'bar')]\n\n        groups = matcher.matcher(cmd, s).match()\n        self.assertEquals(len(groups), 2)\n        self.assertEquals(groups[0].results, shellresults)\n        self.assertEquals(groups[1].results, matchresults)\n\n    def test_expansion_limit(self):\n        cmd = 'a $(b $(c))'\n        m = matcher.matcher(cmd, s)\n        m.match()\n\n        class depthchecker(bashlex.ast.nodevisitor):\n            def __init__(self):\n                self.depth = 0\n                self.maxdepth = 0\n            def visitnode(self, node):\n                if 'substitution' in node.kind:\n                    self.depth += 1\n                    self.maxdepth = max(self.maxdepth, self.depth)\n            def visitendnode(self, node):\n                if 'substitution' in node.kind:\n                    self.depth -= 1\n\n        v = depthchecker()\n        v.visit(m.ast)\n        self.assertEquals(v.maxdepth, 1)\n\n    def test_functions(self):\n        cmd = 'function a() { bar; }'\n        shellresults = [(0, 14, helpconstants._function, 'function a() {'),\n                        (18, 19, helpconstants.OPSEMICOLON, ';'),\n                        (20, 21, helpconstants._function, '}'),]\n\n        matchresults = [(15, 18, 'bar synopsis', 'bar')]\n\n        groups = matcher.matcher(cmd, s).match()\n        self.assertEquals(len(groups), 2)\n        self.assertEquals(groups[0].results, shellresults)\n        self.assertEquals(groups[1].results, matchresults)\n\n        cmd = 'function a() { bar \"$(a)\"; }'\n        shellresults = [(0, 14, helpconstants._function, 'function a() {'),\n                        (25, 26, helpconstants.OPSEMICOLON, ';'),\n                        (27, 28, helpconstants._function, '}'),]\n\n        matchresults = [(15, 18, 'bar synopsis', 'bar'),\n                        (19, 25, None, '\"$(a)\"')]\n\n        m = matcher.matcher(cmd, s)\n        groups = m.match()\n\n        self.assertEquals(len(groups), 2)\n        self.assertEquals(groups[0].results, shellresults)\n        self.assertEquals(groups[1].results, matchresults)\n        self.assertEquals(m.expansions, [(22, 23, 'substitution')])\n\n    def test_function_reference(self):\n        cmd = 'function a() { bar; a b; }; a'\n        shellresults = [(0, 14, helpconstants._function, 'function a() {'),\n                        (18, 19, helpconstants.OPSEMICOLON, ';'),\n                        (20, 21, helpconstants._functioncall % 'a', 'a'),\n                        (22, 23, helpconstants._functionarg % 'a', 'b'),\n                        (23, 24, helpconstants.OPSEMICOLON, ';'),\n                        (25, 26, helpconstants._function, '}'),\n                        (26, 27, helpconstants.OPSEMICOLON, ';'),\n                        (28, 29, helpconstants._functioncall % 'a', 'a'),]\n\n        matchresults = [(15, 18, 'bar synopsis', 'bar')]\n\n        m = matcher.matcher(cmd, s)\n        groups = m.match()\n        self.assertEquals(len(groups), 2)\n        self.assertEquals(groups[0].results, shellresults)\n        self.assertEquals(groups[1].results, matchresults)\n\n        self.assertEquals(m.functions, set(['a']))\n\n    def test_comment(self):\n        cmd = 'bar # a comment'\n\n        shellresults = [(4, 15, helpconstants.COMMENT, '# a comment')]\n        matchresults = [(0, 3, 'bar synopsis', 'bar')]\n\n        m = matcher.matcher(cmd, s)\n        groups = m.match()\n        self.assertEquals(len(groups), 2)\n        self.assertEquals(groups[0].results, shellresults)\n        self.assertEquals(groups[1].results, matchresults)\n\n        cmd = '# just a comment'\n\n        shellresults = [(0, 16, helpconstants.COMMENT, '# just a comment')]\n\n        m = matcher.matcher(cmd, s)\n        groups = m.match()\n        self.assertEquals(len(groups), 1)\n        self.assertEquals(groups[0].results, shellresults)\n\n    def test_heredoc_at_eof(self):\n        cmd = 'bar <<EOF'\n\n        shellresults = [(4, 9, helpconstants.REDIRECTION + '\\n\\n' +\n                               helpconstants.REDIRECTION_KIND['<<'], '<<EOF')]\n\n        matchresults = [(0, 3, 'bar synopsis', 'bar')]\n\n        groups = matcher.matcher(cmd, s).match()\n        self.assertEquals(len(groups), 2)\n        self.assertEquals(groups[0].results, shellresults)\n        self.assertEquals(groups[1].results, matchresults)\n\n    def test_no_synopsis(self):\n        cmd = 'nosynopsis a'\n\n        matchresults = [(0, 10, helpconstants.NOSYNOPSIS, 'nosynopsis'),\n                        (11, 12, None, 'a')]\n\n        groups = matcher.matcher(cmd, s).match()\n        self.assertEquals(len(groups), 2)\n        self.assertEquals(groups[0].results, [])\n        self.assertEquals(groups[1].results, matchresults)\n"
  },
  {
    "path": "tests/test-options.py",
    "content": "import unittest\n\nfrom explainshell import options, store, errors\n\nclass test_options(unittest.TestCase):\n    def test_simple(self):\n        s = '\\t-a description'\n        self.assertEquals(options.extract_option(s), (['-a'], []))\n\n        s = '\\t-a, description'\n        self.assertEquals(options.extract_option(s), (['-a'], []))\n\n        r = (['-a', '-b'], [])\n        s = '\\t-a, -b description'\n        self.assertEquals(options.extract_option(s), r)\n\n        s = '\\t-a/-b description'\n        self.assertEquals(options.extract_option(s), r)\n\n        s = '\\t-a -b description'\n        self.assertEquals(options.extract_option(s), r)\n\n        s = '\\t-a     -b,-c,           -d description'\n        self.assertEquals(options.extract_option(s), (['-a', '-b', '-c', '-d'], []))\n\n        s = '\\t--a, -b, --c-d description'\n        self.assertEquals(options.extract_option(s), (['-b'], ['--a', '--c-d']))\n\n        s = '---c-d '\n        self.assertEquals(options.extract_option(s), ([], []))\n\n        s = '-c- '\n        self.assertEquals(options.extract_option(s), ([], []))\n\n    def test_option_arg(self):\n        s = '\\t-a FOO, -b=BAR, description'\n        self.assertEquals(options.extract_option(s),\n                          ([('-a', 'FOO'), ('-b', 'BAR')], []))\n\n        s = '\\t-a [FOO], -b[=BAR], description'\n        self.assertEquals(options.extract_option(s),\n                          ([('-a', 'FOO'), ('-b', 'BAR')], []))\n\n        s = '\\t-a<n>, -b=<BAR>, -C <ah>'\n        self.assertEquals(options.extract_option(s),\n                          ([('-a', 'n'), ('-b', 'BAR'), ('-C', 'ah')], []))\n\n        s = '\\t--aa    FOO, --bb=BAR, description'\n        self.assertEquals(options.extract_option(s),\n                          ([], [('--aa', 'FOO'), ('--bb', 'BAR')]))\n\n        s = '-a or -b'\n        self.assertEquals(options.extract_option(s),\n                          (['-a', '-b'], []))\n\n    def test_pipe_separator(self):\n        s = '-a|b'\n        self.assertEquals(options.extract_option(s),\n                          (['-a', 'b'], []))\n\n        s = '-a|-b|--c|d'\n        self.assertEquals(options.extract_option(s),\n                          (['-a', '-b', 'd'], ['--c']))\n\n    def test_multiline_options(self):\n        s = '\\t-a, -b, \\n-c, --ddd description'\n        self.assertEquals(options.extract_option(s),\n                          (['-a', '-b', '-c'], ['--ddd']))\n\n    def test_multiline_desc(self):\n        s = '\\t-a, -b description\\n\\tmultiline\\n  another line'\n        self.assertEquals(options.extract_option(s), (['-a', '-b'], []))\n\n    def test_not_an_option(self):\n        self.assertEquals(options.extract_option('foobar'), ([], []))\n\n    def test_no_hyphen(self):\n        s = '\\ta=b description'\n        self.assertEquals(options.extract_option(s), ([], [('a', 'b')]))\n\n    def test_hyphen_in_arg(self):\n        s = '-a=FOO-BAR, --aa=FOO-BAR'\n        self.assertEquals(options.extract_option(s),\n                          ([('-a', 'FOO-BAR')], [('--aa', 'FOO-BAR')]))\n\n        #s = '-a FOO-BAR, --aa FOO-BAR'\n        #self.assertEquals(options.extract_option(s),\n        #                  ([('-a', 'FOO-BAR')], [('--aa', 'FOO-BAR')]))\n\n    def test_extract(self):\n        p1 = store.paragraph(0, '<b>--test</b>=<u>arg</u>\\ndesc', '', True)\n        p2 = store.paragraph(1, 'no options here', '', True)\n        p3 = store.paragraph(2, '--foo-bar=&lt;arg&gt;\\ndesc', '', True)\n\n        m = store.manpage('', '', '', [p1, p2, p3], [])\n        options.extract(m)\n        r = m.options\n        self.assertEquals(len(r), 2)\n        self.assertEquals(r[0].text, p1.text)\n        self.assertEquals(r[0].short, [])\n        self.assertEquals(r[0].long, ['--test'])\n        self.assertEquals(r[0].expectsarg, True)\n\n        self.assertEquals(r[1].text, p3.text)\n        self.assertEquals(r[1].short, [])\n        self.assertEquals(r[1].long, ['--foo-bar'])\n        self.assertEquals(r[1].expectsarg, True)\n\n    def test_help(self):\n        s = '\\t-?, --help description'\n        self.assertEquals(options.extract_option(s), (['-?'], ['--help']))\n"
  },
  {
    "path": "tools/dlgzlist",
    "content": "#!/bin/bash -e\n\nwhile read url; do\n\tif [ -f $(printf \"$url\" | cut -d / -f 7) ]; then\n\t\tcontinue\n\tfi\n\n\tpython -c 'import time, random; time.sleep(float(random.randint(1000, 2000)) / 1000)'\n\twget -nv \"$url\" || echo \"$url\" >> failed\ndone < gzlist\n"
  },
  {
    "path": "tools/extractgzlist",
    "content": "#!/bin/bash\n\nrelease=\"precise\"\nsection=\"8\"\nman1list=\"http://manpages.ubuntu.com/manpages/$release/en/man$section/\"\ngzroot=\"http://manpages.ubuntu.com/manpages.gz/$release/man$section/\"\nfilename=\"index$section.html\"\n\nif ! [ -f $filename ]; then\n\tcurl -o $filename \"$man1list\"\nfi\n\ngrep 'alt=\"\\[TXT\\]\"' $filename | cut -d '<' -f 3 | cut -d '>' -f 2 | sed 's/\\.html//' | sed -e 's/$/.gz/' -e \"s|^|$gzroot|\" > gzlist$section\n"
  },
  {
    "path": "tools/shellbuiltins.py",
    "content": "# -*- coding: utf-8 -*-\n\n'''manually define and add shell builtins into the store\n\nunfortunately the bash section for builtins isn't written in a way\nexplainshell can understannd, so we have to resort to manually\nwriting these down and adding them.'''\n\nimport textwrap\nfrom explainshell import store, config\n\nsp = store.paragraph\nso = store.option\nsm = store.manpage\n\nBUILTINS = {}\n\ndef _add(names, synopsis, options):\n    name = names[0]\n    # hack: fake a source man page (this breaks the outgoing links from\n    # explainshell, oh well)\n    names.append('bash-%s' % name)\n    BUILTINS[name] = sm('bash-%s.1.gz' % name, name, synopsis, options, [(name, 20) for name in names])\n\n_add([':'], 'the command does nothing', [so(sp(0, '''No  effect;  the command does nothing beyond expanding arguments and performing any specified redirections.  A zero\nexit code  is returned.''', '', True), [], [], False, True, False)])\n\nsource = textwrap.dedent('''       <b>.</b>  <u>filename</u> [<u>arguments</u>]\n       <b>source</b> <u>filename</u> [<u>arguments</u>]\n              Read  and  execute  commands  from <u>filename</u> in the current shell environment and return the  exit  status  of\n              the  last  command executed  from  <u>filename</u>.  If <u>filename</u> does not contain a slash, filenames in <b>PATH</b> are used\n              to  find  the  directory  containing <u>filename</u>.  The file searched for in <b>PATH</b> need not be executable.  When\n              <b>bash</b> is not  in  <u>posix</u>  <u>mode</u>,  the  current  directory  is searched  if no file is found in <b>PATH</b>.  If the\n              <b>sourcepath</b> option to the <b>shopt</b> builtin command is turned  off,  the  <b>PATH</b>  is  not searched.   If  any\n              <u>arguments</u>  are  supplied,  they  become the positional parameters when <u>filename</u> is executed.  Otherwise\n              the positional  parameters  are unchanged.  The return status is the status of the last command exited within\n              the  script  (0  if  no commands  are  executed), and false if <u>filename</u> is not found or cannot be read.''')\n_add(['source', '.'], 'read and execute commands in the current shell', [so(sp(0, source, '', True), [], [], False, True, False)])\n\n_add(['break'], 'exit from within a for, while, until, or select loop',\n     [so(sp(0, '''If <u>n</u> is specified, break <u>n</u> levels.  <u>n</u> must be ≥ 1.  If <u>n</u> is greater than the  number  of enclosing loops, all enclosing loops are exited.  The return value is 0 unless <u>n</u> is not greater than or  equal  to 1.''', '', True), [], [], False, True, False)])\n\n_add(['history'], 'display the  command  history  list  with  line numbers',\n    [so(sp(0, '''<b>history</b> <b>[</b><u>n</u><b>]</b>\n<b>history</b> <b>-c</b>\n<b>history</b> <b>-d</b> <u>offset</u>\n<b>history</b> <b>-anrw</b> [<u>filename</u>]\n<b>history</b> <b>-p</b> <u>arg</u> [<u>arg</u> <u>...</u>]\n<b>history</b> <b>-s</b> <u>arg</u> [<u>arg</u> <u>...</u>]\n\nWith no options, display the  command  history  list  with  line numbers.  Lines listed with a <b>*</b> have been modified.\nAn argument of <u>n</u> lists only  the  last  <u>n</u>  lines.   If  the  shell  variable <b>HISTTIMEFORMAT</b>  is  set\nand  not  null,  it is used as a format string for <u>strftime</u>(3) to display the time stamp associated with each\ndisplayed  history entry.  No intervening blank is printed between the formatted time  stamp  and  the  history\nline.   If <u>filename</u>  is  supplied,  it  is  used as the name of the history file; if not, the  value  of\n<b>HISTFILE</b>  is  used.''', '', True), [], [], False, True, False),\n     so(sp(1, '<b>-c</b>     Clear the history list by deleting all the entries.', '', True), ['-c'], [], False, False, False),\n     so(sp(2, textwrap.dedent('''              <b>-d</b> <u>offset</u>\n                     Delete the history entry at position <u>offset</u>.'''), '', True), ['-d'], [], 'offset', False, False),\n     so(sp(3, textwrap.dedent('''              <b>-a</b>     Append  the  ``new'' history lines (history lines entered since the beginning of the current <b>bash</b> session)\n                     to  the history file.'''), '', True), ['-a'], [], False, False, False),\n     so(sp(4, textwrap.dedent('''              <b>-n</b>     Read  the history lines not already read from the history file into the current  history  list.   These  are\n                     lines appended  to  the history file since the beginning of the current <b>bash</b> session.'''), '', True), ['-n'], [], False, False, False),\n     so(sp(5, textwrap.dedent('''              <b>-r</b>     Read the contents of the history file and append them  to the current history list.'''), '', True), ['-r'], [], False, False, False),\n     so(sp(6, textwrap.dedent('''              <b>-w</b>     Write  the  current  history  list  to  the history file, overwriting the history file's contents.'''), '', True), ['-w'], [], 'filename', False, False),\n     so(sp(7, textwrap.dedent('''              <b>-p</b>     Perform history substitution on the  following  <u>args</u>  and display  the  result  on  the  standard output.\n                     Does not store the results in the history list.  Each <u>arg</u> must  be quoted to disable normal history expansion.'''), '', True), ['-p'], [], 'arg', True, False),\n     so(sp(8, textwrap.dedent('''              <b>-s</b>     Store  the  <u>args</u>  in  the history list as a single entry.  The last command in the history list  is\n                     removed  before the <u>args</u> are added.'''), '', True), ['-s'], [], 'arg', False, False)])\n\nif __name__ == '__main__':\n    import logging.config\n    logging.config.dictConfig(config.LOGGING_DICT)\n\n    s = store.store('explainshell', config.MONGO_URI)\n    for m in BUILTINS.itervalues():\n        s.addmanpage(m)\n"
  },
  {
    "path": "tools/w3mman2html.cgi",
    "content": "#!/usr/bin/env perl\n\n$MAN = $ENV{'W3MMAN_MAN'} || '@MAN@';\n$QUERY = $ENV{'QUERY_STRING'} || $ARGV[0];\n$SCRIPT_NAME = $ENV{'SCRIPT_NAME'} || $0;\n$CGI = \"file://$SCRIPT_NAME\";\n$CGI2 = \"file:\";\n# $CGI2 = \"file:///\\$LIB/hlink.cgi?\";\n$SQUEEZE = 1;\n$ENV{'PAGER'} = 'cat';\n\nif ($QUERY =~ /\\=/) {\n  for (split('&', $QUERY)) {\n    ($v, $q) = split('=', $_, 2);\n    $query{$v} = &form_decode($q); \n  }\n} else {\n  $QUERY =~ s/^man=//;\n  $query{\"man\"} = &form_decode($QUERY);\n}\n\nif ((! $query{\"man\"}) && (! $query{\"local\"})) {\n  if ($query{\"keyword\"}) {\n    $keyword = $query{\"keyword\"};\n    $k = &html_quote($keyword);\n    print <<EOF;\nContent-Type: text/html\n\n<html>\n<head><title>man -k $k</title></head>\n<body>\n<h2>man -k <b>$k</b></h2>\n<ul>\nEOF\n    $keyword =~ s:([^-\\w\\200-\\377.,])::g;\n    open(F, \"$MAN -k $keyword 2> /dev/null |\");\n    @line = ();\n    while(<F>) {\n      chop;\n      $_ = &html_quote($_);\n      s/(\\s+-.*)$//;\n      $title = $1;\n      s@(\\w[\\w.\\-]*(\\s*\\,\\s*\\w[\\w.\\-]*)*)\\s*(\\([\\dn]\\w*\\))@&keyword_ref($1, $3)@ge;\n      print \"<li>$_$title\\n\";\n    }\n    close(F);\n    print <<EOF;\n</ul>\n</body>\n</html>\nEOF\n    exit;\n  }\n  print <<EOF;\nContent-Type: text/html\n\n<html>\n<head><title>man</title></head>\n<body>\n<form action=\"$CGI\">\n<table>\n<tr><td>Manual:<td><input name=man>\n<tr><td>Section:<td><input name=section>\n<tr><td>Keyword:<td><input name=keyword>\n<tr><td><td><input type=submit> <input type=reset>\n</table>\n</form>\n</body>\n</html>\nEOF\n  exit;\n}\n\nif ($query{\"local\"}) {\n  $file = $query{\"local\"};\n  if (! ($file =~ /^\\//)) {\n    $file = $query{\"pwd\"} . '/' . $file;\n  }\n  open(F, \"MAN_KEEP_FORMATTING=1 $MAN -l $file 2> /dev/null |\");\n} else {\n  $man = $query{\"man\"};\n  if ($man =~ s/\\((\\w+)\\)$//) {\n    $section = $1;\n    $man_section = \"$man($1)\";\n  } elsif ($query{\"section\"}) {\n    $section = $query{\"section\"};\n    $man_section = \"$man($section)\";\n  } else {\n    $section = \"\";\n    $man_section = \"$man\";\n  }\n\n  $section =~ s:([^-\\w\\200-\\377.,])::g;\n  $man =~ s:([^-\\w\\200-\\377.,])::g;\n  open(F, \"MAN_KEEP_FORMATTING=1 $MAN $section $man 2> /dev/null |\");\n}\n$ok = 0;\nundef $header;\n$blank = -1;\n$cmd = \"\";\n$prev = \"\";\nwhile(<F>) {\n  if (! defined($header)) {\n    /^\\s*$/ && next;\n    $header = $_;\n    $space = $header;\n    chop $space;\n    $space =~ s/\\S.*//;\n  } elsif ($_ eq $header) {\t\t# delete header\n    $blank = -1;\n    next;\n  } elsif (!/\\010/ && /^$space[\\w\\200-\\377].*\\s\\S/o) {\t# delete footer\n    $blank = -1;\n    next;\n  }\n  if ($SQUEEZE) {\n    if (/^\\s*$/) {\n      $blank || $blank++;\n      next;\n    } elsif ($blank) {\n      $blank > 0 && print \"\\n\";\n      $blank = 0;\n    }\n  }\n\n  s/\\&/\\&amp;/g;\n  s/\\</\\&lt;/g;\n  s/\\>/\\&gt;/g;\n\n  s@([\\200-\\377].)(\\010{1,2}\\1)+@<b>$1</b>@g;\n  s@(\\&\\w+;|.)(\\010\\1)+@<b>$1</b>@g;\n  s@__\\010{1,2}((\\<b\\>)?[\\200-\\377].(\\</b\\>)?)@<u>$1</u>@g;\n  s@_\\010((\\<b\\>)?(\\&\\w+\\;|.)(\\</b\\>)?)@<u>$1</u>@g;\n  s@((\\<b\\>)?[\\200-\\377].(\\</b\\>)?)\\010{1,2}__@<u>$1</u>@g;\n  s@((\\<b\\>)?(\\&\\w+\\;|.)(\\</b\\>)?)\\010_@<u>$1</u>@g;\n  s@.\\010(.)@$1@g;\n\n  s@\\</b\\>\\</u\\>\\<b\\>_\\</b\\>\\<u\\>\\<b\\>@_@g;\n  s@\\</u\\>\\<b\\>_\\</b\\>\\<u\\>@_@g;\n  s@\\</u\\>\\<u\\>@@g;\n  s@\\</b\\>\\<b\\>@@g;\n\n  if (! $ok) {\n    /^No/ && last;\n    print <<EOF;\nContent-Type: text/html\n\n<html>\n<head><title>man $man_section</title></head>\n<body>\n<pre>\nEOF\n    print;\n    $ok = 1;\n    next;\n  }\n\n  s@(http|ftp)://[\\w.\\-/~]+[\\w/]@<a href=\"$&\">$&</a>@g;\n  s@(\\W)(mailto:)?(\\w[\\w.\\-]*\\@\\w[\\w.\\-]*\\.[\\w.\\-]*\\w)@$1<a href=\"mailto:$3\">$2$3</a>@g;\n  s@(\\W)(\\~?/[\\w.][\\w.\\-/~]*)@$1 . &file_ref($2)@ge;\n  s@(include(<\\/?[bu]\\>|\\s)*\\&lt;)([\\w.\\-/]+)@$1 . &include_ref($3)@ge;\n  if ($prev && m@^\\s*(\\<[bu]\\>)*(\\w[\\w.\\-]*)(\\</[bu]\\>)*(\\([\\dm]\\w*\\))@) {\n    $cmd .= \"$2$4\";\n    $prev =~ s@(\\w[\\w.\\-]*-)((\\</[bu]\\>)*\\s*)$@<a href=\"$CGI?$cmd\">$1</a>$2@;\n    print $prev;\n    $prev = '';\n    s@^(\\s*(\\<[bu]\\>)*)(\\w[\\w.\\-]*)@@;\n    print \"$1<a href=\\\"$CGI?$cmd\\\">$3</a>\";\n  } elsif ($prev) {\n    print $prev;\n    $prev = '';\n  }\n  s@(\\w[\\w.\\-]*)((\\</[bu]\\>)*)(\\([\\dm]\\w*\\))@<a href=\"$CGI?$1$4\">$1</a>$2$4@g;\n  if (m@(\\w[\\w.\\-]*)-(\\</[bu]\\>)*\\s*$@) {\n    $cmd = $1;\n    $prev = $_;\n    next;\n  }\n  print;\n}\nif ($prev) {\n  print $prev;\n}\nclose(F);\nif (! $ok) {\n  if ($query{'quit'}) {\n    if ($query{'local'}) {\n      print STDERR \"File $file not found.\\n\";\n    } else {\n      print STDERR \"No manual entry for $man_section.\\n\";\n    }\n    print STDERR \"No manual entry for $man_section.\\n\";\n    print <<EOF;\nw3m-control: EXIT\nEOF\n    exit 1;\n  }\n  print <<EOF;\nContent-Type: text/html\n\n<html>\n<head><title>man $man_section</title></head>\n<body>\n<pre>\nEOF\n  if ($query{'local'}) {\n    print \"File <B>$file</B> not found.\\n\";\n  } else {\n    print \"No manual entry for <B>$man_section</B>.\\n\";\n  }\n}\nprint <<EOF;\n</pre>\n</body>\n</html>\nEOF\n\nsub is_command {\n  local($_) = @_;\n  local($p);\n\n  (! -d && -x) || return 0;\n  if (! (%PATH)) {\n    for $p (split(\":\", $ENV{'PATH'})) {\n      $p =~ s@/+$@@;\n      $PATH{$p} = 1;\n    }\n  }\n  s@/[^/]*$@@;\n  return defined($PATH{$_});\n}\n\nsub file_ref {\n  local($_) = @_;\n\n  if (&is_command($_)) {\n    ($man = $_) =~ s@.*/@@;\n    return \"<a href=\\\"$CGI?$man\\\">$_</a>\";\n  }\n  if (/^\\~/ || -f || -d) {\n    return \"<a href=\\\"$CGI2$_\\\">$_</a>\";\n  }\n  return $_;\n}\n\nsub include_ref {\n  local($_) = @_;\n  local($d);\n\n  for $d (\n\t\"/usr/include\",\n\t\"/usr/local/include\",\n\t\"/usr/X11R6/include\",\n\t\"/usr/X11/include\",\n\t\"/usr/X/include\",\n\t\"/usr/include/X11\"\n  ) {\n    -f \"$d/$_\" && return \"<a href=\\\"$CGI2$d/$_\\\">$_</a>\";\n  }\n  return $_;\n}\n\nsub keyword_ref {\n  local($_, $s) = @_;\n  local(@a) = ();\n\n  for (split(/\\s*,\\s*/)) {\n    push(@a, \"<a href=\\\"$CGI?$_$s\\\">$_</a>\");\n  }\n  return join(\", \", @a) . $s;\n}\n\nsub html_quote {\n  local($_) = @_;\n  local(%QUOTE) = (\n    '<', '&lt;',\n    '>', '&gt;',\n    '&', '&amp;',\n    '\"', '&quot;',\n  );\n  s/[<>&\"]/$QUOTE{$&}/g;\n  return $_;\n}\n\nsub form_decode {\n  local($_) = @_;\n  s/\\+/ /g;\n  s/%([\\da-f][\\da-f])/pack('c', hex($1))/egi;\n  return $_;\n}\n\n"
  }
]