[
  {
    "path": ".gitignore",
    "content": "# Created by .ignore support plugin (hsz.mobi)\n### Example user template\n\n# IntelliJ project files\n.idea\n*.iml\nout\ngen### Python template\n# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / packaging\n.Python\nenv/\nbuild/\ndevelop-eggs/\ndist/\ndownloads/\neggs/\n.eggs/\nlib/\nlib64/\nparts/\nsdist/\nvar/\n*.egg-info/\n.installed.cfg\n*.egg\n\n# PyInstaller\n#  Usually these files are written by a python script from a template\n#  before PyInstaller builds the exe, so as to inject date/other infos into it.\n*.manifest\n*.spec\n\n# Installer logs\npip-log.txt\npip-delete-this-directory.txt\n\n# Unit test / coverage reports\nhtmlcov/\n.tox/\n.coverage\n.coverage.*\n.cache\nnosetests.xml\ncoverage.xml\n*,cover\n.hypothesis/\n\n# Translations\n*.mo\n*.pot\n\n# Django stuff:\n*.log\nlocal_settings.py\n\n# Flask stuff:\ninstance/\n.webassets-cache\n\n# Scrapy stuff:\n.scrapy\n\n# Sphinx documentation\ndocs/_build/\n\n# PyBuilder\ntarget/\n\n# IPython Notebook\n.ipynb_checkpoints\n\n# pyenv\n.python-version\n\n# celery beat schedule file\ncelerybeat-schedule\n\n# dotenv\n.env\n\n# virtualenv\nvenv/\nENV/\n\n# Spyder project settings\n.spyderproject\n\n# Rope project settings\n.ropeproject\n### JetBrains template\n# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm\n# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839\n\n# User-specific stuff:\n.idea/workspace.xml\n.idea/tasks.xml\n.idea/dictionaries\n.idea/vcs.xml\n.idea/jsLibraryMappings.xml\n\n# Sensitive or high-churn files:\n.idea/dataSources.ids\n.idea/dataSources.xml\n.idea/dataSources.local.xml\n.idea/sqlDataSources.xml\n.idea/dynamic.xml\n.idea/uiDesigner.xml\n\n# Gradle:\n.idea/gradle.xml\n.idea/libraries\n\n# Mongo Explorer plugin:\n.idea/mongoSettings.xml\n\n## File-based project format:\n*.iws\n\n## Plugin-specific files:\n\n# IntelliJ\n/out/\n\n# mpeltonen/sbt-idea plugin\n.idea_modules/\n\n# JIRA plugin\natlassian-ide-plugin.xml\n\n# Crashlytics plugin (for Android Studio and IntelliJ)\ncom_crashlytics_export_strings.xml\ncrashlytics.properties\ncrashlytics-build.properties\nfabric.properties\n### VirtualEnv template\n# Virtualenv\n# http://iamzed.com/2009/05/07/a-primer-on-virtualenv/\n[Bb]in\n[Ii]nclude\n[Ll]ib\n[Ll]ib64\n[Ll]ocal\n[Ss]cripts\npyvenv.cfg\n.venv\npip-selfcheck.json\n\n## USER STUFF!\nlogs/*\n!.gitkeep\nnode_modules/\nbower_components/\ntmp\n.DS_Store\n.idea"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"extras/phppgadmin-docker\"]\n\tpath = extras/phppgadmin-docker\n\turl = https://github.com/luckydonald-forks/phppgadmin-docker.git\n[submodule \"code/node_java\"]\n\tpath = code/node_java\n\turl = https://github.com/luckydonald/PBFT-JAVA.git\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: python\n\npython:\n  - \"3.5\"\n  - \"3.6\"\n  - \"nightly\"\n\nmatrix:\n  allow_failures:\n    - python: nightly\n\n# command to install dependencies\ninstall:\n  - \"pip install -r code/api/requirements.txt\"\n  - \"pip install coverage coveralls\"\n\n# command to run tests\nscript:\n  - cd code && coverage run tests.py\n\nafter_success:\n  - coveralls\n\nnotifications:\n  # https://docs.travis-ci.com/user/notifications#Notifications\n  webhooks:\n    urls:\n      - \"https://bot.proxy.bronies.link/travis/webhook/tfgDCtRoiTR4LPP1ZHMvjcdBWzuyhMgiotsTSRgg6Dc\"\n    on_success: always  # default: always\n    on_failure: always  # default: always\n    on_start: always    # default: never\n    # [always|never|change]  # change means to notify when the build status changes.\n"
  },
  {
    "path": "Dockerfile",
    "content": "FROM python:3.5\n\n# dependencies:\nRUN mkdir /code\nWORKDIR /code/\n\n# libs\nRUN mkdir /code/libs/\nADD ./extras/libs/ /code/libs\nADD ./requirements.txt /code\nRUN pip install -r requirements.txt\nRUN rm requirements.txt\n# dependencies done\n\n# our code:\nWORKDIR /code/\nADD ./code /code/\n\n# defaults for running it\nENTRYPOINT [\"python\"]\nCMD [\"main.py\"]\n"
  },
  {
    "path": "LICENSE",
    "content": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU General Public License is a free, copyleft license for\nsoftware and other kinds of works.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nthe GNU General Public License is intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.  We, the Free Software Foundation, use the\nGNU General Public License for most of our software; it applies also to\nany other work released this way by its authors.  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  To protect your rights, we need to prevent others from denying you\nthese rights or asking you to surrender the rights.  Therefore, you have\ncertain responsibilities if you distribute copies of the software, or if\nyou modify it: responsibilities to respect the freedom of others.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must pass on to the recipients the same\nfreedoms that you received.  You must make sure that they, too, receive\nor can get the source code.  And you must show them these terms so they\nknow their rights.\n\n  Developers that use the GNU GPL protect your rights with two steps:\n(1) assert copyright on the software, and (2) offer you this License\ngiving you legal permission to copy, distribute and/or modify it.\n\n  For the developers' and authors' protection, the GPL clearly explains\nthat there is no warranty for this free software.  For both users' and\nauthors' sake, the GPL requires that modified versions be marked as\nchanged, so that their problems will not be attributed erroneously to\nauthors of previous versions.\n\n  Some devices are designed to deny users access to install or run\nmodified versions of the software inside them, although the manufacturer\ncan do so.  This is fundamentally incompatible with the aim of\nprotecting users' freedom to change the software.  The systematic\npattern of such abuse occurs in the area of products for individuals to\nuse, which is precisely where it is most unacceptable.  Therefore, we\nhave designed this version of the GPL to prohibit the practice for those\nproducts.  If such problems arise substantially in other domains, we\nstand ready to extend this provision to those domains in future versions\nof the GPL, as needed to protect the freedom of users.\n\n  Finally, every program is threatened constantly by software patents.\nStates should not allow patents to restrict development and use of\nsoftware on general-purpose computers, but in those that do, we wish to\navoid the special danger that patents applied to a free program could\nmake it effectively proprietary.  To prevent this, the GPL assures that\npatents cannot be used to render the program non-free.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Use with the GNU Affero General Public License.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU Affero General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the special requirements of the GNU Affero General Public License,\nsection 13, concerning interaction through a network will apply to the\ncombination as such.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    {one line to give the program's name and a brief idea of what it does.}\n    Copyright (C) {year}  {name of author}\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If the program does terminal interaction, make it output a short\nnotice like this when it starts in an interactive mode:\n\n    {project}  Copyright (C) {year}  {fullname}\n    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, your program's commands\nmight be different; for a GUI interface, you would use an \"about box\".\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU GPL, see\n<http://www.gnu.org/licenses/>.\n\n  The GNU General Public License does not permit incorporating your program\ninto proprietary programs.  If your program is a subroutine library, you\nmay consider it more useful to permit linking proprietary applications with\nthe library.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.  But first, please read\n<http://www.gnu.org/philosophy/why-not-lgpl.html>.\n"
  },
  {
    "path": "Makefile",
    "content": "update:\n\tgit log -1\n\tgit status\n\tgit pull origin master\n\tgit submodule foreach git pull origin master\n\nstart:\n\tdocker-compose up -d postgres\n\tdocker-compose up --force-recreate -d postgres_browser\n\tdocker-compose up -d --build api\n\tdocker-compose build node node_java\n\nhelp:\n\techo \"docker-compose up --build -t 0 node_java\"\n"
  },
  {
    "path": "README.md",
    "content": "# pbft\nImplementation of the ~~Peters~~ Practical Byzantine Fault Tolerant Algorithm    \n\n\n## Web GUI\n\nThis project supports a web interface to `b e a u t i f u l l y` represent what's going on.\n\nYou'll get a overview over all the values the nodes measured.\n\n![image](https://user-images.githubusercontent.com/2737108/33264568-63590e78-d36e-11e7-91e3-d0b2545546ae.png)\n\nYou can also get insight which messages get send by which node to which node.\n\n![image](https://user-images.githubusercontent.com/2737108/33264484-06f95a3e-d36e-11e7-9128-e3a2de4c37d5.png)\n\n\n## Code status\n\n> Please note, the project for which this was made for has reached an end,\n> so the code will not be actively maintained any longer.\n> However, pull requests with fixes and improvements will be merged.\n> Have a look into the bugtracker, if someone else had a similar issue, and already made it work.\n\n#### Java PBFT Node \n[![Build Status](https://travis-ci.org/luckydonald/PBFT-JAVA.svg?branch=master)](https://travis-ci.org/luckydonald/PBFT-JAVA) [![Coverage Status](https://coveralls.io/repos/github/luckydonald/PBFT-JAVA/badge.svg?branch=master)](https://coveralls.io/github/luckydonald/PBFT-JAVA?branch=master)\n\n#### API Server\n[![Build Status](https://travis-ci.org/luckydonald/pbft.svg?branch=master)](https://travis-ci.org/luckydonald/pbft) [![Coverage Status](https://coveralls.io/repos/github/luckydonald/pbft/badge.svg?branch=master)](https://coveralls.io/github/luckydonald/pbft?branch=master)\n\n\n## Get the Code\n```bash\ngit clone --recursive https://github.com/luckydonald/pbft.git\n```\nIf you forget `--recursive`, the `phppgadmin` container won't be available.\n\n## Starting everything\nYou need Docker installed.\n\n\n```shell\n$ docker-compose build\n```\n \nBecause some services need longer to start it is best to start them in the following order:\n \n1. Database and Database browser\n    ```shell\n    $ docker-compose up -d postgres postgres_browser\n    ```\n\n2. The API\n    ```shell\n    $ docker-compose up -d api \n    ```\n\n3. Start the web GUI\n    ```shell\n    $ docker-compose up -d web\n    ```\n\n4. Scale the nodes to use e.g. `4` instances\n  - a) Older compose syntax\n      ```shell\n      $ docker-compose scale node=4\n      ```\n  - b) Newer compose syntax\n      ```shell\n      docker-compose up --scale node=4\n      ```\n\n5. Start the nodes\n    ```shell\n    $ docker-compose up -d node\n    ```\n    \n6. Stop & reset everything\n    ```shell\n    $ docker-compose down\n    ```\n    - [Remove unused containers](http://stackoverflow.com/a/32723127):\n        ```shell\n        $ docker rmi $(docker images --filter \"dangling=true\" -q --no-trunc)\n        ```\n\n## Standart Ports and URLs\nAssuming your docker is publishing it's ports on `localhost`.\n \n| Server   | URL                               |\n| -------- | --------------------------------- |\n| API      | http://localhost:80/              |\n| Database | http://localhost:8080/phppgadmin/ |\n| Web GUI  | http://localhost:8000/src/        |\n\n\n## Links\nThe whole project: https://github.com/luckydonald/pbft\n\nThe Java node implementation: https://github.com/luckydonald/PBFT-JAVA\n\nDB Struktur (for debugging and powering the web gui): https://editor.ponyorm.com/user/luckydonald/pbft\n![pbft database structure](https://user-images.githubusercontent.com/2737108/33264396-a8310146-d36d-11e7-8ec9-8485d5d625b5.png)\n"
  },
  {
    "path": "api.Dockerfile",
    "content": "FROM tiangolo/uwsgi-nginx-flask:flask-python3.5\n\nRUN mkdir -p /app/code\nWORKDIR /app/\nCOPY ./code/api/requirements.txt /app/\nRUN pip install -r requirements.txt\nRUN rm requirements.txt\nCOPY ./code /app\nCOPY ./code/api/uwsgi.ini /app/uwsgi.ini\n"
  },
  {
    "path": "api.docker-compose.yml",
    "content": "version: '2'\nservices:\n  api:\n    build:\n      context: .\n      dockerfile: ./api.Dockerfile\n    restart: \"unless-stopped\"\n    environment:\n      POSTGRES_HOST: \"postgres\"  # service name\n      POSTGRES_USER: \"postgres\"\n      POSTGRES_PASS: \"1234secure\"\n      POSTGRES_DB: \"messages\"\n\n  postgres:\n    image: postgres\n    restart: \"unless-stopped\"\n    environment:\n      POSTGRES_USER: \"postgres\"\n      POSTGRES_PASSWORD: \"1234secure\"\n      POSTGRES_DB: \"messages\"\n\n  postgres_browser:\n    # image: jacksoncage/phppgadmin\n    build: ./extras/phppgadmin-docker\n    environment:\n      POSTGRES_HOST: \"postgres\"  # service name\n      POSTGRES_USER: \"postgres\"\n      POSTGRES_PASSWORD: \"1234secure\"\n      POSTGRES_DEFAULTDB: \"messages\"\n      # APACHE_SERVERNAME: \"postgres_browser\"\n      APACHE_SERVERNAME: \"localhost\""
  },
  {
    "path": "code/api/README.md",
    "content": "# The events\n\n\n| Type \\ Class    | Message | Init | Propose | Prevote | Vote | Ack |\n| --------------- | ------- | ---- | ------- | ------- | ---- | --- |\n| **Sequence**    | X | X | X | X | X | X |\n| **Node**        | X | X | X | X | X | X |\n| **Value**       | - | X | - | X | X | - | \n| **Leader**      | - | - | X | X | X | - | \n| **Value Store** | - | - | X | - | - | - | \n| **Sender**      | - | - | - | - | - | X | \n| **Raw**         | - | - | - | - | - | X | \n\n\n\n\n\n# `GET /get_value`\n\nReturns the latest value the nodes decided on,\nand the most recent measured value of each node.\nOnly considers events in the last 10 seconds.    \n\n##### Returns\nAn dictionary.\nWill have an entry for each node with its latest measured value.\nAlso contains a `\"summary\"` field, containing the last value they have agreed on, if any.\n\n##### Note\n If nothing happened in the last 10 seconds, that node / the summary will be missing. \n\n##### Example\n```curl\n$ curl http://$IP_OR_HOST/get_value/\n```\n```python\n{  # if no data is present, the field just does not exist.\n    \"1\": 0.5,\n    \"2\": 0.6,\n    \"5\": 0.5,\n    \"6\": 0.5,\n    \"7\": 0.5,\n    \"summary\": 0.5\n}\n```\n\n\n# `GET /api/v2/get_value/`\n\nSimilar to `/get_value/`, but     \n\n##### Returns\nAn dictionary.\nWill have an entry for each node with its latest measured value.\nAlso contains a `\"summary\"` field, containing the last value they have agreed on, if any.\n\n##### Note\n If nothing happened in the last 10 seconds, that node / the summary will be missing. \n\n##### Example\n```curl\n$ curl http://$IP_OR_HOST/api/v2/get_value/\n```\n```python\n{\n    \"summary\":  0.5,  # or null\n    \"leader\": 1, \n    \"nodes\": [\n        {\"node\": \"1\", \"value\": 0.5},\n        {\"node\": \"2\", \"value\": 0.6},\n        {\"node\": \"5\", \"value\": 0.5},\n        {\"node\": \"6\", \"value\": 0.5},\n        {\"node\": \"5\", \"value\": 0.5}\n    ]\n}\n```\n\n\n# `GET /get_data`\n\nReturns list of recent measurements,\n\n##### Optional parameters\n- `node`: the node you want to filter for. You can specify this argument multible times. Omit to receive all of them.\n- `limit`: will only get the specified count of measurements. \n   **Note**: This is the total count, not per node. So `limit=5` could mean 1 entry in _node 1_ and 4 measurement in _node 2_, depending of the time.\n\n\n##### Returns\nAn dictionary with nodes as keys and a subdictionary, with timestaps as keys for the measured values.\n\n\n##### Example\n```curl\n$ curl http://$IP_OR_HOST/get_data/\n```\n```python\n\n{\n    \"1\": {\n        \"123134\":  0.12,\n        # timestamp : value\n        \"123135\": 0.5\n    },\n    \"2\": {\n        \"123134\":  0.13,\n        # timestamp : value\n        \"123135\": 0.8\n    }\n    \"3\": {\n        \"123134\":  0.13,\n        # timestamp : value\n        \"123135\": 0.5\n    }\n}\n```\n\n##### Example 2\n\n```curl\n$ curl http://$IP_OR_HOST/get_data/?node=1&node=2\n```\n```python\n\n{\n    \"1\": {\n        \"123134\":  0.12,\n        # timestamp : value\n        \"123135\": 0.5\n    },\n    \"2\": {\n        \"123134\":  0.13,\n        # timestamp : value\n        \"123135\": 0.8\n    }\n}\n```\n\n# `PUT /dump`\n\nSent an json encoded `Message` into the database.\nThe json to be send is exactly the same as used internally between the nodes.\n"
  },
  {
    "path": "code/api/database.py",
    "content": "from datetime import datetime\nfrom pony import orm\nimport logging\n\nfrom node import messages\nfrom node.enums import UNSET, INIT, PROPOSE, PREVOTE, VOTE, ACKNOWLEDGE\nfrom .env import POSTGRES_HOST, POSTGRES_USER, POSTGRES_PASS, POSTGRES_DB\n\n__author__ = \"luckydonald\"\n\nlogger = logging.getLogger(__file__)\ndb = orm.Database()\n\nVALUE_TYPE = float\nMSG_TYPE_TYPE = int\nNODE_TYPE = int\nSEQUENCE_TYPE = int\n\n# https://editor.ponyorm.com/user/luckydonald/pbft\n# Last permalink:\n# https://editor.ponyorm.com/user/luckydonald/pbft_2\n\n\nclass DBMessage(db.Entity):\n    type = orm.Discriminator(MSG_TYPE_TYPE)\n    date = orm.Required(datetime, sql_default='CURRENT_TIMESTAMP')\n    sequence_no = orm.Required(SEQUENCE_TYPE)\n    node = orm.Optional(NODE_TYPE)\n    value = orm.Optional(VALUE_TYPE)\n    leader = orm.Optional(NODE_TYPE)\n    sender = orm.Optional(NODE_TYPE)\n    raw = orm.Optional(orm.Json)\n\n    _discriminator_ = UNSET\n\n    def from_db(self):\n        clazz = MSG_TYPE_CLASS_MAP[self.type]\n        assert issubclass(clazz, messages.Message)\n        return clazz.from_dict(self.as_dict())\n    # end def\n\n    @classmethod\n    def to_db(cls, msg):\n        return cls(**msg.to_dict())\n    # end def\n# end class\n\n\nclass DBInitMessage(DBMessage):\n    _discriminator_ = INIT\n\n    def from_db(self):\n        return messages.InitMessage(sequence_no=self.sequence_no, node=self.node, value=self.value)\n    # end def\n\n    @classmethod\n    def to_db(cls, msg):\n        assert isinstance(msg, messages.InitMessage)\n        return super().to_db(msg)\n    # end def\n# end class\n\n\nclass DBProposeMessage(DBMessage):\n    _discriminator_ = PROPOSE\n    proposal = orm.Required(VALUE_TYPE)\n    value_store = orm.Required(orm.Json)  # json\n\n    def from_db(self):\n        return messages.ProposeMessage(\n            sequence_no=self.sequence_no, node=self.node, leader=self.leader, proposal=self.proposal,\n            value_store=self.value_store\n        )\n    # end def\n\n    @classmethod\n    def to_db(cls, msg):\n        assert isinstance(msg, messages.ProposeMessage)\n        return super().to_db(msg)\n    # end def\n# end class\n\n\nclass DBPrevoteMessage(DBMessage):\n    _discriminator_ = PREVOTE\n\n    @classmethod\n    def to_db(cls, msg):\n        assert isinstance(msg, messages.PrevoteMessage)\n        return super().to_db(msg)\n    # end def\n\n    def from_db(self):\n        return messages.PrevoteMessage(sequence_no=self.sequence_no, node=self.node, leader=self.leader, value=self.value)\n    # end def\n# end class\n\n\nclass DBVoteMessage(DBMessage):\n    _discriminator_ = VOTE\n\n    @classmethod\n    def to_db(cls, msg):\n        assert isinstance(msg, messages.VoteMessage)\n        return super().to_db(msg)\n    # end def\n\n    def from_db(self):\n        return messages.VoteMessage(sequence_no=self.sequence_no, node=self.node, leader=self.leader, value=self.value)\n    # end def\n# end class\n\n\nclass DBAcknowledge(DBMessage):\n    _discriminator_ = ACKNOWLEDGE\n\n    @classmethod\n    def to_db(cls, msg):\n        assert isinstance(msg, messages.Acknowledge)\n        return super().to_db(msg)\n    # end def\n\n    def from_db(self):\n        return messages.Acknowledge(sequence_no=self.sequence_no, node=self.node, sender=self.sender, raw=self.raw)\n    # end def\n# end class\n\n\nMSG_TYPE_CLASS_MAP = {\n    INIT: DBInitMessage,\n    PROPOSE: DBProposeMessage,\n    PREVOTE: DBPrevoteMessage,\n    VOTE: DBVoteMessage,\n    # ...\n    ACKNOWLEDGE: DBAcknowledge,\n}\n\n\n@orm.db_session\ndef to_db(msg):\n    if msg is None:\n        return None\n    if isinstance(msg, dict):\n        # is still dict (json)\n        msg = messages.Message.from_dict(msg)  # make a Message subclass first.\n    assert isinstance(msg, messages.Message)\n    db_msg_clazz = MSG_TYPE_CLASS_MAP[msg.type]  # Key error = not implemented yet.\n    assert issubclass(db_msg_clazz, DBMessage)\n    db_msg = db_msg_clazz.to_db(msg)\n    assert db_msg.type == msg.type\n    return db_msg\n# end def\n\ndb.bind(\"postgres\", host=POSTGRES_HOST, user=POSTGRES_USER, password=POSTGRES_PASS, database=POSTGRES_DB)\ndb.generate_mapping(create_tables=True)"
  },
  {
    "path": "code/api/enums.py",
    "content": "# -*- coding: utf-8 -*-\nfrom luckydonaldUtils.logger import logging\nfrom node.enums import INIT, PROPOSE,PREVOTE, VOTE\n__author__ = 'luckydonald'\nlogger = logging.getLogger(__name__)\n\nJSON_TYPES = {\n    INIT: \"init\",\n    PROPOSE: \"propose\",\n    PREVOTE: \"prevote\",\n    VOTE: \"vote\",\n}"
  },
  {
    "path": "code/api/env.py",
    "content": "# -*- coding: utf-8 -*-\nimport os\n\nfrom luckydonaldUtils.logger import logging\n\n__author__ = 'luckydonald'\nlogger = logging.getLogger(__name__)\n\nPOSTGRES_HOST = os.environ.get(\"POSTGRES_HOST\", None)\nassert POSTGRES_HOST is not None\n\nPOSTGRES_USER = os.environ.get(\"POSTGRES_USER\", None)\nassert POSTGRES_USER is not None\n\nPOSTGRES_PASS = os.environ.get(\"POSTGRES_PASS\", None)\nassert POSTGRES_PASS is not None\n\nPOSTGRES_DB = os.environ.get(\"POSTGRES_DB\", None)\nassert POSTGRES_DB is not None\n\n\n"
  },
  {
    "path": "code/api/main.py",
    "content": "# -*- coding: utf-8 -*-\nfrom datetime import datetime\n\nfrom DictObject import DictObject\nfrom flask import Flask, request\nfrom luckydonaldUtils.logger import logging\nfrom pony import orm\n\nfrom .enums import JSON_TYPES\nfrom .utils import jsonify\nfrom .database import to_db, db, DBVoteMessage, DBMessage, DBInitMessage, DBPrevoteMessage, DBProposeMessage, DBAcknowledge, \\\n    MSG_TYPE_CLASS_MAP\nfrom node.enums import INIT  # noqa # pylint: disable=unused-import\nfrom node.messages import Message  # noqa # pylint: disable=unused-import\n\n__author__ = 'luckydonald'\nlogger = logging.getLogger(__name__)\n\nVERSION = \"0.0.1\"\n__version__ = VERSION\nassert INIT == INIT  # to prevent the unused import warning. Is used in SQL statement.\n\nfrom werkzeug.debug import DebuggedApplication\napp = Flask(__name__)\ndebug = DebuggedApplication(app, console_path=\"/console/\")\n\nAPI_V1 = \"\"\nAPI_V2 = \"/api/v2\"\n\n\n@app.route(API_V1+\"/dump\", methods=['POST', 'GET', 'PUT'])\n@app.route(API_V1+\"/dump/\", methods=['POST', 'GET', 'PUT'])\n@orm.db_session\ndef dump_to_db():\n    try:\n        logger.info(\"Incoming: {}\".format(request.get_json(force=True)))\n        msg = to_db(request.get_json(force=True))\n        if msg:\n            db.commit()\n            logger.info(\"Added {}: {id}\".format(msg, id=msg.id))\n            return \"ok: {}\".format(msg)\n        else:\n            return \"fail: None\"\n        # end if\n    except Exception as e:\n        logger.exception(\"lel\")\n        raise\n# end def\n\n\n@app.route(API_V1+\"/get_value\")\n@app.route(API_V1+\"/get_value/\")\n@orm.db_session\ndef get_value():\n    \"\"\"\n    Gets latest value they decided on, and the most recent measured value of each node.\n    Only considers events in the last 10 seconds.\n\n    > {\"summary\": 3.456, \"1\": 2.345, \"2\": 3.456, \"3\": 4.567, \"4\": 5.678}}\n\n    :return:\n    \"\"\"\n    latest_vote = orm.select(m for m in DBVoteMessage if m.date > orm.raw_sql(\"NOW() - '10 seconds'::INTERVAL\")).order_by(orm.desc(DBVoteMessage.date)).first()\n    if not latest_vote:\n        return jsonify({}, allow_all_origin=True)\n    # end if\n    assert isinstance(latest_vote, DBVoteMessage)\n    latest_values = DBMessage.select_by_sql(\"\"\"\n    SELECT DISTINCT ON (m.node) * FROM (\n      SELECT * FROM DBmessage\n      WHERE type = $INIT\n      AND date >= NOW() - '10 seconds'::INTERVAL\n    ) as m ORDER BY m.node, m.date DESC\n    \"\"\")\n    data = {\"summary\": latest_vote.value}\n    for msg in latest_values:\n        assert isinstance(msg, DBInitMessage)\n        data[str(msg.node)] = msg.value\n    # end for\n    return jsonify(data, allow_all_origin=True)\n# end def\n\n\n@app.route(API_V2+\"/get_value\")\n@app.route(API_V2+\"/get_value/\")\n@orm.db_session\ndef get_value_v2():\n    \"\"\"\n    Gets latest value they decided on, and the most recent measured value of each node.\n    Only considers events in the last 10 seconds.\n\n    {\n        \"summary\": None,\n        \"leader\": 1,  # done later via observing latest LeaderChange events.\n        \"nodes\": []\n    }\n\n    :return:\n    \"\"\"\n    latest_vote = orm.select(m for m in DBVoteMessage if m.date > orm.raw_sql(\"NOW() - '10 seconds'::INTERVAL\")).order_by(orm.desc(DBVoteMessage.date)).first()\n    latest_values = DBMessage.select_by_sql(\"\"\"\n    SELECT DISTINCT ON (m.node) * FROM (\n      SELECT * FROM DBmessage\n      WHERE type = $INIT\n      AND date >= NOW() - '10 seconds'::INTERVAL\n    ) as m ORDER BY m.node, m.date DESC\n    \"\"\")\n    data = {\n        \"summary\": None,\n        \"leader\": 1,  # done later via observing latest LeaderChange events.\n        \"nodes\": []\n    }\n    if latest_vote:\n        assert isinstance(latest_vote, DBVoteMessage)\n        data[\"summary\"] = {\"value\": latest_vote.value}\n    # end if\n\n    for msg in latest_values:\n        assert isinstance(msg, DBInitMessage)\n        data[\"nodes\"].append({\"node\": str(msg.node), \"value\": msg.value})\n    # end for\n    return jsonify(data, allow_all_origin=True)\n# end def\n\n\n@app.route(API_V2+\"/get_timeline\")\n@app.route(API_V2+\"/get_timeline/\")\n@orm.db_session\ndef get_timeline():\n    node_list = set()\n    event_list = list()\n    date_min = None\n    date_max = None\n    node_events = DBMessage.select_by_sql(\"\"\"\n      SELECT * FROM DBmessage WHERE date >= NOW() - '60 seconds'::INTERVAL\n    \"\"\")\n    for node_event in node_events:\n        event_dict = DictObject.objectify({\n             \"id\": {},  # for deduplication in the GUI\n             \"action\": None, # \"send\" or \"acknowledge\"\n             \"type\": None,\n             \"nodes\": {},\n             \"timestamps\": {},\n             \"data\": {}\n         })\n        node_list.add(node_event.node)  # update node list\n        if date_min is None or node_event.date < date_min:\n            date_min = node_event.date\n        # end if\n        if date_max is None or node_event.date > date_max:\n            date_max = node_event.date\n        # end if\n        if isinstance(node_event, DBAcknowledge):\n            received_msg = Message.from_dict(node_event.raw)\n            event_dict.id[\"receive\"] = node_event.id\n            event_dict.action = \"acknowledge\"\n            event_dict.nodes[\"send\"] = received_msg.node\n            event_dict.nodes[\"receive\"] = node_event.node\n            event_dict.timestamps[\"receive\"] = generate_date_data(node_event.date)\n            event_dict.type = JSON_TYPES[received_msg.type]\n            event_dict.data = generate_msg_data(received_msg)\n            node_list.add(received_msg.node)  # update node list\n            # additional DB query, to get sender\n            DBClazz = MSG_TYPE_CLASS_MAP[received_msg.type]\n            try:\n                db_received_msg = DBClazz.get(\n                    sequence_no=received_msg.sequence_no,\n                    node=received_msg.node\n                )\n                event_dict.id[\"send\"] = db_received_msg.id\n                event_dict.timestamps[\"send\"] = generate_date_data(db_received_msg.date)\n                if date_min is None or db_received_msg.date < date_min:\n                    date_min = node_event.date\n                # end if\n                if date_max is None or db_received_msg.date > date_max:\n                    date_max = node_event.date\n                # end if\n            except orm.DatabaseError:\n                event_dict.id[\"send\"] = None\n                event_dict.timestamps[\"send\"] = generate_date_data(None)\n            # end try\n        else:\n            event_dict.action = \"send\"\n            event_dict.id[\"send\"] = node_event.id\n            event_dict.nodes[\"send\"] = node_event.node\n            event_dict.timestamps[\"send\"] = generate_date_data(node_event.date)\n            event_dict.type = JSON_TYPES[node_event.type]\n            event_dict.data = generate_msg_data(node_event)\n        # end if\n        event_list.append(event_dict)\n    # end for\n    result = DictObject.objectify({\n        \"nodes\": node_list,\n        \"timestamps\": {\"min\": generate_date_data(date_min), \"max\": generate_date_data(date_max)},\n        \"events\": event_list,\n    })\n    return jsonify(result, allow_all_origin=True)\n# end def\n\n\ndef generate_date_data(datetime_obj):\n    if datetime_obj is None:\n        return {\"string\": \"unknown\", \"unix\": None}\n    # end if\n    assert isinstance(datetime_obj, datetime)\n    return {\"string\": datetime_obj, \"unix\": datetime_obj.timestamp()}\n# end def\n\n\ndef generate_msg_data(msg):\n    if isinstance(msg, DBMessage):\n        msg = msg.from_db()\n    assert isinstance(msg, Message)\n    msg = msg.to_dict()\n    return msg\n# end def\n\n\n@app.route(API_V1+\"/get_data\")\n@app.route(API_V1+\"/get_data/\")\n@orm.db_session\ndef get_data():\n    node = request.args.getlist('node', None)\n    limit = request.args.get('limit', 100)\n    assert isinstance(limit, int) or str.isnumeric(limit)   # TODO: specify error message, on error  # like int(\"abc\")\n    limit = int(limit)\n    if node:\n        for i in node:\n            assert str.isnumeric(i)  # TODO: specify error message\n        # end for\n        node_values = orm.select(m for m in DBInitMessage if m.node in list(node)).order_by(orm.desc(DBInitMessage.date)).limit(limit)\n    else:\n        node_values = orm.select(m for m in DBInitMessage).order_by(orm.desc(DBInitMessage.date)).limit(limit)\n    if not node_values:\n        return jsonify({}, allow_all_origin=True)\n    # end if\n    data = {}\n    for msg in node_values:\n        assert isinstance(msg, DBInitMessage)\n        assert isinstance(msg.date, datetime)\n        if str(msg.node) not in data:\n            data[str(msg.node)] = dict()\n        # end if\n        data[str(msg.node)][msg.date.timestamp()] = msg.value\n    # end for\n    return jsonify(data, allow_all_origin=True)\n# end def\n\n\n@app.route(API_V1+\"/test\")\n@app.route(API_V1+\"/test/\")\n@orm.db_session\ndef test():\n    node = request.args.getlist('node', None)\n    if request.environ.get('HTTP_ORIGIN', None) is not None:\n        logger.warning(\"HTTP_ORIGIN: {!r}\".format(request.environ['HTTP_ORIGIN']))\n        # res.headers[\"Access-Control-Allow-Origin\"] = request.environ['HTTP_ORIGIN']\n    # end if\n    return str(request.environ.get('HTTP_ORIGIN', None))\n# end def\n\n\n@app.route(\"/console/\")\ndef console():\n    return debug.display_console(request)\n# end def\n\n\n@app.route(\"/\")\ndef root():\n    return \"Ready to take your requests.\"\n# end def\n"
  },
  {
    "path": "code/api/requirements.txt",
    "content": "luckydonald-utils==0.51\ndocker-py\n\nflask  # api\npony  # db\npsycopg2cffi  # db"
  },
  {
    "path": "code/api/timeline.json",
    "content": "{\n    \"nodes\": [\"1\", \"2\", \"3\", \"4\"],\n    \"timestamps\": {\"min\": \"23428001\", \"max\": \"23428013\"},\n    \"events\": [\n        {\n            \"id\": {\"send\": 1},\n            \"action\": \"send\",\n            \"type\": \"init\",\n            \"nodes\": {\"send\": \"1\"},\n            \"timestamps\": {\"send\": \"23428001\"},\n            \"data\": {\"value\": \"0.5\"}\n        },\n        {\n            \"id\": {\"send\": 1, \"receive\": 2},\n            \"action\": \"acknowledge\",\n            \"type\": \"init\",\n            \"nodes\": {\"send\": \"1\", \"receive\": \"2\"},\n            \"timestamps\": {\"send\": \"23428001\", \"receive\": \"23428011\"},\n            \"data\": {\"value\": \"0.5\"}\n\n        },\n        {\n            \"id\": {\"send\": null, \"receive\": 3},\n            \"action\": \"acknowledge\",\n            \"type\": \"init\",\n            \"nodes\": {\"send\": \"1\", \"receive\": \"3\"},\n            \"timestamps\": {\"send\": null, \"receive\": \"23428013\"},\n            \"data\": {\"value\": \"0.5\"}\n        },\n        {\n            \"id\": {\"send\": 1, \"receive\": 4},\n            \"action\": \"acknowledge\",\n            \"type\": \"init\",\n            \"nodes\": {\"send\": \"1\", \"receive\": \"3\"},\n            \"timestamps\": {\"send\": \"23428001\", \"receive\": \"23428013\"},\n            \"data\": {\"value\": \"0.5\"}\n        }\n\n    ]\n}\n\n"
  },
  {
    "path": "code/api/utils.py",
    "content": "# -*- coding: utf-8 -*-\nfrom flask import request\nfrom luckydonaldUtils.logger import logging\n\n__author__ = 'luckydonald'\nlogger = logging.getLogger(__name__)\n\nORIGIN_LIST = [\"http://localhost\"]\n\n\ndef jsonify(data, allow_all_origin=False):\n    from flask import Response, jsonify as json_ify\n    res = json_ify(data)\n    assert isinstance(res, Response)\n    origin = request.environ.get('HTTP_ORIGIN')\n    if not origin:\n        origin = request.environ.get('ORIGIN')\n    # end if\n    if allow_all_origin:\n        res.headers[\"Access-Control-Allow-Origin\"] = '*'\n    elif origin and origin in ORIGIN_LIST:\n        res.headers[\"Access-Control-Allow-Origin\"] = origin\n    # end if\n    return res\n# end def\n"
  },
  {
    "path": "code/api/uwsgi.ini",
    "content": "[uwsgi]\nmodule = main_api\ncallable = app"
  },
  {
    "path": "code/main_api.py",
    "content": "# -*- coding: utf-8 -*-\nfrom luckydonaldUtils.logger import logging, LevelByNameFilter\n\n__author__ = 'luckydonald'\nlogger = logging.getLogger(__name__)\n\nfrom api import main\n\napp = main.app\n\nprint(\"## LOADED ##\")\ndef setup_logging():\n    filter = LevelByNameFilter(logging.WARNING, debug=\"api.main, node.messages\", info=\"node, api\")\n    logging.add_colored_handler(level=logging.DEBUG, date_formatter=\"%Y-%m-%d %H:%M:%S\", filter=filter)\n    logging.test_logger_levels()\n# end def\n\nsetup_logging()\n\nif __name__ == \"__main__\":\n    # no nginx, else the __name__ would be \"api\" (because api.py)\n    app.run(host='0.0.0.0', debug=True, port=80)\n# end if\n\n"
  },
  {
    "path": "code/main_node.py",
    "content": "# -*- coding: utf-8 -*-\nfrom luckydonaldUtils.logger import logging\n\nfrom node.main import setup_logging, main\n\n__author__ = 'luckydonald'\nlogger = logging.getLogger(__name__)\n\n\nif __name__ == '__main__':  # if this is the executed file\n    setup_logging()\n    main()\n# end if main()\n"
  },
  {
    "path": "code/node/__init__.py",
    "content": ""
  },
  {
    "path": "code/node/algo.py",
    "content": "# -*- coding: utf-8 -*-\n\n# built in modules\nimport sys\nfrom datetime import timedelta\nfrom statistics import median\n\n# dependency modules\nfrom luckydonaldUtils.functions import cached, gone\nfrom luckydonaldUtils.logger import logging\n\n# own modules\nfrom .message_queue import MessageQueueReceiver\nfrom .networks.sender import send_message\nfrom .functions import flatten_list\nfrom .messages import InitMessage, LeaderChangeMessage, ProposeMessage, PrevoteMessage, VoteMessage\nfrom .env import DEBUGGER\nfrom . import todo\n\n__author__ = 'luckydonald'\nlogger = logging.getLogger(__name__)\n\nif DEBUGGER:\n    sys.path.append(\"libs/pycharm-debug-py3k.egg\")\n    try:\n        import pydevd\n    except ImportError:\n        sys.path.remove(\"libs/pycharm-debug-py3k.egg\")\n        logger.warning(\"Debug disabled.\")\n    # end def\n    try:\n        pydevd.settrace('192.168.188.20', port=49872, stdoutToServer=True, stderrToServer=True, suspend=False)\n        logger.success(\"Debugger connected.\")\n    except Exception:\n        logger.warning(\"No debugger.\")\n    # end try\nelse:\n    logger.debug(\"Debugger disabled via $NODE_DEBUGGER.\")\n# end if\n\n# init\n# sensor_value = 0.4 # vp\n# self.node_number = 0  # p\n# TOTAL_NODES = 4 # n\n# POSSIBLE_FAILURES = 1 # t\n# value_store = {}  # INIT_Store\n# current_leader = 0 # o\n# sequence_no = None # cid\n# P = {}\n# LC = {}  # leader change\n\n\n# MAIN FILE IS main_node.py IN THE /code DIRECTORY!\n\n\nclass BFT_ARM():\n    sequence_no = None\n    should_timeout = False\n\n    def __init__(self, sequence_number=None, receiver=None):\n        \"\"\"\n        Starts a new sequence.\n        You can provide a sequence number to use as `sequence_number`\n        and a (started) MessageQueueReceiver `receiver`, too.\n\n        :param sequence_number: the sequence number to use. Is stored as `self.sequence_no`\n        :param receiver: Reuse a existing :class:`MessageQueueReceiver`,\n                         allowing to keep the messages, and minimizing the socket port problems\n\n        \"\"\"\n        self.value_store = {}  # INIT_Store\n        self.current_leader = 1  # ø\n        if receiver:\n            assert isinstance(receiver, MessageQueueReceiver)\n            self.rec = receiver\n        else:\n            self.rec = MessageQueueReceiver()\n            self.rec.start()\n        # end if\n        self.sequence_no = sequence_number\n    # end def\n\n    def MsgCollect(self):\n        received_message = self.get_specific_message_type(InitMessage, LeaderChangeMessage)\n        if isinstance(received_message, InitMessage):\n            self.value_store[received_message.node] = received_message\n        elif isinstance(received_message, LeaderChangeMessage):\n            # TODO: LC <- LC u {received_message}\n            logger.warning(\"not implemented.\")\n            pass\n        if todo.timeout():\n            # BFT_ARM.task_leader_change()\n            # todo.timeout.reset()\n            pass\n            # end if\n    # end def\n\n    def task_normal_case(self):\n        value = todo.get_sensor_value()  # vp\n        logger.critical(\"Step 0 INIT>\")\n        send_message(InitMessage(self.sequence_no, self.node_number, value))\n        logger.info(\"I'm node [{self!r}], [{leader!r}] is leader, {filler}.\".format(\n            leader=self.current_leader, self=self.node_number,\n            filler=\"it's a me\" if self.node_number == self.current_leader else \"not me\"\n        ))\n        if self.node_number == self.current_leader:\n            logger.critical(\"Step 1.0 (leader)\")\n            # CURRENT LEADER\n            # self.new_sequence()\n            while not (len(self.value_store) >= (self.nodes_total - self.nodes_faulty)):\n                # wait until |INIT_Store| > n - t\n                logger.success(\"INITs: {} > {}\".format(len(self.value_store), (self.nodes_total - self.nodes_faulty)))\n                init_msg = self.rec.init_queue.get_message(sequence_number=self.sequence_no)\n                assert isinstance(init_msg, InitMessage)\n                self.value_store[init_msg.node] = init_msg\n            # end\n            proposal = median([x.value for x in self.value_store.values()])\n            send_message(ProposeMessage(\n                self.sequence_no, self.node_number, self.current_leader, proposal, list(self.value_store.values())\n            ))\n            logger.critical(\"Step 1.1 PROPOSAL>\")\n        # end if\n        logger.critical(\"Step 2.0 >PROPOSAL\")\n        prop_message = self.rec.propose_queue.get_message(sequence_number=self.sequence_no)\n        assert isinstance(prop_message, ProposeMessage)\n        if self.verify_proposal(prop_message):\n            send_message(PrevoteMessage(self.sequence_no, self.node_number, self.current_leader, value))\n            logger.critical(\"Step 2.1 PROPOSAL>\")\n        # if exist v:|<PREVOTE,cid,·,„,vÍ‡·|>(n+t)\n\n        # hier auch, weil timeout uns notfalls rettet.\n        prevote_buffer = dict()  # dict with P inside\n        vote_buffer = dict()  # just decide\n        logger.critical(\"Step 3.0 >(PRE)VOTE\")\n        while not self.should_timeout:\n            if self.rec.prevote_queue.has_message():\n                logger.critical(\"Step 3.A >PREVOTE\")\n                msg = self.rec.prevote_queue.get_message(sequence_number=self.sequence_no)\n                value, is_enough = self.buffer_incomming(msg, prevote_buffer)\n                if is_enough:\n                    send_message(VoteMessage(self.sequence_no, self.node_number, self.current_leader, value))\n                    logger.critical(\"Step 3.A VOTE>\")\n                    # end def\n            elif self.rec.vote_queue.has_message():\n                msg = self.rec.vote_queue.get_message(sequence_number=self.sequence_no)\n                logger.critical(\"Step 3.B >VOTE\")\n                value, is_enough = self.buffer_incomming(msg, vote_buffer)\n                if is_enough:\n                    logger.critical(\"Step 4 (commit {value})\".format(value=value))\n                    return value\n                # end if\n            # end if\n        # end while\n        logger.warning(\"Hit end unexpectedly.\")\n    # end def run\n\n    def stop(self):\n        logger.info(\"Requested to stop.\")\n        self.should_timeout = True\n        assert isinstance(self.rec, MessageQueueReceiver)\n        self.rec.stop()\n        self.rec = None\n    # end def\n\n    def new_sequence(self):\n        if self.sequence_no is None:\n            self.sequence_no = 0\n        else:\n            self.sequence_no = (self.sequence_no + 1) % 256\n        # end if\n        logger.info(\"Sequence: {i}\".format(i=self.sequence_no))\n        return self.sequence_no\n    # end def\n\n    def buffer_incomming(self, msg, buffer):\n        if not msg.value in buffer:\n            buffer[msg.value] = list()\n        # end if\n        assert isinstance(buffer[msg.value], list)\n        buffer[msg.value].append(msg)\n        return msg.value, len(buffer[msg.value]) > (self.nodes_total + self.nodes_faulty) / 2\n    # end def\n\n    def verify_proposal(self, msg):\n        \"\"\"\n        Überprüfe ob proposal vom leader ist und\n        Rechnen nach, das die von msg empfangenen InitMessages den von ihm berechneten Wert (proposal) ergeben.\n        :param msg:\n        :return:\n        \"\"\"\n        # TODO: optimieren, indem man leader abfrage nach oben schiebt?\n        # if not msg.leader == self.current_leader:\n        #     return False\n        values = list()\n        known_nodes = list()\n\n        if not isinstance(msg, ProposeMessage):\n            raise AttributeError(\"msg is not ProposeMessage type, but {type}:\\n{val}\".format(type=type(msg), val=msg))\n        for init_msg in msg.value_store:\n            assert isinstance(init_msg, InitMessage)  # right message type\n            assert init_msg.node not in known_nodes  # no duplicates\n            values.append(init_msg.value)  # store the value\n            known_nodes.append(init_msg.node)  # remember this node\n        # end for\n        return msg.leader == self.current_leader and median(values) == msg.proposal\n    # end def\n\n    @gone  # TODO: get_specific_message_type function not needed anymore\n    def get_specific_message_type(self, *classes_or_types, sequence_number=None):  # TODO Remove this def\n        msg = None\n        classes_or_types = flatten_list(classes_or_types)\n        classes_or_types = tuple(classes_or_types)\n\n        while True:  # todo: something better\n            msg = self.rec.pop_message()\n            if isinstance(msg, classes_or_types):\n                logger.success(\"Got Message: {}\".format(msg))\n                if sequence_number is not None and msg.sequence_no != sequence_number:\n                    logger.warning(\"Discarded Message (wrong sequence number): {}\".format(msg))\n                    msg = None\n                else:\n                    break\n                # end if\n            else:\n                logger.warning(\"Discarded Message (wrong type): {}\".format(msg))\n                msg = None\n            # end if\n        # end while\n        return msg\n    # end def\n\n    @property\n    @cached(max_age=timedelta(seconds=60))\n    def nodes_total(self):\n        from .dockerus import ServiceInfos\n        return len(ServiceInfos().other_numbers(exclude_self=False))\n    # end def\n\n    @property\n    @cached(max_age=timedelta(seconds=60))\n    def nodes_faulty(self):\n        return (self.nodes_total - 1)/3\n    # end def\n\n    @property\n    def node_number(self):\n        from .dockerus import ServiceInfos\n        return ServiceInfos().number\n    # end def\n\n    def get_receiver(self):\n        return self.rec\n    # end def\n# end class\n"
  },
  {
    "path": "code/node/dockerus.py",
    "content": "# -*- coding: utf-8 -*-\n\nfrom DictObject import DictObject\nfrom luckydonaldUtils.logger import logging\nfrom luckydonaldUtils.functions import cached\nfrom luckydonaldUtils.clazzes import Singleton\nfrom docker import Client\nfrom datetime import timedelta\n\n__author__ = 'luckydonald'\n\nlogger = logging.getLogger(__name__)\n\n\nclass ServiceInfos(object, metaclass=Singleton):\n    \"\"\"\n    Infos about a `docker-compose scale` group.\n    \"\"\"\n    __author__ = 'luckydonald'\n    LABEL_COMPOSE_CONTAINER_NUMBER = 'com.docker.compose.container-number'\n    LABEL_COMPOSE_PROJECT = 'com.docker.compose.project'\n    LABEL_COMPOSE_SERVICE = 'com.docker.compose.service'\n    CACHING_TIME = timedelta(seconds=5)\n\n    def __init__(self, caching_time=None):\n        \"\"\"\n        Infos about a `docker-compose scale` group.\n\n        If caching_time is not specified, the $DOCKER_CACHING_TIME environment variable will be used.\n        If that is empty, too, it will fallback to the default CACHING_TIME of 5 seconds.\n\n        :param caching_time: must be a datetime.timedelta object\n        \"\"\"\n        if caching_time:\n            assert isinstance(caching_time, timedelta)\n            self.CACHING_TIME = caching_time\n        else:\n            import os\n            timedelta(seconds=float(os.environ.get(\"DOCKER_CACHING_TIME\", ServiceInfos.CACHING_TIME.total_seconds())))\n        # end if\n    # end def\n\n    @property\n    @cached\n    def cli(self):\n        return Client(base_url='unix://var/run/docker.sock')\n    # end def\n\n    @property\n    @cached(max_age=max(timedelta(hours=1), CACHING_TIME))\n    def hostname_env(self):\n        import os\n        return os.environ.get(\"HOSTNAME\")\n    # end def\n\n    @property\n    @cached(max_age=CACHING_TIME)\n    def me(self):\n        return [DictObject.objectify(c) for c in self.cli.containers() if c['Id'][:12] == self.hostname_env[:12]][0]\n    # end def\n\n    @property\n    @cached(max_age=CACHING_TIME)\n    def id(self):\n        return self.me.Id\n    # end def\n\n    @property\n    @cached(max_age=CACHING_TIME)\n    def service(self):\n        return self.me.Labels[self.LABEL_COMPOSE_SERVICE]\n    # end def\n\n    @property\n    @cached(max_age=CACHING_TIME)\n    def name(self):\n        return self.service\n    # end def\n\n    @property\n    @cached(max_age=CACHING_TIME)\n    def project(self):\n        return self.me.Labels[self.LABEL_COMPOSE_PROJECT]\n    # end def\n\n    @property\n    @cached(max_age=CACHING_TIME)\n    def number(self):\n        return int(self.me.Labels[self.LABEL_COMPOSE_CONTAINER_NUMBER])\n    # end def\n\n    @cached(max_age=CACHING_TIME)\n    def containers(self, exclude_self=False):\n        \"\"\"\n        Gets metadata for all containers in this scale grouping.\n\n        :return:\n        \"\"\"\n        filters = [\n            '{0}={1}'.format(self.LABEL_COMPOSE_PROJECT, self.project),\n            '{0}={1}'.format(self.LABEL_COMPOSE_SERVICE, self.service),\n            # '{0}={1}'.format(LABEL_ONE_OFF, \"True\" if one_off else \"False\")\n        ]\n        return DictObject.objectify([\n            c for c in self.cli.containers(filters={'label': filters})\n            if not (exclude_self and c['Id'][:12] == self.hostname_env[:12])\n        ])\n    # end def\n\n    @property\n    @cached(max_age=CACHING_TIME)\n    def hostname(self):\n        c = self.me\n        return \"{project}_{service}_{i}\".format(\n                project=c.Labels[self.LABEL_COMPOSE_PROJECT],\n                service=c.Labels[self.LABEL_COMPOSE_SERVICE],\n                i=c.Labels[self.LABEL_COMPOSE_CONTAINER_NUMBER]\n        )\n    # end def\n\n    @cached(max_age=CACHING_TIME)\n    def other_hostnames(self, exclude_self=False):\n        return [\n            \"{project}_{service}_{i}\".format(\n                project=c.Labels[self.LABEL_COMPOSE_PROJECT],\n                service=c.Labels[self.LABEL_COMPOSE_SERVICE],\n                i=c.Labels[self.LABEL_COMPOSE_CONTAINER_NUMBER]\n            ) for c in self.containers(exclude_self=exclude_self)\n\n        ]\n    # end def\n\n    @cached(max_age=CACHING_TIME)\n    def other_numbers(self, exclude_self=False):\n        \"\"\"\n        :param exclude_self:\n        :return:\n        \"\"\"\n        return [\n            c.Labels[self.LABEL_COMPOSE_CONTAINER_NUMBER]\n            for c in self.containers(exclude_self=exclude_self)\n        ]\n    # end def\n# end class\n"
  },
  {
    "path": "code/node/enums.py",
    "content": "# -*- coding: utf-8 -*-\nfrom luckydonaldUtils.logger import logging\n\n__author__ = 'luckydonald'\nlogger = logging.getLogger(__name__)\n\n__all__ = [\"UNSET\", \"INIT\", \"PROPOSE\", \"PREVOTE\", \"VOTE\", \"LEADER_CHANGE\", \"ACKNOWLEDGE\", \"all\"]\n\nUNSET = 0\nINIT = 1\nPROPOSE = 2\nPREVOTE = 3\nVOTE = 4\nLEADER_CHANGE = 5\n\nACKNOWLEDGE = -1\n\nall = [UNSET, INIT, PROPOSE, PREVOTE, VOTE, LEADER_CHANGE, ACKNOWLEDGE]\n"
  },
  {
    "path": "code/node/env.py",
    "content": "# -*- coding: utf-8 -*-\nimport os\nfrom datetime import timedelta\n\nfrom luckydonaldUtils.logger import logging\n\n__author__ = 'luckydonald'\n__all__ = [\"NODE_PORT\", \"NODES_CACHING_TIME\", \"DEBUGGER\"]\n\nlogger = logging.getLogger(__name__)\n\n\nNODE_PORT = int(os.environ.get(\"NODE_PORT\", None))\n\n\n# DOCKER_CACHING_TIME in seconds\ndocker_caching_time_seconds = os.environ.get(\"DOCKER_CACHING_TIME\", None)\nif docker_caching_time_seconds is None:\n    DOCKER_CACHING_TIME = None\nelse:\n    DOCKER_CACHING_TIME = timedelta(seconds=float(docker_caching_time_seconds))\n# end if\n\n\nDEBUGGER = os.environ.get(\"NODE_DEBUGGER\", \"\")\nif DEBUGGER.lower() in [\"true\", \"yes\", \"1\"]:\n    DEBUGGER = True\nelse:\n    DEBUGGER = False\n# end if\n\nDATABASE_URL = \"http://api/dump/\"\n"
  },
  {
    "path": "code/node/functions.py",
    "content": "# -*- coding: utf-8 -*-\nfrom luckydonaldUtils.logger import logging\n\n__author__ = 'luckydonald'\nlogger = logging.getLogger(__name__)\n\n\ndef flatten_list(args):\n    if isinstance(args, tuple):\n        args = list(args)\n    elif not isinstance(args, list):\n        args = [args]\n    # end if\n    assert isinstance(args, list)\n    new_args = []\n    for arg in args:\n        if isinstance(arg, (list,tuple)):\n            new_args.extend(arg)\n        else:\n            new_args.append(arg)\n    # end if\n    return new_args\n# end def"
  },
  {
    "path": "code/node/main.py",
    "content": "# -*- coding: utf-8 -*-\nfrom time import sleep\n\nfrom luckydonaldUtils.logger import logging, LevelByNameFilter\n\nfrom .algo import BFT_ARM\n\n__author__ = 'luckydonald'\nlogger = logging.getLogger(__name__)\n\n\ndo_quit = False\n\n\ndef main():\n    algo = BFT_ARM()\n    sequence = algo.new_sequence()\n    receiver = algo.get_receiver()\n    setup_cleanup(algo)\n\n    logger.info(\"Sleeping 2 seconds to give other nodes the time to get the receiver ready.\")\n    sleep(2)\n\n    while not do_quit:\n        logger.debug(\"Starting new Round.\")\n        algo = BFT_ARM(sequence_number=sequence, receiver=receiver)\n        sequence = algo.new_sequence()\n        algo.task_normal_case()\n    # end while\n    logger.info(\"Exiting.\")\n# end def\n\n\ndef setup_cleanup(algo):\n    import signal\n    import sys\n    assert isinstance(algo, BFT_ARM)\n\n    def signal_handler(signal, frame):\n        print('You pressed Ctrl+C!')\n        global do_quit\n        do_quit = True\n        assert isinstance(algo, BFT_ARM)\n        algo.stop()\n        sys.exit(0)\n    # end def\n    signal.signal(signal.SIGINT, signal_handler)\n# end def\n\n\ndef setup_logging():\n    filter = LevelByNameFilter(logging.WARNING, debug=\"node.main, node.todo, node.messages\", info=\"node\")\n    logging.add_colored_handler(level=logging.DEBUG, date_formatter=\"%Y-%m-%d %H:%M:%S\", filter=filter)\n    logging.test_logger_levels()\n# end def\n"
  },
  {
    "path": "code/node/message_queue.py",
    "content": "# -*- coding: utf-8 -*-\nimport threading\nfrom collections import deque\n\nfrom DictObject import DictObject\nimport json\nfrom luckydonaldUtils.logger import logging\n\nfrom .messages import Message, InitMessage, ProposeMessage, PrevoteMessage, VoteMessage\nfrom .networks.receiver import Receiver\n\n__author__ = 'luckydonald'\nlogger = logging.getLogger(__name__)\n\n\nclass LockedQueue(object):\n    def __init__(self, clazz):\n        assert issubclass(clazz, Message)\n        self._clazz = clazz\n        self._queue = deque()\n        self._new_messages = threading.Semaphore(0)\n        self._queue_access = threading.Lock()\n\n    def pop_message(self):\n        \"\"\"\n        Get a message.\n        :return:\n        \"\"\"\n        logger.debug(\"Called pop_message on {type}.\".format(type=self._clazz))\n        self._new_messages.acquire()  # waits until at least 1 message is in the queue.\n        with self._queue_access:\n            message = self._queue.popleft()  # pop oldest item\n            logger.debug('Messages waiting in queue: %d', len(self._queue))\n            if not isinstance(message, self._clazz):\n                raise TypeError(\"Popped message is not type {_clazz} but type {type}:\\n{msg}\".format(\n                    _clazz=self._clazz, type=type(message), msg=message\n                ))\n            # end if\n            assert isinstance(message, Message)\n            assert isinstance(message, self._clazz)\n            return message\n        # end with\n    # end def\n\n    def get_message(self, sequence_number=None):\n        if sequence_number is None:  # no check needed:\n            return self.pop_message()\n        # end if\n        msg = None\n        while msg is None:\n            msg = self.pop_message()\n            if msg.sequence_no != sequence_number:\n                logger.warning(\"Discarded Message, wrong sequence number ({a} instead of {b}): {msg}\".format(\n                    a=msg.sequence_no, b=sequence_number, msg=msg\n                ))\n                msg = None\n            # end if\n        # end while\n        assert isinstance(msg, Message)\n        assert isinstance(msg, self._clazz)\n        return msg\n    # end def\n\n    def append_message(self, message):\n        if not isinstance(message, self._clazz):\n            raise TypeError(\"Given message is not type {_clazz} but type {type}:\\n{msg}\".format(\n                _clazz=self._clazz, type=type(message), msg=message\n            ))\n        # end if\n        with self._queue_access:\n            self._queue.append(message)\n        # end if\n        self._new_messages.release()\n    # end def\n\n    def queue_length(self):\n        with self._queue_access:\n            return len(self._queue)\n        # end with\n    # end def\n\n    __len__ = queue_length\n\n    def has_message(self):\n        with self._queue_access:\n            return len(self._queue) > 0\n        # end with\n    # end def\n# end class\n\n\nclass MessageQueueReceiver(Receiver):\n    init_queue = LockedQueue(InitMessage)\n    propose_queue = LockedQueue(ProposeMessage)\n    prevote_queue = LockedQueue(PrevoteMessage)\n    vote_queue = LockedQueue(VoteMessage)\n\n    pop_message = None  # the function\n\n    def _add_message(self, text):\n        \"\"\"\n        Appends a message to the message queue.\n\n        :type text: builtins.str\n        :return:\n        \"\"\"\n        try:\n            logger.debug(\"Received Message: \\\"{str}\\\"\".format(str=text))\n            json_dict = json.loads(text)\n            message = DictObject.objectify(json_dict)\n            message = self.parse_message(message)\n        except ValueError as e:\n            logger.warn(\"Received message could not be parsed.\\nMessage:>{}<\".format(text), exc_info=True)\n            return\n        if isinstance(message, InitMessage):\n            self.init_queue.append_message(message)\n        elif isinstance(message, ProposeMessage):\n            self.propose_queue.append_message(message)\n        elif isinstance(message, PrevoteMessage):\n            self.prevote_queue.append_message(message)\n        elif isinstance(message, VoteMessage):\n            self.vote_queue.append_message(message)\n        else:\n            logger.warning(\"Discarded unknown message type: {msg_type}, {msg}\".format(\n                msg_type=type(message), msg=message\n            ))\n        # end if\n    # end def\n# end class\n"
  },
  {
    "path": "code/node/messages.py",
    "content": "# -*- coding: utf-8 -*-\nfrom luckydonaldUtils.logger import logging\n\nfrom .enums import UNSET, INIT, LEADER_CHANGE, PROPOSE, PREVOTE, VOTE, ACKNOWLEDGE\n\n__author__ = 'luckydonald'\nlogger = logging.getLogger(__name__)\n\n\nclass Message(object):\n    def __init__(self, type, sequence_no, node):\n        if type is None:\n            type = UNSET\n        # end if\n        assert isinstance(type, int)\n        self.type = type\n        self.sequence_no = sequence_no\n        self.node = node  # i\n\n\n    @classmethod\n    def from_dict(cls, data):\n        assert \"type\" in data\n        type = data[\"type\"]\n        assert type in [UNSET, INIT, LEADER_CHANGE, PROPOSE, PREVOTE, VOTE, ACKNOWLEDGE]\n        if type == INIT:\n            return InitMessage.from_dict(data)\n        # end def\n        if type == LEADER_CHANGE: # pragma: no cover\n            return LeaderChangeMessage.from_dict(data)\n        # end def\n        if type == PROPOSE:\n            return ProposeMessage.from_dict(data)\n        # end def\n        if type == PREVOTE:\n            return PrevoteMessage.from_dict(data)\n        # end def\n        if type == VOTE:\n            return VoteMessage.from_dict(data)\n        # end def\n        if type == ACKNOWLEDGE:\n            return Acknowledge.from_dict(data)\n        # end def\n        return cls(**{\n            \"type\": data[\"type\"],\n            \"sequence_no\": data[\"sequence_no\"],\n            \"node\": data[\"node\"]\n        })\n    # end def\n\n    def to_dict(self):\n        return {\n            \"type\": self.type,\n            \"sequence_no\": self.sequence_no,\n            \"node\": self.node\n        }\n    # end def\n\n    def __str__(self):\n        data = self.to_dict()\n        return \"{class_name}({values})\".format(\n            class_name=self.__class__.__name__,\n            values=\", \".join([\"{key}={value!r}\".format(key=k, value=data[k]) for k in sorted(data)])\n        )\n# end class\n\n\nclass InitMessage(Message):\n    def __init__(self, sequence_no, node, value):\n        super(InitMessage, self).__init__(INIT, sequence_no, node)\n        self.value = value  # vi\n    # end def\n\n    @classmethod\n    def from_dict(cls, data):\n        kwargs = {\n            \"sequence_no\": data[\"sequence_no\"],\n            \"node\": data[\"node\"],\n            \"value\": data[\"value\"],\n        }\n        return cls(**kwargs)\n    # end def\n\n    def to_dict(self):\n        data = super().to_dict()\n        data[\"value\"] = self.value\n        return data\n    # end def\n# end class\n\n\nclass LeaderChangeMessage(Message):  # pragma: no cover\n    def __init__(self, sequence_no, node_num, leader, P):\n        raise NotImplementedError(\"LeaderChangeMessage\")\n        super(LeaderChangeMessage, self).__init__(LEADER_CHANGE, sequence_no)\n    # end def\n\n    @classmethod\n    def from_dict(cls, data):\n        raise NotImplementedError(\"LeaderChangeMessage\")\n        kwargs = {\n            \"type\": data[\"type\"],\n            \"sequence_no\": data[\"sequence_no\"],\n        }\n        return cls(**kwargs)\n    # end def\n\n    def to_dict(self):\n        raise NotImplementedError(\"LeaderChangeMessage\")\n        return {\n            \"type\": self.type,\n            \"sequence_no\": self.sequence_no,\n        }\n    # end def\n# end class\n\n\nclass ProposeMessage(Message):\n    def __init__(self, sequence_no, node, leader, proposal, value_store):\n        super(ProposeMessage, self).__init__(PROPOSE, sequence_no, node)\n        self.leader = leader\n        self.proposal = proposal\n        assert isinstance(value_store, list)\n        self.value_store = value_store\n\n    @classmethod\n    def from_dict(cls, data):\n        value_store = []\n        for v in data.get(\"value_store\", []):\n            msg = InitMessage.from_dict(v)\n            # value_store[msg.node] = msg\n            value_store.append(msg)\n        # end for\n        kwargs = {\n            \"sequence_no\": data[\"sequence_no\"],\n            \"node\": data.get(\"node\"),\n            \"leader\": data.get(\"leader\"),\n            \"proposal\": data.get(\"proposal\"),\n            \"value_store\": value_store\n        }\n        return cls(**kwargs)\n    # end def\n\n    def to_dict(self):\n        data = super().to_dict()\n        data[\"leader\"] = self.leader\n        data[\"proposal\"] = self.proposal\n        data[\"value_store\"] = [x.to_dict() if hasattr(x, \"to_dict\") else x for x in self.value_store]\n        return data\n    # end def\n# end class\n\n\nclass PrevoteMessage(Message):\n    def __init__(self, sequence_no, node, leader, value):\n        super().__init__(PREVOTE, sequence_no, node)\n        self.leader = leader\n        self.value = value\n    # end if\n\n    @classmethod\n    def from_dict(cls, data):\n        kwargs = {\n            \"sequence_no\": data[\"sequence_no\"],\n            \"node\": data[\"node\"],\n            \"leader\": data[\"leader\"],\n            \"value\": data[\"value\"],\n        }\n        return cls(**kwargs)\n\n    # end def\n\n    def to_dict(self):\n        data = super().to_dict()\n        data[\"leader\"] = self.leader\n        data[\"value\"] = self.value\n        return data\n    # end def\n# end class\n\n\nclass VoteMessage(Message):\n    def __init__(self, sequence_no, node, leader, value):\n        super().__init__(VOTE, sequence_no, node)\n        self.leader = leader\n        self.value = value\n    # end def\n\n    @classmethod\n    def from_dict(cls, data):\n        kwargs = {\n            \"sequence_no\": data[\"sequence_no\"],\n            \"node\": data[\"node\"],\n            \"leader\": data[\"leader\"],\n            \"value\": data[\"value\"],\n        }\n        return cls(**kwargs)\n    # end def\n\n    def to_dict(self):\n        data = super().to_dict()\n        data[\"leader\"] = self.leader\n        data[\"value\"] = self.value\n        return data\n    # end def\n# end class\n\n\nclass NewLeaderMessage(Message): # pragma: no cover\n    def __init__(self, sequence_no, node, leader, value):\n        super().__init__(VOTE, sequence_no, node)\n        self.leader = leader\n        self.value = value\n    # end def\n# end class\n\n\nclass Acknowledge(Message):\n    def __init__(self, sequence_no, node, sender, raw):\n        super().__init__(ACKNOWLEDGE, sequence_no, node)\n        self.sender = sender\n        self.raw = raw\n    # end def\n\n    @classmethod\n    def from_dict(cls, data):\n        kwargs = {\n            \"sequence_no\": data[\"sequence_no\"],\n            \"node\": data[\"node\"],\n            \"sender\": data[\"sender\"],\n            \"raw\": data[\"raw\"],\n        }\n        return cls(**kwargs)\n    # end def\n\n    def to_dict(self):\n        data = super().to_dict()\n        data[\"sender\"] = self.sender\n        data[\"raw\"] = self.raw\n        return data\n    # end def\n# end class"
  },
  {
    "path": "code/node/networks/__init__.py",
    "content": "# -*- coding: utf-8 -*-\nfrom luckydonaldUtils.logger import logging\n\n__author__ = 'luckydonald'\nlogger = logging.getLogger(__name__)\n"
  },
  {
    "path": "code/node/networks/receiver.py",
    "content": "# -*- coding: utf-8 -*-\nimport json\nimport threading\nfrom collections import deque\n\nfrom DictObject import DictObject\nfrom luckydonaldUtils.logger import logging\nfrom luckydonaldUtils.encoding import to_binary as b\nfrom luckydonaldUtils.encoding import to_native as n\nimport socket\n\nfrom ..messages import Message\nfrom ..dockerus import ServiceInfos\n\n__author__ = 'luckydonald'\nlogger = logging.getLogger(__name__)\n\n\n_EMPTY_RAW_BYTE = b(\"\")\n_ANSWER_SYNTAX = b(\"ANSWER \")\n_LINE_BREAK = b(\"\\n\")\n\n\nclass Receiver(object):\n    _queue = deque()\n    _new_messages = threading.Semaphore(0)\n    _queue_access = threading.Lock()\n\n    def __init__(self):\n        self._do_quit = False\n        self.s = None  # socket\n        self.client = None\n    # end def\n\n    def __receiver_logging_wrapper(self):\n        try:\n            self._receiver()\n        except Exception:\n            logger.exception(\"Receiver failed. Exited.\")\n        # end try\n    # end def\n\n    def _receiver(self):\n        from ..env import NODE_PORT\n        from errno import ECONNREFUSED\n\n        logger.info(\"Starting receiver on {host}:{port}\".format(host=ServiceInfos().hostname, port=NODE_PORT))\n        while not self._do_quit:  # retry connection\n            self.s = socket.socket(socket.AF_INET,  # Internet\n                                   socket.SOCK_STREAM)  # TCP\n            try:\n                self.s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)\n                self.s.bind((ServiceInfos().hostname, NODE_PORT))\n                self.s.listen(5)\n                logger.debug(\"Socket Set up.\")\n                while not self._do_quit and self.s:\n                    self.client, address = self.s.accept()\n\n                    buffer = _EMPTY_RAW_BYTE\n                    answer = _EMPTY_RAW_BYTE\n                    completed = -1  # -1 = answer size yet unknown, >0 = got remaining answer size\n                    while (not self._do_quit) and self.s and self.client:  # read loop\n                        while 1:  # retry if CTRL+C'd\n                            try:\n                                # self.s.setblocking(True)\n                                answer = self.client.recv(1)\n                                # recv() returns an empty string if the remote end is closed\n                                if len(answer) == 0:\n                                    logger.debug(\"Remote end closed.\")\n                                    self.reset_client()\n                                # end if\n                                # logger.debug(\"received byte: {}\".format(answer))\n                                break\n                            except socket.error as err:\n                                if self._do_quit:\n                                    self.reset_client()\n                                # end if\n                                from errno import EINTR\n                                if err.errno != EINTR:  # interrupted system call\n                                    raise\n                                else:\n                                    logger.exception(\n                                        \"Uncatched exception in reading message from {client}.\".format(client=address)\n                                    )\n                                    self.reset_client()\n                                    break  # to the retry connection look again.\n                                # end if\n                            # end try\n                        # end while: ctrl+c protection\n                        if not self.s or not self.client:  # check if socket is still open\n                            break\n                        if completed == 0:\n                            logger.debug(\"Hit end.\")\n                            if answer != _LINE_BREAK:\n                                raise ValueError(\"Message does not end with a double linebreak.\")\n                            if buffer == _EMPTY_RAW_BYTE:\n                                logger.debug(\"skipping second linebreak.\")\n                                completed = -1\n                                continue\n                            logger.debug(\n                                \"Received Message from {client}: {buffer}\".format(client=address, buffer=buffer)\n                            )\n                            text = n(buffer)\n                            if len(text) > 0 and text.strip() != \"\":\n                                self._add_message(text)\n                            else:\n                                logger.warn(\"Striped text was empty.\")\n                            answer = _EMPTY_RAW_BYTE\n                            buffer = _EMPTY_RAW_BYTE\n                            # completed = 0 (unchanged)\n                            continue\n                        buffer += answer\n                        if completed < -1 and buffer[:len(_ANSWER_SYNTAX)] != _ANSWER_SYNTAX[:len(buffer)]:\n                            raise ArithmeticError(\"Server response does not fit. (Got >{}<)\".format(buffer))\n                        if completed <= -1 and buffer.startswith(_ANSWER_SYNTAX) and buffer.endswith(_LINE_BREAK):\n                            completed = int(n(buffer[len(_ANSWER_SYNTAX):-1]))  # TODO regex.\n                            buffer = _EMPTY_RAW_BYTE\n                        completed -= 1\n                    # end while: read loop\n                # end while: for connected clients\n            except socket.error as error:\n                # if error.errno in [ECONNREFUSED] and not self._do_quit:\n                #   continue\n                # # end if\n                logger.error(\"Socket failed with network error: {e}\\nRetrying...\".format(e=error))\n            except Exception as error:\n                logger.error(\"Socket failed: {e}\\nRetrying...\".format(e=error))\n            # end try\n            self.reset_socket()\n        # end while not ._do_quit: retry connection\n        self.reset_socket()\n    # end def\n\n    def reset_client(self):\n        if self.client:\n            self.client.close()\n            self.client = None\n        # end if\n    # end def\n\n    def reset_socket(self):\n        self.reset_client()\n        if self.s:\n            self.s.close()\n            self.s = None\n        # end if\n    # end def\n\n    def _add_message(self, text):\n        \"\"\"\n        Appends a message to the message queue.\n\n        :type text: builtins.str\n        :return:\n        \"\"\"\n        try:\n            logger.debug(\"Received Message: \\\"{str}\\\"\".format(str=text))\n            json_dict = json.loads(text)\n            message = DictObject.objectify(json_dict)\n            message = self.parse_message(message)\n        except ValueError as e:\n                logger.warn(\"Received message could not be parsed.\\nMessage:>{}<\".format(text), exc_info=True)\n                return\n        with self._queue_access:\n            self._queue.append(message)\n            self._new_messages.release()\n        # end with\n    # end def\n\n    def parse_message(self, dict):\n        return Message.from_dict(dict)\n    # end def\n\n    def start(self):\n        \"\"\"\n        Starts the receiver.\n        When started, messages will be queued.\n        :return:\n        \"\"\"\n        self._receiver_thread = threading.Thread(name=\"Receiver\", target=self.__receiver_logging_wrapper, args=())\n        self._receiver_thread.daemon = True  # exit if script reaches end.\n        self._receiver_thread.start()\n        logger.success(\"Started Receiver Thread.\")\n    # end def\n\n    def stop(self):\n        \"\"\"\n        Shuts down the receivers server.\n        No more messages will be received.\n        You should not try to start() it again afterwards.\n        \"\"\"\n        self._do_quit = True\n        if self.client:\n            self.s.settimeout(0)\n        if self.client:\n            self.client.close()\n        if self.s:\n            self.s.settimeout(0)\n        if self.s:\n            self.s.close()\n        if hasattr(self, \"_receiver_thread\"):\n            logger.debug(\"receiver thread existing: {}\".format(self._receiver_thread.isAlive()))\n        else:\n            logger.debug(\"receiver thread existing: Not created.\")\n        # end if\n\n    def pop_message(self):\n        \"\"\"\n        Get a message.\n        :return:\n        \"\"\"\n        self._new_messages.acquire()  # waits until at least 1 message is in the queue.\n        with self._queue_access:\n            message = self._queue.popleft()  # pop oldest item\n            logger.debug('Messages waiting in queue: %d', len(self._queue))\n            assert isinstance(message, Message)\n            return message\n        # end with\n    # end def\n"
  },
  {
    "path": "code/node/networks/sender.py",
    "content": "# -*- coding: utf-8 -*-\nimport socket\nfrom time import sleep\n\nfrom luckydonaldUtils.logger import logging\n\nfrom ..env import NODE_PORT, DATABASE_URL\nfrom ..messages import Message\nfrom ..todo import logger\n\n__author__ = 'luckydonald'\nlogger = logging.getLogger(__name__)\n\nMSG_FORMAT = \"ANSWER {length}\\n{msg}\\n\"\n\n\ndef send_message(msg):\n    import json\n    import requests\n    logger.debug(msg)\n    assert isinstance(msg, Message)\n    data = msg.to_dict()\n    data_string = json.dumps(data)\n    broadcast(data_string)\n    loggert = logging.getLogger(\"request\")\n    def print_url(r, *args, **kwargs):\n        loggert.info(r.url)\n    # end def\n    while (True):\n        try:\n            requests.put(DATABASE_URL, data=data_string, hooks=dict(response=print_url))\n            break\n        except requests.RequestException as e:\n            logger.warning(\"Failed to report message to db: {e}\".format(e=e))\n        # end def\n        return\n# end def\n\n\ndef broadcast(message):\n    from ..dockerus import ServiceInfos\n    if not isinstance(message, str):\n        raise TypeError(\"Parameter `message` is not type `str` but {type}: {msg}\".format(type=type(message), msg=message))\n    hosts = ServiceInfos().other_hostnames()\n    # msg = MSG_FORMAT.format(length=len(message), msg=message)\n    message += \"\\n\"\n    msg = \"ANSWER \" + str(len(message)) + \"\\n\" + message\n    logger.debug(\"Prepared sending to *:{port}:\\n{msg}\".format(port=NODE_PORT, msg=msg))\n    msg = bytes(msg, \"utf-8\")\n    for node_host in hosts:\n        sent = -1\n        while not sent == 1:\n            try:\n                with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:  # UDP SOCK_DGRAM\n                    sock.connect((node_host, NODE_PORT))\n                    sock.sendall(msg)\n                    logger.log(\n                        msg=\"Sending to {host}:{port} succeeded.\".format(host=node_host, port=NODE_PORT),\n                        level=(logging.SUCCESS if sent == 0 else logging.DEBUG)\n                    )\n                    sent = 1\n                # end with\n            except OSError as e:\n                logger.error(\"Sending to {host}:{port} failed: {e} Retrying...\".format(e=e, host=node_host, port=NODE_PORT))\n                sleep(0.1)\n                sent = 0\n            # end try\n        # end while\n    # end for\n# end def"
  },
  {
    "path": "code/node/tests.py",
    "content": "# -*- coding: utf-8 -*-\nfrom luckydonaldUtils.logger import logging\n\nimport unittest\nfrom .messages import Message, InitMessage, ProposeMessage, PrevoteMessage, VoteMessage, Acknowledge\nfrom .enums import UNSET, INIT, PROPOSE, PREVOTE, VOTE, ACKNOWLEDGE\n\n__author__ = 'luckydonald'\n__all__ = [\"TestJsonToObject\"]\n\nlogger = logging.getLogger(__name__)\n\n\nclass TestJsonToObject(unittest.TestCase):\n    data_InitMessage = {\n        \"type\": INIT,\n        \"sequence_no\": 12,\n        \"node\": 1,\n        \"value\": 0.5,\n    }\n\n    def check_InitMessage(self, msg, data):\n        self.assertIsInstance(msg, InitMessage)\n        self.assertEqual(msg.type, data[\"type\"])\n        self.assertEqual(msg.sequence_no, data[\"sequence_no\"])\n        self.assertEqual(msg.node, data[\"node\"])\n        self.assertEqual(msg.value, data[\"value\"])\n    # end def\n\n    def test_InitMessage_toObject(self):\n        msg = InitMessage.from_dict(self.data_InitMessage)\n        self.check_InitMessage(msg, self.data_InitMessage)\n    # end def\n\n    def test_Message_toObject_InitMessage(self):\n        msg = Message.from_dict(self.data_InitMessage)\n        self.check_InitMessage(msg, self.data_InitMessage)\n    # end def\n\n    def test_InitMessage_toDict(self):\n        data = self.data_InitMessage\n        msg = InitMessage(data[\"sequence_no\"], data[\"node\"], data[\"value\"])\n        self.check_InitMessage(msg, self.data_InitMessage)\n        self.assertDictEqual(msg.to_dict(), data)\n    # end def\n\n    def test_InitMessage_toString(self):\n        msg = Message.from_dict(self.data_InitMessage)\n        self.assertEqual(\"InitMessage(node=1, sequence_no=12, type=1, value=0.5)\", str(msg))\n    # end def\n\n    data_ProposeMessage = {\n        \"type\": PROPOSE,\n        \"sequence_no\": 12,\n        \"node\": 1,\n        \"leader\": 1,\n        \"proposal\": 0.5,\n        \"value_store\": [],\n    }\n\n    def check_ProposeMessage(self, msg):\n        self.assertIsInstance(msg, ProposeMessage)\n        self.assertEqual(msg.type, self.data_ProposeMessage[\"type\"])\n        self.assertEqual(msg.sequence_no, self.data_ProposeMessage[\"sequence_no\"])\n        self.assertEqual(msg.node, self.data_ProposeMessage[\"node\"])\n        self.assertEqual(msg.leader, self.data_ProposeMessage[\"leader\"])\n        self.assertEqual(msg.proposal, self.data_ProposeMessage[\"proposal\"])\n    #  end def\n\n    def test_ProposeMessage_toObject(self):\n        msg = ProposeMessage.from_dict(self.data_ProposeMessage)\n        self.check_ProposeMessage(msg)\n        self.assertListEqual(msg.value_store, [])\n    # end def\n\n    def test_Message_toObject_ProposeMessage(self):\n        msg = Message.from_dict(self.data_ProposeMessage)\n        self.check_ProposeMessage(msg)\n        self.assertListEqual(msg.value_store, [])\n    # end def\n\n    def test_ProposeMessage_toDict(self):\n        data = self.data_ProposeMessage\n        msg = ProposeMessage(data[\"sequence_no\"], data[\"node\"], data[\"leader\"], data[\"proposal\"], [])\n        self.check_ProposeMessage(msg)\n        self.assertListEqual(msg.value_store, [])\n        self.assertDictEqual(msg.to_dict(), data)\n    # end def\n\n    def test_ProposeMessage_toString(self):\n        msg = Message.from_dict(self.data_ProposeMessage)\n        self.assertEqual(\"ProposeMessage(leader=1, node=1, proposal=0.5, sequence_no=12, type=2, value_store=[])\", str(msg))\n    # end def\n\n    data_ProposeMessage_with_InitMessage = {\n        \"type\": PROPOSE,\n        \"sequence_no\": 12,\n        \"node\": 1,\n        \"leader\": 1,\n        \"proposal\": 0.5,\n        \"value_store\": [data_InitMessage],\n    }\n\n    def test_ProposeMessage_with_InitMessage(self):\n        msg = Message.from_dict(self.data_ProposeMessage_with_InitMessage)\n        self.check_ProposeMessage(msg)\n        self.assertEqual(len(msg.value_store), 1)\n        self.check_InitMessage(msg.value_store[0], self.data_ProposeMessage_with_InitMessage[\"value_store\"][0], )\n    # end def\n\n    data_PrevoteMessage = {\n        \"type\": PREVOTE,\n        \"sequence_no\": 12,\n        \"node\": 1,\n        \"leader\": 1,\n        \"value\": 0.5,\n    }\n\n    def check_PrevoteMessage(self, msg):\n        self.assertIsInstance(msg, PrevoteMessage)\n        self.assertEqual(msg.type, self.data_PrevoteMessage[\"type\"])\n        self.assertEqual(msg.sequence_no, self.data_PrevoteMessage[\"sequence_no\"])\n        self.assertEqual(msg.node, self.data_PrevoteMessage[\"node\"])\n        self.assertEqual(msg.leader, self.data_PrevoteMessage[\"leader\"])\n        self.assertEqual(msg.value, self.data_PrevoteMessage[\"value\"])\n    # end def\n\n    def test_PrevoteMessage_toObject(self):\n        msg = PrevoteMessage.from_dict(self.data_PrevoteMessage)\n        self.check_PrevoteMessage(msg)\n    # end def\n\n    def test_Message_toObject_PrevoteMessage(self):\n        msg = Message.from_dict(self.data_PrevoteMessage)\n        self.check_PrevoteMessage(msg)\n    # end def\n\n    def test_PrevoteMessage_toDict(self):\n        data = self.data_PrevoteMessage\n        msg = PrevoteMessage(data[\"sequence_no\"], data[\"node\"], data[\"leader\"], data[\"value\"])\n        self.check_PrevoteMessage(msg)\n        self.assertDictEqual(msg.to_dict(), data)\n    # end def\n\n    def test_PrevoteMessage_toString(self):\n        msg = Message.from_dict(self.data_PrevoteMessage)\n        self.assertEqual(\"PrevoteMessage(leader=1, node=1, sequence_no=12, type=3, value=0.5)\", str(msg))\n    # end def\n\n    data_VoteMessage = {\n        \"type\": VOTE,\n        \"sequence_no\": 12,\n        \"node\": 1,\n        \"leader\": 1,\n        \"value\": 0.5,\n    }\n\n    def check_VoteMessage(self, msg):\n        self.assertIsInstance(msg, VoteMessage)\n        self.assertEqual(msg.type, self.data_VoteMessage[\"type\"])\n        self.assertEqual(msg.sequence_no, self.data_VoteMessage[\"sequence_no\"])\n        self.assertEqual(msg.node, self.data_VoteMessage[\"node\"])\n        self.assertEqual(msg.leader, self.data_VoteMessage[\"leader\"])\n        self.assertEqual(msg.value, self.data_VoteMessage[\"value\"])\n    # end def\n\n    def test_VoteMessage_toObject(self):\n        msg = VoteMessage.from_dict(self.data_VoteMessage)\n        self.check_VoteMessage(msg)\n    # end def\n\n    def test_Message_toObject_VoteMessage(self):\n        msg = Message.from_dict(self.data_VoteMessage)\n        self.check_VoteMessage(msg)\n    # end def\n\n    def test_VoteMessage_toDict(self):\n        data = self.data_VoteMessage\n        msg = VoteMessage(data[\"sequence_no\"], data[\"node\"], data[\"leader\"], data[\"value\"])\n        self.check_VoteMessage(msg)\n        self.assertDictEqual(msg.to_dict(), data)\n    # end def\n\n    def test_VoteMessage_toString(self):\n        msg = Message.from_dict(self.data_VoteMessage)\n        self.assertEqual(\"VoteMessage(leader=1, node=1, sequence_no=12, type=4, value=0.5)\", str(msg))\n    # end def\n\n    data_Acknowledge = {\n        \"type\": ACKNOWLEDGE,\n        \"sequence_no\": 12,\n        \"node\": 1,\n        \"sender\": 1,\n        \"raw\": {},\n    }\n\n    def check_Acknowledge(self, msg):\n        self.assertIsInstance(msg, Acknowledge)\n        self.assertEqual(msg.type, self.data_Acknowledge[\"type\"])\n        self.assertEqual(msg.sequence_no, self.data_Acknowledge[\"sequence_no\"])\n        self.assertEqual(msg.node, self.data_Acknowledge[\"node\"])\n        self.assertEqual(msg.sender, self.data_Acknowledge[\"sender\"])\n        self.assertDictEqual(msg.raw, self.data_Acknowledge[\"raw\"])\n    # end def\n\n    def test_Acknowledge_toObject(self):\n        msg = Acknowledge.from_dict(self.data_Acknowledge)\n        self.check_Acknowledge(msg)\n    # end def\n\n    def test_Message_Acknowledge_toObject(self):\n        msg = Message.from_dict(self.data_Acknowledge)\n        self.check_Acknowledge(msg)\n    # end def\n\n    def test_Acknowledge_toDict(self):\n        data = self.data_Acknowledge\n        msg = Acknowledge(data[\"sequence_no\"], data[\"node\"], data[\"sender\"], data[\"raw\"])\n        self.check_Acknowledge(msg)\n        self.assertDictEqual(msg.to_dict(), data)\n    # end def\n\n    def test_Acknowledge_toString(self):\n        msg = Message.from_dict(self.data_Acknowledge)\n        self.assertEqual(\"Acknowledge(node=1, raw={}, sender=1, sequence_no=12, type=-1)\", str(msg))\n    # end def\n\n    data_unknown_type1 = {\n        \"type\": UNSET,\n        \"sequence_no\": 12,\n        \"node\": 1,\n        \"foo\": \"bar\",\n        \"best_pony\": \"Littlepip\"\n    }\n\n    def test_Init_unknown_type1_toObject(self):\n        data = self.data_unknown_type1\n        msg = Message.from_dict(data)\n        self.assertIsInstance(msg, Message)\n        self.assertEqual(msg.type, data[\"type\"])\n        self.assertEqual(msg.sequence_no, data[\"sequence_no\"])\n        # self.assertEqual(msg.node, data[\"node\"])  # TODO put node to super, into Message\n    # end def\n\n    data_unknown_type2 = {\n        \"type\": 4458,  # <- this is different to data_unknown_type1\n        \"sequence_no\": 12,\n        \"node\": 1,\n        \"foo\": \"bar\",\n        \"best_pony\": \"Littlepip\"\n    }\n\n    def test_Init_unknown_type2_toObject(self):\n        self.assertRaises(AssertionError, Message.from_dict, self.data_unknown_type2)\n    # end def\n\n    def test_Message_new(self):\n        # data is inline\n        msg = Message(None, 12, 1)\n        self.assertIsInstance(msg, Message)\n        self.assertEqual(UNSET, msg.type)\n        self.assertEqual(12, msg.sequence_no)\n    # end def\n\n    def test_Message_new_toString(self):\n        msg = Message(None, 12, 1)\n        self.assertEqual(\"Message(node=1, sequence_no=12, type=0)\", str(msg))\n    # end def\n\n# end class\n\n\nif __name__ == '__main__':  # pragma: no cover\n    unittest.main()"
  },
  {
    "path": "code/node/todo.py",
    "content": "# -*- coding: utf-8 -*-\nfrom luckydonaldUtils.logger import logging\n\n__author__ = 'luckydonald'\nlogger = logging.getLogger(__name__)\n\n\ndef get_sensor_value():\n    return 0.5\n    # import random\n    # return round(random.uniform(0.0, 1.0), 1)\n# end def\n\n\n\ndef timeout():\n    return False\n# end def"
  },
  {
    "path": "code/tests.py",
    "content": "import unittest\nfrom node.tests import *\n\n\nif __name__ == '__main__':  # pragma: no cover\n    unittest.main()\n# end if"
  },
  {
    "path": "code/web/.bowerrc",
    "content": "{\n  \"directory\": \"/app/bower_components\"\n}"
  },
  {
    "path": "code/web/Dockerfile",
    "content": "FROM node\nEXPOSE 8000\n\n# Code Dir\nRUN mkdir -p /app/code\nWORKDIR /app/\n\n# Node lib dir\nRUN npm config set prefix /app/libs\n\n#RUN echo $PATH\nENV PATH /app/libs/bin:$PATH\nRUN echo $PATH\n\n# code install\nRUN npm install -g bower\nRUN npm install -g http-server\n\nADD package.json /app\n\n# Bower install\nADD .bowerrc /app\nADD bower.json /app\nRUN bower install --allow-root\n\nADD ./src /app/src\nADD ./example /app/example\nCOPY ./entrypoint.sh /entrypoint.sh\nRUN chmod +x /entrypoint.sh\nENTRYPOINT [\"/entrypoint.sh\"]"
  },
  {
    "path": "code/web/bower.json",
    "content": "{\n  \"name\": \"pbft-gui\",\n  \"description\": \"A starter project for AngularJS\",\n  \"version\": \"0.0.0\",\n  \"homepage\": \"https://github.com/angular/angular-seed\",\n  \"license\": \"MIT\",\n  \"private\": true,\n  \"dependencies\": {\n    \"angular\": \"~1.5.0\",\n    \"angular-route\": \"1.5.0\",\n    \"angular-loader\": \"1.5.0\",\n    \"angular-mocks\": \"1.5.0\",\n    \"angular-resource\": \"1.5.0\",\n    \"angular-animate\": \"1.5.x\",\n    \"html5-boilerplate\": \"^5.3.0\",\n    \"bootstrap\": \"3.3.x\",\n    \"jquery\": \"2.2.x\",\n    \"d3\": \"~3.4\",\n    \"highcharts\": \"5.0.7\",\n    \"tooltipster\": \"4.2.3\",\n    \"svg.js\": \"2.5.0\",\n    \"svg.screenbbox.js\": \"0.1.2\"\n  },\n  \"resolutions\": {\n    \"angular\": \"~1.5.0\"\n  }\n}\n"
  },
  {
    "path": "code/web/d3/d3.v3.js",
    "content": "!function() {\n  var d3 = {\n    version: \"3.5.17\"\n  };\n  var d3_arraySlice = [].slice, d3_array = function(list) {\n    return d3_arraySlice.call(list);\n  };\n  var d3_document = this.document;\n  function d3_documentElement(node) {\n    return node && (node.ownerDocument || node.document || node).documentElement;\n  }\n  function d3_window(node) {\n    return node && (node.ownerDocument && node.ownerDocument.defaultView || node.document && node || node.defaultView);\n  }\n  if (d3_document) {\n    try {\n      d3_array(d3_document.documentElement.childNodes)[0].nodeType;\n    } catch (e) {\n      d3_array = function(list) {\n        var i = list.length, array = new Array(i);\n        while (i--) array[i] = list[i];\n        return array;\n      };\n    }\n  }\n  if (!Date.now) Date.now = function() {\n    return +new Date();\n  };\n  if (d3_document) {\n    try {\n      d3_document.createElement(\"DIV\").style.setProperty(\"opacity\", 0, \"\");\n    } catch (error) {\n      var d3_element_prototype = this.Element.prototype, d3_element_setAttribute = d3_element_prototype.setAttribute, d3_element_setAttributeNS = d3_element_prototype.setAttributeNS, d3_style_prototype = this.CSSStyleDeclaration.prototype, d3_style_setProperty = d3_style_prototype.setProperty;\n      d3_element_prototype.setAttribute = function(name, value) {\n        d3_element_setAttribute.call(this, name, value + \"\");\n      };\n      d3_element_prototype.setAttributeNS = function(space, local, value) {\n        d3_element_setAttributeNS.call(this, space, local, value + \"\");\n      };\n      d3_style_prototype.setProperty = function(name, value, priority) {\n        d3_style_setProperty.call(this, name, value + \"\", priority);\n      };\n    }\n  }\n  d3.ascending = d3_ascending;\n  function d3_ascending(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) if ((b = array[i]) != null && b >= b) {\n        a = b;\n        break;\n      }\n      while (++i < n) if ((b = array[i]) != null && a > b) a = b;\n    } else {\n      while (++i < n) if ((b = f.call(array, array[i], i)) != null && b >= b) {\n        a = b;\n        break;\n      }\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) if ((b = array[i]) != null && b >= b) {\n        a = b;\n        break;\n      }\n      while (++i < n) if ((b = array[i]) != null && b > a) a = b;\n    } else {\n      while (++i < n) if ((b = f.call(array, array[i], i)) != null && b >= b) {\n        a = b;\n        break;\n      }\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) if ((b = array[i]) != null && b >= b) {\n        a = c = b;\n        break;\n      }\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) if ((b = f.call(array, array[i], i)) != null && b >= b) {\n        a = c = b;\n        break;\n      }\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  function d3_number(x) {\n    return x === null ? NaN : +x;\n  }\n  function d3_numeric(x) {\n    return !isNaN(x);\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 (d3_numeric(a = +array[i])) s += a;\n    } else {\n      while (++i < n) if (d3_numeric(a = +f.call(array, array[i], i))) s += a;\n    }\n    return s;\n  };\n  d3.mean = function(array, f) {\n    var s = 0, n = array.length, a, i = -1, j = n;\n    if (arguments.length === 1) {\n      while (++i < n) if (d3_numeric(a = d3_number(array[i]))) s += a; else --j;\n    } else {\n      while (++i < n) if (d3_numeric(a = d3_number(f.call(array, array[i], i)))) s += a; else --j;\n    }\n    if (j) return s / j;\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    var numbers = [], n = array.length, a, i = -1;\n    if (arguments.length === 1) {\n      while (++i < n) if (d3_numeric(a = d3_number(array[i]))) numbers.push(a);\n    } else {\n      while (++i < n) if (d3_numeric(a = d3_number(f.call(array, array[i], i)))) numbers.push(a);\n    }\n    if (numbers.length) return d3.quantile(numbers.sort(d3_ascending), .5);\n  };\n  d3.variance = function(array, f) {\n    var n = array.length, m = 0, a, d, s = 0, i = -1, j = 0;\n    if (arguments.length === 1) {\n      while (++i < n) {\n        if (d3_numeric(a = d3_number(array[i]))) {\n          d = a - m;\n          m += d / ++j;\n          s += d * (a - m);\n        }\n      }\n    } else {\n      while (++i < n) {\n        if (d3_numeric(a = d3_number(f.call(array, array[i], i)))) {\n          d = a - m;\n          m += d / ++j;\n          s += d * (a - m);\n        }\n      }\n    }\n    if (j > 1) return s / (j - 1);\n  };\n  d3.deviation = function() {\n    var v = d3.variance.apply(this, arguments);\n    return v ? Math.sqrt(v) : v;\n  };\n  function d3_bisector(compare) {\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 (compare(a[mid], x) < 0) 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 (compare(a[mid], x) > 0) hi = mid; else lo = mid + 1;\n        }\n        return lo;\n      }\n    };\n  }\n  var d3_bisect = d3_bisector(d3_ascending);\n  d3.bisectLeft = d3_bisect.left;\n  d3.bisect = d3.bisectRight = d3_bisect.right;\n  d3.bisector = function(f) {\n    return d3_bisector(f.length === 1 ? function(d, x) {\n      return d3_ascending(f(d), x);\n    } : f);\n  };\n  d3.shuffle = function(array, i0, i1) {\n    if ((m = arguments.length) < 3) {\n      i1 = array.length;\n      if (m < 2) i0 = 0;\n    }\n    var m = i1 - i0, t, i;\n    while (m) {\n      i = Math.random() * m-- | 0;\n      t = array[m + i0], array[m + i0] = array[i + i0], array[i + i0] = t;\n    }\n    return array;\n  };\n  d3.permute = function(array, indexes) {\n    var i = indexes.length, permutes = new Array(i);\n    while (i--) permutes[i] = array[indexes[i]];\n    return permutes;\n  };\n  d3.pairs = function(array) {\n    var i = 0, n = array.length - 1, p0, p1 = array[0], pairs = new Array(n < 0 ? 0 : n);\n    while (i < n) pairs[i] = [ p0 = p1, p1 = array[++i] ];\n    return pairs;\n  };\n  d3.transpose = function(matrix) {\n    if (!(n = matrix.length)) return [];\n    for (var i = -1, m = d3.min(matrix, d3_transposeLength), transpose = new Array(m); ++i < m; ) {\n      for (var j = -1, n, row = transpose[i] = new Array(n); ++j < n; ) {\n        row[j] = matrix[j][i];\n      }\n    }\n    return transpose;\n  };\n  function d3_transposeLength(d) {\n    return d.length;\n  }\n  d3.zip = function() {\n    return d3.transpose(arguments);\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    var n = arrays.length, m, i = -1, j = 0, merged, array;\n    while (++i < n) j += arrays[i].length;\n    merged = new Array(j);\n    while (--n >= 0) {\n      array = arrays[n];\n      m = array.length;\n      while (--m >= 0) {\n        merged[--j] = array[m];\n      }\n    }\n    return merged;\n  };\n  var abs = Math.abs;\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(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    for (var key in properties) {\n      Object.defineProperty(ctor.prototype, key, {\n        value: properties[key],\n        enumerable: false\n      });\n    }\n  }\n  d3.map = function(object, f) {\n    var map = new d3_Map();\n    if (object instanceof d3_Map) {\n      object.forEach(function(key, value) {\n        map.set(key, value);\n      });\n    } else if (Array.isArray(object)) {\n      var i = -1, n = object.length, o;\n      if (arguments.length === 1) while (++i < n) map.set(i, object[i]); else while (++i < n) map.set(f.call(object, o = object[i], i), o);\n    } else {\n      for (var key in object) map.set(key, object[key]);\n    }\n    return map;\n  };\n  function d3_Map() {\n    this._ = Object.create(null);\n  }\n  var d3_map_proto = \"__proto__\", d3_map_zero = \"\\x00\";\n  d3_class(d3_Map, {\n    has: d3_map_has,\n    get: function(key) {\n      return this._[d3_map_escape(key)];\n    },\n    set: function(key, value) {\n      return this._[d3_map_escape(key)] = value;\n    },\n    remove: d3_map_remove,\n    keys: d3_map_keys,\n    values: function() {\n      var values = [];\n      for (var key in this._) values.push(this._[key]);\n      return values;\n    },\n    entries: function() {\n      var entries = [];\n      for (var key in this._) entries.push({\n        key: d3_map_unescape(key),\n        value: this._[key]\n      });\n      return entries;\n    },\n    size: d3_map_size,\n    empty: d3_map_empty,\n    forEach: function(f) {\n      for (var key in this._) f.call(this, d3_map_unescape(key), this._[key]);\n    }\n  });\n  function d3_map_escape(key) {\n    return (key += \"\") === d3_map_proto || key[0] === d3_map_zero ? d3_map_zero + key : key;\n  }\n  function d3_map_unescape(key) {\n    return (key += \"\")[0] === d3_map_zero ? key.slice(1) : key;\n  }\n  function d3_map_has(key) {\n    return d3_map_escape(key) in this._;\n  }\n  function d3_map_remove(key) {\n    return (key = d3_map_escape(key)) in this._ && delete this._[key];\n  }\n  function d3_map_keys() {\n    var keys = [];\n    for (var key in this._) keys.push(d3_map_unescape(key));\n    return keys;\n  }\n  function d3_map_size() {\n    var size = 0;\n    for (var key in this._) ++size;\n    return size;\n  }\n  function d3_map_empty() {\n    for (var key in this._) return false;\n    return true;\n  }\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, n = array.length; i < n; ++i) set.add(array[i]);\n    return set;\n  };\n  function d3_Set() {\n    this._ = Object.create(null);\n  }\n  d3_class(d3_Set, {\n    has: d3_map_has,\n    add: function(key) {\n      this._[d3_map_escape(key += \"\")] = true;\n      return key;\n    },\n    remove: d3_map_remove,\n    values: d3_map_keys,\n    size: d3_map_size,\n    empty: d3_map_empty,\n    forEach: function(f) {\n      for (var key in this._) f.call(this, d3_map_unescape(key));\n    }\n  });\n  d3.behavior = {};\n  function d3_identity(d) {\n    return d;\n  }\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  function d3_vendorSymbol(object, name) {\n    if (name in object) return name;\n    name = name.charAt(0).toUpperCase() + name.slice(1);\n    for (var i = 0, n = d3_vendorPrefixes.length; i < n; ++i) {\n      var prefixName = d3_vendorPrefixes[i] + name;\n      if (prefixName in object) return prefixName;\n    }\n  }\n  var d3_vendorPrefixes = [ \"webkit\", \"ms\", \"moz\", \"Moz\", \"o\", \"O\" ];\n  function d3_noop() {}\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.slice(i + 1);\n      type = type.slice(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_eventPreventDefault() {\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.requote = function(s) {\n    return s.replace(d3_requote_re, \"\\\\$&\");\n  };\n  var d3_requote_re = /[\\\\\\^\\$\\*\\+\\?\\|\\[\\]\\(\\)\\.\\{\\}]/g;\n  var d3_subclass = {}.__proto__ ? function(object, prototype) {\n    object.__proto__ = prototype;\n  } : function(object, prototype) {\n    for (var property in prototype) object[property] = prototype[property];\n  };\n  function d3_selection(groups) {\n    d3_subclass(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_selectMatches = function(n, s) {\n    var d3_selectMatcher = n.matches || n[d3_vendorSymbol(n, \"matchesSelector\")];\n    d3_selectMatches = function(n, s) {\n      return d3_selectMatcher.call(n, s);\n    };\n    return d3_selectMatches(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 = Sizzle;\n    d3_selectMatches = Sizzle.matchesSelector;\n  }\n  d3.selection = function() {\n    return d3.select(d3_document.documentElement);\n  };\n  var d3_selectionPrototype = d3.selection.prototype = [];\n  d3_selectionPrototype.select = function(selector) {\n    var subgroups = [], subgroup, subnode, group, node;\n    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, j));\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 typeof selector === \"function\" ? selector : function() {\n      return d3_select(selector, this);\n    };\n  }\n  d3_selectionPrototype.selectAll = function(selector) {\n    var subgroups = [], subgroup, node;\n    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, j)));\n          subgroup.parentNode = node;\n        }\n      }\n    }\n    return d3_selection(subgroups);\n  };\n  function d3_selection_selectorAll(selector) {\n    return typeof selector === \"function\" ? selector : function() {\n      return d3_selectAll(selector, this);\n    };\n  }\n  var d3_nsXhtml = \"http://www.w3.org/1999/xhtml\";\n  var d3_nsPrefix = {\n    svg: \"http://www.w3.org/2000/svg\",\n    xhtml: d3_nsXhtml,\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 && (prefix = name.slice(0, i)) !== \"xmlns\") name = name.slice(i + 1);\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_selectionPrototype.classed = function(name, value) {\n    if (arguments.length < 2) {\n      if (typeof name === \"string\") {\n        var node = this.node(), n = (name = d3_selection_classes(name)).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_classes(name) {\n    return (name + \"\").trim().split(/^|\\s+/);\n  }\n  function d3_selection_classed(name, value) {\n    name = d3_selection_classes(name).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) {\n        var node = this.node();\n        return d3_window(node).getComputedStyle(node, null).getPropertyValue(name);\n      }\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_selection_creator(name);\n    return this.select(function() {\n      return this.appendChild(name.apply(this, arguments));\n    });\n  };\n  function d3_selection_creator(name) {\n    function create() {\n      var document = this.ownerDocument, namespace = this.namespaceURI;\n      return namespace === d3_nsXhtml && document.documentElement.namespaceURI === d3_nsXhtml ? document.createElement(name) : document.createElementNS(namespace, name);\n    }\n    function createNS() {\n      return this.ownerDocument.createElementNS(name.space, name.local);\n    }\n    return typeof name === \"function\" ? name : (name = d3.ns.qualify(name)).local ? createNS : create;\n  }\n  d3_selectionPrototype.insert = function(name, before) {\n    name = d3_selection_creator(name);\n    before = d3_selection_selector(before);\n    return this.select(function() {\n      return this.insertBefore(name.apply(this, arguments), before.apply(this, arguments) || null);\n    });\n  };\n  d3_selectionPrototype.remove = function() {\n    return this.each(d3_selectionRemove);\n  };\n  function d3_selectionRemove() {\n    var parent = this.parentNode;\n    if (parent) parent.removeChild(this);\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(), keyValues = new Array(n), keyValue;\n        for (i = -1; ++i < n; ) {\n          if (node = group[i]) {\n            if (nodeByKeyValue.has(keyValue = key.call(node, node.__data__, i))) {\n              exitNodes[i] = node;\n            } else {\n              nodeByKeyValue.set(keyValue, node);\n            }\n            keyValues[i] = keyValue;\n          }\n        }\n        for (i = -1; ++i < m; ) {\n          if (!(node = nodeByKeyValue.get(keyValue = key.call(groupData, nodeData = groupData[i], i)))) {\n            enterNodes[i] = d3_selection_dataNode(nodeData);\n          } else if (node !== true) {\n            updateNodes[i] = node;\n            node.__data__ = nodeData;\n          }\n          nodeByKeyValue.set(keyValue, true);\n        }\n        for (i = -1; ++i < n; ) {\n          if (i in keyValues && nodeByKeyValue.get(keyValues[i]) !== true) {\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, j)) {\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__) : !a - !b;\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  d3_selectionPrototype.size = function() {\n    var n = 0;\n    d3_selection_each(this, function() {\n      ++n;\n    });\n    return n;\n  };\n  function d3_selection_enter(selection) {\n    d3_subclass(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.empty = d3_selectionPrototype.empty;\n  d3_selection_enterPrototype.node = d3_selectionPrototype.node;\n  d3_selection_enterPrototype.call = d3_selectionPrototype.call;\n  d3_selection_enterPrototype.size = d3_selectionPrototype.size;\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, j));\n          subnode.__data__ = node.__data__;\n        } else {\n          subgroup.push(null);\n        }\n      }\n    }\n    return d3_selection(subgroups);\n  };\n  d3_selection_enterPrototype.insert = function(name, before) {\n    if (arguments.length < 2) before = d3_selection_enterInsertBefore(this);\n    return d3_selectionPrototype.insert.call(this, name, before);\n  };\n  function d3_selection_enterInsertBefore(enter) {\n    var i0, j0;\n    return function(d, i, j) {\n      var group = enter[j].update, n = group.length, node;\n      if (j != j0) j0 = j, i0 = 0;\n      if (i >= i0) i0 = i + 1;\n      while (!(node = group[i0]) && ++i0 < n) ;\n      return node;\n    };\n  }\n  d3.select = function(node) {\n    var group;\n    if (typeof node === \"string\") {\n      group = [ d3_select(node, d3_document) ];\n      group.parentNode = d3_document.documentElement;\n    } else {\n      group = [ node ];\n      group.parentNode = d3_documentElement(node);\n    }\n    return d3_selection([ group ]);\n  };\n  d3.selectAll = function(nodes) {\n    var group;\n    if (typeof nodes === \"string\") {\n      group = d3_array(d3_selectAll(nodes, d3_document));\n      group.parentNode = d3_document.documentElement;\n    } else {\n      group = d3_array(nodes);\n      group.parentNode = null;\n    }\n    return d3_selection([ group ]);\n  };\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.slice(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  if (d3_document) {\n    d3_selection_onFilters.forEach(function(k) {\n      if (\"on\" + k in d3_document) d3_selection_onFilters.remove(k);\n    });\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  var d3_event_dragSelect, d3_event_dragId = 0;\n  function d3_event_dragSuppress(node) {\n    var name = \".dragsuppress-\" + ++d3_event_dragId, click = \"click\" + name, w = d3.select(d3_window(node)).on(\"touchmove\" + name, d3_eventPreventDefault).on(\"dragstart\" + name, d3_eventPreventDefault).on(\"selectstart\" + name, d3_eventPreventDefault);\n    if (d3_event_dragSelect == null) {\n      d3_event_dragSelect = \"onselectstart\" in node ? false : d3_vendorSymbol(node.style, \"userSelect\");\n    }\n    if (d3_event_dragSelect) {\n      var style = d3_documentElement(node).style, select = style[d3_event_dragSelect];\n      style[d3_event_dragSelect] = \"none\";\n    }\n    return function(suppressClick) {\n      w.on(name, null);\n      if (d3_event_dragSelect) style[d3_event_dragSelect] = select;\n      if (suppressClick) {\n        var off = function() {\n          w.on(click, null);\n        };\n        w.on(click, function() {\n          d3_eventPreventDefault();\n          off();\n        }, true);\n        setTimeout(off, 0);\n      }\n    };\n  }\n  d3.mouse = function(container) {\n    return d3_mousePoint(container, d3_eventSource());\n  };\n  var d3_mouse_bug44083 = this.navigator && /WebKit/.test(this.navigator.userAgent) ? -1 : 0;\n  function d3_mousePoint(container, e) {\n    if (e.changedTouches) e = e.changedTouches[0];\n    var svg = container.ownerSVGElement || container;\n    if (svg.createSVGPoint) {\n      var point = svg.createSVGPoint();\n      if (d3_mouse_bug44083 < 0) {\n        var window = d3_window(container);\n        if (window.scrollX || window.scrollY) {\n          svg = d3.select(\"body\").append(\"svg\").style({\n            position: \"absolute\",\n            top: 0,\n            left: 0,\n            margin: 0,\n            padding: 0,\n            border: \"none\"\n          }, \"important\");\n          var ctm = svg[0][0].getScreenCTM();\n          d3_mouse_bug44083 = !(ctm.f || ctm.e);\n          svg.remove();\n        }\n      }\n      if (d3_mouse_bug44083) point.x = e.pageX, point.y = e.pageY; else point.x = e.clientX, \n      point.y = e.clientY;\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  d3.touch = function(container, touches, identifier) {\n    if (arguments.length < 3) identifier = touches, touches = d3_eventSource().changedTouches;\n    if (touches) for (var i = 0, n = touches.length, touch; i < n; ++i) {\n      if ((touch = touches[i]).identifier === identifier) {\n        return d3_mousePoint(container, touch);\n      }\n    }\n  };\n  d3.behavior.drag = function() {\n    var event = d3_eventDispatch(drag, \"drag\", \"dragstart\", \"dragend\"), origin = null, mousedown = dragstart(d3_noop, d3.mouse, d3_window, \"mousemove\", \"mouseup\"), touchstart = dragstart(d3_behavior_dragTouchId, d3.touch, d3_identity, \"touchmove\", \"touchend\");\n    function drag() {\n      this.on(\"mousedown.drag\", mousedown).on(\"touchstart.drag\", touchstart);\n    }\n    function dragstart(id, position, subject, move, end) {\n      return function() {\n        var that = this, target = d3.event.target.correspondingElement || d3.event.target, parent = that.parentNode, dispatch = event.of(that, arguments), dragged = 0, dragId = id(), dragName = \".drag\" + (dragId == null ? \"\" : \"-\" + dragId), dragOffset, dragSubject = d3.select(subject(target)).on(move + dragName, moved).on(end + dragName, ended), dragRestore = d3_event_dragSuppress(target), position0 = position(parent, dragId);\n        if (origin) {\n          dragOffset = origin.apply(that, arguments);\n          dragOffset = [ dragOffset.x - position0[0], dragOffset.y - position0[1] ];\n        } else {\n          dragOffset = [ 0, 0 ];\n        }\n        dispatch({\n          type: \"dragstart\"\n        });\n        function moved() {\n          var position1 = position(parent, dragId), dx, dy;\n          if (!position1) return;\n          dx = position1[0] - position0[0];\n          dy = position1[1] - position0[1];\n          dragged |= dx | dy;\n          position0 = position1;\n          dispatch({\n            type: \"drag\",\n            x: position1[0] + dragOffset[0],\n            y: position1[1] + dragOffset[1],\n            dx: dx,\n            dy: dy\n          });\n        }\n        function ended() {\n          if (!position(parent, dragId)) return;\n          dragSubject.on(move + dragName, null).on(end + dragName, null);\n          dragRestore(dragged);\n          dispatch({\n            type: \"dragend\"\n          });\n        }\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_behavior_dragTouchId() {\n    return d3.event.changedTouches[0].identifier;\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  var ε = 1e-6, ε2 = ε * ε, π = Math.PI, τ = 2 * π, τε = τ - ε, halfπ = π / 2, d3_radians = π / 180, d3_degrees = 180 / π;\n  function d3_sgn(x) {\n    return x > 0 ? 1 : x < 0 ? -1 : 0;\n  }\n  function d3_cross2d(a, b, c) {\n    return (b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0]);\n  }\n  function d3_acos(x) {\n    return x > 1 ? 0 : x < -1 ? π : Math.acos(x);\n  }\n  function d3_asin(x) {\n    return x > 1 ? halfπ : x < -1 ? -halfπ : Math.asin(x);\n  }\n  function d3_sinh(x) {\n    return ((x = Math.exp(x)) - 1 / x) / 2;\n  }\n  function d3_cosh(x) {\n    return ((x = Math.exp(x)) + 1 / x) / 2;\n  }\n  function d3_tanh(x) {\n    return ((x = Math.exp(2 * x)) - 1) / (x + 1);\n  }\n  function d3_haversin(x) {\n    return (x = Math.sin(x / 2)) * x;\n  }\n  var ρ = Math.SQRT2, ρ2 = 2, ρ4 = 4;\n  d3.interpolateZoom = function(p0, p1) {\n    var ux0 = p0[0], uy0 = p0[1], w0 = p0[2], ux1 = p1[0], uy1 = p1[1], w1 = p1[2], dx = ux1 - ux0, dy = uy1 - uy0, d2 = dx * dx + dy * dy, i, S;\n    if (d2 < ε2) {\n      S = Math.log(w1 / w0) / ρ;\n      i = function(t) {\n        return [ ux0 + t * dx, uy0 + t * dy, w0 * Math.exp(ρ * t * S) ];\n      };\n    } else {\n      var d1 = Math.sqrt(d2), b0 = (w1 * w1 - w0 * w0 + ρ4 * d2) / (2 * w0 * ρ2 * d1), b1 = (w1 * w1 - w0 * w0 - ρ4 * d2) / (2 * w1 * ρ2 * d1), r0 = Math.log(Math.sqrt(b0 * b0 + 1) - b0), r1 = Math.log(Math.sqrt(b1 * b1 + 1) - b1);\n      S = (r1 - r0) / ρ;\n      i = function(t) {\n        var s = t * S, coshr0 = d3_cosh(r0), u = w0 / (ρ2 * d1) * (coshr0 * d3_tanh(ρ * s + r0) - d3_sinh(r0));\n        return [ ux0 + u * dx, uy0 + u * dy, w0 * coshr0 / d3_cosh(ρ * s + r0) ];\n      };\n    }\n    i.duration = S * 1e3;\n    return i;\n  };\n  d3.behavior.zoom = function() {\n    var view = {\n      x: 0,\n      y: 0,\n      k: 1\n    }, translate0, center0, center, size = [ 960, 500 ], scaleExtent = d3_behavior_zoomInfinity, duration = 250, zooming = 0, mousedown = \"mousedown.zoom\", mousemove = \"mousemove.zoom\", mouseup = \"mouseup.zoom\", mousewheelTimer, touchstart = \"touchstart.zoom\", touchtime, event = d3_eventDispatch(zoom, \"zoomstart\", \"zoom\", \"zoomend\"), x0, x1, y0, y1;\n    if (!d3_behavior_zoomWheel) {\n      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    }\n    function zoom(g) {\n      g.on(mousedown, mousedowned).on(d3_behavior_zoomWheel + \".zoom\", mousewheeled).on(\"dblclick.zoom\", dblclicked).on(touchstart, touchstarted);\n    }\n    zoom.event = function(g) {\n      g.each(function() {\n        var dispatch = event.of(this, arguments), view1 = view;\n        if (d3_transitionInheritId) {\n          d3.select(this).transition().each(\"start.zoom\", function() {\n            view = this.__chart__ || {\n              x: 0,\n              y: 0,\n              k: 1\n            };\n            zoomstarted(dispatch);\n          }).tween(\"zoom:zoom\", function() {\n            var dx = size[0], dy = size[1], cx = center0 ? center0[0] : dx / 2, cy = center0 ? center0[1] : dy / 2, i = d3.interpolateZoom([ (cx - view.x) / view.k, (cy - view.y) / view.k, dx / view.k ], [ (cx - view1.x) / view1.k, (cy - view1.y) / view1.k, dx / view1.k ]);\n            return function(t) {\n              var l = i(t), k = dx / l[2];\n              this.__chart__ = view = {\n                x: cx - l[0] * k,\n                y: cy - l[1] * k,\n                k: k\n              };\n              zoomed(dispatch);\n            };\n          }).each(\"interrupt.zoom\", function() {\n            zoomended(dispatch);\n          }).each(\"end.zoom\", function() {\n            zoomended(dispatch);\n          });\n        } else {\n          this.__chart__ = view;\n          zoomstarted(dispatch);\n          zoomed(dispatch);\n          zoomended(dispatch);\n        }\n      });\n    };\n    zoom.translate = function(_) {\n      if (!arguments.length) return [ view.x, view.y ];\n      view = {\n        x: +_[0],\n        y: +_[1],\n        k: view.k\n      };\n      rescale();\n      return zoom;\n    };\n    zoom.scale = function(_) {\n      if (!arguments.length) return view.k;\n      view = {\n        x: view.x,\n        y: view.y,\n        k: null\n      };\n      scaleTo(+_);\n      rescale();\n      return zoom;\n    };\n    zoom.scaleExtent = function(_) {\n      if (!arguments.length) return scaleExtent;\n      scaleExtent = _ == null ? d3_behavior_zoomInfinity : [ +_[0], +_[1] ];\n      return zoom;\n    };\n    zoom.center = function(_) {\n      if (!arguments.length) return center;\n      center = _ && [ +_[0], +_[1] ];\n      return zoom;\n    };\n    zoom.size = function(_) {\n      if (!arguments.length) return size;\n      size = _ && [ +_[0], +_[1] ];\n      return zoom;\n    };\n    zoom.duration = function(_) {\n      if (!arguments.length) return duration;\n      duration = +_;\n      return zoom;\n    };\n    zoom.x = function(z) {\n      if (!arguments.length) return x1;\n      x1 = z;\n      x0 = z.copy();\n      view = {\n        x: 0,\n        y: 0,\n        k: 1\n      };\n      return zoom;\n    };\n    zoom.y = function(z) {\n      if (!arguments.length) return y1;\n      y1 = z;\n      y0 = z.copy();\n      view = {\n        x: 0,\n        y: 0,\n        k: 1\n      };\n      return zoom;\n    };\n    function location(p) {\n      return [ (p[0] - view.x) / view.k, (p[1] - view.y) / view.k ];\n    }\n    function point(l) {\n      return [ l[0] * view.k + view.x, l[1] * view.k + view.y ];\n    }\n    function scaleTo(s) {\n      view.k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], s));\n    }\n    function translateTo(p, l) {\n      l = point(l);\n      view.x += p[0] - l[0];\n      view.y += p[1] - l[1];\n    }\n    function zoomTo(that, p, l, k) {\n      that.__chart__ = {\n        x: view.x,\n        y: view.y,\n        k: view.k\n      };\n      scaleTo(Math.pow(2, k));\n      translateTo(center0 = p, l);\n      that = d3.select(that);\n      if (duration > 0) that = that.transition().duration(duration);\n      that.call(zoom.event);\n    }\n    function rescale() {\n      if (x1) x1.domain(x0.range().map(function(x) {\n        return (x - view.x) / view.k;\n      }).map(x0.invert));\n      if (y1) y1.domain(y0.range().map(function(y) {\n        return (y - view.y) / view.k;\n      }).map(y0.invert));\n    }\n    function zoomstarted(dispatch) {\n      if (!zooming++) dispatch({\n        type: \"zoomstart\"\n      });\n    }\n    function zoomed(dispatch) {\n      rescale();\n      dispatch({\n        type: \"zoom\",\n        scale: view.k,\n        translate: [ view.x, view.y ]\n      });\n    }\n    function zoomended(dispatch) {\n      if (!--zooming) dispatch({\n        type: \"zoomend\"\n      }), center0 = null;\n    }\n    function mousedowned() {\n      var that = this, dispatch = event.of(that, arguments), dragged = 0, subject = d3.select(d3_window(that)).on(mousemove, moved).on(mouseup, ended), location0 = location(d3.mouse(that)), dragRestore = d3_event_dragSuppress(that);\n      d3_selection_interrupt.call(that);\n      zoomstarted(dispatch);\n      function moved() {\n        dragged = 1;\n        translateTo(d3.mouse(that), location0);\n        zoomed(dispatch);\n      }\n      function ended() {\n        subject.on(mousemove, null).on(mouseup, null);\n        dragRestore(dragged);\n        zoomended(dispatch);\n      }\n    }\n    function touchstarted() {\n      var that = this, dispatch = event.of(that, arguments), locations0 = {}, distance0 = 0, scale0, zoomName = \".zoom-\" + d3.event.changedTouches[0].identifier, touchmove = \"touchmove\" + zoomName, touchend = \"touchend\" + zoomName, targets = [], subject = d3.select(that), dragRestore = d3_event_dragSuppress(that);\n      started();\n      zoomstarted(dispatch);\n      subject.on(mousedown, null).on(touchstart, started);\n      function relocate() {\n        var touches = d3.touches(that);\n        scale0 = view.k;\n        touches.forEach(function(t) {\n          if (t.identifier in locations0) locations0[t.identifier] = location(t);\n        });\n        return touches;\n      }\n      function started() {\n        var target = d3.event.target;\n        d3.select(target).on(touchmove, moved).on(touchend, ended);\n        targets.push(target);\n        var changed = d3.event.changedTouches;\n        for (var i = 0, n = changed.length; i < n; ++i) {\n          locations0[changed[i].identifier] = null;\n        }\n        var touches = relocate(), now = Date.now();\n        if (touches.length === 1) {\n          if (now - touchtime < 500) {\n            var p = touches[0];\n            zoomTo(that, p, locations0[p.identifier], Math.floor(Math.log(view.k) / Math.LN2) + 1);\n            d3_eventPreventDefault();\n          }\n          touchtime = now;\n        } else if (touches.length > 1) {\n          var p = touches[0], q = touches[1], dx = p[0] - q[0], dy = p[1] - q[1];\n          distance0 = dx * dx + dy * dy;\n        }\n      }\n      function moved() {\n        var touches = d3.touches(that), p0, l0, p1, l1;\n        d3_selection_interrupt.call(that);\n        for (var i = 0, n = touches.length; i < n; ++i, l1 = null) {\n          p1 = touches[i];\n          if (l1 = locations0[p1.identifier]) {\n            if (l0) break;\n            p0 = p1, l0 = l1;\n          }\n        }\n        if (l1) {\n          var distance1 = (distance1 = p1[0] - p0[0]) * distance1 + (distance1 = p1[1] - p0[1]) * distance1, scale1 = distance0 && Math.sqrt(distance1 / distance0);\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(scale1 * scale0);\n        }\n        touchtime = null;\n        translateTo(p0, l0);\n        zoomed(dispatch);\n      }\n      function ended() {\n        if (d3.event.touches.length) {\n          var changed = d3.event.changedTouches;\n          for (var i = 0, n = changed.length; i < n; ++i) {\n            delete locations0[changed[i].identifier];\n          }\n          for (var identifier in locations0) {\n            return void relocate();\n          }\n        }\n        d3.selectAll(targets).on(zoomName, null);\n        subject.on(mousedown, mousedowned).on(touchstart, touchstarted);\n        dragRestore();\n        zoomended(dispatch);\n      }\n    }\n    function mousewheeled() {\n      var dispatch = event.of(this, arguments);\n      if (mousewheelTimer) clearTimeout(mousewheelTimer); else d3_selection_interrupt.call(this), \n      translate0 = location(center0 = center || d3.mouse(this)), zoomstarted(dispatch);\n      mousewheelTimer = setTimeout(function() {\n        mousewheelTimer = null;\n        zoomended(dispatch);\n      }, 50);\n      d3_eventPreventDefault();\n      scaleTo(Math.pow(2, d3_behavior_zoomDelta() * .002) * view.k);\n      translateTo(center0, translate0);\n      zoomed(dispatch);\n    }\n    function dblclicked() {\n      var p = d3.mouse(this), k = Math.log(view.k) / Math.LN2;\n      zoomTo(this, p, location(p), d3.event.shiftKey ? Math.ceil(k) - 1 : Math.floor(k) + 1);\n    }\n    return d3.rebind(zoom, event, \"on\");\n  };\n  var d3_behavior_zoomInfinity = [ 0, Infinity ], d3_behavior_zoomDelta, d3_behavior_zoomWheel;\n  d3.color = d3_color;\n  function d3_color() {}\n  d3_color.prototype.toString = function() {\n    return this.rgb() + \"\";\n  };\n  d3.hsl = d3_hsl;\n  function d3_hsl(h, s, l) {\n    return this instanceof d3_hsl ? void (this.h = +h, this.s = +s, this.l = +l) : arguments.length < 2 ? h instanceof d3_hsl ? new d3_hsl(h.h, h.s, h.l) : d3_rgb_parse(\"\" + h, d3_rgb_hsl, d3_hsl) : new d3_hsl(h, s, 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 new 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 new 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 = isNaN(h) ? 0 : (h %= 360) < 0 ? h + 360 : h;\n    s = isNaN(s) ? 0 : 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 new d3_rgb(vv(h + 120), vv(h), vv(h - 120));\n  }\n  d3.hcl = d3_hcl;\n  function d3_hcl(h, c, l) {\n    return this instanceof d3_hcl ? void (this.h = +h, this.c = +c, this.l = +l) : arguments.length < 2 ? h instanceof d3_hcl ? new 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) : new d3_hcl(h, c, l);\n  }\n  var d3_hclPrototype = d3_hcl.prototype = new d3_color();\n  d3_hclPrototype.brighter = function(k) {\n    return new 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 new 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    if (isNaN(h)) h = 0;\n    if (isNaN(c)) c = 0;\n    return new d3_lab(l, Math.cos(h *= d3_radians) * c, Math.sin(h) * c);\n  }\n  d3.lab = d3_lab;\n  function d3_lab(l, a, b) {\n    return this instanceof d3_lab ? void (this.l = +l, this.a = +a, this.b = +b) : arguments.length < 2 ? l instanceof d3_lab ? new d3_lab(l.l, l.a, l.b) : l instanceof d3_hcl ? d3_hcl_lab(l.h, l.c, l.l) : d3_rgb_lab((l = d3_rgb(l)).r, l.g, l.b) : new d3_lab(l, a, 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 new 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 new 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 new 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 l > 0 ? new d3_hcl(Math.atan2(b, a) * d3_degrees, Math.sqrt(a * a + b * b), l) : new d3_hcl(NaN, NaN, 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 = d3_rgb;\n  function d3_rgb(r, g, b) {\n    return this instanceof d3_rgb ? void (this.r = ~~r, this.g = ~~g, this.b = ~~b) : arguments.length < 2 ? r instanceof d3_rgb ? new d3_rgb(r.r, r.g, r.b) : d3_rgb_parse(\"\" + r, d3_rgb, d3_hsl_rgb) : new d3_rgb(r, g, b);\n  }\n  function d3_rgbNumber(value) {\n    return new d3_rgb(value >> 16, value >> 8 & 255, value & 255);\n  }\n  function d3_rgbString(value) {\n    return d3_rgbNumber(value) + \"\";\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 new 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 new d3_rgb(Math.min(255, r / k), Math.min(255, g / k), Math.min(255, b / k));\n  };\n  d3_rgbPrototype.darker = function(k) {\n    k = Math.pow(.7, arguments.length ? k : 1);\n    return new d3_rgb(k * this.r, k * this.g, 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, color;\n    m1 = /([a-z]+)\\((.*)\\)/.exec(format = format.toLowerCase());\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 (color = d3_rgb_names.get(format)) {\n      return rgb(color.r, color.g, color.b);\n    }\n    if (format != null && format.charAt(0) === \"#\" && !isNaN(color = parseInt(format.slice(1), 16))) {\n      if (format.length === 4) {\n        r = (color & 3840) >> 4;\n        r = r >> 4 | r;\n        g = color & 240;\n        g = g >> 4 | g;\n        b = color & 15;\n        b = b << 4 | b;\n      } else if (format.length === 7) {\n        r = (color & 16711680) >> 16;\n        g = (color & 65280) >> 8;\n        b = color & 255;\n      }\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      h = NaN;\n      s = l > 0 && l < 1 ? 0 : h;\n    }\n    return new 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: 15792383,\n    antiquewhite: 16444375,\n    aqua: 65535,\n    aquamarine: 8388564,\n    azure: 15794175,\n    beige: 16119260,\n    bisque: 16770244,\n    black: 0,\n    blanchedalmond: 16772045,\n    blue: 255,\n    blueviolet: 9055202,\n    brown: 10824234,\n    burlywood: 14596231,\n    cadetblue: 6266528,\n    chartreuse: 8388352,\n    chocolate: 13789470,\n    coral: 16744272,\n    cornflowerblue: 6591981,\n    cornsilk: 16775388,\n    crimson: 14423100,\n    cyan: 65535,\n    darkblue: 139,\n    darkcyan: 35723,\n    darkgoldenrod: 12092939,\n    darkgray: 11119017,\n    darkgreen: 25600,\n    darkgrey: 11119017,\n    darkkhaki: 12433259,\n    darkmagenta: 9109643,\n    darkolivegreen: 5597999,\n    darkorange: 16747520,\n    darkorchid: 10040012,\n    darkred: 9109504,\n    darksalmon: 15308410,\n    darkseagreen: 9419919,\n    darkslateblue: 4734347,\n    darkslategray: 3100495,\n    darkslategrey: 3100495,\n    darkturquoise: 52945,\n    darkviolet: 9699539,\n    deeppink: 16716947,\n    deepskyblue: 49151,\n    dimgray: 6908265,\n    dimgrey: 6908265,\n    dodgerblue: 2003199,\n    firebrick: 11674146,\n    floralwhite: 16775920,\n    forestgreen: 2263842,\n    fuchsia: 16711935,\n    gainsboro: 14474460,\n    ghostwhite: 16316671,\n    gold: 16766720,\n    goldenrod: 14329120,\n    gray: 8421504,\n    green: 32768,\n    greenyellow: 11403055,\n    grey: 8421504,\n    honeydew: 15794160,\n    hotpink: 16738740,\n    indianred: 13458524,\n    indigo: 4915330,\n    ivory: 16777200,\n    khaki: 15787660,\n    lavender: 15132410,\n    lavenderblush: 16773365,\n    lawngreen: 8190976,\n    lemonchiffon: 16775885,\n    lightblue: 11393254,\n    lightcoral: 15761536,\n    lightcyan: 14745599,\n    lightgoldenrodyellow: 16448210,\n    lightgray: 13882323,\n    lightgreen: 9498256,\n    lightgrey: 13882323,\n    lightpink: 16758465,\n    lightsalmon: 16752762,\n    lightseagreen: 2142890,\n    lightskyblue: 8900346,\n    lightslategray: 7833753,\n    lightslategrey: 7833753,\n    lightsteelblue: 11584734,\n    lightyellow: 16777184,\n    lime: 65280,\n    limegreen: 3329330,\n    linen: 16445670,\n    magenta: 16711935,\n    maroon: 8388608,\n    mediumaquamarine: 6737322,\n    mediumblue: 205,\n    mediumorchid: 12211667,\n    mediumpurple: 9662683,\n    mediumseagreen: 3978097,\n    mediumslateblue: 8087790,\n    mediumspringgreen: 64154,\n    mediumturquoise: 4772300,\n    mediumvioletred: 13047173,\n    midnightblue: 1644912,\n    mintcream: 16121850,\n    mistyrose: 16770273,\n    moccasin: 16770229,\n    navajowhite: 16768685,\n    navy: 128,\n    oldlace: 16643558,\n    olive: 8421376,\n    olivedrab: 7048739,\n    orange: 16753920,\n    orangered: 16729344,\n    orchid: 14315734,\n    palegoldenrod: 15657130,\n    palegreen: 10025880,\n    paleturquoise: 11529966,\n    palevioletred: 14381203,\n    papayawhip: 16773077,\n    peachpuff: 16767673,\n    peru: 13468991,\n    pink: 16761035,\n    plum: 14524637,\n    powderblue: 11591910,\n    purple: 8388736,\n    rebeccapurple: 6697881,\n    red: 16711680,\n    rosybrown: 12357519,\n    royalblue: 4286945,\n    saddlebrown: 9127187,\n    salmon: 16416882,\n    sandybrown: 16032864,\n    seagreen: 3050327,\n    seashell: 16774638,\n    sienna: 10506797,\n    silver: 12632256,\n    skyblue: 8900331,\n    slateblue: 6970061,\n    slategray: 7372944,\n    slategrey: 7372944,\n    snow: 16775930,\n    springgreen: 65407,\n    steelblue: 4620980,\n    tan: 13808780,\n    teal: 32896,\n    thistle: 14204888,\n    tomato: 16737095,\n    turquoise: 4251856,\n    violet: 15631086,\n    wheat: 16113331,\n    white: 16777215,\n    whitesmoke: 16119285,\n    yellow: 16776960,\n    yellowgreen: 10145074\n  });\n  d3_rgb_names.forEach(function(key, value) {\n    d3_rgb_names.set(key, d3_rgbNumber(value));\n  });\n  function d3_functor(v) {\n    return typeof v === \"function\" ? v : function() {\n      return v;\n    };\n  }\n  d3.functor = d3_functor;\n  d3.xhr = d3_xhrType(d3_identity);\n  function d3_xhrType(response) {\n    return function(url, mimeType, callback) {\n      if (arguments.length === 2 && typeof mimeType === \"function\") callback = mimeType, \n      mimeType = null;\n      return d3_xhr(url, mimeType, response, callback);\n    };\n  }\n  function d3_xhr(url, mimeType, response, callback) {\n    var xhr = {}, dispatch = d3.dispatch(\"beforesend\", \"progress\", \"load\", \"error\"), headers = {}, request = new XMLHttpRequest(), responseType = null;\n    if (this.XDomainRequest && !(\"withCredentials\" in request) && /^(http(s)?:)?\\/\\//.test(url)) request = new XDomainRequest();\n    \"onload\" in request ? request.onload = request.onerror = respond : request.onreadystatechange = function() {\n      request.readyState > 3 && respond();\n    };\n    function respond() {\n      var status = request.status, result;\n      if (!status && d3_xhrHasResponse(request) || status >= 200 && status < 300 || status === 304) {\n        try {\n          result = response.call(xhr, request);\n        } catch (e) {\n          dispatch.error.call(xhr, e);\n          return;\n        }\n        dispatch.load.call(xhr, result);\n      } else {\n        dispatch.error.call(xhr, request);\n      }\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.responseType = function(value) {\n      if (!arguments.length) return responseType;\n      responseType = 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 (responseType != null) request.responseType = responseType;\n      if (callback != null) xhr.on(\"error\", callback).on(\"load\", function(request) {\n        callback(null, request);\n      });\n      dispatch.beforesend.call(xhr, request);\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    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_xhrHasResponse(request) {\n    var type = request.responseType;\n    return type && type !== \"text\" ? request.response : request.responseText;\n  }\n  d3.dsv = function(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, row == null ? response : typedResponse(row), callback);\n      xhr.row = function(_) {\n        return arguments.length ? xhr.response((row = _) == null ? response : typedResponse(_)) : row;\n      };\n      return xhr;\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.slice(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.slice(j, I - k);\n        }\n        return text.slice(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++)) == null) 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_queueHead, d3_timer_queueTail, d3_timer_interval, d3_timer_timeout, d3_timer_frame = this[d3_vendorSymbol(this, \"requestAnimationFrame\")] || function(callback) {\n    setTimeout(callback, 17);\n  };\n  d3.timer = function() {\n    d3_timer.apply(this, arguments);\n  };\n  function d3_timer(callback, delay, then) {\n    var n = arguments.length;\n    if (n < 2) delay = 0;\n    if (n < 3) then = Date.now();\n    var time = then + delay, timer = {\n      c: callback,\n      t: time,\n      n: null\n    };\n    if (d3_timer_queueTail) d3_timer_queueTail.n = timer; else d3_timer_queueHead = timer;\n    d3_timer_queueTail = timer;\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    return timer;\n  }\n  function d3_timer_step() {\n    var now = d3_timer_mark(), delay = d3_timer_sweep() - 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    d3_timer_mark();\n    d3_timer_sweep();\n  };\n  function d3_timer_mark() {\n    var now = Date.now(), timer = d3_timer_queueHead;\n    while (timer) {\n      if (now >= timer.t && timer.c(now - timer.t)) timer.c = null;\n      timer = timer.n;\n    }\n    return now;\n  }\n  function d3_timer_sweep() {\n    var t0, t1 = d3_timer_queueHead, time = Infinity;\n    while (t1) {\n      if (t1.c) {\n        if (t1.t < time) time = t1.t;\n        t1 = (t0 = t1).n;\n      } else {\n        t1 = t0 ? t0.n = t1.n : d3_timer_queueHead = t1.n;\n      }\n    }\n    d3_timer_queueTail = t0;\n    return time;\n  }\n  function d3_format_precision(x, p) {\n    return p - (x ? Math.ceil(Math.log(x) / Math.LN10) : 1);\n  }\n  d3.round = function(x, n) {\n    return n ? Math.round(x * (n = Math.pow(10, n))) / n : Math.round(x);\n  };\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 = +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 - 1) / 3) * 3));\n    }\n    return d3_formatPrefixes[8 + i / 3];\n  };\n  function d3_formatPrefix(d, i) {\n    var k = Math.pow(10, 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  function d3_locale_numberFormat(locale) {\n    var locale_decimal = locale.decimal, locale_thousands = locale.thousands, locale_grouping = locale.grouping, locale_currency = locale.currency, formatGroup = locale_grouping && locale_thousands ? function(value, width) {\n      var i = value.length, t = [], j = 0, g = locale_grouping[0], length = 0;\n      while (i > 0 && g > 0) {\n        if (length + g + 1 > width) g = Math.max(1, width - length);\n        t.push(value.substring(i -= g, i + g));\n        if ((length += g + 1) > width) break;\n        g = locale_grouping[j = (j + 1) % locale_grouping.length];\n      }\n      return t.reverse().join(locale_thousands);\n    } : d3_identity;\n    return function(specifier) {\n      var match = d3_format_re.exec(specifier), fill = match[1] || \" \", align = match[2] || \">\", sign = match[3] || \"-\", symbol = match[4] || \"\", zfill = match[5], width = +match[6], comma = match[7], precision = match[8], type = match[9], scale = 1, prefix = \"\", suffix = \"\", integer = false, exponent = true;\n      if (precision) precision = +precision.substring(1);\n      if (zfill || fill === \"0\" && align === \"=\") {\n        zfill = fill = \"0\";\n        align = \"=\";\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 (symbol === \"#\") prefix = \"0\" + type.toLowerCase();\n\n       case \"c\":\n        exponent = false;\n\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 (symbol === \"$\") prefix = locale_currency[0], suffix = locale_currency[1];\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        var fullSuffix = suffix;\n        if (integer && value % 1) return \"\";\n        var negative = value < 0 || value === 0 && 1 / value < 0 ? (value = -value, \"-\") : sign === \"-\" ? \"\" : sign;\n        if (scale < 0) {\n          var unit = d3.formatPrefix(value, precision);\n          value = unit.scale(value);\n          fullSuffix = unit.symbol + suffix;\n        } else {\n          value *= scale;\n        }\n        value = type(value, precision);\n        var i = value.lastIndexOf(\".\"), before, after;\n        if (i < 0) {\n          var j = exponent ? value.lastIndexOf(\"e\") : -1;\n          if (j < 0) before = value, after = \"\"; else before = value.substring(0, j), after = value.substring(j);\n        } else {\n          before = value.substring(0, i);\n          after = locale_decimal + value.substring(i + 1);\n        }\n        if (!zfill && comma) before = formatGroup(before, Infinity);\n        var length = prefix.length + before.length + after.length + (zcomma ? 0 : negative.length), padding = length < width ? new Array(length = width - length + 1).join(fill) : \"\";\n        if (zcomma) before = formatGroup(padding + before, padding.length ? width - after.length : Infinity);\n        negative += prefix;\n        value = before + after;\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)) + fullSuffix;\n      };\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_typeDefault(x) {\n    return x + \"\";\n  }\n  var d3_time = d3.time = {}, d3_date = Date;\n  function d3_date_utc() {\n    this._ = new Date(arguments.length > 1 ? Date.UTC.apply(this, arguments) : arguments[0]);\n  }\n  d3_date_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  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_date(date - 1)), 1);\n      return date;\n    }\n    function offset(date, k) {\n      step(date = new d3_date(+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_date = d3_date_utc;\n        var utc = new d3_date_utc();\n        utc._ = t0;\n        return range(utc, t1, dt);\n      } finally {\n        d3_date = 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_date = d3_date_utc;\n        var utc = new d3_date_utc();\n        utc._ = date;\n        return method(utc, k)._;\n      } finally {\n        d3_date = 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_date(2e3, 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  [ \"sunday\", \"monday\", \"tuesday\", \"wednesday\", \"thursday\", \"friday\", \"saturday\" ].forEach(function(day, i) {\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  function d3_locale_timeFormat(locale) {\n    var locale_dateTime = locale.dateTime, locale_date = locale.date, locale_time = locale.time, locale_periods = locale.periods, locale_days = locale.days, locale_shortDays = locale.shortDays, locale_months = locale.months, locale_shortMonths = locale.shortMonths;\n    function d3_time_format(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.slice(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.slice(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          Z: null\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 localZ = d.Z != null && d3_date !== d3_date_utc, date = new (localZ ? d3_date_utc : d3_date)();\n        if (\"j\" in d) date.setFullYear(d.y, 0, d.j); else if (\"W\" in d || \"U\" in d) {\n          if (!(\"w\" in d)) d.w = \"W\" in d ? 1 : 0;\n          date.setFullYear(d.y, 0, 1);\n          date.setFullYear(d.y, 0, \"W\" in d ? (d.w + 6) % 7 + d.W * 7 - (date.getDay() + 5) % 7 : d.w + d.U * 7 - (date.getDay() + 6) % 7);\n        } else date.setFullYear(d.y, d.m, d.d);\n        date.setHours(d.H + (d.Z / 100 | 0), d.M + d.Z % 100, d.S, d.L);\n        return localZ ? date._ : 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, t, 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          t = template.charAt(i++);\n          p = d3_time_parsers[t in d3_time_formatPads ? template.charAt(i++) : t];\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    d3_time_format.utc = function(template) {\n      var local = d3_time_format(template);\n      function format(date) {\n        try {\n          d3_date = d3_date_utc;\n          var utc = new d3_date();\n          utc._ = date;\n          return local(utc);\n        } finally {\n          d3_date = Date;\n        }\n      }\n      format.parse = function(string) {\n        try {\n          d3_date = d3_date_utc;\n          var date = local.parse(string);\n          return date && date._;\n        } finally {\n          d3_date = Date;\n        }\n      };\n      format.toString = local.toString;\n      return format;\n    };\n    d3_time_format.multi = d3_time_format.utc.multi = d3_time_formatMulti;\n    var d3_time_periodLookup = d3.map(), d3_time_dayRe = d3_time_formatRe(locale_days), d3_time_dayLookup = d3_time_formatLookup(locale_days), d3_time_dayAbbrevRe = d3_time_formatRe(locale_shortDays), d3_time_dayAbbrevLookup = d3_time_formatLookup(locale_shortDays), d3_time_monthRe = d3_time_formatRe(locale_months), d3_time_monthLookup = d3_time_formatLookup(locale_months), d3_time_monthAbbrevRe = d3_time_formatRe(locale_shortMonths), d3_time_monthAbbrevLookup = d3_time_formatLookup(locale_shortMonths);\n    locale_periods.forEach(function(p, i) {\n      d3_time_periodLookup.set(p.toLowerCase(), i);\n    });\n    var d3_time_formats = {\n      a: function(d) {\n        return locale_shortDays[d.getDay()];\n      },\n      A: function(d) {\n        return locale_days[d.getDay()];\n      },\n      b: function(d) {\n        return locale_shortMonths[d.getMonth()];\n      },\n      B: function(d) {\n        return locale_months[d.getMonth()];\n      },\n      c: d3_time_format(locale_dateTime),\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 locale_periods[+(d.getHours() >= 12)];\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(locale_date),\n      X: d3_time_format(locale_time),\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      j: d3_time_parseDayOfYear,\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      U: d3_time_parseWeekNumberSunday,\n      w: d3_time_parseWeekdayNumber,\n      W: d3_time_parseWeekNumberMonday,\n      x: d3_time_parseLocaleDate,\n      X: d3_time_parseLocaleTime,\n      y: d3_time_parseYear,\n      Y: d3_time_parseFullYear,\n      Z: d3_time_parseZone,\n      \"%\": d3_time_parseLiteralPercent\n    };\n    function d3_time_parseWeekdayAbbrev(date, string, i) {\n      d3_time_dayAbbrevRe.lastIndex = 0;\n      var n = d3_time_dayAbbrevRe.exec(string.slice(i));\n      return n ? (date.w = d3_time_dayAbbrevLookup.get(n[0].toLowerCase()), 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.slice(i));\n      return n ? (date.w = d3_time_dayLookup.get(n[0].toLowerCase()), 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.slice(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.slice(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_parseAmPm(date, string, i) {\n      var n = d3_time_periodLookup.get(string.slice(i, i += 2).toLowerCase());\n      return n == null ? -1 : (date.p = n, i);\n    }\n    return d3_time_format;\n  }\n  var d3_time_formatPads = {\n    \"-\": \"\",\n    _: \" \",\n    \"0\": \"0\"\n  }, d3_time_numberRe = /^\\s*\\d+/, d3_time_percentRe = /^%/;\n  function d3_time_formatPad(value, fill, width) {\n    var sign = value < 0 ? \"-\" : \"\", string = (sign ? -value : value) + \"\", length = string.length;\n    return sign + (length < width ? new Array(width - length + 1).join(fill) + string : string);\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_parseWeekdayNumber(date, string, i) {\n    d3_time_numberRe.lastIndex = 0;\n    var n = d3_time_numberRe.exec(string.slice(i, i + 1));\n    return n ? (date.w = +n[0], i + n[0].length) : -1;\n  }\n  function d3_time_parseWeekNumberSunday(date, string, i) {\n    d3_time_numberRe.lastIndex = 0;\n    var n = d3_time_numberRe.exec(string.slice(i));\n    return n ? (date.U = +n[0], i + n[0].length) : -1;\n  }\n  function d3_time_parseWeekNumberMonday(date, string, i) {\n    d3_time_numberRe.lastIndex = 0;\n    var n = d3_time_numberRe.exec(string.slice(i));\n    return n ? (date.W = +n[0], i + n[0].length) : -1;\n  }\n  function d3_time_parseFullYear(date, string, i) {\n    d3_time_numberRe.lastIndex = 0;\n    var n = d3_time_numberRe.exec(string.slice(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.slice(i, i + 2));\n    return n ? (date.y = d3_time_expandYear(+n[0]), i + n[0].length) : -1;\n  }\n  function d3_time_parseZone(date, string, i) {\n    return /^[+-]\\d{4}$/.test(string = string.slice(i, i + 5)) ? (date.Z = -string, \n    i + 5) : -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.slice(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.slice(i, i + 2));\n    return n ? (date.d = +n[0], i + n[0].length) : -1;\n  }\n  function d3_time_parseDayOfYear(date, string, i) {\n    d3_time_numberRe.lastIndex = 0;\n    var n = d3_time_numberRe.exec(string.slice(i, i + 3));\n    return n ? (date.j = +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.slice(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.slice(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.slice(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.slice(i, i + 3));\n    return n ? (date.L = +n[0], i + n[0].length) : -1;\n  }\n  function d3_time_zone(d) {\n    var z = d.getTimezoneOffset(), zs = z > 0 ? \"-\" : \"+\", zh = abs(z) / 60 | 0, zm = abs(z) % 60;\n    return zs + d3_time_formatPad(zh, \"0\", 2) + d3_time_formatPad(zm, \"0\", 2);\n  }\n  function d3_time_parseLiteralPercent(date, string, i) {\n    d3_time_percentRe.lastIndex = 0;\n    var n = d3_time_percentRe.exec(string.slice(i, i + 1));\n    return n ? i + n[0].length : -1;\n  }\n  function d3_time_formatMulti(formats) {\n    var n = formats.length, i = -1;\n    while (++i < n) formats[i][0] = this(formats[i][0]);\n    return function(date) {\n      var i = 0, f = formats[i];\n      while (!f[1](date)) f = formats[++i];\n      return f[0](date);\n    };\n  }\n  d3.locale = function(locale) {\n    return {\n      numberFormat: d3_locale_numberFormat(locale),\n      timeFormat: d3_locale_timeFormat(locale)\n    };\n  };\n  var d3_locale_enUS = d3.locale({\n    decimal: \".\",\n    thousands: \",\",\n    grouping: [ 3 ],\n    currency: [ \"$\", \"\" ],\n    dateTime: \"%a %b %e %X %Y\",\n    date: \"%m/%d/%Y\",\n    time: \"%H:%M:%S\",\n    periods: [ \"AM\", \"PM\" ],\n    days: [ \"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\" ],\n    shortDays: [ \"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\" ],\n    months: [ \"January\", \"February\", \"March\", \"April\", \"May\", \"June\", \"July\", \"August\", \"September\", \"October\", \"November\", \"December\" ],\n    shortMonths: [ \"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\" ]\n  });\n  d3.format = d3_locale_enUS.numberFormat;\n  d3.geo = {};\n  function d3_adder() {}\n  d3_adder.prototype = {\n    s: 0,\n    t: 0,\n    add: function(y) {\n      d3_adderSum(y, this.t, d3_adderTemp);\n      d3_adderSum(d3_adderTemp.s, this.s, this);\n      if (this.s) this.t += d3_adderTemp.t; else this.s = d3_adderTemp.t;\n    },\n    reset: function() {\n      this.s = this.t = 0;\n    },\n    valueOf: function() {\n      return this.s;\n    }\n  };\n  var d3_adderTemp = new d3_adder();\n  function d3_adderSum(a, b, o) {\n    var x = o.s = a + b, bv = x - a, av = x - bv;\n    o.t = a - av + (b - bv);\n  }\n  d3.geo.stream = function(object, listener) {\n    if (object && 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 (geometry && 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      object = object.coordinates;\n      listener.point(object[0], object[1], object[2]);\n    },\n    MultiPoint: function(object, listener) {\n      var coordinates = object.coordinates, i = -1, n = coordinates.length;\n      while (++i < n) object = coordinates[i], listener.point(object[0], object[1], object[2]);\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], coordinate[2]);\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_areaRingSum = new d3_adder();\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_areaRingSum.reset();\n      d3_geo_area.lineStart = d3_geo_areaRingStart;\n    },\n    polygonEnd: function() {\n      var area = 2 * d3_geo_areaRingSum;\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, sdλ = dλ >= 0 ? 1 : -1, adλ = sdλ * dλ, cosφ = Math.cos(φ), sinφ = Math.sin(φ), k = sinφ0 * sinφ, u = cosφ0 * cosφ + k * Math.cos(adλ), v = k * sdλ * Math.sin(adλ);\n      d3_geo_areaRingSum.add(Math.atan2(v, u));\n      λ0 = λ, cosφ0 = cosφ, sinφ0 = sinφ;\n    }\n    d3_geo_area.lineEnd = function() {\n      nextPoint(λ00, φ00);\n    };\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_geo_spherical(cartesian) {\n    return [ Math.atan2(cartesian[1], cartesian[0]), d3_asin(cartesian[2]) ];\n  }\n  function d3_geo_sphericalEqual(a, b) {\n    return abs(a[0] - b[0]) < ε && abs(a[1] - b[1]) < ε;\n  }\n  d3.geo.bounds = function() {\n    var λ0, φ0, λ1, φ1, λ_, λ__, φ__, p0, dλSum, ranges, range;\n    var bound = {\n      point: point,\n      lineStart: lineStart,\n      lineEnd: lineEnd,\n      polygonStart: function() {\n        bound.point = ringPoint;\n        bound.lineStart = ringStart;\n        bound.lineEnd = ringEnd;\n        dλSum = 0;\n        d3_geo_area.polygonStart();\n      },\n      polygonEnd: function() {\n        d3_geo_area.polygonEnd();\n        bound.point = point;\n        bound.lineStart = lineStart;\n        bound.lineEnd = lineEnd;\n        if (d3_geo_areaRingSum < 0) λ0 = -(λ1 = 180), φ0 = -(φ1 = 90); else if (dλSum > ε) φ1 = 90; else if (dλSum < -ε) φ0 = -90;\n        range[0] = λ0, range[1] = λ1;\n      }\n    };\n    function point(λ, φ) {\n      ranges.push(range = [ λ0 = λ, λ1 = λ ]);\n      if (φ < φ0) φ0 = φ;\n      if (φ > φ1) φ1 = φ;\n    }\n    function linePoint(λ, φ) {\n      var p = d3_geo_cartesian([ λ * d3_radians, φ * d3_radians ]);\n      if (p0) {\n        var normal = d3_geo_cartesianCross(p0, p), equatorial = [ normal[1], -normal[0], 0 ], inflection = d3_geo_cartesianCross(equatorial, normal);\n        d3_geo_cartesianNormalize(inflection);\n        inflection = d3_geo_spherical(inflection);\n        var dλ = λ - λ_, s = dλ > 0 ? 1 : -1, λi = inflection[0] * d3_degrees * s, antimeridian = abs(dλ) > 180;\n        if (antimeridian ^ (s * λ_ < λi && λi < s * λ)) {\n          var φi = inflection[1] * d3_degrees;\n          if (φi > φ1) φ1 = φi;\n        } else if (λi = (λi + 360) % 360 - 180, antimeridian ^ (s * λ_ < λi && λi < s * λ)) {\n          var φi = -inflection[1] * d3_degrees;\n          if (φi < φ0) φ0 = φi;\n        } else {\n          if (φ < φ0) φ0 = φ;\n          if (φ > φ1) φ1 = φ;\n        }\n        if (antimeridian) {\n          if (λ < λ_) {\n            if (angle(λ0, λ) > angle(λ0, λ1)) λ1 = λ;\n          } else {\n            if (angle(λ, λ1) > angle(λ0, λ1)) λ0 = λ;\n          }\n        } else {\n          if (λ1 >= λ0) {\n            if (λ < λ0) λ0 = λ;\n            if (λ > λ1) λ1 = λ;\n          } else {\n            if (λ > λ_) {\n              if (angle(λ0, λ) > angle(λ0, λ1)) λ1 = λ;\n            } else {\n              if (angle(λ, λ1) > angle(λ0, λ1)) λ0 = λ;\n            }\n          }\n        }\n      } else {\n        point(λ, φ);\n      }\n      p0 = p, λ_ = λ;\n    }\n    function lineStart() {\n      bound.point = linePoint;\n    }\n    function lineEnd() {\n      range[0] = λ0, range[1] = λ1;\n      bound.point = point;\n      p0 = null;\n    }\n    function ringPoint(λ, φ) {\n      if (p0) {\n        var dλ = λ - λ_;\n        dλSum += abs(dλ) > 180 ? dλ + (dλ > 0 ? 360 : -360) : dλ;\n      } else λ__ = λ, φ__ = φ;\n      d3_geo_area.point(λ, φ);\n      linePoint(λ, φ);\n    }\n    function ringStart() {\n      d3_geo_area.lineStart();\n    }\n    function ringEnd() {\n      ringPoint(λ__, φ__);\n      d3_geo_area.lineEnd();\n      if (abs(dλSum) > ε) λ0 = -(λ1 = 180);\n      range[0] = λ0, range[1] = λ1;\n      p0 = null;\n    }\n    function angle(λ0, λ1) {\n      return (λ1 -= λ0) < 0 ? λ1 + 360 : λ1;\n    }\n    function compareRanges(a, b) {\n      return a[0] - b[0];\n    }\n    function withinRange(x, range) {\n      return range[0] <= range[1] ? range[0] <= x && x <= range[1] : x < range[0] || range[1] < x;\n    }\n    return function(feature) {\n      φ1 = λ1 = -(λ0 = φ0 = Infinity);\n      ranges = [];\n      d3.geo.stream(feature, bound);\n      var n = ranges.length;\n      if (n) {\n        ranges.sort(compareRanges);\n        for (var i = 1, a = ranges[0], b, merged = [ a ]; i < n; ++i) {\n          b = ranges[i];\n          if (withinRange(b[0], a) || withinRange(b[1], a)) {\n            if (angle(a[0], b[1]) > angle(a[0], a[1])) a[1] = b[1];\n            if (angle(b[0], a[1]) > angle(a[0], a[1])) a[0] = b[0];\n          } else {\n            merged.push(a = b);\n          }\n        }\n        var best = -Infinity, dλ;\n        for (var n = merged.length - 1, i = 0, a = merged[n], b; i <= n; a = b, ++i) {\n          b = merged[i];\n          if ((dλ = angle(a[1], b[0])) > best) best = dλ, λ0 = b[0], λ1 = a[1];\n        }\n      }\n      ranges = range = null;\n      return λ0 === Infinity || φ0 === Infinity ? [ [ NaN, NaN ], [ NaN, NaN ] ] : [ [ λ0, φ0 ], [ λ1, φ1 ] ];\n    };\n  }();\n  d3.geo.centroid = function(object) {\n    d3_geo_centroidW0 = d3_geo_centroidW1 = d3_geo_centroidX0 = d3_geo_centroidY0 = d3_geo_centroidZ0 = d3_geo_centroidX1 = d3_geo_centroidY1 = d3_geo_centroidZ1 = d3_geo_centroidX2 = d3_geo_centroidY2 = d3_geo_centroidZ2 = 0;\n    d3.geo.stream(object, d3_geo_centroid);\n    var x = d3_geo_centroidX2, y = d3_geo_centroidY2, z = d3_geo_centroidZ2, m = x * x + y * y + z * z;\n    if (m < ε2) {\n      x = d3_geo_centroidX1, y = d3_geo_centroidY1, z = d3_geo_centroidZ1;\n      if (d3_geo_centroidW1 < ε) x = d3_geo_centroidX0, y = d3_geo_centroidY0, z = d3_geo_centroidZ0;\n      m = x * x + y * y + z * z;\n      if (m < ε2) return [ NaN, NaN ];\n    }\n    return [ Math.atan2(y, x) * d3_degrees, d3_asin(z / Math.sqrt(m)) * d3_degrees ];\n  };\n  var d3_geo_centroidW0, d3_geo_centroidW1, d3_geo_centroidX0, d3_geo_centroidY0, d3_geo_centroidZ0, d3_geo_centroidX1, d3_geo_centroidY1, d3_geo_centroidZ1, d3_geo_centroidX2, d3_geo_centroidY2, d3_geo_centroidZ2;\n  var d3_geo_centroid = {\n    sphere: d3_noop,\n    point: d3_geo_centroidPoint,\n    lineStart: d3_geo_centroidLineStart,\n    lineEnd: d3_geo_centroidLineEnd,\n    polygonStart: function() {\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    λ *= d3_radians;\n    var cosφ = Math.cos(φ *= d3_radians);\n    d3_geo_centroidPointXYZ(cosφ * Math.cos(λ), cosφ * Math.sin(λ), Math.sin(φ));\n  }\n  function d3_geo_centroidPointXYZ(x, y, z) {\n    ++d3_geo_centroidW0;\n    d3_geo_centroidX0 += (x - d3_geo_centroidX0) / d3_geo_centroidW0;\n    d3_geo_centroidY0 += (y - d3_geo_centroidY0) / d3_geo_centroidW0;\n    d3_geo_centroidZ0 += (z - d3_geo_centroidZ0) / d3_geo_centroidW0;\n  }\n  function d3_geo_centroidLineStart() {\n    var x0, y0, z0;\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      d3_geo_centroidPointXYZ(x0, y0, z0);\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_centroidW1 += w;\n      d3_geo_centroidX1 += w * (x0 + (x0 = x));\n      d3_geo_centroidY1 += w * (y0 + (y0 = y));\n      d3_geo_centroidZ1 += w * (z0 + (z0 = z));\n      d3_geo_centroidPointXYZ(x0, y0, z0);\n    }\n  }\n  function d3_geo_centroidLineEnd() {\n    d3_geo_centroid.point = d3_geo_centroidPoint;\n  }\n  function d3_geo_centroidRingStart() {\n    var λ00, φ00, x0, y0, z0;\n    d3_geo_centroid.point = function(λ, φ) {\n      λ00 = λ, φ00 = φ;\n      d3_geo_centroid.point = nextPoint;\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_centroidPointXYZ(x0, y0, z0);\n    };\n    d3_geo_centroid.lineEnd = function() {\n      nextPoint(λ00, φ00);\n      d3_geo_centroid.lineEnd = d3_geo_centroidLineEnd;\n      d3_geo_centroid.point = d3_geo_centroidPoint;\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(φ), cx = y0 * z - z0 * y, cy = z0 * x - x0 * z, cz = x0 * y - y0 * x, m = Math.sqrt(cx * cx + cy * cy + cz * cz), u = x0 * x + y0 * y + z0 * z, v = m && -d3_acos(u) / m, w = Math.atan2(m, u);\n      d3_geo_centroidX2 += v * cx;\n      d3_geo_centroidY2 += v * cy;\n      d3_geo_centroidZ2 += v * cz;\n      d3_geo_centroidW1 += w;\n      d3_geo_centroidX1 += w * (x0 + (x0 = x));\n      d3_geo_centroidY1 += w * (y0 + (y0 = y));\n      d3_geo_centroidZ1 += w * (z0 + (z0 = z));\n      d3_geo_centroidPointXYZ(x0, y0, z0);\n    }\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_true() {\n    return true;\n  }\n  function d3_geo_clipPolygon(segments, compare, clipStartInside, 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 = new d3_geo_clipPolygonIntersection(p0, segment, null, true), b = new d3_geo_clipPolygonIntersection(p0, null, a, false);\n      a.o = b;\n      subject.push(a);\n      clip.push(b);\n      a = new d3_geo_clipPolygonIntersection(p1, segment, null, false);\n      b = new d3_geo_clipPolygonIntersection(p1, null, a, true);\n      a.o = 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    for (var i = 0, entry = clipStartInside, n = clip.length; i < n; ++i) {\n      clip[i].e = entry = !entry;\n    }\n    var start = subject[0], points, point;\n    while (1) {\n      var current = start, isSubject = true;\n      while (current.v) if ((current = current.n) === start) return;\n      points = current.z;\n      listener.lineStart();\n      do {\n        current.v = current.o.v = true;\n        if (current.e) {\n          if (isSubject) {\n            for (var i = 0, n = points.length; i < n; ++i) listener.point((point = points[i])[0], point[1]);\n          } else {\n            interpolate(current.x, current.n.x, 1, listener);\n          }\n          current = current.n;\n        } else {\n          if (isSubject) {\n            points = current.p.z;\n            for (var i = points.length - 1; i >= 0; --i) listener.point((point = points[i])[0], point[1]);\n          } else {\n            interpolate(current.x, current.p.x, -1, listener);\n          }\n          current = current.p;\n        }\n        current = current.o;\n        points = current.z;\n        isSubject = !isSubject;\n      } while (!current.v);\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.n = b = array[i];\n      b.p = a;\n      a = b;\n    }\n    a.n = b = array[0];\n    b.p = a;\n  }\n  function d3_geo_clipPolygonIntersection(point, points, other, entry) {\n    this.x = point;\n    this.z = points;\n    this.o = other;\n    this.e = entry;\n    this.v = false;\n    this.n = this.p = null;\n  }\n  function d3_geo_clip(pointVisible, clipLine, interpolate, clipStart) {\n    return function(rotate, listener) {\n      var line = clipLine(listener), rotatedClipStart = rotate.invert(clipStart[0], clipStart[1]);\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          segments = [];\n          polygon = [];\n        },\n        polygonEnd: function() {\n          clip.point = point;\n          clip.lineStart = lineStart;\n          clip.lineEnd = lineEnd;\n          segments = d3.merge(segments);\n          var clipStartInside = d3_geo_pointInPolygon(rotatedClipStart, polygon);\n          if (segments.length) {\n            if (!polygonStarted) listener.polygonStart(), polygonStarted = true;\n            d3_geo_clipPolygon(segments, d3_geo_clipSort, clipStartInside, interpolate, listener);\n          } else if (clipStartInside) {\n            if (!polygonStarted) listener.polygonStart(), polygonStarted = true;\n            listener.lineStart();\n            interpolate(null, null, 1, listener);\n            listener.lineEnd();\n          }\n          if (polygonStarted) listener.polygonEnd(), polygonStarted = false;\n          segments = polygon = 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        var point = rotate(λ, φ);\n        if (pointVisible(λ = point[0], φ = point[1])) listener.point(λ, φ);\n      }\n      function pointLine(λ, φ) {\n        var point = rotate(λ, φ);\n        line.point(point[0], point[1]);\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;\n      var buffer = d3_geo_clipBufferListener(), ringListener = clipLine(buffer), polygonStarted = false, polygon, ring;\n      function pointRing(λ, φ) {\n        ring.push([ λ, φ ]);\n        var point = rotate(λ, φ);\n        ringListener.point(point[0], point[1]);\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        ring.pop();\n        polygon.push(ring);\n        ring = null;\n        if (!n) return;\n        if (clean & 1) {\n          segment = ringSegments[0];\n          var n = segment.length - 1, i = -1, point;\n          if (n > 0) {\n            if (!polygonStarted) listener.polygonStart(), polygonStarted = true;\n            listener.lineStart();\n            while (++i < n) listener.point((point = segment[i])[0], point[1]);\n            listener.lineEnd();\n          }\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_clipSort(a, b) {\n    return ((a = a.x)[0] < 0 ? a[1] - halfπ - ε : halfπ - a[1]) - ((b = b.x)[0] < 0 ? b[1] - halfπ - ε : halfπ - b[1]);\n  }\n  var d3_geo_clipAntimeridian = d3_geo_clip(d3_true, d3_geo_clipAntimeridianLine, d3_geo_clipAntimeridianInterpolate, [ -π, -π / 2 ]);\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λ = abs(λ1 - λ0);\n        if (abs(dλ - π) < ε) {\n          listener.point(λ0, φ0 = (φ0 + φ1) / 2 > 0 ? halfπ : -halfπ);\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 (abs(λ0 - sλ0) < ε) λ0 -= sλ0 * ε;\n          if (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 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 * halfπ;\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 (abs(from[0] - to[0]) > ε) {\n      var s = from[0] < to[0] ? π : -π;\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_pointInPolygon(point, polygon) {\n    var meridian = point[0], parallel = point[1], meridianNormal = [ Math.sin(meridian), -Math.cos(meridian), 0 ], polarAngle = 0, winding = 0;\n    d3_geo_areaRingSum.reset();\n    for (var i = 0, n = polygon.length; i < n; ++i) {\n      var ring = polygon[i], m = ring.length;\n      if (!m) continue;\n      var point0 = ring[0], λ0 = point0[0], φ0 = point0[1] / 2 + π / 4, sinφ0 = Math.sin(φ0), cosφ0 = Math.cos(φ0), j = 1;\n      while (true) {\n        if (j === m) j = 0;\n        point = ring[j];\n        var λ = point[0], φ = point[1] / 2 + π / 4, sinφ = Math.sin(φ), cosφ = Math.cos(φ), dλ = λ - λ0, sdλ = dλ >= 0 ? 1 : -1, adλ = sdλ * dλ, antimeridian = adλ > π, k = sinφ0 * sinφ;\n        d3_geo_areaRingSum.add(Math.atan2(k * sdλ * Math.sin(adλ), cosφ0 * cosφ + k * Math.cos(adλ)));\n        polarAngle += antimeridian ? dλ + sdλ * τ : dλ;\n        if (antimeridian ^ λ0 >= meridian ^ λ >= meridian) {\n          var arc = d3_geo_cartesianCross(d3_geo_cartesian(point0), d3_geo_cartesian(point));\n          d3_geo_cartesianNormalize(arc);\n          var intersection = d3_geo_cartesianCross(meridianNormal, arc);\n          d3_geo_cartesianNormalize(intersection);\n          var φarc = (antimeridian ^ dλ >= 0 ? -1 : 1) * d3_asin(intersection[2]);\n          if (parallel > φarc || parallel === φarc && (arc[0] || arc[1])) {\n            winding += antimeridian ^ dλ >= 0 ? 1 : -1;\n          }\n        }\n        if (!j++) break;\n        λ0 = λ, sinφ0 = sinφ, cosφ0 = cosφ, point0 = point;\n      }\n    }\n    return (polarAngle < -ε || polarAngle < ε && d3_geo_areaRingSum < -ε) ^ winding & 1;\n  }\n  function d3_geo_clipCircle(radius) {\n    var cr = Math.cos(radius), smallRadius = cr > 0, notHemisphere = abs(cr) > ε, interpolate = d3_geo_circleInterpolate(radius, 6 * d3_radians);\n    return d3_geo_clip(visible, clipLine, interpolate, smallRadius ? [ 0, -radius ] : [ -π, radius - π ]);\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 = abs(δλ - π) < ε, meridian = polar || δλ < ε;\n      if (!polar && φ1 < φ0) z = φ0, φ0 = φ1, φ1 = z;\n      if (meridian ? polar ? φ0 + φ1 > 0 ^ q[1] < (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  function d3_geom_clipLine(x0, y0, x1, y1) {\n    return function(line) {\n      var a = line.a, b = line.b, ax = a.x, ay = a.y, bx = b.x, by = b.y, t0 = 0, t1 = 1, dx = bx - ax, dy = by - ay, r;\n      r = x0 - ax;\n      if (!dx && r > 0) return;\n      r /= dx;\n      if (dx < 0) {\n        if (r < t0) return;\n        if (r < t1) t1 = r;\n      } else if (dx > 0) {\n        if (r > t1) return;\n        if (r > t0) t0 = r;\n      }\n      r = x1 - ax;\n      if (!dx && r < 0) return;\n      r /= dx;\n      if (dx < 0) {\n        if (r > t1) return;\n        if (r > t0) t0 = r;\n      } else if (dx > 0) {\n        if (r < t0) return;\n        if (r < t1) t1 = r;\n      }\n      r = y0 - ay;\n      if (!dy && r > 0) return;\n      r /= dy;\n      if (dy < 0) {\n        if (r < t0) return;\n        if (r < t1) t1 = r;\n      } else if (dy > 0) {\n        if (r > t1) return;\n        if (r > t0) t0 = r;\n      }\n      r = y1 - ay;\n      if (!dy && r < 0) return;\n      r /= dy;\n      if (dy < 0) {\n        if (r > t1) return;\n        if (r > t0) t0 = r;\n      } else if (dy > 0) {\n        if (r < t0) return;\n        if (r < t1) t1 = r;\n      }\n      if (t0 > 0) line.a = {\n        x: ax + t0 * dx,\n        y: ay + t0 * dy\n      };\n      if (t1 < 1) line.b = {\n        x: ax + t1 * dx,\n        y: ay + t1 * dy\n      };\n      return line;\n    };\n  }\n  var d3_geo_clipExtentMAX = 1e9;\n  d3.geo.clipExtent = function() {\n    var x0, y0, x1, y1, stream, clip, clipExtent = {\n      stream: function(output) {\n        if (stream) stream.valid = false;\n        stream = clip(output);\n        stream.valid = true;\n        return stream;\n      },\n      extent: function(_) {\n        if (!arguments.length) return [ [ x0, y0 ], [ x1, y1 ] ];\n        clip = d3_geo_clipExtent(x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1]);\n        if (stream) stream.valid = false, stream = null;\n        return clipExtent;\n      }\n    };\n    return clipExtent.extent([ [ 0, 0 ], [ 960, 500 ] ]);\n  };\n  function d3_geo_clipExtent(x0, y0, x1, y1) {\n    return function(listener) {\n      var listener_ = listener, bufferListener = d3_geo_clipBufferListener(), clipLine = d3_geom_clipLine(x0, y0, x1, y1), 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          clean = true;\n        },\n        polygonEnd: function() {\n          listener = listener_;\n          segments = d3.merge(segments);\n          var clipStartInside = insidePolygon([ x0, y1 ]), inside = clean && clipStartInside, visible = segments.length;\n          if (inside || visible) {\n            listener.polygonStart();\n            if (inside) {\n              listener.lineStart();\n              interpolate(null, null, 1, listener);\n              listener.lineEnd();\n            }\n            if (visible) {\n              d3_geo_clipPolygon(segments, compare, clipStartInside, interpolate, listener);\n            }\n            listener.polygonEnd();\n          }\n          segments = polygon = ring = null;\n        }\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], b; j < m; ++j) {\n            b = v[j];\n            if (a[1] <= y) {\n              if (b[1] > y && d3_cross2d(a, b, p) > 0) ++wn;\n            } else {\n              if (b[1] <= y && d3_cross2d(a, b, p) < 0) --wn;\n            }\n            a = b;\n          }\n        }\n        return wn !== 0;\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 pointVisible(x, y) {\n        return x0 <= x && x <= x1 && y0 <= y && y <= y1;\n      }\n      function point(x, y) {\n        if (pointVisible(x, y)) listener.point(x, y);\n      }\n      var x__, y__, v__, x_, y_, v_, first, clean;\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_clipExtentMAX, Math.min(d3_geo_clipExtentMAX, x));\n        y = Math.max(-d3_geo_clipExtentMAX, Math.min(d3_geo_clipExtentMAX, y));\n        var v = pointVisible(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 l = {\n              a: {\n                x: x_,\n                y: y_\n              },\n              b: {\n                x: x,\n                y: y\n              }\n            };\n            if (clipLine(l)) {\n              if (!v_) {\n                listener.lineStart();\n                listener.point(l.a.x, l.a.y);\n              }\n              listener.point(l.b.x, l.b.y);\n              if (!v) listener.lineEnd();\n              clean = false;\n            } else if (v) {\n              listener.lineStart();\n              listener.point(x, y);\n              clean = false;\n            }\n          }\n        }\n        x_ = x, y_ = y, v_ = v;\n      }\n      return clip;\n    };\n    function corner(p, direction) {\n      return abs(p[0] - x0) < ε ? direction > 0 ? 0 : 3 : abs(p[0] - x1) < ε ? direction > 0 ? 2 : 1 : abs(p[1] - y0) < ε ? direction > 0 ? 1 : 0 : direction > 0 ? 3 : 2;\n    }\n    function compare(a, b) {\n      return comparePoints(a.x, b.x);\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  }\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, d3_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.albers = function() {\n    return d3.geo.conicEqualArea().rotate([ 96, 0 ]).center([ -.6, 38.7 ]).parallels([ 29.5, 45.5 ]).scale(1070);\n  };\n  d3.geo.albersUsa = function() {\n    var lower48 = d3.geo.albers();\n    var alaska = d3.geo.conicEqualArea().rotate([ 154, 0 ]).center([ -2, 58.5 ]).parallels([ 55, 65 ]);\n    var hawaii = d3.geo.conicEqualArea().rotate([ 157, 0 ]).center([ -3, 19.9 ]).parallels([ 8, 18 ]);\n    var point, pointStream = {\n      point: function(x, y) {\n        point = [ x, y ];\n      }\n    }, lower48Point, alaskaPoint, hawaiiPoint;\n    function albersUsa(coordinates) {\n      var x = coordinates[0], y = coordinates[1];\n      point = null;\n      (lower48Point(x, y), point) || (alaskaPoint(x, y), point) || hawaiiPoint(x, y);\n      return point;\n    }\n    albersUsa.invert = function(coordinates) {\n      var k = lower48.scale(), t = lower48.translate(), x = (coordinates[0] - t[0]) / k, y = (coordinates[1] - t[1]) / k;\n      return (y >= .12 && y < .234 && x >= -.425 && x < -.214 ? alaska : y >= .166 && y < .234 && x >= -.214 && x < -.115 ? hawaii : lower48).invert(coordinates);\n    };\n    albersUsa.stream = function(stream) {\n      var lower48Stream = lower48.stream(stream), alaskaStream = alaska.stream(stream), hawaiiStream = hawaii.stream(stream);\n      return {\n        point: function(x, y) {\n          lower48Stream.point(x, y);\n          alaskaStream.point(x, y);\n          hawaiiStream.point(x, y);\n        },\n        sphere: function() {\n          lower48Stream.sphere();\n          alaskaStream.sphere();\n          hawaiiStream.sphere();\n        },\n        lineStart: function() {\n          lower48Stream.lineStart();\n          alaskaStream.lineStart();\n          hawaiiStream.lineStart();\n        },\n        lineEnd: function() {\n          lower48Stream.lineEnd();\n          alaskaStream.lineEnd();\n          hawaiiStream.lineEnd();\n        },\n        polygonStart: function() {\n          lower48Stream.polygonStart();\n          alaskaStream.polygonStart();\n          hawaiiStream.polygonStart();\n        },\n        polygonEnd: function() {\n          lower48Stream.polygonEnd();\n          alaskaStream.polygonEnd();\n          hawaiiStream.polygonEnd();\n        }\n      };\n    };\n    albersUsa.precision = function(_) {\n      if (!arguments.length) return lower48.precision();\n      lower48.precision(_);\n      alaska.precision(_);\n      hawaii.precision(_);\n      return albersUsa;\n    };\n    albersUsa.scale = function(_) {\n      if (!arguments.length) return lower48.scale();\n      lower48.scale(_);\n      alaska.scale(_ * .35);\n      hawaii.scale(_);\n      return albersUsa.translate(lower48.translate());\n    };\n    albersUsa.translate = function(_) {\n      if (!arguments.length) return lower48.translate();\n      var k = lower48.scale(), x = +_[0], y = +_[1];\n      lower48Point = lower48.translate(_).clipExtent([ [ x - .455 * k, y - .238 * k ], [ x + .455 * k, y + .238 * k ] ]).stream(pointStream).point;\n      alaskaPoint = alaska.translate([ x - .307 * k, y + .201 * k ]).clipExtent([ [ x - .425 * k + ε, y + .12 * k + ε ], [ x - .214 * k - ε, y + .234 * k - ε ] ]).stream(pointStream).point;\n      hawaiiPoint = hawaii.translate([ x - .205 * k, y + .212 * k ]).clipExtent([ [ x - .214 * k + ε, y + .166 * k + ε ], [ x - .115 * k - ε, y + .234 * k - ε ] ]).stream(pointStream).point;\n      return albersUsa;\n    };\n    return albersUsa.scale(1070);\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 += 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  var d3_geo_pathBoundsX0, d3_geo_pathBoundsY0, d3_geo_pathBoundsX1, d3_geo_pathBoundsY1;\n  var d3_geo_pathBounds = {\n    point: d3_geo_pathBoundsPoint,\n    lineStart: d3_noop,\n    lineEnd: d3_noop,\n    polygonStart: d3_noop,\n    polygonEnd: d3_noop\n  };\n  function d3_geo_pathBoundsPoint(x, y) {\n    if (x < d3_geo_pathBoundsX0) d3_geo_pathBoundsX0 = x;\n    if (x > d3_geo_pathBoundsX1) d3_geo_pathBoundsX1 = x;\n    if (y < d3_geo_pathBoundsY0) d3_geo_pathBoundsY0 = y;\n    if (y > d3_geo_pathBoundsY1) d3_geo_pathBoundsY1 = y;\n  }\n  function d3_geo_pathBuffer() {\n    var pointCircle = d3_geo_pathBufferCircle(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_pathBufferCircle(_);\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  function d3_geo_pathBufferCircle(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  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    d3_geo_centroidX0 += x;\n    d3_geo_centroidY0 += y;\n    ++d3_geo_centroidZ0;\n  }\n  function d3_geo_pathCentroidLineStart() {\n    var x0, y0;\n    d3_geo_pathCentroid.point = function(x, y) {\n      d3_geo_pathCentroid.point = nextPoint;\n      d3_geo_pathCentroidPoint(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_centroidX1 += z * (x0 + x) / 2;\n      d3_geo_centroidY1 += z * (y0 + y) / 2;\n      d3_geo_centroidZ1 += z;\n      d3_geo_pathCentroidPoint(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    d3_geo_pathCentroid.point = function(x, y) {\n      d3_geo_pathCentroid.point = nextPoint;\n      d3_geo_pathCentroidPoint(x00 = x0 = x, y00 = 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_centroidX1 += z * (x0 + x) / 2;\n      d3_geo_centroidY1 += z * (y0 + y) / 2;\n      d3_geo_centroidZ1 += z;\n      z = y0 * x - x0 * y;\n      d3_geo_centroidX2 += z * (x0 + x);\n      d3_geo_centroidY2 += z * (y0 + y);\n      d3_geo_centroidZ2 += z * 3;\n      d3_geo_pathCentroidPoint(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 + pointRadius, y);\n      context.arc(x, y, pointRadius, 0, τ);\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  function d3_geo_resample(project) {\n    var δ2 = .5, cosMinDistance = Math.cos(30 * d3_radians), maxDepth = 16;\n    function resample(stream) {\n      return (maxDepth ? resampleRecursive : resampleNone)(stream);\n    }\n    function resampleNone(stream) {\n      return d3_geo_transformPoint(stream, function(x, y) {\n        x = project(x, y);\n        stream.point(x[0], x[1]);\n      });\n    }\n    function resampleRecursive(stream) {\n      var λ00, φ00, x00, y00, a00, b00, c00, λ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 = ringStart;\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 ringStart() {\n        lineStart();\n        resample.point = ringPoint;\n        resample.lineEnd = ringEnd;\n      }\n      function ringPoint(λ, φ) {\n        linePoint(λ00 = λ, φ00 = φ), x00 = x0, y00 = y0, a00 = a0, b00 = b0, c00 = c0;\n        resample.point = linePoint;\n      }\n      function ringEnd() {\n        resampleLineTo(x0, y0, λ0, a0, b0, c0, x00, y00, λ00, a00, b00, c00, maxDepth, stream);\n        resample.lineEnd = lineEnd;\n        lineEnd();\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 = abs(abs(c) - 1) < ε || abs(λ0 - λ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 || abs((dx * dx2 + dy * dy2) / d2 - .5) > .3 || a0 * a1 + b0 * b1 + c0 * c1 < cosMinDistance) {\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.path = function() {\n    var pointRadius = 4.5, projection, context, projectStream, contextStream, cacheStream;\n    function path(object) {\n      if (object) {\n        if (typeof pointRadius === \"function\") contextStream.pointRadius(+pointRadius.apply(this, arguments));\n        if (!cacheStream || !cacheStream.valid) cacheStream = projectStream(contextStream);\n        d3.geo.stream(object, cacheStream);\n      }\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_centroidX0 = d3_geo_centroidY0 = d3_geo_centroidZ0 = d3_geo_centroidX1 = d3_geo_centroidY1 = d3_geo_centroidZ1 = d3_geo_centroidX2 = d3_geo_centroidY2 = d3_geo_centroidZ2 = 0;\n      d3.geo.stream(object, projectStream(d3_geo_pathCentroid));\n      return d3_geo_centroidZ2 ? [ d3_geo_centroidX2 / d3_geo_centroidZ2, d3_geo_centroidY2 / d3_geo_centroidZ2 ] : d3_geo_centroidZ1 ? [ d3_geo_centroidX1 / d3_geo_centroidZ1, d3_geo_centroidY1 / d3_geo_centroidZ1 ] : d3_geo_centroidZ0 ? [ d3_geo_centroidX0 / d3_geo_centroidZ0, d3_geo_centroidY0 / d3_geo_centroidZ0 ] : [ NaN, NaN ];\n    };\n    path.bounds = function(object) {\n      d3_geo_pathBoundsX1 = d3_geo_pathBoundsY1 = -(d3_geo_pathBoundsX0 = d3_geo_pathBoundsY0 = Infinity);\n      d3.geo.stream(object, projectStream(d3_geo_pathBounds));\n      return [ [ d3_geo_pathBoundsX0, d3_geo_pathBoundsY0 ], [ d3_geo_pathBoundsX1, d3_geo_pathBoundsY1 ] ];\n    };\n    path.projection = function(_) {\n      if (!arguments.length) return projection;\n      projectStream = (projection = _) ? _.stream || d3_geo_pathProjectStream(_) : d3_identity;\n      return reset();\n    };\n    path.context = function(_) {\n      if (!arguments.length) return context;\n      contextStream = (context = _) == null ? new d3_geo_pathBuffer() : new d3_geo_pathContext(_);\n      if (typeof pointRadius !== \"function\") contextStream.pointRadius(pointRadius);\n      return reset();\n    };\n    path.pointRadius = function(_) {\n      if (!arguments.length) return pointRadius;\n      pointRadius = typeof _ === \"function\" ? _ : (contextStream.pointRadius(+_), +_);\n      return path;\n    };\n    function reset() {\n      cacheStream = null;\n      return path;\n    }\n    return path.projection(d3.geo.albersUsa()).context(null);\n  };\n  function d3_geo_pathProjectStream(project) {\n    var resample = d3_geo_resample(function(x, y) {\n      return project([ x * d3_degrees, y * d3_degrees ]);\n    });\n    return function(stream) {\n      return d3_geo_projectionRadians(resample(stream));\n    };\n  }\n  d3.geo.transform = function(methods) {\n    return {\n      stream: function(stream) {\n        var transform = new d3_geo_transform(stream);\n        for (var k in methods) transform[k] = methods[k];\n        return transform;\n      }\n    };\n  };\n  function d3_geo_transform(stream) {\n    this.stream = stream;\n  }\n  d3_geo_transform.prototype = {\n    point: function(x, y) {\n      this.stream.point(x, y);\n    },\n    sphere: function() {\n      this.stream.sphere();\n    },\n    lineStart: function() {\n      this.stream.lineStart();\n    },\n    lineEnd: function() {\n      this.stream.lineEnd();\n    },\n    polygonStart: function() {\n      this.stream.polygonStart();\n    },\n    polygonEnd: function() {\n      this.stream.polygonEnd();\n    }\n  };\n  function d3_geo_transformPoint(stream, point) {\n    return {\n      point: point,\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  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, stream;\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(output) {\n      if (stream) stream.valid = false;\n      stream = d3_geo_projectionRadians(preclip(rotate, projectResample(postclip(output))));\n      stream.valid = true;\n      return 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 invalidate();\n    };\n    projection.clipExtent = function(_) {\n      if (!arguments.length) return clipExtent;\n      clipExtent = _;\n      postclip = _ ? d3_geo_clipExtent(_[0][0], _[0][1], _[1][0], _[1][1]) : d3_identity;\n      return invalidate();\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 invalidate();\n    }\n    function invalidate() {\n      if (stream) stream.valid = false, stream = null;\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_projectionRadians(stream) {\n    return d3_geo_transformPoint(stream, function(x, y) {\n      stream.point(x * d3_radians, y * d3_radians);\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_identityRotation(λ, φ) {\n    return [ λ > π ? λ - τ : λ < -π ? λ + τ : λ, φ ];\n  }\n  d3_geo_identityRotation.invert = d3_geo_equirectangular;\n  function d3_geo_rotation(δλ, δφ, δγ) {\n    return δλ ? δφ || δγ ? d3_geo_compose(d3_geo_rotationλ(δλ), d3_geo_rotationφγ(δφ, δγ)) : d3_geo_rotationλ(δλ) : δφ || δγ ? d3_geo_rotationφγ(δφ, δγ) : d3_geo_identityRotation;\n  }\n  function d3_geo_forwardRotationλ(δλ) {\n    return function(λ, φ) {\n      return λ += δλ, [ λ > π ? λ - τ : λ < -π ? λ + τ : λ, φ ];\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δφ), d3_asin(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δφ), d3_asin(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      var step = direction * precision;\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 * τ;\n      } else {\n        from = radius + direction * τ;\n        to = radius - .5 * step;\n      }\n      for (var point, 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 abs(x % DX) > ε;\n      }).map(x)).concat(d3.range(Math.ceil(y0 / dy) * dy, y1, dy).filter(function(y) {\n        return 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 = 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_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      if (F > 0) {\n        if (φ < -halfπ + ε) φ = -halfπ + ε;\n      } else {\n        if (φ > halfπ - ε) φ = halfπ - ε;\n      }\n      var ρ = 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)) - halfπ ];\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 (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)) - halfπ ];\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    return [ Math.log(Math.tan(π / 4 + φ / 2)), -λ ];\n  }\n  d3_geo_transverseMercator.invert = function(x, y) {\n    return [ -y, 2 * Math.atan(Math.exp(x)) - halfπ ];\n  };\n  (d3.geo.transverseMercator = function() {\n    var projection = d3_geo_mercatorProjection(d3_geo_transverseMercator), center = projection.center, rotate = projection.rotate;\n    projection.center = function(_) {\n      return _ ? center([ -_[1], _[0] ]) : (_ = center(), [ _[1], -_[0] ]);\n    };\n    projection.rotate = function(_) {\n      return _ ? rotate([ _[0], _[1], _.length > 2 ? _[2] + 90 : 90 ]) : (_ = rotate(), \n      [ _[0], _[1], _[2] - 90 ]);\n    };\n    return rotate([ 0, 0, 90 ]);\n  }).raw = d3_geo_transverseMercator;\n  d3.geom = {};\n  function d3_geom_pointX(d) {\n    return d[0];\n  }\n  function d3_geom_pointY(d) {\n    return d[1];\n  }\n  d3.geom.hull = function(vertices) {\n    var x = d3_geom_pointX, y = d3_geom_pointY;\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), i, n = data.length, points = [], flippedPoints = [];\n      for (i = 0; i < n; i++) {\n        points.push([ +fx.call(this, data[i], i), +fy.call(this, data[i], i), i ]);\n      }\n      points.sort(d3_geom_hullOrder);\n      for (i = 0; i < n; i++) flippedPoints.push([ points[i][0], -points[i][1] ]);\n      var upper = d3_geom_hullUpper(points), lower = d3_geom_hullUpper(flippedPoints);\n      var skipLeft = lower[0] === upper[0], skipRight = lower[lower.length - 1] === upper[upper.length - 1], polygon = [];\n      for (i = upper.length - 1; i >= 0; --i) polygon.push(data[points[upper[i]][2]]);\n      for (i = +skipLeft; i < lower.length - skipRight; ++i) polygon.push(data[points[lower[i]][2]]);\n      return polygon;\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_hullUpper(points) {\n    var n = points.length, hull = [ 0, 1 ], hs = 2;\n    for (var i = 2; i < n; i++) {\n      while (hs > 1 && d3_cross2d(points[hull[hs - 2]], points[hull[hs - 1]], points[i]) <= 0) --hs;\n      hull[hs++] = i;\n    }\n    return hull.slice(0, hs);\n  }\n  function d3_geom_hullOrder(a, b) {\n    return a[0] - b[0] || a[1] - b[1];\n  }\n  d3.geom.polygon = function(coordinates) {\n    d3_subclass(coordinates, d3_geom_polygonPrototype);\n    return coordinates;\n  };\n  var d3_geom_polygonPrototype = d3.geom.polygon.prototype = [];\n  d3_geom_polygonPrototype.area = function() {\n    var i = -1, n = this.length, a, b = this[n - 1], area = 0;\n    while (++i < n) {\n      a = b;\n      b = this[i];\n      area += a[1] * b[0] - a[0] * b[1];\n    }\n    return area * .5;\n  };\n  d3_geom_polygonPrototype.centroid = function(k) {\n    var i = -1, n = this.length, x = 0, y = 0, a, b = this[n - 1], c;\n    if (!arguments.length) k = -1 / (6 * this.area());\n    while (++i < n) {\n      a = b;\n      b = this[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  d3_geom_polygonPrototype.clip = function(subject) {\n    var input, closed = d3_geom_polygonClosed(subject), i = -1, n = this.length - d3_geom_polygonClosed(this), j, m, a = this[n - 1], b, c, d;\n    while (++i < n) {\n      input = subject.slice();\n      subject.length = 0;\n      b = this[i];\n      c = input[(m = input.length - closed) - 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      if (closed) subject.push(subject[0]);\n      a = b;\n    }\n    return subject;\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  function d3_geom_polygonClosed(coordinates) {\n    var a = coordinates[0], b = coordinates[coordinates.length - 1];\n    return !(a[0] - b[0] || a[1] - b[1]);\n  }\n  var d3_geom_voronoiEdges, d3_geom_voronoiCells, d3_geom_voronoiBeaches, d3_geom_voronoiBeachPool = [], d3_geom_voronoiFirstCircle, d3_geom_voronoiCircles, d3_geom_voronoiCirclePool = [];\n  function d3_geom_voronoiBeach() {\n    d3_geom_voronoiRedBlackNode(this);\n    this.edge = this.site = this.circle = null;\n  }\n  function d3_geom_voronoiCreateBeach(site) {\n    var beach = d3_geom_voronoiBeachPool.pop() || new d3_geom_voronoiBeach();\n    beach.site = site;\n    return beach;\n  }\n  function d3_geom_voronoiDetachBeach(beach) {\n    d3_geom_voronoiDetachCircle(beach);\n    d3_geom_voronoiBeaches.remove(beach);\n    d3_geom_voronoiBeachPool.push(beach);\n    d3_geom_voronoiRedBlackNode(beach);\n  }\n  function d3_geom_voronoiRemoveBeach(beach) {\n    var circle = beach.circle, x = circle.x, y = circle.cy, vertex = {\n      x: x,\n      y: y\n    }, previous = beach.P, next = beach.N, disappearing = [ beach ];\n    d3_geom_voronoiDetachBeach(beach);\n    var lArc = previous;\n    while (lArc.circle && abs(x - lArc.circle.x) < ε && abs(y - lArc.circle.cy) < ε) {\n      previous = lArc.P;\n      disappearing.unshift(lArc);\n      d3_geom_voronoiDetachBeach(lArc);\n      lArc = previous;\n    }\n    disappearing.unshift(lArc);\n    d3_geom_voronoiDetachCircle(lArc);\n    var rArc = next;\n    while (rArc.circle && abs(x - rArc.circle.x) < ε && abs(y - rArc.circle.cy) < ε) {\n      next = rArc.N;\n      disappearing.push(rArc);\n      d3_geom_voronoiDetachBeach(rArc);\n      rArc = next;\n    }\n    disappearing.push(rArc);\n    d3_geom_voronoiDetachCircle(rArc);\n    var nArcs = disappearing.length, iArc;\n    for (iArc = 1; iArc < nArcs; ++iArc) {\n      rArc = disappearing[iArc];\n      lArc = disappearing[iArc - 1];\n      d3_geom_voronoiSetEdgeEnd(rArc.edge, lArc.site, rArc.site, vertex);\n    }\n    lArc = disappearing[0];\n    rArc = disappearing[nArcs - 1];\n    rArc.edge = d3_geom_voronoiCreateEdge(lArc.site, rArc.site, null, vertex);\n    d3_geom_voronoiAttachCircle(lArc);\n    d3_geom_voronoiAttachCircle(rArc);\n  }\n  function d3_geom_voronoiAddBeach(site) {\n    var x = site.x, directrix = site.y, lArc, rArc, dxl, dxr, node = d3_geom_voronoiBeaches._;\n    while (node) {\n      dxl = d3_geom_voronoiLeftBreakPoint(node, directrix) - x;\n      if (dxl > ε) node = node.L; else {\n        dxr = x - d3_geom_voronoiRightBreakPoint(node, directrix);\n        if (dxr > ε) {\n          if (!node.R) {\n            lArc = node;\n            break;\n          }\n          node = node.R;\n        } else {\n          if (dxl > -ε) {\n            lArc = node.P;\n            rArc = node;\n          } else if (dxr > -ε) {\n            lArc = node;\n            rArc = node.N;\n          } else {\n            lArc = rArc = node;\n          }\n          break;\n        }\n      }\n    }\n    var newArc = d3_geom_voronoiCreateBeach(site);\n    d3_geom_voronoiBeaches.insert(lArc, newArc);\n    if (!lArc && !rArc) return;\n    if (lArc === rArc) {\n      d3_geom_voronoiDetachCircle(lArc);\n      rArc = d3_geom_voronoiCreateBeach(lArc.site);\n      d3_geom_voronoiBeaches.insert(newArc, rArc);\n      newArc.edge = rArc.edge = d3_geom_voronoiCreateEdge(lArc.site, newArc.site);\n      d3_geom_voronoiAttachCircle(lArc);\n      d3_geom_voronoiAttachCircle(rArc);\n      return;\n    }\n    if (!rArc) {\n      newArc.edge = d3_geom_voronoiCreateEdge(lArc.site, newArc.site);\n      return;\n    }\n    d3_geom_voronoiDetachCircle(lArc);\n    d3_geom_voronoiDetachCircle(rArc);\n    var lSite = lArc.site, ax = lSite.x, ay = lSite.y, bx = site.x - ax, by = site.y - ay, rSite = rArc.site, cx = rSite.x - ax, cy = rSite.y - ay, d = 2 * (bx * cy - by * cx), hb = bx * bx + by * by, hc = cx * cx + cy * cy, vertex = {\n      x: (cy * hb - by * hc) / d + ax,\n      y: (bx * hc - cx * hb) / d + ay\n    };\n    d3_geom_voronoiSetEdgeEnd(rArc.edge, lSite, rSite, vertex);\n    newArc.edge = d3_geom_voronoiCreateEdge(lSite, site, null, vertex);\n    rArc.edge = d3_geom_voronoiCreateEdge(site, rSite, null, vertex);\n    d3_geom_voronoiAttachCircle(lArc);\n    d3_geom_voronoiAttachCircle(rArc);\n  }\n  function d3_geom_voronoiLeftBreakPoint(arc, directrix) {\n    var site = arc.site, rfocx = site.x, rfocy = site.y, pby2 = rfocy - directrix;\n    if (!pby2) return rfocx;\n    var lArc = arc.P;\n    if (!lArc) return -Infinity;\n    site = lArc.site;\n    var lfocx = site.x, lfocy = site.y, plby2 = lfocy - directrix;\n    if (!plby2) return lfocx;\n    var hl = lfocx - rfocx, aby2 = 1 / pby2 - 1 / plby2, b = hl / plby2;\n    if (aby2) return (-b + Math.sqrt(b * b - 2 * aby2 * (hl * hl / (-2 * plby2) - lfocy + plby2 / 2 + rfocy - pby2 / 2))) / aby2 + rfocx;\n    return (rfocx + lfocx) / 2;\n  }\n  function d3_geom_voronoiRightBreakPoint(arc, directrix) {\n    var rArc = arc.N;\n    if (rArc) return d3_geom_voronoiLeftBreakPoint(rArc, directrix);\n    var site = arc.site;\n    return site.y === directrix ? site.x : Infinity;\n  }\n  function d3_geom_voronoiCell(site) {\n    this.site = site;\n    this.edges = [];\n  }\n  d3_geom_voronoiCell.prototype.prepare = function() {\n    var halfEdges = this.edges, iHalfEdge = halfEdges.length, edge;\n    while (iHalfEdge--) {\n      edge = halfEdges[iHalfEdge].edge;\n      if (!edge.b || !edge.a) halfEdges.splice(iHalfEdge, 1);\n    }\n    halfEdges.sort(d3_geom_voronoiHalfEdgeOrder);\n    return halfEdges.length;\n  };\n  function d3_geom_voronoiCloseCells(extent) {\n    var x0 = extent[0][0], x1 = extent[1][0], y0 = extent[0][1], y1 = extent[1][1], x2, y2, x3, y3, cells = d3_geom_voronoiCells, iCell = cells.length, cell, iHalfEdge, halfEdges, nHalfEdges, start, end;\n    while (iCell--) {\n      cell = cells[iCell];\n      if (!cell || !cell.prepare()) continue;\n      halfEdges = cell.edges;\n      nHalfEdges = halfEdges.length;\n      iHalfEdge = 0;\n      while (iHalfEdge < nHalfEdges) {\n        end = halfEdges[iHalfEdge].end(), x3 = end.x, y3 = end.y;\n        start = halfEdges[++iHalfEdge % nHalfEdges].start(), x2 = start.x, y2 = start.y;\n        if (abs(x3 - x2) > ε || abs(y3 - y2) > ε) {\n          halfEdges.splice(iHalfEdge, 0, new d3_geom_voronoiHalfEdge(d3_geom_voronoiCreateBorderEdge(cell.site, end, abs(x3 - x0) < ε && y1 - y3 > ε ? {\n            x: x0,\n            y: abs(x2 - x0) < ε ? y2 : y1\n          } : abs(y3 - y1) < ε && x1 - x3 > ε ? {\n            x: abs(y2 - y1) < ε ? x2 : x1,\n            y: y1\n          } : abs(x3 - x1) < ε && y3 - y0 > ε ? {\n            x: x1,\n            y: abs(x2 - x1) < ε ? y2 : y0\n          } : abs(y3 - y0) < ε && x3 - x0 > ε ? {\n            x: abs(y2 - y0) < ε ? x2 : x0,\n            y: y0\n          } : null), cell.site, null));\n          ++nHalfEdges;\n        }\n      }\n    }\n  }\n  function d3_geom_voronoiHalfEdgeOrder(a, b) {\n    return b.angle - a.angle;\n  }\n  function d3_geom_voronoiCircle() {\n    d3_geom_voronoiRedBlackNode(this);\n    this.x = this.y = this.arc = this.site = this.cy = null;\n  }\n  function d3_geom_voronoiAttachCircle(arc) {\n    var lArc = arc.P, rArc = arc.N;\n    if (!lArc || !rArc) return;\n    var lSite = lArc.site, cSite = arc.site, rSite = rArc.site;\n    if (lSite === rSite) return;\n    var bx = cSite.x, by = cSite.y, ax = lSite.x - bx, ay = lSite.y - by, cx = rSite.x - bx, cy = rSite.y - by;\n    var d = 2 * (ax * cy - ay * cx);\n    if (d >= -ε2) return;\n    var ha = ax * ax + ay * ay, hc = cx * cx + cy * cy, x = (cy * ha - ay * hc) / d, y = (ax * hc - cx * ha) / d, cy = y + by;\n    var circle = d3_geom_voronoiCirclePool.pop() || new d3_geom_voronoiCircle();\n    circle.arc = arc;\n    circle.site = cSite;\n    circle.x = x + bx;\n    circle.y = cy + Math.sqrt(x * x + y * y);\n    circle.cy = cy;\n    arc.circle = circle;\n    var before = null, node = d3_geom_voronoiCircles._;\n    while (node) {\n      if (circle.y < node.y || circle.y === node.y && circle.x <= node.x) {\n        if (node.L) node = node.L; else {\n          before = node.P;\n          break;\n        }\n      } else {\n        if (node.R) node = node.R; else {\n          before = node;\n          break;\n        }\n      }\n    }\n    d3_geom_voronoiCircles.insert(before, circle);\n    if (!before) d3_geom_voronoiFirstCircle = circle;\n  }\n  function d3_geom_voronoiDetachCircle(arc) {\n    var circle = arc.circle;\n    if (circle) {\n      if (!circle.P) d3_geom_voronoiFirstCircle = circle.N;\n      d3_geom_voronoiCircles.remove(circle);\n      d3_geom_voronoiCirclePool.push(circle);\n      d3_geom_voronoiRedBlackNode(circle);\n      arc.circle = null;\n    }\n  }\n  function d3_geom_voronoiClipEdges(extent) {\n    var edges = d3_geom_voronoiEdges, clip = d3_geom_clipLine(extent[0][0], extent[0][1], extent[1][0], extent[1][1]), i = edges.length, e;\n    while (i--) {\n      e = edges[i];\n      if (!d3_geom_voronoiConnectEdge(e, extent) || !clip(e) || abs(e.a.x - e.b.x) < ε && abs(e.a.y - e.b.y) < ε) {\n        e.a = e.b = null;\n        edges.splice(i, 1);\n      }\n    }\n  }\n  function d3_geom_voronoiConnectEdge(edge, extent) {\n    var vb = edge.b;\n    if (vb) return true;\n    var va = edge.a, x0 = extent[0][0], x1 = extent[1][0], y0 = extent[0][1], y1 = extent[1][1], lSite = edge.l, rSite = edge.r, lx = lSite.x, ly = lSite.y, rx = rSite.x, ry = rSite.y, fx = (lx + rx) / 2, fy = (ly + ry) / 2, fm, fb;\n    if (ry === ly) {\n      if (fx < x0 || fx >= x1) return;\n      if (lx > rx) {\n        if (!va) va = {\n          x: fx,\n          y: y0\n        }; else if (va.y >= y1) return;\n        vb = {\n          x: fx,\n          y: y1\n        };\n      } else {\n        if (!va) va = {\n          x: fx,\n          y: y1\n        }; else if (va.y < y0) return;\n        vb = {\n          x: fx,\n          y: y0\n        };\n      }\n    } else {\n      fm = (lx - rx) / (ry - ly);\n      fb = fy - fm * fx;\n      if (fm < -1 || fm > 1) {\n        if (lx > rx) {\n          if (!va) va = {\n            x: (y0 - fb) / fm,\n            y: y0\n          }; else if (va.y >= y1) return;\n          vb = {\n            x: (y1 - fb) / fm,\n            y: y1\n          };\n        } else {\n          if (!va) va = {\n            x: (y1 - fb) / fm,\n            y: y1\n          }; else if (va.y < y0) return;\n          vb = {\n            x: (y0 - fb) / fm,\n            y: y0\n          };\n        }\n      } else {\n        if (ly < ry) {\n          if (!va) va = {\n            x: x0,\n            y: fm * x0 + fb\n          }; else if (va.x >= x1) return;\n          vb = {\n            x: x1,\n            y: fm * x1 + fb\n          };\n        } else {\n          if (!va) va = {\n            x: x1,\n            y: fm * x1 + fb\n          }; else if (va.x < x0) return;\n          vb = {\n            x: x0,\n            y: fm * x0 + fb\n          };\n        }\n      }\n    }\n    edge.a = va;\n    edge.b = vb;\n    return true;\n  }\n  function d3_geom_voronoiEdge(lSite, rSite) {\n    this.l = lSite;\n    this.r = rSite;\n    this.a = this.b = null;\n  }\n  function d3_geom_voronoiCreateEdge(lSite, rSite, va, vb) {\n    var edge = new d3_geom_voronoiEdge(lSite, rSite);\n    d3_geom_voronoiEdges.push(edge);\n    if (va) d3_geom_voronoiSetEdgeEnd(edge, lSite, rSite, va);\n    if (vb) d3_geom_voronoiSetEdgeEnd(edge, rSite, lSite, vb);\n    d3_geom_voronoiCells[lSite.i].edges.push(new d3_geom_voronoiHalfEdge(edge, lSite, rSite));\n    d3_geom_voronoiCells[rSite.i].edges.push(new d3_geom_voronoiHalfEdge(edge, rSite, lSite));\n    return edge;\n  }\n  function d3_geom_voronoiCreateBorderEdge(lSite, va, vb) {\n    var edge = new d3_geom_voronoiEdge(lSite, null);\n    edge.a = va;\n    edge.b = vb;\n    d3_geom_voronoiEdges.push(edge);\n    return edge;\n  }\n  function d3_geom_voronoiSetEdgeEnd(edge, lSite, rSite, vertex) {\n    if (!edge.a && !edge.b) {\n      edge.a = vertex;\n      edge.l = lSite;\n      edge.r = rSite;\n    } else if (edge.l === rSite) {\n      edge.b = vertex;\n    } else {\n      edge.a = vertex;\n    }\n  }\n  function d3_geom_voronoiHalfEdge(edge, lSite, rSite) {\n    var va = edge.a, vb = edge.b;\n    this.edge = edge;\n    this.site = lSite;\n    this.angle = rSite ? Math.atan2(rSite.y - lSite.y, rSite.x - lSite.x) : edge.l === lSite ? Math.atan2(vb.x - va.x, va.y - vb.y) : Math.atan2(va.x - vb.x, vb.y - va.y);\n  }\n  d3_geom_voronoiHalfEdge.prototype = {\n    start: function() {\n      return this.edge.l === this.site ? this.edge.a : this.edge.b;\n    },\n    end: function() {\n      return this.edge.l === this.site ? this.edge.b : this.edge.a;\n    }\n  };\n  function d3_geom_voronoiRedBlackTree() {\n    this._ = null;\n  }\n  function d3_geom_voronoiRedBlackNode(node) {\n    node.U = node.C = node.L = node.R = node.P = node.N = null;\n  }\n  d3_geom_voronoiRedBlackTree.prototype = {\n    insert: function(after, node) {\n      var parent, grandpa, uncle;\n      if (after) {\n        node.P = after;\n        node.N = after.N;\n        if (after.N) after.N.P = node;\n        after.N = node;\n        if (after.R) {\n          after = after.R;\n          while (after.L) after = after.L;\n          after.L = node;\n        } else {\n          after.R = node;\n        }\n        parent = after;\n      } else if (this._) {\n        after = d3_geom_voronoiRedBlackFirst(this._);\n        node.P = null;\n        node.N = after;\n        after.P = after.L = node;\n        parent = after;\n      } else {\n        node.P = node.N = null;\n        this._ = node;\n        parent = null;\n      }\n      node.L = node.R = null;\n      node.U = parent;\n      node.C = true;\n      after = node;\n      while (parent && parent.C) {\n        grandpa = parent.U;\n        if (parent === grandpa.L) {\n          uncle = grandpa.R;\n          if (uncle && uncle.C) {\n            parent.C = uncle.C = false;\n            grandpa.C = true;\n            after = grandpa;\n          } else {\n            if (after === parent.R) {\n              d3_geom_voronoiRedBlackRotateLeft(this, parent);\n              after = parent;\n              parent = after.U;\n            }\n            parent.C = false;\n            grandpa.C = true;\n            d3_geom_voronoiRedBlackRotateRight(this, grandpa);\n          }\n        } else {\n          uncle = grandpa.L;\n          if (uncle && uncle.C) {\n            parent.C = uncle.C = false;\n            grandpa.C = true;\n            after = grandpa;\n          } else {\n            if (after === parent.L) {\n              d3_geom_voronoiRedBlackRotateRight(this, parent);\n              after = parent;\n              parent = after.U;\n            }\n            parent.C = false;\n            grandpa.C = true;\n            d3_geom_voronoiRedBlackRotateLeft(this, grandpa);\n          }\n        }\n        parent = after.U;\n      }\n      this._.C = false;\n    },\n    remove: function(node) {\n      if (node.N) node.N.P = node.P;\n      if (node.P) node.P.N = node.N;\n      node.N = node.P = null;\n      var parent = node.U, sibling, left = node.L, right = node.R, next, red;\n      if (!left) next = right; else if (!right) next = left; else next = d3_geom_voronoiRedBlackFirst(right);\n      if (parent) {\n        if (parent.L === node) parent.L = next; else parent.R = next;\n      } else {\n        this._ = next;\n      }\n      if (left && right) {\n        red = next.C;\n        next.C = node.C;\n        next.L = left;\n        left.U = next;\n        if (next !== right) {\n          parent = next.U;\n          next.U = node.U;\n          node = next.R;\n          parent.L = node;\n          next.R = right;\n          right.U = next;\n        } else {\n          next.U = parent;\n          parent = next;\n          node = next.R;\n        }\n      } else {\n        red = node.C;\n        node = next;\n      }\n      if (node) node.U = parent;\n      if (red) return;\n      if (node && node.C) {\n        node.C = false;\n        return;\n      }\n      do {\n        if (node === this._) break;\n        if (node === parent.L) {\n          sibling = parent.R;\n          if (sibling.C) {\n            sibling.C = false;\n            parent.C = true;\n            d3_geom_voronoiRedBlackRotateLeft(this, parent);\n            sibling = parent.R;\n          }\n          if (sibling.L && sibling.L.C || sibling.R && sibling.R.C) {\n            if (!sibling.R || !sibling.R.C) {\n              sibling.L.C = false;\n              sibling.C = true;\n              d3_geom_voronoiRedBlackRotateRight(this, sibling);\n              sibling = parent.R;\n            }\n            sibling.C = parent.C;\n            parent.C = sibling.R.C = false;\n            d3_geom_voronoiRedBlackRotateLeft(this, parent);\n            node = this._;\n            break;\n          }\n        } else {\n          sibling = parent.L;\n          if (sibling.C) {\n            sibling.C = false;\n            parent.C = true;\n            d3_geom_voronoiRedBlackRotateRight(this, parent);\n            sibling = parent.L;\n          }\n          if (sibling.L && sibling.L.C || sibling.R && sibling.R.C) {\n            if (!sibling.L || !sibling.L.C) {\n              sibling.R.C = false;\n              sibling.C = true;\n              d3_geom_voronoiRedBlackRotateLeft(this, sibling);\n              sibling = parent.L;\n            }\n            sibling.C = parent.C;\n            parent.C = sibling.L.C = false;\n            d3_geom_voronoiRedBlackRotateRight(this, parent);\n            node = this._;\n            break;\n          }\n        }\n        sibling.C = true;\n        node = parent;\n        parent = parent.U;\n      } while (!node.C);\n      if (node) node.C = false;\n    }\n  };\n  function d3_geom_voronoiRedBlackRotateLeft(tree, node) {\n    var p = node, q = node.R, parent = p.U;\n    if (parent) {\n      if (parent.L === p) parent.L = q; else parent.R = q;\n    } else {\n      tree._ = q;\n    }\n    q.U = parent;\n    p.U = q;\n    p.R = q.L;\n    if (p.R) p.R.U = p;\n    q.L = p;\n  }\n  function d3_geom_voronoiRedBlackRotateRight(tree, node) {\n    var p = node, q = node.L, parent = p.U;\n    if (parent) {\n      if (parent.L === p) parent.L = q; else parent.R = q;\n    } else {\n      tree._ = q;\n    }\n    q.U = parent;\n    p.U = q;\n    p.L = q.R;\n    if (p.L) p.L.U = p;\n    q.R = p;\n  }\n  function d3_geom_voronoiRedBlackFirst(node) {\n    while (node.L) node = node.L;\n    return node;\n  }\n  function d3_geom_voronoi(sites, bbox) {\n    var site = sites.sort(d3_geom_voronoiVertexOrder).pop(), x0, y0, circle;\n    d3_geom_voronoiEdges = [];\n    d3_geom_voronoiCells = new Array(sites.length);\n    d3_geom_voronoiBeaches = new d3_geom_voronoiRedBlackTree();\n    d3_geom_voronoiCircles = new d3_geom_voronoiRedBlackTree();\n    while (true) {\n      circle = d3_geom_voronoiFirstCircle;\n      if (site && (!circle || site.y < circle.y || site.y === circle.y && site.x < circle.x)) {\n        if (site.x !== x0 || site.y !== y0) {\n          d3_geom_voronoiCells[site.i] = new d3_geom_voronoiCell(site);\n          d3_geom_voronoiAddBeach(site);\n          x0 = site.x, y0 = site.y;\n        }\n        site = sites.pop();\n      } else if (circle) {\n        d3_geom_voronoiRemoveBeach(circle.arc);\n      } else {\n        break;\n      }\n    }\n    if (bbox) d3_geom_voronoiClipEdges(bbox), d3_geom_voronoiCloseCells(bbox);\n    var diagram = {\n      cells: d3_geom_voronoiCells,\n      edges: d3_geom_voronoiEdges\n    };\n    d3_geom_voronoiBeaches = d3_geom_voronoiCircles = d3_geom_voronoiEdges = d3_geom_voronoiCells = null;\n    return diagram;\n  }\n  function d3_geom_voronoiVertexOrder(a, b) {\n    return b.y - a.y || b.x - a.x;\n  }\n  d3.geom.voronoi = function(points) {\n    var x = d3_geom_pointX, y = d3_geom_pointY, fx = x, fy = y, clipExtent = d3_geom_voronoiClipExtent;\n    if (points) return voronoi(points);\n    function voronoi(data) {\n      var polygons = new Array(data.length), x0 = clipExtent[0][0], y0 = clipExtent[0][1], x1 = clipExtent[1][0], y1 = clipExtent[1][1];\n      d3_geom_voronoi(sites(data), clipExtent).cells.forEach(function(cell, i) {\n        var edges = cell.edges, site = cell.site, polygon = polygons[i] = edges.length ? edges.map(function(e) {\n          var s = e.start();\n          return [ s.x, s.y ];\n        }) : site.x >= x0 && site.x <= x1 && site.y >= y0 && site.y <= y1 ? [ [ x0, y1 ], [ x1, y1 ], [ x1, y0 ], [ x0, y0 ] ] : [];\n        polygon.point = data[i];\n      });\n      return polygons;\n    }\n    function sites(data) {\n      return data.map(function(d, i) {\n        return {\n          x: Math.round(fx(d, i) / ε) * ε,\n          y: Math.round(fy(d, i) / ε) * ε,\n          i: i\n        };\n      });\n    }\n    voronoi.links = function(data) {\n      return d3_geom_voronoi(sites(data)).edges.filter(function(edge) {\n        return edge.l && edge.r;\n      }).map(function(edge) {\n        return {\n          source: data[edge.l.i],\n          target: data[edge.r.i]\n        };\n      });\n    };\n    voronoi.triangles = function(data) {\n      var triangles = [];\n      d3_geom_voronoi(sites(data)).cells.forEach(function(cell, i) {\n        var site = cell.site, edges = cell.edges.sort(d3_geom_voronoiHalfEdgeOrder), j = -1, m = edges.length, e0, s0, e1 = edges[m - 1].edge, s1 = e1.l === site ? e1.r : e1.l;\n        while (++j < m) {\n          e0 = e1;\n          s0 = s1;\n          e1 = edges[j].edge;\n          s1 = e1.l === site ? e1.r : e1.l;\n          if (i < s0.i && i < s1.i && d3_geom_voronoiTriangleArea(site, s0, s1) < 0) {\n            triangles.push([ data[i], data[s0.i], data[s1.i] ]);\n          }\n        }\n      });\n      return triangles;\n    };\n    voronoi.x = function(_) {\n      return arguments.length ? (fx = d3_functor(x = _), voronoi) : x;\n    };\n    voronoi.y = function(_) {\n      return arguments.length ? (fy = d3_functor(y = _), voronoi) : y;\n    };\n    voronoi.clipExtent = function(_) {\n      if (!arguments.length) return clipExtent === d3_geom_voronoiClipExtent ? null : clipExtent;\n      clipExtent = _ == null ? d3_geom_voronoiClipExtent : _;\n      return voronoi;\n    };\n    voronoi.size = function(_) {\n      if (!arguments.length) return clipExtent === d3_geom_voronoiClipExtent ? null : clipExtent && clipExtent[1];\n      return voronoi.clipExtent(_ && [ [ 0, 0 ], _ ]);\n    };\n    return voronoi;\n  };\n  var d3_geom_voronoiClipExtent = [ [ -1e6, -1e6 ], [ 1e6, 1e6 ] ];\n  function d3_geom_voronoiTriangleArea(a, b, c) {\n    return (a.x - c.x) * (b.y - a.y) - (a.x - b.x) * (c.y - a.y);\n  }\n  d3.geom.delaunay = function(vertices) {\n    return d3.geom.voronoi().triangles(vertices);\n  };\n  d3.geom.quadtree = function(points, x1, y1, x2, y2) {\n    var x = d3_geom_pointX, y = d3_geom_pointY, 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 (abs(nx - x) + 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 xm = (x1 + x2) * .5, ym = (y1 + y2) * .5, right = x >= xm, below = y >= ym, i = below << 1 | right;\n        n.leaf = false;\n        n = n.nodes[i] || (n.nodes[i] = d3_geom_quadtreeNode());\n        if (right) x1 = xm; else x2 = xm;\n        if (below) y1 = ym; else y2 = ym;\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      root.find = function(point) {\n        return d3_geom_quadtreeFind(root, point[0], point[1], 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.extent = function(_) {\n      if (!arguments.length) return x1 == null ? null : [ [ x1, y1 ], [ x2, y2 ] ];\n      if (_ == null) x1 = y1 = x2 = y2 = null; else x1 = +_[0][0], y1 = +_[0][1], x2 = +_[1][0], \n      y2 = +_[1][1];\n      return quadtree;\n    };\n    quadtree.size = function(_) {\n      if (!arguments.length) return x1 == null ? null : [ x2 - x1, y2 - y1 ];\n      if (_ == null) x1 = y1 = x2 = y2 = null; else x1 = y1 = 0, x2 = +_[0], y2 = +_[1];\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  function d3_geom_quadtreeFind(root, x, y, x0, y0, x3, y3) {\n    var minDistance2 = Infinity, closestPoint;\n    (function find(node, x1, y1, x2, y2) {\n      if (x1 > x3 || y1 > y3 || x2 < x0 || y2 < y0) return;\n      if (point = node.point) {\n        var point, dx = x - node.x, dy = y - node.y, distance2 = dx * dx + dy * dy;\n        if (distance2 < minDistance2) {\n          var distance = Math.sqrt(minDistance2 = distance2);\n          x0 = x - distance, y0 = y - distance;\n          x3 = x + distance, y3 = y + distance;\n          closestPoint = point;\n        }\n      }\n      var children = node.nodes, xm = (x1 + x2) * .5, ym = (y1 + y2) * .5, right = x >= xm, below = y >= ym;\n      for (var i = below << 1 | right, j = i + 4; i < j; ++i) {\n        if (node = children[i & 3]) switch (i & 3) {\n         case 0:\n          find(node, x1, y1, xm, ym);\n          break;\n\n         case 1:\n          find(node, xm, y1, x2, ym);\n          break;\n\n         case 2:\n          find(node, x1, ym, xm, y2);\n          break;\n\n         case 3:\n          find(node, xm, ym, x2, y2);\n          break;\n        }\n      }\n    })(root, x0, y0, x3, y3);\n    return closestPoint;\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.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_interpolate(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.interpolateNumber = d3_interpolateNumber;\n  function d3_interpolateNumber(a, b) {\n    a = +a, b = +b;\n    return function(t) {\n      return a * (1 - t) + b * t;\n    };\n  }\n  d3.interpolateString = d3_interpolateString;\n  function d3_interpolateString(a, b) {\n    var bi = d3_interpolate_numberA.lastIndex = d3_interpolate_numberB.lastIndex = 0, am, bm, bs, i = -1, s = [], q = [];\n    a = a + \"\", b = b + \"\";\n    while ((am = d3_interpolate_numberA.exec(a)) && (bm = d3_interpolate_numberB.exec(b))) {\n      if ((bs = bm.index) > bi) {\n        bs = b.slice(bi, bs);\n        if (s[i]) s[i] += bs; else s[++i] = bs;\n      }\n      if ((am = am[0]) === (bm = bm[0])) {\n        if (s[i]) s[i] += bm; else s[++i] = bm;\n      } else {\n        s[++i] = null;\n        q.push({\n          i: i,\n          x: d3_interpolateNumber(am, bm)\n        });\n      }\n      bi = d3_interpolate_numberB.lastIndex;\n    }\n    if (bi < b.length) {\n      bs = b.slice(bi);\n      if (s[i]) s[i] += bs; else s[++i] = bs;\n    }\n    return s.length < 2 ? q[0] ? (b = q[0].x, function(t) {\n      return b(t) + \"\";\n    }) : function() {\n      return b;\n    } : (b = q.length, function(t) {\n      for (var i = 0, o; i < b; ++i) s[(o = q[i]).i] = o.x(t);\n      return s.join(\"\");\n    });\n  }\n  var d3_interpolate_numberA = /[-+]?(?:\\d+\\.?\\d*|\\.?\\d+)(?:[eE][-+]?\\d+)?/g, d3_interpolate_numberB = new RegExp(d3_interpolate_numberA.source, \"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  d3.interpolators = [ function(a, b) {\n    var t = typeof b;\n    return (t === \"string\" ? d3_rgb_names.has(b.toLowerCase()) || /^(#|rgb\\(|hsl\\()/i.test(b) ? d3_interpolateRgb : d3_interpolateString : b instanceof d3_color ? d3_interpolateRgb : Array.isArray(b) ? d3_interpolateArray : t === \"object\" && isNaN(b) ? d3_interpolateObject : 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.slice(0, i) : name, m = i >= 0 ? name.slice(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, d3_arraySlice.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 * halfπ);\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 / τ * 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) * τ / 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 (isNaN(bc)) bc = 0, ac = isNaN(ac) ? b.c : ac;\n    if (isNaN(bh)) bh = 0, ah = isNaN(ah) ? b.h : ah; else 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 ah = a.h, as = a.s, al = a.l, bh = b.h - ah, bs = b.s - as, bl = b.l - al;\n    if (isNaN(bs)) bs = 0, as = isNaN(as) ? b.s : as;\n    if (isNaN(bh)) bh = 0, ah = isNaN(ah) ? b.h : ah; else if (bh > 180) bh -= 360; else if (bh < -180) bh += 360;\n    return function(t) {\n      return d3_hsl_rgb(ah + bh * t, as + bs * t, al + bl * 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  d3.transform = function(string) {\n    var g = d3_document.createElementNS(d3.ns.prefix.svg, \"g\");\n    return (d3.transform = function(string) {\n      if (string != null) {\n        g.setAttribute(\"transform\", string);\n        var t = g.transform.baseVal.consolidate();\n      }\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.interpolateTransform = d3_interpolateTransform;\n  function d3_interpolateTransformPop(s) {\n    return s.length ? s.pop() + \",\" : \"\";\n  }\n  function d3_interpolateTranslate(ta, tb, s, q) {\n    if (ta[0] !== tb[0] || ta[1] !== tb[1]) {\n      var i = s.push(\"translate(\", null, \",\", null, \")\");\n      q.push({\n        i: i - 4,\n        x: d3_interpolateNumber(ta[0], tb[0])\n      }, {\n        i: i - 2,\n        x: d3_interpolateNumber(ta[1], tb[1])\n      });\n    } else if (tb[0] || tb[1]) {\n      s.push(\"translate(\" + tb + \")\");\n    }\n  }\n  function d3_interpolateRotate(ra, rb, s, q) {\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(d3_interpolateTransformPop(s) + \"rotate(\", null, \")\") - 2,\n        x: d3_interpolateNumber(ra, rb)\n      });\n    } else if (rb) {\n      s.push(d3_interpolateTransformPop(s) + \"rotate(\" + rb + \")\");\n    }\n  }\n  function d3_interpolateSkew(wa, wb, s, q) {\n    if (wa !== wb) {\n      q.push({\n        i: s.push(d3_interpolateTransformPop(s) + \"skewX(\", null, \")\") - 2,\n        x: d3_interpolateNumber(wa, wb)\n      });\n    } else if (wb) {\n      s.push(d3_interpolateTransformPop(s) + \"skewX(\" + wb + \")\");\n    }\n  }\n  function d3_interpolateScale(ka, kb, s, q) {\n    if (ka[0] !== kb[0] || ka[1] !== kb[1]) {\n      var i = s.push(d3_interpolateTransformPop(s) + \"scale(\", null, \",\", null, \")\");\n      q.push({\n        i: i - 4,\n        x: d3_interpolateNumber(ka[0], kb[0])\n      }, {\n        i: i - 2,\n        x: d3_interpolateNumber(ka[1], kb[1])\n      });\n    } else if (kb[0] !== 1 || kb[1] !== 1) {\n      s.push(d3_interpolateTransformPop(s) + \"scale(\" + kb + \")\");\n    }\n  }\n  function d3_interpolateTransform(a, b) {\n    var s = [], q = [];\n    a = d3.transform(a), b = d3.transform(b);\n    d3_interpolateTranslate(a.translate, b.translate, s, q);\n    d3_interpolateRotate(a.rotate, b.rotate, s, q);\n    d3_interpolateSkew(a.skew, b.skew, s, q);\n    d3_interpolateScale(a.scale, b.scale, s, q);\n    a = b = null;\n    return function(t) {\n      var i = -1, n = q.length, o;\n      while (++i < n) s[(o = q[i]).i] = o.x(t);\n      return s.join(\"\");\n    };\n  }\n  function d3_uninterpolateNumber(a, b) {\n    b = (b -= a = +a) || 1 / b;\n    return function(x) {\n      return (x - a) / b;\n    };\n  }\n  function d3_uninterpolateClamp(a, b) {\n    b = (b -= a = +a) || 1 / b;\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 = (τ - 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: groupSums[di]\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\"), timer, size = [ 1, 1 ], drag, alpha, friction = .9, linkDistance = d3_layout_forceLinkDistance, linkStrength = d3_layout_forceLinkStrength, charge = -30, chargeDistance2 = d3_layout_forceChargeDistance2, gravity = .1, theta2 = .64, 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, dw = x2 - x1, dn = dx * dx + dy * dy;\n          if (dw * dw / theta2 < dn) {\n            if (dn < chargeDistance2) {\n              var k = quad.charge / dn;\n              node.px -= dx * k;\n              node.py -= dy * k;\n            }\n            return true;\n          }\n          if (quad.point && dn && dn < chargeDistance2) {\n            var k = quad.pointCharge / 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        timer = null;\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 / (s.weight + t.weight) : .5);\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.chargeDistance = function(x) {\n      if (!arguments.length) return Math.sqrt(chargeDistance2);\n      chargeDistance2 = 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 Math.sqrt(theta2);\n      theta2 = x * 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) {\n          alpha = x;\n        } else {\n          timer.c = null, timer.t = NaN, timer = null;\n          event.end({\n            type: \"end\",\n            alpha: alpha = 0\n          });\n        }\n      } else if (x > 0) {\n        event.start({\n          type: \"start\",\n          alpha: alpha = x\n        });\n        timer = d3_timer(force.tick);\n      }\n      return force;\n    };\n    force.start = function() {\n      var i, 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        if (!neighbors) {\n          neighbors = new Array(n);\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        var candidates = neighbors[i], j = -1, l = candidates.length, x;\n        while (++j < l) if (!isNaN(x = candidates[j][dimension])) return x;\n        return Math.random() * size;\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, d3_layout_forceChargeDistance2 = Infinity;\n  d3.layout.hierarchy = function() {\n    var sort = d3_layout_hierarchySort, children = d3_layout_hierarchyChildren, value = d3_layout_hierarchyValue;\n    function hierarchy(root) {\n      var stack = [ root ], nodes = [], node;\n      root.depth = 0;\n      while ((node = stack.pop()) != null) {\n        nodes.push(node);\n        if ((childs = children.call(hierarchy, node, node.depth)) && (n = childs.length)) {\n          var n, childs, child;\n          while (--n >= 0) {\n            stack.push(child = childs[n]);\n            child.parent = node;\n            child.depth = node.depth + 1;\n          }\n          if (value) node.value = 0;\n          node.children = childs;\n        } else {\n          if (value) node.value = +value.call(hierarchy, node, node.depth) || 0;\n          delete node.children;\n        }\n      }\n      d3_layout_hierarchyVisitAfter(root, function(node) {\n        var childs, parent;\n        if (sort && (childs = node.children)) childs.sort(sort);\n        if (value && (parent = node.parent)) parent.value += node.value;\n      });\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      if (value) {\n        d3_layout_hierarchyVisitBefore(root, function(node) {\n          if (node.children) node.value = 0;\n        });\n        d3_layout_hierarchyVisitAfter(root, function(node) {\n          var parent;\n          if (!node.children) node.value = +value.call(hierarchy, node, node.depth) || 0;\n          if (parent = node.parent) parent.value += node.value;\n        });\n      }\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_hierarchyVisitBefore(node, callback) {\n    var nodes = [ node ];\n    while ((node = nodes.pop()) != null) {\n      callback(node);\n      if ((children = node.children) && (n = children.length)) {\n        var n, children;\n        while (--n >= 0) nodes.push(children[n]);\n      }\n    }\n  }\n  function d3_layout_hierarchyVisitAfter(node, callback) {\n    var nodes = [ node ], nodes2 = [];\n    while ((node = nodes.pop()) != null) {\n      nodes2.push(node);\n      if ((children = node.children) && (n = children.length)) {\n        var i = -1, n, children;\n        while (++i < n) nodes.push(children[i]);\n      }\n    }\n    while ((node = nodes2.pop()) != null) {\n      callback(node);\n    }\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 = τ, padAngle = 0;\n    function pie(data) {\n      var n = data.length, values = data.map(function(d, i) {\n        return +value.call(pie, d, i);\n      }), a = +(typeof startAngle === \"function\" ? startAngle.apply(this, arguments) : startAngle), da = (typeof endAngle === \"function\" ? endAngle.apply(this, arguments) : endAngle) - a, p = Math.min(Math.abs(da) / n, +(typeof padAngle === \"function\" ? padAngle.apply(this, arguments) : padAngle)), pa = p * (da < 0 ? -1 : 1), sum = d3.sum(values), k = sum ? (da - n * pa) / sum : 0, index = d3.range(n), arcs = [], v;\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      index.forEach(function(i) {\n        arcs[i] = {\n          data: data[i],\n          value: v = values[i],\n          startAngle: a,\n          endAngle: a += v * k + pa,\n          padAngle: p\n        };\n      });\n      return arcs;\n    }\n    pie.value = function(_) {\n      if (!arguments.length) return value;\n      value = _;\n      return pie;\n    };\n    pie.sort = function(_) {\n      if (!arguments.length) return sort;\n      sort = _;\n      return pie;\n    };\n    pie.startAngle = function(_) {\n      if (!arguments.length) return startAngle;\n      startAngle = _;\n      return pie;\n    };\n    pie.endAngle = function(_) {\n      if (!arguments.length) return endAngle;\n      endAngle = _;\n      return pie;\n    };\n    pie.padAngle = function(_) {\n      if (!arguments.length) return padAngle;\n      padAngle = _;\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      if (!(n = data.length)) return data;\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 m = series[0].length, n, 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.pack = function() {\n    var hierarchy = d3.layout.hierarchy().sort(d3_layout_packSort), padding = 0, size = [ 1, 1 ], radius;\n    function pack(d, i) {\n      var nodes = hierarchy.call(this, d, i), root = nodes[0], w = size[0], h = size[1], r = radius == null ? Math.sqrt : typeof radius === \"function\" ? radius : function() {\n        return radius;\n      };\n      root.x = root.y = 0;\n      d3_layout_hierarchyVisitAfter(root, function(d) {\n        d.r = +r(d.value);\n      });\n      d3_layout_hierarchyVisitAfter(root, d3_layout_packSiblings);\n      if (padding) {\n        var dr = padding * (radius ? 1 : Math.max(2 * root.r / w, 2 * root.r / h)) / 2;\n        d3_layout_hierarchyVisitAfter(root, function(d) {\n          d.r += dr;\n        });\n        d3_layout_hierarchyVisitAfter(root, d3_layout_packSiblings);\n        d3_layout_hierarchyVisitAfter(root, function(d) {\n          d.r -= dr;\n        });\n      }\n      d3_layout_packTransform(root, w / 2, h / 2, radius ? 1 : 1 / Math.max(2 * root.r / w, 2 * root.r / h));\n      return nodes;\n    }\n    pack.size = function(_) {\n      if (!arguments.length) return size;\n      size = _;\n      return pack;\n    };\n    pack.radius = function(_) {\n      if (!arguments.length) return radius;\n      radius = _ == null || typeof _ === \"function\" ? _ : +_;\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 .999 * dr * dr > dx * dx + dy * dy;\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.tree = function() {\n    var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ], nodeSize = null;\n    function tree(d, i) {\n      var nodes = hierarchy.call(this, d, i), root0 = nodes[0], root1 = wrapTree(root0);\n      d3_layout_hierarchyVisitAfter(root1, firstWalk), root1.parent.m = -root1.z;\n      d3_layout_hierarchyVisitBefore(root1, secondWalk);\n      if (nodeSize) d3_layout_hierarchyVisitBefore(root0, sizeNode); else {\n        var left = root0, right = root0, bottom = root0;\n        d3_layout_hierarchyVisitBefore(root0, function(node) {\n          if (node.x < left.x) left = node;\n          if (node.x > right.x) right = node;\n          if (node.depth > bottom.depth) bottom = node;\n        });\n        var tx = separation(left, right) / 2 - left.x, kx = size[0] / (right.x + separation(right, left) / 2 + tx), ky = size[1] / (bottom.depth || 1);\n        d3_layout_hierarchyVisitBefore(root0, function(node) {\n          node.x = (node.x + tx) * kx;\n          node.y = node.depth * ky;\n        });\n      }\n      return nodes;\n    }\n    function wrapTree(root0) {\n      var root1 = {\n        A: null,\n        children: [ root0 ]\n      }, queue = [ root1 ], node1;\n      while ((node1 = queue.pop()) != null) {\n        for (var children = node1.children, child, i = 0, n = children.length; i < n; ++i) {\n          queue.push((children[i] = child = {\n            _: children[i],\n            parent: node1,\n            children: (child = children[i].children) && child.slice() || [],\n            A: null,\n            a: null,\n            z: 0,\n            m: 0,\n            c: 0,\n            s: 0,\n            t: null,\n            i: i\n          }).a = child);\n        }\n      }\n      return root1.children[0];\n    }\n    function firstWalk(v) {\n      var children = v.children, siblings = v.parent.children, w = v.i ? siblings[v.i - 1] : null;\n      if (children.length) {\n        d3_layout_treeShift(v);\n        var midpoint = (children[0].z + children[children.length - 1].z) / 2;\n        if (w) {\n          v.z = w.z + separation(v._, w._);\n          v.m = v.z - midpoint;\n        } else {\n          v.z = midpoint;\n        }\n      } else if (w) {\n        v.z = w.z + separation(v._, w._);\n      }\n      v.parent.A = apportion(v, w, v.parent.A || siblings[0]);\n    }\n    function secondWalk(v) {\n      v._.x = v.z + v.parent.m;\n      v.m += v.parent.m;\n    }\n    function apportion(v, w, ancestor) {\n      if (w) {\n        var vip = v, vop = v, vim = w, vom = vip.parent.children[0], sip = vip.m, sop = vop.m, sim = vim.m, som = vom.m, 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.a = v;\n          shift = vim.z + sim - vip.z - sip + separation(vim._, vip._);\n          if (shift > 0) {\n            d3_layout_treeMove(d3_layout_treeAncestor(vim, v, ancestor), v, shift);\n            sip += shift;\n            sop += shift;\n          }\n          sim += vim.m;\n          sip += vip.m;\n          som += vom.m;\n          sop += vop.m;\n        }\n        if (vim && !d3_layout_treeRight(vop)) {\n          vop.t = vim;\n          vop.m += sim - sop;\n        }\n        if (vip && !d3_layout_treeLeft(vom)) {\n          vom.t = vip;\n          vom.m += sip - som;\n          ancestor = v;\n        }\n      }\n      return ancestor;\n    }\n    function sizeNode(node) {\n      node.x *= size[0];\n      node.y = node.depth * size[1];\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 nodeSize ? null : size;\n      nodeSize = (size = x) == null ? sizeNode : null;\n      return tree;\n    };\n    tree.nodeSize = function(x) {\n      if (!arguments.length) return nodeSize ? size : null;\n      nodeSize = (size = x) == null ? null : sizeNode;\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(v) {\n    var children = v.children;\n    return children.length ? children[0] : v.t;\n  }\n  function d3_layout_treeRight(v) {\n    var children = v.children, n;\n    return (n = children.length) ? children[n - 1] : v.t;\n  }\n  function d3_layout_treeMove(wm, wp, shift) {\n    var change = shift / (wp.i - wm.i);\n    wp.c -= change;\n    wp.s += shift;\n    wm.c += change;\n    wp.z += shift;\n    wp.m += shift;\n  }\n  function d3_layout_treeShift(v) {\n    var shift = 0, change = 0, children = v.children, i = children.length, w;\n    while (--i >= 0) {\n      w = children[i];\n      w.z += shift;\n      w.m += shift;\n      shift += w.s + (change += w.c);\n    }\n  }\n  function d3_layout_treeAncestor(vim, v, ancestor) {\n    return vim.a.parent === v.parent ? vim.a : ancestor;\n  }\n  d3.layout.cluster = function() {\n    var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ], nodeSize = false;\n    function cluster(d, i) {\n      var nodes = hierarchy.call(this, d, i), root = nodes[0], previousNode, x = 0;\n      d3_layout_hierarchyVisitAfter(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_hierarchyVisitAfter(root, nodeSize ? function(node) {\n        node.x = (node.x - root.x) * size[0];\n        node.y = (root.y - node.y) * size[1];\n      } : 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 nodeSize ? null : size;\n      nodeSize = (size = x) == null;\n      return cluster;\n    };\n    cluster.nodeSize = function(x) {\n      if (!arguments.length) return nodeSize ? size : null;\n      nodeSize = (size = x) != null;\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 = root.y = 0;\n      if (root.value) root.dx = size[0], root.dy = size[1]; else root.dx = root.dy = 0;\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    bates: function(m) {\n      var random = d3.random.irwinHall(m);\n      return function() {\n        return random() / m;\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;\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    domain[i0] = nice.floor(x0);\n    domain[i1] = nice.ceil(x1);\n    return domain;\n  }\n  function d3_scale_niceStep(step) {\n    return step ? {\n      floor: function(x) {\n        return Math.floor(x / step) * step;\n      },\n      ceil: function(x) {\n        return Math.ceil(x / step) * step;\n      }\n    } : d3_scale_niceIdentity;\n  }\n  var d3_scale_niceIdentity = {\n    floor: d3_identity,\n    ceil: d3_identity\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(m) {\n      d3_scale_linearNice(domain, m);\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(domain, m) {\n    d3_scale_nice(domain, d3_scale_niceStep(d3_scale_linearTickRange(domain, m)[2]));\n    d3_scale_nice(domain, d3_scale_niceStep(d3_scale_linearTickRange(domain, m)[2]));\n    return domain;\n  }\n  function d3_scale_linearTickRange(domain, m) {\n    if (m == null) m = 10;\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 range = d3_scale_linearTickRange(domain, m);\n    if (format) {\n      var match = d3_format_re.exec(format);\n      match.shift();\n      if (match[8] === \"s\") {\n        var prefix = d3.formatPrefix(Math.max(abs(range[0]), abs(range[1])));\n        if (!match[7]) match[7] = \".\" + d3_scale_linearPrecision(prefix.scale(range[2]));\n        match[8] = \"f\";\n        format = d3.format(match.join(\"\"));\n        return function(d) {\n          return format(prefix.scale(d)) + prefix.symbol;\n        };\n      }\n      if (!match[7]) match[7] = \".\" + d3_scale_linearFormatPrecision(match[8], range);\n      format = match.join(\"\");\n    } else {\n      format = \",.\" + d3_scale_linearPrecision(range[2]) + \"f\";\n    }\n    return d3.format(format);\n  }\n  var d3_scale_linearFormatSignificant = {\n    s: 1,\n    g: 1,\n    p: 1,\n    r: 1,\n    e: 1\n  };\n  function d3_scale_linearPrecision(value) {\n    return -Math.floor(Math.log(value) / Math.LN10 + .01);\n  }\n  function d3_scale_linearFormatPrecision(type, range) {\n    var p = d3_scale_linearPrecision(range[2]);\n    return type in d3_scale_linearFormatSignificant ? Math.abs(p - d3_scale_linearPrecision(Math.max(abs(range[0]), abs(range[1])))) + +(type !== \"e\") : p - (type === \"%\") * 2;\n  }\n  d3.scale.log = function() {\n    return d3_scale_log(d3.scale.linear().domain([ 0, 1 ]), 10, true, [ 1, 10 ]);\n  };\n  function d3_scale_log(linear, base, positive, domain) {\n    function log(x) {\n      return (positive ? Math.log(x < 0 ? 0 : x) : -Math.log(x > 0 ? 0 : -x)) / Math.log(base);\n    }\n    function pow(x) {\n      return positive ? Math.pow(base, x) : -Math.pow(base, -x);\n    }\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 domain;\n      positive = x[0] >= 0;\n      linear.domain((domain = x.map(Number)).map(log));\n      return scale;\n    };\n    scale.base = function(_) {\n      if (!arguments.length) return base;\n      base = +_;\n      linear.domain(domain.map(log));\n      return scale;\n    };\n    scale.nice = function() {\n      var niced = d3_scale_nice(domain.map(log), positive ? Math : d3_scale_logNiceNegative);\n      linear.domain(niced);\n      domain = niced.map(pow);\n      return scale;\n    };\n    scale.ticks = function() {\n      var extent = d3_scaleExtent(domain), ticks = [], u = extent[0], v = extent[1], i = Math.floor(log(u)), j = Math.ceil(log(v)), n = base % 1 ? 2 : base;\n      if (isFinite(j - i)) {\n        if (positive) {\n          for (;i < j; i++) for (var k = 1; k < n; k++) ticks.push(pow(i) * k);\n          ticks.push(pow(i));\n        } else {\n          ticks.push(pow(i));\n          for (;i++ < j; ) for (var k = n - 1; k > 0; k--) ticks.push(pow(i) * k);\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) return d3_scale_logFormat;\n      if (arguments.length < 2) format = d3_scale_logFormat; else if (typeof format !== \"function\") format = d3.format(format);\n      var k = Math.max(1, base * n / scale.ticks().length);\n      return function(d) {\n        var i = d / pow(Math.round(log(d)));\n        if (i * base < base - .5) i *= base;\n        return i <= k ? format(d) : \"\";\n      };\n    };\n    scale.copy = function() {\n      return d3_scale_log(linear.copy(), base, positive, domain);\n    };\n    return d3_scale_linearRebind(scale, linear);\n  }\n  var d3_scale_logFormat = d3.format(\".0e\"), d3_scale_logNiceNegative = {\n    floor: function(x) {\n      return -Math.ceil(-x);\n    },\n    ceil: function(x) {\n      return -Math.floor(-x);\n    }\n  };\n  d3.scale.pow = function() {\n    return d3_scale_pow(d3.scale.linear(), 1, [ 0, 1 ]);\n  };\n  function d3_scale_pow(linear, exponent, domain) {\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 domain;\n      linear.domain((domain = x.map(Number)).map(powp));\n      return scale;\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(m) {\n      return scale.domain(d3_scale_linearNice(domain, m));\n    };\n    scale.exponent = function(x) {\n      if (!arguments.length) return exponent;\n      powp = d3_scale_powPow(exponent = x);\n      powb = d3_scale_powPow(1 / exponent);\n      linear.domain(domain.map(powp));\n      return scale;\n    };\n    scale.copy = function() {\n      return d3_scale_pow(linear.copy(), exponent, domain);\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) || (ranger.t === \"range\" ? index.set(x, domain.push(x)) : NaN)) - 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 = domain.length < 2 ? (start = (start + stop) / 2, \n      0) : (stop - start) / (domain.length - 1 + padding);\n      range = steps(start + step * padding / 2, step);\n      rangeBand = 0;\n      ranger = {\n        t: \"rangePoints\",\n        a: arguments\n      };\n      return scale;\n    };\n    scale.rangeRoundPoints = function(x, padding) {\n      if (arguments.length < 2) padding = 0;\n      var start = x[0], stop = x[1], step = domain.length < 2 ? (start = stop = Math.round((start + stop) / 2), \n      0) : (stop - start) / (domain.length - 1 + padding) | 0;\n      range = steps(start + Math.round(step * padding / 2 + (stop - start - (domain.length - 1 + padding) * step) / 2), step);\n      rangeBand = 0;\n      ranger = {\n        t: \"rangeRoundPoints\",\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));\n      range = steps(start + Math.round((stop - start - (domain.length - padding) * step) / 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 = [ 2062260, 16744206, 2924588, 14034728, 9725885, 9197131, 14907330, 8355711, 12369186, 1556175 ].map(d3_rgbString);\n  var d3_category20 = [ 2062260, 11454440, 16744206, 16759672, 2924588, 10018698, 14034728, 16750742, 9725885, 12955861, 9197131, 12885140, 14907330, 16234194, 8355711, 13092807, 12369186, 14408589, 1556175, 10410725 ].map(d3_rgbString);\n  var d3_category20b = [ 3750777, 5395619, 7040719, 10264286, 6519097, 9216594, 11915115, 13556636, 9202993, 12426809, 15186514, 15190932, 8666169, 11356490, 14049643, 15177372, 8077683, 10834324, 13528509, 14589654 ].map(d3_rgbString);\n  var d3_category20c = [ 3244733, 7057110, 10406625, 13032431, 15095053, 16616764, 16625259, 16634018, 3253076, 7652470, 10607003, 13101504, 7695281, 10394312, 12369372, 14342891, 6513507, 9868950, 12434877, 14277081 ].map(d3_rgbString);\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 range[d3.bisect(thresholds, x)];\n    }\n    scale.domain = function(x) {\n      if (!arguments.length) return domain;\n      domain = x.map(d3_number).filter(d3_numeric).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.invertExtent = function(y) {\n      y = range.indexOf(y);\n      return y < 0 ? [ NaN, NaN ] : [ y > 0 ? thresholds[y - 1] : domain[0], y < thresholds.length ? thresholds[y] : domain[domain.length - 1] ];\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.invertExtent = function(y) {\n      y = range.indexOf(y);\n      y = y < 0 ? NaN : y / kx + x0;\n      return [ y, y + 1 / kx ];\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      if (x <= x) 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.invertExtent = function(y) {\n      y = range.indexOf(y);\n      return [ domain[y - 1], domain[y] ];\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 = {};\n  function d3_zero() {\n    return 0;\n  }\n  d3.svg.arc = function() {\n    var innerRadius = d3_svg_arcInnerRadius, outerRadius = d3_svg_arcOuterRadius, cornerRadius = d3_zero, padRadius = d3_svg_arcAuto, startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle, padAngle = d3_svg_arcPadAngle;\n    function arc() {\n      var r0 = Math.max(0, +innerRadius.apply(this, arguments)), r1 = Math.max(0, +outerRadius.apply(this, arguments)), a0 = startAngle.apply(this, arguments) - halfπ, a1 = endAngle.apply(this, arguments) - halfπ, da = Math.abs(a1 - a0), cw = a0 > a1 ? 0 : 1;\n      if (r1 < r0) rc = r1, r1 = r0, r0 = rc;\n      if (da >= τε) return circleSegment(r1, cw) + (r0 ? circleSegment(r0, 1 - cw) : \"\") + \"Z\";\n      var rc, cr, rp, ap, p0 = 0, p1 = 0, x0, y0, x1, y1, x2, y2, x3, y3, path = [];\n      if (ap = (+padAngle.apply(this, arguments) || 0) / 2) {\n        rp = padRadius === d3_svg_arcAuto ? Math.sqrt(r0 * r0 + r1 * r1) : +padRadius.apply(this, arguments);\n        if (!cw) p1 *= -1;\n        if (r1) p1 = d3_asin(rp / r1 * Math.sin(ap));\n        if (r0) p0 = d3_asin(rp / r0 * Math.sin(ap));\n      }\n      if (r1) {\n        x0 = r1 * Math.cos(a0 + p1);\n        y0 = r1 * Math.sin(a0 + p1);\n        x1 = r1 * Math.cos(a1 - p1);\n        y1 = r1 * Math.sin(a1 - p1);\n        var l1 = Math.abs(a1 - a0 - 2 * p1) <= π ? 0 : 1;\n        if (p1 && d3_svg_arcSweep(x0, y0, x1, y1) === cw ^ l1) {\n          var h1 = (a0 + a1) / 2;\n          x0 = r1 * Math.cos(h1);\n          y0 = r1 * Math.sin(h1);\n          x1 = y1 = null;\n        }\n      } else {\n        x0 = y0 = 0;\n      }\n      if (r0) {\n        x2 = r0 * Math.cos(a1 - p0);\n        y2 = r0 * Math.sin(a1 - p0);\n        x3 = r0 * Math.cos(a0 + p0);\n        y3 = r0 * Math.sin(a0 + p0);\n        var l0 = Math.abs(a0 - a1 + 2 * p0) <= π ? 0 : 1;\n        if (p0 && d3_svg_arcSweep(x2, y2, x3, y3) === 1 - cw ^ l0) {\n          var h0 = (a0 + a1) / 2;\n          x2 = r0 * Math.cos(h0);\n          y2 = r0 * Math.sin(h0);\n          x3 = y3 = null;\n        }\n      } else {\n        x2 = y2 = 0;\n      }\n      if (da > ε && (rc = Math.min(Math.abs(r1 - r0) / 2, +cornerRadius.apply(this, arguments))) > .001) {\n        cr = r0 < r1 ^ cw ? 0 : 1;\n        var rc1 = rc, rc0 = rc;\n        if (da < π) {\n          var oc = x3 == null ? [ x2, y2 ] : x1 == null ? [ x0, y0 ] : d3_geom_polygonIntersect([ x0, y0 ], [ x3, y3 ], [ x1, y1 ], [ x2, y2 ]), ax = x0 - oc[0], ay = y0 - oc[1], bx = x1 - oc[0], by = y1 - oc[1], kc = 1 / Math.sin(Math.acos((ax * bx + ay * by) / (Math.sqrt(ax * ax + ay * ay) * Math.sqrt(bx * bx + by * by))) / 2), lc = Math.sqrt(oc[0] * oc[0] + oc[1] * oc[1]);\n          rc0 = Math.min(rc, (r0 - lc) / (kc - 1));\n          rc1 = Math.min(rc, (r1 - lc) / (kc + 1));\n        }\n        if (x1 != null) {\n          var t30 = d3_svg_arcCornerTangents(x3 == null ? [ x2, y2 ] : [ x3, y3 ], [ x0, y0 ], r1, rc1, cw), t12 = d3_svg_arcCornerTangents([ x1, y1 ], [ x2, y2 ], r1, rc1, cw);\n          if (rc === rc1) {\n            path.push(\"M\", t30[0], \"A\", rc1, \",\", rc1, \" 0 0,\", cr, \" \", t30[1], \"A\", r1, \",\", r1, \" 0 \", 1 - cw ^ d3_svg_arcSweep(t30[1][0], t30[1][1], t12[1][0], t12[1][1]), \",\", cw, \" \", t12[1], \"A\", rc1, \",\", rc1, \" 0 0,\", cr, \" \", t12[0]);\n          } else {\n            path.push(\"M\", t30[0], \"A\", rc1, \",\", rc1, \" 0 1,\", cr, \" \", t12[0]);\n          }\n        } else {\n          path.push(\"M\", x0, \",\", y0);\n        }\n        if (x3 != null) {\n          var t03 = d3_svg_arcCornerTangents([ x0, y0 ], [ x3, y3 ], r0, -rc0, cw), t21 = d3_svg_arcCornerTangents([ x2, y2 ], x1 == null ? [ x0, y0 ] : [ x1, y1 ], r0, -rc0, cw);\n          if (rc === rc0) {\n            path.push(\"L\", t21[0], \"A\", rc0, \",\", rc0, \" 0 0,\", cr, \" \", t21[1], \"A\", r0, \",\", r0, \" 0 \", cw ^ d3_svg_arcSweep(t21[1][0], t21[1][1], t03[1][0], t03[1][1]), \",\", 1 - cw, \" \", t03[1], \"A\", rc0, \",\", rc0, \" 0 0,\", cr, \" \", t03[0]);\n          } else {\n            path.push(\"L\", t21[0], \"A\", rc0, \",\", rc0, \" 0 0,\", cr, \" \", t03[0]);\n          }\n        } else {\n          path.push(\"L\", x2, \",\", y2);\n        }\n      } else {\n        path.push(\"M\", x0, \",\", y0);\n        if (x1 != null) path.push(\"A\", r1, \",\", r1, \" 0 \", l1, \",\", cw, \" \", x1, \",\", y1);\n        path.push(\"L\", x2, \",\", y2);\n        if (x3 != null) path.push(\"A\", r0, \",\", r0, \" 0 \", l0, \",\", 1 - cw, \" \", x3, \",\", y3);\n      }\n      path.push(\"Z\");\n      return path.join(\"\");\n    }\n    function circleSegment(r1, cw) {\n      return \"M0,\" + r1 + \"A\" + r1 + \",\" + r1 + \" 0 1,\" + cw + \" 0,\" + -r1 + \"A\" + r1 + \",\" + r1 + \" 0 1,\" + cw + \" 0,\" + r1;\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.cornerRadius = function(v) {\n      if (!arguments.length) return cornerRadius;\n      cornerRadius = d3_functor(v);\n      return arc;\n    };\n    arc.padRadius = function(v) {\n      if (!arguments.length) return padRadius;\n      padRadius = v == d3_svg_arcAuto ? d3_svg_arcAuto : 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.padAngle = function(v) {\n      if (!arguments.length) return padAngle;\n      padAngle = 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 - halfπ;\n      return [ Math.cos(a) * r, Math.sin(a) * r ];\n    };\n    return arc;\n  };\n  var d3_svg_arcAuto = \"auto\";\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  function d3_svg_arcPadAngle(d) {\n    return d && d.padAngle;\n  }\n  function d3_svg_arcSweep(x0, y0, x1, y1) {\n    return (x0 - x1) * y0 - (y0 - y1) * x0 > 0 ? 0 : 1;\n  }\n  function d3_svg_arcCornerTangents(p0, p1, r1, rc, cw) {\n    var x01 = p0[0] - p1[0], y01 = p0[1] - p1[1], lo = (cw ? rc : -rc) / Math.sqrt(x01 * x01 + y01 * y01), ox = lo * y01, oy = -lo * x01, x1 = p0[0] + ox, y1 = p0[1] + oy, x2 = p1[0] + ox, y2 = p1[1] + oy, x3 = (x1 + x2) / 2, y3 = (y1 + y2) / 2, dx = x2 - x1, dy = y2 - y1, d2 = dx * dx + dy * dy, r = r1 - rc, D = x1 * y2 - x2 * y1, d = (dy < 0 ? -1 : 1) * Math.sqrt(Math.max(0, r * r * d2 - D * D)), cx0 = (D * dy - dx * d) / d2, cy0 = (-D * dx - dy * d) / d2, cx1 = (D * dy + dx * d) / d2, cy1 = (-D * dx + dy * d) / d2, dx0 = cx0 - x3, dy0 = cy0 - y3, dx1 = cx1 - x3, dy1 = cy1 - y3;\n    if (dx0 * dx0 + dy0 * dy0 > dx1 * dx1 + dy1 * dy1) cx0 = cx1, cy0 = cy1;\n    return [ [ cx0 - ox, cy0 - oy ], [ cx0 * r1 / r, cy0 * r1 / r ] ];\n  }\n  function d3_svg_line(projection) {\n    var x = d3_geom_pointX, y = d3_geom_pointY, 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  var d3_svg_lineInterpolators = d3.map({\n    linear: d3_svg_lineLinear,\n    \"linear-closed\": d3_svg_lineLinearClosed,\n    step: d3_svg_lineStep,\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.length > 1 ? points.join(\"L\") : points + \"Z\";\n  }\n  function d3_svg_lineLinearClosed(points) {\n    return points.join(\"L\") + \"Z\";\n  }\n  function d3_svg_lineStep(points) {\n    var i = 0, n = points.length, p = points[0], path = [ p[0], \",\", p[1] ];\n    while (++i < n) path.push(\"H\", (p[0] + (p = points[i])[0]) / 2, \"V\", p[1]);\n    if (n > 1) path.push(\"H\", p[0]);\n    return path.join(\"\");\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, -1), d3_svg_lineCardinalTangents(points, tension));\n  }\n  function d3_svg_lineCardinalClosed(points, tension) {\n    return points.length < 3 ? d3_svg_lineLinearClosed(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, \"L\", d3_svg_lineDot4(d3_svg_lineBasisBezier3, px), \",\", d3_svg_lineDot4(d3_svg_lineBasisBezier3, py) ];\n    points.push(points[n - 1]);\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    points.pop();\n    path.push(\"L\", pi);\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 (abs(d) < ε) {\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.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] - halfπ;\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_geom_pointX, x1 = d3_geom_pointX, y0 = 0, y1 = d3_geom_pointY, 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) - halfπ, a1 = endAngle.call(self, subgroup, i) - halfπ;\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] - halfπ;\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  d3_selectionPrototype.transition = function(name) {\n    var id = d3_transitionInheritId || ++d3_transitionId, ns = d3_transitionNamespace(name), subgroups = [], subgroup, node, transition = d3_transitionInherit || {\n      time: Date.now(),\n      ease: d3_ease_cubicInOut,\n      delay: 0,\n      duration: 250\n    };\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, ns, id, transition);\n        subgroup.push(node);\n      }\n    }\n    return d3_transition(subgroups, ns, id);\n  };\n  d3_selectionPrototype.interrupt = function(name) {\n    return this.each(name == null ? d3_selection_interrupt : d3_selection_interruptNS(d3_transitionNamespace(name)));\n  };\n  var d3_selection_interrupt = d3_selection_interruptNS(d3_transitionNamespace());\n  function d3_selection_interruptNS(ns) {\n    return function() {\n      var lock, activeId, active;\n      if ((lock = this[ns]) && (active = lock[activeId = lock.active])) {\n        active.timer.c = null;\n        active.timer.t = NaN;\n        if (--lock.count) delete lock[activeId]; else delete this[ns];\n        lock.active += .5;\n        active.event && active.event.interrupt.call(this, this.__data__, active.index);\n      }\n    };\n  }\n  function d3_transition(groups, ns, id) {\n    d3_subclass(groups, d3_transitionPrototype);\n    groups.namespace = ns;\n    groups.id = id;\n    return groups;\n  }\n  var d3_transitionPrototype = [], d3_transitionId = 0, d3_transitionInheritId, d3_transitionInherit;\n  d3_transitionPrototype.call = d3_selectionPrototype.call;\n  d3_transitionPrototype.empty = d3_selectionPrototype.empty;\n  d3_transitionPrototype.node = d3_selectionPrototype.node;\n  d3_transitionPrototype.size = d3_selectionPrototype.size;\n  d3.transition = function(selection, name) {\n    return selection && selection.transition ? d3_transitionInheritId ? selection.transition(name) : selection : d3.selection().transition(selection);\n  };\n  d3.transition.prototype = d3_transitionPrototype;\n  d3_transitionPrototype.select = function(selector) {\n    var id = this.id, ns = this.namespace, subgroups = [], subgroup, subnode, node;\n    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, j))) {\n          if (\"__data__\" in node) subnode.__data__ = node.__data__;\n          d3_transitionNode(subnode, i, ns, id, node[ns][id]);\n          subgroup.push(subnode);\n        } else {\n          subgroup.push(null);\n        }\n      }\n    }\n    return d3_transition(subgroups, ns, id);\n  };\n  d3_transitionPrototype.selectAll = function(selector) {\n    var id = this.id, ns = this.namespace, subgroups = [], subgroup, subnodes, node, subnode, transition;\n    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[ns][id];\n          subnodes = selector.call(node, node.__data__, i, j);\n          subgroups.push(subgroup = []);\n          for (var k = -1, o = subnodes.length; ++k < o; ) {\n            if (subnode = subnodes[k]) d3_transitionNode(subnode, k, ns, id, transition);\n            subgroup.push(subnode);\n          }\n        }\n      }\n    }\n    return d3_transition(subgroups, ns, 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, j)) {\n          subgroup.push(node);\n        }\n      }\n    }\n    return d3_transition(subgroups, this.namespace, this.id);\n  };\n  d3_transitionPrototype.tween = function(name, tween) {\n    var id = this.id, ns = this.namespace;\n    if (arguments.length < 2) return this.node()[ns][id].tween.get(name);\n    return d3_selection_each(this, tween == null ? function(node) {\n      node[ns][id].tween.remove(name);\n    } : function(node) {\n      node[ns][id].tween.set(name, tween);\n    });\n  };\n  function d3_transition_tween(groups, name, value, tween) {\n    var id = groups.id, ns = groups.namespace;\n    return d3_selection_each(groups, typeof value === \"function\" ? function(node, i, j) {\n      node[ns][id].tween.set(name, tween(value.call(node, node.__data__, i, j)));\n    } : (value = tween(value), function(node) {\n      node[ns][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 = nameNS == \"transform\" ? d3_interpolateTransform : d3_interpolate, 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    function attrTween(b) {\n      return b == null ? attrNull : (b += \"\", function() {\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    }\n    function attrTweenNS(b) {\n      return b == null ? attrNullNS : (b += \"\", function() {\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    }\n    return d3_transition_tween(this, \"attr.\" + nameNS, value, name.local ? attrTweenNS : attrTween);\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    function styleNull() {\n      this.style.removeProperty(name);\n    }\n    function styleString(b) {\n      return b == null ? styleNull : (b += \"\", function() {\n        var a = d3_window(this).getComputedStyle(this, null).getPropertyValue(name), i;\n        return a !== b && (i = d3_interpolate(a, b), function(t) {\n          this.style.setProperty(name, i(t), priority);\n        });\n      });\n    }\n    return d3_transition_tween(this, \"style.\" + name, value, styleString);\n  };\n  d3_transitionPrototype.styleTween = function(name, tween, priority) {\n    if (arguments.length < 3) priority = \"\";\n    function styleTween(d, i) {\n      var f = tween.call(this, d, i, d3_window(this).getComputedStyle(this, null).getPropertyValue(name));\n      return f && function(t) {\n        this.style.setProperty(name, f(t), priority);\n      };\n    }\n    return this.tween(\"style.\" + name, styleTween);\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    var ns = this.namespace;\n    return this.each(\"end.transition\", function() {\n      var p;\n      if (this[ns].count < 2 && (p = this.parentNode)) p.removeChild(this);\n    });\n  };\n  d3_transitionPrototype.ease = function(value) {\n    var id = this.id, ns = this.namespace;\n    if (arguments.length < 1) return this.node()[ns][id].ease;\n    if (typeof value !== \"function\") value = d3.ease.apply(d3, arguments);\n    return d3_selection_each(this, function(node) {\n      node[ns][id].ease = value;\n    });\n  };\n  d3_transitionPrototype.delay = function(value) {\n    var id = this.id, ns = this.namespace;\n    if (arguments.length < 1) return this.node()[ns][id].delay;\n    return d3_selection_each(this, typeof value === \"function\" ? function(node, i, j) {\n      node[ns][id].delay = +value.call(node, node.__data__, i, j);\n    } : (value = +value, function(node) {\n      node[ns][id].delay = value;\n    }));\n  };\n  d3_transitionPrototype.duration = function(value) {\n    var id = this.id, ns = this.namespace;\n    if (arguments.length < 1) return this.node()[ns][id].duration;\n    return d3_selection_each(this, typeof value === \"function\" ? function(node, i, j) {\n      node[ns][id].duration = Math.max(1, value.call(node, node.__data__, i, j));\n    } : (value = Math.max(1, value), function(node) {\n      node[ns][id].duration = value;\n    }));\n  };\n  d3_transitionPrototype.each = function(type, listener) {\n    var id = this.id, ns = this.namespace;\n    if (arguments.length < 2) {\n      var inherit = d3_transitionInherit, inheritId = d3_transitionInheritId;\n      try {\n        d3_transitionInheritId = id;\n        d3_selection_each(this, function(node, i, j) {\n          d3_transitionInherit = node[ns][id];\n          type.call(node, node.__data__, i, j);\n        });\n      } finally {\n        d3_transitionInherit = inherit;\n        d3_transitionInheritId = inheritId;\n      }\n    } else {\n      d3_selection_each(this, function(node) {\n        var transition = node[ns][id];\n        (transition.event || (transition.event = d3.dispatch(\"start\", \"end\", \"interrupt\"))).on(type, listener);\n      });\n    }\n    return this;\n  };\n  d3_transitionPrototype.transition = function() {\n    var id0 = this.id, id1 = ++d3_transitionId, ns = this.namespace, 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 = node[ns][id0];\n          d3_transitionNode(node, i, ns, id1, {\n            time: transition.time,\n            ease: transition.ease,\n            delay: transition.delay + transition.duration,\n            duration: transition.duration\n          });\n        }\n        subgroup.push(node);\n      }\n    }\n    return d3_transition(subgroups, ns, id1);\n  };\n  function d3_transitionNamespace(name) {\n    return name == null ? \"__transition__\" : \"__transition_\" + name + \"__\";\n  }\n  function d3_transitionNode(node, i, ns, id, inherit) {\n    var lock = node[ns] || (node[ns] = {\n      active: 0,\n      count: 0\n    }), transition = lock[id], time, timer, duration, ease, tweens;\n    function schedule(elapsed) {\n      var delay = transition.delay;\n      timer.t = delay + time;\n      if (delay <= elapsed) return start(elapsed - delay);\n      timer.c = start;\n    }\n    function start(elapsed) {\n      var activeId = lock.active, active = lock[activeId];\n      if (active) {\n        active.timer.c = null;\n        active.timer.t = NaN;\n        --lock.count;\n        delete lock[activeId];\n        active.event && active.event.interrupt.call(node, node.__data__, active.index);\n      }\n      for (var cancelId in lock) {\n        if (+cancelId < id) {\n          var cancel = lock[cancelId];\n          cancel.timer.c = null;\n          cancel.timer.t = NaN;\n          --lock.count;\n          delete lock[cancelId];\n        }\n      }\n      timer.c = tick;\n      d3_timer(function() {\n        if (timer.c && tick(elapsed || 1)) {\n          timer.c = null;\n          timer.t = NaN;\n        }\n        return 1;\n      }, 0, time);\n      lock.active = id;\n      transition.event && transition.event.start.call(node, node.__data__, i);\n      tweens = [];\n      transition.tween.forEach(function(key, value) {\n        if (value = value.call(node, node.__data__, i)) {\n          tweens.push(value);\n        }\n      });\n      ease = transition.ease;\n      duration = transition.duration;\n    }\n    function tick(elapsed) {\n      var t = elapsed / duration, e = ease(t), n = tweens.length;\n      while (n > 0) {\n        tweens[--n].call(node, e);\n      }\n      if (t >= 1) {\n        transition.event && transition.event.end.call(node, node.__data__, i);\n        if (--lock.count) delete lock[id]; else delete node[ns];\n        return 1;\n      }\n    }\n    if (!transition) {\n      time = inherit.time;\n      timer = d3_timer(schedule, 0, time);\n      transition = lock[id] = {\n        tween: new d3_Map(),\n        time: time,\n        timer: timer,\n        delay: inherit.delay,\n        duration: inherit.duration,\n        ease: inherit.ease,\n        index: i\n      };\n      inherit = null;\n      ++lock.count;\n    }\n  }\n  d3.svg.axis = function() {\n    var scale = d3.scale.linear(), orient = d3_svg_axisDefaultOrient, innerTickSize = 6, outerTickSize = 6, tickPadding = 3, tickArguments_ = [ 10 ], tickValues = null, tickFormat_;\n    function axis(g) {\n      g.each(function() {\n        var g = d3.select(this);\n        var scale0 = this.__chart__ || scale, scale1 = this.__chart__ = scale.copy();\n        var ticks = tickValues == null ? scale1.ticks ? scale1.ticks.apply(scale1, tickArguments_) : scale1.domain() : tickValues, tickFormat = tickFormat_ == null ? scale1.tickFormat ? scale1.tickFormat.apply(scale1, tickArguments_) : d3_identity : tickFormat_, tick = g.selectAll(\".tick\").data(ticks, scale1), tickEnter = tick.enter().insert(\"g\", \".domain\").attr(\"class\", \"tick\").style(\"opacity\", ε), tickExit = d3.transition(tick.exit()).style(\"opacity\", ε).remove(), tickUpdate = d3.transition(tick.order()).style(\"opacity\", 1), tickSpacing = Math.max(innerTickSize, 0) + tickPadding, tickTransform;\n        var range = d3_scaleRange(scale1), path = g.selectAll(\".domain\").data([ 0 ]), pathUpdate = (path.enter().append(\"path\").attr(\"class\", \"domain\"), \n        d3.transition(path));\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\"), sign = orient === \"top\" || orient === \"left\" ? -1 : 1, x1, x2, y1, y2;\n        if (orient === \"bottom\" || orient === \"top\") {\n          tickTransform = d3_svg_axisX, x1 = \"x\", y1 = \"y\", x2 = \"x2\", y2 = \"y2\";\n          text.attr(\"dy\", sign < 0 ? \"0em\" : \".71em\").style(\"text-anchor\", \"middle\");\n          pathUpdate.attr(\"d\", \"M\" + range[0] + \",\" + sign * outerTickSize + \"V0H\" + range[1] + \"V\" + sign * outerTickSize);\n        } else {\n          tickTransform = d3_svg_axisY, x1 = \"y\", y1 = \"x\", x2 = \"y2\", y2 = \"x2\";\n          text.attr(\"dy\", \".32em\").style(\"text-anchor\", sign < 0 ? \"end\" : \"start\");\n          pathUpdate.attr(\"d\", \"M\" + sign * outerTickSize + \",\" + range[0] + \"H0V\" + range[1] + \"H\" + sign * outerTickSize);\n        }\n        lineEnter.attr(y2, sign * innerTickSize);\n        textEnter.attr(y1, sign * tickSpacing);\n        lineUpdate.attr(x2, 0).attr(y2, sign * innerTickSize);\n        textUpdate.attr(x1, 0).attr(y1, sign * tickSpacing);\n        if (scale1.rangeBand) {\n          var x = scale1, dx = x.rangeBand() / 2;\n          scale0 = scale1 = function(d) {\n            return x(d) + dx;\n          };\n        } else if (scale0.rangeBand) {\n          scale0 = scale1;\n        } else {\n          tickExit.call(tickTransform, scale1, scale0);\n        }\n        tickEnter.call(tickTransform, scale0, scale1);\n        tickUpdate.call(tickTransform, scale1, scale1);\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_ = d3_array(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) {\n      var n = arguments.length;\n      if (!n) return innerTickSize;\n      innerTickSize = +x;\n      outerTickSize = +arguments[n - 1];\n      return axis;\n    };\n    axis.innerTickSize = function(x) {\n      if (!arguments.length) return innerTickSize;\n      innerTickSize = +x;\n      return axis;\n    };\n    axis.outerTickSize = function(x) {\n      if (!arguments.length) return outerTickSize;\n      outerTickSize = +x;\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() {\n      return arguments.length && 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, x0, x1) {\n    selection.attr(\"transform\", function(d) {\n      var v0 = x0(d);\n      return \"translate(\" + (isFinite(v0) ? v0 : x1(d)) + \",0)\";\n    });\n  }\n  function d3_svg_axisY(selection, y0, y1) {\n    selection.attr(\"transform\", function(d) {\n      var v0 = y0(d);\n      return \"translate(0,\" + (isFinite(v0) ? v0 : y1(d)) + \")\";\n    });\n  }\n  d3.svg.brush = function() {\n    var event = d3_eventDispatch(brush, \"brushstart\", \"brush\", \"brushend\"), x = null, y = null, xExtent = [ 0, 0 ], yExtent = [ 0, 0 ], xExtentDomain, yExtentDomain, xClamp = true, yClamp = true, resizes = d3_svg_brushResizes[0];\n    function brush(g) {\n      g.each(function() {\n        var g = d3.select(this).style(\"pointer-events\", \"all\").style(\"-webkit-tap-highlight-color\", \"rgba(0,0,0,0)\").on(\"mousedown.brush\", brushstart).on(\"touchstart.brush\", brushstart);\n        var background = g.selectAll(\".background\").data([ 0 ]);\n        background.enter().append(\"rect\").attr(\"class\", \"background\").style(\"visibility\", \"hidden\").style(\"cursor\", \"crosshair\");\n        g.selectAll(\".extent\").data([ 0 ]).enter().append(\"rect\").attr(\"class\", \"extent\").style(\"cursor\", \"move\");\n        var resize = g.selectAll(\".resize\").data(resizes, d3_identity);\n        resize.exit().remove();\n        resize.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        resize.style(\"display\", brush.empty() ? \"none\" : null);\n        var gUpdate = d3.transition(g), backgroundUpdate = d3.transition(background), range;\n        if (x) {\n          range = d3_scaleRange(x);\n          backgroundUpdate.attr(\"x\", range[0]).attr(\"width\", range[1] - range[0]);\n          redrawX(gUpdate);\n        }\n        if (y) {\n          range = d3_scaleRange(y);\n          backgroundUpdate.attr(\"y\", range[0]).attr(\"height\", range[1] - range[0]);\n          redrawY(gUpdate);\n        }\n        redraw(gUpdate);\n      });\n    }\n    brush.event = function(g) {\n      g.each(function() {\n        var event_ = event.of(this, arguments), extent1 = {\n          x: xExtent,\n          y: yExtent,\n          i: xExtentDomain,\n          j: yExtentDomain\n        }, extent0 = this.__chart__ || extent1;\n        this.__chart__ = extent1;\n        if (d3_transitionInheritId) {\n          d3.select(this).transition().each(\"start.brush\", function() {\n            xExtentDomain = extent0.i;\n            yExtentDomain = extent0.j;\n            xExtent = extent0.x;\n            yExtent = extent0.y;\n            event_({\n              type: \"brushstart\"\n            });\n          }).tween(\"brush:brush\", function() {\n            var xi = d3_interpolateArray(xExtent, extent1.x), yi = d3_interpolateArray(yExtent, extent1.y);\n            xExtentDomain = yExtentDomain = null;\n            return function(t) {\n              xExtent = extent1.x = xi(t);\n              yExtent = extent1.y = yi(t);\n              event_({\n                type: \"brush\",\n                mode: \"resize\"\n              });\n            };\n          }).each(\"end.brush\", function() {\n            xExtentDomain = extent1.i;\n            yExtentDomain = extent1.j;\n            event_({\n              type: \"brush\",\n              mode: \"resize\"\n            });\n            event_({\n              type: \"brushend\"\n            });\n          });\n        } else {\n          event_({\n            type: \"brushstart\"\n          });\n          event_({\n            type: \"brush\",\n            mode: \"resize\"\n          });\n          event_({\n            type: \"brushend\"\n          });\n        }\n      });\n    };\n    function redraw(g) {\n      g.selectAll(\".resize\").attr(\"transform\", function(d) {\n        return \"translate(\" + xExtent[+/e$/.test(d)] + \",\" + yExtent[+/^s/.test(d)] + \")\";\n      });\n    }\n    function redrawX(g) {\n      g.select(\".extent\").attr(\"x\", xExtent[0]);\n      g.selectAll(\".extent,.n>rect,.s>rect\").attr(\"width\", xExtent[1] - xExtent[0]);\n    }\n    function redrawY(g) {\n      g.select(\".extent\").attr(\"y\", yExtent[0]);\n      g.selectAll(\".extent,.e>rect,.w>rect\").attr(\"height\", yExtent[1] - yExtent[0]);\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\"), dragRestore = d3_event_dragSuppress(target), center, origin = d3.mouse(target), offset;\n      var w = d3.select(d3_window(target)).on(\"keydown.brush\", keydown).on(\"keyup.brush\", keyup);\n      if (d3.event.changedTouches) {\n        w.on(\"touchmove.brush\", brushmove).on(\"touchend.brush\", brushend);\n      } else {\n        w.on(\"mousemove.brush\", brushmove).on(\"mouseup.brush\", brushend);\n      }\n      g.interrupt().selectAll(\"*\").interrupt();\n      if (dragging) {\n        origin[0] = xExtent[0] - origin[0];\n        origin[1] = yExtent[0] - origin[1];\n      } else if (resizing) {\n        var ex = +/w$/.test(resizing), ey = +/^n/.test(resizing);\n        offset = [ xExtent[1 - ex] - origin[0], yExtent[1 - ey] - origin[1] ];\n        origin[0] = xExtent[ex];\n        origin[1] = yExtent[ey];\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      function keydown() {\n        if (d3.event.keyCode == 32) {\n          if (!dragging) {\n            center = null;\n            origin[0] -= xExtent[1];\n            origin[1] -= yExtent[1];\n            dragging = 2;\n          }\n          d3_eventPreventDefault();\n        }\n      }\n      function keyup() {\n        if (d3.event.keyCode == 32 && dragging == 2) {\n          origin[0] += xExtent[1];\n          origin[1] += yExtent[1];\n          dragging = 0;\n          d3_eventPreventDefault();\n        }\n      }\n      function brushmove() {\n        var point = d3.mouse(target), 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 = [ (xExtent[0] + xExtent[1]) / 2, (yExtent[0] + yExtent[1]) / 2 ];\n            origin[0] = xExtent[+(point[0] < center[0])];\n            origin[1] = yExtent[+(point[1] < center[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], extent = i ? yExtent : xExtent, size = extent[1] - extent[0], min, max;\n        if (dragging) {\n          r0 -= position;\n          r1 -= size + position;\n        }\n        min = (i ? yClamp : xClamp) ? Math.max(r0, Math.min(r1, point[i])) : 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] != min || extent[1] != max) {\n          if (i) yExtentDomain = null; else xExtentDomain = null;\n          extent[0] = min;\n          extent[1] = 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        dragRestore();\n        event_({\n          type: \"brushend\"\n        });\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.clamp = function(z) {\n      if (!arguments.length) return x && y ? [ xClamp, yClamp ] : x ? xClamp : y ? yClamp : null;\n      if (x && y) xClamp = !!z[0], yClamp = !!z[1]; else if (x) xClamp = !!z; else if (y) yClamp = !!z;\n      return brush;\n    };\n    brush.extent = function(z) {\n      var x0, x1, y0, y1, t;\n      if (!arguments.length) {\n        if (x) {\n          if (xExtentDomain) {\n            x0 = xExtentDomain[0], x1 = xExtentDomain[1];\n          } else {\n            x0 = xExtent[0], x1 = xExtent[1];\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          if (yExtentDomain) {\n            y0 = yExtentDomain[0], y1 = yExtentDomain[1];\n          } else {\n            y0 = yExtent[0], y1 = yExtent[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      if (x) {\n        x0 = z[0], x1 = z[1];\n        if (y) x0 = x0[0], x1 = x1[0];\n        xExtentDomain = [ x0, x1 ];\n        if (x.invert) x0 = x(x0), x1 = x(x1);\n        if (x1 < x0) t = x0, x0 = x1, x1 = t;\n        if (x0 != xExtent[0] || x1 != xExtent[1]) xExtent = [ x0, x1 ];\n      }\n      if (y) {\n        y0 = z[0], y1 = z[1];\n        if (x) y0 = y0[1], y1 = y1[1];\n        yExtentDomain = [ y0, y1 ];\n        if (y.invert) y0 = y(y0), y1 = y(y1);\n        if (y1 < y0) t = y0, y0 = y1, y1 = t;\n        if (y0 != yExtent[0] || y1 != yExtent[1]) yExtent = [ y0, y1 ];\n      }\n      return brush;\n    };\n    brush.clear = function() {\n      if (!brush.empty()) {\n        xExtent = [ 0, 0 ], yExtent = [ 0, 0 ];\n        xExtentDomain = yExtentDomain = null;\n      }\n      return brush;\n    };\n    brush.empty = function() {\n      return !!x && xExtent[0] == xExtent[1] || !!y && yExtent[0] == yExtent[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  var d3_time_format = d3_time.format = d3_locale_enUS.timeFormat;\n  var d3_time_formatUtc = d3_time_format.utc;\n  var d3_time_formatIso = d3_time_formatUtc(\"%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_date(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_date(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_date((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    function tickMethod(extent, count) {\n      var span = extent[1] - extent[0], target = span / count, i = d3.bisect(d3_time_scaleSteps, target);\n      return i == d3_time_scaleSteps.length ? [ methods.year, d3_scale_linearTickRange(extent.map(function(d) {\n        return d / 31536e6;\n      }), count)[2] ] : !i ? [ d3_time_scaleMilliseconds, d3_scale_linearTickRange(extent, count)[2] ] : methods[target / d3_time_scaleSteps[i - 1] < d3_time_scaleSteps[i] / target ? i - 1 : i];\n    }\n    scale.nice = function(interval, skip) {\n      var domain = scale.domain(), extent = d3_scaleExtent(domain), method = interval == null ? tickMethod(extent, 10) : typeof interval === \"number\" && tickMethod(extent, interval);\n      if (method) interval = method[0], skip = method[1];\n      function skipped(date) {\n        return !isNaN(date) && !interval.range(date, d3_time_scaleDate(+date + 1), skip).length;\n      }\n      return scale.domain(d3_scale_nice(domain, skip > 1 ? {\n        floor: function(date) {\n          while (skipped(date = interval.floor(date))) date = d3_time_scaleDate(date - 1);\n          return date;\n        },\n        ceil: function(date) {\n          while (skipped(date = interval.ceil(date))) date = d3_time_scaleDate(+date + 1);\n          return date;\n        }\n      } : interval));\n    };\n    scale.ticks = function(interval, skip) {\n      var extent = d3_scaleExtent(scale.domain()), method = interval == null ? tickMethod(extent, 10) : typeof interval === \"number\" ? tickMethod(extent, interval) : !interval.range && [ {\n        range: interval\n      }, skip ];\n      if (method) interval = method[0], skip = method[1];\n      return interval.range(extent[0], d3_time_scaleDate(+extent[1] + 1), skip < 1 ? 1 : skip);\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_scale_linearRebind(scale, linear);\n  }\n  function d3_time_scaleDate(t) {\n    return new Date(t);\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_scaleLocalFormat = d3_time_format.multi([ [ \".%L\", function(d) {\n    return d.getMilliseconds();\n  } ], [ \":%S\", function(d) {\n    return d.getSeconds();\n  } ], [ \"%I:%M\", function(d) {\n    return d.getMinutes();\n  } ], [ \"%I %p\", function(d) {\n    return d.getHours();\n  } ], [ \"%a %d\", function(d) {\n    return d.getDay() && d.getDate() != 1;\n  } ], [ \"%b %d\", function(d) {\n    return d.getDate() != 1;\n  } ], [ \"%B\", function(d) {\n    return d.getMonth();\n  } ], [ \"%Y\", d3_true ] ]);\n  var d3_time_scaleMilliseconds = {\n    range: function(start, stop, step) {\n      return d3.range(Math.ceil(start / step) * step, +stop, step).map(d3_time_scaleDate);\n    },\n    floor: d3_identity,\n    ceil: d3_identity\n  };\n  d3_time_scaleLocalMethods.year = d3_time.year;\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_scaleUtcFormat = d3_time_formatUtc.multi([ [ \".%L\", function(d) {\n    return d.getUTCMilliseconds();\n  } ], [ \":%S\", function(d) {\n    return d.getUTCSeconds();\n  } ], [ \"%I:%M\", function(d) {\n    return d.getUTCMinutes();\n  } ], [ \"%I %p\", function(d) {\n    return d.getUTCHours();\n  } ], [ \"%a %d\", function(d) {\n    return d.getUTCDay() && d.getUTCDate() != 1;\n  } ], [ \"%b %d\", function(d) {\n    return d.getUTCDate() != 1;\n  } ], [ \"%B\", function(d) {\n    return d.getUTCMonth();\n  } ], [ \"%Y\", d3_true ] ]);\n  d3_time_scaleUtcMethods.year = d3_time.year.utc;\n  d3_time.scale.utc = function() {\n    return d3_time_scale(d3.scale.linear(), d3_time_scaleUtcMethods, d3_time_scaleUtcFormat);\n  };\n  d3.text = d3_xhrType(function(request) {\n    return request.responseText;\n  });\n  d3.json = function(url, callback) {\n    return d3_xhr(url, \"application/json\", d3_json, callback);\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\", d3_html, callback);\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 = d3_xhrType(function(request) {\n    return request.responseXML;\n  });\n  if (typeof define === \"function\" && define.amd) this.d3 = d3, define(d3); else if (typeof module === \"object\" && module.exports) module.exports = d3; else this.d3 = d3;\n}();"
  },
  {
    "path": "code/web/d3test.html",
    "content": "<!DOCTYPE html>\n<html lang=\"de\">\n    <head>\n        <meta charset=\"utf-8\">\n        <title>D3 Test n stuff</title>\n        <script src=\"d3/d3.v3.js\"></script>\n        <style type=\"text/css\">\n            div.bar {\n                display: inline-block;\n                text-align: center;\n                font-family: Verdana, sans-serif;\n                color: white;\n                width: 30px;\n                margin: 0 5px 5px 0;\n                background-color: red;\n            }\n            rect:hover {\n                fill: teal;\n            }\n            .axis path,\n            .axis line {\n                fill: none;\n                stroke: black;\n                shape-rendering: crispEdges;\n            }\n            .axis text {\n                font-family: sans-serif;\n                font-size: 11px;\n            }\n        </style>\n    </head>\n    <body>\n        <p id=\"randomize\">Click me to randomize (add, delete, update) values.</p>\n        <p id=\"add\">Click me to add a value.</p>\n        <p id=\"delete\">Click me to delete a value.</p>\n        <script type=\"text/javascript\">\n            // derp.\n            var dataset = [];\n            var setset = [\n                    [5,20],\n                    [480,90],\n                    [250,50],\n                    [100,33],\n                    [330,95],\n                    [410,12],\n                    [475,44],\n                    [25,67],\n                    [85,21],\n                    [220,88],\n                    [600,150],\n                    [400,170]\n\n            ];\n            var bars = 40;\n            var w = 1000;\n            var h = 200;\n            var barPadding = 2;\n            var circlePadding = 30;\n            var fontsize = 10;\n\n            dataset = getRandom(dataset,h);\n\n            var xScale = d3.scale.ordinal()\n                    .domain(d3.range(dataset.length))\n                    .rangeRoundBands([0,w],0.05);\n            var yScale = d3.scale.linear()\n                    .domain([0,d3.max(dataset,function(d){\n                        return d;\n                    })])\n                    .range([15,h]);\n\n            var svg_plain = d3.select(\"body\")\n                    .append(\"svg\")\n                    .attr(\"width\",w)\n                    .attr(\"height\",h);\n            var svg_plain_rects = svg_plain.selectAll(\"rect\")\n                    .data(dataset);\n            svg_plain_rects.enter()\n                    .append(\"rect\")\n                    .attr(\"x\",function(d,e){\n                        return xScale(e);\n                    })\n                    .attr(\"y\",function(d){\n                        return h-yScale(d);\n                    })\n                    .attr(\"width\",function(d,e){\n                        return xScale.rangeBand();\n                    })\n                    .attr(\"height\",function(d){\n                        return yScale(d);\n                    })\n                    .attr(\"fill\",function(d){\n                        return \"rgb(\"+(d+100)+\",\"+(d+75)+\",\"+(d+100)+\")\";\n                    });\n            var svg_plain_txt = svg_plain.selectAll(\"text\")\n                    .data(dataset);\n            svg_plain_txt.enter()\n                    .append(\"text\")\n                    .text(function(d){\n                        return d;\n                    })\n                    .attr(\"x\",function(d,e){\n                        return xScale(e)+(w/dataset.length-barPadding)/2;\n                    })\n                    .attr(\"y\",function(){\n                        return h-5;\n                    })\n                    .attr(\"font-family\",\"sans-serif\")\n                    .attr(\"font-size\",function(){\n                        return w/dataset.length-barPadding-5;\n                    })\n                    .attr(\"text-anchor\",\"middle\")\n                    .attr(\"fill\",\"white\")\n                    .attr(\"stroke\",function(d){\n                        return yScale(d) <= (w/dataset.length-barPadding-1) ? \"black\" : \"white\"\n                    });\n\n            d3.select(\"p#randomize\")\n                    .on(\"click\", function() {\n                        dataset = getRandom(dataset,h);\n\n                        update();\n                    });\n            d3.select(\"p#add\")\n                    .on(\"click\",function() {\n                        d3.select(this).text(\"I'm too lazy to program this right now..\")\n                                .transition().delay(2000).text(\"...sorry.\");\n\n                        var randomNum = Math.round(Math.random()*100);\n                        dataset.push(randomNum);\n\n                        console.log(\"new value:\"+randomNum+\" dataset:\"+dataset);\n\n                        update();\n                    });\n            d3.select(\"p#delete\")\n                    .on(\"click\",function() {\n                        d3.select(this).text(\"I'm too lazy to program this right now..\").transition().delay(2000).text(\"...not sorry. :^)\");\n                    });\n\n\n            function update() {\n                xScale.domain(d3.range(dataset.length));\n                yScale.domain([0,d3.max(dataset,function(d){\n                    return d;\n                })]);\n\n                svg_plain_rects = svg_plain.selectAll(\"rect\")\n                        .data(dataset);\n\n                svg_plain_rects.enter().append(\"rect\")\n                        .attr(\"x\",function(d,e){\n                            return xScale(e);\n                        })\n                        .attr(\"y\",function(){\n                            return h;\n                        })\n                        .attr(\"width\",function(d,e){\n                            return xScale.rangeBand();\n                        })\n                        .attr(\"height\",function(){\n                            return 0;\n                        })\n                        .attr(\"fill\",function(d){\n                            return \"rgb(\"+(d+100)+\",\"+(d+75)+\",\"+(d+100)+\")\";\n                        });\n                svg_plain_rects.transition()\n                        .duration(100)\n                        .ease(\"linear\")\n                        .each(\"start\",function(d){\n                            d3.select(this)\n                                    .attr(\"fill\",\"rgb(\"+(d+10)+\",\"+(d+5)+\",\"+(d+10)+\")\");\n                        })\n                        .attr(\"x\",function(d,e){\n                            return xScale(e);\n                        })\n                        .attr(\"width\",function(d,e){\n                            return xScale.rangeBand();\n                        })\n                        .transition()\n                        .delay(function(d,e){\n                            return 100+e/dataset.length*1000;\n                        })\n                        .duration(500)\n                        .ease(\"linear\")\n                        .attr(\"y\",function(d){\n                            return h-yScale(d);\n                        })\n                        .attr(\"height\",function(d){\n                            return yScale(d);\n                        })\n                        .attr(\"fill\",function(d){\n                            return \"rgb(\"+(d+100)+\",\"+(d+75)+\",\"+(d+100)+\")\";\n                        });\n\n                svg_plain_txt = svg_plain.selectAll(\"text\")\n                        .data(dataset);\n\n                svg_plain_txt.enter()\n                        .append(\"text\")\n                        .transition()\n                        .delay(function(d,e){\n                            return 100+e/dataset.length*1000;\n                        })\n                        .duration(500)\n                        .ease(\"linear\")\n                        .text(function(d){\n                            return d;\n                        })\n                        .attr(\"x\",function(d,e){\n                            return xScale(e)+(w/dataset.length-barPadding)/2;\n                        })\n                        .attr(\"y\",function(){\n                            return h-5;\n                        })\n                        .attr(\"font-family\",\"sans-serif\")\n                        .attr(\"font-size\",function(){\n                            return w/dataset.length-barPadding-5;\n                        })\n                        .attr(\"text-anchor\",\"middle\")\n                        .attr(\"fill\",\"white\")\n                        .attr(\"stroke\",function(d){\n                            return yScale(d) <= (w/dataset.length-barPadding-1) ? \"black\" : \"white\"\n                        });\n                svg_plain_txt.transition()\n                        .duration(100)\n                        .ease(\"linear\")\n                        .attr(\"x\",function(d,e){\n                            return xScale(e)+(w/dataset.length-barPadding)/2;\n                        })\n                        .attr(\"font-size\",function(){\n                            return w/dataset.length-barPadding-5;\n                        })\n                        .transition()\n                        .delay(function(d,e){\n                            return 100+e/dataset.length*1000;\n                        })\n                        .duration(500)\n                        .ease(\"linear\")\n                        .text(function(d){\n                            return d;\n                        })\n                        .attr(\"y\",function(){\n                            return h-5;\n                        })\n                        .attr(\"font-family\",\"sans-serif\")\n                        .attr(\"font-size\",function(){\n                            return w/dataset.length-barPadding-5;\n                        })\n                        .attr(\"text-anchor\",\"middle\")\n                        .attr(\"fill\",\"white\")\n                        .attr(\"stroke\",function(d){\n                            return yScale(d) <= (w/dataset.length-barPadding-1) ? \"black\" : \"white\"\n                        });\n\n                svg_plain_rects.exit().remove();\n                svg_plain_txt.exit().remove();\n            }\n\n            /*var xScale = d3.scale.linear()\n                    .domain([0,d3.max(setset,function(d){return d[0];})])\n                    .range([circlePadding,w - circlePadding * 2]);\n            var yScale = d3.scale.linear()\n                    .domain([0,d3.max(setset,function(d){return d[1];})])\n                    .range([h - circlePadding,circlePadding]);\n            var rScale = d3.scale.linear()\n                    .domain([0,d3.max(setset,function(d){return d[1];})])\n                    .range([2,15]);\n            var xAxis = d3.svg.axis()\n                    .scale(xScale)\n                    .orient(\"bottom\")\n                    .ticks(5);\n            var yAxis = d3.svg.axis()\n                    .scale(yScale)\n                    .orient(\"left\")\n                    .ticks(5);\n\n            var svg_scatter = d3.select(\"body\")\n                    .append(\"svg\")\n                    .attr(\"width\",w)\n                    .attr(\"height\",h);\n            svg_scatter.selectAll(\"circle\")\n                    .data(setset)\n                    .enter()\n                    .append(\"circle\")\n                    .attr(\"cx\",function(d){return xScale(d[0]);})\n                    .attr(\"cy\",function(d){return yScale(d[1]);})\n                    .attr(\"r\",function(d){return rScale(d[1]);});\n            svg_scatter.selectAll(\"line\")\n                    .data(setset)\n                    .enter()\n                    .append(\"line\")\n                    .attr(\"x1\",function(d){return xScale(d[0]);})\n                    .attr(\"y1\",function(d){return yScale(d[1]);})\n                    .attr(\"x2\",function(d){return xScale(d[0])+20;})\n                    .attr(\"y2\",function(d){return yScale(d[1])-5;})\n                    .attr(\"stroke\",\"blue\");\n            svg_scatter.selectAll(\"text\")\n                    .data(setset)\n                    .enter()\n                    .append(\"text\")\n                    .text(function(d){return d[0]+\",\"+d[1];})\n                    .attr(\"x\",function(d){return xScale(d[0])+20;})\n                    .attr(\"y\",function(d){return yScale(d[1]);})\n                    .attr(\"font-family\",\"sans-serif\")\n                    .attr(\"font-size\",\"11px\")\n                    .attr(\"fill\",\"blue\");\n\n            svg_scatter.append(\"g\")\n                    .attr(\"class\",\"axis\")\n                    .attr(\"transform\",\"translate(0,\"+(h-circlePadding)+\")\")\n                    .call(xAxis);\n            svg_scatter.append(\"g\")\n                    .attr(\"class\",\"axis\")\n                    .attr(\"transform\",\"translate(\"+circlePadding+\",0)\")\n                    .call(yAxis);\n            */\n            /*var circles = svg.selectAll(\"circles\")\n                    .data(dataset)\n                    .enter()\n                    .append(\"circle\")\n                    .attr(\"fill\",makeRandomColor());\n            circles.attr(\"cx\", function(d,i) {\n                return (i*50)+25;\n            })\n                    .attr(\"cy\",h/2)\n                    .attr(\"r\",function(d){return d;});\n            */\n\n            function getRandom(array, max) {\n                bars = Math.round(Math.random()*100);\n                console.log(\"random! #bars: \" +bars);\n                array = [];\n                if (max === undefined) {\n                    for (var i = 0; i < bars; i++) {\n                        array.push(Math.round(Math.random()*100));\n                    }\n                } else {\n                    for (var i = 0; i < bars; i++) {\n                        array.push(Math.round((Math.random()*100)%max));\n                    }\n                }\n\n                return array;\n            }\n\n            function bubbleSort(array) {\n                for (var i = 0; i < array.length; i++) {\n                    for (var j = 0; j < array.length-1; j++) {\n                        if (array[j] > array[j+1]) {\n                            var temp = array[j+1];\n                            array[j+1] = array[j];\n                            array[j] = temp;\n                        }\n                    }\n                }\n                return array;\n            }\n\n            function makeRandomColor() {\n                var r = Math.round((Math.random()*1000)+(Math.random()*100)+(Math.random()*10))%255;\n                var g = Math.round((Math.random()*1000)+(Math.random()*100)+(Math.random()*10))%255;\n                var b = Math.round((Math.random()*1000)+(Math.random()*100)+(Math.random()*10))%255;\n                console.log(\"r\"+r+\"g\"+g+\"b\"+b);\n                return \"#\"+to2DigitHex(r)+to2DigitHex(g)+to2DigitHex(b);\n            }\n\n            function to2DigitHex(val) {\n                var firstDigit = Math.floor(val/16);\n                var secDigit = val - firstDigit*16;\n                console.log(\"1stDigit: \" +firstDigit+ \" | \" +toHexDigit(firstDigit)+ \" ; 2ndDigit: \" +secDigit+ \" | \" +toHexDigit(secDigit));\n                return \"\"+(toHexDigit(firstDigit))+(toHexDigit(secDigit));\n            }\n\n            function toHexDigit(val) {\n                return (val <= 9 ? val :\n                                (val == 10 ? \"a\" :\n                                                (val == 11 ? \"b\" :\n                                                                (val == 12 ? \"c\" :\n                                                                                (val == 13 ? \"d\" :\n                                                                                                (val == 14 ? \"e\" :\n                                                                                                                (val == 15 ? \"f\" : \"x\")\n                                                                                                )\n                                                                                )\n                                                                )\n                                                )\n                                )\n                );\n            }\n        </script>\n    </body>\n</html>"
  },
  {
    "path": "code/web/docker-compose.yml",
    "content": "version: '2'\nservices:\n  web:\n    build:\n      context: .\n      dockerfile: ./Dockerfile\n    ports:\n      - \"8000:8000\"\n    entrypoint: http-server -p 8000 -c-1 /app/\n    # interactive: true\n    #environment:\n    #  DOCKER_CACHING_TIME: 5\n    #  NODE_PORT: 4458\n    #  NODE_DEBUGGER: 0\n"
  },
  {
    "path": "code/web/entrypoint.sh",
    "content": "#!/usr/bin/env bash\nset -e;\n\n# first use first program parameter, if not set use $PORT, if that is undefined use default 8000.\nPORT=${PORT:-8000}\nPORT=${1:-$PORT}\nAPI_URL=${API_URL:-http://localhost}\nJS_PATH=${JS_PATH:-/app/}\n\nSECRET_FILE='src/config.js'\necho \"'use strict';\" > $SECRET_FILE;\necho \"\" >> $SECRET_FILE;\necho \"var _API_URL = \\\"$API_URL\\\";\" >> $SECRET_FILE;\n\necho \"Starting server on port $PORT (\\$PORT), serving path \\\"$JS_PATH\\\" (\\$JS_PATH).\"\necho \"The browser will connect to the API at \\\"$API_URL\\\" (\\$API_URL).\"\n\nCOMMAND=\"http-server -p $PORT -c-1 $JS_PATH\"\necho \"\\$ $COMMAND\"\n\n$COMMAND"
  },
  {
    "path": "code/web/example/api/v2/get_timeline/index.html",
    "content": "{\n  \"events\": [\n    {\n      \"action\": \"send\",\n      \"data\": {\n        \"node\": 1,\n        \"sequence_no\": 298111723,\n        \"type\": 1,\n        \"value\": 7.23430061340332\n      },\n      \"id\": {\n        \"send\": 68317\n      },\n      \"nodes\": {\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.079226\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 1,\n        \"sequence_no\": 298111723,\n        \"type\": 1,\n        \"value\": 7.23430061340332\n      },\n      \"id\": {\n        \"receive\": 68318,\n        \"send\": 68317\n      },\n      \"nodes\": {\n        \"receive\": 1,\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.117529\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.079226\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 1,\n        \"sequence_no\": 298111723,\n        \"type\": 1,\n        \"value\": 7.23430061340332\n      },\n      \"id\": {\n        \"receive\": 68319,\n        \"send\": 68317\n      },\n      \"nodes\": {\n        \"receive\": 3,\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.146206\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.079226\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 1,\n        \"sequence_no\": 298111723,\n        \"type\": 1,\n        \"value\": 7.23430061340332\n      },\n      \"id\": {\n        \"receive\": 68320,\n        \"send\": 68317\n      },\n      \"nodes\": {\n        \"receive\": 4,\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.160484\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.079226\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 1,\n        \"sequence_no\": 298111723,\n        \"type\": 1,\n        \"value\": 7.23430061340332\n      },\n      \"id\": {\n        \"receive\": 68321,\n        \"send\": 68317\n      },\n      \"nodes\": {\n        \"receive\": 2,\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.172507\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.079226\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"send\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 1,\n        \"proposal\": 6.1647744178772,\n        \"sequence_no\": 298111723,\n        \"type\": 2,\n        \"value_store\": [\n          {\n            \"node\": 3,\n            \"sequence_no\": 298111722,\n            \"type\": 1,\n            \"value\": 6.164774417877197\n          },\n          {\n            \"node\": 2,\n            \"sequence_no\": 298111722,\n            \"type\": 1,\n            \"value\": 3.569486618041992\n          },\n          {\n            \"node\": 4,\n            \"sequence_no\": 298111722,\n            \"type\": 1,\n            \"value\": 2.458043336868286\n          },\n          {\n            \"node\": 1,\n            \"sequence_no\": 298111722,\n            \"type\": 1,\n            \"value\": 6.970949649810791\n          },\n          {\n            \"node\": 1,\n            \"sequence_no\": 298111723,\n            \"type\": 1,\n            \"value\": 7.23430061340332\n          }\n        ]\n      },\n      \"id\": {\n        \"send\": 68322\n      },\n      \"nodes\": {\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.184613\n        }\n      },\n      \"type\": \"propose\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 1,\n        \"proposal\": 6.164774417877197,\n        \"sequence_no\": 298111723,\n        \"type\": 2,\n        \"value_store\": [\n          {\n            \"node\": 3,\n            \"sequence_no\": 298111722,\n            \"type\": 1,\n            \"value\": 6.164774417877197\n          },\n          {\n            \"node\": 2,\n            \"sequence_no\": 298111722,\n            \"type\": 1,\n            \"value\": 3.569486618041992\n          },\n          {\n            \"node\": 4,\n            \"sequence_no\": 298111722,\n            \"type\": 1,\n            \"value\": 2.458043336868286\n          },\n          {\n            \"node\": 1,\n            \"sequence_no\": 298111722,\n            \"type\": 1,\n            \"value\": 6.970949649810791\n          },\n          {\n            \"node\": 1,\n            \"sequence_no\": 298111723,\n            \"type\": 1,\n            \"value\": 7.23430061340332\n          }\n        ]\n      },\n      \"id\": {\n        \"receive\": 68323,\n        \"send\": 68322\n      },\n      \"nodes\": {\n        \"receive\": 4,\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.223817\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.184613\n        }\n      },\n      \"type\": \"propose\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 1,\n        \"proposal\": 6.164774417877197,\n        \"sequence_no\": 298111723,\n        \"type\": 2,\n        \"value_store\": [\n          {\n            \"node\": 3,\n            \"sequence_no\": 298111722,\n            \"type\": 1,\n            \"value\": 6.164774417877197\n          },\n          {\n            \"node\": 2,\n            \"sequence_no\": 298111722,\n            \"type\": 1,\n            \"value\": 3.569486618041992\n          },\n          {\n            \"node\": 4,\n            \"sequence_no\": 298111722,\n            \"type\": 1,\n            \"value\": 2.458043336868286\n          },\n          {\n            \"node\": 1,\n            \"sequence_no\": 298111722,\n            \"type\": 1,\n            \"value\": 6.970949649810791\n          },\n          {\n            \"node\": 1,\n            \"sequence_no\": 298111723,\n            \"type\": 1,\n            \"value\": 7.23430061340332\n          }\n        ]\n      },\n      \"id\": {\n        \"receive\": 68324,\n        \"send\": 68322\n      },\n      \"nodes\": {\n        \"receive\": 3,\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.238699\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.184613\n        }\n      },\n      \"type\": \"propose\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 1,\n        \"proposal\": 6.164774417877197,\n        \"sequence_no\": 298111723,\n        \"type\": 2,\n        \"value_store\": [\n          {\n            \"node\": 3,\n            \"sequence_no\": 298111722,\n            \"type\": 1,\n            \"value\": 6.164774417877197\n          },\n          {\n            \"node\": 2,\n            \"sequence_no\": 298111722,\n            \"type\": 1,\n            \"value\": 3.569486618041992\n          },\n          {\n            \"node\": 4,\n            \"sequence_no\": 298111722,\n            \"type\": 1,\n            \"value\": 2.458043336868286\n          },\n          {\n            \"node\": 1,\n            \"sequence_no\": 298111722,\n            \"type\": 1,\n            \"value\": 6.970949649810791\n          },\n          {\n            \"node\": 1,\n            \"sequence_no\": 298111723,\n            \"type\": 1,\n            \"value\": 7.23430061340332\n          }\n        ]\n      },\n      \"id\": {\n        \"receive\": 68325,\n        \"send\": 68322\n      },\n      \"nodes\": {\n        \"receive\": 2,\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.251722\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.184613\n        }\n      },\n      \"type\": \"propose\"\n    },\n    {\n      \"action\": \"send\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 1,\n        \"sequence_no\": 298111723,\n        \"type\": 3,\n        \"value\": 6.1647744178772\n      },\n      \"id\": {\n        \"send\": 68326\n      },\n      \"nodes\": {\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.263576\n        }\n      },\n      \"type\": \"prevote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 1,\n        \"sequence_no\": 298111723,\n        \"type\": 3,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68327,\n        \"send\": 68326\n      },\n      \"nodes\": {\n        \"receive\": 4,\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.297539\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.263576\n        }\n      },\n      \"type\": \"prevote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 1,\n        \"sequence_no\": 298111723,\n        \"type\": 3,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68328,\n        \"send\": 68326\n      },\n      \"nodes\": {\n        \"receive\": 3,\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.32096\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.263576\n        }\n      },\n      \"type\": \"prevote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 1,\n        \"sequence_no\": 298111723,\n        \"type\": 3,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68329,\n        \"send\": 68326\n      },\n      \"nodes\": {\n        \"receive\": 2,\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.348517\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.263576\n        }\n      },\n      \"type\": \"prevote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 1,\n        \"proposal\": 6.164774417877197,\n        \"sequence_no\": 298111723,\n        \"type\": 2,\n        \"value_store\": [\n          {\n            \"node\": 3,\n            \"sequence_no\": 298111722,\n            \"type\": 1,\n            \"value\": 6.164774417877197\n          },\n          {\n            \"node\": 2,\n            \"sequence_no\": 298111722,\n            \"type\": 1,\n            \"value\": 3.569486618041992\n          },\n          {\n            \"node\": 4,\n            \"sequence_no\": 298111722,\n            \"type\": 1,\n            \"value\": 2.458043336868286\n          },\n          {\n            \"node\": 1,\n            \"sequence_no\": 298111722,\n            \"type\": 1,\n            \"value\": 6.970949649810791\n          },\n          {\n            \"node\": 1,\n            \"sequence_no\": 298111723,\n            \"type\": 1,\n            \"value\": 7.23430061340332\n          }\n        ]\n      },\n      \"id\": {\n        \"receive\": 68330,\n        \"send\": 68322\n      },\n      \"nodes\": {\n        \"receive\": 1,\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.370485\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.184613\n        }\n      },\n      \"type\": \"propose\"\n    },\n    {\n      \"action\": \"send\",\n      \"data\": {\n        \"node\": 3,\n        \"sequence_no\": 298111723,\n        \"type\": 1,\n        \"value\": 0.694884359836578\n      },\n      \"id\": {\n        \"send\": 68331\n      },\n      \"nodes\": {\n        \"send\": 3\n      },\n      \"timestamps\": {\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.384545\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 1,\n        \"sequence_no\": 298111723,\n        \"type\": 3,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68332,\n        \"send\": 68326\n      },\n      \"nodes\": {\n        \"receive\": 1,\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.424323\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.263576\n        }\n      },\n      \"type\": \"prevote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 3,\n        \"sequence_no\": 298111723,\n        \"type\": 1,\n        \"value\": 0.6948843598365784\n      },\n      \"id\": {\n        \"receive\": 68333,\n        \"send\": 68331\n      },\n      \"nodes\": {\n        \"receive\": 4,\n        \"send\": 3\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.468844\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.384545\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 3,\n        \"sequence_no\": 298111723,\n        \"type\": 1,\n        \"value\": 0.6948843598365784\n      },\n      \"id\": {\n        \"receive\": 68334,\n        \"send\": 68331\n      },\n      \"nodes\": {\n        \"receive\": 2,\n        \"send\": 3\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.499564\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.384545\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 3,\n        \"sequence_no\": 298111723,\n        \"type\": 1,\n        \"value\": 0.6948843598365784\n      },\n      \"id\": {\n        \"receive\": 68335,\n        \"send\": 68331\n      },\n      \"nodes\": {\n        \"receive\": 3,\n        \"send\": 3\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.513264\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.384545\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"send\",\n      \"data\": {\n        \"node\": 4,\n        \"sequence_no\": 298111723,\n        \"type\": 1,\n        \"value\": 7.75692510604858\n      },\n      \"id\": {\n        \"send\": 68336\n      },\n      \"nodes\": {\n        \"send\": 4\n      },\n      \"timestamps\": {\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.531546\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"send\",\n      \"data\": {\n        \"node\": 2,\n        \"sequence_no\": 298111723,\n        \"type\": 1,\n        \"value\": 1.71371591091156\n      },\n      \"id\": {\n        \"send\": 68337\n      },\n      \"nodes\": {\n        \"send\": 2\n      },\n      \"timestamps\": {\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.559259\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 3,\n        \"sequence_no\": 298111723,\n        \"type\": 1,\n        \"value\": 0.6948843598365784\n      },\n      \"id\": {\n        \"receive\": 68338,\n        \"send\": 68331\n      },\n      \"nodes\": {\n        \"receive\": 1,\n        \"send\": 3\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.57986\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.384545\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"send\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 3,\n        \"sequence_no\": 298111723,\n        \"type\": 3,\n        \"value\": 6.1647744178772\n      },\n      \"id\": {\n        \"send\": 68339\n      },\n      \"nodes\": {\n        \"send\": 3\n      },\n      \"timestamps\": {\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.598602\n        }\n      },\n      \"type\": \"prevote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 4,\n        \"sequence_no\": 298111723,\n        \"type\": 1,\n        \"value\": 7.756925106048584\n      },\n      \"id\": {\n        \"receive\": 68340,\n        \"send\": 68336\n      },\n      \"nodes\": {\n        \"receive\": 2,\n        \"send\": 4\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.636808\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.531546\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 4,\n        \"sequence_no\": 298111723,\n        \"type\": 1,\n        \"value\": 7.756925106048584\n      },\n      \"id\": {\n        \"receive\": 68341,\n        \"send\": 68336\n      },\n      \"nodes\": {\n        \"receive\": 4,\n        \"send\": 4\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.680829\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.531546\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"send\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 2,\n        \"sequence_no\": 298111723,\n        \"type\": 3,\n        \"value\": 6.1647744178772\n      },\n      \"id\": {\n        \"send\": 68342\n      },\n      \"nodes\": {\n        \"send\": 2\n      },\n      \"timestamps\": {\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.718341\n        }\n      },\n      \"type\": \"prevote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 4,\n        \"sequence_no\": 298111723,\n        \"type\": 1,\n        \"value\": 7.756925106048584\n      },\n      \"id\": {\n        \"receive\": 68343,\n        \"send\": 68336\n      },\n      \"nodes\": {\n        \"receive\": 1,\n        \"send\": 4\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.74658\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.531546\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 4,\n        \"sequence_no\": 298111723,\n        \"type\": 1,\n        \"value\": 7.756925106048584\n      },\n      \"id\": {\n        \"receive\": 68344,\n        \"send\": 68336\n      },\n      \"nodes\": {\n        \"receive\": 3,\n        \"send\": 4\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.789794\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.531546\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"send\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 4,\n        \"sequence_no\": 298111723,\n        \"type\": 3,\n        \"value\": 6.1647744178772\n      },\n      \"id\": {\n        \"send\": 68345\n      },\n      \"nodes\": {\n        \"send\": 4\n      },\n      \"timestamps\": {\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.825813\n        }\n      },\n      \"type\": \"prevote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 2,\n        \"sequence_no\": 298111723,\n        \"type\": 1,\n        \"value\": 1.71371591091156\n      },\n      \"id\": {\n        \"receive\": 68346,\n        \"send\": 68337\n      },\n      \"nodes\": {\n        \"receive\": 2,\n        \"send\": 2\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.857244\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.559259\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 2,\n        \"sequence_no\": 298111723,\n        \"type\": 1,\n        \"value\": 1.71371591091156\n      },\n      \"id\": {\n        \"receive\": 68347,\n        \"send\": 68337\n      },\n      \"nodes\": {\n        \"receive\": 3,\n        \"send\": 2\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.894072\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.559259\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"send\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 1,\n        \"sequence_no\": 298111723,\n        \"type\": 4,\n        \"value\": 6.1647744178772\n      },\n      \"id\": {\n        \"send\": 68348\n      },\n      \"nodes\": {\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.933549\n        }\n      },\n      \"type\": \"vote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 3,\n        \"sequence_no\": 298111723,\n        \"type\": 3,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68349,\n        \"send\": 68339\n      },\n      \"nodes\": {\n        \"receive\": 2,\n        \"send\": 3\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.993445\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.598602\n        }\n      },\n      \"type\": \"prevote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 2,\n        \"sequence_no\": 298111723,\n        \"type\": 1,\n        \"value\": 1.71371591091156\n      },\n      \"id\": {\n        \"receive\": 68350,\n        \"send\": 68337\n      },\n      \"nodes\": {\n        \"receive\": 4,\n        \"send\": 2\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:36 GMT\",\n          \"unix\": 1490558616.036265\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.559259\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 3,\n        \"sequence_no\": 298111723,\n        \"type\": 3,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68351,\n        \"send\": 68339\n      },\n      \"nodes\": {\n        \"receive\": 3,\n        \"send\": 3\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:36 GMT\",\n          \"unix\": 1490558616.113367\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.598602\n        }\n      },\n      \"type\": \"prevote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 2,\n        \"sequence_no\": 298111723,\n        \"type\": 1,\n        \"value\": 1.71371591091156\n      },\n      \"id\": {\n        \"receive\": 68352,\n        \"send\": 68337\n      },\n      \"nodes\": {\n        \"receive\": 1,\n        \"send\": 2\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:36 GMT\",\n          \"unix\": 1490558616.176518\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.559259\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 2,\n        \"sequence_no\": 298111723,\n        \"type\": 3,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68353,\n        \"send\": 68342\n      },\n      \"nodes\": {\n        \"receive\": 2,\n        \"send\": 2\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:36 GMT\",\n          \"unix\": 1490558616.208524\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.718341\n        }\n      },\n      \"type\": \"prevote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 3,\n        \"sequence_no\": 298111723,\n        \"type\": 3,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68354,\n        \"send\": 68339\n      },\n      \"nodes\": {\n        \"receive\": 4,\n        \"send\": 3\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:36 GMT\",\n          \"unix\": 1490558616.242285\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.598602\n        }\n      },\n      \"type\": \"prevote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 3,\n        \"sequence_no\": 298111723,\n        \"type\": 3,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68355,\n        \"send\": 68339\n      },\n      \"nodes\": {\n        \"receive\": 1,\n        \"send\": 3\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:36 GMT\",\n          \"unix\": 1490558616.281475\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.598602\n        }\n      },\n      \"type\": \"prevote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 2,\n        \"sequence_no\": 298111723,\n        \"type\": 3,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68356,\n        \"send\": 68342\n      },\n      \"nodes\": {\n        \"receive\": 3,\n        \"send\": 2\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:36 GMT\",\n          \"unix\": 1490558616.319874\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.718341\n        }\n      },\n      \"type\": \"prevote\"\n    },\n    {\n      \"action\": \"send\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 2,\n        \"sequence_no\": 298111723,\n        \"type\": 4,\n        \"value\": 6.1647744178772\n      },\n      \"id\": {\n        \"send\": 68357\n      },\n      \"nodes\": {\n        \"send\": 2\n      },\n      \"timestamps\": {\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:36 GMT\",\n          \"unix\": 1490558616.344503\n        }\n      },\n      \"type\": \"vote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 2,\n        \"sequence_no\": 298111723,\n        \"type\": 3,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68358,\n        \"send\": 68342\n      },\n      \"nodes\": {\n        \"receive\": 1,\n        \"send\": 2\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:36 GMT\",\n          \"unix\": 1490558616.368168\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.718341\n        }\n      },\n      \"type\": \"prevote\"\n    },\n    {\n      \"action\": \"send\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 4,\n        \"sequence_no\": 298111723,\n        \"type\": 4,\n        \"value\": 6.1647744178772\n      },\n      \"id\": {\n        \"send\": 68359\n      },\n      \"nodes\": {\n        \"send\": 4\n      },\n      \"timestamps\": {\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:36 GMT\",\n          \"unix\": 1490558616.422657\n        }\n      },\n      \"type\": \"vote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 4,\n        \"sequence_no\": 298111723,\n        \"type\": 3,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68360,\n        \"send\": 68345\n      },\n      \"nodes\": {\n        \"receive\": 2,\n        \"send\": 4\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:36 GMT\",\n          \"unix\": 1490558616.446184\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.825813\n        }\n      },\n      \"type\": \"prevote\"\n    },\n    {\n      \"action\": \"send\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 3,\n        \"sequence_no\": 298111723,\n        \"type\": 4,\n        \"value\": 6.1647744178772\n      },\n      \"id\": {\n        \"send\": 68361\n      },\n      \"nodes\": {\n        \"send\": 3\n      },\n      \"timestamps\": {\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:36 GMT\",\n          \"unix\": 1490558616.46845\n        }\n      },\n      \"type\": \"vote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 4,\n        \"sequence_no\": 298111723,\n        \"type\": 3,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68362,\n        \"send\": 68345\n      },\n      \"nodes\": {\n        \"receive\": 1,\n        \"send\": 4\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:36 GMT\",\n          \"unix\": 1490558616.50039\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.825813\n        }\n      },\n      \"type\": \"prevote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 2,\n        \"sequence_no\": 298111723,\n        \"type\": 3,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68363,\n        \"send\": 68342\n      },\n      \"nodes\": {\n        \"receive\": 4,\n        \"send\": 2\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:36 GMT\",\n          \"unix\": 1490558616.531405\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.718341\n        }\n      },\n      \"type\": \"prevote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 1,\n        \"sequence_no\": 298111723,\n        \"type\": 4,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68364,\n        \"send\": 68348\n      },\n      \"nodes\": {\n        \"receive\": 2,\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:36 GMT\",\n          \"unix\": 1490558616.549436\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.933549\n        }\n      },\n      \"type\": \"vote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 4,\n        \"sequence_no\": 298111723,\n        \"type\": 3,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68365,\n        \"send\": 68345\n      },\n      \"nodes\": {\n        \"receive\": 3,\n        \"send\": 4\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:36 GMT\",\n          \"unix\": 1490558616.568338\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.825813\n        }\n      },\n      \"type\": \"prevote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 1,\n        \"sequence_no\": 298111723,\n        \"type\": 4,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68366,\n        \"send\": 68348\n      },\n      \"nodes\": {\n        \"receive\": 1,\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:36 GMT\",\n          \"unix\": 1490558616.587922\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.933549\n        }\n      },\n      \"type\": \"vote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 4,\n        \"sequence_no\": 298111723,\n        \"type\": 3,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68367,\n        \"send\": 68345\n      },\n      \"nodes\": {\n        \"receive\": 4,\n        \"send\": 4\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:36 GMT\",\n          \"unix\": 1490558616.613553\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.825813\n        }\n      },\n      \"type\": \"prevote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 2,\n        \"sequence_no\": 298111723,\n        \"type\": 4,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68368,\n        \"send\": 68357\n      },\n      \"nodes\": {\n        \"receive\": 2,\n        \"send\": 2\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:36 GMT\",\n          \"unix\": 1490558616.65048\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:36 GMT\",\n          \"unix\": 1490558616.344503\n        }\n      },\n      \"type\": \"vote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 1,\n        \"sequence_no\": 298111723,\n        \"type\": 4,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68369,\n        \"send\": 68348\n      },\n      \"nodes\": {\n        \"receive\": 3,\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:36 GMT\",\n          \"unix\": 1490558616.668285\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.933549\n        }\n      },\n      \"type\": \"vote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 1,\n        \"sequence_no\": 298111723,\n        \"type\": 4,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68370,\n        \"send\": 68348\n      },\n      \"nodes\": {\n        \"receive\": 4,\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:36 GMT\",\n          \"unix\": 1490558616.695515\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n          \"unix\": 1490558615.933549\n        }\n      },\n      \"type\": \"vote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 2,\n        \"sequence_no\": 298111723,\n        \"type\": 4,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68371,\n        \"send\": 68357\n      },\n      \"nodes\": {\n        \"receive\": 1,\n        \"send\": 2\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:36 GMT\",\n          \"unix\": 1490558616.729508\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:36 GMT\",\n          \"unix\": 1490558616.344503\n        }\n      },\n      \"type\": \"vote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 4,\n        \"sequence_no\": 298111723,\n        \"type\": 4,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68372,\n        \"send\": 68359\n      },\n      \"nodes\": {\n        \"receive\": 2,\n        \"send\": 4\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:36 GMT\",\n          \"unix\": 1490558616.772382\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:36 GMT\",\n          \"unix\": 1490558616.422657\n        }\n      },\n      \"type\": \"vote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 2,\n        \"sequence_no\": 298111723,\n        \"type\": 4,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68373,\n        \"send\": 68357\n      },\n      \"nodes\": {\n        \"receive\": 3,\n        \"send\": 2\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:36 GMT\",\n          \"unix\": 1490558616.808814\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:36 GMT\",\n          \"unix\": 1490558616.344503\n        }\n      },\n      \"type\": \"vote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 2,\n        \"sequence_no\": 298111723,\n        \"type\": 4,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68374,\n        \"send\": 68357\n      },\n      \"nodes\": {\n        \"receive\": 4,\n        \"send\": 2\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:36 GMT\",\n          \"unix\": 1490558616.849705\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:36 GMT\",\n          \"unix\": 1490558616.344503\n        }\n      },\n      \"type\": \"vote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 4,\n        \"sequence_no\": 298111723,\n        \"type\": 4,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68375,\n        \"send\": 68359\n      },\n      \"nodes\": {\n        \"receive\": 1,\n        \"send\": 4\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:36 GMT\",\n          \"unix\": 1490558616.912457\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:36 GMT\",\n          \"unix\": 1490558616.422657\n        }\n      },\n      \"type\": \"vote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 4,\n        \"sequence_no\": 298111723,\n        \"type\": 4,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68376,\n        \"send\": 68359\n      },\n      \"nodes\": {\n        \"receive\": 3,\n        \"send\": 4\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:36 GMT\",\n          \"unix\": 1490558616.978688\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:36 GMT\",\n          \"unix\": 1490558616.422657\n        }\n      },\n      \"type\": \"vote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 4,\n        \"sequence_no\": 298111723,\n        \"type\": 4,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68377,\n        \"send\": 68359\n      },\n      \"nodes\": {\n        \"receive\": 4,\n        \"send\": 4\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:37 GMT\",\n          \"unix\": 1490558617.066265\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:36 GMT\",\n          \"unix\": 1490558616.422657\n        }\n      },\n      \"type\": \"vote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 3,\n        \"sequence_no\": 298111723,\n        \"type\": 4,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68378,\n        \"send\": 68361\n      },\n      \"nodes\": {\n        \"receive\": 1,\n        \"send\": 3\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:37 GMT\",\n          \"unix\": 1490558617.110159\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:36 GMT\",\n          \"unix\": 1490558616.46845\n        }\n      },\n      \"type\": \"vote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 3,\n        \"sequence_no\": 298111723,\n        \"type\": 4,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68379,\n        \"send\": 68361\n      },\n      \"nodes\": {\n        \"receive\": 3,\n        \"send\": 3\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:37 GMT\",\n          \"unix\": 1490558617.167484\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:36 GMT\",\n          \"unix\": 1490558616.46845\n        }\n      },\n      \"type\": \"vote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 3,\n        \"sequence_no\": 298111723,\n        \"type\": 4,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68380,\n        \"send\": 68361\n      },\n      \"nodes\": {\n        \"receive\": 2,\n        \"send\": 3\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:37 GMT\",\n          \"unix\": 1490558617.179415\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:36 GMT\",\n          \"unix\": 1490558616.46845\n        }\n      },\n      \"type\": \"vote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 3,\n        \"sequence_no\": 298111723,\n        \"type\": 4,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68381,\n        \"send\": 68361\n      },\n      \"nodes\": {\n        \"receive\": 4,\n        \"send\": 3\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:37 GMT\",\n          \"unix\": 1490558617.190296\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:36 GMT\",\n          \"unix\": 1490558616.46845\n        }\n      },\n      \"type\": \"vote\"\n    },\n    {\n      \"action\": \"send\",\n      \"data\": {\n        \"node\": 1,\n        \"sequence_no\": 298111724,\n        \"type\": 1,\n        \"value\": 4.35809087753296\n      },\n      \"id\": {\n        \"send\": 68382\n      },\n      \"nodes\": {\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.060954\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 1,\n        \"sequence_no\": 298111724,\n        \"type\": 1,\n        \"value\": 4.358090877532959\n      },\n      \"id\": {\n        \"receive\": 68383,\n        \"send\": 68382\n      },\n      \"nodes\": {\n        \"receive\": 1,\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.0892\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.060954\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 1,\n        \"sequence_no\": 298111724,\n        \"type\": 1,\n        \"value\": 4.358090877532959\n      },\n      \"id\": {\n        \"receive\": 68384,\n        \"send\": 68382\n      },\n      \"nodes\": {\n        \"receive\": 4,\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.125562\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.060954\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 1,\n        \"sequence_no\": 298111724,\n        \"type\": 1,\n        \"value\": 4.358090877532959\n      },\n      \"id\": {\n        \"receive\": 68385,\n        \"send\": 68382\n      },\n      \"nodes\": {\n        \"receive\": 2,\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.171997\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.060954\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 1,\n        \"sequence_no\": 298111724,\n        \"type\": 1,\n        \"value\": 4.358090877532959\n      },\n      \"id\": {\n        \"receive\": 68386,\n        \"send\": 68382\n      },\n      \"nodes\": {\n        \"receive\": 3,\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.203967\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.060954\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"send\",\n      \"data\": {\n        \"node\": 3,\n        \"sequence_no\": 298111724,\n        \"type\": 1,\n        \"value\": 7.8886079788208\n      },\n      \"id\": {\n        \"send\": 68387\n      },\n      \"nodes\": {\n        \"send\": 3\n      },\n      \"timestamps\": {\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.222616\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"send\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 1,\n        \"proposal\": 4.35809087753296,\n        \"sequence_no\": 298111724,\n        \"type\": 2,\n        \"value_store\": [\n          {\n            \"node\": 1,\n            \"sequence_no\": 298111723,\n            \"type\": 1,\n            \"value\": 7.23430061340332\n          },\n          {\n            \"node\": 3,\n            \"sequence_no\": 298111723,\n            \"type\": 1,\n            \"value\": 0.6948843598365784\n          },\n          {\n            \"node\": 4,\n            \"sequence_no\": 298111723,\n            \"type\": 1,\n            \"value\": 7.756925106048584\n          },\n          {\n            \"node\": 2,\n            \"sequence_no\": 298111723,\n            \"type\": 1,\n            \"value\": 1.71371591091156\n          },\n          {\n            \"node\": 1,\n            \"sequence_no\": 298111724,\n            \"type\": 1,\n            \"value\": 4.358090877532959\n          }\n        ]\n      },\n      \"id\": {\n        \"send\": 68388\n      },\n      \"nodes\": {\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.25346\n        }\n      },\n      \"type\": \"propose\"\n    },\n    {\n      \"action\": \"send\",\n      \"data\": {\n        \"node\": 2,\n        \"sequence_no\": 298111724,\n        \"type\": 1,\n        \"value\": 9.73530006408691\n      },\n      \"id\": {\n        \"send\": 68389\n      },\n      \"nodes\": {\n        \"send\": 2\n      },\n      \"timestamps\": {\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.2805\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"send\",\n      \"data\": {\n        \"node\": 4,\n        \"sequence_no\": 298111724,\n        \"type\": 1,\n        \"value\": 0.359470218420029\n      },\n      \"id\": {\n        \"send\": 68390\n      },\n      \"nodes\": {\n        \"send\": 4\n      },\n      \"timestamps\": {\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.306264\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 3,\n        \"sequence_no\": 298111724,\n        \"type\": 1,\n        \"value\": 7.888607978820801\n      },\n      \"id\": {\n        \"receive\": 68391,\n        \"send\": 68387\n      },\n      \"nodes\": {\n        \"receive\": 4,\n        \"send\": 3\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.333955\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.222616\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 3,\n        \"sequence_no\": 298111724,\n        \"type\": 1,\n        \"value\": 7.888607978820801\n      },\n      \"id\": {\n        \"receive\": 68392,\n        \"send\": 68387\n      },\n      \"nodes\": {\n        \"receive\": 3,\n        \"send\": 3\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.352303\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.222616\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 3,\n        \"sequence_no\": 298111724,\n        \"type\": 1,\n        \"value\": 7.888607978820801\n      },\n      \"id\": {\n        \"receive\": 68393,\n        \"send\": 68387\n      },\n      \"nodes\": {\n        \"receive\": 2,\n        \"send\": 3\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.376673\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.222616\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"send\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 1,\n        \"sequence_no\": 298111724,\n        \"type\": 3,\n        \"value\": 4.35809087753296\n      },\n      \"id\": {\n        \"send\": 68394\n      },\n      \"nodes\": {\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.409385\n        }\n      },\n      \"type\": \"prevote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 2,\n        \"sequence_no\": 298111724,\n        \"type\": 1,\n        \"value\": 9.735300064086914\n      },\n      \"id\": {\n        \"receive\": 68395,\n        \"send\": 68389\n      },\n      \"nodes\": {\n        \"receive\": 4,\n        \"send\": 2\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.437733\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.2805\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 2,\n        \"sequence_no\": 298111724,\n        \"type\": 1,\n        \"value\": 9.735300064086914\n      },\n      \"id\": {\n        \"receive\": 68396,\n        \"send\": 68389\n      },\n      \"nodes\": {\n        \"receive\": 3,\n        \"send\": 2\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.485383\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.2805\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 2,\n        \"sequence_no\": 298111724,\n        \"type\": 1,\n        \"value\": 9.735300064086914\n      },\n      \"id\": {\n        \"receive\": 68397,\n        \"send\": 68389\n      },\n      \"nodes\": {\n        \"receive\": 2,\n        \"send\": 2\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.536161\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.2805\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"send\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 4,\n        \"sequence_no\": 298111724,\n        \"type\": 3,\n        \"value\": 4.35809087753296\n      },\n      \"id\": {\n        \"send\": 68398\n      },\n      \"nodes\": {\n        \"send\": 4\n      },\n      \"timestamps\": {\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.564023\n        }\n      },\n      \"type\": \"prevote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 3,\n        \"sequence_no\": 298111724,\n        \"type\": 1,\n        \"value\": 7.888607978820801\n      },\n      \"id\": {\n        \"receive\": 68399,\n        \"send\": 68387\n      },\n      \"nodes\": {\n        \"receive\": 1,\n        \"send\": 3\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.587171\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.222616\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"send\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 3,\n        \"sequence_no\": 298111724,\n        \"type\": 3,\n        \"value\": 4.35809087753296\n      },\n      \"id\": {\n        \"send\": 68400\n      },\n      \"nodes\": {\n        \"send\": 3\n      },\n      \"timestamps\": {\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.602183\n        }\n      },\n      \"type\": \"prevote\"\n    },\n    {\n      \"action\": \"send\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 2,\n        \"sequence_no\": 298111724,\n        \"type\": 3,\n        \"value\": 4.35809087753296\n      },\n      \"id\": {\n        \"send\": 68401\n      },\n      \"nodes\": {\n        \"send\": 2\n      },\n      \"timestamps\": {\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.729595\n        }\n      },\n      \"type\": \"prevote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 1,\n        \"proposal\": 4.358090877532959,\n        \"sequence_no\": 298111724,\n        \"type\": 2,\n        \"value_store\": [\n          {\n            \"node\": 1,\n            \"sequence_no\": 298111723,\n            \"type\": 1,\n            \"value\": 7.23430061340332\n          },\n          {\n            \"node\": 3,\n            \"sequence_no\": 298111723,\n            \"type\": 1,\n            \"value\": 0.6948843598365784\n          },\n          {\n            \"node\": 4,\n            \"sequence_no\": 298111723,\n            \"type\": 1,\n            \"value\": 7.756925106048584\n          },\n          {\n            \"node\": 2,\n            \"sequence_no\": 298111723,\n            \"type\": 1,\n            \"value\": 1.71371591091156\n          },\n          {\n            \"node\": 1,\n            \"sequence_no\": 298111724,\n            \"type\": 1,\n            \"value\": 4.358090877532959\n          }\n        ]\n      },\n      \"id\": {\n        \"receive\": 68402,\n        \"send\": 68388\n      },\n      \"nodes\": {\n        \"receive\": 2,\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.959672\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.25346\n        }\n      },\n      \"type\": \"propose\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 1,\n        \"proposal\": 4.358090877532959,\n        \"sequence_no\": 298111724,\n        \"type\": 2,\n        \"value_store\": [\n          {\n            \"node\": 1,\n            \"sequence_no\": 298111723,\n            \"type\": 1,\n            \"value\": 7.23430061340332\n          },\n          {\n            \"node\": 3,\n            \"sequence_no\": 298111723,\n            \"type\": 1,\n            \"value\": 0.6948843598365784\n          },\n          {\n            \"node\": 4,\n            \"sequence_no\": 298111723,\n            \"type\": 1,\n            \"value\": 7.756925106048584\n          },\n          {\n            \"node\": 2,\n            \"sequence_no\": 298111723,\n            \"type\": 1,\n            \"value\": 1.71371591091156\n          },\n          {\n            \"node\": 1,\n            \"sequence_no\": 298111724,\n            \"type\": 1,\n            \"value\": 4.358090877532959\n          }\n        ]\n      },\n      \"id\": {\n        \"receive\": 68403,\n        \"send\": 68388\n      },\n      \"nodes\": {\n        \"receive\": 3,\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:41 GMT\",\n          \"unix\": 1490558621.036251\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.25346\n        }\n      },\n      \"type\": \"propose\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 2,\n        \"sequence_no\": 298111724,\n        \"type\": 1,\n        \"value\": 9.735300064086914\n      },\n      \"id\": {\n        \"receive\": 68404,\n        \"send\": 68389\n      },\n      \"nodes\": {\n        \"receive\": 1,\n        \"send\": 2\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:41 GMT\",\n          \"unix\": 1490558621.114397\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.2805\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 4,\n        \"sequence_no\": 298111724,\n        \"type\": 1,\n        \"value\": 0.3594702184200287\n      },\n      \"id\": {\n        \"receive\": 68405,\n        \"send\": 68390\n      },\n      \"nodes\": {\n        \"receive\": 2,\n        \"send\": 4\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:41 GMT\",\n          \"unix\": 1490558621.148923\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.306264\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"send\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 3,\n        \"sequence_no\": 298111724,\n        \"type\": 4,\n        \"value\": 6.1647744178772\n      },\n      \"id\": {\n        \"send\": 68406\n      },\n      \"nodes\": {\n        \"send\": 3\n      },\n      \"timestamps\": {\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:41 GMT\",\n          \"unix\": 1490558621.209692\n        }\n      },\n      \"type\": \"vote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 1,\n        \"sequence_no\": 298111724,\n        \"type\": 3,\n        \"value\": 4.358090877532959\n      },\n      \"id\": {\n        \"receive\": 68407,\n        \"send\": 68394\n      },\n      \"nodes\": {\n        \"receive\": 2,\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:41 GMT\",\n          \"unix\": 1490558621.318121\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.409385\n        }\n      },\n      \"type\": \"prevote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 1,\n        \"proposal\": 4.358090877532959,\n        \"sequence_no\": 298111724,\n        \"type\": 2,\n        \"value_store\": [\n          {\n            \"node\": 1,\n            \"sequence_no\": 298111723,\n            \"type\": 1,\n            \"value\": 7.23430061340332\n          },\n          {\n            \"node\": 3,\n            \"sequence_no\": 298111723,\n            \"type\": 1,\n            \"value\": 0.6948843598365784\n          },\n          {\n            \"node\": 4,\n            \"sequence_no\": 298111723,\n            \"type\": 1,\n            \"value\": 7.756925106048584\n          },\n          {\n            \"node\": 2,\n            \"sequence_no\": 298111723,\n            \"type\": 1,\n            \"value\": 1.71371591091156\n          },\n          {\n            \"node\": 1,\n            \"sequence_no\": 298111724,\n            \"type\": 1,\n            \"value\": 4.358090877532959\n          }\n        ]\n      },\n      \"id\": {\n        \"receive\": 68408,\n        \"send\": 68388\n      },\n      \"nodes\": {\n        \"receive\": 4,\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:41 GMT\",\n          \"unix\": 1490558621.413337\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.25346\n        }\n      },\n      \"type\": \"propose\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 4,\n        \"sequence_no\": 298111724,\n        \"type\": 1,\n        \"value\": 0.3594702184200287\n      },\n      \"id\": {\n        \"receive\": 68409,\n        \"send\": 68390\n      },\n      \"nodes\": {\n        \"receive\": 3,\n        \"send\": 4\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:41 GMT\",\n          \"unix\": 1490558621.464501\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.306264\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"send\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 1,\n        \"sequence_no\": 298111724,\n        \"type\": 4,\n        \"value\": 6.1647744178772\n      },\n      \"id\": {\n        \"send\": 68410\n      },\n      \"nodes\": {\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:41 GMT\",\n          \"unix\": 1490558621.524051\n        }\n      },\n      \"type\": \"vote\"\n    },\n    {\n      \"action\": \"send\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 2,\n        \"sequence_no\": 298111724,\n        \"type\": 4,\n        \"value\": 6.1647744178772\n      },\n      \"id\": {\n        \"send\": 68411\n      },\n      \"nodes\": {\n        \"send\": 2\n      },\n      \"timestamps\": {\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:41 GMT\",\n          \"unix\": 1490558621.553096\n        }\n      },\n      \"type\": \"vote\"\n    },\n    {\n      \"action\": \"send\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 4,\n        \"sequence_no\": 298111724,\n        \"type\": 4,\n        \"value\": 6.1647744178772\n      },\n      \"id\": {\n        \"send\": 68412\n      },\n      \"nodes\": {\n        \"send\": 4\n      },\n      \"timestamps\": {\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:41 GMT\",\n          \"unix\": 1490558621.609441\n        }\n      },\n      \"type\": \"vote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 1,\n        \"sequence_no\": 298111724,\n        \"type\": 3,\n        \"value\": 4.358090877532959\n      },\n      \"id\": {\n        \"receive\": 68413,\n        \"send\": 68394\n      },\n      \"nodes\": {\n        \"receive\": 3,\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:41 GMT\",\n          \"unix\": 1490558621.664591\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.409385\n        }\n      },\n      \"type\": \"prevote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 1,\n        \"proposal\": 4.358090877532959,\n        \"sequence_no\": 298111724,\n        \"type\": 2,\n        \"value_store\": [\n          {\n            \"node\": 1,\n            \"sequence_no\": 298111723,\n            \"type\": 1,\n            \"value\": 7.23430061340332\n          },\n          {\n            \"node\": 3,\n            \"sequence_no\": 298111723,\n            \"type\": 1,\n            \"value\": 0.6948843598365784\n          },\n          {\n            \"node\": 4,\n            \"sequence_no\": 298111723,\n            \"type\": 1,\n            \"value\": 7.756925106048584\n          },\n          {\n            \"node\": 2,\n            \"sequence_no\": 298111723,\n            \"type\": 1,\n            \"value\": 1.71371591091156\n          },\n          {\n            \"node\": 1,\n            \"sequence_no\": 298111724,\n            \"type\": 1,\n            \"value\": 4.358090877532959\n          }\n        ]\n      },\n      \"id\": {\n        \"receive\": 68414,\n        \"send\": 68388\n      },\n      \"nodes\": {\n        \"receive\": 1,\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:41 GMT\",\n          \"unix\": 1490558621.703477\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.25346\n        }\n      },\n      \"type\": \"propose\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 4,\n        \"sequence_no\": 298111724,\n        \"type\": 3,\n        \"value\": 4.358090877532959\n      },\n      \"id\": {\n        \"receive\": 68415,\n        \"send\": 68398\n      },\n      \"nodes\": {\n        \"receive\": 2,\n        \"send\": 4\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:41 GMT\",\n          \"unix\": 1490558621.732756\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.564023\n        }\n      },\n      \"type\": \"prevote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 4,\n        \"sequence_no\": 298111724,\n        \"type\": 1,\n        \"value\": 0.3594702184200287\n      },\n      \"id\": {\n        \"receive\": 68416,\n        \"send\": 68390\n      },\n      \"nodes\": {\n        \"receive\": 4,\n        \"send\": 4\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:41 GMT\",\n          \"unix\": 1490558621.788268\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.306264\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 4,\n        \"sequence_no\": 298111724,\n        \"type\": 3,\n        \"value\": 4.358090877532959\n      },\n      \"id\": {\n        \"receive\": 68417,\n        \"send\": 68398\n      },\n      \"nodes\": {\n        \"receive\": 3,\n        \"send\": 4\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:41 GMT\",\n          \"unix\": 1490558621.822536\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.564023\n        }\n      },\n      \"type\": \"prevote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 4,\n        \"sequence_no\": 298111724,\n        \"type\": 1,\n        \"value\": 0.3594702184200287\n      },\n      \"id\": {\n        \"receive\": 68418,\n        \"send\": 68390\n      },\n      \"nodes\": {\n        \"receive\": 1,\n        \"send\": 4\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:41 GMT\",\n          \"unix\": 1490558621.864831\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.306264\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 3,\n        \"sequence_no\": 298111724,\n        \"type\": 3,\n        \"value\": 4.358090877532959\n      },\n      \"id\": {\n        \"receive\": 68419,\n        \"send\": 68400\n      },\n      \"nodes\": {\n        \"receive\": 2,\n        \"send\": 3\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:41 GMT\",\n          \"unix\": 1490558621.9004\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.602183\n        }\n      },\n      \"type\": \"prevote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 1,\n        \"sequence_no\": 298111724,\n        \"type\": 3,\n        \"value\": 4.358090877532959\n      },\n      \"id\": {\n        \"receive\": 68420,\n        \"send\": 68394\n      },\n      \"nodes\": {\n        \"receive\": 4,\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:41 GMT\",\n          \"unix\": 1490558621.94405\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.409385\n        }\n      },\n      \"type\": \"prevote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 3,\n        \"sequence_no\": 298111724,\n        \"type\": 3,\n        \"value\": 4.358090877532959\n      },\n      \"id\": {\n        \"receive\": 68421,\n        \"send\": 68400\n      },\n      \"nodes\": {\n        \"receive\": 3,\n        \"send\": 3\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:41 GMT\",\n          \"unix\": 1490558621.976853\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.602183\n        }\n      },\n      \"type\": \"prevote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 1,\n        \"sequence_no\": 298111724,\n        \"type\": 3,\n        \"value\": 4.358090877532959\n      },\n      \"id\": {\n        \"receive\": 68422,\n        \"send\": 68394\n      },\n      \"nodes\": {\n        \"receive\": 1,\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:42 GMT\",\n          \"unix\": 1490558622.015507\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.409385\n        }\n      },\n      \"type\": \"prevote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 2,\n        \"sequence_no\": 298111724,\n        \"type\": 3,\n        \"value\": 4.358090877532959\n      },\n      \"id\": {\n        \"receive\": 68423,\n        \"send\": 68401\n      },\n      \"nodes\": {\n        \"receive\": 2,\n        \"send\": 2\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:42 GMT\",\n          \"unix\": 1490558622.044734\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.729595\n        }\n      },\n      \"type\": \"prevote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 4,\n        \"sequence_no\": 298111724,\n        \"type\": 3,\n        \"value\": 4.358090877532959\n      },\n      \"id\": {\n        \"receive\": 68424,\n        \"send\": 68398\n      },\n      \"nodes\": {\n        \"receive\": 4,\n        \"send\": 4\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:42 GMT\",\n          \"unix\": 1490558622.082456\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.564023\n        }\n      },\n      \"type\": \"prevote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 2,\n        \"sequence_no\": 298111724,\n        \"type\": 3,\n        \"value\": 4.358090877532959\n      },\n      \"id\": {\n        \"receive\": 68425,\n        \"send\": 68401\n      },\n      \"nodes\": {\n        \"receive\": 3,\n        \"send\": 2\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:42 GMT\",\n          \"unix\": 1490558622.112521\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.729595\n        }\n      },\n      \"type\": \"prevote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 4,\n        \"sequence_no\": 298111724,\n        \"type\": 3,\n        \"value\": 4.358090877532959\n      },\n      \"id\": {\n        \"receive\": 68426,\n        \"send\": 68398\n      },\n      \"nodes\": {\n        \"receive\": 1,\n        \"send\": 4\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:42 GMT\",\n          \"unix\": 1490558622.152662\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.564023\n        }\n      },\n      \"type\": \"prevote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 3,\n        \"sequence_no\": 298111724,\n        \"type\": 4,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68427,\n        \"send\": 68406\n      },\n      \"nodes\": {\n        \"receive\": 2,\n        \"send\": 3\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:42 GMT\",\n          \"unix\": 1490558622.180283\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:41 GMT\",\n          \"unix\": 1490558621.209692\n        }\n      },\n      \"type\": \"vote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 3,\n        \"sequence_no\": 298111724,\n        \"type\": 3,\n        \"value\": 4.358090877532959\n      },\n      \"id\": {\n        \"receive\": 68428,\n        \"send\": 68400\n      },\n      \"nodes\": {\n        \"receive\": 4,\n        \"send\": 3\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:42 GMT\",\n          \"unix\": 1490558622.260693\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.602183\n        }\n      },\n      \"type\": \"prevote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 3,\n        \"sequence_no\": 298111724,\n        \"type\": 4,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68429,\n        \"send\": 68406\n      },\n      \"nodes\": {\n        \"receive\": 3,\n        \"send\": 3\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:42 GMT\",\n          \"unix\": 1490558622.293036\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:41 GMT\",\n          \"unix\": 1490558621.209692\n        }\n      },\n      \"type\": \"vote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 3,\n        \"sequence_no\": 298111724,\n        \"type\": 3,\n        \"value\": 4.358090877532959\n      },\n      \"id\": {\n        \"receive\": 68430,\n        \"send\": 68400\n      },\n      \"nodes\": {\n        \"receive\": 1,\n        \"send\": 3\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:42 GMT\",\n          \"unix\": 1490558622.341159\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.602183\n        }\n      },\n      \"type\": \"prevote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 1,\n        \"sequence_no\": 298111724,\n        \"type\": 4,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68431,\n        \"send\": 68410\n      },\n      \"nodes\": {\n        \"receive\": 2,\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:42 GMT\",\n          \"unix\": 1490558622.42285\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:41 GMT\",\n          \"unix\": 1490558621.524051\n        }\n      },\n      \"type\": \"vote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 2,\n        \"sequence_no\": 298111724,\n        \"type\": 3,\n        \"value\": 4.358090877532959\n      },\n      \"id\": {\n        \"receive\": 68432,\n        \"send\": 68401\n      },\n      \"nodes\": {\n        \"receive\": 4,\n        \"send\": 2\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:42 GMT\",\n          \"unix\": 1490558622.474849\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.729595\n        }\n      },\n      \"type\": \"prevote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 1,\n        \"sequence_no\": 298111724,\n        \"type\": 4,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68433,\n        \"send\": 68410\n      },\n      \"nodes\": {\n        \"receive\": 3,\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:42 GMT\",\n          \"unix\": 1490558622.534648\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:41 GMT\",\n          \"unix\": 1490558621.524051\n        }\n      },\n      \"type\": \"vote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 2,\n        \"sequence_no\": 298111724,\n        \"type\": 3,\n        \"value\": 4.358090877532959\n      },\n      \"id\": {\n        \"receive\": 68434,\n        \"send\": 68401\n      },\n      \"nodes\": {\n        \"receive\": 1,\n        \"send\": 2\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:42 GMT\",\n          \"unix\": 1490558622.575433\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:40 GMT\",\n          \"unix\": 1490558620.729595\n        }\n      },\n      \"type\": \"prevote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 2,\n        \"sequence_no\": 298111724,\n        \"type\": 4,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68435,\n        \"send\": 68411\n      },\n      \"nodes\": {\n        \"receive\": 2,\n        \"send\": 2\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:42 GMT\",\n          \"unix\": 1490558622.616609\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:41 GMT\",\n          \"unix\": 1490558621.553096\n        }\n      },\n      \"type\": \"vote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 3,\n        \"sequence_no\": 298111724,\n        \"type\": 4,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68436,\n        \"send\": 68406\n      },\n      \"nodes\": {\n        \"receive\": 4,\n        \"send\": 3\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:42 GMT\",\n          \"unix\": 1490558622.655002\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:41 GMT\",\n          \"unix\": 1490558621.209692\n        }\n      },\n      \"type\": \"vote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 2,\n        \"sequence_no\": 298111724,\n        \"type\": 4,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68437,\n        \"send\": 68411\n      },\n      \"nodes\": {\n        \"receive\": 3,\n        \"send\": 2\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:42 GMT\",\n          \"unix\": 1490558622.705866\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:41 GMT\",\n          \"unix\": 1490558621.553096\n        }\n      },\n      \"type\": \"vote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 3,\n        \"sequence_no\": 298111724,\n        \"type\": 4,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68438,\n        \"send\": 68406\n      },\n      \"nodes\": {\n        \"receive\": 1,\n        \"send\": 3\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:42 GMT\",\n          \"unix\": 1490558622.753005\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:41 GMT\",\n          \"unix\": 1490558621.209692\n        }\n      },\n      \"type\": \"vote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 4,\n        \"sequence_no\": 298111724,\n        \"type\": 4,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68439,\n        \"send\": 68412\n      },\n      \"nodes\": {\n        \"receive\": 2,\n        \"send\": 4\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:42 GMT\",\n          \"unix\": 1490558622.790398\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:41 GMT\",\n          \"unix\": 1490558621.609441\n        }\n      },\n      \"type\": \"vote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 1,\n        \"sequence_no\": 298111724,\n        \"type\": 4,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68440,\n        \"send\": 68410\n      },\n      \"nodes\": {\n        \"receive\": 4,\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:42 GMT\",\n          \"unix\": 1490558622.820384\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:41 GMT\",\n          \"unix\": 1490558621.524051\n        }\n      },\n      \"type\": \"vote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 4,\n        \"sequence_no\": 298111724,\n        \"type\": 4,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68441,\n        \"send\": 68412\n      },\n      \"nodes\": {\n        \"receive\": 3,\n        \"send\": 4\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:42 GMT\",\n          \"unix\": 1490558622.866261\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:41 GMT\",\n          \"unix\": 1490558621.609441\n        }\n      },\n      \"type\": \"vote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 2,\n        \"sequence_no\": 298111724,\n        \"type\": 4,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68442,\n        \"send\": 68411\n      },\n      \"nodes\": {\n        \"receive\": 4,\n        \"send\": 2\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:42 GMT\",\n          \"unix\": 1490558622.885713\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:41 GMT\",\n          \"unix\": 1490558621.553096\n        }\n      },\n      \"type\": \"vote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 1,\n        \"sequence_no\": 298111724,\n        \"type\": 4,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68443,\n        \"send\": 68410\n      },\n      \"nodes\": {\n        \"receive\": 1,\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:42 GMT\",\n          \"unix\": 1490558622.922574\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:41 GMT\",\n          \"unix\": 1490558621.524051\n        }\n      },\n      \"type\": \"vote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 4,\n        \"sequence_no\": 298111724,\n        \"type\": 4,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68444,\n        \"send\": 68412\n      },\n      \"nodes\": {\n        \"receive\": 4,\n        \"send\": 4\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:42 GMT\",\n          \"unix\": 1490558622.952755\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:41 GMT\",\n          \"unix\": 1490558621.609441\n        }\n      },\n      \"type\": \"vote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 2,\n        \"sequence_no\": 298111724,\n        \"type\": 4,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68445,\n        \"send\": 68411\n      },\n      \"nodes\": {\n        \"receive\": 1,\n        \"send\": 2\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:42 GMT\",\n          \"unix\": 1490558622.982509\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:41 GMT\",\n          \"unix\": 1490558621.553096\n        }\n      },\n      \"type\": \"vote\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 4,\n        \"sequence_no\": 298111724,\n        \"type\": 4,\n        \"value\": 6.164774417877197\n      },\n      \"id\": {\n        \"receive\": 68446,\n        \"send\": 68412\n      },\n      \"nodes\": {\n        \"receive\": 1,\n        \"send\": 4\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:43 GMT\",\n          \"unix\": 1490558623.041606\n        },\n        \"send\": {\n          \"string\": \"Sun, 26 Mar 2017 20:03:41 GMT\",\n          \"unix\": 1490558621.609441\n        }\n      },\n      \"type\": \"vote\"\n    }\n  ],\n  \"nodes\": [\n    1,\n    2,\n    3,\n    4\n  ],\n  \"timestamps\": {\n    \"max\": {\n      \"string\": \"Sun, 26 Mar 2017 20:03:43 GMT\",\n      \"unix\": 1490558623.041606\n    },\n    \"min\": {\n      \"string\": \"Sun, 26 Mar 2017 20:03:35 GMT\",\n      \"unix\": 1490558615.079226\n    }\n  }\n}\n"
  },
  {
    "path": "code/web/example/nodes.json",
    "content": "[{\n\t\"id\": 1,\n\t\"value\": 0.5,\n\t\"primary\": true\n}, {\n\t\"id\": 2,\n\t\"value\": 0.6,\n\t\"primary\": false\n}, {\n\t\"id\": 3,\n\t\"value\": 0.5,\n\t\"primary\": false\n}, {\n\t\"id\": 4,\n\t\"value\": 0.5,\n\t\"primary\": false\n}, {\n\t\"id\": \"summary\",\n\t\"value\": 0.5\n}]"
  },
  {
    "path": "code/web/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <link rel=\"stylesheet\" href=\"styles.css\"/>\n    <title>pbft gui</title>\n    <script src=\"http://code.jquery.com/jquery-3.1.1.js\" integrity=\"sha256-16cdPddA6VdVInumRGo6IbivbERE8p7CQR3HzTBuELA=\" crossorigin=\"anonymous\"></script>\n    <script src=\"js.js\"></script>\n\n</head>\n<body>\n    <div id=\"container\">\n        <div id=\"menubar\">\n            <div class=\"menuitem\">Nodes</div>\n            <div class=\"menuitem\">Timeline</div>\n        </div>\n        <div id=\"main\">\n            <div id=\"nodearea\">\n                <div class=\"node summary\">\n                    <h3>Summary</h3>\n                    <h5>Agreed Value:</h5>\n                    <span class=\"value\">???</span>\n                </div>\n                <div class=\"node primary\">\n                    <h3>Node 1<!--<span class=\"primary-label\">P</span>--></h3>\n                    <h5>Value:</h5>\n                    <span class=\"value\">???</span>\n                </div>\n                <div class=\"node\">\n                    <h3>Node 2</h3>\n                    <h5>Value:</h5>\n                    <span class=\"value\">???</span>\n                </div>\n                <div class=\"node\">\n                    <h3>Node 3</h3>\n                    <h5>Value:</h5>\n                    <span class=\"value\">???</span>\n                </div>\n                <div class=\"node\">\n                    <h3>Node 4</h3>\n                    <h5>Value:</h5>\n                    <span class=\"value\">???</span>\n                </div>\n            </div>\n        </div>\n        <div id=\"footer\">\n            (c) by us, yay.\n        </div>\n    </div>\n</body>\n</html>"
  },
  {
    "path": "code/web/js.js",
    "content": "/**\n * Created by luckydonald on 25/10/16.\n */\n\n$( document ).ready(function(){\n    setInterval( function () {\n        $.getJSON(\"http://localhost/get_value/\", function (data) { //TODO host\n            var container = $(\"#nodearea\");\n            container.empty();\n            console.log(data);\n            var node = $(\"<div>\");\n            node.addClass(\"node\").addClass(\"summary\");\n            node.append($(\"<h3>\").text(\"Summary\"));\n            node.append(\"<h5>Agreed Value:</h5>\");\n            if(\"summary\" in data) {\n                node.append($(\"<span>\").text(data[\"summary\"]).addClass(\"value\"));\n            } else {\n                node.append($(\"<span>\").text(\"No recent agreement\").addClass(\"value\"));\n            }\n            container.prepend(node);\n            Object.keys(data).forEach(function (key, value) {\n                if (key === \"summary\") {\n                    return;\n                }\n                var node = $(\"<div>\");\n                node.addClass(\"node\");\n                node.append($(\"<h3>\").text(\"Node \" + key));\n                node.append(\"<h5>Value:</h5>\");\n                node.append($(\"<span>\").text(this[key]).addClass(\"value\"));\n                container.append(node);\n            }, data);\n        });\n    }, 100);\n});"
  },
  {
    "path": "code/web/package.json",
    "content": "{\n  \"name\": \"pbft-gui\",\n  \"private\": true,\n  \"version\": \"0.0.0\",\n  \"description\": \"Web GUI for PBFT\",\n  \"repository\": \"https://github.com/luckydonald/pbft\",\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n    \"bower\": \"^1.7.7\",\n    \"http-server\": \"^0.9.0\"\n  },\n  \"scripts\": {\n    \"postinstall\": \"bower install\",\n\n    \"prestart\": \"npm install\",\n    \"start\": \"http-server -p 8000 -c-1 /code\"\n  }\n}\n"
  },
  {
    "path": "code/web/src/app.animations.css",
    "content": ".view-frame {\n  position: relative;\n}\n.view-frame.ng-enter,\n.view-frame.ng-leave {\n  position: absolute;\n  left: 0;\n  right: 0;\n  top: inherit;\n}\n.view-frame.ng-enter {\n  animation: 0.5s fade-in;\n  z-index: 100;\n}\n.view-frame.ng-leave {\n  animation: 0.5s fade-out;\n  z-index: 99;\n}\n@keyframes fade-in {\n  from {\n    opacity: 0;\n  }\n  to {\n    opacity: 1;\n  }\n}\n@keyframes fade-out {\n  from {\n    opacity: 1;\n  }\n  to {\n    opacity: 0;\n  }\n}\n.node.ng-enter,\n.node.ng-leave,\n.node.ng-move {\n  transition: 0.25s linear all;\n}\n.node.ng-enter,\n.node.ng-move {\n  width: 0;\n  opacity: 0;\n  overflow: hidden;\n}\n.node.ng-enter.ng-enter-active,\n.node.ng-move.ng-move-active {\n  width: 120px;\n  opacity: 1;\n}\n.node.ng-leave {\n  opacity: 1;\n  overflow: hidden;\n}\n.node.ng-leave.ng-leave-active {\n  width: 0;\n  opacity: 0;\n  padding: 0;\n}\n"
  },
  {
    "path": "code/web/src/app.animations.js",
    "content": "/**\n * Created by PlayingBacon on 30.10.2016.\n */\n"
  },
  {
    "path": "code/web/src/app.animations.less",
    "content": ".view-frame {\n  position: relative;\n\n  &.ng-enter, &.ng-leave {\n    position: absolute;\n    left: 0;\n    right: 0;\n    top: inherit;\n  }\n\n  &.ng-enter {\n    animation: 0.5s fade-in;\n    z-index: 100;\n  }\n\n  &.ng-leave {\n    animation: 0.5s fade-out;\n    z-index: 99;\n  }\n}\n\n\n@keyframes fade-in {\n  from {opacity: 0;}\n  to {opacity: 1;}\n}\n\n@keyframes fade-out {\n  from {opacity: 1;}\n  to {opacity: 0;}\n}\n\n.node {\n  &.ng-enter,\n  &.ng-leave,\n  &.ng-move {\n    transition: 0.25s linear all;\n  }\n  &.ng-enter,\n  &.ng-move {\n    width: 0;\n    opacity: 0;\n    overflow: hidden;\n  }\n\n  &.ng-enter.ng-enter-active,\n  &.ng-move.ng-move-active {\n    width: 120px;\n    opacity: 1;\n  }\n\n  &.ng-leave {\n    opacity: 1;\n    overflow: hidden;\n\n    &.ng-leave-active {\n      width: 0;\n      opacity: 0;\n      padding: 0;\n    }\n  }\n}"
  },
  {
    "path": "code/web/src/app.config.js",
    "content": "/**\n * Created by PlayingBacon on 27.10.2016.\n */\n'use strict';\n\nangular.\n    module('pbftGui').\n    config(['$locationProvider', '$routeProvider', \n        function($locationProvider, $routeProvider, $routeParams) {\n            $locationProvider.hashPrefix('!');\n\n            $routeProvider.\n                when('/nodes', {\n                    template: '<node-list-view></node-list-view>'\n                }).\n                when('/failures', {\n                    template: '<failure-table-view></failure-table-view>'\n                }).\n                when('/nodes/:nodeid', {\n                    template: function($routeParams) { return \"<value-graph nodeid='\"+$routeParams.nodeid+\"'></value-graph>\"; } //<div>This is a detailed view of node \" +$routeParams.nodeid+ \"!</div><a href='#!/nodes'>Return</a>\n                }).\n                otherwise({redirectTo: '/nodes'});\n}]);\n"
  },
  {
    "path": "code/web/src/app.css",
    "content": "/* app css stylesheet */\nbody {\n  margin: 0;\n  font-family: \"Lucida Sans Unicode\", \"Lucida Grande\", sans-serif;\n  font-variant: small-caps;\n}\nth,\ntd {\n  padding: 5px;\n  border: 1px dashed white;\n}\ninput {\n  color: black;\n}\n#container {\n  width: 100%;\n  height: 100vh;\n  margin: 0 auto 0 auto;\n  border: 0 solid transparent;\n  background-color: #124;\n}\n#menubar {\n  width: 100%;\n  padding-top: 2vh;\n  background-color: lightgray;\n  margin: 0 auto 0 auto;\n  display: table;\n  border-spacing: 10px 0;\n  text-align: center;\n}\n#menubar a {\n  background-color: #124;\n  height: 5vh;\n  vertical-align: middle;\n  border-width: 0 5px 0 5px;\n  border-radius: 7px 7px 0 0;\n  margin: 0 3% 0 3%;\n  padding: 1%;\n  display: inline-block;\n  color: white;\n  text-decoration: none;\n  width: 40%;\n}\n#menubar a:hover {\n  background-color: #126;\n  color: #7cf1ca;\n}\n#main {\n  width: 100%;\n  background-color: #124;\n  color: white;\n}\n#footer {\n  width: 100%;\n  display: block;\n  height: 5vh;\n  position: fixed;\n  bottom: 0;\n  background-color: #124;\n}\n#footer .footer-fillin {\n  width: 10%;\n  height: 100%;\n  float: left;\n}\n#footer #footer-content {\n  width: 80%;\n  height: 100%;\n  float: left;\n  text-align: center;\n  color: white;\n  border-top: 1px solid white;\n}\n#nodearea {\n  margin: 0 auto;\n  width: 100%;\n  box-sizing: border-box;\n  padding: 3% 10px;\n  background-color: #124;\n}\n#nodearea .no_data {\n  text-align: center;\n  width: 100%;\n  padding-top: 2em;\n}\n#nodearea,\n#nodearea .node-list {\n  display: flex;\n  flex-wrap: wrap;\n  width: 100%;\n}\n#nodearea .node {\n  flex: 1 0 auto;\n  display: inline-block;\n  position: relative;\n  opacity: 1;\n  text-align: center;\n  margin-right: 1%;\n  margin-left: 1%;\n  margin-bottom: 2.1em;\n  box-sizing: border-box;\n  color: black;\n  -webkit-transition: width 0.3s ease-out, height 0.2s ease-out;\n  -moz-transition: width 0.3s ease-out, height 0.2s ease-out;\n  -o-transition: width 0.3s ease-out, height 0.2s ease-out;\n  transition: width 0.3s ease-out, height 0.2s ease-out;\n}\n#nodearea .node a,\n#nodearea .node a:visited {\n  color: black;\n  text-decoration: none;\n}\n#nodearea .node .node-main {\n  border-color: transparent;\n  border-radius: 0.5em;\n  border-width: 0 5px 0 5px;\n  border-style: solid;\n  background-color: cornflowerblue;\n  box-sizing: border-box;\n  padding: 0.5em 1%;\n}\n#nodearea .node h3,\n#nodearea .node h5 {\n  margin-bottom: 0;\n  margin-top: 0;\n  -webkit-transition: font-size 0.3s ease-out, opacity 0.3s ease-out;\n  -moz-transition: font-size 0.3s ease-out, opacity 0.3s ease-out;\n  -o-transition: font-size 0.3s ease-out, opacity 0.3s ease-out;\n  transition: font-size 0.3s ease-out, opacity 0.3s ease-out;\n}\n#nodearea .node .click-hint-wrapper {\n  height: 1.4em;\n  margin-top: -0.5em;\n}\n#nodearea .node .click-hint-wrapper .click-hint {\n  display: block;\n  white-space: nowrap;\n  padding: 0 0.3em;\n  -webkit-transition: width 0.3s ease-out, height 0.2s ease-in-out;\n  -moz-transition: width 0.3s ease-out, height 0.2s ease-in-out;\n  -o-transition: width 0.3s ease-out, height 0.2s ease-in-out;\n  transition: width 0.3s ease-out, height 0.2s ease-in-out;\n}\n#nodearea .node.upscaled {\n  width: 100%;\n  text-align: left;\n  margin: 0;\n  height: 70vh;\n}\n#nodearea .node.upscaled h3.id-label {\n  font-size: 2em;\n}\n#nodearea .node.upscaled div.node-main {\n  height: 100%;\n}\n#nodearea .node.reduced {\n  display: none;\n}\n#nodearea .node.non-upscaled:hover .node-main {\n  border-bottom-left-radius: 0;\n  border-bottom-right-radius: 0;\n  background-color: #1972ff;\n}\n#nodearea .node.non-upscaled:hover .click-hint {\n  color: black;\n  height: 1.4em;\n  background-color: #1972ff;\n  -webkit-transition: height 0.2s ease-in-out, width 0.2s ease-in-out, color 0.2s ease-in-out;\n  -moz-transition: height 0.2s ease-in-out, width 0.2s ease-in-out, color 0.2s ease-in-out;\n  -o-transition: height 0.2s ease-in-out, width 0.2s ease-in-out, color 0.2s ease-in-out;\n  transition: height 0.2s ease-in-out, width 0.2s ease-in-out, color 0.2s ease-in-out;\n}\n#nodearea .node.non-upscaled .overview {\n  display: block;\n}\n#nodearea .node.non-upscaled .details {\n  display: none;\n}\n#nodearea .node.upscaled {\n  width: 98%;\n}\n#nodearea .node.upscaled .overview {\n  display: none;\n}\n#nodearea .node.upscaled .overview .click-hint {\n  height: 0;\n}\n#nodearea .node.upscaled .details {\n  display: block;\n}\n#nodearea .node.upscaled .details .value-graph {\n  width: 100%;\n  height: 100%;\n  text-align: center;\n}\n#nodearea .node.leader .node-main {\n  border-color: #c4e3f3;\n}\n#nodearea .node.leader:hover .node-main,\n#nodearea .node.leader:hover .click-hint {\n  border-color: #7cf1ca;\n}\n#nodearea .node.leader:hover .leader-label {\n  color: #7cf1ca;\n}\n#nodearea .node.leader .leader-label {\n  font-style: italic;\n  font-size: 0.8em;\n  color: #c4e3f3;\n}\n#nodearea .node.summary {\n  color: white;\n}\n#nodearea .node.summary .node-main {\n  background-color: cadetblue;\n}\n#nodearea .node.summary.non-upscaled:hover .node-main,\n#nodearea .node.summary.non-upscaled:hover .click-hint {\n  background-color: #7cf1ca;\n  color: white;\n}\n#nodearea .node .click-hint {\n  color: transparent;\n  overflow: hidden;\n  height: 0;\n  position: relative;\n  border-color: transparent;\n  border-width: 0 5px 0 5px;\n  border-style: solid;\n  border-bottom-left-radius: 0.5em;\n  border-bottom-right-radius: 0.5em;\n  box-sizing: border-box;\n  padding: 0 1%;\n  -webkit-transition: height 0.2s ease-in-out, width 0.2s ease-in-out, color 0.2s ease-in-out;\n  -moz-transition: height 0.2s ease-in-out, width 0.2s ease-in-out, color 0.2s ease-in-out;\n  -o-transition: height 0.2s ease-in-out, width 0.2s ease-in-out, color 0.2s ease-in-out;\n  transition: height 0.2s ease-in-out, width 0.2s ease-in-out, color 0.2s ease-in-out;\n}\n#nodearea .node .click-hint-wrapper {\n  border-bottom-left-radius: 0.5em;\n  border-bottom-right-radius: 0.5em;\n}\n#nodearea .node .leader-edge {\n  width: 0;\n  height: 0;\n}\n#failure-table {\n  width: 100%;\n  margin: 5vh 0 0 0;\n  font-variant: small-caps;\n}\n#failure-table h3 {\n  margin: 0 auto 5px auto;\n  text-align: center;\n  width: 50%;\n  /*height: 5vh;*/\n  min-height: 30px;\n  border-bottom: 1px solid white;\n}\n#failure-table div#refresher {\n  width: 30%;\n  margin: 0 auto;\n}\n#failure-table div#refresher button {\n  color: black;\n}\n#failure-table #symbology {\n  float: left;\n  width: 8%;\n  padding: 2%;\n  height: 70vh;\n  margin: 0;\n  vertical-align: top;\n}\n#failure-table #symbology div.sym-section {\n  width: 100%;\n  float: left;\n  margin-bottom: 5px;\n}\n#failure-table #symbology div.sym-section div.circle {\n  margin-right: 5px;\n  float: left;\n  width: 24px;\n  height: 24px;\n  -moz-border-radius: 12px;\n  -webkit-border-radius: 12px;\n  border-radius: 12px;\n}\n#failure-table #symbology div.sym-section div.circle.type-init {\n  background: #7cf1cb;\n}\n#failure-table #symbology div.sym-section div.circle.type-propose {\n  background: #85b9f0;\n}\n#failure-table #symbology div.sym-section div.circle.type-prevote {\n  background: #ffcd83;\n}\n#failure-table #symbology div.sym-section div.circle.type-vote {\n  background: #ffad83;\n}\n#failure-table #symbology div.sym-section div.circle div.ringHole {\n  margin: 6px;\n  width: 12px;\n  height: 12px;\n  -moz-border-radius: 6px;\n  -webkit-border-radius: 6px;\n  border-radius: 6px;\n  background: #124;\n}\n#failure-table #symbology div.sym-section div.arrow {\n  float: left;\n  width: 24px;\n  height: 24px;\n}\n#failure-table #symbology div.sym-section div.arrow div.head {\n  float: left;\n  margin: 6px 0;\n  width: 0;\n  height: 0;\n  border-top: 6px solid transparent;\n  border-bottom: 6px solid transparent;\n}\n#failure-table #symbology div.sym-section div.arrow div.head.type-init {\n  border-left: 12px solid #7cf1cb;\n}\n#failure-table #symbology div.sym-section div.arrow div.head.type-propose {\n  border-left: 12px solid #85b9f0;\n}\n#failure-table #symbology div.sym-section div.arrow div.head.type-prevote {\n  border-left: 12px solid #ffcd83;\n}\n#failure-table #symbology div.sym-section div.arrow div.head.type-vote {\n  border-left: 12px solid #ffad83;\n}\n#failure-table #symbology div.sym-section div.arrow div.shaft {\n  float: left;\n  margin: 10px 0;\n  width: 12px;\n  height: 4px;\n}\n#failure-table #symbology div.sym-section div.arrow div.shaft.type-init {\n  background: #7cf1cb;\n}\n#failure-table #symbology div.sym-section div.arrow div.shaft.type-propose {\n  background: #85b9f0;\n}\n#failure-table #symbology div.sym-section div.arrow div.shaft.type-prevote {\n  background: #ffcd83;\n}\n#failure-table #symbology div.sym-section div.arrow div.shaft.type-vote {\n  background: #ffad83;\n}\n#failure-table #symbology div.top-label {\n  width: 100%;\n  font-variant: small-caps;\n  font-size: 1.5em;\n}\n#failure-table #symbology div.sym-label {\n  width: 100%;\n  font-variant: small-caps;\n}\n#failure-table #timeline {\n  float: left;\n  width: 80%;\n  height: 70vh;\n  margin: 0 auto;\n  vertical-align: top;\n  overflow-y: scroll;\n}\n#failure-table #timeline .svg-content {\n  display: inline-block;\n  position: absolute;\n  top: 0;\n  left: 0;\n}\n#failure-table #timeline svg .arrow.type-init,\n#failure-table #timeline svg circle.type-init {\n  stroke: #7cf1cb;\n}\n#failure-table #timeline svg .arrow.type-prevote,\n#failure-table #timeline svg circle.type-prevote {\n  stroke: #ffcd83;\n}\n#failure-table #timeline svg .arrow.type-propose,\n#failure-table #timeline svg circle.type-propose {\n  stroke: #85b9f0;\n}\n#failure-table #timeline svg .arrow.type-vote,\n#failure-table #timeline svg circle.type-vote {\n  stroke: #ffad83;\n}\n#failure-table #timeline svg .arrow {\n  stroke-width: 2px;\n  fill: none;\n}\n#failure-table #timeline svg circle.action-acknowledge.type-init {\n  fill: #7cf1cb;\n}\n#failure-table #timeline svg circle.action-acknowledge.type-prevote {\n  fill: #ffcd83;\n}\n#failure-table #timeline svg circle.action-acknowledge.type-propose {\n  fill: #85b9f0;\n}\n#failure-table #timeline svg circle.action-acknowledge.type-vote {\n  fill: #ffad83;\n}\n#failure-table #timeline svg circle.action-send {\n  fill-opacity: 0.0;\n  stroke-width: 3;\n}\n.tooltipster-content p.type,\n.tooltipster-content div.type {\n  text-align: center;\n  font-size: 0.5em;\n  margin-bottom: -0.5em;\n  margin-top: 0;\n}\n.tooltipster-content p.type span,\n.tooltipster-content div.type span {\n  font-weight: bold;\n  text-transform: capitalize;\n}\n.tooltipster-content p.value_store label span .node.different {\n  text-decoration: line-through;\n}\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-init.tooltipster-top .tooltipster-box,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-init.tooltipster-top .tooltipster-box,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-init.tooltipster-bottom .tooltipster-box,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-init.tooltipster-bottom .tooltipster-box {\n  border-left: 0 none #2a2a2a;\n  border-right: 0 none #2a2a2a;\n  border-bottom: 3px solid #7cf1cb;\n  border-top: 3px solid #7cf1cb;\n}\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-init.tooltipster-top .tooltipster-arrow-border,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-init.tooltipster-top .tooltipster-arrow-border,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-init.tooltipster-bottom .tooltipster-arrow-border,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-init.tooltipster-bottom .tooltipster-arrow-border {\n  border-bottom-color: #7cf1cb;\n  border-top-color: #7cf1cb;\n}\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-init.tooltipster-left .tooltipster-box,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-init.tooltipster-left .tooltipster-box,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-init.tooltipster-right .tooltipster-box,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-init.tooltipster-right .tooltipster-box {\n  border-top: 0 none #2a2a2a;\n  border-bottom: 0 none #2a2a2a;\n  border-left: 3px solid #7cf1cb;\n  border-right: 3px solid #7cf1cb;\n}\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-init.tooltipster-left .tooltipster-arrow-border,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-init.tooltipster-left .tooltipster-arrow-border,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-init.tooltipster-right .tooltipster-arrow-border,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-init.tooltipster-right .tooltipster-arrow-border {\n  border-left-color: #7cf1cb;\n  border-right-color: #7cf1cb;\n}\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-init .tooltipster-content,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-init .tooltipster-content {\n  color: #7cf1cb;\n  font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Helvetica, Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\";\n  font-variant: normal;\n}\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-propose.tooltipster-top .tooltipster-box,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-propose.tooltipster-top .tooltipster-box,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-propose.tooltipster-bottom .tooltipster-box,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-propose.tooltipster-bottom .tooltipster-box {\n  border-left: 0 none #2a2a2a;\n  border-right: 0 none #2a2a2a;\n  border-bottom: 3px solid #85b9f0;\n  border-top: 3px solid #85b9f0;\n}\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-propose.tooltipster-top .tooltipster-arrow-border,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-propose.tooltipster-top .tooltipster-arrow-border,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-propose.tooltipster-bottom .tooltipster-arrow-border,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-propose.tooltipster-bottom .tooltipster-arrow-border {\n  border-bottom-color: #85b9f0;\n  border-top-color: #85b9f0;\n}\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-propose.tooltipster-left .tooltipster-box,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-propose.tooltipster-left .tooltipster-box,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-propose.tooltipster-right .tooltipster-box,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-propose.tooltipster-right .tooltipster-box {\n  border-top: 0 none #2a2a2a;\n  border-bottom: 0 none #2a2a2a;\n  border-left: 3px solid #85b9f0;\n  border-right: 3px solid #85b9f0;\n}\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-propose.tooltipster-left .tooltipster-arrow-border,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-propose.tooltipster-left .tooltipster-arrow-border,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-propose.tooltipster-right .tooltipster-arrow-border,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-propose.tooltipster-right .tooltipster-arrow-border {\n  border-left-color: #85b9f0;\n  border-right-color: #85b9f0;\n}\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-propose .tooltipster-content,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-propose .tooltipster-content {\n  color: #85b9f0;\n  font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Helvetica, Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\";\n  font-variant: normal;\n}\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-prevote.tooltipster-top .tooltipster-box,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-prevote.tooltipster-top .tooltipster-box,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-prevote.tooltipster-bottom .tooltipster-box,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-prevote.tooltipster-bottom .tooltipster-box {\n  border-left: 0 none #2a2a2a;\n  border-right: 0 none #2a2a2a;\n  border-bottom: 3px solid #ffcd83;\n  border-top: 3px solid #ffcd83;\n}\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-prevote.tooltipster-top .tooltipster-arrow-border,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-prevote.tooltipster-top .tooltipster-arrow-border,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-prevote.tooltipster-bottom .tooltipster-arrow-border,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-prevote.tooltipster-bottom .tooltipster-arrow-border {\n  border-bottom-color: #ffcd83;\n  border-top-color: #ffcd83;\n}\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-prevote.tooltipster-left .tooltipster-box,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-prevote.tooltipster-left .tooltipster-box,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-prevote.tooltipster-right .tooltipster-box,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-prevote.tooltipster-right .tooltipster-box {\n  border-top: 0 none #2a2a2a;\n  border-bottom: 0 none #2a2a2a;\n  border-left: 3px solid #ffcd83;\n  border-right: 3px solid #ffcd83;\n}\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-prevote.tooltipster-left .tooltipster-arrow-border,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-prevote.tooltipster-left .tooltipster-arrow-border,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-prevote.tooltipster-right .tooltipster-arrow-border,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-prevote.tooltipster-right .tooltipster-arrow-border {\n  border-left-color: #ffcd83;\n  border-right-color: #ffcd83;\n}\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-prevote .tooltipster-content,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-prevote .tooltipster-content {\n  color: #ffcd83;\n  font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Helvetica, Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\";\n  font-variant: normal;\n}\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-vote.tooltipster-top .tooltipster-box,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-vote.tooltipster-top .tooltipster-box,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-vote.tooltipster-bottom .tooltipster-box,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-vote.tooltipster-bottom .tooltipster-box {\n  border-left: 0 none #2a2a2a;\n  border-right: 0 none #2a2a2a;\n  border-bottom: 3px solid #ffad83;\n  border-top: 3px solid #ffad83;\n}\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-vote.tooltipster-top .tooltipster-arrow-border,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-vote.tooltipster-top .tooltipster-arrow-border,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-vote.tooltipster-bottom .tooltipster-arrow-border,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-vote.tooltipster-bottom .tooltipster-arrow-border {\n  border-bottom-color: #ffad83;\n  border-top-color: #ffad83;\n}\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-vote.tooltipster-left .tooltipster-box,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-vote.tooltipster-left .tooltipster-box,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-vote.tooltipster-right .tooltipster-box,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-vote.tooltipster-right .tooltipster-box {\n  border-top: 0 none #2a2a2a;\n  border-bottom: 0 none #2a2a2a;\n  border-left: 3px solid #ffad83;\n  border-right: 3px solid #ffad83;\n}\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-vote.tooltipster-left .tooltipster-arrow-border,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-vote.tooltipster-left .tooltipster-arrow-border,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-vote.tooltipster-right .tooltipster-arrow-border,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-vote.tooltipster-right .tooltipster-arrow-border {\n  border-left-color: #ffad83;\n  border-right-color: #ffad83;\n}\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-vote .tooltipster-content,\n.tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-vote .tooltipster-content {\n  color: #ffad83;\n  font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Helvetica, Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\";\n  font-variant: normal;\n}\n"
  },
  {
    "path": "code/web/src/app.js",
    "content": "'use strict';\n\n// Declare app level module which depends on views, and components\nangular.module('myApp', [\n  'ngRoute',\n  'myApp.view1',\n  'myApp.view2',\n  'myApp.version'\n]).\nconfig(['$locationProvider', '$routeProvider', function($locationProvider, $routeProvider) {\n  $locationProvider.hashPrefix('!');\n\n  $routeProvider.otherwise({redirectTo: '/view1'});\n}]);\n"
  },
  {
    "path": "code/web/src/app.less",
    "content": "// MACROS\n.transition(...) {  // http://stackoverflow.com/a/14988517/3423324\n@props: ~`\"@{arguments}\".replace(/[\\[\\]]/g, '')`;\n-webkit-transition: @props;\n-moz-transition: @props;\n-o-transition: @props;\ntransition: @props;\n}\n\n\n// COLORS\n@node-highlight: cadetblue;\n@node-highlight-hover: #7cf1ca;\n\n@node-normal: cornflowerblue;\n@node-normal-hover: #1972ff;\n\n@node-leader: #c4e3f3;\n@node-leader-hover: @node-highlight-hover;\n\n@bg-color: #124;\n\n\n// Colors for Message Types\n@msg-type1: #7cf1cb;\n@msg-type2: #85b9f0;\n@msg-type3: #ffcd83;\n@msg-type4: #ffad83;\n\n@msg-init: @msg-type1;\n@msg-propose: @msg-type2;\n@msg-prevote: @msg-type3;\n@msg-vote: @msg-type4;\n\n\n// STYLES\n/* app css stylesheet */\nbody {\n  margin: 0;\n  font-family: \"Lucida Sans Unicode\",\"Lucida Grande\",sans-serif;\n  font-variant: small-caps;\n}\n\n\n//.menu {\n//  list-style: none;\n//  border-bottom: 0.1em solid black;\n//  margin-bottom: 2em;\n//  padding: 0 0 0.5em;\n//}\n//\n//.menu:before {\n//  content: \"[\";\n//}\n//\n//.menu:after {\n//  content: \"]\";\n//}\n//\n//.menu > li {\n//  display: inline;\n//}\n//\n//.menu > li + li:before {\n//  content: \"|\";\n//  padding-right: 0.3em;\n//}\n\nth, td {\n  padding: 5px;\n  border: 1px dashed white;\n}\n\ninput {\n  color: black;\n}\n\n#container {\n  width: 100%;\n  height: 100vh;\n  margin: 0 auto 0 auto;\n  border: 0 solid transparent;\n  background-color: @bg-color;\n}\n\n#menubar {\n  width: 100%;\n  padding-top: 2vh;\n  background-color: lightgray;\n  margin: 0 auto 0 auto;\n  display: table;\n  border-spacing: 10px 0;\n  text-align: center;\n\n  a {\n    background-color: @bg-color;\n    height: 5vh;\n    vertical-align: middle;\n    border-width: 0 5px 0 5px;\n    border-radius: 7px 7px 0 0;\n    margin: 0 3% 0 3%;\n    padding: 1%;\n    display: inline-block;\n    color: white;\n    text-decoration: none;\n    width: 40%;\n\n    &:hover {\n      background-color: #126;\n      color: @node-highlight-hover;\n    }\n  }\n}\n\n#main {\n  width: 100%;\n  background-color: @bg-color;\n  color: white;\n}\n\n#footer {\n  width: 100%;\n  display: block;\n  height: 5vh;\n  position: fixed;\n  bottom: 0;\n  background-color: @bg-color;\n\n  .footer-fillin {\n    width: 10%;\n    height: 100%;\n    float: left;\n  }\n\n  #footer-content {\n    width: 80%;\n    height: 100%;\n    float: left;\n    text-align: center;\n    color: white;\n    border-top: 1px solid white;\n  }\n}\n\n#nodearea {\n  margin: 0 auto;\n  width: 100%;\n  box-sizing: border-box;\n  padding: 3% 10px; //top+bottom  left+right\n  background-color: @bg-color;\n\n  .no_data {\n    text-align: center;\n    width: 100%;\n    padding-top: 2em;\n  }\n\n  &, .node-list {\n    display: flex;\n    flex-wrap: wrap;\n    width: 100%;\n  }\n\n  .node {\n    flex: 1 0 auto;\n    display: inline-block;\n    position: relative;\n    opacity: 1;\n    text-align: center;\n    //width: 18%;\n    margin-right: 1%;\n    margin-left: 1%;\n    margin-bottom: 2.1em;\n    //margin: 3% 1% 1% 1%;\n    box-sizing: border-box;\n    color: black;\n    .transition(width .3s ease-out, height .2s ease-out);\n\n    a, a:visited {\n      color: black;\n      text-decoration: none;\n    }\n\n    .node-main {\n      border-color: transparent;\n      border-radius: 0.5em;\n      border-width: 0 5px 0 5px;\n      border-style: solid;\n      background-color: @node-normal;\n      box-sizing: border-box;\n      padding: 0.5em 1%;\n    }\n\n    h3, h5 {\n      margin-bottom: 0;\n      margin-top: 0;\n      .transition(font-size .3s ease-out, opacity .3s ease-out);\n    }\n\n    .click-hint-wrapper {\n      height: 1.4em;\n      margin-top: -0.5em;\n\n      .click-hint {\n        display: block;\n        white-space: nowrap;\n        padding: 0 0.3em;\n        .transition(width .3s ease-out, height .2s ease-in-out);\n      }\n    }\n\n    // One clicked -> Detail view.\n    // The clicked one, in foreground\n    &.upscaled {\n      width: 100%;\n      text-align: left;\n      margin: 0;\n      height: 70vh;\n\n      h3.id-label {\n        font-size: 2em;\n      }\n\n      div.node-main {\n        height: 100%;\n      }\n    }\n\n    // One clicked -> Detail view.\n    // The not-clicked ones, hidden\n    &.reduced {\n      display: none;\n    }\n\n    // None clicked -> Overview.\n    // Display all nodes.\n    &.non-upscaled {\n      &:hover {\n        .node-main {\n          border-bottom-left-radius: 0;\n          border-bottom-right-radius: 0;\n          background-color: @node-normal-hover;\n        }\n        .click-hint {\n          color: black;\n          height: 1.4em;\n          background-color: @node-normal-hover;\n          .transition(height .2s ease-in-out, width .2s ease-in-out, color .2s ease-in-out);\n        }\n      }\n      .overview {\n        display: block;\n      }\n      .details {\n        display: none;\n      }\n    }\n\n    &.upscaled {\n      width: 100%-2%;\n      .overview {\n        display: none;\n        .click-hint {\n          height: 0;\n          // opacity: 0;\n        }\n      }\n      .details {\n        display: block;\n\n        .value-graph {\n          width: 100%;\n          height: 100%;\n          text-align: center;\n        }\n      }\n    }\n\n    &.leader {\n      .node-main {\n        border-color: @node-leader;\n      }\n\n      &:hover {\n        .node-main, .click-hint {\n          border-color: @node-leader-hover;\n        }\n\n        .leader-label {\n          color: @node-leader-hover;\n        }\n\n      }\n\n      .leader-label {\n        font-style: italic;\n        font-size: 0.8em;\n        color: @node-leader;\n      }\n    }\n\n    &.summary {\n      color: white;\n\n      .node-main {\n        background-color: @node-highlight;\n      }\n\n      &.non-upscaled:hover {\n        .node-main, .click-hint {\n          background-color: @node-highlight-hover;\n          color: white;\n        }\n      }\n    }\n\n    .click-hint {\n      color: transparent;\n      overflow: hidden;\n      height: 0;\n      position: relative;\n      border-color: transparent;\n      border-width: 0 5px 0 5px;\n      border-style: solid;\n      border-bottom-left-radius: 0.5em;\n      border-bottom-right-radius: 0.5em;\n      box-sizing: border-box;\n      padding: 0 1%;\n      .transition(height .2s ease-in-out, width .2s ease-in-out, color .2s ease-in-out);\n    }\n\n    .click-hint-wrapper {\n        border-bottom-left-radius: 0.5em;\n        border-bottom-right-radius: 0.5em;\n    }\n\n    .leader-edge {\n      width: 0;\n      height: 0;\n    }\n  }\n}\n\n#failure-table {\n  width: 100%;\n  margin: 5vh 0 0 0;\n  font-variant: small-caps;\n\n  h3 {\n    margin: 0 auto 5px auto;\n    text-align: center;\n    width: 50%;\n    /*height: 5vh;*/\n    min-height: 30px;\n    border-bottom: 1px solid white;\n  }\n\n  div#refresher {\n    width: 30%;\n    margin: 0 auto;\n\n    button {\n      color: black;\n    }\n  }\n\n  #symbology {\n    float:left;\n    width: 8%;\n    padding: 2%;\n    height: 70vh;\n    margin: 0;\n    vertical-align: top;\n\n    div.sym-section {\n      width: 100%;\n      float: left;\n      margin-bottom: 5px;\n\n      div.circle {\n        margin-right: 5px;\n        float: left;\n        width: 24px;\n        height: 24px;\n        -moz-border-radius: 12px;\n        -webkit-border-radius: 12px;\n        border-radius: 12px;  // half of width and height -> circle\n\n        &.type-init {\n          background: @msg-init;\n        }\n\n        &.type-propose {\n          background: @msg-propose;\n        }\n\n        &.type-prevote {\n          background: @msg-prevote;\n        }\n\n        &.type-vote {\n          background: @msg-vote;\n        }\n\n        div.ringHole {    // a circle contained in another circle to give the illusion of a ring\n          margin: 6px;\n          width: 12px;\n          height: 12px;\n          -moz-border-radius: 6px;\n          -webkit-border-radius: 6px;\n          border-radius: 6px;\n          background: @bg-color;\n        }\n      }\n\n      div.arrow {\n        float: left;\n        width: 24px;  // full space the arrow occupies\n        height: 24px; // \"\n\n        div.head {    // head of an arrow\n          float: left;\n          margin: 6px 0;    // top and bottom margin = (arrowAreaHeight - borderLeftHeight)/2\n          width: 0;\n          height: 0;\n          border-top: 6px solid transparent;\n          border-bottom: 6px solid transparent;\n\n          &.type-init {\n            border-left: 12px solid @msg-init;  // arrow shall be half as big as the circles\n          }\n\n          &.type-propose {\n            border-left: 12px solid @msg-propose;\n          }\n\n          &.type-prevote {\n            border-left: 12px solid @msg-prevote;\n          }\n\n          &.type-vote {\n            border-left: 12px solid @msg-vote;\n          }\n        }\n        div.shaft {   // shaft / \"stick\" of an arrow\n          float: left;\n          margin: 10px 0; // top and bottom margin = (arrowAreaHeight - shaftHeight)/2\n          width: 12px;  // half of the total arrow area\n          height: 4px;  // doesn't follow any particular rule, tried out what looks best\n\n          &.type-init {\n            background: @msg-init;\n          }\n\n          &.type-propose {\n            background: @msg-propose;\n          }\n\n          &.type-prevote {\n            background: @msg-prevote;\n          }\n\n          &.type-vote {\n            background: @msg-vote;\n          }\n        }\n      }\n    }\n\n    div.top-label {\n      width: 100%;\n      font-variant: small-caps;\n      font-size: 1.5em;         // I think it looks good this way..\n    }\n\n    div.sym-label {\n      width: 100%;\n      font-variant: small-caps;\n    }\n  }\n\n  #timeline {\n    float: left;\n    width: 80%;\n    height: 70vh;\n    margin: 0 auto;\n    vertical-align: top;\n    overflow-y: scroll;\n\n    .svg-content {\n      display: inline-block;\n      position: absolute;\n      top: 0;\n      left: 0;\n\n    }\n\n    svg {\n      .arrow, circle {\n        &.type-init {\n          stroke: @msg-init;\n        }\n        &.type-prevote {\n          stroke: @msg-prevote;\n        }\n        &.type-propose {\n          stroke: @msg-propose;\n        }\n        &.type-vote {\n          stroke: @msg-vote;\n        }\n      }\n      .arrow {\n        stroke-width: 2px;\n        fill: none;\n      }\n      circle {\n        &.action-acknowledge {\n          &.type-init {\n            fill: @msg-init;\n          }\n          &.type-prevote {\n            fill: @msg-prevote;\n          }\n          &.type-propose {\n            fill: @msg-propose;\n          }\n          &.type-vote {\n            fill: @msg-vote;\n          }\n        }\n        &.action-send {\n          fill-opacity: 0.0;\n          stroke-width: 3;\n        }\n      }\n    }\n  }\n}\n\n\n\n\n\n// TOOLTIPS\n\n.tooltipster-content {\n  p.type, div.type {\n    text-align: center;\n    font-size: 0.5em;\n    margin-bottom: -0.5em;\n    margin-top: 0;\n    span {\n      font-weight: bold;\n      text-transform: capitalize;\n    }\n  }\n  p.value_store label span .node.different {\n    text-decoration: line-through;\n  }\n}\n// THEME\n.makro_tooltipster_color(@color) {\n  &.tooltipster-top,\n  &.tooltipster-bottom {\n    .tooltipster-box {\n      border-left: 0 none #2a2a2a;\n      border-right: 0 none #2a2a2a;\n      border-bottom: 3px solid @color;\n      border-top: 3px solid @color;\n    }\n    .tooltipster-arrow-border {\n      border-bottom-color: @color;\n      border-top-color: @color;\n    }\n  }\n  &.tooltipster-left,\n  &.tooltipster-right {\n    .tooltipster-box {\n      border-top: 0 none #2a2a2a;\n      border-bottom: 0 none #2a2a2a;\n      border-left: 3px solid @color;\n      border-right: 3px solid @color;\n    }\n    .tooltipster-arrow-border {\n      border-left-color: @color;\n      border-right-color: @color;\n    }\n  }\n  .tooltipster-content {\n    color: @color;\n    font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Helvetica, Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\";\n    font-variant: normal;\n  }\n}\n.tooltipster-sidetip.tooltipster-punk {\n  &.tooltipster-punk-acknowledge-init,\n  &.tooltipster-punk-send-init {\n    .makro_tooltipster_color(@msg-init);\n  }\n\n  &.tooltipster-punk-acknowledge-propose,\n  &.tooltipster-punk-send-propose {\n    .makro_tooltipster_color(@msg-propose);\n  }\n\n  &.tooltipster-punk-acknowledge-prevote,\n  &.tooltipster-punk-send-prevote {\n    .makro_tooltipster_color(@msg-prevote);\n  }\n\n  &.tooltipster-punk-acknowledge-vote,\n  &.tooltipster-punk-send-vote {\n    .makro_tooltipster_color(@msg-vote);\n  }\n}\n"
  },
  {
    "path": "code/web/src/app.module.js",
    "content": "'use strict';\n\n// Declare app level module which depends on views, and components\nangular.module('pbftGui', [\n  'ngAnimate',\n  'ngRoute',\n  'ngResource',\n  'core',\n  'nodeList',\n  'valueGraph',\n  'nodeListView',\n  'failureTable',\n  'failureTableView'\n]);\n"
  },
  {
    "path": "code/web/src/config.js",
    "content": "'use strict';\n\n// WARNING\n// If you use docker, to start this\n// this file will be overwritten on startup.\n// This happens in entrypoint.sh,\n// _API_URL is set to $API_URL.\n// WARNING\n\nvar _API_URL = \"http://192.168.99.100\";"
  },
  {
    "path": "code/web/src/core/core.module.js",
    "content": "/**\n * Created by PlayingBacon on 30.10.2016.\n */\n'use strict';\n\nangular.module('core', [\n    'core.node',\n    'core.d3Factory'\n    //'core.d3Directive',\n    //'core.recompile'\n]);\n"
  },
  {
    "path": "code/web/src/core/d3/d3.directive.js",
    "content": "/**\n * Created by PlayingBacon on 15.11.2016.\n */\n(function() {\n    'use strict';\n\n    angular.module('core.d3Directive')\n        .directive('d3Directive', ['d3Factory', function (d3) {\n            return {\n                restrict: 'EA',\n                scope: {},\n                link: function (scope, iElement, iAttrs) {\n                    var svg = d3.select(iElement[0])\n                        .append(\"svg\")\n                        .attr(\"width\", \"100%\")\n                        .attr(\"height\", \"100%\");\n\n                    // dummy data\n                    scope.data = [\n                        /*{name: \"Greg\", score: 98},\n                        {name: \"Ari\", score: 96},\n                        {name: \"Loser\", score: 48},\n                        {name: \"Me\", score: 66},\n                        {name: \"Rita\", score: 20},\n                        {name: \"Nameless\", score: 75}*/\n                        0.5, 0.6, 0.5, 3.0, 0.4, 0.5, 0.5, 0.6, 0.5, 1.0, 0.5, 0.5, 0.4, 0.7\n                    ];\n\n                    // on window resize, re-render d3 canvas\n                    window.onresize = function () {\n                        return scope.$apply();\n                    };\n                    scope.$watch(function () {\n                        return angular.element(window)[0].innerWidth;\n                    }, function () {\n                        return scope.render(scope.data);\n                    });\n\n                    // define render function\n                    scope.render = function (data) {\n                        // remove all previous items before render\n                        svg.selectAll(\"*\").remove();\n\n                        // setup variables\n                        var str = \"Output |\";\n                        /*var classes = d3.select(iElement[0]).attr(\"class\");\n                        for (var i = 0; i < classes.length; i++) {\n                            str = str+ \"| \" +classes[i]+ \" \";\n                        }\n                        console.log(str);*/\n                        /*\n                        var elements = d3.select(iElement[0]);\n                        for (var i = 0; i < elements.length; i++) {\n                            str = str + \"| ::(\" +i+ \") \"\n                            for (var j = 0; j < elements[i].length; j++) {\n                                str = str + \"| \" +elements[i][j]+ \" \";\n                            }\n                        }\n                        console.log(str);*/\n                        console.log(\"Bounding rect (div): \" +d3.select(iElement[0]).node().getBoundingClientRect().width);\n                        console.log(\"svg.width: \" +svg.select(\"svg\").offsetWidth);\n                        var divs = d3.selectAll(\"div\");\n                        for (var i = 0; i < divs.length; i++) {\n                            console.log(divs.attr(\"class\"));\n                            /*for (var j = 0; j < divs[i].length; j++) {\n                                console.log(\"(\" +i+ \") Class: \" +divs[i][j].attr(\"class\")+ \" || Width: \" +divs[i][j].node().getBoundingClientRect().width);\n                            }*/\n                        }\n\n                        var width, height, max;\n                        width = d3.select(iElement[0])[0][0];/*d3.select(iElement[0])[0][0].offsetWidth - 20;*/ // 20 is for margins\n                        console.log(\"iElement[0]: \" +d3.select(iElement[0])+ \" | offsetWidth: \" +d3.select(iElement[0]).offsetWidth);\n                        console.log(\"(iElement[0])[0][0]: \" +d3.select(iElement[0])[0][0]+ \" | (iElement[0])[0][0].offsetWidth: \" +d3.select(iElement[0])[0][0].offsetWidth);\n                        height = scope.data.length * 35; // 35 = bar height (30) + margin (5)\n                        max = 98; // just some value\n\n                        var parent = svg.node().parentNode;\n                        console.log(\"PARENT :: element : \" +parent+ \" ; offsetWidth : \" +parent.offsetWidth+ \" ; clientWidth : \" +parent.clientWidth+ \" ; scrollWidth : \" +parent.scrollWidth);\n\n                        var xScale = d3.scale.linear()\n                            .domain([0,d3.max(scope.data,function(d){return d;})])\n                            .range([0,/*WIDTH, die ich nicht berechnet kriege! WAH!*/]);\n                        var yScale = d3.scale.linear()\n                            .domain([0,d3.max(scope.data,function(d){return d;})])\n                            .range([0,height]);\n\n                        svg.attr(\"height\", height);\n                        svg.selectAll(\"circle\")\n                            .data(data)\n                            .enter()\n                            /*.append(\"rect\")\n                            .attr(\"height\", 30)\n                            .attr(\"width\", 0)\n                            .attr(\"x\", 10)\n                            .attr(\"y\", function (d, i) {\n                                return i * 35;\n                            })*/\n                            .append(\"circle\")\n                            .attr(\"cx\",function(d,i){return i*100+100;})\n                            .attr(\"cy\",function(d,i){return ;})\n                            .attr(\"r\",10)\n                            .attr(\"fill\",function(d){return \"rgb(\" +(d+100)+ \",\" +(d+50)+ \",\" +d+ \")\";});\n                            /*.transition()\n                            .duration(1000)\n                            .attr(\"width\", function (d) {\n                                return d.score / (max / width);\n                            })*/\n                        svg.append(\"text\")\n                            .text(\"D3 funktioniert! Theoretisch!\")\n                            .attr(\"x\",\"0px\")\n                            .attr(\"y\",\"100px\")\n                            .attr(\"font-family\",\"sans-serif\")\n                            .attr(\"font-size\",\"20px\")\n                            .attr(\"color\", \"white\");\n\n                        console.log(\"NACH APPEND :: (iElement[0])[0][0]: \" +d3.select(iElement[0])[0][0]+ \" | (iElement[0])[0][0].offsetWidth: \" +d3.select(iElement[0])[0][0].offsetWidth);\n                    }\n                }\n                // directive code\n            };\n        }]);\n}());"
  },
  {
    "path": "code/web/src/core/d3/d3.directive.module.js",
    "content": "/**\n * Created by PlayingBacon on 15.11.2016.\n */\n'use strict';\n\nangular.module('core.d3Directive', ['core.d3Factory']);"
  },
  {
    "path": "code/web/src/core/d3/d3.factory.js",
    "content": "/**\n * Created by PlayingBacon on 15.11.2016.\n */\n'use strict';\n\nangular.module('core.d3Factory')\n    .factory('d3Factory',[function() {\n        var d3;\n        // https://d3js.org Version 4.3.0. Copyright 2016 Mike Bostock.\n        d3 = function(){function n(n){return null!=n&&!isNaN(n)}function t(n){return n.length}function e(n){for(var t=1;n*t%1;)t*=10;return t}function r(n,t){try{for(var e in t)Object.defineProperty(n.prototype,e,{value:t[e],enumerable:!1})}catch(r){n.prototype=t}}function u(){}function i(){}function o(n,t,e){return function(){var r=e.apply(t,arguments);return r===t?n:r}}function a(n,t){if(t in n)return t;t=t.charAt(0).toUpperCase()+t.substring(1);for(var e=0,r=Do.length;r>e;++e){var u=Do[e]+t;if(u in n)return u}}function c(){}function l(){}function s(n){function t(){for(var t,r=e,u=-1,i=r.length;++u<i;)(t=r[u].on)&&t.apply(this,arguments);return n}var e=[],r=new u;return t.on=function(t,u){var i,o=r.get(t);return arguments.length<2?o&&o.on:(o&&(o.on=null,e=e.slice(0,i=e.indexOf(o)).concat(e.slice(i+1)),r.remove(t)),u&&e.push(r.set(t,{on:u})),n)},t}function f(){mo.event.preventDefault()}function h(){for(var n,t=mo.event;n=t.sourceEvent;)t=n;return t}function g(n){for(var t=new l,e=0,r=arguments.length;++e<r;)t[arguments[e]]=s(t);return t.of=function(e,r){return function(u){try{var i=u.sourceEvent=mo.event;u.target=n,mo.event=u,t[u.type].apply(e,r)}finally{mo.event=i}}},t}function p(n){return Lo(n,Ro),n}function d(n){return\"function\"==typeof n?n:function(){return Ho(n,this)}}function v(n){return\"function\"==typeof n?n:function(){return Fo(n,this)}}function m(n,t){function e(){this.removeAttribute(n)}function r(){this.removeAttributeNS(n.space,n.local)}function u(){this.setAttribute(n,t)}function i(){this.setAttributeNS(n.space,n.local,t)}function o(){var e=t.apply(this,arguments);null==e?this.removeAttribute(n):this.setAttribute(n,e)}function a(){var e=t.apply(this,arguments);null==e?this.removeAttributeNS(n.space,n.local):this.setAttributeNS(n.space,n.local,e)}return n=mo.ns.qualify(n),null==t?n.local?r:e:\"function\"==typeof t?n.local?a:o:n.local?i:u}function y(n){return n.trim().replace(/\\s+/g,\" \")}function M(n){return new RegExp(\"(?:^|\\\\s+)\"+mo.requote(n)+\"(?:\\\\s+|$)\",\"g\")}function x(n,t){function e(){for(var e=-1;++e<u;)n[e](this,t)}function r(){for(var e=-1,r=t.apply(this,arguments);++e<u;)n[e](this,r)}n=n.trim().split(/\\s+/).map(b);var u=n.length;return\"function\"==typeof t?r:e}function b(n){var t=M(n);return function(e,r){if(u=e.classList)return r?u.add(n):u.remove(n);var u=e.getAttribute(\"class\")||\"\";r?(t.lastIndex=0,t.test(u)||e.setAttribute(\"class\",y(u+\" \"+n))):e.setAttribute(\"class\",y(u.replace(t,\" \")))}}function _(n,t,e){function r(){this.style.removeProperty(n)}function u(){this.style.setProperty(n,t,e)}function i(){var r=t.apply(this,arguments);null==r?this.style.removeProperty(n):this.style.setProperty(n,r,e)}return null==t?r:\"function\"==typeof t?i:u}function w(n,t){function e(){delete this[n]}function r(){this[n]=t}function u(){var e=t.apply(this,arguments);null==e?delete this[n]:this[n]=e}return null==t?e:\"function\"==typeof t?u:r}function S(n){return\"function\"==typeof n?n:(n=mo.ns.qualify(n)).local?function(){return xo.createElementNS(n.space,n.local)}:function(){return xo.createElementNS(this.namespaceURI,n)}}function E(n){return{__data__:n}}function k(n){return function(){return Oo(this,n)}}function A(n){return arguments.length||(n=mo.ascending),function(t,e){return t&&e?n(t.__data__,e.__data__):!t-!e}}function N(n,t){for(var e=0,r=n.length;r>e;e++)for(var u,i=n[e],o=0,a=i.length;a>o;o++)(u=i[o])&&t(u,o,e);return n}function T(n){return Lo(n,Io),n}function q(n){var t,e;return function(r,u,i){var o,a=n[i].update,c=a.length;for(i!=e&&(e=i,t=0),u>=t&&(t=u+1);!(o=a[t])&&++t<c;);return o}}function z(){var n=this.__transition__;n&&++n.active}function C(n,t,e){function r(){var t=this[o];t&&(this.removeEventListener(n,t,t.$),delete this[o])}function u(){var u=l(t,Mo(arguments));r.call(this),this.addEventListener(n,this[o]=u,u.$=e),u._=t}function i(){var t,e=new RegExp(\"^__on([^.]+)\"+mo.requote(n)+\"$\");for(var r in this)if(t=r.match(e)){var u=this[r];this.removeEventListener(t[1],u,u.$),delete this[r]}}var o=\"__on\"+n,a=n.indexOf(\".\"),l=D;a>0&&(n=n.substring(0,a));var s=Zo.get(n);return s&&(n=s,l=j),a?t?u:r:t?c:i}function D(n,t){return function(e){var r=mo.event;mo.event=e,t[0]=this.__data__;try{n.apply(this,t)}finally{mo.event=r}}}function j(n,t){var e=D(n,t);return function(n){var t=this,r=n.relatedTarget;r&&(r===t||8&r.compareDocumentPosition(t))||e.call(t,n)}}function L(){var n=\".dragsuppress-\"+ ++Xo,t=\"touchmove\"+n,e=\"selectstart\"+n,r=\"dragstart\"+n,u=\"click\"+n,i=mo.select(_o).on(t,f).on(e,f).on(r,f),o=bo.style,a=o[Vo];return o[Vo]=\"none\",function(t){function e(){i.on(u,null)}i.on(n,null),o[Vo]=a,t&&(i.on(u,function(){f(),e()},!0),setTimeout(e,0))}}function H(n,t){t.changedTouches&&(t=t.changedTouches[0]);var e=n.ownerSVGElement||n;if(e.createSVGPoint){var r=e.createSVGPoint();if(0>$o&&(_o.scrollX||_o.scrollY)){e=mo.select(\"body\").append(\"svg\").style({position:\"absolute\",top:0,left:0,margin:0,padding:0,border:\"none\"},\"important\");var u=e[0][0].getScreenCTM();$o=!(u.f||u.e),e.remove()}return $o?(r.x=t.pageX,r.y=t.pageY):(r.x=t.clientX,r.y=t.clientY),r=r.matrixTransform(n.getScreenCTM().inverse()),[r.x,r.y]}var i=n.getBoundingClientRect();return[t.clientX-i.left-n.clientLeft,t.clientY-i.top-n.clientTop]}function F(n){return n>0?1:0>n?-1:0}function P(n){return n>1?0:-1>n?Bo:Math.acos(n)}function O(n){return n>1?Bo/2:-1>n?-Bo/2:Math.asin(n)}function R(n){return(Math.exp(n)-Math.exp(-n))/2}function Y(n){return(Math.exp(n)+Math.exp(-n))/2}function I(n){return R(n)/Y(n)}function U(n){return(n=Math.sin(n/2))*n}function Z(){}function V(n,t,e){return new X(n,t,e)}function X(n,t,e){this.h=n,this.s=t,this.l=e}function $(n,t,e){function r(n){return n>360?n-=360:0>n&&(n+=360),60>n?i+(o-i)*n/60:180>n?o:240>n?i+(o-i)*(240-n)/60:i}function u(n){return Math.round(255*r(n))}var i,o;return n=isNaN(n)?0:(n%=360)<0?n+360:n,t=isNaN(t)?0:0>t?0:t>1?1:t,e=0>e?0:e>1?1:e,o=.5>=e?e*(1+t):e+t-e*t,i=2*e-o,ot(u(n+120),u(n),u(n-120))}function B(n,t,e){return new W(n,t,e)}function W(n,t,e){this.h=n,this.c=t,this.l=e}function J(n,t,e){return isNaN(n)&&(n=0),isNaN(t)&&(t=0),G(e,Math.cos(n*=Go)*t,Math.sin(n)*t)}function G(n,t,e){return new K(n,t,e)}function K(n,t,e){this.l=n,this.a=t,this.b=e}function Q(n,t,e){var r=(n+16)/116,u=r+t/500,i=r-e/200;return u=tt(u)*ca,r=tt(r)*la,i=tt(i)*sa,ot(rt(3.2404542*u-1.5371385*r-.4985314*i),rt(-.969266*u+1.8760108*r+.041556*i),rt(.0556434*u-.2040259*r+1.0572252*i))}function nt(n,t,e){return n>0?B(Math.atan2(e,t)*Ko,Math.sqrt(t*t+e*e),n):B(0/0,0/0,n)}function tt(n){return n>.206893034?n*n*n:(n-4/29)/7.787037}function et(n){return n>.008856?Math.pow(n,1/3):7.787037*n+4/29}function rt(n){return Math.round(255*(.00304>=n?12.92*n:1.055*Math.pow(n,1/2.4)-.055))}function ut(n){return ot(n>>16,255&n>>8,255&n)}function it(n){return ut(n)+\"\"}function ot(n,t,e){return new at(n,t,e)}function at(n,t,e){this.r=n,this.g=t,this.b=e}function ct(n){return 16>n?\"0\"+Math.max(0,n).toString(16):Math.min(255,n).toString(16)}function lt(n,t,e){var r,u,i,o=0,a=0,c=0;if(r=/([a-z]+)\\((.*)\\)/i.exec(n))switch(u=r[2].split(\",\"),r[1]){case\"hsl\":return e(parseFloat(u[0]),parseFloat(u[1])/100,parseFloat(u[2])/100);case\"rgb\":return t(gt(u[0]),gt(u[1]),gt(u[2]))}return(i=ga.get(n))?t(i.r,i.g,i.b):(null!=n&&\"#\"===n.charAt(0)&&(4===n.length?(o=n.charAt(1),o+=o,a=n.charAt(2),a+=a,c=n.charAt(3),c+=c):7===n.length&&(o=n.substring(1,3),a=n.substring(3,5),c=n.substring(5,7)),o=parseInt(o,16),a=parseInt(a,16),c=parseInt(c,16)),t(o,a,c))}function st(n,t,e){var r,u,i=Math.min(n/=255,t/=255,e/=255),o=Math.max(n,t,e),a=o-i,c=(o+i)/2;return a?(u=.5>c?a/(o+i):a/(2-o-i),r=n==o?(t-e)/a+(e>t?6:0):t==o?(e-n)/a+2:(n-t)/a+4,r*=60):(r=0/0,u=c>0&&1>c?0:r),V(r,u,c)}function ft(n,t,e){n=ht(n),t=ht(t),e=ht(e);var r=et((.4124564*n+.3575761*t+.1804375*e)/ca),u=et((.2126729*n+.7151522*t+.072175*e)/la),i=et((.0193339*n+.119192*t+.9503041*e)/sa);return G(116*u-16,500*(r-u),200*(u-i))}function ht(n){return(n/=255)<=.04045?n/12.92:Math.pow((n+.055)/1.055,2.4)}function gt(n){var t=parseFloat(n);return\"%\"===n.charAt(n.length-1)?Math.round(2.55*t):t}function pt(n){return\"function\"==typeof n?n:function(){return n}}function dt(n){return n}function vt(n){return function(t,e,r){return 2===arguments.length&&\"function\"==typeof e&&(r=e,e=null),mt(t,e,n,r)}}function mt(n,t,e,r){function u(){var n,t=c.status;if(!t&&c.responseText||t>=200&&300>t||304===t){try{n=e.call(i,c)}catch(r){return o.error.call(i,r),void 0}o.load.call(i,n)}else o.error.call(i,c)}var i={},o=mo.dispatch(\"beforesend\",\"progress\",\"load\",\"error\"),a={},c=new XMLHttpRequest,l=null;return!_o.XDomainRequest||\"withCredentials\"in c||!/^(http(s)?:)?\\/\\//.test(n)||(c=new XDomainRequest),\"onload\"in c?c.onload=c.onerror=u:c.onreadystatechange=function(){c.readyState>3&&u()},c.onprogress=function(n){var t=mo.event;mo.event=n;try{o.progress.call(i,c)}finally{mo.event=t}},i.header=function(n,t){return n=(n+\"\").toLowerCase(),arguments.length<2?a[n]:(null==t?delete a[n]:a[n]=t+\"\",i)},i.mimeType=function(n){return arguments.length?(t=null==n?null:n+\"\",i):t},i.responseType=function(n){return arguments.length?(l=n,i):l},i.response=function(n){return e=n,i},[\"get\",\"post\"].forEach(function(n){i[n]=function(){return i.send.apply(i,[n].concat(Mo(arguments)))}}),i.send=function(e,r,u){if(2===arguments.length&&\"function\"==typeof r&&(u=r,r=null),c.open(e,n,!0),null==t||\"accept\"in a||(a.accept=t+\",*/*\"),c.setRequestHeader)for(var s in a)c.setRequestHeader(s,a[s]);return null!=t&&c.overrideMimeType&&c.overrideMimeType(t),null!=l&&(c.responseType=l),null!=u&&i.on(\"error\",u).on(\"load\",function(n){u(null,n)}),o.beforesend.call(i,c),c.send(null==r?null:r),i},i.abort=function(){return c.abort(),i},mo.rebind(i,o,\"on\"),null==r?i:i.get(yt(r))}function yt(n){return 1===n.length?function(t,e){n(null==t?e:null)}:n}function Mt(){var n=bt(),t=_t()-n;t>24?(isFinite(t)&&(clearTimeout(ma),ma=setTimeout(Mt,t)),va=0):(va=1,Ma(Mt))}function xt(n,t,e){var r=arguments.length;2>r&&(t=0),3>r&&(e=Date.now()),ya.callback=n,ya.time=e+t}function bt(){var n=Date.now();for(ya=pa;ya;)n>=ya.time&&(ya.flush=ya.callback(n-ya.time)),ya=ya.next;return n}function _t(){for(var n,t=pa,e=1/0;t;)t.flush?t=n?n.next=t.next:pa=t.next:(t.time<e&&(e=t.time),t=(n=t).next);return da=n,e}function wt(n,t){var e=Math.pow(10,3*Math.abs(8-t));return{scale:t>8?function(n){return n/e}:function(n){return n*e},symbol:n}}function St(n,t){return t-(n?Math.ceil(Math.log(n)/Math.LN10):1)}function Et(n){return n+\"\"}function kt(){}function At(n,t,e){var r=e.s=n+t,u=r-n,i=r-u;e.t=n-i+(t-u)}function Nt(n,t){n&&za.hasOwnProperty(n.type)&&za[n.type](n,t)}function Tt(n,t,e){var r,u=-1,i=n.length-e;for(t.lineStart();++u<i;)r=n[u],t.point(r[0],r[1],r[2]);t.lineEnd()}function qt(n,t){var e=-1,r=n.length;for(t.polygonStart();++e<r;)Tt(n[e],t,1);t.polygonEnd()}function zt(){function n(n,t){n*=Go,t=t*Go/2+Bo/4;var e=n-r,o=Math.cos(t),a=Math.sin(t),c=i*a,l=u*o+c*Math.cos(e),s=c*Math.sin(e);Da.add(Math.atan2(s,l)),r=n,u=o,i=a}var t,e,r,u,i;ja.point=function(o,a){ja.point=n,r=(t=o)*Go,u=Math.cos(a=(e=a)*Go/2+Bo/4),i=Math.sin(a)},ja.lineEnd=function(){n(t,e)}}function Ct(n){var t=n[0],e=n[1],r=Math.cos(e);return[r*Math.cos(t),r*Math.sin(t),Math.sin(e)]}function Dt(n,t){return n[0]*t[0]+n[1]*t[1]+n[2]*t[2]}function jt(n,t){return[n[1]*t[2]-n[2]*t[1],n[2]*t[0]-n[0]*t[2],n[0]*t[1]-n[1]*t[0]]}function Lt(n,t){n[0]+=t[0],n[1]+=t[1],n[2]+=t[2]}function Ht(n,t){return[n[0]*t,n[1]*t,n[2]*t]}function Ft(n){var t=Math.sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]);n[0]/=t,n[1]/=t,n[2]/=t}function Pt(n){return[Math.atan2(n[1],n[0]),O(n[2])]}function Ot(n,t){return Math.abs(n[0]-t[0])<Wo&&Math.abs(n[1]-t[1])<Wo}function Rt(n,t){n*=Go;var e=Math.cos(t*=Go);Yt(e*Math.cos(n),e*Math.sin(n),Math.sin(t))}function Yt(n,t,e){++La,Fa+=(n-Fa)/La,Pa+=(t-Pa)/La,Oa+=(e-Oa)/La}function It(){function n(n,u){n*=Go;var i=Math.cos(u*=Go),o=i*Math.cos(n),a=i*Math.sin(n),c=Math.sin(u),l=Math.atan2(Math.sqrt((l=e*c-r*a)*l+(l=r*o-t*c)*l+(l=t*a-e*o)*l),t*o+e*a+r*c);Ha+=l,Ra+=l*(t+(t=o)),Ya+=l*(e+(e=a)),Ia+=l*(r+(r=c)),Yt(t,e,r)}var t,e,r;Xa.point=function(u,i){u*=Go;var o=Math.cos(i*=Go);t=o*Math.cos(u),e=o*Math.sin(u),r=Math.sin(i),Xa.point=n,Yt(t,e,r)}}function Ut(){Xa.point=Rt}function Zt(){function n(n,t){n*=Go;var e=Math.cos(t*=Go),o=e*Math.cos(n),a=e*Math.sin(n),c=Math.sin(t),l=u*c-i*a,s=i*o-r*c,f=r*a-u*o,h=Math.sqrt(l*l+s*s+f*f),g=r*o+u*a+i*c,p=h&&-P(g)/h,d=Math.atan2(h,g);Ua+=p*l,Za+=p*s,Va+=p*f,Ha+=d,Ra+=d*(r+(r=o)),Ya+=d*(u+(u=a)),Ia+=d*(i+(i=c)),Yt(r,u,i)}var t,e,r,u,i;Xa.point=function(o,a){t=o,e=a,Xa.point=n,o*=Go;var c=Math.cos(a*=Go);r=c*Math.cos(o),u=c*Math.sin(o),i=Math.sin(a),Yt(r,u,i)},Xa.lineEnd=function(){n(t,e),Xa.lineEnd=Ut,Xa.point=Rt}}function Vt(){return!0}function Xt(n,t,e,r,u){var i=[],o=[];if(n.forEach(function(n){if(!((t=n.length-1)<=0)){var t,e=n[0],r=n[t];if(Ot(e,r)){u.lineStart();for(var a=0;t>a;++a)u.point((e=n[a])[0],e[1]);return u.lineEnd(),void 0}var c={point:e,points:n,other:null,visited:!1,entry:!0,subject:!0},l={point:e,points:[e],other:c,visited:!1,entry:!1,subject:!1};c.other=l,i.push(c),o.push(l),c={point:r,points:[r],other:null,visited:!1,entry:!1,subject:!0},l={point:r,points:[r],other:c,visited:!1,entry:!0,subject:!1},c.other=l,i.push(c),o.push(l)}}),o.sort(t),$t(i),$t(o),i.length){if(e)for(var a=1,c=!e(o[0].point),l=o.length;l>a;++a)o[a].entry=c=!c;for(var s,f,h,g=i[0];;){for(s=g;s.visited;)if((s=s.next)===g)return;f=s.points,u.lineStart();do{if(s.visited=s.other.visited=!0,s.entry){if(s.subject)for(var a=0;a<f.length;a++)u.point((h=f[a])[0],h[1]);else r(s.point,s.next.point,1,u);s=s.next}else{if(s.subject){f=s.prev.points;for(var a=f.length;--a>=0;)u.point((h=f[a])[0],h[1])}else r(s.point,s.prev.point,-1,u);s=s.prev}s=s.other,f=s.points}while(!s.visited);u.lineEnd()}}}function $t(n){if(t=n.length){for(var t,e,r=0,u=n[0];++r<t;)u.next=e=n[r],e.prev=u,u=e;u.next=e=n[0],e.prev=u}}function Bt(n,t,e,r){return function(u){function i(t,e){n(t,e)&&u.point(t,e)}function o(n,t){d.point(n,t)}function a(){v.point=o,d.lineStart()}function c(){v.point=i,d.lineEnd()}function l(n,t){y.point(n,t),p.push([n,t])}function s(){y.lineStart(),p=[]}function f(){l(p[0][0],p[0][1]),y.lineEnd();var n,t=y.clean(),e=m.buffer(),r=e.length;if(p.pop(),g.push(p),p=null,r){if(1&t){n=e[0];var i,r=n.length-1,o=-1;for(u.lineStart();++o<r;)u.point((i=n[o])[0],i[1]);return u.lineEnd(),void 0}r>1&&2&t&&e.push(e.pop().concat(e.shift())),h.push(e.filter(Wt))}}var h,g,p,d=t(u),v={point:i,lineStart:a,lineEnd:c,polygonStart:function(){v.point=l,v.lineStart=s,v.lineEnd=f,h=[],g=[],u.polygonStart()},polygonEnd:function(){v.point=i,v.lineStart=a,v.lineEnd=c,h=mo.merge(h),h.length?Xt(h,Gt,null,e,u):r(g)&&(u.lineStart(),e(null,null,1,u),u.lineEnd()),u.polygonEnd(),h=g=null},sphere:function(){u.polygonStart(),u.lineStart(),e(null,null,1,u),u.lineEnd(),u.polygonEnd()}},m=Jt(),y=t(m);return v}}function Wt(n){return n.length>1}function Jt(){var n,t=[];return{lineStart:function(){t.push(n=[])},point:function(t,e){n.push([t,e])},lineEnd:c,buffer:function(){var e=t;return t=[],n=null,e},rejoin:function(){t.length>1&&t.push(t.pop().concat(t.shift()))}}}function Gt(n,t){return((n=n.point)[0]<0?n[1]-Bo/2-Wo:Bo/2-n[1])-((t=t.point)[0]<0?t[1]-Bo/2-Wo:Bo/2-t[1])}function Kt(n,t){var e=n[0],r=n[1],u=[Math.sin(e),-Math.cos(e),0],i=0,o=!1,a=!1,c=0;Da.reset();for(var l=0,s=t.length;s>l;++l){var f=t[l],h=f.length;if(h){for(var g=f[0],p=g[0],d=g[1]/2+Bo/4,v=Math.sin(d),m=Math.cos(d),y=1;;){y===h&&(y=0),n=f[y];var M=n[0],x=n[1]/2+Bo/4,b=Math.sin(x),_=Math.cos(x),w=M-p,S=Math.abs(w)>Bo,E=v*b;if(Da.add(Math.atan2(E*Math.sin(w),m*_+E*Math.cos(w))),Math.abs(x)<Wo&&(a=!0),i+=S?w+(w>=0?2:-2)*Bo:w,S^p>=e^M>=e){var k=jt(Ct(g),Ct(n));Ft(k);var A=jt(u,k);Ft(A);var N=(S^w>=0?-1:1)*O(A[2]);r>N&&(c+=S^w>=0?1:-1)}if(!y++)break;p=M,v=b,m=_,g=n}Math.abs(i)>Wo&&(o=!0)}}return(!a&&!o&&0>Da||-Wo>i)^1&c}function Qt(n){var t,e=0/0,r=0/0,u=0/0;return{lineStart:function(){n.lineStart(),t=1},point:function(i,o){var a=i>0?Bo:-Bo,c=Math.abs(i-e);Math.abs(c-Bo)<Wo?(n.point(e,r=(r+o)/2>0?Bo/2:-Bo/2),n.point(u,r),n.lineEnd(),n.lineStart(),n.point(a,r),n.point(i,r),t=0):u!==a&&c>=Bo&&(Math.abs(e-u)<Wo&&(e-=u*Wo),Math.abs(i-a)<Wo&&(i-=a*Wo),r=ne(e,r,i,o),n.point(u,r),n.lineEnd(),n.lineStart(),n.point(a,r),t=0),n.point(e=i,r=o),u=a},lineEnd:function(){n.lineEnd(),e=r=0/0},clean:function(){return 2-t}}}function ne(n,t,e,r){var u,i,o=Math.sin(n-e);return Math.abs(o)>Wo?Math.atan((Math.sin(t)*(i=Math.cos(r))*Math.sin(e)-Math.sin(r)*(u=Math.cos(t))*Math.sin(n))/(u*i*o)):(t+r)/2}function te(n,t,e,r){var u;if(null==n)u=e*Bo/2,r.point(-Bo,u),r.point(0,u),r.point(Bo,u),r.point(Bo,0),r.point(Bo,-u),r.point(0,-u),r.point(-Bo,-u),r.point(-Bo,0),r.point(-Bo,u);else if(Math.abs(n[0]-t[0])>Wo){var i=(n[0]<t[0]?1:-1)*Bo;u=e*i/2,r.point(-i,u),r.point(0,u),r.point(i,u)}else r.point(t[0],t[1])}function ee(n){return Kt(Ba,n)}function re(n){function t(n,t){return Math.cos(n)*Math.cos(t)>o}function e(n){var e,i,o,c,s;return{lineStart:function(){c=o=!1,s=1},point:function(f,h){var g,p=[f,h],d=t(f,h),v=a?d?0:u(f,h):d?u(f+(0>f?Bo:-Bo),h):0;if(!e&&(c=o=d)&&n.lineStart(),d!==o&&(g=r(e,p),(Ot(e,g)||Ot(p,g))&&(p[0]+=Wo,p[1]+=Wo,d=t(p[0],p[1]))),d!==o)s=0,d?(n.lineStart(),g=r(p,e),n.point(g[0],g[1])):(g=r(e,p),n.point(g[0],g[1]),n.lineEnd()),e=g;else if(l&&e&&a^d){var m;v&i||!(m=r(p,e,!0))||(s=0,a?(n.lineStart(),n.point(m[0][0],m[0][1]),n.point(m[1][0],m[1][1]),n.lineEnd()):(n.point(m[1][0],m[1][1]),n.lineEnd(),n.lineStart(),n.point(m[0][0],m[0][1])))}!d||e&&Ot(e,p)||n.point(p[0],p[1]),e=p,o=d,i=v},lineEnd:function(){o&&n.lineEnd(),e=null},clean:function(){return s|(c&&o)<<1}}}function r(n,t,e){var r=Ct(n),u=Ct(t),i=[1,0,0],a=jt(r,u),c=Dt(a,a),l=a[0],s=c-l*l;if(!s)return!e&&n;var f=o*c/s,h=-o*l/s,g=jt(i,a),p=Ht(i,f),d=Ht(a,h);Lt(p,d);var v=g,m=Dt(p,v),y=Dt(v,v),M=m*m-y*(Dt(p,p)-1);if(!(0>M)){var x=Math.sqrt(M),b=Ht(v,(-m-x)/y);if(Lt(b,p),b=Pt(b),!e)return b;var _,w=n[0],S=t[0],E=n[1],k=t[1];w>S&&(_=w,w=S,S=_);var A=S-w,N=Math.abs(A-Bo)<Wo,T=N||Wo>A;if(!N&&E>k&&(_=E,E=k,k=_),T?N?E+k>0^b[1]<(Math.abs(b[0]-w)<Wo?E:k):E<=b[1]&&b[1]<=k:A>Bo^(w<=b[0]&&b[0]<=S)){var q=Ht(v,(-m+x)/y);return Lt(q,p),[b,Pt(q)]}}}function u(t,e){var r=a?n:Bo-n,u=0;return-r>t?u|=1:t>r&&(u|=2),-r>e?u|=4:e>r&&(u|=8),u}function i(n){return Kt(c,n)}var o=Math.cos(n),a=o>0,c=[n,0],l=Math.abs(o)>Wo,s=Te(n,6*Go);return Bt(t,e,s,i)}function ue(n,t,e,r){function u(r,u){return Math.abs(r[0]-n)<Wo?u>0?0:3:Math.abs(r[0]-e)<Wo?u>0?2:1:Math.abs(r[1]-t)<Wo?u>0?1:0:u>0?3:2}function i(n,t){return o(n.point,t.point)}function o(n,t){var e=u(n,1),r=u(t,1);return e!==r?e-r:0===e?t[1]-n[1]:1===e?n[0]-t[0]:2===e?n[1]-t[1]:t[0]-n[0]}function a(u,i){var o=i[0]-u[0],a=i[1]-u[1],c=[0,1];return Math.abs(o)<Wo&&Math.abs(a)<Wo?n<=u[0]&&u[0]<=e&&t<=u[1]&&u[1]<=r:ie(n-u[0],o,c)&&ie(u[0]-e,-o,c)&&ie(t-u[1],a,c)&&ie(u[1]-r,-a,c)?(c[1]<1&&(i[0]=u[0]+c[1]*o,i[1]=u[1]+c[1]*a),c[0]>0&&(u[0]+=c[0]*o,u[1]+=c[0]*a),!0):!1}return function(c){function l(i){var o=u(i,-1),a=s([0===o||3===o?n:e,o>1?r:t]);return a}function s(n){for(var t=0,e=M.length,r=n[1],u=0;e>u;++u)for(var i,o=1,a=M[u],c=a.length,l=a[0];c>o;++o)i=a[o],l[1]<=r?i[1]>r&&f(l,i,n)>0&&++t:i[1]<=r&&f(l,i,n)<0&&--t,l=i;return 0!==t}function f(n,t,e){return(t[0]-n[0])*(e[1]-n[1])-(e[0]-n[0])*(t[1]-n[1])}function h(i,a,c,l){var s=0,f=0;if(null==i||(s=u(i,c))!==(f=u(a,c))||o(i,a)<0^c>0){do l.point(0===s||3===s?n:e,s>1?r:t);while((s=(s+c+4)%4)!==f)}else l.point(a[0],a[1])}function g(u,i){return u>=n&&e>=u&&i>=t&&r>=i}function p(n,t){g(n,t)&&c.point(n,t)}function d(){q.point=m,M&&M.push(x=[]),A=!0,k=!1,S=E=0/0}function v(){y&&(m(b,_),w&&k&&T.rejoin(),y.push(T.buffer())),q.point=p,k&&c.lineEnd()}function m(n,t){n=Math.max(-Wa,Math.min(Wa,n)),t=Math.max(-Wa,Math.min(Wa,t));var e=g(n,t);if(M&&x.push([n,t]),A)b=n,_=t,w=e,A=!1,e&&(c.lineStart(),c.point(n,t));else if(e&&k)c.point(n,t);else{var r=[S,E],u=[n,t];a(r,u)?(k||(c.lineStart(),c.point(r[0],r[1])),c.point(u[0],u[1]),e||c.lineEnd()):e&&(c.lineStart(),c.point(n,t))}S=n,E=t,k=e}var y,M,x,b,_,w,S,E,k,A,N=c,T=Jt(),q={point:p,lineStart:d,lineEnd:v,polygonStart:function(){c=T,y=[],M=[]},polygonEnd:function(){c=N,(y=mo.merge(y)).length?(c.polygonStart(),Xt(y,i,l,h,c),c.polygonEnd()):s([n,t])&&(c.polygonStart(),c.lineStart(),h(null,null,1,c),c.lineEnd(),c.polygonEnd()),y=M=x=null}};return q}}function ie(n,t,e){if(Math.abs(t)<Wo)return 0>=n;var r=n/t;if(t>0){if(r>e[1])return!1;r>e[0]&&(e[0]=r)}else{if(r<e[0])return!1;r<e[1]&&(e[1]=r)}return!0}function oe(n,t){function e(e,r){return e=n(e,r),t(e[0],e[1])}return n.invert&&t.invert&&(e.invert=function(e,r){return e=t.invert(e,r),e&&n.invert(e[0],e[1])}),e}function ae(n){var t=0,e=Bo/3,r=_e(n),u=r(t,e);return u.parallels=function(n){return arguments.length?r(t=n[0]*Bo/180,e=n[1]*Bo/180):[180*(t/Bo),180*(e/Bo)]},u}function ce(n,t){function e(n,t){var e=Math.sqrt(i-2*u*Math.sin(t))/u;return[e*Math.sin(n*=u),o-e*Math.cos(n)]}var r=Math.sin(n),u=(r+Math.sin(t))/2,i=1+r*(2*u-r),o=Math.sqrt(i)/u;return e.invert=function(n,t){var e=o-t;return[Math.atan2(n,e)/u,O((i-(n*n+e*e)*u*u)/(2*u))]},e}function le(){function n(n,t){Ga+=u*n-r*t,r=n,u=t}var t,e,r,u;ec.point=function(i,o){ec.point=n,t=r=i,e=u=o},ec.lineEnd=function(){n(t,e)}}function se(n,t){Ka>n&&(Ka=n),n>nc&&(nc=n),Qa>t&&(Qa=t),t>tc&&(tc=t)}function fe(){function n(n,t){o.push(\"M\",n,\",\",t,i)}function t(n,t){o.push(\"M\",n,\",\",t),a.point=e}function e(n,t){o.push(\"L\",n,\",\",t)}function r(){a.point=n}function u(){o.push(\"Z\")}var i=he(4.5),o=[],a={point:n,lineStart:function(){a.point=t},lineEnd:r,polygonStart:function(){a.lineEnd=u},polygonEnd:function(){a.lineEnd=r,a.point=n},pointRadius:function(n){return i=he(n),a},result:function(){if(o.length){var n=o.join(\"\");return o=[],n}}};return a}function he(n){return\"m0,\"+n+\"a\"+n+\",\"+n+\" 0 1,1 0,\"+-2*n+\"a\"+n+\",\"+n+\" 0 1,1 0,\"+2*n+\"z\"}function ge(n,t){Fa+=n,Pa+=t,++Oa}function pe(){function n(n,r){var u=n-t,i=r-e,o=Math.sqrt(u*u+i*i);Ra+=o*(t+n)/2,Ya+=o*(e+r)/2,Ia+=o,ge(t=n,e=r)}var t,e;uc.point=function(r,u){uc.point=n,ge(t=r,e=u)}}function de(){uc.point=ge}function ve(){function n(n,t){var e=n-r,i=t-u,o=Math.sqrt(e*e+i*i);Ra+=o*(r+n)/2,Ya+=o*(u+t)/2,Ia+=o,o=u*n-r*t,Ua+=o*(r+n),Za+=o*(u+t),Va+=3*o,ge(r=n,u=t)}var t,e,r,u;uc.point=function(i,o){uc.point=n,ge(t=r=i,e=u=o)},uc.lineEnd=function(){n(t,e)}}function me(n){function t(t,e){n.moveTo(t,e),n.arc(t,e,o,0,2*Bo)}function e(t,e){n.moveTo(t,e),a.point=r}function r(t,e){n.lineTo(t,e)}function u(){a.point=t}function i(){n.closePath()}var o=4.5,a={point:t,lineStart:function(){a.point=e},lineEnd:u,polygonStart:function(){a.lineEnd=i},polygonEnd:function(){a.lineEnd=u,a.point=t},pointRadius:function(n){return o=n,a},result:c};return a}function ye(n){function t(t){function r(e,r){e=n(e,r),t.point(e[0],e[1])}function u(){M=0/0,S.point=o,t.lineStart()}function o(r,u){var o=Ct([r,u]),a=n(r,u);e(M,x,y,b,_,w,M=a[0],x=a[1],y=r,b=o[0],_=o[1],w=o[2],i,t),t.point(M,x)}function a(){S.point=r,t.lineEnd()}function c(){u(),S.point=l,S.lineEnd=s}function l(n,t){o(f=n,h=t),g=M,p=x,d=b,v=_,m=w,S.point=o}function s(){e(M,x,y,b,_,w,g,p,f,d,v,m,i,t),S.lineEnd=a,a()}var f,h,g,p,d,v,m,y,M,x,b,_,w,S={point:r,lineStart:u,lineEnd:a,polygonStart:function(){t.polygonStart(),S.lineStart=c},polygonEnd:function(){t.polygonEnd(),S.lineStart=u}};return S}function e(t,i,o,a,c,l,s,f,h,g,p,d,v,m){var y=s-t,M=f-i,x=y*y+M*M;if(x>4*r&&v--){var b=a+g,_=c+p,w=l+d,S=Math.sqrt(b*b+_*_+w*w),E=Math.asin(w/=S),k=Math.abs(Math.abs(w)-1)<Wo?(o+h)/2:Math.atan2(_,b),A=n(k,E),N=A[0],T=A[1],q=N-t,z=T-i,C=M*q-y*z;(C*C/x>r||Math.abs((y*q+M*z)/x-.5)>.3||u>a*g+c*p+l*d)&&(e(t,i,o,a,c,l,N,T,k,b/=S,_/=S,w,v,m),m.point(N,T),e(N,T,k,b,_,w,s,f,h,g,p,d,v,m))}}var r=.5,u=Math.cos(30*Go),i=16;return t.precision=function(n){return arguments.length?(i=(r=n*n)>0&&16,t):Math.sqrt(r)},t}function Me(n){this.stream=n}function xe(n){var t=ye(function(t,e){return n([t*Ko,e*Ko])});return function(n){var e=new Me(n=t(n));return e.point=function(t,e){n.point(t*Go,e*Go)},e}}function be(n){return _e(function(){return n})()}function _e(n){function t(n){return n=a(n[0]*Go,n[1]*Go),[n[0]*h+c,l-n[1]*h]}function e(n){return n=a.invert((n[0]-c)/h,(l-n[1])/h),n&&[n[0]*Ko,n[1]*Ko]}function r(){a=oe(o=Ee(m,y,M),i);var n=i(d,v);return c=g-n[0]*h,l=p+n[1]*h,u()}function u(){return s&&(s.valid=!1,s=null),t}var i,o,a,c,l,s,f=ye(function(n,t){return n=i(n,t),[n[0]*h+c,l-n[1]*h]}),h=150,g=480,p=250,d=0,v=0,m=0,y=0,M=0,x=$a,b=dt,_=null,w=null;return t.stream=function(n){return s&&(s.valid=!1),s=we(o,x(f(b(n)))),s.valid=!0,s},t.clipAngle=function(n){return arguments.length?(x=null==n?(_=n,$a):re((_=+n)*Go),u()):_},t.clipExtent=function(n){return arguments.length?(w=n,b=n?ue(n[0][0],n[0][1],n[1][0],n[1][1]):dt,u()):w},t.scale=function(n){return arguments.length?(h=+n,r()):h},t.translate=function(n){return arguments.length?(g=+n[0],p=+n[1],r()):[g,p]},t.center=function(n){return arguments.length?(d=n[0]%360*Go,v=n[1]%360*Go,r()):[d*Ko,v*Ko]},t.rotate=function(n){return arguments.length?(m=n[0]%360*Go,y=n[1]%360*Go,M=n.length>2?n[2]%360*Go:0,r()):[m*Ko,y*Ko,M*Ko]},mo.rebind(t,f,\"precision\"),function(){return i=n.apply(this,arguments),t.invert=i.invert&&e,r()}}function we(n,t){var e=new Me(t);return e.point=function(e,r){r=n(e*Go,r*Go),e=r[0],t.point(e>Bo?e-2*Bo:-Bo>e?e+2*Bo:e,r[1])},e}function Se(n,t){return[n,t]}function Ee(n,t,e){return n?t||e?oe(Ae(n),Ne(t,e)):Ae(n):t||e?Ne(t,e):Se}function ke(n){return function(t,e){return t+=n,[t>Bo?t-2*Bo:-Bo>t?t+2*Bo:t,e]}}function Ae(n){var t=ke(n);return t.invert=ke(-n),t}function Ne(n,t){function e(n,t){var e=Math.cos(t),a=Math.cos(n)*e,c=Math.sin(n)*e,l=Math.sin(t),s=l*r+a*u;return[Math.atan2(c*i-s*o,a*r-l*u),O(s*i+c*o)]}var r=Math.cos(n),u=Math.sin(n),i=Math.cos(t),o=Math.sin(t);return e.invert=function(n,t){var e=Math.cos(t),a=Math.cos(n)*e,c=Math.sin(n)*e,l=Math.sin(t),s=l*i-c*o;return[Math.atan2(c*i+l*o,a*r+s*u),O(s*r-a*u)]},e}function Te(n,t){var e=Math.cos(n),r=Math.sin(n);return function(u,i,o,a){var c=o*t;null!=u?(u=qe(e,u),i=qe(e,i),(o>0?i>u:u>i)&&(u+=2*o*Bo)):(u=n+2*o*Bo,i=n-.5*c);for(var l,s=u;o>0?s>i:i>s;s-=c)a.point((l=Pt([e,-r*Math.cos(s),-r*Math.sin(s)]))[0],l[1])}}function qe(n,t){var e=Ct(t);e[0]-=n,Ft(e);var r=P(-e[1]);return((-e[2]<0?-r:r)+2*Math.PI-Wo)%(2*Math.PI)}function ze(n,t,e){var r=mo.range(n,t-Wo,e).concat(t);return function(n){return r.map(function(t){return[n,t]})}}function Ce(n,t,e){var r=mo.range(n,t-Wo,e).concat(t);return function(n){return r.map(function(t){return[t,n]})}}function De(n){return n.source}function je(n){return n.target}function Le(n,t,e,r){var u=Math.cos(t),i=Math.sin(t),o=Math.cos(r),a=Math.sin(r),c=u*Math.cos(n),l=u*Math.sin(n),s=o*Math.cos(e),f=o*Math.sin(e),h=2*Math.asin(Math.sqrt(U(r-t)+u*o*U(e-n))),g=1/Math.sin(h),p=h?function(n){var t=Math.sin(n*=h)*g,e=Math.sin(h-n)*g,r=e*c+t*s,u=e*l+t*f,o=e*i+t*a;return[Math.atan2(u,r)*Ko,Math.atan2(o,Math.sqrt(r*r+u*u))*Ko]}:function(){return[n*Ko,t*Ko]};return p.distance=h,p}function He(){function n(n,u){var i=Math.sin(u*=Go),o=Math.cos(u),a=Math.abs((n*=Go)-t),c=Math.cos(a);ic+=Math.atan2(Math.sqrt((a=o*Math.sin(a))*a+(a=r*i-e*o*c)*a),e*i+r*o*c),t=n,e=i,r=o}var t,e,r;oc.point=function(u,i){t=u*Go,e=Math.sin(i*=Go),r=Math.cos(i),oc.point=n},oc.lineEnd=function(){oc.point=oc.lineEnd=c}}function Fe(n,t){function e(t,e){var r=Math.cos(t),u=Math.cos(e),i=n(r*u);return[i*u*Math.sin(t),i*Math.sin(e)]}return e.invert=function(n,e){var r=Math.sqrt(n*n+e*e),u=t(r),i=Math.sin(u),o=Math.cos(u);return[Math.atan2(n*i,r*o),Math.asin(r&&e*i/r)]},e}function Pe(n,t){function e(n,t){var e=Math.abs(Math.abs(t)-Bo/2)<Wo?0:o/Math.pow(u(t),i);return[e*Math.sin(i*n),o-e*Math.cos(i*n)]}var r=Math.cos(n),u=function(n){return Math.tan(Bo/4+n/2)},i=n===t?Math.sin(n):Math.log(r/Math.cos(t))/Math.log(u(t)/u(n)),o=r*Math.pow(u(n),i)/i;return i?(e.invert=function(n,t){var e=o-t,r=F(i)*Math.sqrt(n*n+e*e);return[Math.atan2(n,e)/i,2*Math.atan(Math.pow(o/r,1/i))-Bo/2]},e):Re}function Oe(n,t){function e(n,t){var e=i-t;return[e*Math.sin(u*n),i-e*Math.cos(u*n)]}var r=Math.cos(n),u=n===t?Math.sin(n):(r-Math.cos(t))/(t-n),i=r/u+n;return Math.abs(u)<Wo?Se:(e.invert=function(n,t){var e=i-t;return[Math.atan2(n,e)/u,i-F(u)*Math.sqrt(n*n+e*e)]},e)}function Re(n,t){return[n,Math.log(Math.tan(Bo/4+t/2))]}function Ye(n){var t,e=be(n),r=e.scale,u=e.translate,i=e.clipExtent;return e.scale=function(){var n=r.apply(e,arguments);return n===e?t?e.clipExtent(null):e:n},e.translate=function(){var n=u.apply(e,arguments);return n===e?t?e.clipExtent(null):e:n},e.clipExtent=function(n){var o=i.apply(e,arguments);if(o===e){if(t=null==n){var a=Bo*r(),c=u();i([[c[0]-a,c[1]-a],[c[0]+a,c[1]+a]])}}else t&&(o=null);return o},e.clipExtent(null)}function Ie(n,t){var e=Math.cos(t)*Math.sin(n);return[Math.log((1+e)/(1-e))/2,Math.atan2(Math.tan(t),Math.cos(n))]}function Ue(n){function t(t){function o(){l.push(\"M\",i(n(s),a))}for(var c,l=[],s=[],f=-1,h=t.length,g=pt(e),p=pt(r);++f<h;)u.call(this,c=t[f],f)?s.push([+g.call(this,c,f),+p.call(this,c,f)]):s.length&&(o(),s=[]);return s.length&&o(),l.length?l.join(\"\"):null}var e=Ze,r=Ve,u=Vt,i=Xe,o=i.key,a=.7;return t.x=function(n){return arguments.length?(e=n,t):e},t.y=function(n){return arguments.length?(r=n,t):r},t.defined=function(n){return arguments.length?(u=n,t):u},t.interpolate=function(n){return arguments.length?(o=\"function\"==typeof n?i=n:(i=hc.get(n)||Xe).key,t):o},t.tension=function(n){return arguments.length?(a=n,t):a},t}function Ze(n){return n[0]}function Ve(n){return n[1]}function Xe(n){return n.join(\"L\")}function $e(n){return Xe(n)+\"Z\"}function Be(n){for(var t=0,e=n.length,r=n[0],u=[r[0],\",\",r[1]];++t<e;)u.push(\"H\",(r[0]+(r=n[t])[0])/2,\"V\",r[1]);return e>1&&u.push(\"H\",r[0]),u.join(\"\")}function We(n){for(var t=0,e=n.length,r=n[0],u=[r[0],\",\",r[1]];++t<e;)u.push(\"V\",(r=n[t])[1],\"H\",r[0]);return u.join(\"\")}function Je(n){for(var t=0,e=n.length,r=n[0],u=[r[0],\",\",r[1]];++t<e;)u.push(\"H\",(r=n[t])[0],\"V\",r[1]);return u.join(\"\")}function Ge(n,t){return n.length<4?Xe(n):n[1]+nr(n.slice(1,n.length-1),tr(n,t))}function Ke(n,t){return n.length<3?Xe(n):n[0]+nr((n.push(n[0]),n),tr([n[n.length-2]].concat(n,[n[1]]),t))}function Qe(n,t){return n.length<3?Xe(n):n[0]+nr(n,tr(n,t))}function nr(n,t){if(t.length<1||n.length!=t.length&&n.length!=t.length+2)return Xe(n);var e=n.length!=t.length,r=\"\",u=n[0],i=n[1],o=t[0],a=o,c=1;if(e&&(r+=\"Q\"+(i[0]-2*o[0]/3)+\",\"+(i[1]-2*o[1]/3)+\",\"+i[0]+\",\"+i[1],u=n[1],c=2),t.length>1){a=t[1],i=n[c],c++,r+=\"C\"+(u[0]+o[0])+\",\"+(u[1]+o[1])+\",\"+(i[0]-a[0])+\",\"+(i[1]-a[1])+\",\"+i[0]+\",\"+i[1];for(var l=2;l<t.length;l++,c++)i=n[c],a=t[l],r+=\"S\"+(i[0]-a[0])+\",\"+(i[1]-a[1])+\",\"+i[0]+\",\"+i[1]}if(e){var s=n[c];r+=\"Q\"+(i[0]+2*a[0]/3)+\",\"+(i[1]+2*a[1]/3)+\",\"+s[0]+\",\"+s[1]}return r}function tr(n,t){for(var e,r=[],u=(1-t)/2,i=n[0],o=n[1],a=1,c=n.length;++a<c;)e=i,i=o,o=n[a],r.push([u*(o[0]-e[0]),u*(o[1]-e[1])]);return r}function er(n){if(n.length<3)return Xe(n);var t=1,e=n.length,r=n[0],u=r[0],i=r[1],o=[u,u,u,(r=n[1])[0]],a=[i,i,i,r[1]],c=[u,\",\",i,\"L\",or(dc,o),\",\",or(dc,a)];for(n.push(n[e-1]);++t<=e;)r=n[t],o.shift(),o.push(r[0]),a.shift(),a.push(r[1]),ar(c,o,a);return n.pop(),c.push(\"L\",r),c.join(\"\")}function rr(n){if(n.length<4)return Xe(n);for(var t,e=[],r=-1,u=n.length,i=[0],o=[0];++r<3;)t=n[r],i.push(t[0]),o.push(t[1]);for(e.push(or(dc,i)+\",\"+or(dc,o)),--r;++r<u;)t=n[r],i.shift(),i.push(t[0]),o.shift(),o.push(t[1]),ar(e,i,o);return e.join(\"\")}function ur(n){for(var t,e,r=-1,u=n.length,i=u+4,o=[],a=[];++r<4;)e=n[r%u],o.push(e[0]),a.push(e[1]);for(t=[or(dc,o),\",\",or(dc,a)],--r;++r<i;)e=n[r%u],o.shift(),o.push(e[0]),a.shift(),a.push(e[1]),ar(t,o,a);return t.join(\"\")}function ir(n,t){var e=n.length-1;if(e)for(var r,u,i=n[0][0],o=n[0][1],a=n[e][0]-i,c=n[e][1]-o,l=-1;++l<=e;)r=n[l],u=l/e,r[0]=t*r[0]+(1-t)*(i+u*a),r[1]=t*r[1]+(1-t)*(o+u*c);return er(n)}function or(n,t){return n[0]*t[0]+n[1]*t[1]+n[2]*t[2]+n[3]*t[3]}function ar(n,t,e){n.push(\"C\",or(gc,t),\",\",or(gc,e),\",\",or(pc,t),\",\",or(pc,e),\",\",or(dc,t),\",\",or(dc,e))}function cr(n,t){return(t[1]-n[1])/(t[0]-n[0])}function lr(n){for(var t=0,e=n.length-1,r=[],u=n[0],i=n[1],o=r[0]=cr(u,i);++t<e;)r[t]=(o+(o=cr(u=i,i=n[t+1])))/2;\n            return r[t]=o,r}function sr(n){for(var t,e,r,u,i=[],o=lr(n),a=-1,c=n.length-1;++a<c;)t=cr(n[a],n[a+1]),Math.abs(t)<1e-6?o[a]=o[a+1]=0:(e=o[a]/t,r=o[a+1]/t,u=e*e+r*r,u>9&&(u=3*t/Math.sqrt(u),o[a]=u*e,o[a+1]=u*r));for(a=-1;++a<=c;)u=(n[Math.min(c,a+1)][0]-n[Math.max(0,a-1)][0])/(6*(1+o[a]*o[a])),i.push([u||0,o[a]*u||0]);return i}function fr(n){return n.length<3?Xe(n):n[0]+nr(n,sr(n))}function hr(n,t,e,r){var u,i,o,a,c,l,s;return u=r[n],i=u[0],o=u[1],u=r[t],a=u[0],c=u[1],u=r[e],l=u[0],s=u[1],(s-o)*(a-i)-(c-o)*(l-i)>0}function gr(n,t,e){return(e[0]-t[0])*(n[1]-t[1])<(e[1]-t[1])*(n[0]-t[0])}function pr(n,t,e,r){var u=n[0],i=e[0],o=t[0]-u,a=r[0]-i,c=n[1],l=e[1],s=t[1]-c,f=r[1]-l,h=(a*(c-l)-f*(u-i))/(f*o-a*s);return[u+h*o,c+h*s]}function dr(n){var t=n[0],e=n[n.length-1];return!(t[0]-e[0]||t[1]-e[1])}function vr(n,t){var e={list:n.map(function(n,t){return{index:t,x:n[0],y:n[1]}}).sort(function(n,t){return n.y<t.y?-1:n.y>t.y?1:n.x<t.x?-1:n.x>t.x?1:0}),bottomSite:null},r={list:[],leftEnd:null,rightEnd:null,init:function(){r.leftEnd=r.createHalfEdge(null,\"l\"),r.rightEnd=r.createHalfEdge(null,\"l\"),r.leftEnd.r=r.rightEnd,r.rightEnd.l=r.leftEnd,r.list.unshift(r.leftEnd,r.rightEnd)},createHalfEdge:function(n,t){return{edge:n,side:t,vertex:null,l:null,r:null}},insert:function(n,t){t.l=n,t.r=n.r,n.r.l=t,n.r=t},leftBound:function(n){var t=r.leftEnd;do t=t.r;while(t!=r.rightEnd&&u.rightOf(t,n));return t=t.l},del:function(n){n.l.r=n.r,n.r.l=n.l,n.edge=null},right:function(n){return n.r},left:function(n){return n.l},leftRegion:function(n){return null==n.edge?e.bottomSite:n.edge.region[n.side]},rightRegion:function(n){return null==n.edge?e.bottomSite:n.edge.region[mc[n.side]]}},u={bisect:function(n,t){var e={region:{l:n,r:t},ep:{l:null,r:null}},r=t.x-n.x,u=t.y-n.y,i=r>0?r:-r,o=u>0?u:-u;return e.c=n.x*r+n.y*u+.5*(r*r+u*u),i>o?(e.a=1,e.b=u/r,e.c/=r):(e.b=1,e.a=r/u,e.c/=u),e},intersect:function(n,t){var e=n.edge,r=t.edge;if(!e||!r||e.region.r==r.region.r)return null;var u=e.a*r.b-e.b*r.a;if(Math.abs(u)<1e-10)return null;var i,o,a=(e.c*r.b-r.c*e.b)/u,c=(r.c*e.a-e.c*r.a)/u,l=e.region.r,s=r.region.r;l.y<s.y||l.y==s.y&&l.x<s.x?(i=n,o=e):(i=t,o=r);var f=a>=o.region.r.x;return f&&\"l\"===i.side||!f&&\"r\"===i.side?null:{x:a,y:c}},rightOf:function(n,t){var e=n.edge,r=e.region.r,u=t.x>r.x;if(u&&\"l\"===n.side)return 1;if(!u&&\"r\"===n.side)return 0;if(1===e.a){var i=t.y-r.y,o=t.x-r.x,a=0,c=0;if(!u&&e.b<0||u&&e.b>=0?c=a=i>=e.b*o:(c=t.x+t.y*e.b>e.c,e.b<0&&(c=!c),c||(a=1)),!a){var l=r.x-e.region.l.x;c=e.b*(o*o-i*i)<l*i*(1+2*o/l+e.b*e.b),e.b<0&&(c=!c)}}else{var s=e.c-e.a*t.x,f=t.y-s,h=t.x-r.x,g=s-r.y;c=f*f>h*h+g*g}return\"l\"===n.side?c:!c},endPoint:function(n,e,r){n.ep[e]=r,n.ep[mc[e]]&&t(n)},distance:function(n,t){var e=n.x-t.x,r=n.y-t.y;return Math.sqrt(e*e+r*r)}},i={list:[],insert:function(n,t,e){n.vertex=t,n.ystar=t.y+e;for(var r=0,u=i.list,o=u.length;o>r;r++){var a=u[r];if(!(n.ystar>a.ystar||n.ystar==a.ystar&&t.x>a.vertex.x))break}u.splice(r,0,n)},del:function(n){for(var t=0,e=i.list,r=e.length;r>t&&e[t]!=n;++t);e.splice(t,1)},empty:function(){return 0===i.list.length},nextEvent:function(n){for(var t=0,e=i.list,r=e.length;r>t;++t)if(e[t]==n)return e[t+1];return null},min:function(){var n=i.list[0];return{x:n.vertex.x,y:n.ystar}},extractMin:function(){return i.list.shift()}};r.init(),e.bottomSite=e.list.shift();for(var o,a,c,l,s,f,h,g,p,d,v,m,y,M=e.list.shift();;)if(i.empty()||(o=i.min()),M&&(i.empty()||M.y<o.y||M.y==o.y&&M.x<o.x))a=r.leftBound(M),c=r.right(a),h=r.rightRegion(a),m=u.bisect(h,M),f=r.createHalfEdge(m,\"l\"),r.insert(a,f),d=u.intersect(a,f),d&&(i.del(a),i.insert(a,d,u.distance(d,M))),a=f,f=r.createHalfEdge(m,\"r\"),r.insert(a,f),d=u.intersect(f,c),d&&i.insert(f,d,u.distance(d,M)),M=e.list.shift();else{if(i.empty())break;a=i.extractMin(),l=r.left(a),c=r.right(a),s=r.right(c),h=r.leftRegion(a),g=r.rightRegion(c),v=a.vertex,u.endPoint(a.edge,a.side,v),u.endPoint(c.edge,c.side,v),r.del(a),i.del(c),r.del(c),y=\"l\",h.y>g.y&&(p=h,h=g,g=p,y=\"r\"),m=u.bisect(h,g),f=r.createHalfEdge(m,y),r.insert(l,f),u.endPoint(m,mc[y],v),d=u.intersect(l,f),d&&(i.del(l),i.insert(l,d,u.distance(d,h))),d=u.intersect(f,s),d&&i.insert(f,d,u.distance(d,h))}for(a=r.right(r.leftEnd);a!=r.rightEnd;a=r.right(a))t(a.edge)}function mr(n){return n.x}function yr(n){return n.y}function Mr(){return{leaf:!0,nodes:[],point:null,x:null,y:null}}function xr(n,t,e,r,u,i){if(!n(t,e,r,u,i)){var o=.5*(e+u),a=.5*(r+i),c=t.nodes;c[0]&&xr(n,c[0],e,r,o,a),c[1]&&xr(n,c[1],o,r,u,a),c[2]&&xr(n,c[2],e,a,o,i),c[3]&&xr(n,c[3],o,a,u,i)}}function br(n,t){n=mo.rgb(n),t=mo.rgb(t);var e=n.r,r=n.g,u=n.b,i=t.r-e,o=t.g-r,a=t.b-u;return function(n){return\"#\"+ct(Math.round(e+i*n))+ct(Math.round(r+o*n))+ct(Math.round(u+a*n))}}function _r(n,t){var e,r={},u={};for(e in n)e in t?r[e]=Er(n[e],t[e]):u[e]=n[e];for(e in t)e in n||(u[e]=t[e]);return function(n){for(e in r)u[e]=r[e](n);return u}}function wr(n,t){return t-=n=+n,function(e){return n+t*e}}function Sr(n,t){var e,r,u,i,o,a=0,c=0,l=[],s=[];for(n+=\"\",t+=\"\",yc.lastIndex=0,r=0;e=yc.exec(t);++r)e.index&&l.push(t.substring(a,c=e.index)),s.push({i:l.length,x:e[0]}),l.push(null),a=yc.lastIndex;for(a<t.length&&l.push(t.substring(a)),r=0,i=s.length;(e=yc.exec(n))&&i>r;++r)if(o=s[r],o.x==e[0]){if(o.i)if(null==l[o.i+1])for(l[o.i-1]+=o.x,l.splice(o.i,1),u=r+1;i>u;++u)s[u].i--;else for(l[o.i-1]+=o.x+l[o.i+1],l.splice(o.i,2),u=r+1;i>u;++u)s[u].i-=2;else if(null==l[o.i+1])l[o.i]=o.x;else for(l[o.i]=o.x+l[o.i+1],l.splice(o.i+1,1),u=r+1;i>u;++u)s[u].i--;s.splice(r,1),i--,r--}else o.x=wr(parseFloat(e[0]),parseFloat(o.x));for(;i>r;)o=s.pop(),null==l[o.i+1]?l[o.i]=o.x:(l[o.i]=o.x+l[o.i+1],l.splice(o.i+1,1)),i--;return 1===l.length?null==l[0]?(o=s[0].x,function(n){return o(n)+\"\"}):function(){return t}:function(n){for(r=0;i>r;++r)l[(o=s[r]).i]=o.x(n);return l.join(\"\")}}function Er(n,t){for(var e,r=mo.interpolators.length;--r>=0&&!(e=mo.interpolators[r](n,t)););return e}function kr(n,t){var e,r=[],u=[],i=n.length,o=t.length,a=Math.min(n.length,t.length);for(e=0;a>e;++e)r.push(Er(n[e],t[e]));for(;i>e;++e)u[e]=n[e];for(;o>e;++e)u[e]=t[e];return function(n){for(e=0;a>e;++e)u[e]=r[e](n);return u}}function Ar(n){return function(t){return 0>=t?0:t>=1?1:n(t)}}function Nr(n){return function(t){return 1-n(1-t)}}function Tr(n){return function(t){return.5*(.5>t?n(2*t):2-n(2-2*t))}}function qr(n){return n*n}function zr(n){return n*n*n}function Cr(n){if(0>=n)return 0;if(n>=1)return 1;var t=n*n,e=t*n;return 4*(.5>n?e:3*(n-t)+e-.75)}function Dr(n){return function(t){return Math.pow(t,n)}}function jr(n){return 1-Math.cos(n*Bo/2)}function Lr(n){return Math.pow(2,10*(n-1))}function Hr(n){return 1-Math.sqrt(1-n*n)}function Fr(n,t){var e;return arguments.length<2&&(t=.45),arguments.length?e=t/(2*Bo)*Math.asin(1/n):(n=1,e=t/4),function(r){return 1+n*Math.pow(2,10*-r)*Math.sin(2*(r-e)*Bo/t)}}function Pr(n){return n||(n=1.70158),function(t){return t*t*((n+1)*t-n)}}function Or(n){return 1/2.75>n?7.5625*n*n:2/2.75>n?7.5625*(n-=1.5/2.75)*n+.75:2.5/2.75>n?7.5625*(n-=2.25/2.75)*n+.9375:7.5625*(n-=2.625/2.75)*n+.984375}function Rr(n,t){n=mo.hcl(n),t=mo.hcl(t);var e=n.h,r=n.c,u=n.l,i=t.h-e,o=t.c-r,a=t.l-u;return isNaN(o)&&(o=0,r=isNaN(r)?t.c:r),isNaN(i)?(i=0,e=isNaN(e)?t.h:e):i>180?i-=360:-180>i&&(i+=360),function(n){return J(e+i*n,r+o*n,u+a*n)+\"\"}}function Yr(n,t){n=mo.hsl(n),t=mo.hsl(t);var e=n.h,r=n.s,u=n.l,i=t.h-e,o=t.s-r,a=t.l-u;return isNaN(o)&&(o=0,r=isNaN(r)?t.s:r),isNaN(i)?(i=0,e=isNaN(e)?t.h:e):i>180?i-=360:-180>i&&(i+=360),function(n){return $(e+i*n,r+o*n,u+a*n)+\"\"}}function Ir(n,t){n=mo.lab(n),t=mo.lab(t);var e=n.l,r=n.a,u=n.b,i=t.l-e,o=t.a-r,a=t.b-u;return function(n){return Q(e+i*n,r+o*n,u+a*n)+\"\"}}function Ur(n,t){return t-=n,function(e){return Math.round(n+t*e)}}function Zr(n){var t=[n.a,n.b],e=[n.c,n.d],r=Xr(t),u=Vr(t,e),i=Xr($r(e,t,-u))||0;t[0]*e[1]<e[0]*t[1]&&(t[0]*=-1,t[1]*=-1,r*=-1,u*=-1),this.rotate=(r?Math.atan2(t[1],t[0]):Math.atan2(-e[0],e[1]))*Ko,this.translate=[n.e,n.f],this.scale=[r,i],this.skew=i?Math.atan2(u,i)*Ko:0}function Vr(n,t){return n[0]*t[0]+n[1]*t[1]}function Xr(n){var t=Math.sqrt(Vr(n,n));return t&&(n[0]/=t,n[1]/=t),t}function $r(n,t,e){return n[0]+=e*t[0],n[1]+=e*t[1],n}function Br(n,t){var e,r=[],u=[],i=mo.transform(n),o=mo.transform(t),a=i.translate,c=o.translate,l=i.rotate,s=o.rotate,f=i.skew,h=o.skew,g=i.scale,p=o.scale;return a[0]!=c[0]||a[1]!=c[1]?(r.push(\"translate(\",null,\",\",null,\")\"),u.push({i:1,x:wr(a[0],c[0])},{i:3,x:wr(a[1],c[1])})):c[0]||c[1]?r.push(\"translate(\"+c+\")\"):r.push(\"\"),l!=s?(l-s>180?s+=360:s-l>180&&(l+=360),u.push({i:r.push(r.pop()+\"rotate(\",null,\")\")-2,x:wr(l,s)})):s&&r.push(r.pop()+\"rotate(\"+s+\")\"),f!=h?u.push({i:r.push(r.pop()+\"skewX(\",null,\")\")-2,x:wr(f,h)}):h&&r.push(r.pop()+\"skewX(\"+h+\")\"),g[0]!=p[0]||g[1]!=p[1]?(e=r.push(r.pop()+\"scale(\",null,\",\",null,\")\"),u.push({i:e-4,x:wr(g[0],p[0])},{i:e-2,x:wr(g[1],p[1])})):(1!=p[0]||1!=p[1])&&r.push(r.pop()+\"scale(\"+p+\")\"),e=u.length,function(n){for(var t,i=-1;++i<e;)r[(t=u[i]).i]=t.x(n);return r.join(\"\")}}function Wr(n,t){return t=t-(n=+n)?1/(t-n):0,function(e){return(e-n)*t}}function Jr(n,t){return t=t-(n=+n)?1/(t-n):0,function(e){return Math.max(0,Math.min(1,(e-n)*t))}}function Gr(n){for(var t=n.source,e=n.target,r=Qr(t,e),u=[t];t!==r;)t=t.parent,u.push(t);for(var i=u.length;e!==r;)u.splice(i,0,e),e=e.parent;return u}function Kr(n){for(var t=[],e=n.parent;null!=e;)t.push(n),n=e,e=e.parent;return t.push(n),t}function Qr(n,t){if(n===t)return n;for(var e=Kr(n),r=Kr(t),u=e.pop(),i=r.pop(),o=null;u===i;)o=u,u=e.pop(),i=r.pop();return o}function nu(n){n.fixed|=2}function tu(n){n.fixed&=-7}function eu(n){n.fixed|=4,n.px=n.x,n.py=n.y}function ru(n){n.fixed&=-5}function uu(n,t,e){var r=0,u=0;if(n.charge=0,!n.leaf)for(var i,o=n.nodes,a=o.length,c=-1;++c<a;)i=o[c],null!=i&&(uu(i,t,e),n.charge+=i.charge,r+=i.charge*i.cx,u+=i.charge*i.cy);if(n.point){n.leaf||(n.point.x+=Math.random()-.5,n.point.y+=Math.random()-.5);var l=t*e[n.point.index];n.charge+=n.pointCharge=l,r+=l*n.point.x,u+=l*n.point.y}n.cx=r/n.charge,n.cy=u/n.charge}function iu(n,t){return mo.rebind(n,t,\"sort\",\"children\",\"value\"),n.nodes=n,n.links=lu,n}function ou(n){return n.children}function au(n){return n.value}function cu(n,t){return t.value-n.value}function lu(n){return mo.merge(n.map(function(n){return(n.children||[]).map(function(t){return{source:n,target:t}})}))}function su(n){return n.x}function fu(n){return n.y}function hu(n,t,e){n.y0=t,n.y=e}function gu(n){return mo.range(n.length)}function pu(n){for(var t=-1,e=n[0].length,r=[];++t<e;)r[t]=0;return r}function du(n){for(var t,e=1,r=0,u=n[0][1],i=n.length;i>e;++e)(t=n[e][1])>u&&(r=e,u=t);return r}function vu(n){return n.reduce(mu,0)}function mu(n,t){return n+t[1]}function yu(n,t){return Mu(n,Math.ceil(Math.log(t.length)/Math.LN2+1))}function Mu(n,t){for(var e=-1,r=+n[0],u=(n[1]-r)/t,i=[];++e<=t;)i[e]=u*e+r;return i}function xu(n){return[mo.min(n),mo.max(n)]}function bu(n,t){return n.parent==t.parent?1:2}function _u(n){var t=n.children;return t&&t.length?t[0]:n._tree.thread}function wu(n){var t,e=n.children;return e&&(t=e.length)?e[t-1]:n._tree.thread}function Su(n,t){var e=n.children;if(e&&(u=e.length))for(var r,u,i=-1;++i<u;)t(r=Su(e[i],t),n)>0&&(n=r);return n}function Eu(n,t){return n.x-t.x}function ku(n,t){return t.x-n.x}function Au(n,t){return n.depth-t.depth}function Nu(n,t){function e(n,r){var u=n.children;if(u&&(o=u.length))for(var i,o,a=null,c=-1;++c<o;)i=u[c],e(i,a),a=i;t(n,r)}e(n,null)}function Tu(n){for(var t,e=0,r=0,u=n.children,i=u.length;--i>=0;)t=u[i]._tree,t.prelim+=e,t.mod+=e,e+=t.shift+(r+=t.change)}function qu(n,t,e){n=n._tree,t=t._tree;var r=e/(t.number-n.number);n.change+=r,t.change-=r,t.shift+=e,t.prelim+=e,t.mod+=e}function zu(n,t,e){return n._tree.ancestor.parent==t.parent?n._tree.ancestor:e}function Cu(n,t){return n.value-t.value}function Du(n,t){var e=n._pack_next;n._pack_next=t,t._pack_prev=n,t._pack_next=e,e._pack_prev=t}function ju(n,t){n._pack_next=t,t._pack_prev=n}function Lu(n,t){var e=t.x-n.x,r=t.y-n.y,u=n.r+t.r;return.999*u*u>e*e+r*r}function Hu(n){function t(n){s=Math.min(n.x-n.r,s),f=Math.max(n.x+n.r,f),h=Math.min(n.y-n.r,h),g=Math.max(n.y+n.r,g)}if((e=n.children)&&(l=e.length)){var e,r,u,i,o,a,c,l,s=1/0,f=-1/0,h=1/0,g=-1/0;if(e.forEach(Fu),r=e[0],r.x=-r.r,r.y=0,t(r),l>1&&(u=e[1],u.x=u.r,u.y=0,t(u),l>2))for(i=e[2],Ru(r,u,i),t(i),Du(r,i),r._pack_prev=i,Du(i,u),u=r._pack_next,o=3;l>o;o++){Ru(r,u,i=e[o]);var p=0,d=1,v=1;for(a=u._pack_next;a!==u;a=a._pack_next,d++)if(Lu(a,i)){p=1;break}if(1==p)for(c=r._pack_prev;c!==a._pack_prev&&!Lu(c,i);c=c._pack_prev,v++);p?(v>d||d==v&&u.r<r.r?ju(r,u=a):ju(r=c,u),o--):(Du(r,i),u=i,t(i))}var m=(s+f)/2,y=(h+g)/2,M=0;for(o=0;l>o;o++)i=e[o],i.x-=m,i.y-=y,M=Math.max(M,i.r+Math.sqrt(i.x*i.x+i.y*i.y));n.r=M,e.forEach(Pu)}}function Fu(n){n._pack_next=n._pack_prev=n}function Pu(n){delete n._pack_next,delete n._pack_prev}function Ou(n,t,e,r){var u=n.children;if(n.x=t+=r*n.x,n.y=e+=r*n.y,n.r*=r,u)for(var i=-1,o=u.length;++i<o;)Ou(u[i],t,e,r)}function Ru(n,t,e){var r=n.r+e.r,u=t.x-n.x,i=t.y-n.y;if(r&&(u||i)){var o=t.r+e.r,a=u*u+i*i;o*=o,r*=r;var c=.5+(r-o)/(2*a),l=Math.sqrt(Math.max(0,2*o*(r+a)-(r-=a)*r-o*o))/(2*a);e.x=n.x+c*u+l*i,e.y=n.y+c*i-l*u}else e.x=n.x+r,e.y=n.y}function Yu(n){return 1+mo.max(n,function(n){return n.y})}function Iu(n){return n.reduce(function(n,t){return n+t.x},0)/n.length}function Uu(n){var t=n.children;return t&&t.length?Uu(t[0]):n}function Zu(n){var t,e=n.children;return e&&(t=e.length)?Zu(e[t-1]):n}function Vu(n){return{x:n.x,y:n.y,dx:n.dx,dy:n.dy}}function Xu(n,t){var e=n.x+t[3],r=n.y+t[0],u=n.dx-t[1]-t[3],i=n.dy-t[0]-t[2];return 0>u&&(e+=u/2,u=0),0>i&&(r+=i/2,i=0),{x:e,y:r,dx:u,dy:i}}function $u(n){var t=n[0],e=n[n.length-1];return e>t?[t,e]:[e,t]}function Bu(n){return n.rangeExtent?n.rangeExtent():$u(n.range())}function Wu(n,t,e,r){var u=e(n[0],n[1]),i=r(t[0],t[1]);return function(n){return i(u(n))}}function Ju(n,t){var e,r=0,u=n.length-1,i=n[r],o=n[u];return i>o&&(e=r,r=u,u=e,e=i,i=o,o=e),n[r]=t.floor(i),n[u]=t.ceil(o),n}function Gu(n){return n?{floor:function(t){return Math.floor(t/n)*n},ceil:function(t){return Math.ceil(t/n)*n}}:Nc}function Ku(n,t,e,r){var u=[],i=[],o=0,a=Math.min(n.length,t.length)-1;for(n[a]<n[0]&&(n=n.slice().reverse(),t=t.slice().reverse());++o<=a;)u.push(e(n[o-1],n[o])),i.push(r(t[o-1],t[o]));return function(t){var e=mo.bisect(n,t,1,a)-1;return i[e](u[e](t))}}function Qu(n,t,e,r){function u(){var u=Math.min(n.length,t.length)>2?Ku:Wu,c=r?Jr:Wr;return o=u(n,t,c,e),a=u(t,n,c,Er),i}function i(n){return o(n)}var o,a;return i.invert=function(n){return a(n)},i.domain=function(t){return arguments.length?(n=t.map(Number),u()):n},i.range=function(n){return arguments.length?(t=n,u()):t},i.rangeRound=function(n){return i.range(n).interpolate(Ur)},i.clamp=function(n){return arguments.length?(r=n,u()):r},i.interpolate=function(n){return arguments.length?(e=n,u()):e},i.ticks=function(t){return ri(n,t)},i.tickFormat=function(t,e){return ui(n,t,e)},i.nice=function(t){return ti(n,t),u()},i.copy=function(){return Qu(n,t,e,r)},u()}function ni(n,t){return mo.rebind(n,t,\"range\",\"rangeRound\",\"interpolate\",\"clamp\")}function ti(n,t){return Ju(n,Gu(ei(n,t)[2]))}function ei(n,t){null==t&&(t=10);var e=$u(n),r=e[1]-e[0],u=Math.pow(10,Math.floor(Math.log(r/t)/Math.LN10)),i=t/r*u;return.15>=i?u*=10:.35>=i?u*=5:.75>=i&&(u*=2),e[0]=Math.ceil(e[0]/u)*u,e[1]=Math.floor(e[1]/u)*u+.5*u,e[2]=u,e}function ri(n,t){return mo.range.apply(mo,ei(n,t))}function ui(n,t,e){var r=-Math.floor(Math.log(ei(n,t)[2])/Math.LN10+.01);return mo.format(e?e.replace(Ea,function(n,t,e,u,i,o,a,c,l,s){return[t,e,u,i,o,a,c,l||\".\"+(r-2*(\"%\"===s)),s].join(\"\")}):\",.\"+r+\"f\")}function ii(n,t,e,r){function u(n){return(e?Math.log(0>n?0:n):-Math.log(n>0?0:-n))/Math.log(t)}function i(n){return e?Math.pow(t,n):-Math.pow(t,-n)}function o(t){return n(u(t))}return o.invert=function(t){return i(n.invert(t))},o.domain=function(t){return arguments.length?(e=t[0]>=0,n.domain((r=t.map(Number)).map(u)),o):r},o.base=function(e){return arguments.length?(t=+e,n.domain(r.map(u)),o):t},o.nice=function(){var t=Ju(r.map(u),e?Math:qc);return n.domain(t),r=t.map(i),o},o.ticks=function(){var n=$u(r),o=[],a=n[0],c=n[1],l=Math.floor(u(a)),s=Math.ceil(u(c)),f=t%1?2:t;if(isFinite(s-l)){if(e){for(;s>l;l++)for(var h=1;f>h;h++)o.push(i(l)*h);o.push(i(l))}else for(o.push(i(l));l++<s;)for(var h=f-1;h>0;h--)o.push(i(l)*h);for(l=0;o[l]<a;l++);for(s=o.length;o[s-1]>c;s--);o=o.slice(l,s)}return o},o.tickFormat=function(n,t){if(!arguments.length)return Tc;arguments.length<2?t=Tc:\"function\"!=typeof t&&(t=mo.format(t));var r,a=Math.max(.1,n/o.ticks().length),c=e?(r=1e-12,Math.ceil):(r=-1e-12,Math.floor);return function(n){return n/i(c(u(n)+r))<=a?t(n):\"\"}},o.copy=function(){return ii(n.copy(),t,e,r)},ni(o,n)}function oi(n,t,e){function r(t){return n(u(t))}var u=ai(t),i=ai(1/t);return r.invert=function(t){return i(n.invert(t))},r.domain=function(t){return arguments.length?(n.domain((e=t.map(Number)).map(u)),r):e},r.ticks=function(n){return ri(e,n)},r.tickFormat=function(n,t){return ui(e,n,t)},r.nice=function(n){return r.domain(ti(e,n))},r.exponent=function(o){return arguments.length?(u=ai(t=o),i=ai(1/t),n.domain(e.map(u)),r):t},r.copy=function(){return oi(n.copy(),t,e)},ni(r,n)}function ai(n){return function(t){return 0>t?-Math.pow(-t,n):Math.pow(t,n)}}function ci(n,t){function e(t){return o[((i.get(t)||i.set(t,n.push(t)))-1)%o.length]}function r(t,e){return mo.range(n.length).map(function(n){return t+e*n})}var i,o,a;return e.domain=function(r){if(!arguments.length)return n;n=[],i=new u;for(var o,a=-1,c=r.length;++a<c;)i.has(o=r[a])||i.set(o,n.push(o));return e[t.t].apply(e,t.a)},e.range=function(n){return arguments.length?(o=n,a=0,t={t:\"range\",a:arguments},e):o},e.rangePoints=function(u,i){arguments.length<2&&(i=0);var c=u[0],l=u[1],s=(l-c)/(Math.max(1,n.length-1)+i);return o=r(n.length<2?(c+l)/2:c+s*i/2,s),a=0,t={t:\"rangePoints\",a:arguments},e},e.rangeBands=function(u,i,c){arguments.length<2&&(i=0),arguments.length<3&&(c=i);var l=u[1]<u[0],s=u[l-0],f=u[1-l],h=(f-s)/(n.length-i+2*c);return o=r(s+h*c,h),l&&o.reverse(),a=h*(1-i),t={t:\"rangeBands\",a:arguments},e},e.rangeRoundBands=function(u,i,c){arguments.length<2&&(i=0),arguments.length<3&&(c=i);var l=u[1]<u[0],s=u[l-0],f=u[1-l],h=Math.floor((f-s)/(n.length-i+2*c)),g=f-s-(n.length-i)*h;return o=r(s+Math.round(g/2),h),l&&o.reverse(),a=Math.round(h*(1-i)),t={t:\"rangeRoundBands\",a:arguments},e},e.rangeBand=function(){return a},e.rangeExtent=function(){return $u(t.a[0])},e.copy=function(){return ci(n,t)},e.domain(n)}function li(n,t){function e(){var e=0,i=t.length;for(u=[];++e<i;)u[e-1]=mo.quantile(n,e/i);return r}function r(n){return isNaN(n=+n)?void 0:t[mo.bisect(u,n)]}var u;return r.domain=function(t){return arguments.length?(n=t.filter(function(n){return!isNaN(n)}).sort(mo.ascending),e()):n},r.range=function(n){return arguments.length?(t=n,e()):t},r.quantiles=function(){return u},r.invertExtent=function(e){return e=t.indexOf(e),0>e?[0/0,0/0]:[e>0?u[e-1]:n[0],e<u.length?u[e]:n[n.length-1]]},r.copy=function(){return li(n,t)},e()}function si(n,t,e){function r(t){return e[Math.max(0,Math.min(o,Math.floor(i*(t-n))))]}function u(){return i=e.length/(t-n),o=e.length-1,r}var i,o;return r.domain=function(e){return arguments.length?(n=+e[0],t=+e[e.length-1],u()):[n,t]},r.range=function(n){return arguments.length?(e=n,u()):e},r.invertExtent=function(t){return t=e.indexOf(t),t=0>t?0/0:t/i+n,[t,t+1/i]},r.copy=function(){return si(n,t,e)},u()}function fi(n,t){function e(e){return e>=e?t[mo.bisect(n,e)]:void 0}return e.domain=function(t){return arguments.length?(n=t,e):n},e.range=function(n){return arguments.length?(t=n,e):t},e.invertExtent=function(e){return e=t.indexOf(e),[n[e-1],n[e]]},e.copy=function(){return fi(n,t)},e}function hi(n){function t(n){return+n}return t.invert=t,t.domain=t.range=function(e){return arguments.length?(n=e.map(t),t):n},t.ticks=function(t){return ri(n,t)},t.tickFormat=function(t,e){return ui(n,t,e)},t.copy=function(){return hi(n)},t}function gi(n){return n.innerRadius}function pi(n){return n.outerRadius}function di(n){return n.startAngle}function vi(n){return n.endAngle}function mi(n){for(var t,e,r,u=-1,i=n.length;++u<i;)t=n[u],e=t[0],r=t[1]+Lc,t[0]=e*Math.cos(r),t[1]=e*Math.sin(r);return n}function yi(n){function t(t){function c(){d.push(\"M\",a(n(m),f),s,l(n(v.reverse()),f),\"Z\")}for(var h,g,p,d=[],v=[],m=[],y=-1,M=t.length,x=pt(e),b=pt(u),_=e===r?function(){return g}:pt(r),w=u===i?function(){return p}:pt(i);++y<M;)o.call(this,h=t[y],y)?(v.push([g=+x.call(this,h,y),p=+b.call(this,h,y)]),m.push([+_.call(this,h,y),+w.call(this,h,y)])):v.length&&(c(),v=[],m=[]);return v.length&&c(),d.length?d.join(\"\"):null}var e=Ze,r=Ze,u=0,i=Ve,o=Vt,a=Xe,c=a.key,l=a,s=\"L\",f=.7;return t.x=function(n){return arguments.length?(e=r=n,t):r},t.x0=function(n){return arguments.length?(e=n,t):e},t.x1=function(n){return arguments.length?(r=n,t):r},t.y=function(n){return arguments.length?(u=i=n,t):i},t.y0=function(n){return arguments.length?(u=n,t):u},t.y1=function(n){return arguments.length?(i=n,t):i},t.defined=function(n){return arguments.length?(o=n,t):o},t.interpolate=function(n){return arguments.length?(c=\"function\"==typeof n?a=n:(a=hc.get(n)||Xe).key,l=a.reverse||a,s=a.closed?\"M\":\"L\",t):c},t.tension=function(n){return arguments.length?(f=n,t):f},t}function Mi(n){return n.radius}function xi(n){return[n.x,n.y]}function bi(n){return function(){var t=n.apply(this,arguments),e=t[0],r=t[1]+Lc;return[e*Math.cos(r),e*Math.sin(r)]}}function _i(){return 64}function wi(){return\"circle\"}function Si(n){var t=Math.sqrt(n/Bo);return\"M0,\"+t+\"A\"+t+\",\"+t+\" 0 1,1 0,\"+-t+\"A\"+t+\",\"+t+\" 0 1,1 0,\"+t+\"Z\"}function Ei(n,t){return Lo(n,Ic),n.id=t,n}function ki(n,t,e,r){var u=n.id;return N(n,\"function\"==typeof e?function(n,i,o){n.__transition__[u].tween.set(t,r(e.call(n,n.__data__,i,o)))}:(e=r(e),function(n){n.__transition__[u].tween.set(t,e)}))}function Ai(n){return null==n&&(n=\"\"),function(){this.textContent=n}}function Ni(n,t,e,r){var i=n.__transition__||(n.__transition__={active:0,count:0}),o=i[e];if(!o){var a=r.time;o=i[e]={tween:new u,time:a,ease:r.ease,delay:r.delay,duration:r.duration},++i.count,mo.timer(function(r){function u(r){return i.active>e?l():(i.active=e,o.event&&o.event.start.call(n,s,t),o.tween.forEach(function(e,r){(r=r.call(n,s,t))&&p.push(r)}),c(r)?1:(xt(c,0,a),void 0))}function c(r){if(i.active!==e)return l();for(var u=(r-h)/g,a=f(u),c=p.length;c>0;)p[--c].call(n,a);return u>=1?(o.event&&o.event.end.call(n,s,t),l()):void 0}function l(){return--i.count?delete i[e]:delete n.__transition__,1}var s=n.__data__,f=o.ease,h=o.delay,g=o.duration,p=[];return r>=h?u(r):(xt(u,h,a),void 0)},0,a)}}function Ti(n,t){n.attr(\"transform\",function(n){return\"translate(\"+t(n)+\",0)\"})}function qi(n,t){n.attr(\"transform\",function(n){return\"translate(0,\"+t(n)+\")\"})}function zi(){this._=new Date(arguments.length>1?Date.UTC.apply(this,arguments):arguments[0])}function Ci(n,t,e){function r(t){var e=n(t),r=i(e,1);return r-t>t-e?e:r}function u(e){return t(e=n(new Wc(e-1)),1),e}function i(n,e){return t(n=new Wc(+n),e),n}function o(n,r,i){var o=u(n),a=[];if(i>1)for(;r>o;)e(o)%i||a.push(new Date(+o)),t(o,1);else for(;r>o;)a.push(new Date(+o)),t(o,1);return a}function a(n,t,e){try{Wc=zi;var r=new zi;return r._=n,o(r,t,e)}finally{Wc=Date}}n.floor=n,n.round=r,n.ceil=u,n.offset=i,n.range=o;var c=n.utc=Di(n);return c.floor=c,c.round=Di(r),c.ceil=Di(u),c.offset=Di(i),c.range=a,n}function Di(n){return function(t,e){try{Wc=zi;var r=new zi;return r._=t,n(r,e)._}finally{Wc=Date}}}function ji(n){function t(t){for(var r,u,i,o=[],a=-1,c=0;++a<e;)37===n.charCodeAt(a)&&(o.push(n.substring(c,a)),null!=(u=pl[r=n.charAt(++a)])&&(r=n.charAt(++a)),(i=dl[r])&&(r=i(t,null==u?\"e\"===r?\" \":\"0\":u)),o.push(r),c=a+1);return o.push(n.substring(c,a)),o.join(\"\")}var e=n.length;return t.parse=function(t){var e={y:1900,m:0,d:1,H:0,M:0,S:0,L:0,Z:null},r=Li(e,n,t,0);if(r!=t.length)return null;\"p\"in e&&(e.H=e.H%12+12*e.p);var u=null!=e.Z&&Wc!==zi,i=new(u?zi:Wc);return\"j\"in e?i.setFullYear(e.y,0,e.j):\"w\"in e&&(\"W\"in e||\"U\"in e)?(i.setFullYear(e.y,0,1),i.setFullYear(e.y,0,\"W\"in e?(e.w+6)%7+7*e.W-(i.getDay()+5)%7:e.w+7*e.U-(i.getDay()+6)%7)):i.setFullYear(e.y,e.m,e.d),i.setHours(e.H+Math.floor(e.Z/100),e.M+e.Z%100,e.S,e.L),u?i._:i},t.toString=function(){return n},t}function Li(n,t,e,r){for(var u,i,o,a=0,c=t.length,l=e.length;c>a;){if(r>=l)return-1;if(u=t.charCodeAt(a++),37===u){if(o=t.charAt(a++),i=vl[o in pl?t.charAt(a++):o],!i||(r=i(n,e,r))<0)return-1}else if(u!=e.charCodeAt(r++))return-1}return r}function Hi(n){return new RegExp(\"^(?:\"+n.map(mo.requote).join(\"|\")+\")\",\"i\")}function Fi(n){for(var t=new u,e=-1,r=n.length;++e<r;)t.set(n[e].toLowerCase(),e);return t}function Pi(n,t,e){var r=0>n?\"-\":\"\",u=(r?-n:n)+\"\",i=u.length;return r+(e>i?new Array(e-i+1).join(t)+u:u)}function Oi(n,t,e){al.lastIndex=0;var r=al.exec(t.substring(e));return r?(n.w=cl.get(r[0].toLowerCase()),e+r[0].length):-1}function Ri(n,t,e){il.lastIndex=0;var r=il.exec(t.substring(e));return r?(n.w=ol.get(r[0].toLowerCase()),e+r[0].length):-1}function Yi(n,t,e){ml.lastIndex=0;var r=ml.exec(t.substring(e,e+1));return r?(n.w=+r[0],e+r[0].length):-1}function Ii(n,t,e){ml.lastIndex=0;var r=ml.exec(t.substring(e));return r?(n.U=+r[0],e+r[0].length):-1}function Ui(n,t,e){ml.lastIndex=0;var r=ml.exec(t.substring(e));return r?(n.W=+r[0],e+r[0].length):-1}function Zi(n,t,e){fl.lastIndex=0;var r=fl.exec(t.substring(e));return r?(n.m=hl.get(r[0].toLowerCase()),e+r[0].length):-1}function Vi(n,t,e){ll.lastIndex=0;var r=ll.exec(t.substring(e));return r?(n.m=sl.get(r[0].toLowerCase()),e+r[0].length):-1}function Xi(n,t,e){return Li(n,dl.c.toString(),t,e)}function $i(n,t,e){return Li(n,dl.x.toString(),t,e)}function Bi(n,t,e){return Li(n,dl.X.toString(),t,e)}function Wi(n,t,e){ml.lastIndex=0;var r=ml.exec(t.substring(e,e+4));return r?(n.y=+r[0],e+r[0].length):-1}function Ji(n,t,e){ml.lastIndex=0;var r=ml.exec(t.substring(e,e+2));return r?(n.y=Ki(+r[0]),e+r[0].length):-1}function Gi(n,t,e){return/^[+-]\\d{4}$/.test(t=t.substring(e,e+5))?(n.Z=+t,e+5):-1}function Ki(n){return n+(n>68?1900:2e3)}function Qi(n,t,e){ml.lastIndex=0;var r=ml.exec(t.substring(e,e+2));return r?(n.m=r[0]-1,e+r[0].length):-1}function no(n,t,e){ml.lastIndex=0;var r=ml.exec(t.substring(e,e+2));return r?(n.d=+r[0],e+r[0].length):-1}function to(n,t,e){ml.lastIndex=0;var r=ml.exec(t.substring(e,e+3));return r?(n.j=+r[0],e+r[0].length):-1}function eo(n,t,e){ml.lastIndex=0;var r=ml.exec(t.substring(e,e+2));return r?(n.H=+r[0],e+r[0].length):-1}function ro(n,t,e){ml.lastIndex=0;var r=ml.exec(t.substring(e,e+2));return r?(n.M=+r[0],e+r[0].length):-1}function uo(n,t,e){ml.lastIndex=0;var r=ml.exec(t.substring(e,e+2));return r?(n.S=+r[0],e+r[0].length):-1}function io(n,t,e){ml.lastIndex=0;var r=ml.exec(t.substring(e,e+3));return r?(n.L=+r[0],e+r[0].length):-1}function oo(n,t,e){var r=yl.get(t.substring(e,e+=2).toLowerCase());return null==r?-1:(n.p=r,e)}function ao(n){var t=n.getTimezoneOffset(),e=t>0?\"-\":\"+\",r=~~(Math.abs(t)/60),u=Math.abs(t)%60;return e+Pi(r,\"0\",2)+Pi(u,\"0\",2)}function co(n,t,e){gl.lastIndex=0;var r=gl.exec(t.substring(e,e+1));return r?e+r[0].length:-1}function lo(n){function t(n){try{Wc=zi;var t=new Wc;return t._=n,e(t)}finally{Wc=Date}}var e=ji(n);return t.parse=function(n){try{Wc=zi;var t=e.parse(n);return t&&t._}finally{Wc=Date}},t.toString=e.toString,t}function so(n){return n.toISOString()}function fo(n,t,e){function r(t){return n(t)}function u(n,e){var r=n[1]-n[0],u=r/e,i=mo.bisect(xl,u);return i==xl.length?[t.year,ei(n.map(function(n){return n/31536e6}),e)[2]]:i?t[u/xl[i-1]<xl[i]/u?i-1:i]:[Sl,ei(n,e)[2]]}return r.invert=function(t){return ho(n.invert(t))},r.domain=function(t){return arguments.length?(n.domain(t),r):n.domain().map(ho)},r.nice=function(n,t){function e(e){return!isNaN(e)&&!n.range(e,ho(+e+1),t).length}var i=r.domain(),o=$u(i),a=null==n?u(o,10):\"number\"==typeof n&&u(o,n);return a&&(n=a[0],t=a[1]),r.domain(Ju(i,t>1?{floor:function(t){for(;e(t=n.floor(t));)t=ho(t-1);return t},ceil:function(t){for(;e(t=n.ceil(t));)t=ho(+t+1);return t}}:n))},r.ticks=function(n,t){var e=$u(r.domain()),i=null==n?u(e,10):\"number\"==typeof n?u(e,n):!n.range&&[{range:n},t];return i&&(n=i[0],t=i[1]),n.range(e[0],ho(+e[1]+1),t)},r.tickFormat=function(){return e},r.copy=function(){return fo(n.copy(),t,e)},ni(r,n)}function ho(n){return new Date(n)}function go(n){return function(t){for(var e=n.length-1,r=n[e];!r[1](t);)r=n[--e];return r[0](t)}}function po(n){return JSON.parse(n.responseText)}function vo(n){var t=xo.createRange();return t.selectNode(xo.body),t.createContextualFragment(n.responseText)}var mo={version:\"3.3.3\"};Date.now||(Date.now=function(){return+new Date});var yo=[].slice,Mo=function(n){return yo.call(n)},xo=document,bo=xo.documentElement,_o=window;try{Mo(bo.childNodes)[0].nodeType}catch(wo){Mo=function(n){for(var t=n.length,e=new Array(t);t--;)e[t]=n[t];return e}}try{xo.createElement(\"div\").style.setProperty(\"opacity\",0,\"\")}catch(So){var Eo=_o.Element.prototype,ko=Eo.setAttribute,Ao=Eo.setAttributeNS,No=_o.CSSStyleDeclaration.prototype,To=No.setProperty;Eo.setAttribute=function(n,t){ko.call(this,n,t+\"\")},Eo.setAttributeNS=function(n,t,e){Ao.call(this,n,t,e+\"\")},No.setProperty=function(n,t,e){To.call(this,n,t+\"\",e)}}mo.ascending=function(n,t){return t>n?-1:n>t?1:n>=t?0:0/0},mo.descending=function(n,t){return n>t?-1:t>n?1:t>=n?0:0/0},mo.min=function(n,t){var e,r,u=-1,i=n.length;if(1===arguments.length){for(;++u<i&&!(null!=(e=n[u])&&e>=e);)e=void 0;for(;++u<i;)null!=(r=n[u])&&e>r&&(e=r)}else{for(;++u<i&&!(null!=(e=t.call(n,n[u],u))&&e>=e);)e=void 0;for(;++u<i;)null!=(r=t.call(n,n[u],u))&&e>r&&(e=r)}return e},mo.max=function(n,t){var e,r,u=-1,i=n.length;if(1===arguments.length){for(;++u<i&&!(null!=(e=n[u])&&e>=e);)e=void 0;for(;++u<i;)null!=(r=n[u])&&r>e&&(e=r)}else{for(;++u<i&&!(null!=(e=t.call(n,n[u],u))&&e>=e);)e=void 0;for(;++u<i;)null!=(r=t.call(n,n[u],u))&&r>e&&(e=r)}return e},mo.extent=function(n,t){var e,r,u,i=-1,o=n.length;if(1===arguments.length){for(;++i<o&&!(null!=(e=u=n[i])&&e>=e);)e=u=void 0;for(;++i<o;)null!=(r=n[i])&&(e>r&&(e=r),r>u&&(u=r))}else{for(;++i<o&&!(null!=(e=u=t.call(n,n[i],i))&&e>=e);)e=void 0;for(;++i<o;)null!=(r=t.call(n,n[i],i))&&(e>r&&(e=r),r>u&&(u=r))}return[e,u]},mo.sum=function(n,t){var e,r=0,u=n.length,i=-1;if(1===arguments.length)for(;++i<u;)isNaN(e=+n[i])||(r+=e);else for(;++i<u;)isNaN(e=+t.call(n,n[i],i))||(r+=e);return r},mo.mean=function(t,e){var r,u=t.length,i=0,o=-1,a=0;if(1===arguments.length)for(;++o<u;)n(r=t[o])&&(i+=(r-i)/++a);else for(;++o<u;)n(r=e.call(t,t[o],o))&&(i+=(r-i)/++a);return a?i:void 0},mo.quantile=function(n,t){var e=(n.length-1)*t+1,r=Math.floor(e),u=+n[r-1],i=e-r;return i?u+i*(n[r]-u):u},mo.median=function(t,e){return arguments.length>1&&(t=t.map(e)),t=t.filter(n),t.length?mo.quantile(t.sort(mo.ascending),.5):void 0},mo.bisector=function(n){return{left:function(t,e,r,u){for(arguments.length<3&&(r=0),arguments.length<4&&(u=t.length);u>r;){var i=r+u>>>1;n.call(t,t[i],i)<e?r=i+1:u=i}return r},right:function(t,e,r,u){for(arguments.length<3&&(r=0),arguments.length<4&&(u=t.length);u>r;){var i=r+u>>>1;e<n.call(t,t[i],i)?u=i:r=i+1}return r}}};var qo=mo.bisector(function(n){return n});mo.bisectLeft=qo.left,mo.bisect=mo.bisectRight=qo.right,mo.shuffle=function(n){for(var t,e,r=n.length;r;)e=0|Math.random()*r--,t=n[r],n[r]=n[e],n[e]=t;return n},mo.permute=function(n,t){for(var e=t.length,r=new Array(e);e--;)r[e]=n[t[e]];return r},mo.pairs=function(n){for(var t,e=0,r=n.length-1,u=n[0],i=new Array(0>r?0:r);r>e;)i[e]=[t=u,u=n[++e]];return i},mo.zip=function(){if(!(u=arguments.length))return[];for(var n=-1,e=mo.min(arguments,t),r=new Array(e);++n<e;)for(var u,i=-1,o=r[n]=new Array(u);++i<u;)o[i]=arguments[i][n];return r},mo.transpose=function(n){return mo.zip.apply(mo,n)},mo.keys=function(n){var t=[];for(var e in n)t.push(e);return t},mo.values=function(n){var t=[];for(var e in n)t.push(n[e]);return t},mo.entries=function(n){var t=[];\n            for(var e in n)t.push({key:e,value:n[e]});return t},mo.merge=function(n){return Array.prototype.concat.apply([],n)},mo.range=function(n,t,r){if(arguments.length<3&&(r=1,arguments.length<2&&(t=n,n=0)),1/0===(t-n)/r)throw new Error(\"infinite range\");var u,i=[],o=e(Math.abs(r)),a=-1;if(n*=o,t*=o,r*=o,0>r)for(;(u=n+r*++a)>t;)i.push(u/o);else for(;(u=n+r*++a)<t;)i.push(u/o);return i},mo.map=function(n){var t=new u;if(n instanceof u)n.forEach(function(n,e){t.set(n,e)});else for(var e in n)t.set(e,n[e]);return t},r(u,{has:function(n){return zo+n in this},get:function(n){return this[zo+n]},set:function(n,t){return this[zo+n]=t},remove:function(n){return n=zo+n,n in this&&delete this[n]},keys:function(){var n=[];return this.forEach(function(t){n.push(t)}),n},values:function(){var n=[];return this.forEach(function(t,e){n.push(e)}),n},entries:function(){var n=[];return this.forEach(function(t,e){n.push({key:t,value:e})}),n},forEach:function(n){for(var t in this)t.charCodeAt(0)===Co&&n.call(this,t.substring(1),this[t])}});var zo=\"\\0\",Co=zo.charCodeAt(0);mo.nest=function(){function n(t,a,c){if(c>=o.length)return r?r.call(i,a):e?a.sort(e):a;for(var l,s,f,h,g=-1,p=a.length,d=o[c++],v=new u;++g<p;)(h=v.get(l=d(s=a[g])))?h.push(s):v.set(l,[s]);return t?(s=t(),f=function(e,r){s.set(e,n(t,r,c))}):(s={},f=function(e,r){s[e]=n(t,r,c)}),v.forEach(f),s}function t(n,e){if(e>=o.length)return n;var r=[],u=a[e++];return n.forEach(function(n,u){r.push({key:n,values:t(u,e)})}),u?r.sort(function(n,t){return u(n.key,t.key)}):r}var e,r,i={},o=[],a=[];return i.map=function(t,e){return n(e,t,0)},i.entries=function(e){return t(n(mo.map,e,0),0)},i.key=function(n){return o.push(n),i},i.sortKeys=function(n){return a[o.length-1]=n,i},i.sortValues=function(n){return e=n,i},i.rollup=function(n){return r=n,i},i},mo.set=function(n){var t=new i;if(n)for(var e=0,r=n.length;r>e;++e)t.add(n[e]);return t},r(i,{has:function(n){return zo+n in this},add:function(n){return this[zo+n]=!0,n},remove:function(n){return n=zo+n,n in this&&delete this[n]},values:function(){var n=[];return this.forEach(function(t){n.push(t)}),n},forEach:function(n){for(var t in this)t.charCodeAt(0)===Co&&n.call(this,t.substring(1))}}),mo.behavior={},mo.rebind=function(n,t){for(var e,r=1,u=arguments.length;++r<u;)n[e=arguments[r]]=o(n,t,t[e]);return n};var Do=[\"webkit\",\"ms\",\"moz\",\"Moz\",\"o\",\"O\"];mo.dispatch=function(){for(var n=new l,t=-1,e=arguments.length;++t<e;)n[arguments[t]]=s(n);return n},l.prototype.on=function(n,t){var e=n.indexOf(\".\"),r=\"\";if(e>=0&&(r=n.substring(e+1),n=n.substring(0,e)),n)return arguments.length<2?this[n].on(r):this[n].on(r,t);if(2===arguments.length){if(null==t)for(n in this)this.hasOwnProperty(n)&&this[n].on(r,null);return this}},mo.event=null,mo.requote=function(n){return n.replace(jo,\"\\\\$&\")};var jo=/[\\\\\\^\\$\\*\\+\\?\\|\\[\\]\\(\\)\\.\\{\\}]/g,Lo={}.__proto__?function(n,t){n.__proto__=t}:function(n,t){for(var e in t)n[e]=t[e]},Ho=function(n,t){return t.querySelector(n)},Fo=function(n,t){return t.querySelectorAll(n)},Po=bo[a(bo,\"matchesSelector\")],Oo=function(n,t){return Po.call(n,t)};\"function\"==typeof Sizzle&&(Ho=function(n,t){return Sizzle(n,t)[0]||null},Fo=function(n,t){return Sizzle.uniqueSort(Sizzle(n,t))},Oo=Sizzle.matchesSelector),mo.selection=function(){return Uo};var Ro=mo.selection.prototype=[];Ro.select=function(n){var t,e,r,u,i=[];n=d(n);for(var o=-1,a=this.length;++o<a;){i.push(t=[]),t.parentNode=(r=this[o]).parentNode;for(var c=-1,l=r.length;++c<l;)(u=r[c])?(t.push(e=n.call(u,u.__data__,c,o)),e&&\"__data__\"in u&&(e.__data__=u.__data__)):t.push(null)}return p(i)},Ro.selectAll=function(n){var t,e,r=[];n=v(n);for(var u=-1,i=this.length;++u<i;)for(var o=this[u],a=-1,c=o.length;++a<c;)(e=o[a])&&(r.push(t=Mo(n.call(e,e.__data__,a,u))),t.parentNode=e);return p(r)};var Yo={svg:\"http://www.w3.org/2000/svg\",xhtml:\"http://www.w3.org/1999/xhtml\",xlink:\"http://www.w3.org/1999/xlink\",xml:\"http://www.w3.org/XML/1998/namespace\",xmlns:\"http://www.w3.org/2000/xmlns/\"};mo.ns={prefix:Yo,qualify:function(n){var t=n.indexOf(\":\"),e=n;return t>=0&&(e=n.substring(0,t),n=n.substring(t+1)),Yo.hasOwnProperty(e)?{space:Yo[e],local:n}:n}},Ro.attr=function(n,t){if(arguments.length<2){if(\"string\"==typeof n){var e=this.node();return n=mo.ns.qualify(n),n.local?e.getAttributeNS(n.space,n.local):e.getAttribute(n)}for(t in n)this.each(m(t,n[t]));return this}return this.each(m(n,t))},Ro.classed=function(n,t){if(arguments.length<2){if(\"string\"==typeof n){var e=this.node(),r=(n=n.trim().split(/^|\\s+/g)).length,u=-1;if(t=e.classList){for(;++u<r;)if(!t.contains(n[u]))return!1}else for(t=e.getAttribute(\"class\");++u<r;)if(!M(n[u]).test(t))return!1;return!0}for(t in n)this.each(x(t,n[t]));return this}return this.each(x(n,t))},Ro.style=function(n,t,e){var r=arguments.length;if(3>r){if(\"string\"!=typeof n){2>r&&(t=\"\");for(e in n)this.each(_(e,n[e],t));return this}if(2>r)return _o.getComputedStyle(this.node(),null).getPropertyValue(n);e=\"\"}return this.each(_(n,t,e))},Ro.property=function(n,t){if(arguments.length<2){if(\"string\"==typeof n)return this.node()[n];for(t in n)this.each(w(t,n[t]));return this}return this.each(w(n,t))},Ro.text=function(n){return arguments.length?this.each(\"function\"==typeof n?function(){var t=n.apply(this,arguments);this.textContent=null==t?\"\":t}:null==n?function(){this.textContent=\"\"}:function(){this.textContent=n}):this.node().textContent},Ro.html=function(n){return arguments.length?this.each(\"function\"==typeof n?function(){var t=n.apply(this,arguments);this.innerHTML=null==t?\"\":t}:null==n?function(){this.innerHTML=\"\"}:function(){this.innerHTML=n}):this.node().innerHTML},Ro.append=function(n){return n=S(n),this.select(function(){return this.appendChild(n.apply(this,arguments))})},Ro.insert=function(n,t){return n=S(n),t=d(t),this.select(function(){return this.insertBefore(n.apply(this,arguments),t.apply(this,arguments))})},Ro.remove=function(){return this.each(function(){var n=this.parentNode;n&&n.removeChild(this)})},Ro.data=function(n,t){function e(n,e){var r,i,o,a=n.length,f=e.length,h=Math.min(a,f),g=new Array(f),p=new Array(f),d=new Array(a);if(t){var v,m=new u,y=new u,M=[];for(r=-1;++r<a;)v=t.call(i=n[r],i.__data__,r),m.has(v)?d[r]=i:m.set(v,i),M.push(v);for(r=-1;++r<f;)v=t.call(e,o=e[r],r),(i=m.get(v))?(g[r]=i,i.__data__=o):y.has(v)||(p[r]=E(o)),y.set(v,o),m.remove(v);for(r=-1;++r<a;)m.has(M[r])&&(d[r]=n[r])}else{for(r=-1;++r<h;)i=n[r],o=e[r],i?(i.__data__=o,g[r]=i):p[r]=E(o);for(;f>r;++r)p[r]=E(e[r]);for(;a>r;++r)d[r]=n[r]}p.update=g,p.parentNode=g.parentNode=d.parentNode=n.parentNode,c.push(p),l.push(g),s.push(d)}var r,i,o=-1,a=this.length;if(!arguments.length){for(n=new Array(a=(r=this[0]).length);++o<a;)(i=r[o])&&(n[o]=i.__data__);return n}var c=T([]),l=p([]),s=p([]);if(\"function\"==typeof n)for(;++o<a;)e(r=this[o],n.call(r,r.parentNode.__data__,o));else for(;++o<a;)e(r=this[o],n);return l.enter=function(){return c},l.exit=function(){return s},l},Ro.datum=function(n){return arguments.length?this.property(\"__data__\",n):this.property(\"__data__\")},Ro.filter=function(n){var t,e,r,u=[];\"function\"!=typeof n&&(n=k(n));for(var i=0,o=this.length;o>i;i++){u.push(t=[]),t.parentNode=(e=this[i]).parentNode;for(var a=0,c=e.length;c>a;a++)(r=e[a])&&n.call(r,r.__data__,a)&&t.push(r)}return p(u)},Ro.order=function(){for(var n=-1,t=this.length;++n<t;)for(var e,r=this[n],u=r.length-1,i=r[u];--u>=0;)(e=r[u])&&(i&&i!==e.nextSibling&&i.parentNode.insertBefore(e,i),i=e);return this},Ro.sort=function(n){n=A.apply(this,arguments);for(var t=-1,e=this.length;++t<e;)this[t].sort(n);return this.order()},Ro.each=function(n){return N(this,function(t,e,r){n.call(t,t.__data__,e,r)})},Ro.call=function(n){var t=Mo(arguments);return n.apply(t[0]=this,t),this},Ro.empty=function(){return!this.node()},Ro.node=function(){for(var n=0,t=this.length;t>n;n++)for(var e=this[n],r=0,u=e.length;u>r;r++){var i=e[r];if(i)return i}return null},Ro.size=function(){var n=0;return this.each(function(){++n}),n};var Io=[];mo.selection.enter=T,mo.selection.enter.prototype=Io,Io.append=Ro.append,Io.empty=Ro.empty,Io.node=Ro.node,Io.call=Ro.call,Io.size=Ro.size,Io.select=function(n){for(var t,e,r,u,i,o=[],a=-1,c=this.length;++a<c;){r=(u=this[a]).update,o.push(t=[]),t.parentNode=u.parentNode;for(var l=-1,s=u.length;++l<s;)(i=u[l])?(t.push(r[l]=e=n.call(u.parentNode,i.__data__,l,a)),e.__data__=i.__data__):t.push(null)}return p(o)},Io.insert=function(n,t){return arguments.length<2&&(t=q(this)),Ro.insert.call(this,n,t)},Ro.transition=function(){for(var n,t,e=Pc||++Uc,r=[],u=Oc||{time:Date.now(),ease:Cr,delay:0,duration:250},i=-1,o=this.length;++i<o;){r.push(n=[]);for(var a=this[i],c=-1,l=a.length;++c<l;)(t=a[c])&&Ni(t,c,e,u),n.push(t)}return Ei(r,e)},Ro.interrupt=function(){return this.each(z)},mo.select=function(n){var t=[\"string\"==typeof n?Ho(n,xo):n];return t.parentNode=bo,p([t])},mo.selectAll=function(n){var t=Mo(\"string\"==typeof n?Fo(n,xo):n);return t.parentNode=bo,p([t])};var Uo=mo.select(bo);Ro.on=function(n,t,e){var r=arguments.length;if(3>r){if(\"string\"!=typeof n){2>r&&(t=!1);for(e in n)this.each(C(e,n[e],t));return this}if(2>r)return(r=this.node()[\"__on\"+n])&&r._;e=!1}return this.each(C(n,t,e))};var Zo=mo.map({mouseenter:\"mouseover\",mouseleave:\"mouseout\"});Zo.forEach(function(n){\"on\"+n in xo&&Zo.remove(n)});var Vo=a(bo.style,\"userSelect\"),Xo=0;mo.mouse=function(n){return H(n,h())};var $o=/WebKit/.test(_o.navigator.userAgent)?-1:0;mo.touches=function(n,t){return arguments.length<2&&(t=h().touches),t?Mo(t).map(function(t){var e=H(n,t);return e.identifier=t.identifier,e}):[]},mo.behavior.drag=function(){function n(){this.on(\"mousedown.drag\",o).on(\"touchstart.drag\",a)}function t(){return mo.event.changedTouches[0].identifier}function e(n,t){return mo.touches(n).filter(function(n){return n.identifier===t})[0]}function r(n,t,e,r){return function(){function o(){if(!s)return a();var n=t(s,g),e=n[0]-d[0],r=n[1]-d[1];v|=e|r,d=n,f({type:\"drag\",x:n[0]+c[0],y:n[1]+c[1],dx:e,dy:r})}function a(){m.on(e+\".\"+p,null).on(r+\".\"+p,null),y(v&&mo.event.target===h),f({type:\"dragend\"})}var c,l=this,s=l.parentNode,f=u.of(l,arguments),h=mo.event.target,g=n(),p=null==g?\"drag\":\"drag-\"+g,d=t(s,g),v=0,m=mo.select(_o).on(e+\".\"+p,o).on(r+\".\"+p,a),y=L();i?(c=i.apply(l,arguments),c=[c.x-d[0],c.y-d[1]]):c=[0,0],f({type:\"dragstart\"})}}var u=g(n,\"drag\",\"dragstart\",\"dragend\"),i=null,o=r(c,mo.mouse,\"mousemove\",\"mouseup\"),a=r(t,e,\"touchmove\",\"touchend\");return n.origin=function(t){return arguments.length?(i=t,n):i},mo.rebind(n,u,\"on\")};var Bo=Math.PI,Wo=1e-6,Jo=Wo*Wo,Go=Bo/180,Ko=180/Bo,Qo=Math.SQRT2,na=2,ta=4;mo.interpolateZoom=function(n,t){function e(n){var t=n*y;if(m){var e=Y(d),o=i/(na*h)*(e*I(Qo*t+d)-R(d));return[r+o*l,u+o*s,i*e/Y(Qo*t+d)]}return[r+n*l,u+n*s,i*Math.exp(Qo*t)]}var r=n[0],u=n[1],i=n[2],o=t[0],a=t[1],c=t[2],l=o-r,s=a-u,f=l*l+s*s,h=Math.sqrt(f),g=(c*c-i*i+ta*f)/(2*i*na*h),p=(c*c-i*i-ta*f)/(2*c*na*h),d=Math.log(Math.sqrt(g*g+1)-g),v=Math.log(Math.sqrt(p*p+1)-p),m=v-d,y=(m||Math.log(c/i))/Qo;return e.duration=1e3*y,e},mo.behavior.zoom=function(){function n(n){n.on(A,l).on(ua+\".zoom\",h).on(N,p).on(\"dblclick.zoom\",d).on(q,s)}function t(n){return[(n[0]-S.x)/S.k,(n[1]-S.y)/S.k]}function e(n){return[n[0]*S.k+S.x,n[1]*S.k+S.y]}function r(n){S.k=Math.max(k[0],Math.min(k[1],n))}function u(n,t){t=e(t),S.x+=n[0]-t[0],S.y+=n[1]-t[1]}function i(){b&&b.domain(x.range().map(function(n){return(n-S.x)/S.k}).map(x.invert)),w&&w.domain(_.range().map(function(n){return(n-S.y)/S.k}).map(_.invert))}function o(n){n({type:\"zoomstart\"})}function a(n){i(),n({type:\"zoom\",scale:S.k,translate:[S.x,S.y]})}function c(n){n({type:\"zoomend\"})}function l(){function n(){s=1,u(mo.mouse(r),h),a(i)}function e(){f.on(N,_o===r?p:null).on(T,null),g(s&&mo.event.target===l),c(i)}var r=this,i=C.of(r,arguments),l=mo.event.target,s=0,f=mo.select(_o).on(N,n).on(T,e),h=t(mo.mouse(r)),g=L();z.call(r),o(i)}function s(){function n(){var n=mo.touches(p);return g=S.k,n.forEach(function(n){n.identifier in v&&(v[n.identifier]=t(n))}),n}function e(){for(var t=mo.event.changedTouches,e=0,i=t.length;i>e;++e)v[t[e].identifier]=null;var o=n(),c=Date.now();if(1===o.length){if(500>c-M){var l=o[0],s=v[l.identifier];r(2*S.k),u(l,s),f(),a(d)}M=c}else if(o.length>1){var l=o[0],h=o[1],g=l[0]-h[0],p=l[1]-h[1];m=g*g+p*p}}function i(){for(var n,t,e,i,o=mo.touches(p),c=0,l=o.length;l>c;++c,i=null)if(e=o[c],i=v[e.identifier]){if(t)break;n=e,t=i}if(i){var s=(s=e[0]-n[0])*s+(s=e[1]-n[1])*s,f=m&&Math.sqrt(s/m);n=[(n[0]+e[0])/2,(n[1]+e[1])/2],t=[(t[0]+i[0])/2,(t[1]+i[1])/2],r(f*g)}M=null,u(n,t),a(d)}function h(){if(mo.event.touches.length){for(var t=mo.event.changedTouches,e=0,r=t.length;r>e;++e)delete v[t[e].identifier];for(var u in v)return void n()}_.on(x,null).on(b,null),w.on(A,l).on(q,s),E(),c(d)}var g,p=this,d=C.of(p,arguments),v={},m=0,y=mo.event.changedTouches[0].identifier,x=\"touchmove.zoom-\"+y,b=\"touchend.zoom-\"+y,_=mo.select(_o).on(x,i).on(b,h),w=mo.select(p).on(A,null).on(q,e),E=L();z.call(p),e(),o(d)}function h(){var n=C.of(this,arguments);y?clearTimeout(y):(z.call(this),o(n)),y=setTimeout(function(){y=null,c(n)},50),f();var e=m||mo.mouse(this);v||(v=t(e)),r(Math.pow(2,.002*ea())*S.k),u(e,v),a(n)}function p(){v=null}function d(){var n=C.of(this,arguments),e=mo.mouse(this),i=t(e),l=Math.log(S.k)/Math.LN2;o(n),r(Math.pow(2,mo.event.shiftKey?Math.ceil(l)-1:Math.floor(l)+1)),u(e,i),a(n),c(n)}var v,m,y,M,x,b,_,w,S={x:0,y:0,k:1},E=[960,500],k=ra,A=\"mousedown.zoom\",N=\"mousemove.zoom\",T=\"mouseup.zoom\",q=\"touchstart.zoom\",C=g(n,\"zoomstart\",\"zoom\",\"zoomend\");return n.event=function(n){n.each(function(){var n=C.of(this,arguments),t=S;Pc?mo.select(this).transition().each(\"start.zoom\",function(){S=this.__chart__||{x:0,y:0,k:1},o(n)}).tween(\"zoom:zoom\",function(){var e=E[0],r=E[1],u=e/2,i=r/2,o=mo.interpolateZoom([(u-S.x)/S.k,(i-S.y)/S.k,e/S.k],[(u-t.x)/t.k,(i-t.y)/t.k,e/t.k]);return function(t){var r=o(t),c=e/r[2];this.__chart__=S={x:u-r[0]*c,y:i-r[1]*c,k:c},a(n)}}).each(\"end.zoom\",function(){c(n)}):(this.__chart__=S,o(n),a(n),c(n))})},n.translate=function(t){return arguments.length?(S={x:+t[0],y:+t[1],k:S.k},i(),n):[S.x,S.y]},n.scale=function(t){return arguments.length?(S={x:S.x,y:S.y,k:+t},i(),n):S.k},n.scaleExtent=function(t){return arguments.length?(k=null==t?ra:[+t[0],+t[1]],n):k},n.center=function(t){return arguments.length?(m=t&&[+t[0],+t[1]],n):m},n.size=function(t){return arguments.length?(E=t&&[+t[0],+t[1]],n):E},n.x=function(t){return arguments.length?(b=t,x=t.copy(),S={x:0,y:0,k:1},n):b},n.y=function(t){return arguments.length?(w=t,_=t.copy(),S={x:0,y:0,k:1},n):w},mo.rebind(n,C,\"on\")};var ea,ra=[0,1/0],ua=\"onwheel\"in xo?(ea=function(){return-mo.event.deltaY*(mo.event.deltaMode?120:1)},\"wheel\"):\"onmousewheel\"in xo?(ea=function(){return mo.event.wheelDelta},\"mousewheel\"):(ea=function(){return-mo.event.detail},\"MozMousePixelScroll\");Z.prototype.toString=function(){return this.rgb()+\"\"},mo.hsl=function(n,t,e){return 1===arguments.length?n instanceof X?V(n.h,n.s,n.l):lt(\"\"+n,st,V):V(+n,+t,+e)};var ia=X.prototype=new Z;ia.brighter=function(n){return n=Math.pow(.7,arguments.length?n:1),V(this.h,this.s,this.l/n)},ia.darker=function(n){return n=Math.pow(.7,arguments.length?n:1),V(this.h,this.s,n*this.l)},ia.rgb=function(){return $(this.h,this.s,this.l)},mo.hcl=function(n,t,e){return 1===arguments.length?n instanceof W?B(n.h,n.c,n.l):n instanceof K?nt(n.l,n.a,n.b):nt((n=ft((n=mo.rgb(n)).r,n.g,n.b)).l,n.a,n.b):B(+n,+t,+e)};var oa=W.prototype=new Z;oa.brighter=function(n){return B(this.h,this.c,Math.min(100,this.l+aa*(arguments.length?n:1)))},oa.darker=function(n){return B(this.h,this.c,Math.max(0,this.l-aa*(arguments.length?n:1)))},oa.rgb=function(){return J(this.h,this.c,this.l).rgb()},mo.lab=function(n,t,e){return 1===arguments.length?n instanceof K?G(n.l,n.a,n.b):n instanceof W?J(n.l,n.c,n.h):ft((n=mo.rgb(n)).r,n.g,n.b):G(+n,+t,+e)};var aa=18,ca=.95047,la=1,sa=1.08883,fa=K.prototype=new Z;fa.brighter=function(n){return G(Math.min(100,this.l+aa*(arguments.length?n:1)),this.a,this.b)},fa.darker=function(n){return G(Math.max(0,this.l-aa*(arguments.length?n:1)),this.a,this.b)},fa.rgb=function(){return Q(this.l,this.a,this.b)},mo.rgb=function(n,t,e){return 1===arguments.length?n instanceof at?ot(n.r,n.g,n.b):lt(\"\"+n,ot,$):ot(~~n,~~t,~~e)};var ha=at.prototype=new Z;ha.brighter=function(n){n=Math.pow(.7,arguments.length?n:1);var t=this.r,e=this.g,r=this.b,u=30;return t||e||r?(t&&u>t&&(t=u),e&&u>e&&(e=u),r&&u>r&&(r=u),ot(Math.min(255,~~(t/n)),Math.min(255,~~(e/n)),Math.min(255,~~(r/n)))):ot(u,u,u)},ha.darker=function(n){return n=Math.pow(.7,arguments.length?n:1),ot(~~(n*this.r),~~(n*this.g),~~(n*this.b))},ha.hsl=function(){return st(this.r,this.g,this.b)},ha.toString=function(){return\"#\"+ct(this.r)+ct(this.g)+ct(this.b)};var ga=mo.map({aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074});ga.forEach(function(n,t){ga.set(n,ut(t))}),mo.functor=pt,mo.xhr=vt(dt),mo.dsv=function(n,t){function e(n,e,i){arguments.length<3&&(i=e,e=null);var o=mo.xhr(n,t,i);return o.row=function(n){return arguments.length?o.response(null==(e=n)?r:u(n)):e},o.row(e)}function r(n){return e.parse(n.responseText)}function u(n){return function(t){return e.parse(t.responseText,n)}}function o(t){return t.map(a).join(n)}function a(n){return c.test(n)?'\"'+n.replace(/\\\"/g,'\"\"')+'\"':n}var c=new RegExp('[\"'+n+\"\\n]\"),l=n.charCodeAt(0);return e.parse=function(n,t){var r;return e.parseRows(n,function(n,e){if(r)return r(n,e-1);var u=new Function(\"d\",\"return {\"+n.map(function(n,t){return JSON.stringify(n)+\": d[\"+t+\"]\"}).join(\",\")+\"}\");r=t?function(n,e){return t(u(n),e)}:u})},e.parseRows=function(n,t){function e(){if(s>=c)return o;if(u)return u=!1,i;var t=s;if(34===n.charCodeAt(t)){for(var e=t;e++<c;)if(34===n.charCodeAt(e)){if(34!==n.charCodeAt(e+1))break;++e}s=e+2;var r=n.charCodeAt(e+1);return 13===r?(u=!0,10===n.charCodeAt(e+2)&&++s):10===r&&(u=!0),n.substring(t+1,e).replace(/\"\"/g,'\"')}for(;c>s;){var r=n.charCodeAt(s++),a=1;if(10===r)u=!0;else if(13===r)u=!0,10===n.charCodeAt(s)&&(++s,++a);else if(r!==l)continue;return n.substring(t,s-a)}return n.substring(t)}for(var r,u,i={},o={},a=[],c=n.length,s=0,f=0;(r=e())!==o;){for(var h=[];r!==i&&r!==o;)h.push(r),r=e();(!t||(h=t(h,f++)))&&a.push(h)}return a},e.format=function(t){if(Array.isArray(t[0]))return e.formatRows(t);var r=new i,u=[];return t.forEach(function(n){for(var t in n)r.has(t)||u.push(r.add(t))}),[u.map(a).join(n)].concat(t.map(function(t){return u.map(function(n){return a(t[n])}).join(n)})).join(\"\\n\")},e.formatRows=function(n){return n.map(o).join(\"\\n\")},e},mo.csv=mo.dsv(\",\",\"text/csv\"),mo.tsv=mo.dsv(\" \",\"text/tab-separated-values\");var pa,da,va,ma,ya,Ma=_o[a(_o,\"requestAnimationFrame\")]||function(n){setTimeout(n,17)};mo.timer=function(n,t,e){var r=arguments.length;2>r&&(t=0),3>r&&(e=Date.now());var u=e+t,i={callback:n,time:u,next:null};da?da.next=i:pa=i,da=i,va||(ma=clearTimeout(ma),va=1,Ma(Mt))},mo.timer.flush=function(){bt(),_t()};var xa=\".\",ba=\",\",_a=[3,3],wa=\"$\",Sa=[\"y\",\"z\",\"a\",\"f\",\"p\",\"n\",\"\\xb5\",\"m\",\"\",\"k\",\"M\",\"G\",\"T\",\"P\",\"E\",\"Z\",\"Y\"].map(wt);mo.formatPrefix=function(n,t){var e=0;return n&&(0>n&&(n*=-1),t&&(n=mo.round(n,St(n,t))),e=1+Math.floor(1e-12+Math.log(n)/Math.LN10),e=Math.max(-24,Math.min(24,3*Math.floor((0>=e?e+1:e-1)/3)))),Sa[8+e/3]},mo.round=function(n,t){return t?Math.round(n*(t=Math.pow(10,t)))/t:Math.round(n)},mo.format=function(n){var t=Ea.exec(n),e=t[1]||\" \",r=t[2]||\">\",u=t[3]||\"\",i=t[4]||\"\",o=t[5],a=+t[6],c=t[7],l=t[8],s=t[9],f=1,h=\"\",g=!1;switch(l&&(l=+l.substring(1)),(o||\"0\"===e&&\"=\"===r)&&(o=e=\"0\",r=\"=\",c&&(a-=Math.floor((a-1)/4))),s){case\"n\":c=!0,s=\"g\";break;case\"%\":f=100,h=\"%\",s=\"f\";break;case\"p\":f=100,h=\"%\",s=\"r\";break;case\"b\":case\"o\":case\"x\":case\"X\":\"#\"===i&&(i=\"0\"+s.toLowerCase());case\"c\":case\"d\":g=!0,l=0;break;case\"s\":f=-1,s=\"r\"}\"#\"===i?i=\"\":\"$\"===i&&(i=wa),\"r\"!=s||l||(s=\"g\"),null!=l&&(\"g\"==s?l=Math.max(1,Math.min(21,l)):(\"e\"==s||\"f\"==s)&&(l=Math.max(0,Math.min(20,l)))),s=ka.get(s)||Et;var p=o&&c;return function(n){if(g&&n%1)return\"\";var t=0>n||0===n&&0>1/n?(n=-n,\"-\"):u;if(0>f){var d=mo.formatPrefix(n,l);n=d.scale(n),h=d.symbol}else n*=f;n=s(n,l);var v=n.lastIndexOf(\".\"),m=0>v?n:n.substring(0,v),y=0>v?\"\":xa+n.substring(v+1);!o&&c&&(m=Aa(m));var M=i.length+m.length+y.length+(p?0:t.length),x=a>M?new Array(M=a-M+1).join(e):\"\";return p&&(m=Aa(x+m)),t+=i,n=m+y,(\"<\"===r?t+n+x:\">\"===r?x+t+n:\"^\"===r?x.substring(0,M>>=1)+t+n+x.substring(M):t+(p?n:x+n))+h}};var Ea=/(?:([^{])?([<>=^]))?([+\\- ])?([$#])?(0)?(\\d+)?(,)?(\\.-?\\d+)?([a-z%])?/i,ka=mo.map({b:function(n){return n.toString(2)},c:function(n){return String.fromCharCode(n)},o:function(n){return n.toString(8)},x:function(n){return n.toString(16)},X:function(n){return n.toString(16).toUpperCase()},g:function(n,t){return n.toPrecision(t)},e:function(n,t){return n.toExponential(t)},f:function(n,t){return n.toFixed(t)},r:function(n,t){return(n=mo.round(n,St(n,t))).toFixed(Math.max(0,Math.min(20,St(n*(1+1e-15),t))))}}),Aa=dt;if(_a){var Na=_a.length;Aa=function(n){for(var t=n.length,e=[],r=0,u=_a[0];t>0&&u>0;)e.push(n.substring(t-=u,t+u)),u=_a[r=(r+1)%Na];return e.reverse().join(ba)}}mo.geo={},kt.prototype={s:0,t:0,add:function(n){At(n,this.t,Ta),At(Ta.s,this.s,this),this.s?this.t+=Ta.t:this.s=Ta.t},reset:function(){this.s=this.t=0},valueOf:function(){return this.s}};var Ta=new kt;mo.geo.stream=function(n,t){n&&qa.hasOwnProperty(n.type)?qa[n.type](n,t):Nt(n,t)};var qa={Feature:function(n,t){Nt(n.geometry,t)},FeatureCollection:function(n,t){for(var e=n.features,r=-1,u=e.length;++r<u;)Nt(e[r].geometry,t)}},za={Sphere:function(n,t){t.sphere()},Point:function(n,t){n=n.coordinates,t.point(n[0],n[1],n[2])},MultiPoint:function(n,t){for(var e=n.coordinates,r=-1,u=e.length;++r<u;)n=e[r],t.point(n[0],n[1],n[2])},LineString:function(n,t){Tt(n.coordinates,t,0)},MultiLineString:function(n,t){for(var e=n.coordinates,r=-1,u=e.length;++r<u;)Tt(e[r],t,0)},Polygon:function(n,t){qt(n.coordinates,t)},MultiPolygon:function(n,t){for(var e=n.coordinates,r=-1,u=e.length;++r<u;)qt(e[r],t)},GeometryCollection:function(n,t){for(var e=n.geometries,r=-1,u=e.length;++r<u;)Nt(e[r],t)}};mo.geo.area=function(n){return Ca=0,mo.geo.stream(n,ja),Ca};var Ca,Da=new kt,ja={sphere:function(){Ca+=4*Bo},point:c,lineStart:c,lineEnd:c,polygonStart:function(){Da.reset(),ja.lineStart=zt},polygonEnd:function(){var n=2*Da;Ca+=0>n?4*Bo+n:n,ja.lineStart=ja.lineEnd=ja.point=c}};mo.geo.bounds=function(){function n(n,t){M.push(x=[s=n,h=n]),f>t&&(f=t),t>g&&(g=t)}function t(t,e){var r=Ct([t*Go,e*Go]);if(m){var u=jt(m,r),i=[u[1],-u[0],0],o=jt(i,u);Ft(o),o=Pt(o);var c=t-p,l=c>0?1:-1,d=o[0]*Ko*l,v=Math.abs(c)>180;if(v^(d>l*p&&l*t>d)){var y=o[1]*Ko;y>g&&(g=y)}else if(d=(d+360)%360-180,v^(d>l*p&&l*t>d)){var y=-o[1]*Ko;f>y&&(f=y)}else f>e&&(f=e),e>g&&(g=e);v?p>t?a(s,t)>a(s,h)&&(h=t):a(t,h)>a(s,h)&&(s=t):h>=s?(s>t&&(s=t),t>h&&(h=t)):t>p?a(s,t)>a(s,h)&&(h=t):a(t,h)>a(s,h)&&(s=t)}else n(t,e);m=r,p=t}function e(){b.point=t}function r(){x[0]=s,x[1]=h,b.point=n,m=null}function u(n,e){if(m){var r=n-p;y+=Math.abs(r)>180?r+(r>0?360:-360):r}else d=n,v=e;ja.point(n,e),t(n,e)}function i(){ja.lineStart()}function o(){u(d,v),ja.lineEnd(),Math.abs(y)>Wo&&(s=-(h=180)),x[0]=s,x[1]=h,m=null}function a(n,t){return(t-=n)<0?t+360:t}function c(n,t){return n[0]-t[0]}function l(n,t){return t[0]<=t[1]?t[0]<=n&&n<=t[1]:n<t[0]||t[1]<n}var s,f,h,g,p,d,v,m,y,M,x,b={point:n,lineStart:e,lineEnd:r,polygonStart:function(){b.point=u,b.lineStart=i,b.lineEnd=o,y=0,ja.polygonStart()},polygonEnd:function(){ja.polygonEnd(),b.point=n,b.lineStart=e,b.lineEnd=r,0>Da?(s=-(h=180),f=-(g=90)):y>Wo?g=90:-Wo>y&&(f=-90),x[0]=s,x[1]=h}};return function(n){g=h=-(s=f=1/0),M=[],mo.geo.stream(n,b);var t=M.length;if(t){M.sort(c);for(var e,r=1,u=M[0],i=[u];t>r;++r)e=M[r],l(e[0],u)||l(e[1],u)?(a(u[0],e[1])>a(u[0],u[1])&&(u[1]=e[1]),a(e[0],u[1])>a(u[0],u[1])&&(u[0]=e[0])):i.push(u=e);for(var o,e,p=-1/0,t=i.length-1,r=0,u=i[t];t>=r;u=e,++r)e=i[r],(o=a(u[1],e[0]))>p&&(p=o,s=e[0],h=u[1])}return M=x=null,1/0===s||1/0===f?[[0/0,0/0],[0/0,0/0]]:[[s,f],[h,g]]}}(),mo.geo.centroid=function(n){La=Ha=Fa=Pa=Oa=Ra=Ya=Ia=Ua=Za=Va=0,mo.geo.stream(n,Xa);var t=Ua,e=Za,r=Va,u=t*t+e*e+r*r;return Jo>u&&(t=Ra,e=Ya,r=Ia,Wo>Ha&&(t=Fa,e=Pa,r=Oa),u=t*t+e*e+r*r,Jo>u)?[0/0,0/0]:[Math.atan2(e,t)*Ko,O(r/Math.sqrt(u))*Ko]};var La,Ha,Fa,Pa,Oa,Ra,Ya,Ia,Ua,Za,Va,Xa={sphere:c,point:Rt,lineStart:It,lineEnd:Ut,polygonStart:function(){Xa.lineStart=Zt},polygonEnd:function(){Xa.lineStart=It}},$a=Bt(Vt,Qt,te,ee),Ba=[-Bo,0],Wa=1e9;mo.geo.clipExtent=function(){var n,t,e,r,u,i,o={stream:function(n){return u&&(u.valid=!1),u=i(n),u.valid=!0,u},extent:function(a){return arguments.length?(i=ue(n=+a[0][0],t=+a[0][1],e=+a[1][0],r=+a[1][1]),u&&(u.valid=!1,u=null),o):[[n,t],[e,r]]}};return o.extent([[0,0],[960,500]])},(mo.geo.conicEqualArea=function(){return ae(ce)}).raw=ce,mo.geo.albers=function(){return mo.geo.conicEqualArea().rotate([96,0]).center([-.6,38.7]).parallels([29.5,45.5]).scale(1070)},mo.geo.albersUsa=function(){function n(n){var i=n[0],o=n[1];return t=null,e(i,o),t||(r(i,o),t)||u(i,o),t}var t,e,r,u,i=mo.geo.albers(),o=mo.geo.conicEqualArea().rotate([154,0]).center([-2,58.5]).parallels([55,65]),a=mo.geo.conicEqualArea().rotate([157,0]).center([-3,19.9]).parallels([8,18]),c={point:function(n,e){t=[n,e]}};return n.invert=function(n){var t=i.scale(),e=i.translate(),r=(n[0]-e[0])/t,u=(n[1]-e[1])/t;return(u>=.12&&.234>u&&r>=-.425&&-.214>r?o:u>=.166&&.234>u&&r>=-.214&&-.115>r?a:i).invert(n)},n.stream=function(n){var t=i.stream(n),e=o.stream(n),r=a.stream(n);return{point:function(n,u){t.point(n,u),e.point(n,u),r.point(n,u)},sphere:function(){t.sphere(),e.sphere(),r.sphere()},lineStart:function(){t.lineStart(),e.lineStart(),r.lineStart()},lineEnd:function(){t.lineEnd(),e.lineEnd(),r.lineEnd()},polygonStart:function(){t.polygonStart(),e.polygonStart(),r.polygonStart()},polygonEnd:function(){t.polygonEnd(),e.polygonEnd(),r.polygonEnd()}}},n.precision=function(t){return arguments.length?(i.precision(t),o.precision(t),a.precision(t),n):i.precision()},n.scale=function(t){return arguments.length?(i.scale(t),o.scale(.35*t),a.scale(t),n.translate(i.translate())):i.scale()},n.translate=function(t){if(!arguments.length)return i.translate();var l=i.scale(),s=+t[0],f=+t[1];return e=i.translate(t).clipExtent([[s-.455*l,f-.238*l],[s+.455*l,f+.238*l]]).stream(c).point,r=o.translate([s-.307*l,f+.201*l]).clipExtent([[s-.425*l+Wo,f+.12*l+Wo],[s-.214*l-Wo,f+.234*l-Wo]]).stream(c).point,u=a.translate([s-.205*l,f+.212*l]).clipExtent([[s-.214*l+Wo,f+.166*l+Wo],[s-.115*l-Wo,f+.234*l-Wo]]).stream(c).point,n},n.scale(1070)};var Ja,Ga,Ka,Qa,nc,tc,ec={point:c,lineStart:c,lineEnd:c,polygonStart:function(){Ga=0,ec.lineStart=le},polygonEnd:function(){ec.lineStart=ec.lineEnd=ec.point=c,Ja+=Math.abs(Ga/2)}},rc={point:se,lineStart:c,lineEnd:c,polygonStart:c,polygonEnd:c},uc={point:ge,lineStart:pe,lineEnd:de,polygonStart:function(){uc.lineStart=ve},polygonEnd:function(){uc.point=ge,uc.lineStart=pe,uc.lineEnd=de}};mo.geo.transform=function(n){return{stream:function(t){var e=new Me(t);for(var r in n)e[r]=n[r];return e}}},Me.prototype={point:function(n,t){this.stream.point(n,t)},sphere:function(){this.stream.sphere()},lineStart:function(){this.stream.lineStart()},lineEnd:function(){this.stream.lineEnd()},polygonStart:function(){this.stream.polygonStart()},polygonEnd:function(){this.stream.polygonEnd()}},mo.geo.path=function(){function n(n){return n&&(\"function\"==typeof a&&i.pointRadius(+a.apply(this,arguments)),o&&o.valid||(o=u(i)),mo.geo.stream(n,o)),i.result()}function t(){return o=null,n}var e,r,u,i,o,a=4.5;return n.area=function(n){return Ja=0,mo.geo.stream(n,u(ec)),Ja},n.centroid=function(n){return Fa=Pa=Oa=Ra=Ya=Ia=Ua=Za=Va=0,mo.geo.stream(n,u(uc)),Va?[Ua/Va,Za/Va]:Ia?[Ra/Ia,Ya/Ia]:Oa?[Fa/Oa,Pa/Oa]:[0/0,0/0]},n.bounds=function(n){return nc=tc=-(Ka=Qa=1/0),mo.geo.stream(n,u(rc)),[[Ka,Qa],[nc,tc]]},n.projection=function(n){return arguments.length?(u=(e=n)?n.stream||xe(n):dt,t()):e},n.context=function(n){return arguments.length?(i=null==(r=n)?new fe:new me(n),\"function\"!=typeof a&&i.pointRadius(a),t()):r},n.pointRadius=function(t){return arguments.length?(a=\"function\"==typeof t?t:(i.pointRadius(+t),+t),n):a},n.projection(mo.geo.albersUsa()).context(null)},mo.geo.projection=be,mo.geo.projectionMutator=_e,(mo.geo.equirectangular=function(){return be(Se)}).raw=Se.invert=Se,mo.geo.rotation=function(n){function t(t){return t=n(t[0]*Go,t[1]*Go),t[0]*=Ko,t[1]*=Ko,t}return n=Ee(n[0]%360*Go,n[1]*Go,n.length>2?n[2]*Go:0),t.invert=function(t){return t=n.invert(t[0]*Go,t[1]*Go),t[0]*=Ko,t[1]*=Ko,t},t},mo.geo.circle=function(){function n(){var n=\"function\"==typeof r?r.apply(this,arguments):r,t=Ee(-n[0]*Go,-n[1]*Go,0).invert,u=[];return e(null,null,1,{point:function(n,e){u.push(n=t(n,e)),n[0]*=Ko,n[1]*=Ko}}),{type:\"Polygon\",coordinates:[u]}}var t,e,r=[0,0],u=6;return n.origin=function(t){return arguments.length?(r=t,n):r},n.angle=function(r){return arguments.length?(e=Te((t=+r)*Go,u*Go),n):t},n.precision=function(r){return arguments.length?(e=Te(t*Go,(u=+r)*Go),n):u},n.angle(90)},mo.geo.distance=function(n,t){var e,r=(t[0]-n[0])*Go,u=n[1]*Go,i=t[1]*Go,o=Math.sin(r),a=Math.cos(r),c=Math.sin(u),l=Math.cos(u),s=Math.sin(i),f=Math.cos(i);return Math.atan2(Math.sqrt((e=f*o)*e+(e=l*s-c*f*a)*e),c*s+l*f*a)},mo.geo.graticule=function(){function n(){return{type:\"MultiLineString\",coordinates:t()}}function t(){return mo.range(Math.ceil(i/v)*v,u,v).map(h).concat(mo.range(Math.ceil(l/m)*m,c,m).map(g)).concat(mo.range(Math.ceil(r/p)*p,e,p).filter(function(n){return Math.abs(n%v)>Wo\n        }).map(s)).concat(mo.range(Math.ceil(a/d)*d,o,d).filter(function(n){return Math.abs(n%m)>Wo}).map(f))}var e,r,u,i,o,a,c,l,s,f,h,g,p=10,d=p,v=90,m=360,y=2.5;return n.lines=function(){return t().map(function(n){return{type:\"LineString\",coordinates:n}})},n.outline=function(){return{type:\"Polygon\",coordinates:[h(i).concat(g(c).slice(1),h(u).reverse().slice(1),g(l).reverse().slice(1))]}},n.extent=function(t){return arguments.length?n.majorExtent(t).minorExtent(t):n.minorExtent()},n.majorExtent=function(t){return arguments.length?(i=+t[0][0],u=+t[1][0],l=+t[0][1],c=+t[1][1],i>u&&(t=i,i=u,u=t),l>c&&(t=l,l=c,c=t),n.precision(y)):[[i,l],[u,c]]},n.minorExtent=function(t){return arguments.length?(r=+t[0][0],e=+t[1][0],a=+t[0][1],o=+t[1][1],r>e&&(t=r,r=e,e=t),a>o&&(t=a,a=o,o=t),n.precision(y)):[[r,a],[e,o]]},n.step=function(t){return arguments.length?n.majorStep(t).minorStep(t):n.minorStep()},n.majorStep=function(t){return arguments.length?(v=+t[0],m=+t[1],n):[v,m]},n.minorStep=function(t){return arguments.length?(p=+t[0],d=+t[1],n):[p,d]},n.precision=function(t){return arguments.length?(y=+t,s=ze(a,o,90),f=Ce(r,e,y),h=ze(l,c,90),g=Ce(i,u,y),n):y},n.majorExtent([[-180,-90+Wo],[180,90-Wo]]).minorExtent([[-180,-80-Wo],[180,80+Wo]])},mo.geo.greatArc=function(){function n(){return{type:\"LineString\",coordinates:[t||r.apply(this,arguments),e||u.apply(this,arguments)]}}var t,e,r=De,u=je;return n.distance=function(){return mo.geo.distance(t||r.apply(this,arguments),e||u.apply(this,arguments))},n.source=function(e){return arguments.length?(r=e,t=\"function\"==typeof e?null:e,n):r},n.target=function(t){return arguments.length?(u=t,e=\"function\"==typeof t?null:t,n):u},n.precision=function(){return arguments.length?n:0},n},mo.geo.interpolate=function(n,t){return Le(n[0]*Go,n[1]*Go,t[0]*Go,t[1]*Go)},mo.geo.length=function(n){return ic=0,mo.geo.stream(n,oc),ic};var ic,oc={sphere:c,point:c,lineStart:He,lineEnd:c,polygonStart:c,polygonEnd:c},ac=Fe(function(n){return Math.sqrt(2/(1+n))},function(n){return 2*Math.asin(n/2)});(mo.geo.azimuthalEqualArea=function(){return be(ac)}).raw=ac;var cc=Fe(function(n){var t=Math.acos(n);return t&&t/Math.sin(t)},dt);(mo.geo.azimuthalEquidistant=function(){return be(cc)}).raw=cc,(mo.geo.conicConformal=function(){return ae(Pe)}).raw=Pe,(mo.geo.conicEquidistant=function(){return ae(Oe)}).raw=Oe;var lc=Fe(function(n){return 1/n},Math.atan);(mo.geo.gnomonic=function(){return be(lc)}).raw=lc,Re.invert=function(n,t){return[n,2*Math.atan(Math.exp(t))-Bo/2]},(mo.geo.mercator=function(){return Ye(Re)}).raw=Re;var sc=Fe(function(){return 1},Math.asin);(mo.geo.orthographic=function(){return be(sc)}).raw=sc;var fc=Fe(function(n){return 1/(1+n)},function(n){return 2*Math.atan(n)});(mo.geo.stereographic=function(){return be(fc)}).raw=fc,Ie.invert=function(n,t){return[Math.atan2(R(n),Math.cos(t)),O(Math.sin(t)/Y(n))]},(mo.geo.transverseMercator=function(){return Ye(Ie)}).raw=Ie,mo.geom={},mo.svg={},mo.svg.line=function(){return Ue(dt)};var hc=mo.map({linear:Xe,\"linear-closed\":$e,step:Be,\"step-before\":We,\"step-after\":Je,basis:er,\"basis-open\":rr,\"basis-closed\":ur,bundle:ir,cardinal:Qe,\"cardinal-open\":Ge,\"cardinal-closed\":Ke,monotone:fr});hc.forEach(function(n,t){t.key=n,t.closed=/-closed$/.test(n)});var gc=[0,2/3,1/3,0],pc=[0,1/3,2/3,0],dc=[0,1/6,2/3,1/6];mo.geom.hull=function(n){function t(n){if(n.length<3)return[];var t,u,i,o,a,c,l,s,f,h,g,p,d=pt(e),v=pt(r),m=n.length,y=m-1,M=[],x=[],b=0;if(d===Ze&&r===Ve)t=n;else for(i=0,t=[];m>i;++i)t.push([+d.call(this,u=n[i],i),+v.call(this,u,i)]);for(i=1;m>i;++i)(t[i][1]<t[b][1]||t[i][1]==t[b][1]&&t[i][0]<t[b][0])&&(b=i);for(i=0;m>i;++i)i!==b&&(c=t[i][1]-t[b][1],a=t[i][0]-t[b][0],M.push({angle:Math.atan2(c,a),index:i}));for(M.sort(function(n,t){return n.angle-t.angle}),g=M[0].angle,h=M[0].index,f=0,i=1;y>i;++i){if(o=M[i].index,g==M[i].angle){if(a=t[h][0]-t[b][0],c=t[h][1]-t[b][1],l=t[o][0]-t[b][0],s=t[o][1]-t[b][1],a*a+c*c>=l*l+s*s){M[i].index=-1;continue}M[f].index=-1}g=M[i].angle,f=i,h=o}for(x.push(b),i=0,o=0;2>i;++o)M[o].index>-1&&(x.push(M[o].index),i++);for(p=x.length;y>o;++o)if(!(M[o].index<0)){for(;!hr(x[p-2],x[p-1],M[o].index,t);)--p;x[p++]=M[o].index}var _=[];for(i=p-1;i>=0;--i)_.push(n[x[i]]);return _}var e=Ze,r=Ve;return arguments.length?t(n):(t.x=function(n){return arguments.length?(e=n,t):e},t.y=function(n){return arguments.length?(r=n,t):r},t)},mo.geom.polygon=function(n){return Lo(n,vc),n};var vc=mo.geom.polygon.prototype=[];vc.area=function(){for(var n,t=-1,e=this.length,r=this[e-1],u=0;++t<e;)n=r,r=this[t],u+=n[1]*r[0]-n[0]*r[1];return.5*u},vc.centroid=function(n){var t,e,r=-1,u=this.length,i=0,o=0,a=this[u-1];for(arguments.length||(n=-1/(6*this.area()));++r<u;)t=a,a=this[r],e=t[0]*a[1]-a[0]*t[1],i+=(t[0]+a[0])*e,o+=(t[1]+a[1])*e;return[i*n,o*n]},vc.clip=function(n){for(var t,e,r,u,i,o,a=dr(n),c=-1,l=this.length-dr(this),s=this[l-1];++c<l;){for(t=n.slice(),n.length=0,u=this[c],i=t[(r=t.length-a)-1],e=-1;++e<r;)o=t[e],gr(o,s,u)?(gr(i,s,u)||n.push(pr(i,o,s,u)),n.push(o)):gr(i,s,u)&&n.push(pr(i,o,s,u)),i=o;a&&n.push(n[0]),s=u}return n},mo.geom.delaunay=function(n){var t=n.map(function(){return[]}),e=[];return vr(n,function(e){t[e.region.l.index].push(n[e.region.r.index])}),t.forEach(function(t,r){var u=n[r],i=u[0],o=u[1];t.forEach(function(n){n.angle=Math.atan2(n[0]-i,n[1]-o)}),t.sort(function(n,t){return n.angle-t.angle});for(var a=0,c=t.length-1;c>a;a++)e.push([u,t[a],t[a+1]])}),e},mo.geom.voronoi=function(n){function t(n){var t,i,o,a=n.map(function(){return[]}),c=pt(e),l=pt(r),s=n.length,f=1e6;if(c===Ze&&l===Ve)t=n;else for(t=new Array(s),o=0;s>o;++o)t[o]=[+c.call(this,i=n[o],o),+l.call(this,i,o)];if(vr(t,function(n){var t,e,r,u,i,o;1===n.a&&n.b>=0?(t=n.ep.r,e=n.ep.l):(t=n.ep.l,e=n.ep.r),1===n.a?(i=t?t.y:-f,r=n.c-n.b*i,o=e?e.y:f,u=n.c-n.b*o):(r=t?t.x:-f,i=n.c-n.a*r,u=e?e.x:f,o=n.c-n.a*u);var c=[r,i],l=[u,o];a[n.region.l.index].push(c,l),a[n.region.r.index].push(c,l)}),a=a.map(function(n,e){var r=t[e][0],u=t[e][1],i=n.map(function(n){return Math.atan2(n[0]-r,n[1]-u)}),o=mo.range(n.length).sort(function(n,t){return i[n]-i[t]});return o.filter(function(n,t){return!t||i[n]-i[o[t-1]]>Wo}).map(function(t){return n[t]})}),a.forEach(function(n,e){var r=n.length;if(!r)return n.push([-f,-f],[-f,f],[f,f],[f,-f]);if(!(r>2)){var u=t[e],i=n[0],o=n[1],a=u[0],c=u[1],l=i[0],s=i[1],h=o[0],g=o[1],p=Math.abs(h-l),d=g-s;if(Math.abs(d)<Wo){var v=s>c?-f:f;n.push([-f,v],[f,v])}else if(Wo>p){var m=l>a?-f:f;n.push([m,-f],[m,f])}else{var v=(l-a)*(g-s)>(h-l)*(s-c)?f:-f,y=Math.abs(d)-p;Math.abs(y)<Wo?n.push([0>d?v:-v,v]):(y>0&&(v*=-1),n.push([-f,v],[f,v]))}}}),u)for(o=0;s>o;++o)u.clip(a[o]);for(o=0;s>o;++o)a[o].point=n[o];return a}var e=Ze,r=Ve,u=null;return arguments.length?t(n):(t.x=function(n){return arguments.length?(e=n,t):e},t.y=function(n){return arguments.length?(r=n,t):r},t.clipExtent=function(n){if(!arguments.length)return u&&[u[0],u[2]];if(null==n)u=null;else{var e=+n[0][0],r=+n[0][1],i=+n[1][0],o=+n[1][1];u=mo.geom.polygon([[e,r],[e,o],[i,o],[i,r]])}return t},t.size=function(n){return arguments.length?t.clipExtent(n&&[[0,0],n]):u&&u[2]},t.links=function(n){var t,u,i,o=n.map(function(){return[]}),a=[],c=pt(e),l=pt(r),s=n.length;if(c===Ze&&l===Ve)t=n;else for(t=new Array(s),i=0;s>i;++i)t[i]=[+c.call(this,u=n[i],i),+l.call(this,u,i)];return vr(t,function(t){var e=t.region.l.index,r=t.region.r.index;o[e][r]||(o[e][r]=o[r][e]=!0,a.push({source:n[e],target:n[r]}))}),a},t.triangles=function(n){if(e===Ze&&r===Ve)return mo.geom.delaunay(n);for(var t,u=new Array(c),i=pt(e),o=pt(r),a=-1,c=n.length;++a<c;)(u[a]=[+i.call(this,t=n[a],a),+o.call(this,t,a)]).data=t;return mo.geom.delaunay(u).map(function(n){return n.map(function(n){return n.data})})},t)};var mc={l:\"r\",r:\"l\"};mo.geom.quadtree=function(n,t,e,r,u){function i(n){function i(n,t,e,r,u,i,o,a){if(!isNaN(e)&&!isNaN(r))if(n.leaf){var c=n.x,s=n.y;if(null!=c)if(Math.abs(c-e)+Math.abs(s-r)<.01)l(n,t,e,r,u,i,o,a);else{var f=n.point;n.x=n.y=n.point=null,l(n,f,c,s,u,i,o,a),l(n,t,e,r,u,i,o,a)}else n.x=e,n.y=r,n.point=t}else l(n,t,e,r,u,i,o,a)}function l(n,t,e,r,u,o,a,c){var l=.5*(u+a),s=.5*(o+c),f=e>=l,h=r>=s,g=(h<<1)+f;n.leaf=!1,n=n.nodes[g]||(n.nodes[g]=Mr()),f?u=l:a=l,h?o=s:c=s,i(n,t,e,r,u,o,a,c)}var s,f,h,g,p,d,v,m,y,M=pt(a),x=pt(c);if(null!=t)d=t,v=e,m=r,y=u;else if(m=y=-(d=v=1/0),f=[],h=[],p=n.length,o)for(g=0;p>g;++g)s=n[g],s.x<d&&(d=s.x),s.y<v&&(v=s.y),s.x>m&&(m=s.x),s.y>y&&(y=s.y),f.push(s.x),h.push(s.y);else for(g=0;p>g;++g){var b=+M(s=n[g],g),_=+x(s,g);d>b&&(d=b),v>_&&(v=_),b>m&&(m=b),_>y&&(y=_),f.push(b),h.push(_)}var w=m-d,S=y-v;w>S?y=v+w:m=d+S;var E=Mr();if(E.add=function(n){i(E,n,+M(n,++g),+x(n,g),d,v,m,y)},E.visit=function(n){xr(n,E,d,v,m,y)},g=-1,null==t){for(;++g<p;)i(E,n[g],f[g],h[g],d,v,m,y);--g}else n.forEach(E.add);return f=h=n=s=null,E}var o,a=Ze,c=Ve;return(o=arguments.length)?(a=mr,c=yr,3===o&&(u=e,r=t,e=t=0),i(n)):(i.x=function(n){return arguments.length?(a=n,i):a},i.y=function(n){return arguments.length?(c=n,i):c},i.extent=function(n){return arguments.length?(null==n?t=e=r=u=null:(t=+n[0][0],e=+n[0][1],r=+n[1][0],u=+n[1][1]),i):null==t?null:[[t,e],[r,u]]},i.size=function(n){return arguments.length?(null==n?t=e=r=u=null:(t=e=0,r=+n[0],u=+n[1]),i):null==t?null:[r-t,u-e]},i)},mo.interpolateRgb=br,mo.interpolateObject=_r,mo.interpolateNumber=wr,mo.interpolateString=Sr;var yc=/[-+]?(?:\\d+\\.?\\d*|\\.?\\d+)(?:[eE][-+]?\\d+)?/g;mo.interpolate=Er,mo.interpolators=[function(n,t){var e=typeof t;return(\"string\"===e?ga.has(t)||/^(#|rgb\\(|hsl\\()/.test(t)?br:Sr:t instanceof Z?br:\"object\"===e?Array.isArray(t)?kr:_r:wr)(n,t)}],mo.interpolateArray=kr;var Mc=function(){return dt},xc=mo.map({linear:Mc,poly:Dr,quad:function(){return qr},cubic:function(){return zr},sin:function(){return jr},exp:function(){return Lr},circle:function(){return Hr},elastic:Fr,back:Pr,bounce:function(){return Or}}),bc=mo.map({\"in\":dt,out:Nr,\"in-out\":Tr,\"out-in\":function(n){return Tr(Nr(n))}});mo.ease=function(n){var t=n.indexOf(\"-\"),e=t>=0?n.substring(0,t):n,r=t>=0?n.substring(t+1):\"in\";return e=xc.get(e)||Mc,r=bc.get(r)||dt,Ar(r(e.apply(null,Array.prototype.slice.call(arguments,1))))},mo.interpolateHcl=Rr,mo.interpolateHsl=Yr,mo.interpolateLab=Ir,mo.interpolateRound=Ur,mo.transform=function(n){var t=xo.createElementNS(mo.ns.prefix.svg,\"g\");return(mo.transform=function(n){if(null!=n){t.setAttribute(\"transform\",n);var e=t.transform.baseVal.consolidate()}return new Zr(e?e.matrix:_c)})(n)},Zr.prototype.toString=function(){return\"translate(\"+this.translate+\")rotate(\"+this.rotate+\")skewX(\"+this.skew+\")scale(\"+this.scale+\")\"};var _c={a:1,b:0,c:0,d:1,e:0,f:0};mo.interpolateTransform=Br,mo.layout={},mo.layout.bundle=function(){return function(n){for(var t=[],e=-1,r=n.length;++e<r;)t.push(Gr(n[e]));return t}},mo.layout.chord=function(){function n(){var n,l,f,h,g,p={},d=[],v=mo.range(i),m=[];for(e=[],r=[],n=0,h=-1;++h<i;){for(l=0,g=-1;++g<i;)l+=u[h][g];d.push(l),m.push(mo.range(i)),n+=l}for(o&&v.sort(function(n,t){return o(d[n],d[t])}),a&&m.forEach(function(n,t){n.sort(function(n,e){return a(u[t][n],u[t][e])})}),n=(2*Bo-s*i)/n,l=0,h=-1;++h<i;){for(f=l,g=-1;++g<i;){var y=v[h],M=m[y][g],x=u[y][M],b=l,_=l+=x*n;p[y+\"-\"+M]={index:y,subindex:M,startAngle:b,endAngle:_,value:x}}r[y]={index:y,startAngle:f,endAngle:l,value:(l-f)/n},l+=s}for(h=-1;++h<i;)for(g=h-1;++g<i;){var w=p[h+\"-\"+g],S=p[g+\"-\"+h];(w.value||S.value)&&e.push(w.value<S.value?{source:S,target:w}:{source:w,target:S})}c&&t()}function t(){e.sort(function(n,t){return c((n.source.value+n.target.value)/2,(t.source.value+t.target.value)/2)})}var e,r,u,i,o,a,c,l={},s=0;return l.matrix=function(n){return arguments.length?(i=(u=n)&&u.length,e=r=null,l):u},l.padding=function(n){return arguments.length?(s=n,e=r=null,l):s},l.sortGroups=function(n){return arguments.length?(o=n,e=r=null,l):o},l.sortSubgroups=function(n){return arguments.length?(a=n,e=null,l):a},l.sortChords=function(n){return arguments.length?(c=n,e&&t(),l):c},l.chords=function(){return e||n(),e},l.groups=function(){return r||n(),r},l},mo.layout.force=function(){function n(n){return function(t,e,r,u){if(t.point!==n){var i=t.cx-n.x,o=t.cy-n.y,a=1/Math.sqrt(i*i+o*o);if(d>(u-e)*a){var c=t.charge*a*a;return n.px-=i*c,n.py-=o*c,!0}if(t.point&&isFinite(a)){var c=t.pointCharge*a*a;n.px-=i*c,n.py-=o*c}}return!t.charge}}function t(n){n.px=mo.event.x,n.py=mo.event.y,a.resume()}var e,r,u,i,o,a={},c=mo.dispatch(\"start\",\"tick\",\"end\"),l=[1,1],s=.9,f=wc,h=Sc,g=-30,p=.1,d=.8,v=[],m=[];return a.tick=function(){if((r*=.99)<.005)return c.end({type:\"end\",alpha:r=0}),!0;var t,e,a,f,h,d,y,M,x,b=v.length,_=m.length;for(e=0;_>e;++e)a=m[e],f=a.source,h=a.target,M=h.x-f.x,x=h.y-f.y,(d=M*M+x*x)&&(d=r*i[e]*((d=Math.sqrt(d))-u[e])/d,M*=d,x*=d,h.x-=M*(y=f.weight/(h.weight+f.weight)),h.y-=x*y,f.x+=M*(y=1-y),f.y+=x*y);if((y=r*p)&&(M=l[0]/2,x=l[1]/2,e=-1,y))for(;++e<b;)a=v[e],a.x+=(M-a.x)*y,a.y+=(x-a.y)*y;if(g)for(uu(t=mo.geom.quadtree(v),r,o),e=-1;++e<b;)(a=v[e]).fixed||t.visit(n(a));for(e=-1;++e<b;)a=v[e],a.fixed?(a.x=a.px,a.y=a.py):(a.x-=(a.px-(a.px=a.x))*s,a.y-=(a.py-(a.py=a.y))*s);c.tick({type:\"tick\",alpha:r})},a.nodes=function(n){return arguments.length?(v=n,a):v},a.links=function(n){return arguments.length?(m=n,a):m},a.size=function(n){return arguments.length?(l=n,a):l},a.linkDistance=function(n){return arguments.length?(f=\"function\"==typeof n?n:+n,a):f},a.distance=a.linkDistance,a.linkStrength=function(n){return arguments.length?(h=\"function\"==typeof n?n:+n,a):h},a.friction=function(n){return arguments.length?(s=+n,a):s},a.charge=function(n){return arguments.length?(g=\"function\"==typeof n?n:+n,a):g},a.gravity=function(n){return arguments.length?(p=+n,a):p},a.theta=function(n){return arguments.length?(d=+n,a):d},a.alpha=function(n){return arguments.length?(n=+n,r?r=n>0?n:0:n>0&&(c.start({type:\"start\",alpha:r=n}),mo.timer(a.tick)),a):r},a.start=function(){function n(n,r){for(var u,i=t(e),o=-1,a=i.length;++o<a;)if(!isNaN(u=i[o][n]))return u;return Math.random()*r}function t(){if(!c){for(c=[],r=0;p>r;++r)c[r]=[];for(r=0;d>r;++r){var n=m[r];c[n.source.index].push(n.target),c[n.target.index].push(n.source)}}return c[e]}var e,r,c,s,p=v.length,d=m.length,y=l[0],M=l[1];for(e=0;p>e;++e)(s=v[e]).index=e,s.weight=0;for(e=0;d>e;++e)s=m[e],\"number\"==typeof s.source&&(s.source=v[s.source]),\"number\"==typeof s.target&&(s.target=v[s.target]),++s.source.weight,++s.target.weight;for(e=0;p>e;++e)s=v[e],isNaN(s.x)&&(s.x=n(\"x\",y)),isNaN(s.y)&&(s.y=n(\"y\",M)),isNaN(s.px)&&(s.px=s.x),isNaN(s.py)&&(s.py=s.y);if(u=[],\"function\"==typeof f)for(e=0;d>e;++e)u[e]=+f.call(this,m[e],e);else for(e=0;d>e;++e)u[e]=f;if(i=[],\"function\"==typeof h)for(e=0;d>e;++e)i[e]=+h.call(this,m[e],e);else for(e=0;d>e;++e)i[e]=h;if(o=[],\"function\"==typeof g)for(e=0;p>e;++e)o[e]=+g.call(this,v[e],e);else for(e=0;p>e;++e)o[e]=g;return a.resume()},a.resume=function(){return a.alpha(.1)},a.stop=function(){return a.alpha(0)},a.drag=function(){return e||(e=mo.behavior.drag().origin(dt).on(\"dragstart.force\",nu).on(\"drag.force\",t).on(\"dragend.force\",tu)),arguments.length?(this.on(\"mouseover.force\",eu).on(\"mouseout.force\",ru).call(e),void 0):e},mo.rebind(a,c,\"on\")};var wc=20,Sc=1;mo.layout.hierarchy=function(){function n(t,o,a){var c=u.call(e,t,o);if(t.depth=o,a.push(t),c&&(l=c.length)){for(var l,s,f=-1,h=t.children=[],g=0,p=o+1;++f<l;)s=n(c[f],p,a),s.parent=t,h.push(s),g+=s.value;r&&h.sort(r),i&&(t.value=g)}else i&&(t.value=+i.call(e,t,o)||0);return t}function t(n,r){var u=n.children,o=0;if(u&&(a=u.length))for(var a,c=-1,l=r+1;++c<a;)o+=t(u[c],l);else i&&(o=+i.call(e,n,r)||0);return i&&(n.value=o),o}function e(t){var e=[];return n(t,0,e),e}var r=cu,u=ou,i=au;return e.sort=function(n){return arguments.length?(r=n,e):r},e.children=function(n){return arguments.length?(u=n,e):u},e.value=function(n){return arguments.length?(i=n,e):i},e.revalue=function(n){return t(n,0),n},e},mo.layout.partition=function(){function n(t,e,r,u){var i=t.children;if(t.x=e,t.y=t.depth*u,t.dx=r,t.dy=u,i&&(o=i.length)){var o,a,c,l=-1;for(r=t.value?r/t.value:0;++l<o;)n(a=i[l],e,c=a.value*r,u),e+=c}}function t(n){var e=n.children,r=0;if(e&&(u=e.length))for(var u,i=-1;++i<u;)r=Math.max(r,t(e[i]));return 1+r}function e(e,i){var o=r.call(this,e,i);return n(o[0],0,u[0],u[1]/t(o[0])),o}var r=mo.layout.hierarchy(),u=[1,1];return e.size=function(n){return arguments.length?(u=n,e):u},iu(e,r)},mo.layout.pie=function(){function n(i){var o=i.map(function(e,r){return+t.call(n,e,r)}),a=+(\"function\"==typeof r?r.apply(this,arguments):r),c=((\"function\"==typeof u?u.apply(this,arguments):u)-a)/mo.sum(o),l=mo.range(i.length);null!=e&&l.sort(e===Ec?function(n,t){return o[t]-o[n]}:function(n,t){return e(i[n],i[t])});var s=[];return l.forEach(function(n){var t;s[n]={data:i[n],value:t=o[n],startAngle:a,endAngle:a+=t*c}}),s}var t=Number,e=Ec,r=0,u=2*Bo;return n.value=function(e){return arguments.length?(t=e,n):t},n.sort=function(t){return arguments.length?(e=t,n):e},n.startAngle=function(t){return arguments.length?(r=t,n):r},n.endAngle=function(t){return arguments.length?(u=t,n):u},n};var Ec={};mo.layout.stack=function(){function n(a,c){var l=a.map(function(e,r){return t.call(n,e,r)}),s=l.map(function(t){return t.map(function(t,e){return[i.call(n,t,e),o.call(n,t,e)]})}),f=e.call(n,s,c);l=mo.permute(l,f),s=mo.permute(s,f);var h,g,p,d=r.call(n,s,c),v=l.length,m=l[0].length;for(g=0;m>g;++g)for(u.call(n,l[0][g],p=d[g],s[0][g][1]),h=1;v>h;++h)u.call(n,l[h][g],p+=s[h-1][g][1],s[h][g][1]);return a}var t=dt,e=gu,r=pu,u=hu,i=su,o=fu;return n.values=function(e){return arguments.length?(t=e,n):t},n.order=function(t){return arguments.length?(e=\"function\"==typeof t?t:kc.get(t)||gu,n):e},n.offset=function(t){return arguments.length?(r=\"function\"==typeof t?t:Ac.get(t)||pu,n):r},n.x=function(t){return arguments.length?(i=t,n):i},n.y=function(t){return arguments.length?(o=t,n):o},n.out=function(t){return arguments.length?(u=t,n):u},n};var kc=mo.map({\"inside-out\":function(n){var t,e,r=n.length,u=n.map(du),i=n.map(vu),o=mo.range(r).sort(function(n,t){return u[n]-u[t]}),a=0,c=0,l=[],s=[];for(t=0;r>t;++t)e=o[t],c>a?(a+=i[e],l.push(e)):(c+=i[e],s.push(e));return s.reverse().concat(l)},reverse:function(n){return mo.range(n.length).reverse()},\"default\":gu}),Ac=mo.map({silhouette:function(n){var t,e,r,u=n.length,i=n[0].length,o=[],a=0,c=[];for(e=0;i>e;++e){for(t=0,r=0;u>t;t++)r+=n[t][e][1];r>a&&(a=r),o.push(r)}for(e=0;i>e;++e)c[e]=(a-o[e])/2;return c},wiggle:function(n){var t,e,r,u,i,o,a,c,l,s=n.length,f=n[0],h=f.length,g=[];for(g[0]=c=l=0,e=1;h>e;++e){for(t=0,u=0;s>t;++t)u+=n[t][e][1];for(t=0,i=0,a=f[e][0]-f[e-1][0];s>t;++t){for(r=0,o=(n[t][e][1]-n[t][e-1][1])/(2*a);t>r;++r)o+=(n[r][e][1]-n[r][e-1][1])/a;i+=o*n[t][e][1]}g[e]=c-=u?i/u*a:0,l>c&&(l=c)}for(e=0;h>e;++e)g[e]-=l;return g},expand:function(n){var t,e,r,u=n.length,i=n[0].length,o=1/u,a=[];for(e=0;i>e;++e){for(t=0,r=0;u>t;t++)r+=n[t][e][1];if(r)for(t=0;u>t;t++)n[t][e][1]/=r;else for(t=0;u>t;t++)n[t][e][1]=o}for(e=0;i>e;++e)a[e]=0;return a},zero:pu});mo.layout.histogram=function(){function n(n,i){for(var o,a,c=[],l=n.map(e,this),s=r.call(this,l,i),f=u.call(this,s,l,i),i=-1,h=l.length,g=f.length-1,p=t?1:1/h;++i<g;)o=c[i]=[],o.dx=f[i+1]-(o.x=f[i]),o.y=0;if(g>0)for(i=-1;++i<h;)a=l[i],a>=s[0]&&a<=s[1]&&(o=c[mo.bisect(f,a,1,g)-1],o.y+=p,o.push(n[i]));return c}var t=!0,e=Number,r=xu,u=yu;return n.value=function(t){return arguments.length?(e=t,n):e},n.range=function(t){return arguments.length?(r=pt(t),n):r},n.bins=function(t){return arguments.length?(u=\"number\"==typeof t?function(n){return Mu(n,t)}:pt(t),n):u},n.frequency=function(e){return arguments.length?(t=!!e,n):t},n},mo.layout.tree=function(){function n(n,i){function o(n,t){var r=n.children,u=n._tree;if(r&&(i=r.length)){for(var i,a,l,s=r[0],f=s,h=-1;++h<i;)l=r[h],o(l,a),f=c(l,a,f),a=l;Tu(n);var g=.5*(s._tree.prelim+l._tree.prelim);t?(u.prelim=t._tree.prelim+e(n,t),u.mod=u.prelim-g):u.prelim=g}else t&&(u.prelim=t._tree.prelim+e(n,t))}function a(n,t){n.x=n._tree.prelim+t;var e=n.children;if(e&&(r=e.length)){var r,u=-1;for(t+=n._tree.mod;++u<r;)a(e[u],t)}}function c(n,t,r){if(t){for(var u,i=n,o=n,a=t,c=n.parent.children[0],l=i._tree.mod,s=o._tree.mod,f=a._tree.mod,h=c._tree.mod;a=wu(a),i=_u(i),a&&i;)c=_u(c),o=wu(o),o._tree.ancestor=n,u=a._tree.prelim+f-i._tree.prelim-l+e(a,i),u>0&&(qu(zu(a,n,r),n,u),l+=u,s+=u),f+=a._tree.mod,l+=i._tree.mod,h+=c._tree.mod,s+=o._tree.mod;a&&!wu(o)&&(o._tree.thread=a,o._tree.mod+=f-s),i&&!_u(c)&&(c._tree.thread=i,c._tree.mod+=l-h,r=n)}return r}var l=t.call(this,n,i),s=l[0];Nu(s,function(n,t){n._tree={ancestor:n,prelim:0,mod:0,change:0,shift:0,number:t?t._tree.number+1:0}}),o(s),a(s,-s._tree.prelim);var f=Su(s,ku),h=Su(s,Eu),g=Su(s,Au),p=f.x-e(f,h)/2,d=h.x+e(h,f)/2,v=g.depth||1;return Nu(s,u?function(n){n.x*=r[0],n.y=n.depth*r[1],delete n._tree}:function(n){n.x=(n.x-p)/(d-p)*r[0],n.y=n.depth/v*r[1],delete n._tree}),l}var t=mo.layout.hierarchy().sort(null).value(null),e=bu,r=[1,1],u=!1;return n.separation=function(t){return arguments.length?(e=t,n):e},n.size=function(t){return arguments.length?(u=null==(r=t),n):u?null:r},n.nodeSize=function(t){return arguments.length?(u=null!=(r=t),n):u?r:null},iu(n,t)},mo.layout.pack=function(){function n(n,i){var o=e.call(this,n,i),a=o[0],c=u[0],l=u[1],s=null==t?Math.sqrt:\"function\"==typeof t?t:function(){return t};if(a.x=a.y=0,Nu(a,function(n){n.r=+s(n.value)}),Nu(a,Hu),r){var f=r*(t?1:Math.max(2*a.r/c,2*a.r/l))/2;Nu(a,function(n){n.r+=f}),Nu(a,Hu),Nu(a,function(n){n.r-=f})}return Ou(a,c/2,l/2,t?1:1/Math.max(2*a.r/c,2*a.r/l)),o}var t,e=mo.layout.hierarchy().sort(Cu),r=0,u=[1,1];return n.size=function(t){return arguments.length?(u=t,n):u},n.radius=function(e){return arguments.length?(t=null==e||\"function\"==typeof e?e:+e,n):t},n.padding=function(t){return arguments.length?(r=+t,n):r},iu(n,e)},mo.layout.cluster=function(){function n(n,i){var o,a=t.call(this,n,i),c=a[0],l=0;Nu(c,function(n){var t=n.children;t&&t.length?(n.x=Iu(t),n.y=Yu(t)):(n.x=o?l+=e(n,o):0,n.y=0,o=n)});var s=Uu(c),f=Zu(c),h=s.x-e(s,f)/2,g=f.x+e(f,s)/2;return Nu(c,u?function(n){n.x=(n.x-c.x)*r[0],n.y=(c.y-n.y)*r[1]}:function(n){n.x=(n.x-h)/(g-h)*r[0],n.y=(1-(c.y?n.y/c.y:1))*r[1]}),a}var t=mo.layout.hierarchy().sort(null).value(null),e=bu,r=[1,1],u=!1;return n.separation=function(t){return arguments.length?(e=t,n):e},n.size=function(t){return arguments.length?(u=null==(r=t),n):u?null:r},n.nodeSize=function(t){return arguments.length?(u=null!=(r=t),n):u?r:null},iu(n,t)},mo.layout.treemap=function(){function n(n,t){for(var e,r,u=-1,i=n.length;++u<i;)r=(e=n[u]).value*(0>t?0:t),e.area=isNaN(r)||0>=r?0:r}function t(e){var i=e.children;if(i&&i.length){var o,a,c,l=f(e),s=[],h=i.slice(),p=1/0,d=\"slice\"===g?l.dx:\"dice\"===g?l.dy:\"slice-dice\"===g?1&e.depth?l.dy:l.dx:Math.min(l.dx,l.dy);for(n(h,l.dx*l.dy/e.value),s.area=0;(c=h.length)>0;)s.push(o=h[c-1]),s.area+=o.area,\"squarify\"!==g||(a=r(s,d))<=p?(h.pop(),p=a):(s.area-=s.pop().area,u(s,d,l,!1),d=Math.min(l.dx,l.dy),s.length=s.area=0,p=1/0);s.length&&(u(s,d,l,!0),s.length=s.area=0),i.forEach(t)}}function e(t){var r=t.children;if(r&&r.length){var i,o=f(t),a=r.slice(),c=[];for(n(a,o.dx*o.dy/t.value),c.area=0;i=a.pop();)c.push(i),c.area+=i.area,null!=i.z&&(u(c,i.z?o.dx:o.dy,o,!a.length),c.length=c.area=0);r.forEach(e)}}function r(n,t){for(var e,r=n.area,u=0,i=1/0,o=-1,a=n.length;++o<a;)(e=n[o].area)&&(i>e&&(i=e),e>u&&(u=e));return r*=r,t*=t,r?Math.max(t*u*p/r,r/(t*i*p)):1/0}function u(n,t,e,r){var u,i=-1,o=n.length,a=e.x,l=e.y,s=t?c(n.area/t):0;if(t==e.dx){for((r||s>e.dy)&&(s=e.dy);++i<o;)u=n[i],u.x=a,u.y=l,u.dy=s,a+=u.dx=Math.min(e.x+e.dx-a,s?c(u.area/s):0);u.z=!0,u.dx+=e.x+e.dx-a,e.y+=s,e.dy-=s}else{for((r||s>e.dx)&&(s=e.dx);++i<o;)u=n[i],u.x=a,u.y=l,u.dx=s,l+=u.dy=Math.min(e.y+e.dy-l,s?c(u.area/s):0);u.z=!1,u.dy+=e.y+e.dy-l,e.x+=s,e.dx-=s}}function i(r){var u=o||a(r),i=u[0];return i.x=0,i.y=0,i.dx=l[0],i.dy=l[1],o&&a.revalue(i),n([i],i.dx*i.dy/i.value),(o?e:t)(i),h&&(o=u),u}var o,a=mo.layout.hierarchy(),c=Math.round,l=[1,1],s=null,f=Vu,h=!1,g=\"squarify\",p=.5*(1+Math.sqrt(5));return i.size=function(n){return arguments.length?(l=n,i):l},i.padding=function(n){function t(t){var e=n.call(i,t,t.depth);return null==e?Vu(t):Xu(t,\"number\"==typeof e?[e,e,e,e]:e)}function e(t){return Xu(t,n)}if(!arguments.length)return s;var r;return f=null==(s=n)?Vu:\"function\"==(r=typeof n)?t:\"number\"===r?(n=[n,n,n,n],e):e,i},i.round=function(n){return arguments.length?(c=n?Math.round:Number,i):c!=Number},i.sticky=function(n){return arguments.length?(h=n,o=null,i):h},i.ratio=function(n){return arguments.length?(p=n,i):p},i.mode=function(n){return arguments.length?(g=n+\"\",i):g},iu(i,a)},mo.random={normal:function(n,t){var e=arguments.length;return 2>e&&(t=1),1>e&&(n=0),function(){var e,r,u;do e=2*Math.random()-1,r=2*Math.random()-1,u=e*e+r*r;while(!u||u>1);return n+t*e*Math.sqrt(-2*Math.log(u)/u)}},logNormal:function(){var n=mo.random.normal.apply(mo,arguments);return function(){return Math.exp(n())}},irwinHall:function(n){return function(){for(var t=0,e=0;n>e;e++)t+=Math.random();return t/n}}},mo.scale={};var Nc={floor:dt,ceil:dt};mo.scale.linear=function(){return Qu([0,1],[0,1],Er,!1)},mo.scale.log=function(){return ii(mo.scale.linear().domain([0,1]),10,!0,[1,10])};var Tc=mo.format(\".0e\"),qc={floor:function(n){return-Math.ceil(-n)},ceil:function(n){return-Math.floor(-n)}};mo.scale.pow=function(){return oi(mo.scale.linear(),1,[0,1])},mo.scale.sqrt=function(){return mo.scale.pow().exponent(.5)},mo.scale.ordinal=function(){return ci([],{t:\"range\",a:[[]]})},mo.scale.category10=function(){return mo.scale.ordinal().range(zc)},mo.scale.category20=function(){return mo.scale.ordinal().range(Cc)},mo.scale.category20b=function(){return mo.scale.ordinal().range(Dc)},mo.scale.category20c=function(){return mo.scale.ordinal().range(jc)};var zc=[2062260,16744206,2924588,14034728,9725885,9197131,14907330,8355711,12369186,1556175].map(it),Cc=[2062260,11454440,16744206,16759672,2924588,10018698,14034728,16750742,9725885,12955861,9197131,12885140,14907330,16234194,8355711,13092807,12369186,14408589,1556175,10410725].map(it),Dc=[3750777,5395619,7040719,10264286,6519097,9216594,11915115,13556636,9202993,12426809,15186514,15190932,8666169,11356490,14049643,15177372,8077683,10834324,13528509,14589654].map(it),jc=[3244733,7057110,10406625,13032431,15095053,16616764,16625259,16634018,3253076,7652470,10607003,13101504,7695281,10394312,12369372,14342891,6513507,9868950,12434877,14277081].map(it);mo.scale.quantile=function(){return li([],[])},mo.scale.quantize=function(){return si(0,1,[0,1])},mo.scale.threshold=function(){return fi([.5],[0,1])},mo.scale.identity=function(){return hi([0,1])},mo.svg.arc=function(){function n(){var n=t.apply(this,arguments),i=e.apply(this,arguments),o=r.apply(this,arguments)+Lc,a=u.apply(this,arguments)+Lc,c=(o>a&&(c=o,o=a,a=c),a-o),l=Bo>c?\"0\":\"1\",s=Math.cos(o),f=Math.sin(o),h=Math.cos(a),g=Math.sin(a);return c>=Hc?n?\"M0,\"+i+\"A\"+i+\",\"+i+\" 0 1,1 0,\"+-i+\"A\"+i+\",\"+i+\" 0 1,1 0,\"+i+\"M0,\"+n+\"A\"+n+\",\"+n+\" 0 1,0 0,\"+-n+\"A\"+n+\",\"+n+\" 0 1,0 0,\"+n+\"Z\":\"M0,\"+i+\"A\"+i+\",\"+i+\" 0 1,1 0,\"+-i+\"A\"+i+\",\"+i+\" 0 1,1 0,\"+i+\"Z\":n?\"M\"+i*s+\",\"+i*f+\"A\"+i+\",\"+i+\" 0 \"+l+\",1 \"+i*h+\",\"+i*g+\"L\"+n*h+\",\"+n*g+\"A\"+n+\",\"+n+\" 0 \"+l+\",0 \"+n*s+\",\"+n*f+\"Z\":\"M\"+i*s+\",\"+i*f+\"A\"+i+\",\"+i+\" 0 \"+l+\",1 \"+i*h+\",\"+i*g+\"L0,0\"+\"Z\"}var t=gi,e=pi,r=di,u=vi;return n.innerRadius=function(e){return arguments.length?(t=pt(e),n):t},n.outerRadius=function(t){return arguments.length?(e=pt(t),n):e},n.startAngle=function(t){return arguments.length?(r=pt(t),n):r},n.endAngle=function(t){return arguments.length?(u=pt(t),n):u},n.centroid=function(){var n=(t.apply(this,arguments)+e.apply(this,arguments))/2,i=(r.apply(this,arguments)+u.apply(this,arguments))/2+Lc;return[Math.cos(i)*n,Math.sin(i)*n]},n};var Lc=-Bo/2,Hc=2*Bo-1e-6;mo.svg.line.radial=function(){var n=Ue(mi);return n.radius=n.x,delete n.x,n.angle=n.y,delete n.y,n},We.reverse=Je,Je.reverse=We,mo.svg.area=function(){return yi(dt)},mo.svg.area.radial=function(){var n=yi(mi);return n.radius=n.x,delete n.x,n.innerRadius=n.x0,delete n.x0,n.outerRadius=n.x1,delete n.x1,n.angle=n.y,delete n.y,n.startAngle=n.y0,delete n.y0,n.endAngle=n.y1,delete n.y1,n},mo.svg.chord=function(){function n(n,a){var c=t(this,i,n,a),l=t(this,o,n,a);return\"M\"+c.p0+r(c.r,c.p1,c.a1-c.a0)+(e(c,l)?u(c.r,c.p1,c.r,c.p0):u(c.r,c.p1,l.r,l.p0)+r(l.r,l.p1,l.a1-l.a0)+u(l.r,l.p1,c.r,c.p0))+\"Z\"}function t(n,t,e,r){var u=t.call(n,e,r),i=a.call(n,u,r),o=c.call(n,u,r)+Lc,s=l.call(n,u,r)+Lc;return{r:i,a0:o,a1:s,p0:[i*Math.cos(o),i*Math.sin(o)],p1:[i*Math.cos(s),i*Math.sin(s)]}}function e(n,t){return n.a0==t.a0&&n.a1==t.a1}function r(n,t,e){return\"A\"+n+\",\"+n+\" 0 \"+ +(e>Bo)+\",1 \"+t}function u(n,t,e,r){return\"Q 0,0 \"+r}var i=De,o=je,a=Mi,c=di,l=vi;return n.radius=function(t){return arguments.length?(a=pt(t),n):a},n.source=function(t){return arguments.length?(i=pt(t),n):i},n.target=function(t){return arguments.length?(o=pt(t),n):o},n.startAngle=function(t){return arguments.length?(c=pt(t),n):c},n.endAngle=function(t){return arguments.length?(l=pt(t),n):l},n},mo.svg.diagonal=function(){function n(n,u){var i=t.call(this,n,u),o=e.call(this,n,u),a=(i.y+o.y)/2,c=[i,{x:i.x,y:a},{x:o.x,y:a},o];return c=c.map(r),\"M\"+c[0]+\"C\"+c[1]+\" \"+c[2]+\" \"+c[3]}var t=De,e=je,r=xi;return n.source=function(e){return arguments.length?(t=pt(e),n):t},n.target=function(t){return arguments.length?(e=pt(t),n):e},n.projection=function(t){return arguments.length?(r=t,n):r},n},mo.svg.diagonal.radial=function(){var n=mo.svg.diagonal(),t=xi,e=n.projection;return n.projection=function(n){return arguments.length?e(bi(t=n)):t},n},mo.svg.symbol=function(){function n(n,r){return(Fc.get(t.call(this,n,r))||Si)(e.call(this,n,r))}var t=wi,e=_i;return n.type=function(e){return arguments.length?(t=pt(e),n):t},n.size=function(t){return arguments.length?(e=pt(t),n):e},n};var Fc=mo.map({circle:Si,cross:function(n){var t=Math.sqrt(n/5)/2;return\"M\"+-3*t+\",\"+-t+\"H\"+-t+\"V\"+-3*t+\"H\"+t+\"V\"+-t+\"H\"+3*t+\"V\"+t+\"H\"+t+\"V\"+3*t+\"H\"+-t+\"V\"+t+\"H\"+-3*t+\"Z\"},diamond:function(n){var t=Math.sqrt(n/(2*Yc)),e=t*Yc;return\"M0,\"+-t+\"L\"+e+\",0\"+\" 0,\"+t+\" \"+-e+\",0\"+\"Z\"},square:function(n){var t=Math.sqrt(n)/2;return\"M\"+-t+\",\"+-t+\"L\"+t+\",\"+-t+\" \"+t+\",\"+t+\" \"+-t+\",\"+t+\"Z\"},\"triangle-down\":function(n){var t=Math.sqrt(n/Rc),e=t*Rc/2;return\"M0,\"+e+\"L\"+t+\",\"+-e+\" \"+-t+\",\"+-e+\"Z\"},\"triangle-up\":function(n){var t=Math.sqrt(n/Rc),e=t*Rc/2;return\"M0,\"+-e+\"L\"+t+\",\"+e+\" \"+-t+\",\"+e+\"Z\"}});mo.svg.symbolTypes=Fc.keys();var Pc,Oc,Rc=Math.sqrt(3),Yc=Math.tan(30*Go),Ic=[],Uc=0;Ic.call=Ro.call,Ic.empty=Ro.empty,Ic.node=Ro.node,Ic.size=Ro.size,mo.transition=function(n){return arguments.length?Pc?n.transition():n:Uo.transition()},mo.transition.prototype=Ic,Ic.select=function(n){var t,e,r,u=this.id,i=[];n=d(n);for(var o=-1,a=this.length;++o<a;){i.push(t=[]);for(var c=this[o],l=-1,s=c.length;++l<s;)(r=c[l])&&(e=n.call(r,r.__data__,l,o))?(\"__data__\"in r&&(e.__data__=r.__data__),Ni(e,l,u,r.__transition__[u]),t.push(e)):t.push(null)}return Ei(i,u)},Ic.selectAll=function(n){var t,e,r,u,i,o=this.id,a=[];n=v(n);for(var c=-1,l=this.length;++c<l;)for(var s=this[c],f=-1,h=s.length;++f<h;)if(r=s[f]){i=r.__transition__[o],e=n.call(r,r.__data__,f,c),a.push(t=[]);for(var g=-1,p=e.length;++g<p;)(u=e[g])&&Ni(u,g,o,i),t.push(u)}return Ei(a,o)},Ic.filter=function(n){var t,e,r,u=[];\"function\"!=typeof n&&(n=k(n));for(var i=0,o=this.length;o>i;i++){u.push(t=[]);for(var e=this[i],a=0,c=e.length;c>a;a++)(r=e[a])&&n.call(r,r.__data__,a)&&t.push(r)}return Ei(u,this.id)},Ic.tween=function(n,t){var e=this.id;return arguments.length<2?this.node().__transition__[e].tween.get(n):N(this,null==t?function(t){t.__transition__[e].tween.remove(n)}:function(r){r.__transition__[e].tween.set(n,t)})},Ic.attr=function(n,t){function e(){this.removeAttribute(a)}function r(){this.removeAttributeNS(a.space,a.local)}function u(n){return null==n?e:(n+=\"\",function(){var t,e=this.getAttribute(a);return e!==n&&(t=o(e,n),function(n){this.setAttribute(a,t(n))})})}function i(n){return null==n?r:(n+=\"\",function(){var t,e=this.getAttributeNS(a.space,a.local);return e!==n&&(t=o(e,n),function(n){this.setAttributeNS(a.space,a.local,t(n))\n            })})}if(arguments.length<2){for(t in n)this.attr(t,n[t]);return this}var o=\"transform\"==n?Br:Er,a=mo.ns.qualify(n);return ki(this,\"attr.\"+n,t,a.local?i:u)},Ic.attrTween=function(n,t){function e(n,e){var r=t.call(this,n,e,this.getAttribute(u));return r&&function(n){this.setAttribute(u,r(n))}}function r(n,e){var r=t.call(this,n,e,this.getAttributeNS(u.space,u.local));return r&&function(n){this.setAttributeNS(u.space,u.local,r(n))}}var u=mo.ns.qualify(n);return this.tween(\"attr.\"+n,u.local?r:e)},Ic.style=function(n,t,e){function r(){this.style.removeProperty(n)}function u(t){return null==t?r:(t+=\"\",function(){var r,u=_o.getComputedStyle(this,null).getPropertyValue(n);return u!==t&&(r=Er(u,t),function(t){this.style.setProperty(n,r(t),e)})})}var i=arguments.length;if(3>i){if(\"string\"!=typeof n){2>i&&(t=\"\");for(e in n)this.style(e,n[e],t);return this}e=\"\"}return ki(this,\"style.\"+n,t,u)},Ic.styleTween=function(n,t,e){function r(r,u){var i=t.call(this,r,u,_o.getComputedStyle(this,null).getPropertyValue(n));return i&&function(t){this.style.setProperty(n,i(t),e)}}return arguments.length<3&&(e=\"\"),this.tween(\"style.\"+n,r)},Ic.text=function(n){return ki(this,\"text\",n,Ai)},Ic.remove=function(){return this.each(\"end.transition\",function(){var n;this.__transition__.count<2&&(n=this.parentNode)&&n.removeChild(this)})},Ic.ease=function(n){var t=this.id;return arguments.length<1?this.node().__transition__[t].ease:(\"function\"!=typeof n&&(n=mo.ease.apply(mo,arguments)),N(this,function(e){e.__transition__[t].ease=n}))},Ic.delay=function(n){var t=this.id;return N(this,\"function\"==typeof n?function(e,r,u){e.__transition__[t].delay=+n.call(e,e.__data__,r,u)}:(n=+n,function(e){e.__transition__[t].delay=n}))},Ic.duration=function(n){var t=this.id;return N(this,\"function\"==typeof n?function(e,r,u){e.__transition__[t].duration=Math.max(1,n.call(e,e.__data__,r,u))}:(n=Math.max(1,n),function(e){e.__transition__[t].duration=n}))},Ic.each=function(n,t){var e=this.id;if(arguments.length<2){var r=Oc,u=Pc;Pc=e,N(this,function(t,r,u){Oc=t.__transition__[e],n.call(t,t.__data__,r,u)}),Oc=r,Pc=u}else N(this,function(r){var u=r.__transition__[e];(u.event||(u.event=mo.dispatch(\"start\",\"end\"))).on(n,t)});return this},Ic.transition=function(){for(var n,t,e,r,u=this.id,i=++Uc,o=[],a=0,c=this.length;c>a;a++){o.push(n=[]);for(var t=this[a],l=0,s=t.length;s>l;l++)(e=t[l])&&(r=Object.create(e.__transition__[u]),r.delay+=r.duration,Ni(e,l,i,r)),n.push(e)}return Ei(o,i)},mo.svg.axis=function(){function n(n){n.each(function(){var n,l=mo.select(this),s=null==c?e.ticks?e.ticks.apply(e,a):e.domain():c,f=null==t?e.tickFormat?e.tickFormat.apply(e,a):dt:t,h=l.selectAll(\".tick\").data(s,dt),g=h.enter().insert(\"g\",\".domain\").attr(\"class\",\"tick\").style(\"opacity\",1e-6),p=mo.transition(h.exit()).style(\"opacity\",1e-6).remove(),d=mo.transition(h).style(\"opacity\",1),v=Bu(e),m=l.selectAll(\".domain\").data([0]),y=(m.enter().append(\"path\").attr(\"class\",\"domain\"),mo.transition(m)),M=e.copy(),x=this.__chart__||M;this.__chart__=M,g.append(\"line\"),g.append(\"text\");var b=g.select(\"line\"),_=d.select(\"line\"),w=h.select(\"text\").text(f),S=g.select(\"text\"),E=d.select(\"text\");switch(r){case\"bottom\":n=Ti,b.attr(\"y2\",u),S.attr(\"y\",Math.max(u,0)+o),_.attr(\"x2\",0).attr(\"y2\",u),E.attr(\"x\",0).attr(\"y\",Math.max(u,0)+o),w.attr(\"dy\",\".71em\").style(\"text-anchor\",\"middle\"),y.attr(\"d\",\"M\"+v[0]+\",\"+i+\"V0H\"+v[1]+\"V\"+i);break;case\"top\":n=Ti,b.attr(\"y2\",-u),S.attr(\"y\",-(Math.max(u,0)+o)),_.attr(\"x2\",0).attr(\"y2\",-u),E.attr(\"x\",0).attr(\"y\",-(Math.max(u,0)+o)),w.attr(\"dy\",\"0em\").style(\"text-anchor\",\"middle\"),y.attr(\"d\",\"M\"+v[0]+\",\"+-i+\"V0H\"+v[1]+\"V\"+-i);break;case\"left\":n=qi,b.attr(\"x2\",-u),S.attr(\"x\",-(Math.max(u,0)+o)),_.attr(\"x2\",-u).attr(\"y2\",0),E.attr(\"x\",-(Math.max(u,0)+o)).attr(\"y\",0),w.attr(\"dy\",\".32em\").style(\"text-anchor\",\"end\"),y.attr(\"d\",\"M\"+-i+\",\"+v[0]+\"H0V\"+v[1]+\"H\"+-i);break;case\"right\":n=qi,b.attr(\"x2\",u),S.attr(\"x\",Math.max(u,0)+o),_.attr(\"x2\",u).attr(\"y2\",0),E.attr(\"x\",Math.max(u,0)+o).attr(\"y\",0),w.attr(\"dy\",\".32em\").style(\"text-anchor\",\"start\"),y.attr(\"d\",\"M\"+i+\",\"+v[0]+\"H0V\"+v[1]+\"H\"+i)}if(e.rangeBand){var k=M.rangeBand()/2,A=function(n){return M(n)+k};g.call(n,A),d.call(n,A)}else g.call(n,x),d.call(n,M),p.call(n,M)})}var t,e=mo.scale.linear(),r=Zc,u=6,i=6,o=3,a=[10],c=null;return n.scale=function(t){return arguments.length?(e=t,n):e},n.orient=function(t){return arguments.length?(r=t in Vc?t+\"\":Zc,n):r},n.ticks=function(){return arguments.length?(a=arguments,n):a},n.tickValues=function(t){return arguments.length?(c=t,n):c},n.tickFormat=function(e){return arguments.length?(t=e,n):t},n.tickSize=function(t){var e=arguments.length;return e?(u=+t,i=+arguments[e-1],n):u},n.innerTickSize=function(t){return arguments.length?(u=+t,n):u},n.outerTickSize=function(t){return arguments.length?(i=+t,n):i},n.tickPadding=function(t){return arguments.length?(o=+t,n):o},n.tickSubdivide=function(){return arguments.length&&n},n};var Zc=\"bottom\",Vc={top:1,right:1,bottom:1,left:1};mo.svg.brush=function(){function n(i){i.each(function(){var i=mo.select(this).style(\"pointer-events\",\"all\").style(\"-webkit-tap-highlight-color\",\"rgba(0,0,0,0)\").on(\"mousedown.brush\",u).on(\"touchstart.brush\",u),o=i.selectAll(\".background\").data([0]);o.enter().append(\"rect\").attr(\"class\",\"background\").style(\"visibility\",\"hidden\").style(\"cursor\",\"crosshair\"),i.selectAll(\".extent\").data([0]).enter().append(\"rect\").attr(\"class\",\"extent\").style(\"cursor\",\"move\");var a=i.selectAll(\".resize\").data(v,dt);a.exit().remove(),a.enter().append(\"g\").attr(\"class\",function(n){return\"resize \"+n}).style(\"cursor\",function(n){return Xc[n]}).append(\"rect\").attr(\"x\",function(n){return/[ew]$/.test(n)?-3:null}).attr(\"y\",function(n){return/^[ns]/.test(n)?-3:null}).attr(\"width\",6).attr(\"height\",6).style(\"visibility\",\"hidden\"),a.style(\"display\",n.empty()?\"none\":null);var s,f=mo.transition(i),h=mo.transition(o);c&&(s=Bu(c),h.attr(\"x\",s[0]).attr(\"width\",s[1]-s[0]),e(f)),l&&(s=Bu(l),h.attr(\"y\",s[0]).attr(\"height\",s[1]-s[0]),r(f)),t(f)})}function t(n){n.selectAll(\".resize\").attr(\"transform\",function(n){return\"translate(\"+s[+/e$/.test(n)]+\",\"+h[+/^s/.test(n)]+\")\"})}function e(n){n.select(\".extent\").attr(\"x\",s[0]),n.selectAll(\".extent,.n>rect,.s>rect\").attr(\"width\",s[1]-s[0])}function r(n){n.select(\".extent\").attr(\"y\",h[0]),n.selectAll(\".extent,.e>rect,.w>rect\").attr(\"height\",h[1]-h[0])}function u(){function u(){32==mo.event.keyCode&&(N||(M=null,q[0]-=s[1],q[1]-=h[1],N=2),f())}function g(){32==mo.event.keyCode&&2==N&&(q[0]+=s[1],q[1]+=h[1],N=0,f())}function v(){var n=mo.mouse(b),u=!1;x&&(n[0]+=x[0],n[1]+=x[1]),N||(mo.event.altKey?(M||(M=[(s[0]+s[1])/2,(h[0]+h[1])/2]),q[0]=s[+(n[0]<M[0])],q[1]=h[+(n[1]<M[1])]):M=null),k&&m(n,c,0)&&(e(S),u=!0),A&&m(n,l,1)&&(r(S),u=!0),u&&(t(S),w({type:\"brush\",mode:N?\"move\":\"resize\"}))}function m(n,t,e){var r,u,a=Bu(t),c=a[0],l=a[1],f=q[e],g=e?h:s,v=g[1]-g[0];return N&&(c-=f,l-=v+f),r=(e?d:p)?Math.max(c,Math.min(l,n[e])):n[e],N?u=(r+=f)+v:(M&&(f=Math.max(c,Math.min(l,2*M[e]-r))),r>f?(u=r,r=f):u=f),g[0]!=r||g[1]!=u?(e?o=null:i=null,g[0]=r,g[1]=u,!0):void 0}function y(){v(),S.style(\"pointer-events\",\"all\").selectAll(\".resize\").style(\"display\",n.empty()?\"none\":null),mo.select(\"body\").style(\"cursor\",null),z.on(\"mousemove.brush\",null).on(\"mouseup.brush\",null).on(\"touchmove.brush\",null).on(\"touchend.brush\",null).on(\"keydown.brush\",null).on(\"keyup.brush\",null),T(),w({type:\"brushend\"})}var M,x,b=this,_=mo.select(mo.event.target),w=a.of(b,arguments),S=mo.select(b),E=_.datum(),k=!/^(n|s)$/.test(E)&&c,A=!/^(e|w)$/.test(E)&&l,N=_.classed(\"extent\"),T=L(),q=mo.mouse(b),z=mo.select(_o).on(\"keydown.brush\",u).on(\"keyup.brush\",g);if(mo.event.changedTouches?z.on(\"touchmove.brush\",v).on(\"touchend.brush\",y):z.on(\"mousemove.brush\",v).on(\"mouseup.brush\",y),S.interrupt().selectAll(\"*\").interrupt(),N)q[0]=s[0]-q[0],q[1]=h[0]-q[1];else if(E){var C=+/w$/.test(E),D=+/^n/.test(E);x=[s[1-C]-q[0],h[1-D]-q[1]],q[0]=s[C],q[1]=h[D]}else mo.event.altKey&&(M=q.slice());S.style(\"pointer-events\",\"none\").selectAll(\".resize\").style(\"display\",null),mo.select(\"body\").style(\"cursor\",_.style(\"cursor\")),w({type:\"brushstart\"}),v()}var i,o,a=g(n,\"brushstart\",\"brush\",\"brushend\"),c=null,l=null,s=[0,0],h=[0,0],p=!0,d=!0,v=$c[0];return n.event=function(n){n.each(function(){var n=a.of(this,arguments),t={x:s,y:h,i:i,j:o},e=this.__chart__||t;this.__chart__=t,Pc?mo.select(this).transition().each(\"start.brush\",function(){i=e.i,o=e.j,s=e.x,h=e.y,n({type:\"brushstart\"})}).tween(\"brush:brush\",function(){var e=kr(s,t.x),r=kr(h,t.y);return i=o=null,function(u){s=t.x=e(u),h=t.y=r(u),n({type:\"brush\",mode:\"resize\"})}}).each(\"end.brush\",function(){i=t.i,o=t.j,n({type:\"brush\",mode:\"resize\"}),n({type:\"brushend\"})}):(n({type:\"brushstart\"}),n({type:\"brush\",mode:\"resize\"}),n({type:\"brushend\"}))})},n.x=function(t){return arguments.length?(c=t,v=$c[!c<<1|!l],n):c},n.y=function(t){return arguments.length?(l=t,v=$c[!c<<1|!l],n):l},n.clamp=function(t){return arguments.length?(c&&l?(p=!!t[0],d=!!t[1]):c?p=!!t:l&&(d=!!t),n):c&&l?[p,d]:c?p:l?d:null},n.extent=function(t){var e,r,u,a,f;return arguments.length?(c&&(e=t[0],r=t[1],l&&(e=e[0],r=r[0]),i=[e,r],c.invert&&(e=c(e),r=c(r)),e>r&&(f=e,e=r,r=f),(e!=s[0]||r!=s[1])&&(s=[e,r])),l&&(u=t[0],a=t[1],c&&(u=u[1],a=a[1]),o=[u,a],l.invert&&(u=l(u),a=l(a)),u>a&&(f=u,u=a,a=f),(u!=h[0]||a!=h[1])&&(h=[u,a])),n):(c&&(i?(e=i[0],r=i[1]):(e=s[0],r=s[1],c.invert&&(e=c.invert(e),r=c.invert(r)),e>r&&(f=e,e=r,r=f))),l&&(o?(u=o[0],a=o[1]):(u=h[0],a=h[1],l.invert&&(u=l.invert(u),a=l.invert(a)),u>a&&(f=u,u=a,a=f))),c&&l?[[e,u],[r,a]]:c?[e,r]:l&&[u,a])},n.clear=function(){return n.empty()||(s=[0,0],h=[0,0],i=o=null),n},n.empty=function(){return!!c&&s[0]==s[1]||!!l&&h[0]==h[1]},mo.rebind(n,a,\"on\")};var Xc={n:\"ns-resize\",e:\"ew-resize\",s:\"ns-resize\",w:\"ew-resize\",nw:\"nwse-resize\",ne:\"nesw-resize\",se:\"nwse-resize\",sw:\"nesw-resize\"},$c=[[\"n\",\"e\",\"s\",\"w\",\"nw\",\"ne\",\"se\",\"sw\"],[\"e\",\"w\"],[\"n\",\"s\"],[]],Bc=mo.time={},Wc=Date,Jc=[\"Sunday\",\"Monday\",\"Tuesday\",\"Wednesday\",\"Thursday\",\"Friday\",\"Saturday\"];zi.prototype={getDate:function(){return this._.getUTCDate()},getDay:function(){return this._.getUTCDay()},getFullYear:function(){return this._.getUTCFullYear()},getHours:function(){return this._.getUTCHours()},getMilliseconds:function(){return this._.getUTCMilliseconds()},getMinutes:function(){return this._.getUTCMinutes()},getMonth:function(){return this._.getUTCMonth()},getSeconds:function(){return this._.getUTCSeconds()},getTime:function(){return this._.getTime()},getTimezoneOffset:function(){return 0},valueOf:function(){return this._.valueOf()},setDate:function(){Gc.setUTCDate.apply(this._,arguments)},setDay:function(){Gc.setUTCDay.apply(this._,arguments)},setFullYear:function(){Gc.setUTCFullYear.apply(this._,arguments)},setHours:function(){Gc.setUTCHours.apply(this._,arguments)},setMilliseconds:function(){Gc.setUTCMilliseconds.apply(this._,arguments)},setMinutes:function(){Gc.setUTCMinutes.apply(this._,arguments)},setMonth:function(){Gc.setUTCMonth.apply(this._,arguments)},setSeconds:function(){Gc.setUTCSeconds.apply(this._,arguments)},setTime:function(){Gc.setTime.apply(this._,arguments)}};var Gc=Date.prototype,Kc=\"%a %b %e %X %Y\",Qc=\"%m/%d/%Y\",nl=\"%H:%M:%S\",tl=[\"Sunday\",\"Monday\",\"Tuesday\",\"Wednesday\",\"Thursday\",\"Friday\",\"Saturday\"],el=[\"Sun\",\"Mon\",\"Tue\",\"Wed\",\"Thu\",\"Fri\",\"Sat\"],rl=[\"January\",\"February\",\"March\",\"April\",\"May\",\"June\",\"July\",\"August\",\"September\",\"October\",\"November\",\"December\"],ul=[\"Jan\",\"Feb\",\"Mar\",\"Apr\",\"May\",\"Jun\",\"Jul\",\"Aug\",\"Sep\",\"Oct\",\"Nov\",\"Dec\"];Bc.year=Ci(function(n){return n=Bc.day(n),n.setMonth(0,1),n},function(n,t){n.setFullYear(n.getFullYear()+t)},function(n){return n.getFullYear()}),Bc.years=Bc.year.range,Bc.years.utc=Bc.year.utc.range,Bc.day=Ci(function(n){var t=new Wc(2e3,0);return t.setFullYear(n.getFullYear(),n.getMonth(),n.getDate()),t},function(n,t){n.setDate(n.getDate()+t)},function(n){return n.getDate()-1}),Bc.days=Bc.day.range,Bc.days.utc=Bc.day.utc.range,Bc.dayOfYear=function(n){var t=Bc.year(n);return Math.floor((n-t-6e4*(n.getTimezoneOffset()-t.getTimezoneOffset()))/864e5)},Jc.forEach(function(n,t){n=n.toLowerCase(),t=7-t;var e=Bc[n]=Ci(function(n){return(n=Bc.day(n)).setDate(n.getDate()-(n.getDay()+t)%7),n},function(n,t){n.setDate(n.getDate()+7*Math.floor(t))},function(n){var e=Bc.year(n).getDay();return Math.floor((Bc.dayOfYear(n)+(e+t)%7)/7)-(e!==t)});Bc[n+\"s\"]=e.range,Bc[n+\"s\"].utc=e.utc.range,Bc[n+\"OfYear\"]=function(n){var e=Bc.year(n).getDay();return Math.floor((Bc.dayOfYear(n)+(e+t)%7)/7)}}),Bc.week=Bc.sunday,Bc.weeks=Bc.sunday.range,Bc.weeks.utc=Bc.sunday.utc.range,Bc.weekOfYear=Bc.sundayOfYear,Bc.format=ji;var il=Hi(tl),ol=Fi(tl),al=Hi(el),cl=Fi(el),ll=Hi(rl),sl=Fi(rl),fl=Hi(ul),hl=Fi(ul),gl=/^%/,pl={\"-\":\"\",_:\" \",0:\"0\"},dl={a:function(n){return el[n.getDay()]},A:function(n){return tl[n.getDay()]},b:function(n){return ul[n.getMonth()]},B:function(n){return rl[n.getMonth()]},c:ji(Kc),d:function(n,t){return Pi(n.getDate(),t,2)},e:function(n,t){return Pi(n.getDate(),t,2)},H:function(n,t){return Pi(n.getHours(),t,2)},I:function(n,t){return Pi(n.getHours()%12||12,t,2)},j:function(n,t){return Pi(1+Bc.dayOfYear(n),t,3)},L:function(n,t){return Pi(n.getMilliseconds(),t,3)},m:function(n,t){return Pi(n.getMonth()+1,t,2)},M:function(n,t){return Pi(n.getMinutes(),t,2)},p:function(n){return n.getHours()>=12?\"PM\":\"AM\"},S:function(n,t){return Pi(n.getSeconds(),t,2)},U:function(n,t){return Pi(Bc.sundayOfYear(n),t,2)},w:function(n){return n.getDay()},W:function(n,t){return Pi(Bc.mondayOfYear(n),t,2)},x:ji(Qc),X:ji(nl),y:function(n,t){return Pi(n.getFullYear()%100,t,2)},Y:function(n,t){return Pi(n.getFullYear()%1e4,t,4)},Z:ao,\"%\":function(){return\"%\"}},vl={a:Oi,A:Ri,b:Zi,B:Vi,c:Xi,d:no,e:no,H:eo,I:eo,j:to,L:io,m:Qi,M:ro,p:oo,S:uo,U:Ii,w:Yi,W:Ui,x:$i,X:Bi,y:Ji,Y:Wi,Z:Gi,\"%\":co},ml=/^\\s*\\d+/,yl=mo.map({am:0,pm:1});ji.utc=lo;var Ml=lo(\"%Y-%m-%dT%H:%M:%S.%LZ\");ji.iso=Date.prototype.toISOString&&+new Date(\"2000-01-01T00:00:00.000Z\")?so:Ml,so.parse=function(n){var t=new Date(n);return isNaN(t)?null:t},so.toString=Ml.toString,Bc.second=Ci(function(n){return new Wc(1e3*Math.floor(n/1e3))},function(n,t){n.setTime(n.getTime()+1e3*Math.floor(t))},function(n){return n.getSeconds()}),Bc.seconds=Bc.second.range,Bc.seconds.utc=Bc.second.utc.range,Bc.minute=Ci(function(n){return new Wc(6e4*Math.floor(n/6e4))},function(n,t){n.setTime(n.getTime()+6e4*Math.floor(t))},function(n){return n.getMinutes()}),Bc.minutes=Bc.minute.range,Bc.minutes.utc=Bc.minute.utc.range,Bc.hour=Ci(function(n){var t=n.getTimezoneOffset()/60;return new Wc(36e5*(Math.floor(n/36e5-t)+t))},function(n,t){n.setTime(n.getTime()+36e5*Math.floor(t))},function(n){return n.getHours()}),Bc.hours=Bc.hour.range,Bc.hours.utc=Bc.hour.utc.range,Bc.month=Ci(function(n){return n=Bc.day(n),n.setDate(1),n},function(n,t){n.setMonth(n.getMonth()+t)},function(n){return n.getMonth()}),Bc.months=Bc.month.range,Bc.months.utc=Bc.month.utc.range;var xl=[1e3,5e3,15e3,3e4,6e4,3e5,9e5,18e5,36e5,108e5,216e5,432e5,864e5,1728e5,6048e5,2592e6,7776e6,31536e6],bl=[[Bc.second,1],[Bc.second,5],[Bc.second,15],[Bc.second,30],[Bc.minute,1],[Bc.minute,5],[Bc.minute,15],[Bc.minute,30],[Bc.hour,1],[Bc.hour,3],[Bc.hour,6],[Bc.hour,12],[Bc.day,1],[Bc.day,2],[Bc.week,1],[Bc.month,1],[Bc.month,3],[Bc.year,1]],_l=[[ji(\"%Y\"),Vt],[ji(\"%B\"),function(n){return n.getMonth()}],[ji(\"%b %d\"),function(n){return 1!=n.getDate()}],[ji(\"%a %d\"),function(n){return n.getDay()&&1!=n.getDate()}],[ji(\"%I %p\"),function(n){return n.getHours()}],[ji(\"%I:%M\"),function(n){return n.getMinutes()}],[ji(\":%S\"),function(n){return n.getSeconds()}],[ji(\".%L\"),function(n){return n.getMilliseconds()}]],wl=go(_l);bl.year=Bc.year,Bc.scale=function(){return fo(mo.scale.linear(),bl,wl)};var Sl={range:function(n,t,e){return mo.range(+n,+t,e).map(ho)}},El=bl.map(function(n){return[n[0].utc,n[1]]}),kl=[[lo(\"%Y\"),Vt],[lo(\"%B\"),function(n){return n.getUTCMonth()}],[lo(\"%b %d\"),function(n){return 1!=n.getUTCDate()}],[lo(\"%a %d\"),function(n){return n.getUTCDay()&&1!=n.getUTCDate()}],[lo(\"%I %p\"),function(n){return n.getUTCHours()}],[lo(\"%I:%M\"),function(n){return n.getUTCMinutes()}],[lo(\":%S\"),function(n){return n.getUTCSeconds()}],[lo(\".%L\"),function(n){return n.getUTCMilliseconds()}]],Al=go(kl);return El.year=Bc.year.utc,Bc.scale.utc=function(){return fo(mo.scale.linear(),El,Al)},mo.text=vt(function(n){return n.responseText}),mo.json=function(n,t){return mt(n,\"application/json\",po,t)},mo.html=function(n,t){return mt(n,\"text/html\",vo,t)},mo.xml=vt(function(n){return n.responseXML}),mo}();\n\n        return d3;\n    }]);\n\n\n"
  },
  {
    "path": "code/web/src/core/d3/d3.factory.module.js",
    "content": "/**\n * Created by PlayingBacon on 15.11.2016.\n */\n'use strict';\n\nangular.module('core.d3Factory', []);"
  },
  {
    "path": "code/web/src/core/node/node.module.js",
    "content": "/**\n * Created by PlayingBacon on 28.10.2016.\n */\n'use strict';\n\nangular.module('core.node', ['ngResource']);\n"
  },
  {
    "path": "code/web/src/core/node/node.service.js",
    "content": "/**\n * Created by PlayingBacon on 28.10.2016.\n */\n'use strict';\n\nangular.\n    module('core.node').\n    factory('Node', ['$resource',\n        function($resource) {\n            return $resource('nodes.json'/*'http://HOSTNAME/get_value/'*/, {}, {\n                query: {\n                    method: 'GET',\n                    //params: {nodeId: 'nodes'},\n                    isArray: true\n                }\n            });\n        }\n    ]);\n"
  },
  {
    "path": "code/web/src/core/recompile/recompile.directive.js",
    "content": "/**\n * Created by PlayingBacon on 23.11.2016.\n */\n'use strict';\n\nangular.module('core.recompile')\n    .directive('recompile', function($compile) {\n        return {\n            restrict: 'AE',\n            link: function(scope, ele, attr) {\n                /* this should watch if the state of an HTML object changes, f.e. when its inner text gets changed or\n                 * the objects attributes get changed, and, if so, call a function to compile the new HTML for Angular\n                 * execution.\n                 * In our specific case: when a value graph object gets inserted into a node it should be set up for\n                 * compilation by Angular.*/\n                scope.$watch(/*<1st param: attribute, what should be watched>, <2nd param: function, what happens if watched stuff changes state>*/);\n            }\n        }\n    });"
  },
  {
    "path": "code/web/src/core/recompile/recompile.directive.module.js",
    "content": "/**\n * Created by PlayingBacon on 23.11.2016.\n */\n'use strict';\n\nangular.module('core.recompile',[]);"
  },
  {
    "path": "code/web/src/desktop.css",
    "content": ".node {\n  width: auto;\n}\n@media only screen and (min-width: 481px) and (max-width: 600px) {\n  .node {\n    width: 48%;\n  }\n}\n@media only screen and (min-width: 601px) and (max-width: 900px) {\n  .node {\n    width: 31.33333333%;\n  }\n}\n"
  },
  {
    "path": "code/web/src/desktop.less",
    "content": ".node {\n  width: auto;\n    @media only screen and (min-width: 481px) and (max-width: 600px) {\n      width: (100%/2) - 2%;\n    }\n    @media only screen and (min-width: 601px) and (max-width: 900px) {\n      width: (100%/3) - 2%;\n    }\n}"
  },
  {
    "path": "code/web/src/failure-table/failure-table.component.js",
    "content": "/**\n * Created by PlayingBacon on 27.10.2016.\n */\n'use strict';\n\nangular.\n    module('failureTable').\n    component('failureTable', {\n        templateUrl: 'failure-table/failure-table.template.html',\n        controller: ['$http','$compile','$scope', '$interval', function FailureTableController($http,$compile,$scope,$interval) {\n            var self = this;\n            var svg = null;\n            var svgWidth = 0;\n            var svgHeight = 0;\n            var nW = 0;                 // node width, will be set in method setupNodeElements\n            var nH = 50;                // node height\n            var nC = \"white\";             // node color\n            var gap = 0;                // gap between nodes, will be set in method setupNodeElements\n            var tlPositions = [];\n            var circleLog = [];         // logs at which position there have already been drawn circles to prevent stacking them\n            var idLog = [];\n            self.startstamp = 0;         // first timestamp that appears in the timeline\n            var yProgress = 0;\n            var arrowOffset = 18;       // offset for drawing arrowheads of lines correctly\n            var eHeight = 0;            // height that gets occupied by all elements contained in the svg\n            var scale = 1000;\n            var EL_MAX = 200;           // maximum of how many elements can be present in the svg at the same time\n            var isSetup = false;\n\n            //var logInfoStore = [];\n            var colors = [\"#7cf1cb\",\"#85b9f0\",\"#ffcd83\",\"#ffad83\"];\n\n            self.nodes = [/*1, 2, 3, 4*/]; // Nodes are added dynamically.\n\n            var tlData = null;\n\n            self.pollValues = (function() {\n                if (isSetup) {\n                    clearSvg();\n                }\n                //$http.get('../example/api/v2/get_timeline/index.html').success(function(response){\n                d3.selectAll(\"span#refresh-label\")[0][0].append(\"Polling for values ...\");\n                out(\"Polling for values ...\");\n                $http.get(_API_URL+\"/api/v2/get_timeline/\").success(function(response){\n                    tlData = response;\n                    self.startstamp = tlData.timestamps.min.unix;\n                    if (!isSetup) {\n                        self.nodes = tlData.nodes;\n                        self.setupTimeline(null,false);\n                    }\n                    handleTimelineInput(tlData);\n                    drawTimeBar();\n                    d3.select(\"span#refresh-label\").html(\"\");\n                });\n\n            });\n\n            self.pollValues();\n\n            /*var promise = $interval(pollValues, 10000);\n            $scope.$on('$destroy',function(){\n                if(promise)\n                    $interval.cancel(promise);\n            });*/\n\n            self.setupTimeline = (function(data, help) {\n                d3.select(\"div#timeline\").select(\"*\").remove();\n                data = self.nodes;\n                svg = d3.select(\"div#timeline\")\n                    .append(\"svg\")\n                    .attr(\"width\",\"100%\").attr(\"height\",\"400px\");\n\n                setupSvgDefs(svg);\n\n                var minW = data.length*80;\n                var tl = d3.select(\"div#timeline\")[0][0];\n                var width = tl.offsetWidth;\n                svgWidth = maxVal(minW,width);\n                svgHeight = tl.offsetHeight;\n\n                window.onresize = (function() {\n                    var oldWidth = svgWidth;\n                    width = tl.offsetWidth;\n                    svgWidth = maxVal(minW,width);\n                    repositionSvgContent(oldWidth,svgWidth);\n                    svgHeight = tl.offsetHeight;\n                });\n                setupBackground(parseInt(svg.attr(\"height\"),10));\n                if (help) {\n                    setupHelpMeasurements(svgHeight);\n                }\n                self.setupNodeElements(svgHeight);\n                isSetup = true;\n            });\n\n            // removes everything except the defs and arrows ^-^\n            function clearSvg() {\n                //svg.selectAll(\"rect\").remove();\n                //svg.selectAll(\"text\").remove();\n                svg.selectAll(\"circle\").remove();\n                svg.selectAll(\"line:not(.nodeLine)\").remove();\n                svg.selectAll(\"text.tbLabel\").remove();\n                svg.selectAll(\"polyline\").remove();\n                svg.selectAll(\"path:not(.norem)\").remove();\n            }\n\n            function setupSvgDefs(svg) {\n                // as of now it's not possible to reference the fill color\n                // of the element from within the marker declaration\n                // http://bl.ocks.org/mbostock/1153292\n                var lel = {init: 0, propose: 1, prevote: 2, vote: 3};\n                svg.append(\"defs\").selectAll(\"marker\")\n                  .data(Object.keys(lel))\n                    .enter().append(\"marker\")\n                      .attr(\"id\", function(d) { return d + \"Arrow\"; })\n                      .attr(\"viewBox\", \"0 -5 10 10\")\n                      .attr(\"refX\", 15)\n                      .attr(\"refY\", 0)\n                      .attr(\"markerWidth\", 6)\n                      .attr(\"markerHeight\", 6)\n                      .attr(\"orient\", \"auto\")\n                    .append(\"path\")\n                      .attr(\"d\", \"M0,-5L10,0L0,5\")\n                      .attr(\"fill\", function(d) { return colors[lel[d]]; });\n            }\n\n\n            function setupBackground(svgHeight) {\n                out(\"### SVG HEIGHT FOR BG: \" +svgHeight);\n                var selection = svg.select(\"rect.svgBg\");\n                if (selection[0][0] != undefined && selection[0][0] != null) {\n                    //selection[0][0].height.baseVal.value = Math.floor(svgHeight);\n                    selection[0][0].height.baseVal.newValueSpecifiedUnits(1,svgHeight);\n                } else {\n                    svg.append(\"rect\")\n                        .attr(\"class\",\"svgBg\")\n                        .attr(\"x\",0).attr(\"y\",0)\n                        .attr(\"width\",svgWidth).attr(\"height\",svgHeight)\n                        .attr(\"fill\",\"transparent\");\n                }\n            }\n\n            self.setupNodeElements = function (svgHeight) {      //isAnim selects if node entry should be animated or not\n                var len = self.nodes.length;\n                nW = svgWidth/(len*len); // node width\n                gap = (svgWidth-(nW*len))/(len+1);  // one gap := (<width of svg> - <width of all nodes combined>) / (<number of gaps present in the svg>)\n                                                        // NOTE: every node has one gap to it's left and right\n                var y = svgHeight*0.1;\n                for (var i = 0; i < len; i++) {\n                    var x = i*nW+(i+1)*gap;\n                    svg.append(\"rect\")\n                        .attr(\"x\",x).attr(\"y\",y)\n                        .attr(\"width\",nW).attr(\"height\",nH)\n                        .attr(\"fill\",nC);\n\n                    var txtW = getTextWidth(\"Node \" +self.nodes);\n                    if (nW > txtW+10) {\n                        var text = svg.append(\"text\")\n                            .text(\"Node \" +self.nodes)\n                            .attr(\"x\",x+(nW/2-txtW/2)).attr(\"y\",(y+nH/2))\n                            .attr(\"fill\",\" #124\")\n                            .attr(\"font-family\",\"Verdana\")\n                            .attr(\"font-weight\",\"bold\");\n                    } else {\n                        txtW = getTextWidth(self.nodes[i]);\n                        var text = svg.append(\"text\")\n                            .text(self.nodes[i])\n                            .attr(\"x\",x+(nW/2-txtW/2)).attr(\"y\",(y+nH/2))\n                            .attr(\"fill\",\" #124\")\n                            .attr(\"font-family\",\"Verdana\")\n                            .attr(\"font-weight\",\"bold\");\n                    }\n\n                    tlPositions[self.nodes[i]] = x+(nW/2);\n                    yProgress = y+nH+30;\n\n                    drawNodeLine(x,y);\n                }\n\n                eHeight = nH + y;\n            };\n\n            function drawNodeLine(x,y) {\n                svg.append(\"line\")\n                    .classed(\"nodeLine\",\"true\")\n                    .attr(\"x1\",(x+(nW/2))).attr(\"y1\",y+(nH/2))\n                    .attr(\"x2\",(x+(nW/2))).attr(\"y2\",svg.attr(\"height\"))\n                    .attr(\"stroke\",nC).attr(\"stroke-width\",1).attr(\"stroke-linecap\",\"round\").attr(\"stroke-dasharray\",\"1,5\");\n            }\n\n            function handleTimelineInput(data) {\n                for (var i = 0; i < minVal(data.events.length,EL_MAX); i++) {\n                    var event = data.events[i];\n                    //var yHeight = 0;\n                    if (event.action === \"acknowledge\") {\n                        if (((event.timestamps.send.unix-self.startstamp)*scale+yProgress) >= yProgress\n                            && !(areIn(idLog,event.id.send,event.id.receive))) {\n                            drawEndLine(event);\n                        }\n                    } else {\n                        if (!(isIn(idLog,event.id.send))) {\n                            drawStartingCircle(event);\n                        }\n                    }\n                    \n                    circleLog = [];\n                }\n                //printIdLog();\n                //deOverflow();\n\n                var circles = svg.selectAll(\"circle\");\n                eHeight = circles[0][circles[0].length-1].cy.baseVal.value + 28 + 50;\n                // eHeight + (margin from last phase or nodes) + (span of two circles) + (additional margin)\n                //eHeight = eHeight + ((data.events[data.events.length-1].timestamps.receive.unix-self.startstamp)*scale-eHeight) + 28 + 50;\n                //if(eHeight > parseInt(svg.attr(\"height\"),10)) {\n                    svg.attr(\"height\",(eHeight+\"px\"));\n                    setupBackground(eHeight);\n                    var content = svg.selectAll(\"line.nodeLine\");\n                    for (var k = 0; k < self.nodes.length; k++) {\n                        var line = content[0][k];\n                        line.y2.baseVal.value = eHeight;\n                    }\n                //}\n\n                /*var circles = svg.selectAll(\"circle.new\");\n                for (var j = 0; j < circles[0].length; j++) {\n                    $compile(circles[0][j])($scope);\n                    //var cls = getAttrValue(circles[0][j],\"class\").split(\" \");\n                    //setAttrValue(circles[0][j],\"class\",(cls[0]))\n                }\n                circles.classed(\"new\",\"false\");*/\n\n            }\n\n            function drawTimeBar() {\n                svg.append(\"line\")\n                    .attr(\"x1\",svgWidth*0.05).attr(\"y1\",yProgress)\n                    .attr(\"x2\",svgWidth*0.05).attr(\"y2\",eHeight)\n                    .attr(\"stroke\",nC).attr(\"stroke-width\",2);\n                svg.append(\"text\")\n                    .text(\"ms\")\n                    .attr(\"x\",svgWidth*0.04).attr(\"y\",yProgress-5)\n                    .attr(\"fill\",\"#fff\")\n                    .attr(\"font-family\",\"Verdana\")\n                    .attr(\"font-size\",\"10pt\");\n                for (var i = 0; i < eHeight; i+=100) {\n                    svg.append(\"line\")\n                        .attr(\"x1\",svgWidth*0.04).attr(\"y1\",i+yProgress)\n                        .attr(\"x2\",svgWidth*0.05).attr(\"y2\",i+yProgress)\n                        .attr(\"stroke\",nC).attr(\"stroke-width\",1);\n                    svg.append(\"text\")\n                        .classed(\"tbLabel\",\"true\")\n                        .text(i)\n                        .attr(\"x\",svgWidth*0.06).attr(\"y\",i+yProgress+5)\n                        .attr(\"fill\",\"#fff\")\n                        .attr(\"font-family\",\"Verdana\")\n                        .attr(\"font-size\",\"10pt\");\n                }\n            }\n\n            function drawStartingCircle(event) {\n                var cy = (event.timestamps.send.unix-self.startstamp)*scale+yProgress;\n                var id_string = \"i\"+event.id.send;\n                if (!(isIn(idLog,id_string)) && cy > yProgress) {\n                    out(\"new startp circle with id \" +event.id.send);\n\n                    svg.append(\"circle\")\n                        .classed(\"action-\"+event.action, \"true\")\n                        .classed(\"type-\"+event.type, \"true\")\n                        .classed(id_string, \"true\")\n                        .attr(\"cId\",id_string)\n                        .attr(\"tSt\",\"t\"+event.timestamps.send.unix)\n                        .attr(\"cx\",tlPositions[event.nodes.send])\n                        .attr(\"cy\",cy)\n                        .attr(\"r\",7);\n\n                    idLog.push(id_string);\n                }\n\n                //var logInfoObj = {id:(\"\"+event.id.send), cx:tlPositions[event.nodes.send], cy:(event.timestamps.send.unix-self.startstamp)*scale+yProgress, timestamp:(\"\"+event.timestamps.send)};\n                //logInfoStore.push(logInfoObj);\n\n                // eHeight + (margin from last phase or nodes) + (span of two circles) + (additional margin)\n                //eHeight = eHeight + ((event.timestamps.send.unix-self.startstamp)*scale-eHeight) + 28 + 50;\n            }\n\n            function drawEndLine(event) {\n                var arrow = event.type+\"Arrow\";\n                var cy = (event.timestamps.receive.unix-self.startstamp)*scale+yProgress;\n                var id_receive_string = \"i\"+event.id.receive;\n                if (!(isIn(idLog,id_receive_string)) && cy > yProgress) {\n                    out(\"new endp circle with id \" +event.id.receive);\n                    var circle = svg.append(\"circle\")\n                            .classed(\"action-\"+event.action, \"true\").classed(\"type-\"+event.type, \"true\")\n                            .classed(\"tooltip\",\"true\").classed(id_receive_string, \"true\")\n                            .attr(\"cId\",id_receive_string)\n                            .attr(\"tSt\",\"t\"+event.timestamps.receive.unix)\n                            .attr(\"cx\",tlPositions[event.nodes.receive])\n                            .attr(\"cy\",cy)\n                            .attr(\"r\",7)\n                            // end\n                            .attr(\"data-meta\", JSON.stringify(event));\n                    $(circle).tooltipster({functionInit: tooltipContent, interactive: true, theme: ['tooltipster-punk', 'tooltipster-punk-' + event.action + '-' + event.type], trigger: 'click'});\n\n                    var x_send = tlPositions[event.nodes.send];\n                    var x_receive = tlPositions[event.nodes.receive];\n                    var y_send = (event.timestamps.send.unix-self.startstamp)*scale+yProgress;\n                    var y_receive = (event.timestamps.receive.unix-self.startstamp)*scale+yProgress;\n                    var id_send_string = \"i\"+event.id.send;\n                    if (x_send == x_receive) {\n                        // create three lines that act as one line with two 90° angles\n                        svg.append(\"polyline\")\n                            .attr(\"points\",\n                                (x_send   ) +\",\"+ y_send +\" \"+\n                                (x_send+30) +\",\"+ y_send +\" \"+\n                                (x_send+30) +\",\"+ y_receive +\" \"+\n                                (x_send   ) +\",\"+ y_receive +\" \"\n                            )\n                            .attr(\"sId\",id_send_string).attr(\"rId\",id_receive_string)\n                            .classed(\"arrow\", true).classed(\"type-\" + event.type, true)\n                            .classed(id_receive_string, \"true\").classed(id_send_string, \"true\")\n                            .attr(\"marker-end\",(\"url(#\"+arrow+\")\"));\n                    } else {\n                        svg.append(\"line\")\n                            .attr(\"sId\",id_send_string).attr(\"rId\",id_receive_string)\n                            .classed(\"arrow\", true).classed(\"type-\" + event.type, true)\n                            .classed(id_receive_string, \"true\").classed(id_send_string, \"true\")\n                            .attr(\"x1\",x_send).attr(\"y1\",y_send)\n                            .attr(\"x2\",x_receive).attr(\"y2\",y_receive)\n                            .attr(\"marker-end\",(\"url(#\"+arrow+\")\"));\n                    }\n\n                    idLog.push(id_receive_string);\n                }\n\n                // eHeight + (margin from last phase or nodes) + (span of two circles) + (additional margin)\n                //eHeight = eHeight + ((event.timestamps.receive.unix-self.startstamp)*scale-eHeight) + 28 + 50;\n            }\n\n            function repositionSvgContent(oldWidth,newWidth) {\n                //out(\"old width:\"+oldWidth+\" -> new width:\"+newWidth);\n                if (oldWidth != newWidth) {\n                    var perc = (newWidth/(oldWidth/100))/100; //percentage where 1.0 equals 100%, how many % is newWidth to oldWidth\n                    gap = gap*perc;\n                    var content = svg.selectAll(\"*:not(text)\");\n                    for (var i = 0; i < content[0].length; i++) {\n                        if (content[0][i].tagName === \"rect\") {\n                            if (content[0][i].attributes.class === undefined\n                                || !(content[0][i].attributes.class.nodeValue === \"svgBg\")) {\n                                var rect = content[0][i];\n                                rect.x.baseVal.value = rect.x.baseVal.value * perc;\n                                rect.width.baseVal.value = rect.width.baseVal.value * perc;\n                                nW = rect.width.baseVal.value;\n                            } else {\n                                var bg = content[0][i];\n                                bg.width.baseVal.value = bg.width.baseVal.value * perc;\n                            }\n                        } else if (content[0][i].tagName === \"circle\") {\n                            var circle = content[0][i];\n                            circle.cx.baseVal.value = circle.cx.baseVal.value * perc;\n                            // change cx value in log info store too!\n                            var classes = circle.attributes.class.nodeValue.split(\" \");\n                            for (var j = 0; j < classes.length; j++) {\n                                if (classes[j][0] === \"c\") {\n                                    var cid = parseInt(classes[j].split(\"_\")[1]);  //TODO: is cid not format \"i123\"?\n                                    logInfoStore[cid].cx = circle.cx.baseVal.value;  //TODO: is logInfoStore undefined?\n                                }\n                            }\n                        } else if (content[0][i].tagName === \"line\") {\n                            var line = content[0][i];\n                            if (content[0][i].attributes.class === undefined\n                                || !(content[0][i].attributes.class.nodeValue === \"nodeLine\")) {\n                                line.x1.baseVal.value = line.x1.baseVal.value * perc;\n                                line.x2.baseVal.value = line.x2.baseVal.value * perc;\n                            } else {\n                                line.x1.baseVal.value = line.x1.baseVal.value * perc;\n                                line.x2.baseVal.value = line.x2.baseVal.value * perc;\n                            }\n                        } else if (content[0][i].tagName === \"polyline\") {\n                            var polyline = content[0][i];\n                            //var classes = polyline.attributes.class.nodeValue.split(\" \");\n                            var points = polyline.attributes.points.nodeValue.split(\" \");\n                            var new_points = [];\n                            for (var j = 0; j < points.length; j++) {\n                                var coords = points[j].split(\",\");\n                                if (coords[0].length == 0) {\n                                    continue;\n                                }\n                                var new_x = parseFloat(coords[0]) * perc;\n                                if (new_x == 0 || isNaN(new_x)) {\n                                    console.log(\"new_x\", new_x)\n                                }\n                                coords[0] = \"\" + (new_x);  // change x coordinate\n                                new_points.push(coords.join(\",\"));\n                            }\n                            polyline.attributes.points.nodeValue = new_points.join(\" \");\n                        }\n                    }\n                    content = svg.selectAll(\"text\");\n                    for (var i = 0; i < content[0].length; i++) {\n                        var text = content[0][i];\n                        //var x = i*nW+(i+1)*gap;\n                        //x+(nW/2-txtW/2)\n                        if (getTextWidth((text.innerHTML.length > 1 ? text.innerHTML : \"Node \"+text.innerHTML))+10 >= nW) {\n                            text.innerHTML = delFromString(text.innerHTML,\"Node \");\n                        } else {\n                            text.innerHTML = (text.innerHTML.length > 1 ? text.innerHTML : \"Node \"+text.innerHTML);\n                        }\n                        var x = i*nW+(i+1)*gap;\n                        text.x.baseVal[0].value = x+(nW/2-getTextWidth(text.innerHTML)/2);\n                    }\n                }\n            }\n\n            function deOverflow() {\n                out(\"idLog length \" +idLog.length);\n                if (idLog.length < EL_MAX) {\n                    return;\n                } else {\n                    do {\n                        var delId = idLog.shift();\n                        svg.selectAll(\".\" + delId).remove();\n                    } while (idLog.length >= EL_MAX);\n\n                    var circles = svg.selectAll(\"circle\");\n                    var nonpoly = svg.selectAll(\"line:not(.nodeLine)\");\n                    var poly = svg.selectAll(\"polyline\");\n                    var len = maxVal(maxVal(circles[0].length,nonpoly[0].length),poly[0].length);\n                    var offset = circles[0][0].attributes[4].value-yProgress;\n                    for (var j = 0; j < len; j++) {\n                        if (j < circles[0].length) {\n                            out(\"---\\noffset:\"+offset+\"\\nold circle cy:\"+circles[0][j].cy.baseVal.value\n                                +\" ; new circle cy:\"+(circles[0][j].cy.baseVal.value-offset)+\"\\ntstmp:\"+circles[0][j].attributes[2].value+\" ; startstamp:\"+self.startstamp+\"\\n---\");\n                            circles[0][j].cy.baseVal.value = circles[0][j].cy.baseVal.value - offset;\n                            if (j === circles[0].length-1) {\n                                self.startstamp = (circles[0][j].attributes[2].value).split(\"t\")[1]; // new startstamp = tSt (timestamp) of last circle\n                            }\n                        }\n                        if (j < nonpoly[0].length) {\n                            nonpoly[0][j].y1.baseVal.value = nonpoly[0][j].y1.baseVal.value - offset;\n                            nonpoly[0][j].y2.baseVal.value = nonpoly[0][j].y2.baseVal.value - offset;\n                        }\n                        if (j < poly[0].length) {\n                            poly[0][j].points[0].y = poly[0][j].points[0].y - offset;\n                            poly[0][j].points[1].y = poly[0][j].points[1].y - offset;\n                            poly[0][j].points[2].y = poly[0][j].points[2].y - offset;\n                            poly[0][j].points[3].y = poly[0][j].points[3].y - offset;\n                        }\n                    }\n\n\n\n                    /*out(\"to high, do shifting!\");\n                    var delId = idLog.shift();\n                    var lines = svg.selectAll(\"[sId=\"+delId+\"]\");\n                    if (lines[0].length > 0) {\n                        for (var i = 0; i < lines[0].length; i++) {\n                            out(\"currently:: lines with \"+delId+\" ; deleting circles \"+lines[0][i].attributes[1].value+\" and \"+lines[0][i].attributes[2].value);\n                            svg.selectAll(\"[cId=\"+lines[0][i].attributes[1].value+\"]\").remove();\n                            svg.selectAll(\"[cId=\"+lines[0][i].attributes[2].value+\"]\").remove();\n                            lines[0][i].remove();\n                            idLog.shift();\n                        }\n                    }\n                    if (!(isIn(idLog,\"i\"+id))) {\n                        idLog.push(\"i\"+id);\n                    }*/\n                }\n            }\n\n            function getTextWidth(str) {\n                var temp = d3.select(\"body\")\n                    .append(\"svg\");\n                temp.append(\"text\").text(str).attr(\"x\",0).attr(\"y\",20).attr(\"font-family\",\"Verdana\").attr(\"font-weight\",\"bold\");\n                var tW = temp.node().getBBox().width;\n                temp.remove();\n\n                return tW;\n            }\n\n            function getAttrValue(elem,attr) {\n                for (var i = 0; i < elem.attributes.length; i++) {\n                    var splitted = elem.attributes[i].split(\"=\");\n                    if (splitted[0] === attr) {\n                        return splitted[1];\n                    }\n                }\n                return \"NOTFOUND\";\n            }\n\n            function setAttrValue(elem,attr,val) {\n                for (var i = 0; i < elem.attributes.length; i++) {\n                    if (elem.attributes[i].split(\"=\")[0] === attr) {\n                        elem.attributes[i].value = val;\n                    }\n                }\n            }\n\n            function setupHelpMeasurements(svgHeight) {\n                // setup vertical line at svg middle\n                svg.append(\"line\")\n                    .attr(\"x1\",(svgWidth/2)).attr(\"y1\",0)\n                    .attr(\"x2\",(svgWidth/2)).attr(\"y2\",svgHeight)\n                    .attr(\"stroke\",\"black\").attr(\"stroke-width\",2);\n\n                // setup horizontal line at svg relative top\n                svg.append(\"line\")\n                    .attr(\"x1\",0).attr(\"y1\",(svgHeight*0.05))\n                    .attr(\"x2\",svgWidth).attr(\"y2\",(svgHeight*0.05))\n                    .attr(\"stroke\",\"black\").attr(\"stroke-width\",2);\n\n                // add additional vertical lines with marking text to horizontal line\n                for (var i = 0; i < (svgWidth/200); i++) {\n                    svg.append(\"line\")\n                        .attr(\"x1\",(svgWidth/2-(i*100))).attr(\"y1\",(svgHeight*0.05))    // lines to the left of the middle\n                        .attr(\"x2\",(svgWidth/2-(i*100))).attr(\"y2\",(svgHeight*0.06))    // \"\n                        .attr(\"stroke\",\"black\").attr(\"stroke-width\",2);\n                    svg.append(\"text\")\n                        .text(i*100)\n                        .attr(\"x\",(svgWidth/2-(i*100))).attr(\"y\",(svgHeight*0.025))\n                        .attr(\"font-family\",\"Verdana\").attr(\"font-size\",\"10px\")\n                        .attr(\"fill\",\"black\");\n                }\n                for (var i = 1; i < (svgWidth/200); i++) {\n                    svg.append(\"line\")\n                        .attr(\"x1\",(svgWidth/2+(i*100))).attr(\"y1\",(svgHeight*0.05))    // lines to the right of the middle\n                        .attr(\"x2\",(svgWidth/2+(i*100))).attr(\"y2\",(svgHeight*0.06))    // \"\n                        .attr(\"stroke\",\"black\").attr(\"stroke-width\",2);\n                    svg.append(\"text\")\n                        .text(i*100)\n                        .attr(\"x\",(svgWidth/2+(i*100))).attr(\"y\",(svgHeight*0.025))\n                        .attr(\"font-family\",\"Verdana\").attr(\"font-size\",\"10px\")\n                        .attr(\"fill\",\"black\");\n                }\n\n                // and also setup this weird little thingie\n                // i*nW+(i+1)*gap\n                /*var len = self.nodes.length;\n                var nW = svgWidth/(len*4); // node width\n                var gap = (svgWidth-(nW*len))/(len+1);\n                for (var i = 0; i < len; i++) {\n                    var x = i*nW+(i+1)*gap;\n                    // i*nW ..\n                    svg.append(\"line\")\n                        .attr(\"x1\",(i*x)).attr(\"y1\",(svgHeight*0.25))\n                        .attr(\"x2\",(i*x)+(i*nW)).attr(\"y2\",svgHeight*0.25)\n                        .attr(\"stroke\",\"blue\").attr(\"stroke-width\",2);\n                    svg.append(\"line\")\n                        .attr(\"x1\",(i*x)).attr(\"y1\",(svgHeight*0.25))\n                        .attr(\"x2\",(i*x)).attr(\"y2\",(svgHeight*0.3))\n                        .attr(\"stroke\",\"blue\").attr(\"stroke-width\",1);\n                    svg.append(\"line\")\n                        .attr(\"x1\",(i*x)+(i*nW)).attr(\"y1\",(svgHeight*0.25))\n                        .attr(\"x2\",(i*x)+(i*nW)).attr(\"y2\",(svgHeight*0.3))\n                        .attr(\"stroke\",\"blue\").attr(\"stroke-width\",1);\n\n                    // + (i+1)*gap\n                    svg.append(\"line\")\n                        .attr(\"x1\",(i*x)+(i*nW)).attr(\"y1\",(svgHeight*0.35))\n                        .attr(\"x2\",(i*x)+(i*nW+(i+1)*gap)).attr(\"y2\",svgHeight*0.35)\n                        .attr(\"stroke\",\"orange\").attr(\"stroke-width\",2);\n                    svg.append(\"line\")\n                        .attr(\"x1\",(i*x)+(i*nW)).attr(\"y1\",(svgHeight*0.35))\n                        .attr(\"x2\",(i*x)+(i*nW)).attr(\"y2\",(svgHeight*0.4))\n                        .attr(\"stroke\",\"orange\").attr(\"stroke-width\",1);\n                    svg.append(\"line\")\n                        .attr(\"x1\",(i*x)+(i*nW+(i+1)*gap)).attr(\"y1\",(svgHeight*0.35))\n                        .attr(\"x2\",(i*x)+(i*nW+(i+1)*gap)).attr(\"y2\",(svgHeight*0.4))\n                        .attr(\"stroke\",\"orange\").attr(\"stroke-width\",1);\n                }*/\n            }\n\n            function calculateYCoordinate(startP,endP,x) {\n                // y = m*x+b\n                out(\"start-x: \" +startP.x+ \"; start-y: \" +startP.y+ \"; end-x: \" +endP.x+ \"; end-y: \" +endP.y);\n                var m = (endP.y-startP.y)/(endP.x-startP.x);\n                if (isNaN(m)) {\n                    console.log(NaN)\n                }\n                var b = startP.y - m*startP.x;\n                if (isNaN(b)) {\n                    console.log(NaN)\n                }\n                if (isNaN(m*x+b)) {\n                    console.log(NaN)\n                }\n                return (m*x+b);\n            }\n\n            function isIn(arr,val) {\n                for (var i = 0; i < arr.length; i++) {\n                    if (arr[i] === val) {\n                        return true;\n                    }\n                }\n                return false;\n            }\n\n            function areIn(arr,val1,val2) {\n                var bool1, bool2;\n                for (var i = 0; i < arr.length; i++) {\n                    bool1 = (arr[i] === val1);\n                    bool2 = (arr[i] === val2);\n                    if (bool1 && bool2) {\n                        return true;\n                    }\n                }\n                return false;\n            }\n\n            function isAtIndex(arr,val) {\n                for (var i = 0; i < arr.val; i++) {\n                    if (arr[i] === val) {\n                        return i;\n                    }\n                }\n                return undefined;\n            }\n\n            function printIdLog() {\n                out(\"length:\"+idLog.length);\n                for (var i = 0; i < idLog.length; i++) {\n                    out(\"[i:\"+i+\"]-> id:\"+idLog[i]+\"\\n\");\n                }\n            }\n\n            function minVal(n1,n2) {\n                return n1 <= n2 ? n1 : n2;\n            }\n\n            function maxVal(n1,n2) {\n                return n1 <= n2 ? n2 : n1;\n            }\n\n            function delFromString(str,substr) {\n                var res = \"\";\n                for (var i = 0; i < str.length; i++) {\n                    if (str[i] == substr[0]) {\n                        var k = i+1;\n                        for (var j = 1; j < substr.length; j++) {\n                            if (str[k] == substr[j]) {\n                                if (j == substr.length-1) {\n                                    i = k;\n                                    break;\n                                }\n                                k++;\n                            } else {\n                                break;\n                            }\n                        }\n                    } else {\n                        res = res+str[i];\n                    }\n                }\n                return res;\n            }\n\n            function printArray(array) {\n                var str = \"\";\n                for (var i = 0; i < array.length; i++) {\n                    str = str +array[i]+ \" \"\n                }\n                return str;\n            }\n\n            function out(str) {\n                console.log(str);\n            }\n        }]\n});"
  },
  {
    "path": "code/web/src/failure-table/failure-table.module.js",
    "content": "/**\n * Created by PlayingBacon on 27.10.2016.\n */\n'use strict';\n\nangular.module('failureTable', []);"
  },
  {
    "path": "code/web/src/failure-table/failure-table.template.html",
    "content": "<div id=\"failure-table\" xmlns=\"http://www.w3.org/1999/html\">\n    <h3>Timeline for Message Flow of Nodes</h3>\n    <div id=\"refresher\">\n        <button type=\"button\" ng-click=\"$ctrl.pollValues();\">REFRESH</button>\n        <span id=\"refresh-label\"></span>\n    </div>\n    <!--<span  style=\"color: black;\">\n        <button type=\"button\" ng-click=\"$ctrl.setupTimeline(null,true)\">Scale ON</button>\n        <button type=\"button\" ng-click=\"$ctrl.setupTimeline(null,false)\">Scale OFF</button>\n    </span>-->\n    <div id=\"symbology\">\n        <div class=\"top-label\">Symbols:</div>\n        <div class=\"sym-section\">\n            <div class=\"sym-label\">Init</div>\n            <div class=\"circle type-init\"></div>\n            <div class=\"circle type-init\"><div class=\"ringHole\"></div></div>\n            <div class=\"arrow\"><div class=\"shaft type-init\"></div><div class=\"head type-init\"></div></div>\n        </div>\n        <div class=\"sym-section\">\n            <div class=\"sym-label\">Pre-Prepare</div>\n            <div class=\"circle type-propose\"></div>\n            <div class=\"circle type-propose\"><div class=\"ringHole\"></div></div>\n            <div class=\"arrow\"><div class=\"shaft type-propose\"></div><div class=\"head type-propose\"></div></div>\n        </div>\n        <div class=\"sym-section\">\n            <div class=\"sym-label\">Prepare</div>\n            <div class=\"circle type-prevote\"></div>\n            <div class=\"circle type-prevote\"><div class=\"ringHole\"></div></div>\n            <div class=\"arrow\"><div class=\"shaft type-prevote\"></div><div class=\"head type-prevote\"></div></div>\n        </div>\n        <div class=\"sym-section\">\n            <div class=\"sym-label\">Commit</div>\n            <div class=\"circle type-vote\"></div>\n            <div class=\"circle type-vote\"><div class=\"ringHole\"></div></div>\n            <div class=\"arrow\"><div class=\"shaft type-vote\"></div><div class=\"head type-vote\"></div></div>\n        </div>\n    </div>\n    <div id=\"timeline\">\n        <!-- TIMELINE SLOT -->\n    </div>\n    <script>\n    var tooltipFormat = function(instance, helper, content){\n        var event = {\n            \"action\": \"acknowledge\",\n            \"type\": \"init\",\n            \"data\": {\n                \"node\": 1,\n                \"sequence_no\": 1490527259,\n                \"type\": 1,\n                \"value\": 9.888978958129883\n            },\n            \"id\": {\"receive\": 18630, \"send\": 18618},\n            \"nodes\": {\"receive\": 1, \"send\": 1},\n            \"timestamps\": {\n                \"receive\": {\"string\": \"Sun, 26 Mar 2017 11:20:59 GMT\", \"unix\": 1490527259.296773},\n                \"send\": {\"string\": \"Sun, 26 Mar 2017 11:20:59 GMT\", \"unix\": 1490527259.150057}\n            }\n        };\n        var $origin = $(helper.origin);\n        var dataOptions = $origin.attr('data-meta');\n        if (dataOptions) {\n            event = JSON.parse(dataOptions);\n        }\n\n        var html = \"<div class='node-tooltip action-\" + event.action + \" type-\" + event.type + \"'>\";\n        function add_data(data, title, key, data_wrap, data_class, newline) {\n            var element = data, orig_key = key;\n            var tree = key.split(\".\");\n            for (var i = 0; i < tree.length; i++) {\n                key = tree[i];\n                if (data.hasOwnProperty(key)) {\n                    element = data[key];\n                } else {\n                    return;\n                }\n            }\n            key = tree.join(\"-\");\n            var clazz = \"\";\n            if (data_class) {\n                clazz = \" class='\" + data_class + \"'\"\n            }\n            var wrap_open = \"<span\" + clazz + \">\", wrap_close = \"</span>\";\n            if (data_wrap) {\n                wrap_open = \"<\" + data_wrap + clazz + \">\";\n                wrap_close = \"</\" + data_wrap + \">\";\n            }\n            var new_line = \" \";\n            if (newline) {\n                new_line = \":<br>\"\n            }\n            //console.log(\"data_wrap\", data_wrap, \",\", wrap_open, wrap_close);\n\n            html += \"<p class='\" + key + \"'><label>\" + title + new_line + wrap_open + element + wrap_close + \"</label></p>\";\n        }\n        // values every node has:\n        html += \"<div class='type'><label><span>\" + event.type + \"</span> (<span>\"+ event.action + \"</span>)</div>\";\n\n        add_data(event, \"Received\", \"timestamps.receive.string\", null, \"timestamp\");\n        add_data(event.data, \"Sequence\", \"sequence_no\", \"code\");  // \"<p><label class='sequence_no'>Sequence <span>\" + data.sequence_no + \"</span></label></p>\" +\n        html += \"<p class='nodes'><label>Node <code>\" + event.nodes.send + \" &rArr; \" + event.nodes.receive + \"</code></label></p>\";\n\n        // some node have:\n        add_data(event.data, \"Value\", \"value\", \"code\", null, true);\n        add_data(event.data, \"Proposal\", \"proposal\", \"code\", null, true);\n        add_data(event.data, \"Leader\", \"leader\", \"code\");\n\n        if (event.data.hasOwnProperty(\"value_store\")) {\n            html += \"<p class='value_store'><label>Received Values:<span>\" +\n                    event.data.value_store.map(function(e){\n                        var different_sequence_no = e.sequence_no !== event.data.sequence_no;\n                        return \"<br><code class='node\" + (different_sequence_no? \" different\" : \"\") + \"' title='Node \"+ e.node + (different_sequence_no? \" - Sequence \" + e.sequence_no : \"\") + \"'>\" + e.value + \"</code>\";\n                    }).join(\", \") +\n                    \"</span></label></p>\";\n        }\n\n        html += \"</div>\";\n        return html;\n    };\n    var tooltipContent = function (instance, helper) {\n        instance.content($(tooltipFormat(instance, helper, null)));\n    };\n\n    </script>\n</div>"
  },
  {
    "path": "code/web/src/failure-table-view/failure-table-view.component.js",
    "content": "/**\n * Created by PlayingBacon on 30.10.2016.\n */\n'use strict';\n\nangular.\n    module('failureTableView').\n    component('failureTableView', {\n        templateUrl: 'failure-table-view/failure-table-view.template.html',\n        controller: function FailureTableViewController() {\n            \n        }\n});"
  },
  {
    "path": "code/web/src/failure-table-view/failure-table-view.module.js",
    "content": "'use strict';\n\nangular.module('failureTableView', ['failureTable']);"
  },
  {
    "path": "code/web/src/failure-table-view/failure-table-view.template.html",
    "content": "<!--<div style=\"width: 400px; margin: 0 auto 0 auto;\"><img src=\"resources/img/nope.gif\" alt=\"nope.avi\"></div>\n<h5 style=\"text-align: center;\">(not implemented atm, sorry)</h5>-->\n<failure-table></failure-table>\n\n"
  },
  {
    "path": "code/web/src/hover-effect.js",
    "content": "/**\n * Created by PlayingBacon on 01.11.2016.\n */\n\n/*$(document).ready(function() {\n    $('.node').hover(function() {\n        $('.click-hint').show();\n    }, function() {\n        $('.click-hint').hide();\n    });\n});*/\n\nfunction toggleDisplay(elements) {\n    var element;\n\n    elements = elements.length ? elements : [elements];\n    for (var i = 0; i < elements.length; i++) {\n        element = elements[i];\n\n        if (isHidden(element)) {\n            element.style.display = 'block';\n            //element.style.visibility = 'visible';\n        } else {\n            element.style.display = 'none';\n            //element.style.visibility = 'hidden';\n        }\n    }\n\n    function isHidden(element) {\n        return window.getComputedStyle(element, null).getPropertyValue('visibility') === 'hidden';\n    }\n}\n\nfunction getClickHintElement(element) {\n    var childs = element.childNodes;\n    for (var x in childs) {\n        if (x.classList.item(0) === 'click-hint') {\n            alert('Eyup.');\n        }\n    }\n    //return element.getElementsByClassName('click-hint')[0];\n}\n"
  },
  {
    "path": "code/web/src/index-async.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"utf-8\">\n  <link rel=\"stylesheet\" href=\"bower_components/html5-boilerplate/dist/css/normalize.css\">\n  <link rel=\"stylesheet\" href=\"bower_components/html5-boilerplate/dist/css/main.css\">\n  <style>\n    [ng-cloak] {\n      display: none;\n    }\n  </style>\n  <script src=\"bower_components/html5-boilerplate/dist/js/vendor/modernizr-2.8.3.min.js\"></script>\n  <script>\n    // include angular loader, which allows the files to load in any order\n    //@@NG_LOADER_START@@\n    // You need to run `npm run update-index-async` to inject the angular async code here\n    //@@NG_LOADER_END@@\n\n    // include a third-party async loader library\n    /*!\n     * $script.js v1.3\n     * https://github.com/ded/script.js\n     * Copyright: @ded & @fat - Dustin Diaz, Jacob Thornton 2011\n     * Follow our software http://twitter.com/dedfat\n     * License: MIT\n     */\n    !function(a,b,c){function t(a,c){var e=b.createElement(\"script\"),f=j;e.onload=e.onerror=e[o]=function(){e[m]&&!/^c|loade/.test(e[m])||f||(e.onload=e[o]=null,f=1,c())},e.async=1,e.src=a,d.insertBefore(e,d.firstChild)}function q(a,b){p(a,function(a){return!b(a)})}var d=b.getElementsByTagName(\"head\")[0],e={},f={},g={},h={},i=\"string\",j=!1,k=\"push\",l=\"DOMContentLoaded\",m=\"readyState\",n=\"addEventListener\",o=\"onreadystatechange\",p=function(a,b){for(var c=0,d=a.length;c<d;++c)if(!b(a[c]))return j;return 1};!b[m]&&b[n]&&(b[n](l,function r(){b.removeEventListener(l,r,j),b[m]=\"complete\"},j),b[m]=\"loading\");var s=function(a,b,d){function o(){if(!--m){e[l]=1,j&&j();for(var a in g)p(a.split(\"|\"),n)&&!q(g[a],n)&&(g[a]=[])}}function n(a){return a.call?a():e[a]}a=a[k]?a:[a];var i=b&&b.call,j=i?b:d,l=i?a.join(\"\"):b,m=a.length;c(function(){q(a,function(a){h[a]?(l&&(f[l]=1),o()):(h[a]=1,l&&(f[l]=1),t(s.path?s.path+a+\".js\":a,o))})},0);return s};s.get=t,s.ready=function(a,b,c){a=a[k]?a:[a];var d=[];!q(a,function(a){e[a]||d[k](a)})&&p(a,function(a){return e[a]})?b():!function(a){g[a]=g[a]||[],g[a][k](b),c&&c(d)}(a.join(\"|\"));return s};var u=a.$script;s.noConflict=function(){a.$script=u;return this},typeof module!=\"undefined\"&&module.exports?module.exports=s:a.$script=s}(this,document,setTimeout)\n\n    // load all of the dependencies asynchronously.\n    $script([\n      'bower_components/angular/angular.js',\n      'bower_components/angular-route/angular-route.js',\n      'app.js',\n      'view1/view1.js',\n      'view2/view2.js',\n      'components/version/version.js',\n      'components/version/version-directive.js',\n      'components/version/interpolate-filter.js'\n    ], function() {\n      // when all is done, execute bootstrap angular application\n      angular.bootstrap(document, ['myApp']);\n    });\n  </script>\n  <title>My AngularJS App</title>\n  <link rel=\"stylesheet\" href=\"app.css\">\n</head>\n<body ng-cloak>\n  <ul class=\"menu\">\n    <li><a href=\"#!/view1\">view1</a></li>\n    <li><a href=\"#!/view2\">view2</a></li>\n  </ul>\n\n  <div ng-view></div>\n\n  <div>Angular seed app: v<span app-version></span></div>\n\n</body>\n</html>\n"
  },
  {
    "path": "code/web/src/index.html",
    "content": "<!DOCTYPE html>\n<!--[if lt IE 7]>      <html lang=\"en\" ng-app=\"pbftGui\" class=\"no-js lt-ie9 lt-ie8 lt-ie7\"> <![endif]-->\n<!--[if IE 7]>         <html lang=\"en\" ng-app=\"pbftGui\" class=\"no-js lt-ie9 lt-ie8\"> <![endif]-->\n<!--[if IE 8]>         <html lang=\"en\" ng-app=\"pbftGui\" class=\"no-js lt-ie9\"> <![endif]-->\n<!--[if gt IE 8]><!--> <html lang=\"en\" ng-app=\"pbftGui\" class=\"no-js\"> <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n  <title>Practical Byzantine Fault Tolerance GUI</title>\n  <meta name=\"description\" content=\"\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n\n  <link rel=\"stylesheet\" href=\"/bower_components/html5-boilerplate/dist/css/normalize.css\">\n  <link rel=\"stylesheet\" href=\"/bower_components/html5-boilerplate/dist/css/main.css\">\n  <link rel=\"stylesheet\" type=\"text/css\" href=\"/bower_components/tooltipster/dist/css/tooltipster.bundle.min.css\" />\n  <link rel=\"stylesheet\" type=\"text/css\" href=\"/bower_components/tooltipster/dist/css/plugins/tooltipster/sideTip/themes/tooltipster-sideTip-punk.min.css\" />\n\n  <link rel=\"stylesheet\" type=\"text/css\" media=\"only screen and (min-width: 481px)\" href=\"desktop.css\">\n  <link rel=\"stylesheet\" type=\"text/css\" media=\"only screen and (max-width: 480px)\" href=\"mobile.css\">\n  <link rel=\"stylesheet\" href=\"app.css\">\n  <link rel=\"stylesheet\" href=\"app.animations.css\">\n\n  <!-- Scripts -->\n  <script src=\"/bower_components/jquery/dist/jquery.js\"></script>\n  <script src=\"/bower_components/html5-boilerplate/dist/js/vendor/modernizr-2.8.3.min.js\"></script>\n  <script src=\"/bower_components/angular/angular.js\"></script>\n  <script src=\"/bower_components/angular-route/angular-route.js\"></script>\n  <script src=\"/bower_components/angular-resource/angular-resource.js\"></script>\n  <script src=\"/bower_components/angular-animate/angular-animate.js\"></script>\n  <script src=\"/bower_components/d3/d3.js\"></script>\n  <script src=\"/bower_components/highcharts/highcharts.js\"></script>\n  <!--<script type=\"text/javascript\" src=\"/bower_components/tooltipster/dist/js/tooltipster.bundle.min.js\"></script><!---->\n  <script type=\"text/javascript\" src=\"/bower_components/tooltipster/dist/js/tooltipster.bundle.js\"></script><!---->\n  <!--<script type=\"text/javascript\" src=\"/bower_components/svg.js/dist/svg.min.js\"></script><!---->\n  <script type=\"text/javascript\" src=\"/bower_components/svg.js/dist/svg.js\"></script><!---->\n  <!--<script type=\"text/javascript\" src=\"/bower_components/svg.screenbbox.js/dist/svg.screenbbox.min.js\"></script><!---->\n  <script type=\"text/javascript\" src=\"/bower_components/svg.screenbbox.js/dist/svg.screenbbox.js\"></script><!---->\n  <!--<script type=\"text/javascript\" src=\"/bower_components/tooltipster/dist/js/plugins/tooltipster/SVG/tooltipster-SVG.min.js\"></script><!---->\n  <script type=\"text/javascript\" src=\"/bower_components/tooltipster/dist/js/plugins/tooltipster/SVG/tooltipster-SVG.js\"></script><!---->\n  <!-- Error handling -->\n  <!--<script src=\"https://cdn.ravenjs.com/3.9.1/angular/raven.min.js\"></script>\n  <script>Raven.config('http://c303c105f206438e8de4cfdd183d0af1@sentry.getstickers.me/7').install()</script>\n  -->\n\n  <!-- Our files -->\n  <script src=\"config.js\"></script>\n\n  <script src=\"hover-effect.js\"></script>\n  <script src=\"node-handling.js\"></script>\n  <script src=\"app.module.js\"></script>\n  <script src=\"app.config.js\"></script>\n  <script src=\"app.animations.js\"></script>\n  <script src=\"core/core.module.js\"></script>\n  <script src=\"core/node/node.module.js\"></script>\n  <script src=\"core/node/node.service.js\"></script>\n  <script src=\"core/d3/d3.factory.module.js\"></script>\n  <script src=\"core/d3/d3.factory.js\"></script>\n  <script src=\"node-list/node-list.module.js\"></script>\n  <script src=\"node-list/node-list.component.js\"></script>\n  <script src=\"value-graph/value-graph.module.js\"></script>\n  <script src=\"value-graph/value-graph.component.js\"></script>\n  <script src=\"value-graph/value-graph.d3.js\"></script>\n  <script src=\"node-list-view/node-list-view.module.js\"></script>\n  <script src=\"node-list-view/node-list-view.component.js\"></script>\n  <script src=\"failure-table/failure-table.module.js\"></script>\n  <script src=\"failure-table/failure-table.component.js\"></script>\n  <script src=\"failure-table-view/failure-table-view.module.js\"></script>\n  <script src=\"failure-table-view/failure-table-view.component.js\"></script>\n</head>\n<body>\n  <div id=\"container\">\n    <div id=\"menubar\">\n      <a href=\"#!/nodes\">Nodes</a>\n      <a href=\"#!/failures\">Timeline</a>\n    </div>\n    <div id=\"main\">\n      <!--[if lt IE 7]>\n          <p class=\"browsehappy\">You are using an <strong>outdated</strong> browser. Please <a href=\"http://browsehappy.com/\">upgrade your browser</a> to improve your experience.</p>\n      <![endif]-->\n\n      <div ng-view class=\"view-frame\"></div>\n      <!-- In production use:\n      <script src=\"//ajax.googleapis.com/ajax/libs/angularjs/x.x.x/angular.min.js\"></script>\n      -->\n    </div>\n    <div id=\"footer\">\n      <div class=\"footer-fillin\">\n        <!-- just for spacing -->\n      </div>\n      <div id=\"footer-content\">\n        (c) by <a href=\"https://github.com/luckydonald\">luckydonald</a>, PlayingBacon, KathrynJaneway. Duh. — Version: <span app-version>&lt;Unknown&gt;</span> — Made with <a href=\"https://flutterb.at/what-is-love\">love</a>.\n      </div>\n      <div class=\"footer-fillin\">\n        <!-- just for spacing -->\n      </div>\n    </div>\n  </div>\n</body>\n</html>\n"
  },
  {
    "path": "code/web/src/mobile.css",
    "content": ".node {\n  width: 100%;\n}\n.node .click-hint {\n  content: 'tap for details';\n}\n"
  },
  {
    "path": "code/web/src/mobile.less",
    "content": ".node {\n  width: 100%;\n  .click-hint {\n    content: 'tap for details';\n  }\n}\n"
  },
  {
    "path": "code/web/src/node-handling.js",
    "content": "/**\n * Created by PlayingBacon on 03.11.2016.\n */\n\nfunction handleNodeScaling(element) {\n    var classes = element.classList;\n    if (!classes.contains('clicked')) {\n        classes.add('clicked');\n    }\n    toggleBigSmall(element, getUnclickedNodes());\n    classes.remove('clicked');\n}\n\nfunction toggleBigSmall(element, otherElements) {\n    var classes = element.classList;\n    if (classes.contains('reduced')) {\n        return;\n    }\n    if (classes.contains('upscaled')) {\n        var vl = getChildByClassName(element, 'value-graph');\n        vl.removeChild(vl.getElementsByTagName(\"value-graph\")[0]);\n        classes.remove('upscaled');\n        classes.add('non-upscaled');\n        for (var i = 0; i < otherElements.length; i++) {\n            otherClasses = otherElements[i].classList;\n            if (!otherClasses.contains('reduced')) {\n                return;\n            } else {\n                otherClasses.remove('reduced');\n            }\n        }\n    } else {\n        classes.add('upscaled');\n        classes.remove('non-upscaled');\n        var vl = getChildByClassName(element, 'value-graph');\n        vl.appendChild(document.createElement(\"value-graph\"));\n        for (var i = 0; i < otherElements.length; i++) {\n            otherClasses = otherElements[i].classList;\n            if (otherClasses.contains('reduced')) {\n                return;\n            } else {\n                otherClasses.add('reduced');\n            }\n        }\n    }\n}\n\nfunction getUnclickedNodes() {\n    var nodes = document.getElementsByClassName('node');\n    var unclickedNodes = [];\n\n    for (var i = 0; i < nodes.length; i++) {\n        classes = nodes[i].classList;\n        if (classes.contains('clicked')) {\n            continue;\n        } else {\n            unclickedNodes.push(nodes[i]);\n        }\n    }\n\n    return unclickedNodes;\n}\n\nfunction toggleVisibility(element) {\n    if (element.parentNode.classList.contains('reduced')) {\n        console.log(\"reduced, don't toggle.\");\n        return;\n    } else if (!element.parentNode.classList.contains('non-upscaled')) {\n        element.style.visibility = 'hidden';\n    } else if (!element.style.length > 0) {\n        element.style.visibility = 'visible';\n    } else {\n        element.style.visibility = (element.style.visibility === 'hidden' ? 'visible' : 'hidden');\n    }\n}\n\nfunction toggleDisplay(element, defaultval) {\n    if (!element.style.length > 0) {\n        element.style.display = ''; //initialising\n        console.log('setting to default.');\n        element.style.display = defaultval;\n    } else {\n        console.log('toggling.');\n        element.style.display = (element.style.display === 'none' ? 'block' : 'none');\n    }\n}\n\nfunction toggleDisplayForChildren(parent) {\n    children = parent.childNodes;\n    for (var i = 0; i < children.length; i++) {\n        if (children[i].nodeType != 1 || children[i].classList.contains('value-graph')) {\n            continue;\n        }\n        if (!children[i].style.length > 0) {\n            children[i].style.display = 'block';\n        }\n        children[i].style.display = (children[i].style.display === 'none' ? 'block' : 'none');\n    }\n}\n\nfunction getChildByClassName(parent,className) {\n    var children = parent.childNodes;\n    var result = null;\n    for (var i = 0; i < children.length && result == null; i++) {\n        //console.log(\"element: \" +children[i]);\n        if (children[i].nodeType != 1) {\n            continue;\n        }\n        var chClasses = children[i].classList;\n        //console.log(\" > classes: \" +chClasses+ \" :: requested class name: \" +className);\n        if (chClasses.contains(className)) {\n            //console.log(\"found it!\");\n            return children[i];\n        } else {\n            //console.log(\"going deeper..\");\n            result = getChildByClassName(children[i],className);\n        }\n    }\n    return result;\n}\n"
  },
  {
    "path": "code/web/src/node-list/node-list.component.js",
    "content": "/**\n * Created by PlayingBacon on 27.10.2016.\n */\n'use strict';\n\nangular.\n    module('nodeList').\n    component('nodeList', {\n        templateUrl: 'node-list/node-list.template.html',\n        /*controller: ['Node',\n            function NodeListController(Node) {\n                this.nodes = Node.query();\n            }\n        ]*/\n        controller: ['$http','$scope','$interval', function NodeListController($http,$scope,$interval) {\n            var self = this;\n            self.summary = null;\n            self.nodes = [];\n            self.leader = -1;\n            var touched = false;\n\n            /*\n            $scope.intervalFunction = function(){\n                $timeout(function() {\n                    $scope.pollValues();\n                    $scope.intervalFunction();\n                }, 5000)\n            };\n\n            // Kick off the interval\n            $scope.intervalFunction();\n            */\n            var pollValues = function() {\n                $http.get(_API_URL+\"/api/v2/get_value/\").success(function (json) {\n                    var data = {\n                        \"summary\":  0.5,  // or null\n                        \"leader\": 1,\n                        \"nodes\": [\n                            {\"node\": \"1\", \"value\": 0.5},\n                            {\"node\": \"2\", \"value\": 0.6},\n                            {\"node\": \"5\", \"value\": 0.5},\n                            {\"node\": \"6\", \"value\": 0.5},\n                            {\"node\": \"5\", \"value\": 0.5}\n                        ]\n                    };\n                    console.log(\"JSON:\", json);\n                    data = json;\n                    touched = !touched;  // this is a flag to check if it was updated yet (?)\n\n                    self.summary = data.summary;\n                    self.leader = data.leader;\n                    for (var i = 0; i < data.nodes.length; i++) {\n                        var node = data.nodes[i];\n                        var searchedIndex;\n                        searchedIndex = searchIndex(self.nodes,node.node);  // check if already exists.\n                        if (searchedIndex == -1) {  // does not exists.\n                            self.nodes.push({\n                                id:node.node,\n                                value:node.value,\n                                name:node.id,\n                                touched:touched\n                            });\n                            console.log(\"Added\", node.node);\n                        } else {\n                            self.nodes[searchedIndex].value = node.value;\n                            self.nodes[searchedIndex].touched = touched;\n                            console.log(\"Updated\", node.node);\n                        }\n                    }\n\n                    for (var i = 0; i < self.nodes.length; i++) {\n                        if (self.nodes[i].touched != touched) {\n                            self.nodes.splice(i,1);  // delete 1 element at index i.\n                            console.log(\"Removed\", self.nodes[i].id);\n\n                        }\n                    }\n\n                    console.log(self.nodes.length);\n                    sortNodes();\n                });\n            };\n\n            var promise = $interval(pollValues, 5000);\n            $scope.$on('$destroy',function(){\n                if(promise)\n                    $interval.cancel(promise);\n            });\n\n            /*$.getJSON(url+\"/get_data/?limit=10\").done(function (json) {\n                // do stuff\n                self.nodes = [];\n                for (var node in json) {\n                    if (json.hasOwnProperty(node)) {\n                        for (var timestamp in json[node]) {\n                            if (json[node].hasOwnProperty(timestamp)) {\n                                var value=json[node][timestamp];\n                                self.nodes.push({id:node,value:value});\n                                break;\n                            }\n                        }\n                    }\n                }\n                console.log(self.nodes.length);\n                //self.nodes = json[];\n                for (var i = 0; i < self.nodes.length; i++) {\n                    console.log(\"i:\"+i+\",id:\"+self.nodes[i].id+\",value:\"+self.nodes[i].value);\n                    sortNode(i);\n                }\n            }).fail(console.error);*/\n\n            function sortNodes() {\n                /**\n                 * Sorts the nodes (in self.nodes) by their ID, ascending.\n                 */\n                for (var i = 0; i < self.nodes.length-1; i++) {\n                    for (var j = 0; j < self.nodes.length-1; j++) {\n                        if (self.nodes[j].id > self.nodes[j+1].id) {\n                            var temp = self.nodes[j];\n                            self.nodes[j] = self.nodes[j+1];\n                            self.nodes[j+1] = temp;\n                        }\n                    }\n                }\n            }\n\n            function searchIndex(arr, id) {\n                /**\n                 * searches array arr for an element with given (node) id.\n                 *\n                 * @returns Element index of array, or -1 if not found.\n                 **/\n                for (var i = 0; i < arr.length; i++) {\n                    if (arr[i].id === id) {\n                        return i;\n                    }\n                }\n                return -1;\n            }\n        }]\n    });\n"
  },
  {
    "path": "code/web/src/node-list/node-list.module.js",
    "content": "/**\n * Created by PlayingBacon on 27.10.2016.\n */\n'use strict';\n\nangular.\n    module('nodeList',[\n        'core.node',\n        'valueGraph'\n    ]);\n"
  },
  {
    "path": "code/web/src/node-list/node-list.template.html",
    "content": "<div ng-show=\"$ctrl.summary && !$ctrl.nodes.length\" class=\"no_data\">No recent events</div>\n\n<div class=\"node summary non-upscaled\">\n    <a href=\"#!/nodes/summary\">\n        <div class=\"node-main\">\n            <h3>Summary</h3>\n            <h5>Agreed value:</h5>\n            <span class=\"value\" ng-show=\"$ctrl.summary\">{{node.value}}</span>\n            <span class=\"value no_data\" ng-hide=\"$ctrl.summary\">No recent commit.</span>\n        </div>\n        <div class=\"click-hint-wrapper\">\n            <div class=\"click-hint\">click for more details</div>\n        </div>\n    </a>\n</div>\n\n<!-- NOTE: for scaling nodes insert: onclick=\"handleNodeScaling(this)\" -->\n<div ng-repeat=\"node in $ctrl.nodes\"\n     class=\"node non-upscaled {{( $ctrl.leader === node.id) ? 'leader' : ''}}\">\n    <a href=\"#!/nodes/{{node.id}}\">\n        <div class=\"node-main\">\n            <h3 class=\"id-label\">\n                Node {{node.id}} <span class=\"leader-label\" ng-show=\"{{$ctrl.leader===node.id}}\">Leader</span>\n            </h3>\n            <div class=\"overview\">\n                <h5 class=\"value-label\">\n                    Value:\n                </h5>\n                <span class=\"value\">\n                    {{node.value}}\n                </span>\n            </div>\n            <!--<div class=\"details\">\n                <div class=\"value-graph\">\n                    <value-graph></value-graph>\n                </div>\n            </div>-->\n        </div>\n        <div class=\"click-hint-wrapper\">\n            <div class=\"click-hint\">click for more details</div>\n        </div>\n    </a>\n</div>\n\n<!--\n<table>\n    <caption>\n        JSON Table\n    </caption>\n    <thead>\n        <tr>\n            <th>ID</th>\n            <th>VALUE</th>\n            <th>Leader</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr ng-repeat=\"node in $ctrl.nodes\">\n            <td>{{node.id}}</td>\n            <td>{{node.value}}</td>\n            <td>{{(node.leader == true || node.leader == false) ? node.leader : 'undefined'}}</td>\n        </tr>\n    </tbody>\n</table>\n-->\n"
  },
  {
    "path": "code/web/src/node-list-view/node-list-view.component.js",
    "content": "/**\n * Created by PlayingBacon on 30.10.2016.\n */\n'use strict';\n\nangular.\n    module('nodeListView').\n    component('nodeListView', {\n        templateUrl: 'node-list-view/node-list-view.template.html',\n        controller: function NodeListViewController() {\n            \n        }\n});\n"
  },
  {
    "path": "code/web/src/node-list-view/node-list-view.module.js",
    "content": "'use strict';\n\nangular.module('nodeListView', ['nodeList']);"
  },
  {
    "path": "code/web/src/node-list-view/node-list-view.template.html",
    "content": "<div id=\"nodearea\">\n    <node-list class=\"node-list\"></node-list>\n</div>"
  },
  {
    "path": "code/web/src/nodes.json",
    "content": "[{\n\t\"id\": 1,\n\t\"value\": 0.5,\n\t\"leader\": true\n}, {\n\t\"id\": 2,\n\t\"value\": 0.6,\n\t\"leader\": false\n}, {\n\t\"id\": 3,\n\t\"value\": 0.5,\n\t\"leader\": false\n}, {\n\t\"id\": 4,\n\t\"value\": 0.5,\n\t\"leader\": false\n}, {\n\t\"id\": 5,\n\t\"value\": 0.5,\n\t\"leader\": false\n}, {\n\t\"id\": 6,\n\t\"value\": 0.5,\n\t\"leader\": false\n}, {\n\t\"id\": 7,\n\t\"value\": 0.8,\n\t\"leader\": false\n}, {\n\t\"id\": 8,\n\t\"value\": 0.5,\n\t\"leader\": false\n}, {\n\t\"id\": \"summary\",\n\t\"value\": 0.5\n}]"
  },
  {
    "path": "code/web/src/test_timeline.json",
    "content": "{\n  \"events\": [\n    {\n      \"action\": \"send\",\n      \"data\": {\n        \"node\": 4,\n        \"sequence_no\": 148847745,\n        \"type\": 1,\n        \"value\": 7.63133525848389\n      },\n      \"id\": {\n        \"send\": 126277\n      },\n      \"nodes\": {\n        \"send\": 4\n      },\n      \"timestamps\": {\n        \"send\": {\n          \"string\": \"Thu, 02 Mar 2017 17:57:30 GMT\",\n          \"unix\": 1488477450.563605\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 4,\n        \"sequence_no\": 148847745,\n        \"type\": 1,\n        \"value\": 7.631335258483887\n      },\n      \"id\": {\n        \"receive\": 126278,\n        \"send\": 126277\n      },\n      \"nodes\": {\n        \"receive\": 4,\n        \"send\": 4\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Thu, 02 Mar 2017 17:57:30 GMT\",\n          \"unix\": 1488477450.576458\n        },\n        \"send\": {\n          \"string\": \"Thu, 02 Mar 2017 17:57:30 GMT\",\n          \"unix\": 1488477450.563605\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"send\",\n      \"data\": {\n        \"node\": 3,\n        \"sequence_no\": 148847745,\n        \"type\": 1,\n        \"value\": 1.97469127178192\n      },\n      \"id\": {\n        \"send\": 126279\n      },\n      \"nodes\": {\n        \"send\": 3\n      },\n      \"timestamps\": {\n        \"send\": {\n          \"string\": \"Thu, 02 Mar 2017 17:57:30 GMT\",\n          \"unix\": 1488477450.680981\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 4,\n        \"sequence_no\": 148847745,\n        \"type\": 1,\n        \"value\": 7.631335258483887\n      },\n      \"id\": {\n        \"receive\": 126280,\n        \"send\": 126277\n      },\n      \"nodes\": {\n        \"receive\": 2,\n        \"send\": 4\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Thu, 02 Mar 2017 17:57:30 GMT\",\n          \"unix\": 1488477450.698291\n        },\n        \"send\": {\n          \"string\": \"Thu, 02 Mar 2017 17:57:30 GMT\",\n          \"unix\": 1488477450.563605\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 4,\n        \"sequence_no\": 148847745,\n        \"type\": 1,\n        \"value\": 7.631335258483887\n      },\n      \"id\": {\n        \"receive\": 126281,\n        \"send\": 126277\n      },\n      \"nodes\": {\n        \"receive\": 1,\n        \"send\": 4\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Thu, 02 Mar 2017 17:57:30 GMT\",\n          \"unix\": 1488477450.714077\n        },\n        \"send\": {\n          \"string\": \"Thu, 02 Mar 2017 17:57:30 GMT\",\n          \"unix\": 1488477450.563605\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 4,\n        \"sequence_no\": 148847745,\n        \"type\": 1,\n        \"value\": 7.631335258483887\n      },\n      \"id\": {\n        \"receive\": 126282,\n        \"send\": 126277\n      },\n      \"nodes\": {\n        \"receive\": 3,\n        \"send\": 4\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Thu, 02 Mar 2017 17:57:30 GMT\",\n          \"unix\": 1488477450.724045\n        },\n        \"send\": {\n          \"string\": \"Thu, 02 Mar 2017 17:57:30 GMT\",\n          \"unix\": 1488477450.563605\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 3,\n        \"sequence_no\": 148847745,\n        \"type\": 1,\n        \"value\": 1.9746912717819214\n      },\n      \"id\": {\n        \"receive\": 126283,\n        \"send\": 126279\n      },\n      \"nodes\": {\n        \"receive\": 4,\n        \"send\": 3\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Thu, 02 Mar 2017 17:57:30 GMT\",\n          \"unix\": 1488477450.735215\n        },\n        \"send\": {\n          \"string\": \"Thu, 02 Mar 2017 17:57:30 GMT\",\n          \"unix\": 1488477450.680981\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"send\",\n      \"data\": {\n        \"node\": 2,\n        \"sequence_no\": 148847745,\n        \"type\": 1,\n        \"value\": 0.883936822414398\n      },\n      \"id\": {\n        \"send\": 126284\n      },\n      \"nodes\": {\n        \"send\": 2\n      },\n      \"timestamps\": {\n        \"send\": {\n          \"string\": \"Thu, 02 Mar 2017 17:57:30 GMT\",\n          \"unix\": 1488477450.751479\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 3,\n        \"sequence_no\": 148847745,\n        \"type\": 1,\n        \"value\": 1.9746912717819214\n      },\n      \"id\": {\n        \"receive\": 126285,\n        \"send\": 126279\n      },\n      \"nodes\": {\n        \"receive\": 2,\n        \"send\": 3\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Thu, 02 Mar 2017 17:57:30 GMT\",\n          \"unix\": 1488477450.761778\n        },\n        \"send\": {\n          \"string\": \"Thu, 02 Mar 2017 17:57:30 GMT\",\n          \"unix\": 1488477450.680981\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 3,\n        \"sequence_no\": 148847745,\n        \"type\": 1,\n        \"value\": 1.9746912717819214\n      },\n      \"id\": {\n        \"receive\": 126286,\n        \"send\": 126279\n      },\n      \"nodes\": {\n        \"receive\": 1,\n        \"send\": 3\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Thu, 02 Mar 2017 17:57:30 GMT\",\n          \"unix\": 1488477450.780048\n        },\n        \"send\": {\n          \"string\": \"Thu, 02 Mar 2017 17:57:30 GMT\",\n          \"unix\": 1488477450.680981\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 3,\n        \"sequence_no\": 148847745,\n        \"type\": 1,\n        \"value\": 1.9746912717819214\n      },\n      \"id\": {\n        \"receive\": 126287,\n        \"send\": 126279\n      },\n      \"nodes\": {\n        \"receive\": 3,\n        \"send\": 3\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Thu, 02 Mar 2017 17:57:30 GMT\",\n          \"unix\": 1488477450.796575\n        },\n        \"send\": {\n          \"string\": \"Thu, 02 Mar 2017 17:57:30 GMT\",\n          \"unix\": 1488477450.680981\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 2,\n        \"sequence_no\": 148847745,\n        \"type\": 1,\n        \"value\": 0.8839368224143982\n      },\n      \"id\": {\n        \"receive\": 126288,\n        \"send\": 126284\n      },\n      \"nodes\": {\n        \"receive\": 4,\n        \"send\": 2\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Thu, 02 Mar 2017 17:57:30 GMT\",\n          \"unix\": 1488477450.809868\n        },\n        \"send\": {\n          \"string\": \"Thu, 02 Mar 2017 17:57:30 GMT\",\n          \"unix\": 1488477450.751479\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 2,\n        \"sequence_no\": 148847745,\n        \"type\": 1,\n        \"value\": 0.8839368224143982\n      },\n      \"id\": {\n        \"receive\": 126289,\n        \"send\": 126284\n      },\n      \"nodes\": {\n        \"receive\": 2,\n        \"send\": 2\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Thu, 02 Mar 2017 17:57:30 GMT\",\n          \"unix\": 1488477450.827377\n        },\n        \"send\": {\n          \"string\": \"Thu, 02 Mar 2017 17:57:30 GMT\",\n          \"unix\": 1488477450.751479\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 2,\n        \"sequence_no\": 148847745,\n        \"type\": 1,\n        \"value\": 0.8839368224143982\n      },\n      \"id\": {\n        \"receive\": 126290,\n        \"send\": 126284\n      },\n      \"nodes\": {\n        \"receive\": 1,\n        \"send\": 2\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Thu, 02 Mar 2017 17:57:30 GMT\",\n          \"unix\": 1488477450.845287\n        },\n        \"send\": {\n          \"string\": \"Thu, 02 Mar 2017 17:57:30 GMT\",\n          \"unix\": 1488477450.751479\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 2,\n        \"sequence_no\": 148847745,\n        \"type\": 1,\n        \"value\": 0.8839368224143982\n      },\n      \"id\": {\n        \"receive\": 126291,\n        \"send\": 126284\n      },\n      \"nodes\": {\n        \"receive\": 3,\n        \"send\": 2\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Thu, 02 Mar 2017 17:57:30 GMT\",\n          \"unix\": 1488477450.861022\n        },\n        \"send\": {\n          \"string\": \"Thu, 02 Mar 2017 17:57:30 GMT\",\n          \"unix\": 1488477450.751479\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"send\",\n      \"data\": {\n        \"node\": 1,\n        \"sequence_no\": 148847745,\n        \"type\": 1,\n        \"value\": 0.957314074039459\n      },\n      \"id\": {\n        \"send\": 126292\n      },\n      \"nodes\": {\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"send\": {\n          \"string\": \"Thu, 02 Mar 2017 17:57:31 GMT\",\n          \"unix\": 1488477451.097073\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 1,\n        \"sequence_no\": 148847745,\n        \"type\": 1,\n        \"value\": 0.9573140740394592\n      },\n      \"id\": {\n        \"receive\": 126293,\n        \"send\": 126292\n      },\n      \"nodes\": {\n        \"receive\": 1,\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Thu, 02 Mar 2017 17:57:31 GMT\",\n          \"unix\": 1488477451.116111\n        },\n        \"send\": {\n          \"string\": \"Thu, 02 Mar 2017 17:57:31 GMT\",\n          \"unix\": 1488477451.097073\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 1,\n        \"sequence_no\": 148847745,\n        \"type\": 1,\n        \"value\": 0.9573140740394592\n      },\n      \"id\": {\n        \"receive\": 126294,\n        \"send\": 126292\n      },\n      \"nodes\": {\n        \"receive\": 2,\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Thu, 02 Mar 2017 17:57:31 GMT\",\n          \"unix\": 1488477451.122682\n        },\n        \"send\": {\n          \"string\": \"Thu, 02 Mar 2017 17:57:31 GMT\",\n          \"unix\": 1488477451.097073\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 1,\n        \"sequence_no\": 148847745,\n        \"type\": 1,\n        \"value\": 0.9573140740394592\n      },\n      \"id\": {\n        \"receive\": 126295,\n        \"send\": 126292\n      },\n      \"nodes\": {\n        \"receive\": 4,\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Thu, 02 Mar 2017 17:57:31 GMT\",\n          \"unix\": 1488477451.128667\n        },\n        \"send\": {\n          \"string\": \"Thu, 02 Mar 2017 17:57:31 GMT\",\n          \"unix\": 1488477451.097073\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"node\": 1,\n        \"sequence_no\": 148847745,\n        \"type\": 1,\n        \"value\": 0.9573140740394592\n      },\n      \"id\": {\n        \"receive\": 126296,\n        \"send\": 126292\n      },\n      \"nodes\": {\n        \"receive\": 3,\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Thu, 02 Mar 2017 17:57:31 GMT\",\n          \"unix\": 1488477451.134851\n        },\n        \"send\": {\n          \"string\": \"Thu, 02 Mar 2017 17:57:31 GMT\",\n          \"unix\": 1488477451.097073\n        }\n      },\n      \"type\": \"init\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 1,\n        \"proposal\": 3.57743239402771,\n        \"sequence_no\": 148847745,\n        \"type\": 2,\n        \"value_store\": [\n          {\n            \"node\": 1,\n            \"sequence_no\": 148847744,\n            \"type\": 1,\n            \"value\": 1.2020764350891113\n          },\n          {\n            \"node\": 2,\n            \"sequence_no\": 148847744,\n            \"type\": 1,\n            \"value\": 5.357077121734619\n          },\n          {\n            \"node\": 3,\n            \"sequence_no\": 148847744,\n            \"type\": 1,\n            \"value\": 3.57743239402771\n          },\n          {\n            \"node\": 4,\n            \"sequence_no\": 148847744,\n            \"type\": 1,\n            \"value\": 5.470797538757324\n          }\n        ]\n      },\n      \"id\": {\n        \"receive\": 126297,\n        \"send\": 126299\n      },\n      \"nodes\": {\n        \"receive\": 4,\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Thu, 02 Mar 2017 17:57:31 GMT\",\n          \"unix\": 1488477451.177011\n        },\n        \"send\": {\n          \"string\": \"Thu, 02 Mar 2017 17:57:31 GMT\",\n          \"unix\": 1488477451.190611\n        }\n      },\n      \"type\": \"propose\"\n    },\n    {\n      \"action\": \"acknowledge\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 1,\n        \"proposal\": 3.57743239402771,\n        \"sequence_no\": 148847745,\n        \"type\": 2,\n        \"value_store\": [\n          {\n            \"node\": 1,\n            \"sequence_no\": 148847744,\n            \"type\": 1,\n            \"value\": 1.2020764350891113\n          },\n          {\n            \"node\": 2,\n            \"sequence_no\": 148847744,\n            \"type\": 1,\n            \"value\": 5.357077121734619\n          },\n          {\n            \"node\": 3,\n            \"sequence_no\": 148847744,\n            \"type\": 1,\n            \"value\": 3.57743239402771\n          },\n          {\n            \"node\": 4,\n            \"sequence_no\": 148847744,\n            \"type\": 1,\n            \"value\": 5.470797538757324\n          }\n        ]\n      },\n      \"id\": {\n        \"receive\": 126298,\n        \"send\": 126299\n      },\n      \"nodes\": {\n        \"receive\": 3,\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"receive\": {\n          \"string\": \"Thu, 02 Mar 2017 17:57:31 GMT\",\n          \"unix\": 1488477451.184246\n        },\n        \"send\": {\n          \"string\": \"Thu, 02 Mar 2017 17:57:31 GMT\",\n          \"unix\": 1488477451.190611\n        }\n      },\n      \"type\": \"propose\"\n    },\n    {\n      \"action\": \"send\",\n      \"data\": {\n        \"leader\": 1,\n        \"node\": 1,\n        \"proposal\": 3.57743239402771,\n        \"sequence_no\": 148847745,\n        \"type\": 2,\n        \"value_store\": [\n          {\n            \"node\": 1,\n            \"sequence_no\": 148847744,\n            \"type\": 1,\n            \"value\": 1.2020764350891113\n          },\n          {\n            \"node\": 2,\n            \"sequence_no\": 148847744,\n            \"type\": 1,\n            \"value\": 5.357077121734619\n          },\n          {\n            \"node\": 3,\n            \"sequence_no\": 148847744,\n            \"type\": 1,\n            \"value\": 3.57743239402771\n          },\n          {\n            \"node\": 4,\n            \"sequence_no\": 148847744,\n            \"type\": 1,\n            \"value\": 5.470797538757324\n          }\n        ]\n      },\n      \"id\": {\n        \"send\": 126299\n      },\n      \"nodes\": {\n        \"send\": 1\n      },\n      \"timestamps\": {\n        \"send\": {\n          \"string\": \"Thu, 02 Mar 2017 17:57:31 GMT\",\n          \"unix\": 1488477451.190611\n        }\n      },\n      \"type\": \"propose\"\n    }\n  ],\n  \"nodes\": [\n    1,\n    2,\n    3,\n    4\n  ],\n  \"timestamps\": {\n    \"max\": {\n      \"string\": \"Thu, 02 Mar 2017 17:57:31 GMT\",\n      \"unix\": 1488477451.190611\n    },\n    \"min\": {\n      \"string\": \"Thu, 02 Mar 2017 17:57:30 GMT\",\n      \"unix\": 1488477450.563605\n    }\n  }\n}"
  },
  {
    "path": "code/web/src/value-graph/value-graph.component.js",
    "content": "/**\n * Created by PlayingBacon on 07.11.2016.\n */\n'use strict';\n\nangular.\n    module('valueGraph').\n    component('valueGraph', {\n        templateUrl: 'value-graph/value-graph.template.html',\n        bindings: {\n            nodeid: '='\n        },\n        controller: ['$http','$scope','$interval', function ValueGraphController($http,$scope,$interval) {\n            var self = this;\n            self.nodeData = {};\n            var myChart = null;\n            self.series = null;\n\n            var pollGraphs = function() {\n                var url;\n                if (self.nodeid === 'summary' || self.nodeid == undefined) {\n                    url = _API_URL + \"/get_data/?limit=40\";\n                } else {\n                    url = _API_URL + \"/get_data/?limit=10&node=\"+self.nodeid;\n                }\n\n                $http.get(url).then(function (json) {\n                    for (var node in json.data) {\n                        if (json.data.hasOwnProperty(node)) {\n                            self.nodeData[node] = [];\n                            for (var timestamp in json.data[node]) {\n                                if (json.data[node].hasOwnProperty(timestamp)) {\n                                    var value=json.data[node][timestamp];\n                                    self.nodeData[node][self.nodeData[node].length] = {timestamp:timestamp,value:value};\n                                }\n                            }\n                        }\n                    }\n                    if (myChart == null) {\n                        constructVG(self.nodeData);\n                    }\n                    drawGraphs(self.nodeData);\n                }, function(json) {\n                    out(\"Yeah, that did not work, at all.\");\n                }, function(json) {\n                    out(\"What does this even do?\");\n                })\n            };\n\n            var promise = $interval(pollGraphs, 5000);\n            $scope.$on('$destroy',function(){\n                if(promise)\n                    $interval.cancel(promise);\n            });\n\n            out(\"data outer :: \" +self.nodeData);\n\n            function dataToValues(nodeData){\n                var list = [];\n                for (var node in nodeData) {\n                    if (!nodeData.hasOwnProperty(node)) {\n                        continue;\n                    }\n                    list[list.length] = {\n                        name: 'Node ' + node,\n                        data: [nodeData[node]]\n                    }\n                }\n                return list;\n            }\n\n            function constructVG(data) {\n                console.log(\"CONSTRUCT STUFF: \",data);\n                setHighchartsTheme();\n                var chart_data = dataToValues(data);\n                myChart = Highcharts.chart('value-graph-container', {\n                    chart: {\n                        type: 'spline',\n                        events: {\n                            load: function() {\n                                self.series = this.series;\n                            }\n                        }\n                    },\n                    title: {\n                        text: 'Values over Time'\n                    },\n                    xAxis: {\n                        type: 'datetime',\n                        title: {\n                            text: 'time'\n                        }\n                    },\n                    yAxis: {\n                        title: {\n                            text: 'values'\n                        }\n                    },\n                    series: chart_data\n                });\n                d3.select(\"text.highcharts-credits\").remove();\n\n                /*var svg = d3.select(\"div.value-graph\")\n                    .append(\"svg\")\n                    .attr(\"width\", \"100%\")\n                    .attr(\"height\", \"100%\")\n                    .attr(\"preserveAspectRatio\",\"xMidYMin\");\n\n                var vg = d3.select(\"div.value-graph\")[0][0];\n                var max = data.length;\n                var width = vg.offsetWidth;\n                var height = vg.offsetHeight;\n                out(\"### MEASUREMENTS :: width \" +width+ \" height \" +height+ \" max \" +max);\n\n                window.onresize = (function(){\n                    width = vg.offsetWidth;\n                    height = vg.offsetHeight;\n                    drawGraphs(null);\n                    console.log(\"resize!\");\n                });*/\n\n                /*var xScale = d3.scale.linear()\n                    .domain([0,d3.max()])\n                    .range();\n                var yScale = d3.scale.linear()\n                    .domain()\n                    .range();*/\n            }\n\n            function drawGraphs(nodes) {\n                for (var node in nodes) {\n                    var d = [];\n                    for (var i = 0; i < nodes[node].length; i++) {\n                        var date = new Date(parseInt(nodes[node][i].timestamp,10)*1000);\n                        d[i] = [date, nodes[node][i].value];\n                    }\n                    for (var i = 0; i < self.series.length; i++) {\n                        if (self.series[i].name === 'Node ' + node) {\n                            self.series[i].update({data: d}, true);\n                        }\n                    }\n                }\n\n                /*svg.selectAll(\"*\").remove();\n                svg.append(\"rect\").attr(\"width\",width).attr(\"height\",height).attr(\"fill\",\"blue\");\n                svg.selectAll(\"circle\")\n                    .data(data)\n                    .enter()\n                    .append(\"circle\")\n                    .attr(\"cx\", function(d,i){return i*(width/max)+((width/2)/max);})\n                    .attr(\"cy\", function(){return height/2;})\n                    .attr(\"r\", function(d){return d.value*30;})\n                    .attr(\"fill\", \"white\");\n                */\n                /*var lineFunction = d3.svg.line()\n                    .x(function(d){return d.x;})\n                    .y(function(d){return d.y;})\n                    .interpolate(\"linear\");\n\n                svg.selectAll(\"*\").remove();\n                svg.append(\"rect\").attr(\"width\",width).attr(\"height\",height).attr(\"fill\",\"blue\");\n                svg.append(\"path\")\n                    .attr(\"d\", lineFunction(data))\n                    .attr(\"stroke\", \"black\")\n                    .attr(\"stroke-width\", 2)\n                    .attr(\"fill\", \"none\");\n                */\n            }\n\n            function setHighchartsTheme() {\n                Highcharts.theme = {\n                    colors: ['#ffffff', '#fff3e2', '#ffcd83', '#ffad32', 'ffa51f', '#ff0066', '#eeaaee',\n                        '#55BF3B', '#DF5353', '#7798BF', '#aaeeee'],\n                    chart: {\n                        backgroundColor: 'transparent',\n                        style: {\n                            fontFamily: '\\'Unica One\\', sans-serif'\n                        },\n                        plotBorderColor: '#606063'\n                    },\n                    title: {\n                        style: {\n                            color: '#124',\n                            fontSize: '20px'\n                        }\n                    },\n                    subtitle: {\n                        style: {\n                            color: '#323d51'\n                        }\n                    },\n                    xAxis: {\n                        gridLineColor: '#323d51',\n                        labels: {\n                            style: {\n                                color: '#124'\n                            }\n                        },\n                        lineColor: '#323d51',\n                        minorGridLineColor: '#124',\n                        tickColor: '#323d51',\n                        title: {\n                            style: {\n                                color: '#124'\n\n                            }\n                        }\n                    },\n                    yAxis: {\n                        gridLineColor: '#323d51',\n                        labels: {\n                            style: {\n                                color: '#124'\n                            }\n                        },\n                        lineColor: '#323d51',\n                        minorGridLineColor: '#124',\n                        tickColor: '#323d51',\n                        tickWidth: 1,\n                        title: {\n                            style: {\n                                color: '#124'\n                            }\n                        }\n                    },\n                    tooltip: {\n                        backgroundColor: '#124',\n                        style: {\n                            color: '#F0F0F0'\n                        }\n                    }\n                };\n\n                // Apply the theme\n                Highcharts.setOptions(Highcharts.theme);\n            }\n\n            // I'm a lazy fuck.\n            function out(str) {\n                console.log(str);\n            }\n        }]\n    });\n"
  },
  {
    "path": "code/web/src/value-graph/value-graph.d3.js",
    "content": "/**\n * Created by PlayingBacon on 15.11.2016.\n */\n'use strict';\n\nangular.\n    module('valueGraph').\n    component('valueGraphD3', {\n        template: '',\n        bindings: {\n            data: '='\n        },\n        controller: ['d3Factory', '$http', function ValueGraphD3Controller(d3, $http) {\n            \n        }]\n});"
  },
  {
    "path": "code/web/src/value-graph/value-graph.module.js",
    "content": "/**\n * Created by PlayingBacon on 07.11.2016.\n */\n'use strict';\n\nangular.module('valueGraph',[\n    'core.d3Factory',\n    'nodeList'\n]);\n"
  },
  {
    "path": "code/web/src/value-graph/value-graph.template.html",
    "content": "<div id=\"nodearea\">\n    <div class=\"node upscaled {{( node.leader == true) ? 'leader' : ''}}\">\n        <a href=\"#!/nodes\">\n            <div class=\"node-main\">\n                <h3 class=\"id-label\">\n                    Node {{($ctrl.nodeid == undefined ? 'Summary' : $ctrl.nodeid)}} <span class=\"leader-label\" ng-show=\"{{node.leader}}\">Leader</span>\n                </h3>\n                <div class=\"details\">\n                    <div id=\"value-graph-container\" class=\"value-graph\">\n                        <!-- VALUE GRAPH SLOT -->\n                    </div>\n                </div>\n            </div>\n        </a>\n        <!--<button type=\"button\" ng-click=\"$ctrl.decrement()\">-</button>\n        <button type=\"button\" ng-click=\"$ctrl.increment()\">+</button>-->\n    </div>\n</div>"
  },
  {
    "path": "code/web/styles.css",
    "content": "body {\n    background-color: darkgrey;\n    margin: 0;\n    font-family: \"Lucida Sans Unicode\",\"Lucida Grande\",sans-serif;\n}\n\nh3, h5 {\n    font-variant: small-caps;\n    margin-bottom: 0px;\n}\n\n#container {\n    width: 100%;\n    min-width: 550px;\n    height: 98vh;\n    margin: 0 auto 0 auto;\n    background-color: black;\n    border-style: solid;\n    border-color: transparent;\n    border-width: 2vh 0vh 0vh 0vh;\n}\n\n#menubar {\n    width: 40%;\n    height: 5%;\n    margin: 0 auto 0 auto;\n    color: aliceblue;\n    display: table;\n    border-spacing: 10px 0px;\n}\n\n#main {\n    width: 100%;\n    height: 90%;\n    margin: 0% auto 0% auto;\n    background-color: #124;\n    overflow: hidden;\n}\n\n#nodearea {\n\n}\n\n#footer {\n    width: 100%;\n    height: 5%;\n    margin: 0% auto 0% auto;\n    text-align: center;\n    background-color: gold;\n}\n\n.menuitem {\n    text-align: center;\n    display: table-cell;\n    vertical-align: middle;\n    width: 44%;\n    font-size: 0.7em;\n    height: 100%;\n    margin: 0 3% 0 3%;\n    border-width: 0 5px 0 5px;\n    background-color: #124;\n    border-radius: 7px 7px 0 0;\n}\n\n.node {\n    float: left;\n    text-align: center;\n    width: 15%;\n    height: 18%;\n    margin: 3% 1% 1% 1%;\n    padding: 1%;\n    background-color: cornflowerblue;\n    border-color: transparent;\n    border-radius: 0.5em;\n    border-width: 0 5px 0 5px;\n    border-style: solid;\n}\n\n.node:hover {\n    background-color: #1972ff;\n}\n\n.node.primary {\n    border-color: cadetblue;\n}\n\n.node.primary:hover {\n    border-color: #7cf1ca;\n}\n\n.primary-label {\n    font-style: italic;\n    color: midnightblue;\n}\n\n.primary-edge {\n    width: 0;\n    height: 0;\n\n}\n\n.node.summary {\n    background-color: cadetblue;\n    color: white;\n}\n\n.node.summary:hover {\n    background-color: #7cf1ca;\n    color: black;\n}\n\n.value {\n\n}"
  },
  {
    "path": "docker-compose.yml",
    "content": "version: '2'\nservices:\n  # # Python node\n  # node:\n  #   extends:\n  #     file: node.docker-compose.yml\n  #     service: node\n  #   volumes:\n  #     - /var/run/docker.sock:/var/run/docker.sock\n  #   environment:\n  #     NODE_DEBUGGER: \"False\"\n  #\n  #  # entrypoint: [\"/bin/bash\"]\n  #\n  #  #  docker run -ti --entrypoint /bin/bash 9b6a81855c06\n  #  #  d-c run --entrypoint /bin/bash node-3\n  #  #  NODE_ID=3 NODE_TOTAL=4 POSSIBLE_FAILURES=1 NODE_HOST=teamproject16_node-{i}_1 NODE_PORT=4458 python main_node.py\n\n  node:\n    extends:\n      file: code/node_java/docker-compose.yml\n      service: node_java\n    volumes:\n      - /var/run/docker.sock:/var/run/docker.sock\n    environment:\n      NODE_DEBUGGER: \"False\"\n      NODE_DEBUG: \"False\"\n      # API_HOST: \"http://192.168.0.42\"\n      API_HOST: ${API_HOST}\n\n  api:\n    extends:\n      file: api.docker-compose.yml\n      service: api\n    ports:\n     - \"80:80\"\n    restart: \"no\"\n    command: [\"python\", \"main_api.py\"]\n\n    #entrypoint: []\n    #command: [\"ls\", \"-la\"]\n\n  web:\n    extends:\n      file: code/web/docker-compose.yml\n      service: web\n    environment:\n      PORT: 8000\n      # API_URL: \"http://192.168.0.42\"\n      API_URL: ${API_HOST}\n    ports:\n     - \"8000:8000\"\n    entrypoint: [\"/entrypoint.sh\"]\n\n  web_static:\n    extends:\n      file: code/web/docker-compose.yml\n      service: web\n    environment:\n      PORT: 8001\n      API_URL: \"http://localhost:8001/example/\"\n      # `${VM_HOST:-localhost}` will evaluate to `localhost` if $VM_HOST is unset or empty in the environment.\n    ports:\n     - \"8001:8001\"\n    entrypoint: [\"/entrypoint.sh\"]\n\n\n\n  postgres:\n    extends:\n      file: api.docker-compose.yml\n      service: postgres\n    #volumes:\n    #  - /data/postgres:/data/postgres\n\n\n  postgres_browser:\n    extends:\n      file: api.docker-compose.yml\n      service: postgres_browser\n    ports:\n     - \"8080:80\""
  },
  {
    "path": "node.docker-compose.yml",
    "content": "version: '2'\nservices:\n  node:\n    build:\n      context: .\n      dockerfile: ./Dockerfile\n    command: [\"main_node.py\"]\n    environment:\n      DOCKER_CACHING_TIME: 5\n      NODE_PORT: 4458\n      NODE_DEBUGGER: 0\n"
  },
  {
    "path": "requirements.txt",
    "content": "luckydonald-utils==0.51\ndocker-py\n\n# api\nflask  # api\npony   # db"
  }
]