Repository: luckydonald/pbft Branch: master Commit: a7d39515bb2a Files: 95 Total size: 815.6 KB Directory structure: gitextract_ld6sa45j/ ├── .gitignore ├── .gitmodules ├── .travis.yml ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── api.Dockerfile ├── api.docker-compose.yml ├── code/ │ ├── api/ │ │ ├── README.md │ │ ├── database.py │ │ ├── enums.py │ │ ├── env.py │ │ ├── main.py │ │ ├── requirements.txt │ │ ├── timeline.json │ │ ├── utils.py │ │ └── uwsgi.ini │ ├── main_api.py │ ├── main_node.py │ ├── node/ │ │ ├── __init__.py │ │ ├── algo.py │ │ ├── dockerus.py │ │ ├── enums.py │ │ ├── env.py │ │ ├── functions.py │ │ ├── main.py │ │ ├── message_queue.py │ │ ├── messages.py │ │ ├── networks/ │ │ │ ├── __init__.py │ │ │ ├── receiver.py │ │ │ └── sender.py │ │ ├── tests.py │ │ └── todo.py │ ├── tests.py │ └── web/ │ ├── .bowerrc │ ├── Dockerfile │ ├── bower.json │ ├── d3/ │ │ └── d3.v3.js │ ├── d3test.html │ ├── docker-compose.yml │ ├── entrypoint.sh │ ├── example/ │ │ ├── api/ │ │ │ └── v2/ │ │ │ └── get_timeline/ │ │ │ └── index.html │ │ └── nodes.json │ ├── index.html │ ├── js.js │ ├── package.json │ ├── src/ │ │ ├── app.animations.css │ │ ├── app.animations.js │ │ ├── app.animations.less │ │ ├── app.config.js │ │ ├── app.css │ │ ├── app.js │ │ ├── app.less │ │ ├── app.module.js │ │ ├── config.js │ │ ├── core/ │ │ │ ├── core.module.js │ │ │ ├── d3/ │ │ │ │ ├── d3.directive.js │ │ │ │ ├── d3.directive.module.js │ │ │ │ ├── d3.factory.js │ │ │ │ └── d3.factory.module.js │ │ │ ├── node/ │ │ │ │ ├── node.module.js │ │ │ │ └── node.service.js │ │ │ └── recompile/ │ │ │ ├── recompile.directive.js │ │ │ └── recompile.directive.module.js │ │ ├── desktop.css │ │ ├── desktop.less │ │ ├── failure-table/ │ │ │ ├── failure-table.component.js │ │ │ ├── failure-table.module.js │ │ │ └── failure-table.template.html │ │ ├── failure-table-view/ │ │ │ ├── failure-table-view.component.js │ │ │ ├── failure-table-view.module.js │ │ │ └── failure-table-view.template.html │ │ ├── hover-effect.js │ │ ├── index-async.html │ │ ├── index.html │ │ ├── mobile.css │ │ ├── mobile.less │ │ ├── node-handling.js │ │ ├── node-list/ │ │ │ ├── node-list.component.js │ │ │ ├── node-list.module.js │ │ │ └── node-list.template.html │ │ ├── node-list-view/ │ │ │ ├── node-list-view.component.js │ │ │ ├── node-list-view.module.js │ │ │ └── node-list-view.template.html │ │ ├── nodes.json │ │ ├── test_timeline.json │ │ └── value-graph/ │ │ ├── value-graph.component.js │ │ ├── value-graph.d3.js │ │ ├── value-graph.module.js │ │ └── value-graph.template.html │ └── styles.css ├── docker-compose.yml ├── node.docker-compose.yml └── requirements.txt ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # Created by .ignore support plugin (hsz.mobi) ### Example user template # IntelliJ project files .idea *.iml out gen### Python template # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # C extensions *.so # Distribution / packaging .Python env/ build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ *.egg-info/ .installed.cfg *.egg # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *,cover .hypothesis/ # Translations *.mo *.pot # Django stuff: *.log local_settings.py # Flask stuff: instance/ .webassets-cache # Scrapy stuff: .scrapy # Sphinx documentation docs/_build/ # PyBuilder target/ # IPython Notebook .ipynb_checkpoints # pyenv .python-version # celery beat schedule file celerybeat-schedule # dotenv .env # virtualenv venv/ ENV/ # Spyder project settings .spyderproject # Rope project settings .ropeproject ### JetBrains template # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 # User-specific stuff: .idea/workspace.xml .idea/tasks.xml .idea/dictionaries .idea/vcs.xml .idea/jsLibraryMappings.xml # Sensitive or high-churn files: .idea/dataSources.ids .idea/dataSources.xml .idea/dataSources.local.xml .idea/sqlDataSources.xml .idea/dynamic.xml .idea/uiDesigner.xml # Gradle: .idea/gradle.xml .idea/libraries # Mongo Explorer plugin: .idea/mongoSettings.xml ## File-based project format: *.iws ## Plugin-specific files: # IntelliJ /out/ # mpeltonen/sbt-idea plugin .idea_modules/ # JIRA plugin atlassian-ide-plugin.xml # Crashlytics plugin (for Android Studio and IntelliJ) com_crashlytics_export_strings.xml crashlytics.properties crashlytics-build.properties fabric.properties ### VirtualEnv template # Virtualenv # http://iamzed.com/2009/05/07/a-primer-on-virtualenv/ [Bb]in [Ii]nclude [Ll]ib [Ll]ib64 [Ll]ocal [Ss]cripts pyvenv.cfg .venv pip-selfcheck.json ## USER STUFF! logs/* !.gitkeep node_modules/ bower_components/ tmp .DS_Store .idea ================================================ FILE: .gitmodules ================================================ [submodule "extras/phppgadmin-docker"] path = extras/phppgadmin-docker url = https://github.com/luckydonald-forks/phppgadmin-docker.git [submodule "code/node_java"] path = code/node_java url = https://github.com/luckydonald/PBFT-JAVA.git ================================================ FILE: .travis.yml ================================================ language: python python: - "3.5" - "3.6" - "nightly" matrix: allow_failures: - python: nightly # command to install dependencies install: - "pip install -r code/api/requirements.txt" - "pip install coverage coveralls" # command to run tests script: - cd code && coverage run tests.py after_success: - coveralls notifications: # https://docs.travis-ci.com/user/notifications#Notifications webhooks: urls: - "https://bot.proxy.bronies.link/travis/webhook/tfgDCtRoiTR4LPP1ZHMvjcdBWzuyhMgiotsTSRgg6Dc" on_success: always # default: always on_failure: always # default: always on_start: always # default: never # [always|never|change] # change means to notify when the build status changes. ================================================ FILE: Dockerfile ================================================ FROM python:3.5 # dependencies: RUN mkdir /code WORKDIR /code/ # libs RUN mkdir /code/libs/ ADD ./extras/libs/ /code/libs ADD ./requirements.txt /code RUN pip install -r requirements.txt RUN rm requirements.txt # dependencies done # our code: WORKDIR /code/ ADD ./code /code/ # defaults for running it ENTRYPOINT ["python"] CMD ["main.py"] ================================================ FILE: LICENSE ================================================ GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. {one line to give the program's name and a brief idea of what it does.} Copyright (C) {year} {name of author} This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: {project} Copyright (C) {year} {fullname} This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . ================================================ FILE: Makefile ================================================ update: git log -1 git status git pull origin master git submodule foreach git pull origin master start: docker-compose up -d postgres docker-compose up --force-recreate -d postgres_browser docker-compose up -d --build api docker-compose build node node_java help: echo "docker-compose up --build -t 0 node_java" ================================================ FILE: README.md ================================================ # pbft Implementation of the ~~Peters~~ Practical Byzantine Fault Tolerant Algorithm     ## Web GUI This project supports a web interface to `b e a u t i f u l l y` represent what's going on. You'll get a overview over all the values the nodes measured. ![image](https://user-images.githubusercontent.com/2737108/33264568-63590e78-d36e-11e7-91e3-d0b2545546ae.png) You can also get insight which messages get send by which node to which node. ![image](https://user-images.githubusercontent.com/2737108/33264484-06f95a3e-d36e-11e7-9128-e3a2de4c37d5.png) ## Code status > Please note, the project for which this was made for has reached an end, > so the code will not be actively maintained any longer. > However, pull requests with fixes and improvements will be merged. > Have a look into the bugtracker, if someone else had a similar issue, and already made it work. #### Java PBFT Node [![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) #### API Server [![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) ## Get the Code ```bash git clone --recursive https://github.com/luckydonald/pbft.git ``` If you forget `--recursive`, the `phppgadmin` container won't be available. ## Starting everything You need Docker installed. ```shell $ docker-compose build ``` Because some services need longer to start it is best to start them in the following order: 1. Database and Database browser ```shell $ docker-compose up -d postgres postgres_browser ``` 2. The API ```shell $ docker-compose up -d api ``` 3. Start the web GUI ```shell $ docker-compose up -d web ``` 4. Scale the nodes to use e.g. `4` instances - a) Older compose syntax ```shell $ docker-compose scale node=4 ``` - b) Newer compose syntax ```shell docker-compose up --scale node=4 ``` 5. Start the nodes ```shell $ docker-compose up -d node ``` 6. Stop & reset everything ```shell $ docker-compose down ``` - [Remove unused containers](http://stackoverflow.com/a/32723127): ```shell $ docker rmi $(docker images --filter "dangling=true" -q --no-trunc) ``` ## Standart Ports and URLs Assuming your docker is publishing it's ports on `localhost`. | Server | URL | | -------- | --------------------------------- | | API | http://localhost:80/ | | Database | http://localhost:8080/phppgadmin/ | | Web GUI | http://localhost:8000/src/ | ## Links The whole project: https://github.com/luckydonald/pbft The Java node implementation: https://github.com/luckydonald/PBFT-JAVA DB Struktur (for debugging and powering the web gui): https://editor.ponyorm.com/user/luckydonald/pbft ![pbft database structure](https://user-images.githubusercontent.com/2737108/33264396-a8310146-d36d-11e7-8ec9-8485d5d625b5.png) ================================================ FILE: api.Dockerfile ================================================ FROM tiangolo/uwsgi-nginx-flask:flask-python3.5 RUN mkdir -p /app/code WORKDIR /app/ COPY ./code/api/requirements.txt /app/ RUN pip install -r requirements.txt RUN rm requirements.txt COPY ./code /app COPY ./code/api/uwsgi.ini /app/uwsgi.ini ================================================ FILE: api.docker-compose.yml ================================================ version: '2' services: api: build: context: . dockerfile: ./api.Dockerfile restart: "unless-stopped" environment: POSTGRES_HOST: "postgres" # service name POSTGRES_USER: "postgres" POSTGRES_PASS: "1234secure" POSTGRES_DB: "messages" postgres: image: postgres restart: "unless-stopped" environment: POSTGRES_USER: "postgres" POSTGRES_PASSWORD: "1234secure" POSTGRES_DB: "messages" postgres_browser: # image: jacksoncage/phppgadmin build: ./extras/phppgadmin-docker environment: POSTGRES_HOST: "postgres" # service name POSTGRES_USER: "postgres" POSTGRES_PASSWORD: "1234secure" POSTGRES_DEFAULTDB: "messages" # APACHE_SERVERNAME: "postgres_browser" APACHE_SERVERNAME: "localhost" ================================================ FILE: code/api/README.md ================================================ # The events | Type \ Class | Message | Init | Propose | Prevote | Vote | Ack | | --------------- | ------- | ---- | ------- | ------- | ---- | --- | | **Sequence** | X | X | X | X | X | X | | **Node** | X | X | X | X | X | X | | **Value** | - | X | - | X | X | - | | **Leader** | - | - | X | X | X | - | | **Value Store** | - | - | X | - | - | - | | **Sender** | - | - | - | - | - | X | | **Raw** | - | - | - | - | - | X | # `GET /get_value` Returns the latest value the nodes decided on, and the most recent measured value of each node. Only considers events in the last 10 seconds. ##### Returns An dictionary. Will have an entry for each node with its latest measured value. Also contains a `"summary"` field, containing the last value they have agreed on, if any. ##### Note If nothing happened in the last 10 seconds, that node / the summary will be missing. ##### Example ```curl $ curl http://$IP_OR_HOST/get_value/ ``` ```python { # if no data is present, the field just does not exist. "1": 0.5, "2": 0.6, "5": 0.5, "6": 0.5, "7": 0.5, "summary": 0.5 } ``` # `GET /api/v2/get_value/` Similar to `/get_value/`, but ##### Returns An dictionary. Will have an entry for each node with its latest measured value. Also contains a `"summary"` field, containing the last value they have agreed on, if any. ##### Note If nothing happened in the last 10 seconds, that node / the summary will be missing. ##### Example ```curl $ curl http://$IP_OR_HOST/api/v2/get_value/ ``` ```python { "summary": 0.5, # or null "leader": 1, "nodes": [ {"node": "1", "value": 0.5}, {"node": "2", "value": 0.6}, {"node": "5", "value": 0.5}, {"node": "6", "value": 0.5}, {"node": "5", "value": 0.5} ] } ``` # `GET /get_data` Returns list of recent measurements, ##### Optional parameters - `node`: the node you want to filter for. You can specify this argument multible times. Omit to receive all of them. - `limit`: will only get the specified count of measurements. **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. ##### Returns An dictionary with nodes as keys and a subdictionary, with timestaps as keys for the measured values. ##### Example ```curl $ curl http://$IP_OR_HOST/get_data/ ``` ```python { "1": { "123134": 0.12, # timestamp : value "123135": 0.5 }, "2": { "123134": 0.13, # timestamp : value "123135": 0.8 } "3": { "123134": 0.13, # timestamp : value "123135": 0.5 } } ``` ##### Example 2 ```curl $ curl http://$IP_OR_HOST/get_data/?node=1&node=2 ``` ```python { "1": { "123134": 0.12, # timestamp : value "123135": 0.5 }, "2": { "123134": 0.13, # timestamp : value "123135": 0.8 } } ``` # `PUT /dump` Sent an json encoded `Message` into the database. The json to be send is exactly the same as used internally between the nodes. ================================================ FILE: code/api/database.py ================================================ from datetime import datetime from pony import orm import logging from node import messages from node.enums import UNSET, INIT, PROPOSE, PREVOTE, VOTE, ACKNOWLEDGE from .env import POSTGRES_HOST, POSTGRES_USER, POSTGRES_PASS, POSTGRES_DB __author__ = "luckydonald" logger = logging.getLogger(__file__) db = orm.Database() VALUE_TYPE = float MSG_TYPE_TYPE = int NODE_TYPE = int SEQUENCE_TYPE = int # https://editor.ponyorm.com/user/luckydonald/pbft # Last permalink: # https://editor.ponyorm.com/user/luckydonald/pbft_2 class DBMessage(db.Entity): type = orm.Discriminator(MSG_TYPE_TYPE) date = orm.Required(datetime, sql_default='CURRENT_TIMESTAMP') sequence_no = orm.Required(SEQUENCE_TYPE) node = orm.Optional(NODE_TYPE) value = orm.Optional(VALUE_TYPE) leader = orm.Optional(NODE_TYPE) sender = orm.Optional(NODE_TYPE) raw = orm.Optional(orm.Json) _discriminator_ = UNSET def from_db(self): clazz = MSG_TYPE_CLASS_MAP[self.type] assert issubclass(clazz, messages.Message) return clazz.from_dict(self.as_dict()) # end def @classmethod def to_db(cls, msg): return cls(**msg.to_dict()) # end def # end class class DBInitMessage(DBMessage): _discriminator_ = INIT def from_db(self): return messages.InitMessage(sequence_no=self.sequence_no, node=self.node, value=self.value) # end def @classmethod def to_db(cls, msg): assert isinstance(msg, messages.InitMessage) return super().to_db(msg) # end def # end class class DBProposeMessage(DBMessage): _discriminator_ = PROPOSE proposal = orm.Required(VALUE_TYPE) value_store = orm.Required(orm.Json) # json def from_db(self): return messages.ProposeMessage( sequence_no=self.sequence_no, node=self.node, leader=self.leader, proposal=self.proposal, value_store=self.value_store ) # end def @classmethod def to_db(cls, msg): assert isinstance(msg, messages.ProposeMessage) return super().to_db(msg) # end def # end class class DBPrevoteMessage(DBMessage): _discriminator_ = PREVOTE @classmethod def to_db(cls, msg): assert isinstance(msg, messages.PrevoteMessage) return super().to_db(msg) # end def def from_db(self): return messages.PrevoteMessage(sequence_no=self.sequence_no, node=self.node, leader=self.leader, value=self.value) # end def # end class class DBVoteMessage(DBMessage): _discriminator_ = VOTE @classmethod def to_db(cls, msg): assert isinstance(msg, messages.VoteMessage) return super().to_db(msg) # end def def from_db(self): return messages.VoteMessage(sequence_no=self.sequence_no, node=self.node, leader=self.leader, value=self.value) # end def # end class class DBAcknowledge(DBMessage): _discriminator_ = ACKNOWLEDGE @classmethod def to_db(cls, msg): assert isinstance(msg, messages.Acknowledge) return super().to_db(msg) # end def def from_db(self): return messages.Acknowledge(sequence_no=self.sequence_no, node=self.node, sender=self.sender, raw=self.raw) # end def # end class MSG_TYPE_CLASS_MAP = { INIT: DBInitMessage, PROPOSE: DBProposeMessage, PREVOTE: DBPrevoteMessage, VOTE: DBVoteMessage, # ... ACKNOWLEDGE: DBAcknowledge, } @orm.db_session def to_db(msg): if msg is None: return None if isinstance(msg, dict): # is still dict (json) msg = messages.Message.from_dict(msg) # make a Message subclass first. assert isinstance(msg, messages.Message) db_msg_clazz = MSG_TYPE_CLASS_MAP[msg.type] # Key error = not implemented yet. assert issubclass(db_msg_clazz, DBMessage) db_msg = db_msg_clazz.to_db(msg) assert db_msg.type == msg.type return db_msg # end def db.bind("postgres", host=POSTGRES_HOST, user=POSTGRES_USER, password=POSTGRES_PASS, database=POSTGRES_DB) db.generate_mapping(create_tables=True) ================================================ FILE: code/api/enums.py ================================================ # -*- coding: utf-8 -*- from luckydonaldUtils.logger import logging from node.enums import INIT, PROPOSE,PREVOTE, VOTE __author__ = 'luckydonald' logger = logging.getLogger(__name__) JSON_TYPES = { INIT: "init", PROPOSE: "propose", PREVOTE: "prevote", VOTE: "vote", } ================================================ FILE: code/api/env.py ================================================ # -*- coding: utf-8 -*- import os from luckydonaldUtils.logger import logging __author__ = 'luckydonald' logger = logging.getLogger(__name__) POSTGRES_HOST = os.environ.get("POSTGRES_HOST", None) assert POSTGRES_HOST is not None POSTGRES_USER = os.environ.get("POSTGRES_USER", None) assert POSTGRES_USER is not None POSTGRES_PASS = os.environ.get("POSTGRES_PASS", None) assert POSTGRES_PASS is not None POSTGRES_DB = os.environ.get("POSTGRES_DB", None) assert POSTGRES_DB is not None ================================================ FILE: code/api/main.py ================================================ # -*- coding: utf-8 -*- from datetime import datetime from DictObject import DictObject from flask import Flask, request from luckydonaldUtils.logger import logging from pony import orm from .enums import JSON_TYPES from .utils import jsonify from .database import to_db, db, DBVoteMessage, DBMessage, DBInitMessage, DBPrevoteMessage, DBProposeMessage, DBAcknowledge, \ MSG_TYPE_CLASS_MAP from node.enums import INIT # noqa # pylint: disable=unused-import from node.messages import Message # noqa # pylint: disable=unused-import __author__ = 'luckydonald' logger = logging.getLogger(__name__) VERSION = "0.0.1" __version__ = VERSION assert INIT == INIT # to prevent the unused import warning. Is used in SQL statement. from werkzeug.debug import DebuggedApplication app = Flask(__name__) debug = DebuggedApplication(app, console_path="/console/") API_V1 = "" API_V2 = "/api/v2" @app.route(API_V1+"/dump", methods=['POST', 'GET', 'PUT']) @app.route(API_V1+"/dump/", methods=['POST', 'GET', 'PUT']) @orm.db_session def dump_to_db(): try: logger.info("Incoming: {}".format(request.get_json(force=True))) msg = to_db(request.get_json(force=True)) if msg: db.commit() logger.info("Added {}: {id}".format(msg, id=msg.id)) return "ok: {}".format(msg) else: return "fail: None" # end if except Exception as e: logger.exception("lel") raise # end def @app.route(API_V1+"/get_value") @app.route(API_V1+"/get_value/") @orm.db_session def get_value(): """ Gets latest value they decided on, and the most recent measured value of each node. Only considers events in the last 10 seconds. > {"summary": 3.456, "1": 2.345, "2": 3.456, "3": 4.567, "4": 5.678}} :return: """ 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() if not latest_vote: return jsonify({}, allow_all_origin=True) # end if assert isinstance(latest_vote, DBVoteMessage) latest_values = DBMessage.select_by_sql(""" SELECT DISTINCT ON (m.node) * FROM ( SELECT * FROM DBmessage WHERE type = $INIT AND date >= NOW() - '10 seconds'::INTERVAL ) as m ORDER BY m.node, m.date DESC """) data = {"summary": latest_vote.value} for msg in latest_values: assert isinstance(msg, DBInitMessage) data[str(msg.node)] = msg.value # end for return jsonify(data, allow_all_origin=True) # end def @app.route(API_V2+"/get_value") @app.route(API_V2+"/get_value/") @orm.db_session def get_value_v2(): """ Gets latest value they decided on, and the most recent measured value of each node. Only considers events in the last 10 seconds. { "summary": None, "leader": 1, # done later via observing latest LeaderChange events. "nodes": [] } :return: """ 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() latest_values = DBMessage.select_by_sql(""" SELECT DISTINCT ON (m.node) * FROM ( SELECT * FROM DBmessage WHERE type = $INIT AND date >= NOW() - '10 seconds'::INTERVAL ) as m ORDER BY m.node, m.date DESC """) data = { "summary": None, "leader": 1, # done later via observing latest LeaderChange events. "nodes": [] } if latest_vote: assert isinstance(latest_vote, DBVoteMessage) data["summary"] = {"value": latest_vote.value} # end if for msg in latest_values: assert isinstance(msg, DBInitMessage) data["nodes"].append({"node": str(msg.node), "value": msg.value}) # end for return jsonify(data, allow_all_origin=True) # end def @app.route(API_V2+"/get_timeline") @app.route(API_V2+"/get_timeline/") @orm.db_session def get_timeline(): node_list = set() event_list = list() date_min = None date_max = None node_events = DBMessage.select_by_sql(""" SELECT * FROM DBmessage WHERE date >= NOW() - '60 seconds'::INTERVAL """) for node_event in node_events: event_dict = DictObject.objectify({ "id": {}, # for deduplication in the GUI "action": None, # "send" or "acknowledge" "type": None, "nodes": {}, "timestamps": {}, "data": {} }) node_list.add(node_event.node) # update node list if date_min is None or node_event.date < date_min: date_min = node_event.date # end if if date_max is None or node_event.date > date_max: date_max = node_event.date # end if if isinstance(node_event, DBAcknowledge): received_msg = Message.from_dict(node_event.raw) event_dict.id["receive"] = node_event.id event_dict.action = "acknowledge" event_dict.nodes["send"] = received_msg.node event_dict.nodes["receive"] = node_event.node event_dict.timestamps["receive"] = generate_date_data(node_event.date) event_dict.type = JSON_TYPES[received_msg.type] event_dict.data = generate_msg_data(received_msg) node_list.add(received_msg.node) # update node list # additional DB query, to get sender DBClazz = MSG_TYPE_CLASS_MAP[received_msg.type] try: db_received_msg = DBClazz.get( sequence_no=received_msg.sequence_no, node=received_msg.node ) event_dict.id["send"] = db_received_msg.id event_dict.timestamps["send"] = generate_date_data(db_received_msg.date) if date_min is None or db_received_msg.date < date_min: date_min = node_event.date # end if if date_max is None or db_received_msg.date > date_max: date_max = node_event.date # end if except orm.DatabaseError: event_dict.id["send"] = None event_dict.timestamps["send"] = generate_date_data(None) # end try else: event_dict.action = "send" event_dict.id["send"] = node_event.id event_dict.nodes["send"] = node_event.node event_dict.timestamps["send"] = generate_date_data(node_event.date) event_dict.type = JSON_TYPES[node_event.type] event_dict.data = generate_msg_data(node_event) # end if event_list.append(event_dict) # end for result = DictObject.objectify({ "nodes": node_list, "timestamps": {"min": generate_date_data(date_min), "max": generate_date_data(date_max)}, "events": event_list, }) return jsonify(result, allow_all_origin=True) # end def def generate_date_data(datetime_obj): if datetime_obj is None: return {"string": "unknown", "unix": None} # end if assert isinstance(datetime_obj, datetime) return {"string": datetime_obj, "unix": datetime_obj.timestamp()} # end def def generate_msg_data(msg): if isinstance(msg, DBMessage): msg = msg.from_db() assert isinstance(msg, Message) msg = msg.to_dict() return msg # end def @app.route(API_V1+"/get_data") @app.route(API_V1+"/get_data/") @orm.db_session def get_data(): node = request.args.getlist('node', None) limit = request.args.get('limit', 100) assert isinstance(limit, int) or str.isnumeric(limit) # TODO: specify error message, on error # like int("abc") limit = int(limit) if node: for i in node: assert str.isnumeric(i) # TODO: specify error message # end for node_values = orm.select(m for m in DBInitMessage if m.node in list(node)).order_by(orm.desc(DBInitMessage.date)).limit(limit) else: node_values = orm.select(m for m in DBInitMessage).order_by(orm.desc(DBInitMessage.date)).limit(limit) if not node_values: return jsonify({}, allow_all_origin=True) # end if data = {} for msg in node_values: assert isinstance(msg, DBInitMessage) assert isinstance(msg.date, datetime) if str(msg.node) not in data: data[str(msg.node)] = dict() # end if data[str(msg.node)][msg.date.timestamp()] = msg.value # end for return jsonify(data, allow_all_origin=True) # end def @app.route(API_V1+"/test") @app.route(API_V1+"/test/") @orm.db_session def test(): node = request.args.getlist('node', None) if request.environ.get('HTTP_ORIGIN', None) is not None: logger.warning("HTTP_ORIGIN: {!r}".format(request.environ['HTTP_ORIGIN'])) # res.headers["Access-Control-Allow-Origin"] = request.environ['HTTP_ORIGIN'] # end if return str(request.environ.get('HTTP_ORIGIN', None)) # end def @app.route("/console/") def console(): return debug.display_console(request) # end def @app.route("/") def root(): return "Ready to take your requests." # end def ================================================ FILE: code/api/requirements.txt ================================================ luckydonald-utils==0.51 docker-py flask # api pony # db psycopg2cffi # db ================================================ FILE: code/api/timeline.json ================================================ { "nodes": ["1", "2", "3", "4"], "timestamps": {"min": "23428001", "max": "23428013"}, "events": [ { "id": {"send": 1}, "action": "send", "type": "init", "nodes": {"send": "1"}, "timestamps": {"send": "23428001"}, "data": {"value": "0.5"} }, { "id": {"send": 1, "receive": 2}, "action": "acknowledge", "type": "init", "nodes": {"send": "1", "receive": "2"}, "timestamps": {"send": "23428001", "receive": "23428011"}, "data": {"value": "0.5"} }, { "id": {"send": null, "receive": 3}, "action": "acknowledge", "type": "init", "nodes": {"send": "1", "receive": "3"}, "timestamps": {"send": null, "receive": "23428013"}, "data": {"value": "0.5"} }, { "id": {"send": 1, "receive": 4}, "action": "acknowledge", "type": "init", "nodes": {"send": "1", "receive": "3"}, "timestamps": {"send": "23428001", "receive": "23428013"}, "data": {"value": "0.5"} } ] } ================================================ FILE: code/api/utils.py ================================================ # -*- coding: utf-8 -*- from flask import request from luckydonaldUtils.logger import logging __author__ = 'luckydonald' logger = logging.getLogger(__name__) ORIGIN_LIST = ["http://localhost"] def jsonify(data, allow_all_origin=False): from flask import Response, jsonify as json_ify res = json_ify(data) assert isinstance(res, Response) origin = request.environ.get('HTTP_ORIGIN') if not origin: origin = request.environ.get('ORIGIN') # end if if allow_all_origin: res.headers["Access-Control-Allow-Origin"] = '*' elif origin and origin in ORIGIN_LIST: res.headers["Access-Control-Allow-Origin"] = origin # end if return res # end def ================================================ FILE: code/api/uwsgi.ini ================================================ [uwsgi] module = main_api callable = app ================================================ FILE: code/main_api.py ================================================ # -*- coding: utf-8 -*- from luckydonaldUtils.logger import logging, LevelByNameFilter __author__ = 'luckydonald' logger = logging.getLogger(__name__) from api import main app = main.app print("## LOADED ##") def setup_logging(): filter = LevelByNameFilter(logging.WARNING, debug="api.main, node.messages", info="node, api") logging.add_colored_handler(level=logging.DEBUG, date_formatter="%Y-%m-%d %H:%M:%S", filter=filter) logging.test_logger_levels() # end def setup_logging() if __name__ == "__main__": # no nginx, else the __name__ would be "api" (because api.py) app.run(host='0.0.0.0', debug=True, port=80) # end if ================================================ FILE: code/main_node.py ================================================ # -*- coding: utf-8 -*- from luckydonaldUtils.logger import logging from node.main import setup_logging, main __author__ = 'luckydonald' logger = logging.getLogger(__name__) if __name__ == '__main__': # if this is the executed file setup_logging() main() # end if main() ================================================ FILE: code/node/__init__.py ================================================ ================================================ FILE: code/node/algo.py ================================================ # -*- coding: utf-8 -*- # built in modules import sys from datetime import timedelta from statistics import median # dependency modules from luckydonaldUtils.functions import cached, gone from luckydonaldUtils.logger import logging # own modules from .message_queue import MessageQueueReceiver from .networks.sender import send_message from .functions import flatten_list from .messages import InitMessage, LeaderChangeMessage, ProposeMessage, PrevoteMessage, VoteMessage from .env import DEBUGGER from . import todo __author__ = 'luckydonald' logger = logging.getLogger(__name__) if DEBUGGER: sys.path.append("libs/pycharm-debug-py3k.egg") try: import pydevd except ImportError: sys.path.remove("libs/pycharm-debug-py3k.egg") logger.warning("Debug disabled.") # end def try: pydevd.settrace('192.168.188.20', port=49872, stdoutToServer=True, stderrToServer=True, suspend=False) logger.success("Debugger connected.") except Exception: logger.warning("No debugger.") # end try else: logger.debug("Debugger disabled via $NODE_DEBUGGER.") # end if # init # sensor_value = 0.4 # vp # self.node_number = 0 # p # TOTAL_NODES = 4 # n # POSSIBLE_FAILURES = 1 # t # value_store = {} # INIT_Store # current_leader = 0 # o # sequence_no = None # cid # P = {} # LC = {} # leader change # MAIN FILE IS main_node.py IN THE /code DIRECTORY! class BFT_ARM(): sequence_no = None should_timeout = False def __init__(self, sequence_number=None, receiver=None): """ Starts a new sequence. You can provide a sequence number to use as `sequence_number` and a (started) MessageQueueReceiver `receiver`, too. :param sequence_number: the sequence number to use. Is stored as `self.sequence_no` :param receiver: Reuse a existing :class:`MessageQueueReceiver`, allowing to keep the messages, and minimizing the socket port problems """ self.value_store = {} # INIT_Store self.current_leader = 1 # ø if receiver: assert isinstance(receiver, MessageQueueReceiver) self.rec = receiver else: self.rec = MessageQueueReceiver() self.rec.start() # end if self.sequence_no = sequence_number # end def def MsgCollect(self): received_message = self.get_specific_message_type(InitMessage, LeaderChangeMessage) if isinstance(received_message, InitMessage): self.value_store[received_message.node] = received_message elif isinstance(received_message, LeaderChangeMessage): # TODO: LC <- LC u {received_message} logger.warning("not implemented.") pass if todo.timeout(): # BFT_ARM.task_leader_change() # todo.timeout.reset() pass # end if # end def def task_normal_case(self): value = todo.get_sensor_value() # vp logger.critical("Step 0 INIT>") send_message(InitMessage(self.sequence_no, self.node_number, value)) logger.info("I'm node [{self!r}], [{leader!r}] is leader, {filler}.".format( leader=self.current_leader, self=self.node_number, filler="it's a me" if self.node_number == self.current_leader else "not me" )) if self.node_number == self.current_leader: logger.critical("Step 1.0 (leader)") # CURRENT LEADER # self.new_sequence() while not (len(self.value_store) >= (self.nodes_total - self.nodes_faulty)): # wait until |INIT_Store| > n - t logger.success("INITs: {} > {}".format(len(self.value_store), (self.nodes_total - self.nodes_faulty))) init_msg = self.rec.init_queue.get_message(sequence_number=self.sequence_no) assert isinstance(init_msg, InitMessage) self.value_store[init_msg.node] = init_msg # end proposal = median([x.value for x in self.value_store.values()]) send_message(ProposeMessage( self.sequence_no, self.node_number, self.current_leader, proposal, list(self.value_store.values()) )) logger.critical("Step 1.1 PROPOSAL>") # end if logger.critical("Step 2.0 >PROPOSAL") prop_message = self.rec.propose_queue.get_message(sequence_number=self.sequence_no) assert isinstance(prop_message, ProposeMessage) if self.verify_proposal(prop_message): send_message(PrevoteMessage(self.sequence_no, self.node_number, self.current_leader, value)) logger.critical("Step 2.1 PROPOSAL>") # if exist v:|(n+t) # hier auch, weil timeout uns notfalls rettet. prevote_buffer = dict() # dict with P inside vote_buffer = dict() # just decide logger.critical("Step 3.0 >(PRE)VOTE") while not self.should_timeout: if self.rec.prevote_queue.has_message(): logger.critical("Step 3.A >PREVOTE") msg = self.rec.prevote_queue.get_message(sequence_number=self.sequence_no) value, is_enough = self.buffer_incomming(msg, prevote_buffer) if is_enough: send_message(VoteMessage(self.sequence_no, self.node_number, self.current_leader, value)) logger.critical("Step 3.A VOTE>") # end def elif self.rec.vote_queue.has_message(): msg = self.rec.vote_queue.get_message(sequence_number=self.sequence_no) logger.critical("Step 3.B >VOTE") value, is_enough = self.buffer_incomming(msg, vote_buffer) if is_enough: logger.critical("Step 4 (commit {value})".format(value=value)) return value # end if # end if # end while logger.warning("Hit end unexpectedly.") # end def run def stop(self): logger.info("Requested to stop.") self.should_timeout = True assert isinstance(self.rec, MessageQueueReceiver) self.rec.stop() self.rec = None # end def def new_sequence(self): if self.sequence_no is None: self.sequence_no = 0 else: self.sequence_no = (self.sequence_no + 1) % 256 # end if logger.info("Sequence: {i}".format(i=self.sequence_no)) return self.sequence_no # end def def buffer_incomming(self, msg, buffer): if not msg.value in buffer: buffer[msg.value] = list() # end if assert isinstance(buffer[msg.value], list) buffer[msg.value].append(msg) return msg.value, len(buffer[msg.value]) > (self.nodes_total + self.nodes_faulty) / 2 # end def def verify_proposal(self, msg): """ Überprüfe ob proposal vom leader ist und Rechnen nach, das die von msg empfangenen InitMessages den von ihm berechneten Wert (proposal) ergeben. :param msg: :return: """ # TODO: optimieren, indem man leader abfrage nach oben schiebt? # if not msg.leader == self.current_leader: # return False values = list() known_nodes = list() if not isinstance(msg, ProposeMessage): raise AttributeError("msg is not ProposeMessage type, but {type}:\n{val}".format(type=type(msg), val=msg)) for init_msg in msg.value_store: assert isinstance(init_msg, InitMessage) # right message type assert init_msg.node not in known_nodes # no duplicates values.append(init_msg.value) # store the value known_nodes.append(init_msg.node) # remember this node # end for return msg.leader == self.current_leader and median(values) == msg.proposal # end def @gone # TODO: get_specific_message_type function not needed anymore def get_specific_message_type(self, *classes_or_types, sequence_number=None): # TODO Remove this def msg = None classes_or_types = flatten_list(classes_or_types) classes_or_types = tuple(classes_or_types) while True: # todo: something better msg = self.rec.pop_message() if isinstance(msg, classes_or_types): logger.success("Got Message: {}".format(msg)) if sequence_number is not None and msg.sequence_no != sequence_number: logger.warning("Discarded Message (wrong sequence number): {}".format(msg)) msg = None else: break # end if else: logger.warning("Discarded Message (wrong type): {}".format(msg)) msg = None # end if # end while return msg # end def @property @cached(max_age=timedelta(seconds=60)) def nodes_total(self): from .dockerus import ServiceInfos return len(ServiceInfos().other_numbers(exclude_self=False)) # end def @property @cached(max_age=timedelta(seconds=60)) def nodes_faulty(self): return (self.nodes_total - 1)/3 # end def @property def node_number(self): from .dockerus import ServiceInfos return ServiceInfos().number # end def def get_receiver(self): return self.rec # end def # end class ================================================ FILE: code/node/dockerus.py ================================================ # -*- coding: utf-8 -*- from DictObject import DictObject from luckydonaldUtils.logger import logging from luckydonaldUtils.functions import cached from luckydonaldUtils.clazzes import Singleton from docker import Client from datetime import timedelta __author__ = 'luckydonald' logger = logging.getLogger(__name__) class ServiceInfos(object, metaclass=Singleton): """ Infos about a `docker-compose scale` group. """ __author__ = 'luckydonald' LABEL_COMPOSE_CONTAINER_NUMBER = 'com.docker.compose.container-number' LABEL_COMPOSE_PROJECT = 'com.docker.compose.project' LABEL_COMPOSE_SERVICE = 'com.docker.compose.service' CACHING_TIME = timedelta(seconds=5) def __init__(self, caching_time=None): """ Infos about a `docker-compose scale` group. If caching_time is not specified, the $DOCKER_CACHING_TIME environment variable will be used. If that is empty, too, it will fallback to the default CACHING_TIME of 5 seconds. :param caching_time: must be a datetime.timedelta object """ if caching_time: assert isinstance(caching_time, timedelta) self.CACHING_TIME = caching_time else: import os timedelta(seconds=float(os.environ.get("DOCKER_CACHING_TIME", ServiceInfos.CACHING_TIME.total_seconds()))) # end if # end def @property @cached def cli(self): return Client(base_url='unix://var/run/docker.sock') # end def @property @cached(max_age=max(timedelta(hours=1), CACHING_TIME)) def hostname_env(self): import os return os.environ.get("HOSTNAME") # end def @property @cached(max_age=CACHING_TIME) def me(self): return [DictObject.objectify(c) for c in self.cli.containers() if c['Id'][:12] == self.hostname_env[:12]][0] # end def @property @cached(max_age=CACHING_TIME) def id(self): return self.me.Id # end def @property @cached(max_age=CACHING_TIME) def service(self): return self.me.Labels[self.LABEL_COMPOSE_SERVICE] # end def @property @cached(max_age=CACHING_TIME) def name(self): return self.service # end def @property @cached(max_age=CACHING_TIME) def project(self): return self.me.Labels[self.LABEL_COMPOSE_PROJECT] # end def @property @cached(max_age=CACHING_TIME) def number(self): return int(self.me.Labels[self.LABEL_COMPOSE_CONTAINER_NUMBER]) # end def @cached(max_age=CACHING_TIME) def containers(self, exclude_self=False): """ Gets metadata for all containers in this scale grouping. :return: """ filters = [ '{0}={1}'.format(self.LABEL_COMPOSE_PROJECT, self.project), '{0}={1}'.format(self.LABEL_COMPOSE_SERVICE, self.service), # '{0}={1}'.format(LABEL_ONE_OFF, "True" if one_off else "False") ] return DictObject.objectify([ c for c in self.cli.containers(filters={'label': filters}) if not (exclude_self and c['Id'][:12] == self.hostname_env[:12]) ]) # end def @property @cached(max_age=CACHING_TIME) def hostname(self): c = self.me return "{project}_{service}_{i}".format( project=c.Labels[self.LABEL_COMPOSE_PROJECT], service=c.Labels[self.LABEL_COMPOSE_SERVICE], i=c.Labels[self.LABEL_COMPOSE_CONTAINER_NUMBER] ) # end def @cached(max_age=CACHING_TIME) def other_hostnames(self, exclude_self=False): return [ "{project}_{service}_{i}".format( project=c.Labels[self.LABEL_COMPOSE_PROJECT], service=c.Labels[self.LABEL_COMPOSE_SERVICE], i=c.Labels[self.LABEL_COMPOSE_CONTAINER_NUMBER] ) for c in self.containers(exclude_self=exclude_self) ] # end def @cached(max_age=CACHING_TIME) def other_numbers(self, exclude_self=False): """ :param exclude_self: :return: """ return [ c.Labels[self.LABEL_COMPOSE_CONTAINER_NUMBER] for c in self.containers(exclude_self=exclude_self) ] # end def # end class ================================================ FILE: code/node/enums.py ================================================ # -*- coding: utf-8 -*- from luckydonaldUtils.logger import logging __author__ = 'luckydonald' logger = logging.getLogger(__name__) __all__ = ["UNSET", "INIT", "PROPOSE", "PREVOTE", "VOTE", "LEADER_CHANGE", "ACKNOWLEDGE", "all"] UNSET = 0 INIT = 1 PROPOSE = 2 PREVOTE = 3 VOTE = 4 LEADER_CHANGE = 5 ACKNOWLEDGE = -1 all = [UNSET, INIT, PROPOSE, PREVOTE, VOTE, LEADER_CHANGE, ACKNOWLEDGE] ================================================ FILE: code/node/env.py ================================================ # -*- coding: utf-8 -*- import os from datetime import timedelta from luckydonaldUtils.logger import logging __author__ = 'luckydonald' __all__ = ["NODE_PORT", "NODES_CACHING_TIME", "DEBUGGER"] logger = logging.getLogger(__name__) NODE_PORT = int(os.environ.get("NODE_PORT", None)) # DOCKER_CACHING_TIME in seconds docker_caching_time_seconds = os.environ.get("DOCKER_CACHING_TIME", None) if docker_caching_time_seconds is None: DOCKER_CACHING_TIME = None else: DOCKER_CACHING_TIME = timedelta(seconds=float(docker_caching_time_seconds)) # end if DEBUGGER = os.environ.get("NODE_DEBUGGER", "") if DEBUGGER.lower() in ["true", "yes", "1"]: DEBUGGER = True else: DEBUGGER = False # end if DATABASE_URL = "http://api/dump/" ================================================ FILE: code/node/functions.py ================================================ # -*- coding: utf-8 -*- from luckydonaldUtils.logger import logging __author__ = 'luckydonald' logger = logging.getLogger(__name__) def flatten_list(args): if isinstance(args, tuple): args = list(args) elif not isinstance(args, list): args = [args] # end if assert isinstance(args, list) new_args = [] for arg in args: if isinstance(arg, (list,tuple)): new_args.extend(arg) else: new_args.append(arg) # end if return new_args # end def ================================================ FILE: code/node/main.py ================================================ # -*- coding: utf-8 -*- from time import sleep from luckydonaldUtils.logger import logging, LevelByNameFilter from .algo import BFT_ARM __author__ = 'luckydonald' logger = logging.getLogger(__name__) do_quit = False def main(): algo = BFT_ARM() sequence = algo.new_sequence() receiver = algo.get_receiver() setup_cleanup(algo) logger.info("Sleeping 2 seconds to give other nodes the time to get the receiver ready.") sleep(2) while not do_quit: logger.debug("Starting new Round.") algo = BFT_ARM(sequence_number=sequence, receiver=receiver) sequence = algo.new_sequence() algo.task_normal_case() # end while logger.info("Exiting.") # end def def setup_cleanup(algo): import signal import sys assert isinstance(algo, BFT_ARM) def signal_handler(signal, frame): print('You pressed Ctrl+C!') global do_quit do_quit = True assert isinstance(algo, BFT_ARM) algo.stop() sys.exit(0) # end def signal.signal(signal.SIGINT, signal_handler) # end def def setup_logging(): filter = LevelByNameFilter(logging.WARNING, debug="node.main, node.todo, node.messages", info="node") logging.add_colored_handler(level=logging.DEBUG, date_formatter="%Y-%m-%d %H:%M:%S", filter=filter) logging.test_logger_levels() # end def ================================================ FILE: code/node/message_queue.py ================================================ # -*- coding: utf-8 -*- import threading from collections import deque from DictObject import DictObject import json from luckydonaldUtils.logger import logging from .messages import Message, InitMessage, ProposeMessage, PrevoteMessage, VoteMessage from .networks.receiver import Receiver __author__ = 'luckydonald' logger = logging.getLogger(__name__) class LockedQueue(object): def __init__(self, clazz): assert issubclass(clazz, Message) self._clazz = clazz self._queue = deque() self._new_messages = threading.Semaphore(0) self._queue_access = threading.Lock() def pop_message(self): """ Get a message. :return: """ logger.debug("Called pop_message on {type}.".format(type=self._clazz)) self._new_messages.acquire() # waits until at least 1 message is in the queue. with self._queue_access: message = self._queue.popleft() # pop oldest item logger.debug('Messages waiting in queue: %d', len(self._queue)) if not isinstance(message, self._clazz): raise TypeError("Popped message is not type {_clazz} but type {type}:\n{msg}".format( _clazz=self._clazz, type=type(message), msg=message )) # end if assert isinstance(message, Message) assert isinstance(message, self._clazz) return message # end with # end def def get_message(self, sequence_number=None): if sequence_number is None: # no check needed: return self.pop_message() # end if msg = None while msg is None: msg = self.pop_message() if msg.sequence_no != sequence_number: logger.warning("Discarded Message, wrong sequence number ({a} instead of {b}): {msg}".format( a=msg.sequence_no, b=sequence_number, msg=msg )) msg = None # end if # end while assert isinstance(msg, Message) assert isinstance(msg, self._clazz) return msg # end def def append_message(self, message): if not isinstance(message, self._clazz): raise TypeError("Given message is not type {_clazz} but type {type}:\n{msg}".format( _clazz=self._clazz, type=type(message), msg=message )) # end if with self._queue_access: self._queue.append(message) # end if self._new_messages.release() # end def def queue_length(self): with self._queue_access: return len(self._queue) # end with # end def __len__ = queue_length def has_message(self): with self._queue_access: return len(self._queue) > 0 # end with # end def # end class class MessageQueueReceiver(Receiver): init_queue = LockedQueue(InitMessage) propose_queue = LockedQueue(ProposeMessage) prevote_queue = LockedQueue(PrevoteMessage) vote_queue = LockedQueue(VoteMessage) pop_message = None # the function def _add_message(self, text): """ Appends a message to the message queue. :type text: builtins.str :return: """ try: logger.debug("Received Message: \"{str}\"".format(str=text)) json_dict = json.loads(text) message = DictObject.objectify(json_dict) message = self.parse_message(message) except ValueError as e: logger.warn("Received message could not be parsed.\nMessage:>{}<".format(text), exc_info=True) return if isinstance(message, InitMessage): self.init_queue.append_message(message) elif isinstance(message, ProposeMessage): self.propose_queue.append_message(message) elif isinstance(message, PrevoteMessage): self.prevote_queue.append_message(message) elif isinstance(message, VoteMessage): self.vote_queue.append_message(message) else: logger.warning("Discarded unknown message type: {msg_type}, {msg}".format( msg_type=type(message), msg=message )) # end if # end def # end class ================================================ FILE: code/node/messages.py ================================================ # -*- coding: utf-8 -*- from luckydonaldUtils.logger import logging from .enums import UNSET, INIT, LEADER_CHANGE, PROPOSE, PREVOTE, VOTE, ACKNOWLEDGE __author__ = 'luckydonald' logger = logging.getLogger(__name__) class Message(object): def __init__(self, type, sequence_no, node): if type is None: type = UNSET # end if assert isinstance(type, int) self.type = type self.sequence_no = sequence_no self.node = node # i @classmethod def from_dict(cls, data): assert "type" in data type = data["type"] assert type in [UNSET, INIT, LEADER_CHANGE, PROPOSE, PREVOTE, VOTE, ACKNOWLEDGE] if type == INIT: return InitMessage.from_dict(data) # end def if type == LEADER_CHANGE: # pragma: no cover return LeaderChangeMessage.from_dict(data) # end def if type == PROPOSE: return ProposeMessage.from_dict(data) # end def if type == PREVOTE: return PrevoteMessage.from_dict(data) # end def if type == VOTE: return VoteMessage.from_dict(data) # end def if type == ACKNOWLEDGE: return Acknowledge.from_dict(data) # end def return cls(**{ "type": data["type"], "sequence_no": data["sequence_no"], "node": data["node"] }) # end def def to_dict(self): return { "type": self.type, "sequence_no": self.sequence_no, "node": self.node } # end def def __str__(self): data = self.to_dict() return "{class_name}({values})".format( class_name=self.__class__.__name__, values=", ".join(["{key}={value!r}".format(key=k, value=data[k]) for k in sorted(data)]) ) # end class class InitMessage(Message): def __init__(self, sequence_no, node, value): super(InitMessage, self).__init__(INIT, sequence_no, node) self.value = value # vi # end def @classmethod def from_dict(cls, data): kwargs = { "sequence_no": data["sequence_no"], "node": data["node"], "value": data["value"], } return cls(**kwargs) # end def def to_dict(self): data = super().to_dict() data["value"] = self.value return data # end def # end class class LeaderChangeMessage(Message): # pragma: no cover def __init__(self, sequence_no, node_num, leader, P): raise NotImplementedError("LeaderChangeMessage") super(LeaderChangeMessage, self).__init__(LEADER_CHANGE, sequence_no) # end def @classmethod def from_dict(cls, data): raise NotImplementedError("LeaderChangeMessage") kwargs = { "type": data["type"], "sequence_no": data["sequence_no"], } return cls(**kwargs) # end def def to_dict(self): raise NotImplementedError("LeaderChangeMessage") return { "type": self.type, "sequence_no": self.sequence_no, } # end def # end class class ProposeMessage(Message): def __init__(self, sequence_no, node, leader, proposal, value_store): super(ProposeMessage, self).__init__(PROPOSE, sequence_no, node) self.leader = leader self.proposal = proposal assert isinstance(value_store, list) self.value_store = value_store @classmethod def from_dict(cls, data): value_store = [] for v in data.get("value_store", []): msg = InitMessage.from_dict(v) # value_store[msg.node] = msg value_store.append(msg) # end for kwargs = { "sequence_no": data["sequence_no"], "node": data.get("node"), "leader": data.get("leader"), "proposal": data.get("proposal"), "value_store": value_store } return cls(**kwargs) # end def def to_dict(self): data = super().to_dict() data["leader"] = self.leader data["proposal"] = self.proposal data["value_store"] = [x.to_dict() if hasattr(x, "to_dict") else x for x in self.value_store] return data # end def # end class class PrevoteMessage(Message): def __init__(self, sequence_no, node, leader, value): super().__init__(PREVOTE, sequence_no, node) self.leader = leader self.value = value # end if @classmethod def from_dict(cls, data): kwargs = { "sequence_no": data["sequence_no"], "node": data["node"], "leader": data["leader"], "value": data["value"], } return cls(**kwargs) # end def def to_dict(self): data = super().to_dict() data["leader"] = self.leader data["value"] = self.value return data # end def # end class class VoteMessage(Message): def __init__(self, sequence_no, node, leader, value): super().__init__(VOTE, sequence_no, node) self.leader = leader self.value = value # end def @classmethod def from_dict(cls, data): kwargs = { "sequence_no": data["sequence_no"], "node": data["node"], "leader": data["leader"], "value": data["value"], } return cls(**kwargs) # end def def to_dict(self): data = super().to_dict() data["leader"] = self.leader data["value"] = self.value return data # end def # end class class NewLeaderMessage(Message): # pragma: no cover def __init__(self, sequence_no, node, leader, value): super().__init__(VOTE, sequence_no, node) self.leader = leader self.value = value # end def # end class class Acknowledge(Message): def __init__(self, sequence_no, node, sender, raw): super().__init__(ACKNOWLEDGE, sequence_no, node) self.sender = sender self.raw = raw # end def @classmethod def from_dict(cls, data): kwargs = { "sequence_no": data["sequence_no"], "node": data["node"], "sender": data["sender"], "raw": data["raw"], } return cls(**kwargs) # end def def to_dict(self): data = super().to_dict() data["sender"] = self.sender data["raw"] = self.raw return data # end def # end class ================================================ FILE: code/node/networks/__init__.py ================================================ # -*- coding: utf-8 -*- from luckydonaldUtils.logger import logging __author__ = 'luckydonald' logger = logging.getLogger(__name__) ================================================ FILE: code/node/networks/receiver.py ================================================ # -*- coding: utf-8 -*- import json import threading from collections import deque from DictObject import DictObject from luckydonaldUtils.logger import logging from luckydonaldUtils.encoding import to_binary as b from luckydonaldUtils.encoding import to_native as n import socket from ..messages import Message from ..dockerus import ServiceInfos __author__ = 'luckydonald' logger = logging.getLogger(__name__) _EMPTY_RAW_BYTE = b("") _ANSWER_SYNTAX = b("ANSWER ") _LINE_BREAK = b("\n") class Receiver(object): _queue = deque() _new_messages = threading.Semaphore(0) _queue_access = threading.Lock() def __init__(self): self._do_quit = False self.s = None # socket self.client = None # end def def __receiver_logging_wrapper(self): try: self._receiver() except Exception: logger.exception("Receiver failed. Exited.") # end try # end def def _receiver(self): from ..env import NODE_PORT from errno import ECONNREFUSED logger.info("Starting receiver on {host}:{port}".format(host=ServiceInfos().hostname, port=NODE_PORT)) while not self._do_quit: # retry connection self.s = socket.socket(socket.AF_INET, # Internet socket.SOCK_STREAM) # TCP try: self.s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.s.bind((ServiceInfos().hostname, NODE_PORT)) self.s.listen(5) logger.debug("Socket Set up.") while not self._do_quit and self.s: self.client, address = self.s.accept() buffer = _EMPTY_RAW_BYTE answer = _EMPTY_RAW_BYTE completed = -1 # -1 = answer size yet unknown, >0 = got remaining answer size while (not self._do_quit) and self.s and self.client: # read loop while 1: # retry if CTRL+C'd try: # self.s.setblocking(True) answer = self.client.recv(1) # recv() returns an empty string if the remote end is closed if len(answer) == 0: logger.debug("Remote end closed.") self.reset_client() # end if # logger.debug("received byte: {}".format(answer)) break except socket.error as err: if self._do_quit: self.reset_client() # end if from errno import EINTR if err.errno != EINTR: # interrupted system call raise else: logger.exception( "Uncatched exception in reading message from {client}.".format(client=address) ) self.reset_client() break # to the retry connection look again. # end if # end try # end while: ctrl+c protection if not self.s or not self.client: # check if socket is still open break if completed == 0: logger.debug("Hit end.") if answer != _LINE_BREAK: raise ValueError("Message does not end with a double linebreak.") if buffer == _EMPTY_RAW_BYTE: logger.debug("skipping second linebreak.") completed = -1 continue logger.debug( "Received Message from {client}: {buffer}".format(client=address, buffer=buffer) ) text = n(buffer) if len(text) > 0 and text.strip() != "": self._add_message(text) else: logger.warn("Striped text was empty.") answer = _EMPTY_RAW_BYTE buffer = _EMPTY_RAW_BYTE # completed = 0 (unchanged) continue buffer += answer if completed < -1 and buffer[:len(_ANSWER_SYNTAX)] != _ANSWER_SYNTAX[:len(buffer)]: raise ArithmeticError("Server response does not fit. (Got >{}<)".format(buffer)) if completed <= -1 and buffer.startswith(_ANSWER_SYNTAX) and buffer.endswith(_LINE_BREAK): completed = int(n(buffer[len(_ANSWER_SYNTAX):-1])) # TODO regex. buffer = _EMPTY_RAW_BYTE completed -= 1 # end while: read loop # end while: for connected clients except socket.error as error: # if error.errno in [ECONNREFUSED] and not self._do_quit: # continue # # end if logger.error("Socket failed with network error: {e}\nRetrying...".format(e=error)) except Exception as error: logger.error("Socket failed: {e}\nRetrying...".format(e=error)) # end try self.reset_socket() # end while not ._do_quit: retry connection self.reset_socket() # end def def reset_client(self): if self.client: self.client.close() self.client = None # end if # end def def reset_socket(self): self.reset_client() if self.s: self.s.close() self.s = None # end if # end def def _add_message(self, text): """ Appends a message to the message queue. :type text: builtins.str :return: """ try: logger.debug("Received Message: \"{str}\"".format(str=text)) json_dict = json.loads(text) message = DictObject.objectify(json_dict) message = self.parse_message(message) except ValueError as e: logger.warn("Received message could not be parsed.\nMessage:>{}<".format(text), exc_info=True) return with self._queue_access: self._queue.append(message) self._new_messages.release() # end with # end def def parse_message(self, dict): return Message.from_dict(dict) # end def def start(self): """ Starts the receiver. When started, messages will be queued. :return: """ self._receiver_thread = threading.Thread(name="Receiver", target=self.__receiver_logging_wrapper, args=()) self._receiver_thread.daemon = True # exit if script reaches end. self._receiver_thread.start() logger.success("Started Receiver Thread.") # end def def stop(self): """ Shuts down the receivers server. No more messages will be received. You should not try to start() it again afterwards. """ self._do_quit = True if self.client: self.s.settimeout(0) if self.client: self.client.close() if self.s: self.s.settimeout(0) if self.s: self.s.close() if hasattr(self, "_receiver_thread"): logger.debug("receiver thread existing: {}".format(self._receiver_thread.isAlive())) else: logger.debug("receiver thread existing: Not created.") # end if def pop_message(self): """ Get a message. :return: """ self._new_messages.acquire() # waits until at least 1 message is in the queue. with self._queue_access: message = self._queue.popleft() # pop oldest item logger.debug('Messages waiting in queue: %d', len(self._queue)) assert isinstance(message, Message) return message # end with # end def ================================================ FILE: code/node/networks/sender.py ================================================ # -*- coding: utf-8 -*- import socket from time import sleep from luckydonaldUtils.logger import logging from ..env import NODE_PORT, DATABASE_URL from ..messages import Message from ..todo import logger __author__ = 'luckydonald' logger = logging.getLogger(__name__) MSG_FORMAT = "ANSWER {length}\n{msg}\n" def send_message(msg): import json import requests logger.debug(msg) assert isinstance(msg, Message) data = msg.to_dict() data_string = json.dumps(data) broadcast(data_string) loggert = logging.getLogger("request") def print_url(r, *args, **kwargs): loggert.info(r.url) # end def while (True): try: requests.put(DATABASE_URL, data=data_string, hooks=dict(response=print_url)) break except requests.RequestException as e: logger.warning("Failed to report message to db: {e}".format(e=e)) # end def return # end def def broadcast(message): from ..dockerus import ServiceInfos if not isinstance(message, str): raise TypeError("Parameter `message` is not type `str` but {type}: {msg}".format(type=type(message), msg=message)) hosts = ServiceInfos().other_hostnames() # msg = MSG_FORMAT.format(length=len(message), msg=message) message += "\n" msg = "ANSWER " + str(len(message)) + "\n" + message logger.debug("Prepared sending to *:{port}:\n{msg}".format(port=NODE_PORT, msg=msg)) msg = bytes(msg, "utf-8") for node_host in hosts: sent = -1 while not sent == 1: try: with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: # UDP SOCK_DGRAM sock.connect((node_host, NODE_PORT)) sock.sendall(msg) logger.log( msg="Sending to {host}:{port} succeeded.".format(host=node_host, port=NODE_PORT), level=(logging.SUCCESS if sent == 0 else logging.DEBUG) ) sent = 1 # end with except OSError as e: logger.error("Sending to {host}:{port} failed: {e} Retrying...".format(e=e, host=node_host, port=NODE_PORT)) sleep(0.1) sent = 0 # end try # end while # end for # end def ================================================ FILE: code/node/tests.py ================================================ # -*- coding: utf-8 -*- from luckydonaldUtils.logger import logging import unittest from .messages import Message, InitMessage, ProposeMessage, PrevoteMessage, VoteMessage, Acknowledge from .enums import UNSET, INIT, PROPOSE, PREVOTE, VOTE, ACKNOWLEDGE __author__ = 'luckydonald' __all__ = ["TestJsonToObject"] logger = logging.getLogger(__name__) class TestJsonToObject(unittest.TestCase): data_InitMessage = { "type": INIT, "sequence_no": 12, "node": 1, "value": 0.5, } def check_InitMessage(self, msg, data): self.assertIsInstance(msg, InitMessage) self.assertEqual(msg.type, data["type"]) self.assertEqual(msg.sequence_no, data["sequence_no"]) self.assertEqual(msg.node, data["node"]) self.assertEqual(msg.value, data["value"]) # end def def test_InitMessage_toObject(self): msg = InitMessage.from_dict(self.data_InitMessage) self.check_InitMessage(msg, self.data_InitMessage) # end def def test_Message_toObject_InitMessage(self): msg = Message.from_dict(self.data_InitMessage) self.check_InitMessage(msg, self.data_InitMessage) # end def def test_InitMessage_toDict(self): data = self.data_InitMessage msg = InitMessage(data["sequence_no"], data["node"], data["value"]) self.check_InitMessage(msg, self.data_InitMessage) self.assertDictEqual(msg.to_dict(), data) # end def def test_InitMessage_toString(self): msg = Message.from_dict(self.data_InitMessage) self.assertEqual("InitMessage(node=1, sequence_no=12, type=1, value=0.5)", str(msg)) # end def data_ProposeMessage = { "type": PROPOSE, "sequence_no": 12, "node": 1, "leader": 1, "proposal": 0.5, "value_store": [], } def check_ProposeMessage(self, msg): self.assertIsInstance(msg, ProposeMessage) self.assertEqual(msg.type, self.data_ProposeMessage["type"]) self.assertEqual(msg.sequence_no, self.data_ProposeMessage["sequence_no"]) self.assertEqual(msg.node, self.data_ProposeMessage["node"]) self.assertEqual(msg.leader, self.data_ProposeMessage["leader"]) self.assertEqual(msg.proposal, self.data_ProposeMessage["proposal"]) # end def def test_ProposeMessage_toObject(self): msg = ProposeMessage.from_dict(self.data_ProposeMessage) self.check_ProposeMessage(msg) self.assertListEqual(msg.value_store, []) # end def def test_Message_toObject_ProposeMessage(self): msg = Message.from_dict(self.data_ProposeMessage) self.check_ProposeMessage(msg) self.assertListEqual(msg.value_store, []) # end def def test_ProposeMessage_toDict(self): data = self.data_ProposeMessage msg = ProposeMessage(data["sequence_no"], data["node"], data["leader"], data["proposal"], []) self.check_ProposeMessage(msg) self.assertListEqual(msg.value_store, []) self.assertDictEqual(msg.to_dict(), data) # end def def test_ProposeMessage_toString(self): msg = Message.from_dict(self.data_ProposeMessage) self.assertEqual("ProposeMessage(leader=1, node=1, proposal=0.5, sequence_no=12, type=2, value_store=[])", str(msg)) # end def data_ProposeMessage_with_InitMessage = { "type": PROPOSE, "sequence_no": 12, "node": 1, "leader": 1, "proposal": 0.5, "value_store": [data_InitMessage], } def test_ProposeMessage_with_InitMessage(self): msg = Message.from_dict(self.data_ProposeMessage_with_InitMessage) self.check_ProposeMessage(msg) self.assertEqual(len(msg.value_store), 1) self.check_InitMessage(msg.value_store[0], self.data_ProposeMessage_with_InitMessage["value_store"][0], ) # end def data_PrevoteMessage = { "type": PREVOTE, "sequence_no": 12, "node": 1, "leader": 1, "value": 0.5, } def check_PrevoteMessage(self, msg): self.assertIsInstance(msg, PrevoteMessage) self.assertEqual(msg.type, self.data_PrevoteMessage["type"]) self.assertEqual(msg.sequence_no, self.data_PrevoteMessage["sequence_no"]) self.assertEqual(msg.node, self.data_PrevoteMessage["node"]) self.assertEqual(msg.leader, self.data_PrevoteMessage["leader"]) self.assertEqual(msg.value, self.data_PrevoteMessage["value"]) # end def def test_PrevoteMessage_toObject(self): msg = PrevoteMessage.from_dict(self.data_PrevoteMessage) self.check_PrevoteMessage(msg) # end def def test_Message_toObject_PrevoteMessage(self): msg = Message.from_dict(self.data_PrevoteMessage) self.check_PrevoteMessage(msg) # end def def test_PrevoteMessage_toDict(self): data = self.data_PrevoteMessage msg = PrevoteMessage(data["sequence_no"], data["node"], data["leader"], data["value"]) self.check_PrevoteMessage(msg) self.assertDictEqual(msg.to_dict(), data) # end def def test_PrevoteMessage_toString(self): msg = Message.from_dict(self.data_PrevoteMessage) self.assertEqual("PrevoteMessage(leader=1, node=1, sequence_no=12, type=3, value=0.5)", str(msg)) # end def data_VoteMessage = { "type": VOTE, "sequence_no": 12, "node": 1, "leader": 1, "value": 0.5, } def check_VoteMessage(self, msg): self.assertIsInstance(msg, VoteMessage) self.assertEqual(msg.type, self.data_VoteMessage["type"]) self.assertEqual(msg.sequence_no, self.data_VoteMessage["sequence_no"]) self.assertEqual(msg.node, self.data_VoteMessage["node"]) self.assertEqual(msg.leader, self.data_VoteMessage["leader"]) self.assertEqual(msg.value, self.data_VoteMessage["value"]) # end def def test_VoteMessage_toObject(self): msg = VoteMessage.from_dict(self.data_VoteMessage) self.check_VoteMessage(msg) # end def def test_Message_toObject_VoteMessage(self): msg = Message.from_dict(self.data_VoteMessage) self.check_VoteMessage(msg) # end def def test_VoteMessage_toDict(self): data = self.data_VoteMessage msg = VoteMessage(data["sequence_no"], data["node"], data["leader"], data["value"]) self.check_VoteMessage(msg) self.assertDictEqual(msg.to_dict(), data) # end def def test_VoteMessage_toString(self): msg = Message.from_dict(self.data_VoteMessage) self.assertEqual("VoteMessage(leader=1, node=1, sequence_no=12, type=4, value=0.5)", str(msg)) # end def data_Acknowledge = { "type": ACKNOWLEDGE, "sequence_no": 12, "node": 1, "sender": 1, "raw": {}, } def check_Acknowledge(self, msg): self.assertIsInstance(msg, Acknowledge) self.assertEqual(msg.type, self.data_Acknowledge["type"]) self.assertEqual(msg.sequence_no, self.data_Acknowledge["sequence_no"]) self.assertEqual(msg.node, self.data_Acknowledge["node"]) self.assertEqual(msg.sender, self.data_Acknowledge["sender"]) self.assertDictEqual(msg.raw, self.data_Acknowledge["raw"]) # end def def test_Acknowledge_toObject(self): msg = Acknowledge.from_dict(self.data_Acknowledge) self.check_Acknowledge(msg) # end def def test_Message_Acknowledge_toObject(self): msg = Message.from_dict(self.data_Acknowledge) self.check_Acknowledge(msg) # end def def test_Acknowledge_toDict(self): data = self.data_Acknowledge msg = Acknowledge(data["sequence_no"], data["node"], data["sender"], data["raw"]) self.check_Acknowledge(msg) self.assertDictEqual(msg.to_dict(), data) # end def def test_Acknowledge_toString(self): msg = Message.from_dict(self.data_Acknowledge) self.assertEqual("Acknowledge(node=1, raw={}, sender=1, sequence_no=12, type=-1)", str(msg)) # end def data_unknown_type1 = { "type": UNSET, "sequence_no": 12, "node": 1, "foo": "bar", "best_pony": "Littlepip" } def test_Init_unknown_type1_toObject(self): data = self.data_unknown_type1 msg = Message.from_dict(data) self.assertIsInstance(msg, Message) self.assertEqual(msg.type, data["type"]) self.assertEqual(msg.sequence_no, data["sequence_no"]) # self.assertEqual(msg.node, data["node"]) # TODO put node to super, into Message # end def data_unknown_type2 = { "type": 4458, # <- this is different to data_unknown_type1 "sequence_no": 12, "node": 1, "foo": "bar", "best_pony": "Littlepip" } def test_Init_unknown_type2_toObject(self): self.assertRaises(AssertionError, Message.from_dict, self.data_unknown_type2) # end def def test_Message_new(self): # data is inline msg = Message(None, 12, 1) self.assertIsInstance(msg, Message) self.assertEqual(UNSET, msg.type) self.assertEqual(12, msg.sequence_no) # end def def test_Message_new_toString(self): msg = Message(None, 12, 1) self.assertEqual("Message(node=1, sequence_no=12, type=0)", str(msg)) # end def # end class if __name__ == '__main__': # pragma: no cover unittest.main() ================================================ FILE: code/node/todo.py ================================================ # -*- coding: utf-8 -*- from luckydonaldUtils.logger import logging __author__ = 'luckydonald' logger = logging.getLogger(__name__) def get_sensor_value(): return 0.5 # import random # return round(random.uniform(0.0, 1.0), 1) # end def def timeout(): return False # end def ================================================ FILE: code/tests.py ================================================ import unittest from node.tests import * if __name__ == '__main__': # pragma: no cover unittest.main() # end if ================================================ FILE: code/web/.bowerrc ================================================ { "directory": "/app/bower_components" } ================================================ FILE: code/web/Dockerfile ================================================ FROM node EXPOSE 8000 # Code Dir RUN mkdir -p /app/code WORKDIR /app/ # Node lib dir RUN npm config set prefix /app/libs #RUN echo $PATH ENV PATH /app/libs/bin:$PATH RUN echo $PATH # code install RUN npm install -g bower RUN npm install -g http-server ADD package.json /app # Bower install ADD .bowerrc /app ADD bower.json /app RUN bower install --allow-root ADD ./src /app/src ADD ./example /app/example COPY ./entrypoint.sh /entrypoint.sh RUN chmod +x /entrypoint.sh ENTRYPOINT ["/entrypoint.sh"] ================================================ FILE: code/web/bower.json ================================================ { "name": "pbft-gui", "description": "A starter project for AngularJS", "version": "0.0.0", "homepage": "https://github.com/angular/angular-seed", "license": "MIT", "private": true, "dependencies": { "angular": "~1.5.0", "angular-route": "1.5.0", "angular-loader": "1.5.0", "angular-mocks": "1.5.0", "angular-resource": "1.5.0", "angular-animate": "1.5.x", "html5-boilerplate": "^5.3.0", "bootstrap": "3.3.x", "jquery": "2.2.x", "d3": "~3.4", "highcharts": "5.0.7", "tooltipster": "4.2.3", "svg.js": "2.5.0", "svg.screenbbox.js": "0.1.2" }, "resolutions": { "angular": "~1.5.0" } } ================================================ FILE: code/web/d3/d3.v3.js ================================================ !function() { var d3 = { version: "3.5.17" }; var d3_arraySlice = [].slice, d3_array = function(list) { return d3_arraySlice.call(list); }; var d3_document = this.document; function d3_documentElement(node) { return node && (node.ownerDocument || node.document || node).documentElement; } function d3_window(node) { return node && (node.ownerDocument && node.ownerDocument.defaultView || node.document && node || node.defaultView); } if (d3_document) { try { d3_array(d3_document.documentElement.childNodes)[0].nodeType; } catch (e) { d3_array = function(list) { var i = list.length, array = new Array(i); while (i--) array[i] = list[i]; return array; }; } } if (!Date.now) Date.now = function() { return +new Date(); }; if (d3_document) { try { d3_document.createElement("DIV").style.setProperty("opacity", 0, ""); } catch (error) { 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; d3_element_prototype.setAttribute = function(name, value) { d3_element_setAttribute.call(this, name, value + ""); }; d3_element_prototype.setAttributeNS = function(space, local, value) { d3_element_setAttributeNS.call(this, space, local, value + ""); }; d3_style_prototype.setProperty = function(name, value, priority) { d3_style_setProperty.call(this, name, value + "", priority); }; } } d3.ascending = d3_ascending; function d3_ascending(a, b) { return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN; } d3.descending = function(a, b) { return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN; }; d3.min = function(array, f) { var i = -1, n = array.length, a, b; if (arguments.length === 1) { while (++i < n) if ((b = array[i]) != null && b >= b) { a = b; break; } while (++i < n) if ((b = array[i]) != null && a > b) a = b; } else { while (++i < n) if ((b = f.call(array, array[i], i)) != null && b >= b) { a = b; break; } while (++i < n) if ((b = f.call(array, array[i], i)) != null && a > b) a = b; } return a; }; d3.max = function(array, f) { var i = -1, n = array.length, a, b; if (arguments.length === 1) { while (++i < n) if ((b = array[i]) != null && b >= b) { a = b; break; } while (++i < n) if ((b = array[i]) != null && b > a) a = b; } else { while (++i < n) if ((b = f.call(array, array[i], i)) != null && b >= b) { a = b; break; } while (++i < n) if ((b = f.call(array, array[i], i)) != null && b > a) a = b; } return a; }; d3.extent = function(array, f) { var i = -1, n = array.length, a, b, c; if (arguments.length === 1) { while (++i < n) if ((b = array[i]) != null && b >= b) { a = c = b; break; } while (++i < n) if ((b = array[i]) != null) { if (a > b) a = b; if (c < b) c = b; } } else { while (++i < n) if ((b = f.call(array, array[i], i)) != null && b >= b) { a = c = b; break; } while (++i < n) if ((b = f.call(array, array[i], i)) != null) { if (a > b) a = b; if (c < b) c = b; } } return [ a, c ]; }; function d3_number(x) { return x === null ? NaN : +x; } function d3_numeric(x) { return !isNaN(x); } d3.sum = function(array, f) { var s = 0, n = array.length, a, i = -1; if (arguments.length === 1) { while (++i < n) if (d3_numeric(a = +array[i])) s += a; } else { while (++i < n) if (d3_numeric(a = +f.call(array, array[i], i))) s += a; } return s; }; d3.mean = function(array, f) { var s = 0, n = array.length, a, i = -1, j = n; if (arguments.length === 1) { while (++i < n) if (d3_numeric(a = d3_number(array[i]))) s += a; else --j; } else { while (++i < n) if (d3_numeric(a = d3_number(f.call(array, array[i], i)))) s += a; else --j; } if (j) return s / j; }; d3.quantile = function(values, p) { var H = (values.length - 1) * p + 1, h = Math.floor(H), v = +values[h - 1], e = H - h; return e ? v + e * (values[h] - v) : v; }; d3.median = function(array, f) { var numbers = [], n = array.length, a, i = -1; if (arguments.length === 1) { while (++i < n) if (d3_numeric(a = d3_number(array[i]))) numbers.push(a); } else { while (++i < n) if (d3_numeric(a = d3_number(f.call(array, array[i], i)))) numbers.push(a); } if (numbers.length) return d3.quantile(numbers.sort(d3_ascending), .5); }; d3.variance = function(array, f) { var n = array.length, m = 0, a, d, s = 0, i = -1, j = 0; if (arguments.length === 1) { while (++i < n) { if (d3_numeric(a = d3_number(array[i]))) { d = a - m; m += d / ++j; s += d * (a - m); } } } else { while (++i < n) { if (d3_numeric(a = d3_number(f.call(array, array[i], i)))) { d = a - m; m += d / ++j; s += d * (a - m); } } } if (j > 1) return s / (j - 1); }; d3.deviation = function() { var v = d3.variance.apply(this, arguments); return v ? Math.sqrt(v) : v; }; function d3_bisector(compare) { return { left: function(a, x, lo, hi) { if (arguments.length < 3) lo = 0; if (arguments.length < 4) hi = a.length; while (lo < hi) { var mid = lo + hi >>> 1; if (compare(a[mid], x) < 0) lo = mid + 1; else hi = mid; } return lo; }, right: function(a, x, lo, hi) { if (arguments.length < 3) lo = 0; if (arguments.length < 4) hi = a.length; while (lo < hi) { var mid = lo + hi >>> 1; if (compare(a[mid], x) > 0) hi = mid; else lo = mid + 1; } return lo; } }; } var d3_bisect = d3_bisector(d3_ascending); d3.bisectLeft = d3_bisect.left; d3.bisect = d3.bisectRight = d3_bisect.right; d3.bisector = function(f) { return d3_bisector(f.length === 1 ? function(d, x) { return d3_ascending(f(d), x); } : f); }; d3.shuffle = function(array, i0, i1) { if ((m = arguments.length) < 3) { i1 = array.length; if (m < 2) i0 = 0; } var m = i1 - i0, t, i; while (m) { i = Math.random() * m-- | 0; t = array[m + i0], array[m + i0] = array[i + i0], array[i + i0] = t; } return array; }; d3.permute = function(array, indexes) { var i = indexes.length, permutes = new Array(i); while (i--) permutes[i] = array[indexes[i]]; return permutes; }; d3.pairs = function(array) { var i = 0, n = array.length - 1, p0, p1 = array[0], pairs = new Array(n < 0 ? 0 : n); while (i < n) pairs[i] = [ p0 = p1, p1 = array[++i] ]; return pairs; }; d3.transpose = function(matrix) { if (!(n = matrix.length)) return []; for (var i = -1, m = d3.min(matrix, d3_transposeLength), transpose = new Array(m); ++i < m; ) { for (var j = -1, n, row = transpose[i] = new Array(n); ++j < n; ) { row[j] = matrix[j][i]; } } return transpose; }; function d3_transposeLength(d) { return d.length; } d3.zip = function() { return d3.transpose(arguments); }; d3.keys = function(map) { var keys = []; for (var key in map) keys.push(key); return keys; }; d3.values = function(map) { var values = []; for (var key in map) values.push(map[key]); return values; }; d3.entries = function(map) { var entries = []; for (var key in map) entries.push({ key: key, value: map[key] }); return entries; }; d3.merge = function(arrays) { var n = arrays.length, m, i = -1, j = 0, merged, array; while (++i < n) j += arrays[i].length; merged = new Array(j); while (--n >= 0) { array = arrays[n]; m = array.length; while (--m >= 0) { merged[--j] = array[m]; } } return merged; }; var abs = Math.abs; d3.range = function(start, stop, step) { if (arguments.length < 3) { step = 1; if (arguments.length < 2) { stop = start; start = 0; } } if ((stop - start) / step === Infinity) throw new Error("infinite range"); var range = [], k = d3_range_integerScale(abs(step)), i = -1, j; start *= k, stop *= k, step *= k; if (step < 0) while ((j = start + step * ++i) > stop) range.push(j / k); else while ((j = start + step * ++i) < stop) range.push(j / k); return range; }; function d3_range_integerScale(x) { var k = 1; while (x * k % 1) k *= 10; return k; } function d3_class(ctor, properties) { for (var key in properties) { Object.defineProperty(ctor.prototype, key, { value: properties[key], enumerable: false }); } } d3.map = function(object, f) { var map = new d3_Map(); if (object instanceof d3_Map) { object.forEach(function(key, value) { map.set(key, value); }); } else if (Array.isArray(object)) { var i = -1, n = object.length, o; 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); } else { for (var key in object) map.set(key, object[key]); } return map; }; function d3_Map() { this._ = Object.create(null); } var d3_map_proto = "__proto__", d3_map_zero = "\x00"; d3_class(d3_Map, { has: d3_map_has, get: function(key) { return this._[d3_map_escape(key)]; }, set: function(key, value) { return this._[d3_map_escape(key)] = value; }, remove: d3_map_remove, keys: d3_map_keys, values: function() { var values = []; for (var key in this._) values.push(this._[key]); return values; }, entries: function() { var entries = []; for (var key in this._) entries.push({ key: d3_map_unescape(key), value: this._[key] }); return entries; }, size: d3_map_size, empty: d3_map_empty, forEach: function(f) { for (var key in this._) f.call(this, d3_map_unescape(key), this._[key]); } }); function d3_map_escape(key) { return (key += "") === d3_map_proto || key[0] === d3_map_zero ? d3_map_zero + key : key; } function d3_map_unescape(key) { return (key += "")[0] === d3_map_zero ? key.slice(1) : key; } function d3_map_has(key) { return d3_map_escape(key) in this._; } function d3_map_remove(key) { return (key = d3_map_escape(key)) in this._ && delete this._[key]; } function d3_map_keys() { var keys = []; for (var key in this._) keys.push(d3_map_unescape(key)); return keys; } function d3_map_size() { var size = 0; for (var key in this._) ++size; return size; } function d3_map_empty() { for (var key in this._) return false; return true; } d3.nest = function() { var nest = {}, keys = [], sortKeys = [], sortValues, rollup; function map(mapType, array, depth) { if (depth >= keys.length) return rollup ? rollup.call(nest, array) : sortValues ? array.sort(sortValues) : array; var i = -1, n = array.length, key = keys[depth++], keyValue, object, setter, valuesByKey = new d3_Map(), values; while (++i < n) { if (values = valuesByKey.get(keyValue = key(object = array[i]))) { values.push(object); } else { valuesByKey.set(keyValue, [ object ]); } } if (mapType) { object = mapType(); setter = function(keyValue, values) { object.set(keyValue, map(mapType, values, depth)); }; } else { object = {}; setter = function(keyValue, values) { object[keyValue] = map(mapType, values, depth); }; } valuesByKey.forEach(setter); return object; } function entries(map, depth) { if (depth >= keys.length) return map; var array = [], sortKey = sortKeys[depth++]; map.forEach(function(key, keyMap) { array.push({ key: key, values: entries(keyMap, depth) }); }); return sortKey ? array.sort(function(a, b) { return sortKey(a.key, b.key); }) : array; } nest.map = function(array, mapType) { return map(mapType, array, 0); }; nest.entries = function(array) { return entries(map(d3.map, array, 0), 0); }; nest.key = function(d) { keys.push(d); return nest; }; nest.sortKeys = function(order) { sortKeys[keys.length - 1] = order; return nest; }; nest.sortValues = function(order) { sortValues = order; return nest; }; nest.rollup = function(f) { rollup = f; return nest; }; return nest; }; d3.set = function(array) { var set = new d3_Set(); if (array) for (var i = 0, n = array.length; i < n; ++i) set.add(array[i]); return set; }; function d3_Set() { this._ = Object.create(null); } d3_class(d3_Set, { has: d3_map_has, add: function(key) { this._[d3_map_escape(key += "")] = true; return key; }, remove: d3_map_remove, values: d3_map_keys, size: d3_map_size, empty: d3_map_empty, forEach: function(f) { for (var key in this._) f.call(this, d3_map_unescape(key)); } }); d3.behavior = {}; function d3_identity(d) { return d; } d3.rebind = function(target, source) { var i = 1, n = arguments.length, method; while (++i < n) target[method = arguments[i]] = d3_rebind(target, source, source[method]); return target; }; function d3_rebind(target, source, method) { return function() { var value = method.apply(source, arguments); return value === source ? target : value; }; } function d3_vendorSymbol(object, name) { if (name in object) return name; name = name.charAt(0).toUpperCase() + name.slice(1); for (var i = 0, n = d3_vendorPrefixes.length; i < n; ++i) { var prefixName = d3_vendorPrefixes[i] + name; if (prefixName in object) return prefixName; } } var d3_vendorPrefixes = [ "webkit", "ms", "moz", "Moz", "o", "O" ]; function d3_noop() {} d3.dispatch = function() { var dispatch = new d3_dispatch(), i = -1, n = arguments.length; while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch); return dispatch; }; function d3_dispatch() {} d3_dispatch.prototype.on = function(type, listener) { var i = type.indexOf("."), name = ""; if (i >= 0) { name = type.slice(i + 1); type = type.slice(0, i); } if (type) return arguments.length < 2 ? this[type].on(name) : this[type].on(name, listener); if (arguments.length === 2) { if (listener == null) for (type in this) { if (this.hasOwnProperty(type)) this[type].on(name, null); } return this; } }; function d3_dispatch_event(dispatch) { var listeners = [], listenerByName = new d3_Map(); function event() { var z = listeners, i = -1, n = z.length, l; while (++i < n) if (l = z[i].on) l.apply(this, arguments); return dispatch; } event.on = function(name, listener) { var l = listenerByName.get(name), i; if (arguments.length < 2) return l && l.on; if (l) { l.on = null; listeners = listeners.slice(0, i = listeners.indexOf(l)).concat(listeners.slice(i + 1)); listenerByName.remove(name); } if (listener) listeners.push(listenerByName.set(name, { on: listener })); return dispatch; }; return event; } d3.event = null; function d3_eventPreventDefault() { d3.event.preventDefault(); } function d3_eventSource() { var e = d3.event, s; while (s = e.sourceEvent) e = s; return e; } function d3_eventDispatch(target) { var dispatch = new d3_dispatch(), i = 0, n = arguments.length; while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch); dispatch.of = function(thiz, argumentz) { return function(e1) { try { var e0 = e1.sourceEvent = d3.event; e1.target = target; d3.event = e1; dispatch[e1.type].apply(thiz, argumentz); } finally { d3.event = e0; } }; }; return dispatch; } d3.requote = function(s) { return s.replace(d3_requote_re, "\\$&"); }; var d3_requote_re = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g; var d3_subclass = {}.__proto__ ? function(object, prototype) { object.__proto__ = prototype; } : function(object, prototype) { for (var property in prototype) object[property] = prototype[property]; }; function d3_selection(groups) { d3_subclass(groups, d3_selectionPrototype); return groups; } var d3_select = function(s, n) { return n.querySelector(s); }, d3_selectAll = function(s, n) { return n.querySelectorAll(s); }, d3_selectMatches = function(n, s) { var d3_selectMatcher = n.matches || n[d3_vendorSymbol(n, "matchesSelector")]; d3_selectMatches = function(n, s) { return d3_selectMatcher.call(n, s); }; return d3_selectMatches(n, s); }; if (typeof Sizzle === "function") { d3_select = function(s, n) { return Sizzle(s, n)[0] || null; }; d3_selectAll = Sizzle; d3_selectMatches = Sizzle.matchesSelector; } d3.selection = function() { return d3.select(d3_document.documentElement); }; var d3_selectionPrototype = d3.selection.prototype = []; d3_selectionPrototype.select = function(selector) { var subgroups = [], subgroup, subnode, group, node; selector = d3_selection_selector(selector); for (var j = -1, m = this.length; ++j < m; ) { subgroups.push(subgroup = []); subgroup.parentNode = (group = this[j]).parentNode; for (var i = -1, n = group.length; ++i < n; ) { if (node = group[i]) { subgroup.push(subnode = selector.call(node, node.__data__, i, j)); if (subnode && "__data__" in node) subnode.__data__ = node.__data__; } else { subgroup.push(null); } } } return d3_selection(subgroups); }; function d3_selection_selector(selector) { return typeof selector === "function" ? selector : function() { return d3_select(selector, this); }; } d3_selectionPrototype.selectAll = function(selector) { var subgroups = [], subgroup, node; selector = d3_selection_selectorAll(selector); for (var j = -1, m = this.length; ++j < m; ) { for (var group = this[j], i = -1, n = group.length; ++i < n; ) { if (node = group[i]) { subgroups.push(subgroup = d3_array(selector.call(node, node.__data__, i, j))); subgroup.parentNode = node; } } } return d3_selection(subgroups); }; function d3_selection_selectorAll(selector) { return typeof selector === "function" ? selector : function() { return d3_selectAll(selector, this); }; } var d3_nsXhtml = "http://www.w3.org/1999/xhtml"; var d3_nsPrefix = { svg: "http://www.w3.org/2000/svg", xhtml: d3_nsXhtml, xlink: "http://www.w3.org/1999/xlink", xml: "http://www.w3.org/XML/1998/namespace", xmlns: "http://www.w3.org/2000/xmlns/" }; d3.ns = { prefix: d3_nsPrefix, qualify: function(name) { var i = name.indexOf(":"), prefix = name; if (i >= 0 && (prefix = name.slice(0, i)) !== "xmlns") name = name.slice(i + 1); return d3_nsPrefix.hasOwnProperty(prefix) ? { space: d3_nsPrefix[prefix], local: name } : name; } }; d3_selectionPrototype.attr = function(name, value) { if (arguments.length < 2) { if (typeof name === "string") { var node = this.node(); name = d3.ns.qualify(name); return name.local ? node.getAttributeNS(name.space, name.local) : node.getAttribute(name); } for (value in name) this.each(d3_selection_attr(value, name[value])); return this; } return this.each(d3_selection_attr(name, value)); }; function d3_selection_attr(name, value) { name = d3.ns.qualify(name); function attrNull() { this.removeAttribute(name); } function attrNullNS() { this.removeAttributeNS(name.space, name.local); } function attrConstant() { this.setAttribute(name, value); } function attrConstantNS() { this.setAttributeNS(name.space, name.local, value); } function attrFunction() { var x = value.apply(this, arguments); if (x == null) this.removeAttribute(name); else this.setAttribute(name, x); } function attrFunctionNS() { var x = value.apply(this, arguments); if (x == null) this.removeAttributeNS(name.space, name.local); else this.setAttributeNS(name.space, name.local, x); } return value == null ? name.local ? attrNullNS : attrNull : typeof value === "function" ? name.local ? attrFunctionNS : attrFunction : name.local ? attrConstantNS : attrConstant; } function d3_collapse(s) { return s.trim().replace(/\s+/g, " "); } d3_selectionPrototype.classed = function(name, value) { if (arguments.length < 2) { if (typeof name === "string") { var node = this.node(), n = (name = d3_selection_classes(name)).length, i = -1; if (value = node.classList) { while (++i < n) if (!value.contains(name[i])) return false; } else { value = node.getAttribute("class"); while (++i < n) if (!d3_selection_classedRe(name[i]).test(value)) return false; } return true; } for (value in name) this.each(d3_selection_classed(value, name[value])); return this; } return this.each(d3_selection_classed(name, value)); }; function d3_selection_classedRe(name) { return new RegExp("(?:^|\\s+)" + d3.requote(name) + "(?:\\s+|$)", "g"); } function d3_selection_classes(name) { return (name + "").trim().split(/^|\s+/); } function d3_selection_classed(name, value) { name = d3_selection_classes(name).map(d3_selection_classedName); var n = name.length; function classedConstant() { var i = -1; while (++i < n) name[i](this, value); } function classedFunction() { var i = -1, x = value.apply(this, arguments); while (++i < n) name[i](this, x); } return typeof value === "function" ? classedFunction : classedConstant; } function d3_selection_classedName(name) { var re = d3_selection_classedRe(name); return function(node, value) { if (c = node.classList) return value ? c.add(name) : c.remove(name); var c = node.getAttribute("class") || ""; if (value) { re.lastIndex = 0; if (!re.test(c)) node.setAttribute("class", d3_collapse(c + " " + name)); } else { node.setAttribute("class", d3_collapse(c.replace(re, " "))); } }; } d3_selectionPrototype.style = function(name, value, priority) { var n = arguments.length; if (n < 3) { if (typeof name !== "string") { if (n < 2) value = ""; for (priority in name) this.each(d3_selection_style(priority, name[priority], value)); return this; } if (n < 2) { var node = this.node(); return d3_window(node).getComputedStyle(node, null).getPropertyValue(name); } priority = ""; } return this.each(d3_selection_style(name, value, priority)); }; function d3_selection_style(name, value, priority) { function styleNull() { this.style.removeProperty(name); } function styleConstant() { this.style.setProperty(name, value, priority); } function styleFunction() { var x = value.apply(this, arguments); if (x == null) this.style.removeProperty(name); else this.style.setProperty(name, x, priority); } return value == null ? styleNull : typeof value === "function" ? styleFunction : styleConstant; } d3_selectionPrototype.property = function(name, value) { if (arguments.length < 2) { if (typeof name === "string") return this.node()[name]; for (value in name) this.each(d3_selection_property(value, name[value])); return this; } return this.each(d3_selection_property(name, value)); }; function d3_selection_property(name, value) { function propertyNull() { delete this[name]; } function propertyConstant() { this[name] = value; } function propertyFunction() { var x = value.apply(this, arguments); if (x == null) delete this[name]; else this[name] = x; } return value == null ? propertyNull : typeof value === "function" ? propertyFunction : propertyConstant; } d3_selectionPrototype.text = function(value) { return arguments.length ? this.each(typeof value === "function" ? function() { var v = value.apply(this, arguments); this.textContent = v == null ? "" : v; } : value == null ? function() { this.textContent = ""; } : function() { this.textContent = value; }) : this.node().textContent; }; d3_selectionPrototype.html = function(value) { return arguments.length ? this.each(typeof value === "function" ? function() { var v = value.apply(this, arguments); this.innerHTML = v == null ? "" : v; } : value == null ? function() { this.innerHTML = ""; } : function() { this.innerHTML = value; }) : this.node().innerHTML; }; d3_selectionPrototype.append = function(name) { name = d3_selection_creator(name); return this.select(function() { return this.appendChild(name.apply(this, arguments)); }); }; function d3_selection_creator(name) { function create() { var document = this.ownerDocument, namespace = this.namespaceURI; return namespace === d3_nsXhtml && document.documentElement.namespaceURI === d3_nsXhtml ? document.createElement(name) : document.createElementNS(namespace, name); } function createNS() { return this.ownerDocument.createElementNS(name.space, name.local); } return typeof name === "function" ? name : (name = d3.ns.qualify(name)).local ? createNS : create; } d3_selectionPrototype.insert = function(name, before) { name = d3_selection_creator(name); before = d3_selection_selector(before); return this.select(function() { return this.insertBefore(name.apply(this, arguments), before.apply(this, arguments) || null); }); }; d3_selectionPrototype.remove = function() { return this.each(d3_selectionRemove); }; function d3_selectionRemove() { var parent = this.parentNode; if (parent) parent.removeChild(this); } d3_selectionPrototype.data = function(value, key) { var i = -1, n = this.length, group, node; if (!arguments.length) { value = new Array(n = (group = this[0]).length); while (++i < n) { if (node = group[i]) { value[i] = node.__data__; } } return value; } function bind(group, groupData) { 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; if (key) { var nodeByKeyValue = new d3_Map(), keyValues = new Array(n), keyValue; for (i = -1; ++i < n; ) { if (node = group[i]) { if (nodeByKeyValue.has(keyValue = key.call(node, node.__data__, i))) { exitNodes[i] = node; } else { nodeByKeyValue.set(keyValue, node); } keyValues[i] = keyValue; } } for (i = -1; ++i < m; ) { if (!(node = nodeByKeyValue.get(keyValue = key.call(groupData, nodeData = groupData[i], i)))) { enterNodes[i] = d3_selection_dataNode(nodeData); } else if (node !== true) { updateNodes[i] = node; node.__data__ = nodeData; } nodeByKeyValue.set(keyValue, true); } for (i = -1; ++i < n; ) { if (i in keyValues && nodeByKeyValue.get(keyValues[i]) !== true) { exitNodes[i] = group[i]; } } } else { for (i = -1; ++i < n0; ) { node = group[i]; nodeData = groupData[i]; if (node) { node.__data__ = nodeData; updateNodes[i] = node; } else { enterNodes[i] = d3_selection_dataNode(nodeData); } } for (;i < m; ++i) { enterNodes[i] = d3_selection_dataNode(groupData[i]); } for (;i < n; ++i) { exitNodes[i] = group[i]; } } enterNodes.update = updateNodes; enterNodes.parentNode = updateNodes.parentNode = exitNodes.parentNode = group.parentNode; enter.push(enterNodes); update.push(updateNodes); exit.push(exitNodes); } var enter = d3_selection_enter([]), update = d3_selection([]), exit = d3_selection([]); if (typeof value === "function") { while (++i < n) { bind(group = this[i], value.call(group, group.parentNode.__data__, i)); } } else { while (++i < n) { bind(group = this[i], value); } } update.enter = function() { return enter; }; update.exit = function() { return exit; }; return update; }; function d3_selection_dataNode(data) { return { __data__: data }; } d3_selectionPrototype.datum = function(value) { return arguments.length ? this.property("__data__", value) : this.property("__data__"); }; d3_selectionPrototype.filter = function(filter) { var subgroups = [], subgroup, group, node; if (typeof filter !== "function") filter = d3_selection_filter(filter); for (var j = 0, m = this.length; j < m; j++) { subgroups.push(subgroup = []); subgroup.parentNode = (group = this[j]).parentNode; for (var i = 0, n = group.length; i < n; i++) { if ((node = group[i]) && filter.call(node, node.__data__, i, j)) { subgroup.push(node); } } } return d3_selection(subgroups); }; function d3_selection_filter(selector) { return function() { return d3_selectMatches(this, selector); }; } d3_selectionPrototype.order = function() { for (var j = -1, m = this.length; ++j < m; ) { for (var group = this[j], i = group.length - 1, next = group[i], node; --i >= 0; ) { if (node = group[i]) { if (next && next !== node.nextSibling) next.parentNode.insertBefore(node, next); next = node; } } } return this; }; d3_selectionPrototype.sort = function(comparator) { comparator = d3_selection_sortComparator.apply(this, arguments); for (var j = -1, m = this.length; ++j < m; ) this[j].sort(comparator); return this.order(); }; function d3_selection_sortComparator(comparator) { if (!arguments.length) comparator = d3_ascending; return function(a, b) { return a && b ? comparator(a.__data__, b.__data__) : !a - !b; }; } d3_selectionPrototype.each = function(callback) { return d3_selection_each(this, function(node, i, j) { callback.call(node, node.__data__, i, j); }); }; function d3_selection_each(groups, callback) { for (var j = 0, m = groups.length; j < m; j++) { for (var group = groups[j], i = 0, n = group.length, node; i < n; i++) { if (node = group[i]) callback(node, i, j); } } return groups; } d3_selectionPrototype.call = function(callback) { var args = d3_array(arguments); callback.apply(args[0] = this, args); return this; }; d3_selectionPrototype.empty = function() { return !this.node(); }; d3_selectionPrototype.node = function() { for (var j = 0, m = this.length; j < m; j++) { for (var group = this[j], i = 0, n = group.length; i < n; i++) { var node = group[i]; if (node) return node; } } return null; }; d3_selectionPrototype.size = function() { var n = 0; d3_selection_each(this, function() { ++n; }); return n; }; function d3_selection_enter(selection) { d3_subclass(selection, d3_selection_enterPrototype); return selection; } var d3_selection_enterPrototype = []; d3.selection.enter = d3_selection_enter; d3.selection.enter.prototype = d3_selection_enterPrototype; d3_selection_enterPrototype.append = d3_selectionPrototype.append; d3_selection_enterPrototype.empty = d3_selectionPrototype.empty; d3_selection_enterPrototype.node = d3_selectionPrototype.node; d3_selection_enterPrototype.call = d3_selectionPrototype.call; d3_selection_enterPrototype.size = d3_selectionPrototype.size; d3_selection_enterPrototype.select = function(selector) { var subgroups = [], subgroup, subnode, upgroup, group, node; for (var j = -1, m = this.length; ++j < m; ) { upgroup = (group = this[j]).update; subgroups.push(subgroup = []); subgroup.parentNode = group.parentNode; for (var i = -1, n = group.length; ++i < n; ) { if (node = group[i]) { subgroup.push(upgroup[i] = subnode = selector.call(group.parentNode, node.__data__, i, j)); subnode.__data__ = node.__data__; } else { subgroup.push(null); } } } return d3_selection(subgroups); }; d3_selection_enterPrototype.insert = function(name, before) { if (arguments.length < 2) before = d3_selection_enterInsertBefore(this); return d3_selectionPrototype.insert.call(this, name, before); }; function d3_selection_enterInsertBefore(enter) { var i0, j0; return function(d, i, j) { var group = enter[j].update, n = group.length, node; if (j != j0) j0 = j, i0 = 0; if (i >= i0) i0 = i + 1; while (!(node = group[i0]) && ++i0 < n) ; return node; }; } d3.select = function(node) { var group; if (typeof node === "string") { group = [ d3_select(node, d3_document) ]; group.parentNode = d3_document.documentElement; } else { group = [ node ]; group.parentNode = d3_documentElement(node); } return d3_selection([ group ]); }; d3.selectAll = function(nodes) { var group; if (typeof nodes === "string") { group = d3_array(d3_selectAll(nodes, d3_document)); group.parentNode = d3_document.documentElement; } else { group = d3_array(nodes); group.parentNode = null; } return d3_selection([ group ]); }; d3_selectionPrototype.on = function(type, listener, capture) { var n = arguments.length; if (n < 3) { if (typeof type !== "string") { if (n < 2) listener = false; for (capture in type) this.each(d3_selection_on(capture, type[capture], listener)); return this; } if (n < 2) return (n = this.node()["__on" + type]) && n._; capture = false; } return this.each(d3_selection_on(type, listener, capture)); }; function d3_selection_on(type, listener, capture) { var name = "__on" + type, i = type.indexOf("."), wrap = d3_selection_onListener; if (i > 0) type = type.slice(0, i); var filter = d3_selection_onFilters.get(type); if (filter) type = filter, wrap = d3_selection_onFilter; function onRemove() { var l = this[name]; if (l) { this.removeEventListener(type, l, l.$); delete this[name]; } } function onAdd() { var l = wrap(listener, d3_array(arguments)); onRemove.call(this); this.addEventListener(type, this[name] = l, l.$ = capture); l._ = listener; } function removeAll() { var re = new RegExp("^__on([^.]+)" + d3.requote(type) + "$"), match; for (var name in this) { if (match = name.match(re)) { var l = this[name]; this.removeEventListener(match[1], l, l.$); delete this[name]; } } } return i ? listener ? onAdd : onRemove : listener ? d3_noop : removeAll; } var d3_selection_onFilters = d3.map({ mouseenter: "mouseover", mouseleave: "mouseout" }); if (d3_document) { d3_selection_onFilters.forEach(function(k) { if ("on" + k in d3_document) d3_selection_onFilters.remove(k); }); } function d3_selection_onListener(listener, argumentz) { return function(e) { var o = d3.event; d3.event = e; argumentz[0] = this.__data__; try { listener.apply(this, argumentz); } finally { d3.event = o; } }; } function d3_selection_onFilter(listener, argumentz) { var l = d3_selection_onListener(listener, argumentz); return function(e) { var target = this, related = e.relatedTarget; if (!related || related !== target && !(related.compareDocumentPosition(target) & 8)) { l.call(target, e); } }; } var d3_event_dragSelect, d3_event_dragId = 0; function d3_event_dragSuppress(node) { 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); if (d3_event_dragSelect == null) { d3_event_dragSelect = "onselectstart" in node ? false : d3_vendorSymbol(node.style, "userSelect"); } if (d3_event_dragSelect) { var style = d3_documentElement(node).style, select = style[d3_event_dragSelect]; style[d3_event_dragSelect] = "none"; } return function(suppressClick) { w.on(name, null); if (d3_event_dragSelect) style[d3_event_dragSelect] = select; if (suppressClick) { var off = function() { w.on(click, null); }; w.on(click, function() { d3_eventPreventDefault(); off(); }, true); setTimeout(off, 0); } }; } d3.mouse = function(container) { return d3_mousePoint(container, d3_eventSource()); }; var d3_mouse_bug44083 = this.navigator && /WebKit/.test(this.navigator.userAgent) ? -1 : 0; function d3_mousePoint(container, e) { if (e.changedTouches) e = e.changedTouches[0]; var svg = container.ownerSVGElement || container; if (svg.createSVGPoint) { var point = svg.createSVGPoint(); if (d3_mouse_bug44083 < 0) { var window = d3_window(container); if (window.scrollX || window.scrollY) { svg = d3.select("body").append("svg").style({ position: "absolute", top: 0, left: 0, margin: 0, padding: 0, border: "none" }, "important"); var ctm = svg[0][0].getScreenCTM(); d3_mouse_bug44083 = !(ctm.f || ctm.e); svg.remove(); } } if (d3_mouse_bug44083) point.x = e.pageX, point.y = e.pageY; else point.x = e.clientX, point.y = e.clientY; point = point.matrixTransform(container.getScreenCTM().inverse()); return [ point.x, point.y ]; } var rect = container.getBoundingClientRect(); return [ e.clientX - rect.left - container.clientLeft, e.clientY - rect.top - container.clientTop ]; } d3.touch = function(container, touches, identifier) { if (arguments.length < 3) identifier = touches, touches = d3_eventSource().changedTouches; if (touches) for (var i = 0, n = touches.length, touch; i < n; ++i) { if ((touch = touches[i]).identifier === identifier) { return d3_mousePoint(container, touch); } } }; d3.behavior.drag = function() { 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"); function drag() { this.on("mousedown.drag", mousedown).on("touchstart.drag", touchstart); } function dragstart(id, position, subject, move, end) { return function() { 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); if (origin) { dragOffset = origin.apply(that, arguments); dragOffset = [ dragOffset.x - position0[0], dragOffset.y - position0[1] ]; } else { dragOffset = [ 0, 0 ]; } dispatch({ type: "dragstart" }); function moved() { var position1 = position(parent, dragId), dx, dy; if (!position1) return; dx = position1[0] - position0[0]; dy = position1[1] - position0[1]; dragged |= dx | dy; position0 = position1; dispatch({ type: "drag", x: position1[0] + dragOffset[0], y: position1[1] + dragOffset[1], dx: dx, dy: dy }); } function ended() { if (!position(parent, dragId)) return; dragSubject.on(move + dragName, null).on(end + dragName, null); dragRestore(dragged); dispatch({ type: "dragend" }); } }; } drag.origin = function(x) { if (!arguments.length) return origin; origin = x; return drag; }; return d3.rebind(drag, event, "on"); }; function d3_behavior_dragTouchId() { return d3.event.changedTouches[0].identifier; } d3.touches = function(container, touches) { if (arguments.length < 2) touches = d3_eventSource().touches; return touches ? d3_array(touches).map(function(touch) { var point = d3_mousePoint(container, touch); point.identifier = touch.identifier; return point; }) : []; }; var ε = 1e-6, ε2 = ε * ε, π = Math.PI, τ = 2 * π, τε = τ - ε, halfπ = π / 2, d3_radians = π / 180, d3_degrees = 180 / π; function d3_sgn(x) { return x > 0 ? 1 : x < 0 ? -1 : 0; } function d3_cross2d(a, b, c) { return (b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0]); } function d3_acos(x) { return x > 1 ? 0 : x < -1 ? π : Math.acos(x); } function d3_asin(x) { return x > 1 ? halfπ : x < -1 ? -halfπ : Math.asin(x); } function d3_sinh(x) { return ((x = Math.exp(x)) - 1 / x) / 2; } function d3_cosh(x) { return ((x = Math.exp(x)) + 1 / x) / 2; } function d3_tanh(x) { return ((x = Math.exp(2 * x)) - 1) / (x + 1); } function d3_haversin(x) { return (x = Math.sin(x / 2)) * x; } var ρ = Math.SQRT2, ρ2 = 2, ρ4 = 4; d3.interpolateZoom = function(p0, p1) { 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; if (d2 < ε2) { S = Math.log(w1 / w0) / ρ; i = function(t) { return [ ux0 + t * dx, uy0 + t * dy, w0 * Math.exp(ρ * t * S) ]; }; } else { 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); S = (r1 - r0) / ρ; i = function(t) { var s = t * S, coshr0 = d3_cosh(r0), u = w0 / (ρ2 * d1) * (coshr0 * d3_tanh(ρ * s + r0) - d3_sinh(r0)); return [ ux0 + u * dx, uy0 + u * dy, w0 * coshr0 / d3_cosh(ρ * s + r0) ]; }; } i.duration = S * 1e3; return i; }; d3.behavior.zoom = function() { var view = { x: 0, y: 0, k: 1 }, 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; if (!d3_behavior_zoomWheel) { d3_behavior_zoomWheel = "onwheel" in d3_document ? (d3_behavior_zoomDelta = function() { return -d3.event.deltaY * (d3.event.deltaMode ? 120 : 1); }, "wheel") : "onmousewheel" in d3_document ? (d3_behavior_zoomDelta = function() { return d3.event.wheelDelta; }, "mousewheel") : (d3_behavior_zoomDelta = function() { return -d3.event.detail; }, "MozMousePixelScroll"); } function zoom(g) { g.on(mousedown, mousedowned).on(d3_behavior_zoomWheel + ".zoom", mousewheeled).on("dblclick.zoom", dblclicked).on(touchstart, touchstarted); } zoom.event = function(g) { g.each(function() { var dispatch = event.of(this, arguments), view1 = view; if (d3_transitionInheritId) { d3.select(this).transition().each("start.zoom", function() { view = this.__chart__ || { x: 0, y: 0, k: 1 }; zoomstarted(dispatch); }).tween("zoom:zoom", function() { 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 ]); return function(t) { var l = i(t), k = dx / l[2]; this.__chart__ = view = { x: cx - l[0] * k, y: cy - l[1] * k, k: k }; zoomed(dispatch); }; }).each("interrupt.zoom", function() { zoomended(dispatch); }).each("end.zoom", function() { zoomended(dispatch); }); } else { this.__chart__ = view; zoomstarted(dispatch); zoomed(dispatch); zoomended(dispatch); } }); }; zoom.translate = function(_) { if (!arguments.length) return [ view.x, view.y ]; view = { x: +_[0], y: +_[1], k: view.k }; rescale(); return zoom; }; zoom.scale = function(_) { if (!arguments.length) return view.k; view = { x: view.x, y: view.y, k: null }; scaleTo(+_); rescale(); return zoom; }; zoom.scaleExtent = function(_) { if (!arguments.length) return scaleExtent; scaleExtent = _ == null ? d3_behavior_zoomInfinity : [ +_[0], +_[1] ]; return zoom; }; zoom.center = function(_) { if (!arguments.length) return center; center = _ && [ +_[0], +_[1] ]; return zoom; }; zoom.size = function(_) { if (!arguments.length) return size; size = _ && [ +_[0], +_[1] ]; return zoom; }; zoom.duration = function(_) { if (!arguments.length) return duration; duration = +_; return zoom; }; zoom.x = function(z) { if (!arguments.length) return x1; x1 = z; x0 = z.copy(); view = { x: 0, y: 0, k: 1 }; return zoom; }; zoom.y = function(z) { if (!arguments.length) return y1; y1 = z; y0 = z.copy(); view = { x: 0, y: 0, k: 1 }; return zoom; }; function location(p) { return [ (p[0] - view.x) / view.k, (p[1] - view.y) / view.k ]; } function point(l) { return [ l[0] * view.k + view.x, l[1] * view.k + view.y ]; } function scaleTo(s) { view.k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], s)); } function translateTo(p, l) { l = point(l); view.x += p[0] - l[0]; view.y += p[1] - l[1]; } function zoomTo(that, p, l, k) { that.__chart__ = { x: view.x, y: view.y, k: view.k }; scaleTo(Math.pow(2, k)); translateTo(center0 = p, l); that = d3.select(that); if (duration > 0) that = that.transition().duration(duration); that.call(zoom.event); } function rescale() { if (x1) x1.domain(x0.range().map(function(x) { return (x - view.x) / view.k; }).map(x0.invert)); if (y1) y1.domain(y0.range().map(function(y) { return (y - view.y) / view.k; }).map(y0.invert)); } function zoomstarted(dispatch) { if (!zooming++) dispatch({ type: "zoomstart" }); } function zoomed(dispatch) { rescale(); dispatch({ type: "zoom", scale: view.k, translate: [ view.x, view.y ] }); } function zoomended(dispatch) { if (!--zooming) dispatch({ type: "zoomend" }), center0 = null; } function mousedowned() { 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); d3_selection_interrupt.call(that); zoomstarted(dispatch); function moved() { dragged = 1; translateTo(d3.mouse(that), location0); zoomed(dispatch); } function ended() { subject.on(mousemove, null).on(mouseup, null); dragRestore(dragged); zoomended(dispatch); } } function touchstarted() { 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); started(); zoomstarted(dispatch); subject.on(mousedown, null).on(touchstart, started); function relocate() { var touches = d3.touches(that); scale0 = view.k; touches.forEach(function(t) { if (t.identifier in locations0) locations0[t.identifier] = location(t); }); return touches; } function started() { var target = d3.event.target; d3.select(target).on(touchmove, moved).on(touchend, ended); targets.push(target); var changed = d3.event.changedTouches; for (var i = 0, n = changed.length; i < n; ++i) { locations0[changed[i].identifier] = null; } var touches = relocate(), now = Date.now(); if (touches.length === 1) { if (now - touchtime < 500) { var p = touches[0]; zoomTo(that, p, locations0[p.identifier], Math.floor(Math.log(view.k) / Math.LN2) + 1); d3_eventPreventDefault(); } touchtime = now; } else if (touches.length > 1) { var p = touches[0], q = touches[1], dx = p[0] - q[0], dy = p[1] - q[1]; distance0 = dx * dx + dy * dy; } } function moved() { var touches = d3.touches(that), p0, l0, p1, l1; d3_selection_interrupt.call(that); for (var i = 0, n = touches.length; i < n; ++i, l1 = null) { p1 = touches[i]; if (l1 = locations0[p1.identifier]) { if (l0) break; p0 = p1, l0 = l1; } } if (l1) { var distance1 = (distance1 = p1[0] - p0[0]) * distance1 + (distance1 = p1[1] - p0[1]) * distance1, scale1 = distance0 && Math.sqrt(distance1 / distance0); p0 = [ (p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2 ]; l0 = [ (l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2 ]; scaleTo(scale1 * scale0); } touchtime = null; translateTo(p0, l0); zoomed(dispatch); } function ended() { if (d3.event.touches.length) { var changed = d3.event.changedTouches; for (var i = 0, n = changed.length; i < n; ++i) { delete locations0[changed[i].identifier]; } for (var identifier in locations0) { return void relocate(); } } d3.selectAll(targets).on(zoomName, null); subject.on(mousedown, mousedowned).on(touchstart, touchstarted); dragRestore(); zoomended(dispatch); } } function mousewheeled() { var dispatch = event.of(this, arguments); if (mousewheelTimer) clearTimeout(mousewheelTimer); else d3_selection_interrupt.call(this), translate0 = location(center0 = center || d3.mouse(this)), zoomstarted(dispatch); mousewheelTimer = setTimeout(function() { mousewheelTimer = null; zoomended(dispatch); }, 50); d3_eventPreventDefault(); scaleTo(Math.pow(2, d3_behavior_zoomDelta() * .002) * view.k); translateTo(center0, translate0); zoomed(dispatch); } function dblclicked() { var p = d3.mouse(this), k = Math.log(view.k) / Math.LN2; zoomTo(this, p, location(p), d3.event.shiftKey ? Math.ceil(k) - 1 : Math.floor(k) + 1); } return d3.rebind(zoom, event, "on"); }; var d3_behavior_zoomInfinity = [ 0, Infinity ], d3_behavior_zoomDelta, d3_behavior_zoomWheel; d3.color = d3_color; function d3_color() {} d3_color.prototype.toString = function() { return this.rgb() + ""; }; d3.hsl = d3_hsl; function d3_hsl(h, s, l) { 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); } var d3_hslPrototype = d3_hsl.prototype = new d3_color(); d3_hslPrototype.brighter = function(k) { k = Math.pow(.7, arguments.length ? k : 1); return new d3_hsl(this.h, this.s, this.l / k); }; d3_hslPrototype.darker = function(k) { k = Math.pow(.7, arguments.length ? k : 1); return new d3_hsl(this.h, this.s, k * this.l); }; d3_hslPrototype.rgb = function() { return d3_hsl_rgb(this.h, this.s, this.l); }; function d3_hsl_rgb(h, s, l) { var m1, m2; h = isNaN(h) ? 0 : (h %= 360) < 0 ? h + 360 : h; s = isNaN(s) ? 0 : s < 0 ? 0 : s > 1 ? 1 : s; l = l < 0 ? 0 : l > 1 ? 1 : l; m2 = l <= .5 ? l * (1 + s) : l + s - l * s; m1 = 2 * l - m2; function v(h) { if (h > 360) h -= 360; else if (h < 0) h += 360; if (h < 60) return m1 + (m2 - m1) * h / 60; if (h < 180) return m2; if (h < 240) return m1 + (m2 - m1) * (240 - h) / 60; return m1; } function vv(h) { return Math.round(v(h) * 255); } return new d3_rgb(vv(h + 120), vv(h), vv(h - 120)); } d3.hcl = d3_hcl; function d3_hcl(h, c, l) { 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); } var d3_hclPrototype = d3_hcl.prototype = new d3_color(); d3_hclPrototype.brighter = function(k) { return new d3_hcl(this.h, this.c, Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1))); }; d3_hclPrototype.darker = function(k) { return new d3_hcl(this.h, this.c, Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1))); }; d3_hclPrototype.rgb = function() { return d3_hcl_lab(this.h, this.c, this.l).rgb(); }; function d3_hcl_lab(h, c, l) { if (isNaN(h)) h = 0; if (isNaN(c)) c = 0; return new d3_lab(l, Math.cos(h *= d3_radians) * c, Math.sin(h) * c); } d3.lab = d3_lab; function d3_lab(l, a, b) { 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); } var d3_lab_K = 18; var d3_lab_X = .95047, d3_lab_Y = 1, d3_lab_Z = 1.08883; var d3_labPrototype = d3_lab.prototype = new d3_color(); d3_labPrototype.brighter = function(k) { return new d3_lab(Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1)), this.a, this.b); }; d3_labPrototype.darker = function(k) { return new d3_lab(Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1)), this.a, this.b); }; d3_labPrototype.rgb = function() { return d3_lab_rgb(this.l, this.a, this.b); }; function d3_lab_rgb(l, a, b) { var y = (l + 16) / 116, x = y + a / 500, z = y - b / 200; x = d3_lab_xyz(x) * d3_lab_X; y = d3_lab_xyz(y) * d3_lab_Y; z = d3_lab_xyz(z) * d3_lab_Z; 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)); } function d3_lab_hcl(l, a, b) { 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); } function d3_lab_xyz(x) { return x > .206893034 ? x * x * x : (x - 4 / 29) / 7.787037; } function d3_xyz_lab(x) { return x > .008856 ? Math.pow(x, 1 / 3) : 7.787037 * x + 4 / 29; } function d3_xyz_rgb(r) { return Math.round(255 * (r <= .00304 ? 12.92 * r : 1.055 * Math.pow(r, 1 / 2.4) - .055)); } d3.rgb = d3_rgb; function d3_rgb(r, g, b) { 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); } function d3_rgbNumber(value) { return new d3_rgb(value >> 16, value >> 8 & 255, value & 255); } function d3_rgbString(value) { return d3_rgbNumber(value) + ""; } var d3_rgbPrototype = d3_rgb.prototype = new d3_color(); d3_rgbPrototype.brighter = function(k) { k = Math.pow(.7, arguments.length ? k : 1); var r = this.r, g = this.g, b = this.b, i = 30; if (!r && !g && !b) return new d3_rgb(i, i, i); if (r && r < i) r = i; if (g && g < i) g = i; if (b && b < i) b = i; return new d3_rgb(Math.min(255, r / k), Math.min(255, g / k), Math.min(255, b / k)); }; d3_rgbPrototype.darker = function(k) { k = Math.pow(.7, arguments.length ? k : 1); return new d3_rgb(k * this.r, k * this.g, k * this.b); }; d3_rgbPrototype.hsl = function() { return d3_rgb_hsl(this.r, this.g, this.b); }; d3_rgbPrototype.toString = function() { return "#" + d3_rgb_hex(this.r) + d3_rgb_hex(this.g) + d3_rgb_hex(this.b); }; function d3_rgb_hex(v) { return v < 16 ? "0" + Math.max(0, v).toString(16) : Math.min(255, v).toString(16); } function d3_rgb_parse(format, rgb, hsl) { var r = 0, g = 0, b = 0, m1, m2, color; m1 = /([a-z]+)\((.*)\)/.exec(format = format.toLowerCase()); if (m1) { m2 = m1[2].split(","); switch (m1[1]) { case "hsl": { return hsl(parseFloat(m2[0]), parseFloat(m2[1]) / 100, parseFloat(m2[2]) / 100); } case "rgb": { return rgb(d3_rgb_parseNumber(m2[0]), d3_rgb_parseNumber(m2[1]), d3_rgb_parseNumber(m2[2])); } } } if (color = d3_rgb_names.get(format)) { return rgb(color.r, color.g, color.b); } if (format != null && format.charAt(0) === "#" && !isNaN(color = parseInt(format.slice(1), 16))) { if (format.length === 4) { r = (color & 3840) >> 4; r = r >> 4 | r; g = color & 240; g = g >> 4 | g; b = color & 15; b = b << 4 | b; } else if (format.length === 7) { r = (color & 16711680) >> 16; g = (color & 65280) >> 8; b = color & 255; } } return rgb(r, g, b); } function d3_rgb_hsl(r, g, b) { 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; if (d) { s = l < .5 ? d / (max + min) : d / (2 - max - min); 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; h *= 60; } else { h = NaN; s = l > 0 && l < 1 ? 0 : h; } return new d3_hsl(h, s, l); } function d3_rgb_lab(r, g, b) { r = d3_rgb_xyz(r); g = d3_rgb_xyz(g); b = d3_rgb_xyz(b); 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); return d3_lab(116 * y - 16, 500 * (x - y), 200 * (y - z)); } function d3_rgb_xyz(r) { return (r /= 255) <= .04045 ? r / 12.92 : Math.pow((r + .055) / 1.055, 2.4); } function d3_rgb_parseNumber(c) { var f = parseFloat(c); return c.charAt(c.length - 1) === "%" ? Math.round(f * 2.55) : f; } var d3_rgb_names = d3.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, rebeccapurple: 6697881, 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 }); d3_rgb_names.forEach(function(key, value) { d3_rgb_names.set(key, d3_rgbNumber(value)); }); function d3_functor(v) { return typeof v === "function" ? v : function() { return v; }; } d3.functor = d3_functor; d3.xhr = d3_xhrType(d3_identity); function d3_xhrType(response) { return function(url, mimeType, callback) { if (arguments.length === 2 && typeof mimeType === "function") callback = mimeType, mimeType = null; return d3_xhr(url, mimeType, response, callback); }; } function d3_xhr(url, mimeType, response, callback) { var xhr = {}, dispatch = d3.dispatch("beforesend", "progress", "load", "error"), headers = {}, request = new XMLHttpRequest(), responseType = null; if (this.XDomainRequest && !("withCredentials" in request) && /^(http(s)?:)?\/\//.test(url)) request = new XDomainRequest(); "onload" in request ? request.onload = request.onerror = respond : request.onreadystatechange = function() { request.readyState > 3 && respond(); }; function respond() { var status = request.status, result; if (!status && d3_xhrHasResponse(request) || status >= 200 && status < 300 || status === 304) { try { result = response.call(xhr, request); } catch (e) { dispatch.error.call(xhr, e); return; } dispatch.load.call(xhr, result); } else { dispatch.error.call(xhr, request); } } request.onprogress = function(event) { var o = d3.event; d3.event = event; try { dispatch.progress.call(xhr, request); } finally { d3.event = o; } }; xhr.header = function(name, value) { name = (name + "").toLowerCase(); if (arguments.length < 2) return headers[name]; if (value == null) delete headers[name]; else headers[name] = value + ""; return xhr; }; xhr.mimeType = function(value) { if (!arguments.length) return mimeType; mimeType = value == null ? null : value + ""; return xhr; }; xhr.responseType = function(value) { if (!arguments.length) return responseType; responseType = value; return xhr; }; xhr.response = function(value) { response = value; return xhr; }; [ "get", "post" ].forEach(function(method) { xhr[method] = function() { return xhr.send.apply(xhr, [ method ].concat(d3_array(arguments))); }; }); xhr.send = function(method, data, callback) { if (arguments.length === 2 && typeof data === "function") callback = data, data = null; request.open(method, url, true); if (mimeType != null && !("accept" in headers)) headers["accept"] = mimeType + ",*/*"; if (request.setRequestHeader) for (var name in headers) request.setRequestHeader(name, headers[name]); if (mimeType != null && request.overrideMimeType) request.overrideMimeType(mimeType); if (responseType != null) request.responseType = responseType; if (callback != null) xhr.on("error", callback).on("load", function(request) { callback(null, request); }); dispatch.beforesend.call(xhr, request); request.send(data == null ? null : data); return xhr; }; xhr.abort = function() { request.abort(); return xhr; }; d3.rebind(xhr, dispatch, "on"); return callback == null ? xhr : xhr.get(d3_xhr_fixCallback(callback)); } function d3_xhr_fixCallback(callback) { return callback.length === 1 ? function(error, request) { callback(error == null ? request : null); } : callback; } function d3_xhrHasResponse(request) { var type = request.responseType; return type && type !== "text" ? request.response : request.responseText; } d3.dsv = function(delimiter, mimeType) { var reFormat = new RegExp('["' + delimiter + "\n]"), delimiterCode = delimiter.charCodeAt(0); function dsv(url, row, callback) { if (arguments.length < 3) callback = row, row = null; var xhr = d3_xhr(url, mimeType, row == null ? response : typedResponse(row), callback); xhr.row = function(_) { return arguments.length ? xhr.response((row = _) == null ? response : typedResponse(_)) : row; }; return xhr; } function response(request) { return dsv.parse(request.responseText); } function typedResponse(f) { return function(request) { return dsv.parse(request.responseText, f); }; } dsv.parse = function(text, f) { var o; return dsv.parseRows(text, function(row, i) { if (o) return o(row, i - 1); var a = new Function("d", "return {" + row.map(function(name, i) { return JSON.stringify(name) + ": d[" + i + "]"; }).join(",") + "}"); o = f ? function(row, i) { return f(a(row), i); } : a; }); }; dsv.parseRows = function(text, f) { var EOL = {}, EOF = {}, rows = [], N = text.length, I = 0, n = 0, t, eol; function token() { if (I >= N) return EOF; if (eol) return eol = false, EOL; var j = I; if (text.charCodeAt(j) === 34) { var i = j; while (i++ < N) { if (text.charCodeAt(i) === 34) { if (text.charCodeAt(i + 1) !== 34) break; ++i; } } I = i + 2; var c = text.charCodeAt(i + 1); if (c === 13) { eol = true; if (text.charCodeAt(i + 2) === 10) ++I; } else if (c === 10) { eol = true; } return text.slice(j + 1, i).replace(/""/g, '"'); } while (I < N) { var c = text.charCodeAt(I++), k = 1; if (c === 10) eol = true; else if (c === 13) { eol = true; if (text.charCodeAt(I) === 10) ++I, ++k; } else if (c !== delimiterCode) continue; return text.slice(j, I - k); } return text.slice(j); } while ((t = token()) !== EOF) { var a = []; while (t !== EOL && t !== EOF) { a.push(t); t = token(); } if (f && (a = f(a, n++)) == null) continue; rows.push(a); } return rows; }; dsv.format = function(rows) { if (Array.isArray(rows[0])) return dsv.formatRows(rows); var fieldSet = new d3_Set(), fields = []; rows.forEach(function(row) { for (var field in row) { if (!fieldSet.has(field)) { fields.push(fieldSet.add(field)); } } }); return [ fields.map(formatValue).join(delimiter) ].concat(rows.map(function(row) { return fields.map(function(field) { return formatValue(row[field]); }).join(delimiter); })).join("\n"); }; dsv.formatRows = function(rows) { return rows.map(formatRow).join("\n"); }; function formatRow(row) { return row.map(formatValue).join(delimiter); } function formatValue(text) { return reFormat.test(text) ? '"' + text.replace(/\"/g, '""') + '"' : text; } return dsv; }; d3.csv = d3.dsv(",", "text/csv"); d3.tsv = d3.dsv(" ", "text/tab-separated-values"); var d3_timer_queueHead, d3_timer_queueTail, d3_timer_interval, d3_timer_timeout, d3_timer_frame = this[d3_vendorSymbol(this, "requestAnimationFrame")] || function(callback) { setTimeout(callback, 17); }; d3.timer = function() { d3_timer.apply(this, arguments); }; function d3_timer(callback, delay, then) { var n = arguments.length; if (n < 2) delay = 0; if (n < 3) then = Date.now(); var time = then + delay, timer = { c: callback, t: time, n: null }; if (d3_timer_queueTail) d3_timer_queueTail.n = timer; else d3_timer_queueHead = timer; d3_timer_queueTail = timer; if (!d3_timer_interval) { d3_timer_timeout = clearTimeout(d3_timer_timeout); d3_timer_interval = 1; d3_timer_frame(d3_timer_step); } return timer; } function d3_timer_step() { var now = d3_timer_mark(), delay = d3_timer_sweep() - now; if (delay > 24) { if (isFinite(delay)) { clearTimeout(d3_timer_timeout); d3_timer_timeout = setTimeout(d3_timer_step, delay); } d3_timer_interval = 0; } else { d3_timer_interval = 1; d3_timer_frame(d3_timer_step); } } d3.timer.flush = function() { d3_timer_mark(); d3_timer_sweep(); }; function d3_timer_mark() { var now = Date.now(), timer = d3_timer_queueHead; while (timer) { if (now >= timer.t && timer.c(now - timer.t)) timer.c = null; timer = timer.n; } return now; } function d3_timer_sweep() { var t0, t1 = d3_timer_queueHead, time = Infinity; while (t1) { if (t1.c) { if (t1.t < time) time = t1.t; t1 = (t0 = t1).n; } else { t1 = t0 ? t0.n = t1.n : d3_timer_queueHead = t1.n; } } d3_timer_queueTail = t0; return time; } function d3_format_precision(x, p) { return p - (x ? Math.ceil(Math.log(x) / Math.LN10) : 1); } d3.round = function(x, n) { return n ? Math.round(x * (n = Math.pow(10, n))) / n : Math.round(x); }; var d3_formatPrefixes = [ "y", "z", "a", "f", "p", "n", "µ", "m", "", "k", "M", "G", "T", "P", "E", "Z", "Y" ].map(d3_formatPrefix); d3.formatPrefix = function(value, precision) { var i = 0; if (value = +value) { if (value < 0) value *= -1; if (precision) value = d3.round(value, d3_format_precision(value, precision)); i = 1 + Math.floor(1e-12 + Math.log(value) / Math.LN10); i = Math.max(-24, Math.min(24, Math.floor((i - 1) / 3) * 3)); } return d3_formatPrefixes[8 + i / 3]; }; function d3_formatPrefix(d, i) { var k = Math.pow(10, abs(8 - i) * 3); return { scale: i > 8 ? function(d) { return d / k; } : function(d) { return d * k; }, symbol: d }; } function d3_locale_numberFormat(locale) { 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) { var i = value.length, t = [], j = 0, g = locale_grouping[0], length = 0; while (i > 0 && g > 0) { if (length + g + 1 > width) g = Math.max(1, width - length); t.push(value.substring(i -= g, i + g)); if ((length += g + 1) > width) break; g = locale_grouping[j = (j + 1) % locale_grouping.length]; } return t.reverse().join(locale_thousands); } : d3_identity; return function(specifier) { 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; if (precision) precision = +precision.substring(1); if (zfill || fill === "0" && align === "=") { zfill = fill = "0"; align = "="; } switch (type) { case "n": comma = true; type = "g"; break; case "%": scale = 100; suffix = "%"; type = "f"; break; case "p": scale = 100; suffix = "%"; type = "r"; break; case "b": case "o": case "x": case "X": if (symbol === "#") prefix = "0" + type.toLowerCase(); case "c": exponent = false; case "d": integer = true; precision = 0; break; case "s": scale = -1; type = "r"; break; } if (symbol === "$") prefix = locale_currency[0], suffix = locale_currency[1]; if (type == "r" && !precision) type = "g"; if (precision != null) { 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)); } type = d3_format_types.get(type) || d3_format_typeDefault; var zcomma = zfill && comma; return function(value) { var fullSuffix = suffix; if (integer && value % 1) return ""; var negative = value < 0 || value === 0 && 1 / value < 0 ? (value = -value, "-") : sign === "-" ? "" : sign; if (scale < 0) { var unit = d3.formatPrefix(value, precision); value = unit.scale(value); fullSuffix = unit.symbol + suffix; } else { value *= scale; } value = type(value, precision); var i = value.lastIndexOf("."), before, after; if (i < 0) { var j = exponent ? value.lastIndexOf("e") : -1; if (j < 0) before = value, after = ""; else before = value.substring(0, j), after = value.substring(j); } else { before = value.substring(0, i); after = locale_decimal + value.substring(i + 1); } if (!zfill && comma) before = formatGroup(before, Infinity); var length = prefix.length + before.length + after.length + (zcomma ? 0 : negative.length), padding = length < width ? new Array(length = width - length + 1).join(fill) : ""; if (zcomma) before = formatGroup(padding + before, padding.length ? width - after.length : Infinity); negative += prefix; value = before + after; 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; }; }; } var d3_format_re = /(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i; var d3_format_types = d3.map({ b: function(x) { return x.toString(2); }, c: function(x) { return String.fromCharCode(x); }, o: function(x) { return x.toString(8); }, x: function(x) { return x.toString(16); }, X: function(x) { return x.toString(16).toUpperCase(); }, g: function(x, p) { return x.toPrecision(p); }, e: function(x, p) { return x.toExponential(p); }, f: function(x, p) { return x.toFixed(p); }, r: function(x, p) { 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)))); } }); function d3_format_typeDefault(x) { return x + ""; } var d3_time = d3.time = {}, d3_date = Date; function d3_date_utc() { this._ = new Date(arguments.length > 1 ? Date.UTC.apply(this, arguments) : arguments[0]); } d3_date_utc.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() { d3_time_prototype.setUTCDate.apply(this._, arguments); }, setDay: function() { d3_time_prototype.setUTCDay.apply(this._, arguments); }, setFullYear: function() { d3_time_prototype.setUTCFullYear.apply(this._, arguments); }, setHours: function() { d3_time_prototype.setUTCHours.apply(this._, arguments); }, setMilliseconds: function() { d3_time_prototype.setUTCMilliseconds.apply(this._, arguments); }, setMinutes: function() { d3_time_prototype.setUTCMinutes.apply(this._, arguments); }, setMonth: function() { d3_time_prototype.setUTCMonth.apply(this._, arguments); }, setSeconds: function() { d3_time_prototype.setUTCSeconds.apply(this._, arguments); }, setTime: function() { d3_time_prototype.setTime.apply(this._, arguments); } }; var d3_time_prototype = Date.prototype; function d3_time_interval(local, step, number) { function round(date) { var d0 = local(date), d1 = offset(d0, 1); return date - d0 < d1 - date ? d0 : d1; } function ceil(date) { step(date = local(new d3_date(date - 1)), 1); return date; } function offset(date, k) { step(date = new d3_date(+date), k); return date; } function range(t0, t1, dt) { var time = ceil(t0), times = []; if (dt > 1) { while (time < t1) { if (!(number(time) % dt)) times.push(new Date(+time)); step(time, 1); } } else { while (time < t1) times.push(new Date(+time)), step(time, 1); } return times; } function range_utc(t0, t1, dt) { try { d3_date = d3_date_utc; var utc = new d3_date_utc(); utc._ = t0; return range(utc, t1, dt); } finally { d3_date = Date; } } local.floor = local; local.round = round; local.ceil = ceil; local.offset = offset; local.range = range; var utc = local.utc = d3_time_interval_utc(local); utc.floor = utc; utc.round = d3_time_interval_utc(round); utc.ceil = d3_time_interval_utc(ceil); utc.offset = d3_time_interval_utc(offset); utc.range = range_utc; return local; } function d3_time_interval_utc(method) { return function(date, k) { try { d3_date = d3_date_utc; var utc = new d3_date_utc(); utc._ = date; return method(utc, k)._; } finally { d3_date = Date; } }; } d3_time.year = d3_time_interval(function(date) { date = d3_time.day(date); date.setMonth(0, 1); return date; }, function(date, offset) { date.setFullYear(date.getFullYear() + offset); }, function(date) { return date.getFullYear(); }); d3_time.years = d3_time.year.range; d3_time.years.utc = d3_time.year.utc.range; d3_time.day = d3_time_interval(function(date) { var day = new d3_date(2e3, 0); day.setFullYear(date.getFullYear(), date.getMonth(), date.getDate()); return day; }, function(date, offset) { date.setDate(date.getDate() + offset); }, function(date) { return date.getDate() - 1; }); d3_time.days = d3_time.day.range; d3_time.days.utc = d3_time.day.utc.range; d3_time.dayOfYear = function(date) { var year = d3_time.year(date); return Math.floor((date - year - (date.getTimezoneOffset() - year.getTimezoneOffset()) * 6e4) / 864e5); }; [ "sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday" ].forEach(function(day, i) { i = 7 - i; var interval = d3_time[day] = d3_time_interval(function(date) { (date = d3_time.day(date)).setDate(date.getDate() - (date.getDay() + i) % 7); return date; }, function(date, offset) { date.setDate(date.getDate() + Math.floor(offset) * 7); }, function(date) { var day = d3_time.year(date).getDay(); return Math.floor((d3_time.dayOfYear(date) + (day + i) % 7) / 7) - (day !== i); }); d3_time[day + "s"] = interval.range; d3_time[day + "s"].utc = interval.utc.range; d3_time[day + "OfYear"] = function(date) { var day = d3_time.year(date).getDay(); return Math.floor((d3_time.dayOfYear(date) + (day + i) % 7) / 7); }; }); d3_time.week = d3_time.sunday; d3_time.weeks = d3_time.sunday.range; d3_time.weeks.utc = d3_time.sunday.utc.range; d3_time.weekOfYear = d3_time.sundayOfYear; function d3_locale_timeFormat(locale) { 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; function d3_time_format(template) { var n = template.length; function format(date) { var string = [], i = -1, j = 0, c, p, f; while (++i < n) { if (template.charCodeAt(i) === 37) { string.push(template.slice(j, i)); if ((p = d3_time_formatPads[c = template.charAt(++i)]) != null) c = template.charAt(++i); if (f = d3_time_formats[c]) c = f(date, p == null ? c === "e" ? " " : "0" : p); string.push(c); j = i + 1; } } string.push(template.slice(j, i)); return string.join(""); } format.parse = function(string) { var d = { y: 1900, m: 0, d: 1, H: 0, M: 0, S: 0, L: 0, Z: null }, i = d3_time_parse(d, template, string, 0); if (i != string.length) return null; if ("p" in d) d.H = d.H % 12 + d.p * 12; var localZ = d.Z != null && d3_date !== d3_date_utc, date = new (localZ ? d3_date_utc : d3_date)(); if ("j" in d) date.setFullYear(d.y, 0, d.j); else if ("W" in d || "U" in d) { if (!("w" in d)) d.w = "W" in d ? 1 : 0; date.setFullYear(d.y, 0, 1); 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); } else date.setFullYear(d.y, d.m, d.d); date.setHours(d.H + (d.Z / 100 | 0), d.M + d.Z % 100, d.S, d.L); return localZ ? date._ : date; }; format.toString = function() { return template; }; return format; } function d3_time_parse(date, template, string, j) { var c, p, t, i = 0, n = template.length, m = string.length; while (i < n) { if (j >= m) return -1; c = template.charCodeAt(i++); if (c === 37) { t = template.charAt(i++); p = d3_time_parsers[t in d3_time_formatPads ? template.charAt(i++) : t]; if (!p || (j = p(date, string, j)) < 0) return -1; } else if (c != string.charCodeAt(j++)) { return -1; } } return j; } d3_time_format.utc = function(template) { var local = d3_time_format(template); function format(date) { try { d3_date = d3_date_utc; var utc = new d3_date(); utc._ = date; return local(utc); } finally { d3_date = Date; } } format.parse = function(string) { try { d3_date = d3_date_utc; var date = local.parse(string); return date && date._; } finally { d3_date = Date; } }; format.toString = local.toString; return format; }; d3_time_format.multi = d3_time_format.utc.multi = d3_time_formatMulti; 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); locale_periods.forEach(function(p, i) { d3_time_periodLookup.set(p.toLowerCase(), i); }); var d3_time_formats = { a: function(d) { return locale_shortDays[d.getDay()]; }, A: function(d) { return locale_days[d.getDay()]; }, b: function(d) { return locale_shortMonths[d.getMonth()]; }, B: function(d) { return locale_months[d.getMonth()]; }, c: d3_time_format(locale_dateTime), d: function(d, p) { return d3_time_formatPad(d.getDate(), p, 2); }, e: function(d, p) { return d3_time_formatPad(d.getDate(), p, 2); }, H: function(d, p) { return d3_time_formatPad(d.getHours(), p, 2); }, I: function(d, p) { return d3_time_formatPad(d.getHours() % 12 || 12, p, 2); }, j: function(d, p) { return d3_time_formatPad(1 + d3_time.dayOfYear(d), p, 3); }, L: function(d, p) { return d3_time_formatPad(d.getMilliseconds(), p, 3); }, m: function(d, p) { return d3_time_formatPad(d.getMonth() + 1, p, 2); }, M: function(d, p) { return d3_time_formatPad(d.getMinutes(), p, 2); }, p: function(d) { return locale_periods[+(d.getHours() >= 12)]; }, S: function(d, p) { return d3_time_formatPad(d.getSeconds(), p, 2); }, U: function(d, p) { return d3_time_formatPad(d3_time.sundayOfYear(d), p, 2); }, w: function(d) { return d.getDay(); }, W: function(d, p) { return d3_time_formatPad(d3_time.mondayOfYear(d), p, 2); }, x: d3_time_format(locale_date), X: d3_time_format(locale_time), y: function(d, p) { return d3_time_formatPad(d.getFullYear() % 100, p, 2); }, Y: function(d, p) { return d3_time_formatPad(d.getFullYear() % 1e4, p, 4); }, Z: d3_time_zone, "%": function() { return "%"; } }; var d3_time_parsers = { a: d3_time_parseWeekdayAbbrev, A: d3_time_parseWeekday, b: d3_time_parseMonthAbbrev, B: d3_time_parseMonth, c: d3_time_parseLocaleFull, d: d3_time_parseDay, e: d3_time_parseDay, H: d3_time_parseHour24, I: d3_time_parseHour24, j: d3_time_parseDayOfYear, L: d3_time_parseMilliseconds, m: d3_time_parseMonthNumber, M: d3_time_parseMinutes, p: d3_time_parseAmPm, S: d3_time_parseSeconds, U: d3_time_parseWeekNumberSunday, w: d3_time_parseWeekdayNumber, W: d3_time_parseWeekNumberMonday, x: d3_time_parseLocaleDate, X: d3_time_parseLocaleTime, y: d3_time_parseYear, Y: d3_time_parseFullYear, Z: d3_time_parseZone, "%": d3_time_parseLiteralPercent }; function d3_time_parseWeekdayAbbrev(date, string, i) { d3_time_dayAbbrevRe.lastIndex = 0; var n = d3_time_dayAbbrevRe.exec(string.slice(i)); return n ? (date.w = d3_time_dayAbbrevLookup.get(n[0].toLowerCase()), i + n[0].length) : -1; } function d3_time_parseWeekday(date, string, i) { d3_time_dayRe.lastIndex = 0; var n = d3_time_dayRe.exec(string.slice(i)); return n ? (date.w = d3_time_dayLookup.get(n[0].toLowerCase()), i + n[0].length) : -1; } function d3_time_parseMonthAbbrev(date, string, i) { d3_time_monthAbbrevRe.lastIndex = 0; var n = d3_time_monthAbbrevRe.exec(string.slice(i)); return n ? (date.m = d3_time_monthAbbrevLookup.get(n[0].toLowerCase()), i + n[0].length) : -1; } function d3_time_parseMonth(date, string, i) { d3_time_monthRe.lastIndex = 0; var n = d3_time_monthRe.exec(string.slice(i)); return n ? (date.m = d3_time_monthLookup.get(n[0].toLowerCase()), i + n[0].length) : -1; } function d3_time_parseLocaleFull(date, string, i) { return d3_time_parse(date, d3_time_formats.c.toString(), string, i); } function d3_time_parseLocaleDate(date, string, i) { return d3_time_parse(date, d3_time_formats.x.toString(), string, i); } function d3_time_parseLocaleTime(date, string, i) { return d3_time_parse(date, d3_time_formats.X.toString(), string, i); } function d3_time_parseAmPm(date, string, i) { var n = d3_time_periodLookup.get(string.slice(i, i += 2).toLowerCase()); return n == null ? -1 : (date.p = n, i); } return d3_time_format; } var d3_time_formatPads = { "-": "", _: " ", "0": "0" }, d3_time_numberRe = /^\s*\d+/, d3_time_percentRe = /^%/; function d3_time_formatPad(value, fill, width) { var sign = value < 0 ? "-" : "", string = (sign ? -value : value) + "", length = string.length; return sign + (length < width ? new Array(width - length + 1).join(fill) + string : string); } function d3_time_formatRe(names) { return new RegExp("^(?:" + names.map(d3.requote).join("|") + ")", "i"); } function d3_time_formatLookup(names) { var map = new d3_Map(), i = -1, n = names.length; while (++i < n) map.set(names[i].toLowerCase(), i); return map; } function d3_time_parseWeekdayNumber(date, string, i) { d3_time_numberRe.lastIndex = 0; var n = d3_time_numberRe.exec(string.slice(i, i + 1)); return n ? (date.w = +n[0], i + n[0].length) : -1; } function d3_time_parseWeekNumberSunday(date, string, i) { d3_time_numberRe.lastIndex = 0; var n = d3_time_numberRe.exec(string.slice(i)); return n ? (date.U = +n[0], i + n[0].length) : -1; } function d3_time_parseWeekNumberMonday(date, string, i) { d3_time_numberRe.lastIndex = 0; var n = d3_time_numberRe.exec(string.slice(i)); return n ? (date.W = +n[0], i + n[0].length) : -1; } function d3_time_parseFullYear(date, string, i) { d3_time_numberRe.lastIndex = 0; var n = d3_time_numberRe.exec(string.slice(i, i + 4)); return n ? (date.y = +n[0], i + n[0].length) : -1; } function d3_time_parseYear(date, string, i) { d3_time_numberRe.lastIndex = 0; var n = d3_time_numberRe.exec(string.slice(i, i + 2)); return n ? (date.y = d3_time_expandYear(+n[0]), i + n[0].length) : -1; } function d3_time_parseZone(date, string, i) { return /^[+-]\d{4}$/.test(string = string.slice(i, i + 5)) ? (date.Z = -string, i + 5) : -1; } function d3_time_expandYear(d) { return d + (d > 68 ? 1900 : 2e3); } function d3_time_parseMonthNumber(date, string, i) { d3_time_numberRe.lastIndex = 0; var n = d3_time_numberRe.exec(string.slice(i, i + 2)); return n ? (date.m = n[0] - 1, i + n[0].length) : -1; } function d3_time_parseDay(date, string, i) { d3_time_numberRe.lastIndex = 0; var n = d3_time_numberRe.exec(string.slice(i, i + 2)); return n ? (date.d = +n[0], i + n[0].length) : -1; } function d3_time_parseDayOfYear(date, string, i) { d3_time_numberRe.lastIndex = 0; var n = d3_time_numberRe.exec(string.slice(i, i + 3)); return n ? (date.j = +n[0], i + n[0].length) : -1; } function d3_time_parseHour24(date, string, i) { d3_time_numberRe.lastIndex = 0; var n = d3_time_numberRe.exec(string.slice(i, i + 2)); return n ? (date.H = +n[0], i + n[0].length) : -1; } function d3_time_parseMinutes(date, string, i) { d3_time_numberRe.lastIndex = 0; var n = d3_time_numberRe.exec(string.slice(i, i + 2)); return n ? (date.M = +n[0], i + n[0].length) : -1; } function d3_time_parseSeconds(date, string, i) { d3_time_numberRe.lastIndex = 0; var n = d3_time_numberRe.exec(string.slice(i, i + 2)); return n ? (date.S = +n[0], i + n[0].length) : -1; } function d3_time_parseMilliseconds(date, string, i) { d3_time_numberRe.lastIndex = 0; var n = d3_time_numberRe.exec(string.slice(i, i + 3)); return n ? (date.L = +n[0], i + n[0].length) : -1; } function d3_time_zone(d) { var z = d.getTimezoneOffset(), zs = z > 0 ? "-" : "+", zh = abs(z) / 60 | 0, zm = abs(z) % 60; return zs + d3_time_formatPad(zh, "0", 2) + d3_time_formatPad(zm, "0", 2); } function d3_time_parseLiteralPercent(date, string, i) { d3_time_percentRe.lastIndex = 0; var n = d3_time_percentRe.exec(string.slice(i, i + 1)); return n ? i + n[0].length : -1; } function d3_time_formatMulti(formats) { var n = formats.length, i = -1; while (++i < n) formats[i][0] = this(formats[i][0]); return function(date) { var i = 0, f = formats[i]; while (!f[1](date)) f = formats[++i]; return f[0](date); }; } d3.locale = function(locale) { return { numberFormat: d3_locale_numberFormat(locale), timeFormat: d3_locale_timeFormat(locale) }; }; var d3_locale_enUS = d3.locale({ decimal: ".", thousands: ",", grouping: [ 3 ], currency: [ "$", "" ], dateTime: "%a %b %e %X %Y", date: "%m/%d/%Y", time: "%H:%M:%S", periods: [ "AM", "PM" ], days: [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ], shortDays: [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ], months: [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ], shortMonths: [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ] }); d3.format = d3_locale_enUS.numberFormat; d3.geo = {}; function d3_adder() {} d3_adder.prototype = { s: 0, t: 0, add: function(y) { d3_adderSum(y, this.t, d3_adderTemp); d3_adderSum(d3_adderTemp.s, this.s, this); if (this.s) this.t += d3_adderTemp.t; else this.s = d3_adderTemp.t; }, reset: function() { this.s = this.t = 0; }, valueOf: function() { return this.s; } }; var d3_adderTemp = new d3_adder(); function d3_adderSum(a, b, o) { var x = o.s = a + b, bv = x - a, av = x - bv; o.t = a - av + (b - bv); } d3.geo.stream = function(object, listener) { if (object && d3_geo_streamObjectType.hasOwnProperty(object.type)) { d3_geo_streamObjectType[object.type](object, listener); } else { d3_geo_streamGeometry(object, listener); } }; function d3_geo_streamGeometry(geometry, listener) { if (geometry && d3_geo_streamGeometryType.hasOwnProperty(geometry.type)) { d3_geo_streamGeometryType[geometry.type](geometry, listener); } } var d3_geo_streamObjectType = { Feature: function(feature, listener) { d3_geo_streamGeometry(feature.geometry, listener); }, FeatureCollection: function(object, listener) { var features = object.features, i = -1, n = features.length; while (++i < n) d3_geo_streamGeometry(features[i].geometry, listener); } }; var d3_geo_streamGeometryType = { Sphere: function(object, listener) { listener.sphere(); }, Point: function(object, listener) { object = object.coordinates; listener.point(object[0], object[1], object[2]); }, MultiPoint: function(object, listener) { var coordinates = object.coordinates, i = -1, n = coordinates.length; while (++i < n) object = coordinates[i], listener.point(object[0], object[1], object[2]); }, LineString: function(object, listener) { d3_geo_streamLine(object.coordinates, listener, 0); }, MultiLineString: function(object, listener) { var coordinates = object.coordinates, i = -1, n = coordinates.length; while (++i < n) d3_geo_streamLine(coordinates[i], listener, 0); }, Polygon: function(object, listener) { d3_geo_streamPolygon(object.coordinates, listener); }, MultiPolygon: function(object, listener) { var coordinates = object.coordinates, i = -1, n = coordinates.length; while (++i < n) d3_geo_streamPolygon(coordinates[i], listener); }, GeometryCollection: function(object, listener) { var geometries = object.geometries, i = -1, n = geometries.length; while (++i < n) d3_geo_streamGeometry(geometries[i], listener); } }; function d3_geo_streamLine(coordinates, listener, closed) { var i = -1, n = coordinates.length - closed, coordinate; listener.lineStart(); while (++i < n) coordinate = coordinates[i], listener.point(coordinate[0], coordinate[1], coordinate[2]); listener.lineEnd(); } function d3_geo_streamPolygon(coordinates, listener) { var i = -1, n = coordinates.length; listener.polygonStart(); while (++i < n) d3_geo_streamLine(coordinates[i], listener, 1); listener.polygonEnd(); } d3.geo.area = function(object) { d3_geo_areaSum = 0; d3.geo.stream(object, d3_geo_area); return d3_geo_areaSum; }; var d3_geo_areaSum, d3_geo_areaRingSum = new d3_adder(); var d3_geo_area = { sphere: function() { d3_geo_areaSum += 4 * π; }, point: d3_noop, lineStart: d3_noop, lineEnd: d3_noop, polygonStart: function() { d3_geo_areaRingSum.reset(); d3_geo_area.lineStart = d3_geo_areaRingStart; }, polygonEnd: function() { var area = 2 * d3_geo_areaRingSum; d3_geo_areaSum += area < 0 ? 4 * π + area : area; d3_geo_area.lineStart = d3_geo_area.lineEnd = d3_geo_area.point = d3_noop; } }; function d3_geo_areaRingStart() { var λ00, φ00, λ0, cosφ0, sinφ0; d3_geo_area.point = function(λ, φ) { d3_geo_area.point = nextPoint; λ0 = (λ00 = λ) * d3_radians, cosφ0 = Math.cos(φ = (φ00 = φ) * d3_radians / 2 + π / 4), sinφ0 = Math.sin(φ); }; function nextPoint(λ, φ) { λ *= d3_radians; φ = φ * d3_radians / 2 + π / 4; 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λ); d3_geo_areaRingSum.add(Math.atan2(v, u)); λ0 = λ, cosφ0 = cosφ, sinφ0 = sinφ; } d3_geo_area.lineEnd = function() { nextPoint(λ00, φ00); }; } function d3_geo_cartesian(spherical) { var λ = spherical[0], φ = spherical[1], cosφ = Math.cos(φ); return [ cosφ * Math.cos(λ), cosφ * Math.sin(λ), Math.sin(φ) ]; } function d3_geo_cartesianDot(a, b) { return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; } function d3_geo_cartesianCross(a, b) { 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] ]; } function d3_geo_cartesianAdd(a, b) { a[0] += b[0]; a[1] += b[1]; a[2] += b[2]; } function d3_geo_cartesianScale(vector, k) { return [ vector[0] * k, vector[1] * k, vector[2] * k ]; } function d3_geo_cartesianNormalize(d) { var l = Math.sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]); d[0] /= l; d[1] /= l; d[2] /= l; } function d3_geo_spherical(cartesian) { return [ Math.atan2(cartesian[1], cartesian[0]), d3_asin(cartesian[2]) ]; } function d3_geo_sphericalEqual(a, b) { return abs(a[0] - b[0]) < ε && abs(a[1] - b[1]) < ε; } d3.geo.bounds = function() { var λ0, φ0, λ1, φ1, λ_, λ__, φ__, p0, dλSum, ranges, range; var bound = { point: point, lineStart: lineStart, lineEnd: lineEnd, polygonStart: function() { bound.point = ringPoint; bound.lineStart = ringStart; bound.lineEnd = ringEnd; dλSum = 0; d3_geo_area.polygonStart(); }, polygonEnd: function() { d3_geo_area.polygonEnd(); bound.point = point; bound.lineStart = lineStart; bound.lineEnd = lineEnd; if (d3_geo_areaRingSum < 0) λ0 = -(λ1 = 180), φ0 = -(φ1 = 90); else if (dλSum > ε) φ1 = 90; else if (dλSum < -ε) φ0 = -90; range[0] = λ0, range[1] = λ1; } }; function point(λ, φ) { ranges.push(range = [ λ0 = λ, λ1 = λ ]); if (φ < φ0) φ0 = φ; if (φ > φ1) φ1 = φ; } function linePoint(λ, φ) { var p = d3_geo_cartesian([ λ * d3_radians, φ * d3_radians ]); if (p0) { var normal = d3_geo_cartesianCross(p0, p), equatorial = [ normal[1], -normal[0], 0 ], inflection = d3_geo_cartesianCross(equatorial, normal); d3_geo_cartesianNormalize(inflection); inflection = d3_geo_spherical(inflection); var dλ = λ - λ_, s = dλ > 0 ? 1 : -1, λi = inflection[0] * d3_degrees * s, antimeridian = abs(dλ) > 180; if (antimeridian ^ (s * λ_ < λi && λi < s * λ)) { var φi = inflection[1] * d3_degrees; if (φi > φ1) φ1 = φi; } else if (λi = (λi + 360) % 360 - 180, antimeridian ^ (s * λ_ < λi && λi < s * λ)) { var φi = -inflection[1] * d3_degrees; if (φi < φ0) φ0 = φi; } else { if (φ < φ0) φ0 = φ; if (φ > φ1) φ1 = φ; } if (antimeridian) { if (λ < λ_) { if (angle(λ0, λ) > angle(λ0, λ1)) λ1 = λ; } else { if (angle(λ, λ1) > angle(λ0, λ1)) λ0 = λ; } } else { if (λ1 >= λ0) { if (λ < λ0) λ0 = λ; if (λ > λ1) λ1 = λ; } else { if (λ > λ_) { if (angle(λ0, λ) > angle(λ0, λ1)) λ1 = λ; } else { if (angle(λ, λ1) > angle(λ0, λ1)) λ0 = λ; } } } } else { point(λ, φ); } p0 = p, λ_ = λ; } function lineStart() { bound.point = linePoint; } function lineEnd() { range[0] = λ0, range[1] = λ1; bound.point = point; p0 = null; } function ringPoint(λ, φ) { if (p0) { var dλ = λ - λ_; dλSum += abs(dλ) > 180 ? dλ + (dλ > 0 ? 360 : -360) : dλ; } else λ__ = λ, φ__ = φ; d3_geo_area.point(λ, φ); linePoint(λ, φ); } function ringStart() { d3_geo_area.lineStart(); } function ringEnd() { ringPoint(λ__, φ__); d3_geo_area.lineEnd(); if (abs(dλSum) > ε) λ0 = -(λ1 = 180); range[0] = λ0, range[1] = λ1; p0 = null; } function angle(λ0, λ1) { return (λ1 -= λ0) < 0 ? λ1 + 360 : λ1; } function compareRanges(a, b) { return a[0] - b[0]; } function withinRange(x, range) { return range[0] <= range[1] ? range[0] <= x && x <= range[1] : x < range[0] || range[1] < x; } return function(feature) { φ1 = λ1 = -(λ0 = φ0 = Infinity); ranges = []; d3.geo.stream(feature, bound); var n = ranges.length; if (n) { ranges.sort(compareRanges); for (var i = 1, a = ranges[0], b, merged = [ a ]; i < n; ++i) { b = ranges[i]; if (withinRange(b[0], a) || withinRange(b[1], a)) { if (angle(a[0], b[1]) > angle(a[0], a[1])) a[1] = b[1]; if (angle(b[0], a[1]) > angle(a[0], a[1])) a[0] = b[0]; } else { merged.push(a = b); } } var best = -Infinity, dλ; for (var n = merged.length - 1, i = 0, a = merged[n], b; i <= n; a = b, ++i) { b = merged[i]; if ((dλ = angle(a[1], b[0])) > best) best = dλ, λ0 = b[0], λ1 = a[1]; } } ranges = range = null; return λ0 === Infinity || φ0 === Infinity ? [ [ NaN, NaN ], [ NaN, NaN ] ] : [ [ λ0, φ0 ], [ λ1, φ1 ] ]; }; }(); d3.geo.centroid = function(object) { 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; d3.geo.stream(object, d3_geo_centroid); var x = d3_geo_centroidX2, y = d3_geo_centroidY2, z = d3_geo_centroidZ2, m = x * x + y * y + z * z; if (m < ε2) { x = d3_geo_centroidX1, y = d3_geo_centroidY1, z = d3_geo_centroidZ1; if (d3_geo_centroidW1 < ε) x = d3_geo_centroidX0, y = d3_geo_centroidY0, z = d3_geo_centroidZ0; m = x * x + y * y + z * z; if (m < ε2) return [ NaN, NaN ]; } return [ Math.atan2(y, x) * d3_degrees, d3_asin(z / Math.sqrt(m)) * d3_degrees ]; }; 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; var d3_geo_centroid = { sphere: d3_noop, point: d3_geo_centroidPoint, lineStart: d3_geo_centroidLineStart, lineEnd: d3_geo_centroidLineEnd, polygonStart: function() { d3_geo_centroid.lineStart = d3_geo_centroidRingStart; }, polygonEnd: function() { d3_geo_centroid.lineStart = d3_geo_centroidLineStart; } }; function d3_geo_centroidPoint(λ, φ) { λ *= d3_radians; var cosφ = Math.cos(φ *= d3_radians); d3_geo_centroidPointXYZ(cosφ * Math.cos(λ), cosφ * Math.sin(λ), Math.sin(φ)); } function d3_geo_centroidPointXYZ(x, y, z) { ++d3_geo_centroidW0; d3_geo_centroidX0 += (x - d3_geo_centroidX0) / d3_geo_centroidW0; d3_geo_centroidY0 += (y - d3_geo_centroidY0) / d3_geo_centroidW0; d3_geo_centroidZ0 += (z - d3_geo_centroidZ0) / d3_geo_centroidW0; } function d3_geo_centroidLineStart() { var x0, y0, z0; d3_geo_centroid.point = function(λ, φ) { λ *= d3_radians; var cosφ = Math.cos(φ *= d3_radians); x0 = cosφ * Math.cos(λ); y0 = cosφ * Math.sin(λ); z0 = Math.sin(φ); d3_geo_centroid.point = nextPoint; d3_geo_centroidPointXYZ(x0, y0, z0); }; function nextPoint(λ, φ) { λ *= d3_radians; 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); d3_geo_centroidW1 += w; d3_geo_centroidX1 += w * (x0 + (x0 = x)); d3_geo_centroidY1 += w * (y0 + (y0 = y)); d3_geo_centroidZ1 += w * (z0 + (z0 = z)); d3_geo_centroidPointXYZ(x0, y0, z0); } } function d3_geo_centroidLineEnd() { d3_geo_centroid.point = d3_geo_centroidPoint; } function d3_geo_centroidRingStart() { var λ00, φ00, x0, y0, z0; d3_geo_centroid.point = function(λ, φ) { λ00 = λ, φ00 = φ; d3_geo_centroid.point = nextPoint; λ *= d3_radians; var cosφ = Math.cos(φ *= d3_radians); x0 = cosφ * Math.cos(λ); y0 = cosφ * Math.sin(λ); z0 = Math.sin(φ); d3_geo_centroidPointXYZ(x0, y0, z0); }; d3_geo_centroid.lineEnd = function() { nextPoint(λ00, φ00); d3_geo_centroid.lineEnd = d3_geo_centroidLineEnd; d3_geo_centroid.point = d3_geo_centroidPoint; }; function nextPoint(λ, φ) { λ *= d3_radians; 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); d3_geo_centroidX2 += v * cx; d3_geo_centroidY2 += v * cy; d3_geo_centroidZ2 += v * cz; d3_geo_centroidW1 += w; d3_geo_centroidX1 += w * (x0 + (x0 = x)); d3_geo_centroidY1 += w * (y0 + (y0 = y)); d3_geo_centroidZ1 += w * (z0 + (z0 = z)); d3_geo_centroidPointXYZ(x0, y0, z0); } } function d3_geo_compose(a, b) { function compose(x, y) { return x = a(x, y), b(x[0], x[1]); } if (a.invert && b.invert) compose.invert = function(x, y) { return x = b.invert(x, y), x && a.invert(x[0], x[1]); }; return compose; } function d3_true() { return true; } function d3_geo_clipPolygon(segments, compare, clipStartInside, interpolate, listener) { var subject = [], clip = []; segments.forEach(function(segment) { if ((n = segment.length - 1) <= 0) return; var n, p0 = segment[0], p1 = segment[n]; if (d3_geo_sphericalEqual(p0, p1)) { listener.lineStart(); for (var i = 0; i < n; ++i) listener.point((p0 = segment[i])[0], p0[1]); listener.lineEnd(); return; } var a = new d3_geo_clipPolygonIntersection(p0, segment, null, true), b = new d3_geo_clipPolygonIntersection(p0, null, a, false); a.o = b; subject.push(a); clip.push(b); a = new d3_geo_clipPolygonIntersection(p1, segment, null, false); b = new d3_geo_clipPolygonIntersection(p1, null, a, true); a.o = b; subject.push(a); clip.push(b); }); clip.sort(compare); d3_geo_clipPolygonLinkCircular(subject); d3_geo_clipPolygonLinkCircular(clip); if (!subject.length) return; for (var i = 0, entry = clipStartInside, n = clip.length; i < n; ++i) { clip[i].e = entry = !entry; } var start = subject[0], points, point; while (1) { var current = start, isSubject = true; while (current.v) if ((current = current.n) === start) return; points = current.z; listener.lineStart(); do { current.v = current.o.v = true; if (current.e) { if (isSubject) { for (var i = 0, n = points.length; i < n; ++i) listener.point((point = points[i])[0], point[1]); } else { interpolate(current.x, current.n.x, 1, listener); } current = current.n; } else { if (isSubject) { points = current.p.z; for (var i = points.length - 1; i >= 0; --i) listener.point((point = points[i])[0], point[1]); } else { interpolate(current.x, current.p.x, -1, listener); } current = current.p; } current = current.o; points = current.z; isSubject = !isSubject; } while (!current.v); listener.lineEnd(); } } function d3_geo_clipPolygonLinkCircular(array) { if (!(n = array.length)) return; var n, i = 0, a = array[0], b; while (++i < n) { a.n = b = array[i]; b.p = a; a = b; } a.n = b = array[0]; b.p = a; } function d3_geo_clipPolygonIntersection(point, points, other, entry) { this.x = point; this.z = points; this.o = other; this.e = entry; this.v = false; this.n = this.p = null; } function d3_geo_clip(pointVisible, clipLine, interpolate, clipStart) { return function(rotate, listener) { var line = clipLine(listener), rotatedClipStart = rotate.invert(clipStart[0], clipStart[1]); var clip = { point: point, lineStart: lineStart, lineEnd: lineEnd, polygonStart: function() { clip.point = pointRing; clip.lineStart = ringStart; clip.lineEnd = ringEnd; segments = []; polygon = []; }, polygonEnd: function() { clip.point = point; clip.lineStart = lineStart; clip.lineEnd = lineEnd; segments = d3.merge(segments); var clipStartInside = d3_geo_pointInPolygon(rotatedClipStart, polygon); if (segments.length) { if (!polygonStarted) listener.polygonStart(), polygonStarted = true; d3_geo_clipPolygon(segments, d3_geo_clipSort, clipStartInside, interpolate, listener); } else if (clipStartInside) { if (!polygonStarted) listener.polygonStart(), polygonStarted = true; listener.lineStart(); interpolate(null, null, 1, listener); listener.lineEnd(); } if (polygonStarted) listener.polygonEnd(), polygonStarted = false; segments = polygon = null; }, sphere: function() { listener.polygonStart(); listener.lineStart(); interpolate(null, null, 1, listener); listener.lineEnd(); listener.polygonEnd(); } }; function point(λ, φ) { var point = rotate(λ, φ); if (pointVisible(λ = point[0], φ = point[1])) listener.point(λ, φ); } function pointLine(λ, φ) { var point = rotate(λ, φ); line.point(point[0], point[1]); } function lineStart() { clip.point = pointLine; line.lineStart(); } function lineEnd() { clip.point = point; line.lineEnd(); } var segments; var buffer = d3_geo_clipBufferListener(), ringListener = clipLine(buffer), polygonStarted = false, polygon, ring; function pointRing(λ, φ) { ring.push([ λ, φ ]); var point = rotate(λ, φ); ringListener.point(point[0], point[1]); } function ringStart() { ringListener.lineStart(); ring = []; } function ringEnd() { pointRing(ring[0][0], ring[0][1]); ringListener.lineEnd(); var clean = ringListener.clean(), ringSegments = buffer.buffer(), segment, n = ringSegments.length; ring.pop(); polygon.push(ring); ring = null; if (!n) return; if (clean & 1) { segment = ringSegments[0]; var n = segment.length - 1, i = -1, point; if (n > 0) { if (!polygonStarted) listener.polygonStart(), polygonStarted = true; listener.lineStart(); while (++i < n) listener.point((point = segment[i])[0], point[1]); listener.lineEnd(); } return; } if (n > 1 && clean & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift())); segments.push(ringSegments.filter(d3_geo_clipSegmentLength1)); } return clip; }; } function d3_geo_clipSegmentLength1(segment) { return segment.length > 1; } function d3_geo_clipBufferListener() { var lines = [], line; return { lineStart: function() { lines.push(line = []); }, point: function(λ, φ) { line.push([ λ, φ ]); }, lineEnd: d3_noop, buffer: function() { var buffer = lines; lines = []; line = null; return buffer; }, rejoin: function() { if (lines.length > 1) lines.push(lines.pop().concat(lines.shift())); } }; } function d3_geo_clipSort(a, b) { return ((a = a.x)[0] < 0 ? a[1] - halfπ - ε : halfπ - a[1]) - ((b = b.x)[0] < 0 ? b[1] - halfπ - ε : halfπ - b[1]); } var d3_geo_clipAntimeridian = d3_geo_clip(d3_true, d3_geo_clipAntimeridianLine, d3_geo_clipAntimeridianInterpolate, [ -π, -π / 2 ]); function d3_geo_clipAntimeridianLine(listener) { var λ0 = NaN, φ0 = NaN, sλ0 = NaN, clean; return { lineStart: function() { listener.lineStart(); clean = 1; }, point: function(λ1, φ1) { var sλ1 = λ1 > 0 ? π : -π, dλ = abs(λ1 - λ0); if (abs(dλ - π) < ε) { listener.point(λ0, φ0 = (φ0 + φ1) / 2 > 0 ? halfπ : -halfπ); listener.point(sλ0, φ0); listener.lineEnd(); listener.lineStart(); listener.point(sλ1, φ0); listener.point(λ1, φ0); clean = 0; } else if (sλ0 !== sλ1 && dλ >= π) { if (abs(λ0 - sλ0) < ε) λ0 -= sλ0 * ε; if (abs(λ1 - sλ1) < ε) λ1 -= sλ1 * ε; φ0 = d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1); listener.point(sλ0, φ0); listener.lineEnd(); listener.lineStart(); listener.point(sλ1, φ0); clean = 0; } listener.point(λ0 = λ1, φ0 = φ1); sλ0 = sλ1; }, lineEnd: function() { listener.lineEnd(); λ0 = φ0 = NaN; }, clean: function() { return 2 - clean; } }; } function d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1) { var cosφ0, cosφ1, sinλ0_λ1 = Math.sin(λ0 - λ1); 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; } function d3_geo_clipAntimeridianInterpolate(from, to, direction, listener) { var φ; if (from == null) { φ = direction * halfπ; listener.point(-π, φ); listener.point(0, φ); listener.point(π, φ); listener.point(π, 0); listener.point(π, -φ); listener.point(0, -φ); listener.point(-π, -φ); listener.point(-π, 0); listener.point(-π, φ); } else if (abs(from[0] - to[0]) > ε) { var s = from[0] < to[0] ? π : -π; φ = direction * s / 2; listener.point(-s, φ); listener.point(0, φ); listener.point(s, φ); } else { listener.point(to[0], to[1]); } } function d3_geo_pointInPolygon(point, polygon) { var meridian = point[0], parallel = point[1], meridianNormal = [ Math.sin(meridian), -Math.cos(meridian), 0 ], polarAngle = 0, winding = 0; d3_geo_areaRingSum.reset(); for (var i = 0, n = polygon.length; i < n; ++i) { var ring = polygon[i], m = ring.length; if (!m) continue; var point0 = ring[0], λ0 = point0[0], φ0 = point0[1] / 2 + π / 4, sinφ0 = Math.sin(φ0), cosφ0 = Math.cos(φ0), j = 1; while (true) { if (j === m) j = 0; point = ring[j]; 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φ; d3_geo_areaRingSum.add(Math.atan2(k * sdλ * Math.sin(adλ), cosφ0 * cosφ + k * Math.cos(adλ))); polarAngle += antimeridian ? dλ + sdλ * τ : dλ; if (antimeridian ^ λ0 >= meridian ^ λ >= meridian) { var arc = d3_geo_cartesianCross(d3_geo_cartesian(point0), d3_geo_cartesian(point)); d3_geo_cartesianNormalize(arc); var intersection = d3_geo_cartesianCross(meridianNormal, arc); d3_geo_cartesianNormalize(intersection); var φarc = (antimeridian ^ dλ >= 0 ? -1 : 1) * d3_asin(intersection[2]); if (parallel > φarc || parallel === φarc && (arc[0] || arc[1])) { winding += antimeridian ^ dλ >= 0 ? 1 : -1; } } if (!j++) break; λ0 = λ, sinφ0 = sinφ, cosφ0 = cosφ, point0 = point; } } return (polarAngle < -ε || polarAngle < ε && d3_geo_areaRingSum < -ε) ^ winding & 1; } function d3_geo_clipCircle(radius) { var cr = Math.cos(radius), smallRadius = cr > 0, notHemisphere = abs(cr) > ε, interpolate = d3_geo_circleInterpolate(radius, 6 * d3_radians); return d3_geo_clip(visible, clipLine, interpolate, smallRadius ? [ 0, -radius ] : [ -π, radius - π ]); function visible(λ, φ) { return Math.cos(λ) * Math.cos(φ) > cr; } function clipLine(listener) { var point0, c0, v0, v00, clean; return { lineStart: function() { v00 = v0 = false; clean = 1; }, point: function(λ, φ) { var point1 = [ λ, φ ], point2, v = visible(λ, φ), c = smallRadius ? v ? 0 : code(λ, φ) : v ? code(λ + (λ < 0 ? π : -π), φ) : 0; if (!point0 && (v00 = v0 = v)) listener.lineStart(); if (v !== v0) { point2 = intersect(point0, point1); if (d3_geo_sphericalEqual(point0, point2) || d3_geo_sphericalEqual(point1, point2)) { point1[0] += ε; point1[1] += ε; v = visible(point1[0], point1[1]); } } if (v !== v0) { clean = 0; if (v) { listener.lineStart(); point2 = intersect(point1, point0); listener.point(point2[0], point2[1]); } else { point2 = intersect(point0, point1); listener.point(point2[0], point2[1]); listener.lineEnd(); } point0 = point2; } else if (notHemisphere && point0 && smallRadius ^ v) { var t; if (!(c & c0) && (t = intersect(point1, point0, true))) { clean = 0; if (smallRadius) { listener.lineStart(); listener.point(t[0][0], t[0][1]); listener.point(t[1][0], t[1][1]); listener.lineEnd(); } else { listener.point(t[1][0], t[1][1]); listener.lineEnd(); listener.lineStart(); listener.point(t[0][0], t[0][1]); } } } if (v && (!point0 || !d3_geo_sphericalEqual(point0, point1))) { listener.point(point1[0], point1[1]); } point0 = point1, v0 = v, c0 = c; }, lineEnd: function() { if (v0) listener.lineEnd(); point0 = null; }, clean: function() { return clean | (v00 && v0) << 1; } }; } function intersect(a, b, two) { var pa = d3_geo_cartesian(a), pb = d3_geo_cartesian(b); var n1 = [ 1, 0, 0 ], n2 = d3_geo_cartesianCross(pa, pb), n2n2 = d3_geo_cartesianDot(n2, n2), n1n2 = n2[0], determinant = n2n2 - n1n2 * n1n2; if (!determinant) return !two && a; 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); d3_geo_cartesianAdd(A, B); 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); if (t2 < 0) return; var t = Math.sqrt(t2), q = d3_geo_cartesianScale(u, (-w - t) / uu); d3_geo_cartesianAdd(q, A); q = d3_geo_spherical(q); if (!two) return q; var λ0 = a[0], λ1 = b[0], φ0 = a[1], φ1 = b[1], z; if (λ1 < λ0) z = λ0, λ0 = λ1, λ1 = z; var δλ = λ1 - λ0, polar = abs(δλ - π) < ε, meridian = polar || δλ < ε; if (!polar && φ1 < φ0) z = φ0, φ0 = φ1, φ1 = z; 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)) { var q1 = d3_geo_cartesianScale(u, (-w + t) / uu); d3_geo_cartesianAdd(q1, A); return [ q, d3_geo_spherical(q1) ]; } } function code(λ, φ) { var r = smallRadius ? radius : π - radius, code = 0; if (λ < -r) code |= 1; else if (λ > r) code |= 2; if (φ < -r) code |= 4; else if (φ > r) code |= 8; return code; } } function d3_geom_clipLine(x0, y0, x1, y1) { return function(line) { 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; r = x0 - ax; if (!dx && r > 0) return; r /= dx; if (dx < 0) { if (r < t0) return; if (r < t1) t1 = r; } else if (dx > 0) { if (r > t1) return; if (r > t0) t0 = r; } r = x1 - ax; if (!dx && r < 0) return; r /= dx; if (dx < 0) { if (r > t1) return; if (r > t0) t0 = r; } else if (dx > 0) { if (r < t0) return; if (r < t1) t1 = r; } r = y0 - ay; if (!dy && r > 0) return; r /= dy; if (dy < 0) { if (r < t0) return; if (r < t1) t1 = r; } else if (dy > 0) { if (r > t1) return; if (r > t0) t0 = r; } r = y1 - ay; if (!dy && r < 0) return; r /= dy; if (dy < 0) { if (r > t1) return; if (r > t0) t0 = r; } else if (dy > 0) { if (r < t0) return; if (r < t1) t1 = r; } if (t0 > 0) line.a = { x: ax + t0 * dx, y: ay + t0 * dy }; if (t1 < 1) line.b = { x: ax + t1 * dx, y: ay + t1 * dy }; return line; }; } var d3_geo_clipExtentMAX = 1e9; d3.geo.clipExtent = function() { var x0, y0, x1, y1, stream, clip, clipExtent = { stream: function(output) { if (stream) stream.valid = false; stream = clip(output); stream.valid = true; return stream; }, extent: function(_) { if (!arguments.length) return [ [ x0, y0 ], [ x1, y1 ] ]; clip = d3_geo_clipExtent(x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1]); if (stream) stream.valid = false, stream = null; return clipExtent; } }; return clipExtent.extent([ [ 0, 0 ], [ 960, 500 ] ]); }; function d3_geo_clipExtent(x0, y0, x1, y1) { return function(listener) { var listener_ = listener, bufferListener = d3_geo_clipBufferListener(), clipLine = d3_geom_clipLine(x0, y0, x1, y1), segments, polygon, ring; var clip = { point: point, lineStart: lineStart, lineEnd: lineEnd, polygonStart: function() { listener = bufferListener; segments = []; polygon = []; clean = true; }, polygonEnd: function() { listener = listener_; segments = d3.merge(segments); var clipStartInside = insidePolygon([ x0, y1 ]), inside = clean && clipStartInside, visible = segments.length; if (inside || visible) { listener.polygonStart(); if (inside) { listener.lineStart(); interpolate(null, null, 1, listener); listener.lineEnd(); } if (visible) { d3_geo_clipPolygon(segments, compare, clipStartInside, interpolate, listener); } listener.polygonEnd(); } segments = polygon = ring = null; } }; function insidePolygon(p) { var wn = 0, n = polygon.length, y = p[1]; for (var i = 0; i < n; ++i) { for (var j = 1, v = polygon[i], m = v.length, a = v[0], b; j < m; ++j) { b = v[j]; if (a[1] <= y) { if (b[1] > y && d3_cross2d(a, b, p) > 0) ++wn; } else { if (b[1] <= y && d3_cross2d(a, b, p) < 0) --wn; } a = b; } } return wn !== 0; } function interpolate(from, to, direction, listener) { var a = 0, a1 = 0; if (from == null || (a = corner(from, direction)) !== (a1 = corner(to, direction)) || comparePoints(from, to) < 0 ^ direction > 0) { do { listener.point(a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0); } while ((a = (a + direction + 4) % 4) !== a1); } else { listener.point(to[0], to[1]); } } function pointVisible(x, y) { return x0 <= x && x <= x1 && y0 <= y && y <= y1; } function point(x, y) { if (pointVisible(x, y)) listener.point(x, y); } var x__, y__, v__, x_, y_, v_, first, clean; function lineStart() { clip.point = linePoint; if (polygon) polygon.push(ring = []); first = true; v_ = false; x_ = y_ = NaN; } function lineEnd() { if (segments) { linePoint(x__, y__); if (v__ && v_) bufferListener.rejoin(); segments.push(bufferListener.buffer()); } clip.point = point; if (v_) listener.lineEnd(); } function linePoint(x, y) { x = Math.max(-d3_geo_clipExtentMAX, Math.min(d3_geo_clipExtentMAX, x)); y = Math.max(-d3_geo_clipExtentMAX, Math.min(d3_geo_clipExtentMAX, y)); var v = pointVisible(x, y); if (polygon) ring.push([ x, y ]); if (first) { x__ = x, y__ = y, v__ = v; first = false; if (v) { listener.lineStart(); listener.point(x, y); } } else { if (v && v_) listener.point(x, y); else { var l = { a: { x: x_, y: y_ }, b: { x: x, y: y } }; if (clipLine(l)) { if (!v_) { listener.lineStart(); listener.point(l.a.x, l.a.y); } listener.point(l.b.x, l.b.y); if (!v) listener.lineEnd(); clean = false; } else if (v) { listener.lineStart(); listener.point(x, y); clean = false; } } } x_ = x, y_ = y, v_ = v; } return clip; }; function corner(p, direction) { 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; } function compare(a, b) { return comparePoints(a.x, b.x); } function comparePoints(a, b) { var ca = corner(a, 1), cb = corner(b, 1); 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]; } } function d3_geo_conic(projectAt) { var φ0 = 0, φ1 = π / 3, m = d3_geo_projectionMutator(projectAt), p = m(φ0, φ1); p.parallels = function(_) { if (!arguments.length) return [ φ0 / π * 180, φ1 / π * 180 ]; return m(φ0 = _[0] * π / 180, φ1 = _[1] * π / 180); }; return p; } function d3_geo_conicEqualArea(φ0, φ1) { 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; function forward(λ, φ) { var ρ = Math.sqrt(C - 2 * n * Math.sin(φ)) / n; return [ ρ * Math.sin(λ *= n), ρ0 - ρ * Math.cos(λ) ]; } forward.invert = function(x, y) { var ρ0_y = ρ0 - y; return [ Math.atan2(x, ρ0_y) / n, d3_asin((C - (x * x + ρ0_y * ρ0_y) * n * n) / (2 * n)) ]; }; return forward; } (d3.geo.conicEqualArea = function() { return d3_geo_conic(d3_geo_conicEqualArea); }).raw = d3_geo_conicEqualArea; d3.geo.albers = function() { return d3.geo.conicEqualArea().rotate([ 96, 0 ]).center([ -.6, 38.7 ]).parallels([ 29.5, 45.5 ]).scale(1070); }; d3.geo.albersUsa = function() { var lower48 = d3.geo.albers(); var alaska = d3.geo.conicEqualArea().rotate([ 154, 0 ]).center([ -2, 58.5 ]).parallels([ 55, 65 ]); var hawaii = d3.geo.conicEqualArea().rotate([ 157, 0 ]).center([ -3, 19.9 ]).parallels([ 8, 18 ]); var point, pointStream = { point: function(x, y) { point = [ x, y ]; } }, lower48Point, alaskaPoint, hawaiiPoint; function albersUsa(coordinates) { var x = coordinates[0], y = coordinates[1]; point = null; (lower48Point(x, y), point) || (alaskaPoint(x, y), point) || hawaiiPoint(x, y); return point; } albersUsa.invert = function(coordinates) { var k = lower48.scale(), t = lower48.translate(), x = (coordinates[0] - t[0]) / k, y = (coordinates[1] - t[1]) / k; return (y >= .12 && y < .234 && x >= -.425 && x < -.214 ? alaska : y >= .166 && y < .234 && x >= -.214 && x < -.115 ? hawaii : lower48).invert(coordinates); }; albersUsa.stream = function(stream) { var lower48Stream = lower48.stream(stream), alaskaStream = alaska.stream(stream), hawaiiStream = hawaii.stream(stream); return { point: function(x, y) { lower48Stream.point(x, y); alaskaStream.point(x, y); hawaiiStream.point(x, y); }, sphere: function() { lower48Stream.sphere(); alaskaStream.sphere(); hawaiiStream.sphere(); }, lineStart: function() { lower48Stream.lineStart(); alaskaStream.lineStart(); hawaiiStream.lineStart(); }, lineEnd: function() { lower48Stream.lineEnd(); alaskaStream.lineEnd(); hawaiiStream.lineEnd(); }, polygonStart: function() { lower48Stream.polygonStart(); alaskaStream.polygonStart(); hawaiiStream.polygonStart(); }, polygonEnd: function() { lower48Stream.polygonEnd(); alaskaStream.polygonEnd(); hawaiiStream.polygonEnd(); } }; }; albersUsa.precision = function(_) { if (!arguments.length) return lower48.precision(); lower48.precision(_); alaska.precision(_); hawaii.precision(_); return albersUsa; }; albersUsa.scale = function(_) { if (!arguments.length) return lower48.scale(); lower48.scale(_); alaska.scale(_ * .35); hawaii.scale(_); return albersUsa.translate(lower48.translate()); }; albersUsa.translate = function(_) { if (!arguments.length) return lower48.translate(); var k = lower48.scale(), x = +_[0], y = +_[1]; lower48Point = lower48.translate(_).clipExtent([ [ x - .455 * k, y - .238 * k ], [ x + .455 * k, y + .238 * k ] ]).stream(pointStream).point; 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; 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; return albersUsa; }; return albersUsa.scale(1070); }; var d3_geo_pathAreaSum, d3_geo_pathAreaPolygon, d3_geo_pathArea = { point: d3_noop, lineStart: d3_noop, lineEnd: d3_noop, polygonStart: function() { d3_geo_pathAreaPolygon = 0; d3_geo_pathArea.lineStart = d3_geo_pathAreaRingStart; }, polygonEnd: function() { d3_geo_pathArea.lineStart = d3_geo_pathArea.lineEnd = d3_geo_pathArea.point = d3_noop; d3_geo_pathAreaSum += abs(d3_geo_pathAreaPolygon / 2); } }; function d3_geo_pathAreaRingStart() { var x00, y00, x0, y0; d3_geo_pathArea.point = function(x, y) { d3_geo_pathArea.point = nextPoint; x00 = x0 = x, y00 = y0 = y; }; function nextPoint(x, y) { d3_geo_pathAreaPolygon += y0 * x - x0 * y; x0 = x, y0 = y; } d3_geo_pathArea.lineEnd = function() { nextPoint(x00, y00); }; } var d3_geo_pathBoundsX0, d3_geo_pathBoundsY0, d3_geo_pathBoundsX1, d3_geo_pathBoundsY1; var d3_geo_pathBounds = { point: d3_geo_pathBoundsPoint, lineStart: d3_noop, lineEnd: d3_noop, polygonStart: d3_noop, polygonEnd: d3_noop }; function d3_geo_pathBoundsPoint(x, y) { if (x < d3_geo_pathBoundsX0) d3_geo_pathBoundsX0 = x; if (x > d3_geo_pathBoundsX1) d3_geo_pathBoundsX1 = x; if (y < d3_geo_pathBoundsY0) d3_geo_pathBoundsY0 = y; if (y > d3_geo_pathBoundsY1) d3_geo_pathBoundsY1 = y; } function d3_geo_pathBuffer() { var pointCircle = d3_geo_pathBufferCircle(4.5), buffer = []; var stream = { point: point, lineStart: function() { stream.point = pointLineStart; }, lineEnd: lineEnd, polygonStart: function() { stream.lineEnd = lineEndPolygon; }, polygonEnd: function() { stream.lineEnd = lineEnd; stream.point = point; }, pointRadius: function(_) { pointCircle = d3_geo_pathBufferCircle(_); return stream; }, result: function() { if (buffer.length) { var result = buffer.join(""); buffer = []; return result; } } }; function point(x, y) { buffer.push("M", x, ",", y, pointCircle); } function pointLineStart(x, y) { buffer.push("M", x, ",", y); stream.point = pointLine; } function pointLine(x, y) { buffer.push("L", x, ",", y); } function lineEnd() { stream.point = point; } function lineEndPolygon() { buffer.push("Z"); } return stream; } function d3_geo_pathBufferCircle(radius) { return "m0," + radius + "a" + radius + "," + radius + " 0 1,1 0," + -2 * radius + "a" + radius + "," + radius + " 0 1,1 0," + 2 * radius + "z"; } var d3_geo_pathCentroid = { point: d3_geo_pathCentroidPoint, lineStart: d3_geo_pathCentroidLineStart, lineEnd: d3_geo_pathCentroidLineEnd, polygonStart: function() { d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidRingStart; }, polygonEnd: function() { d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint; d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidLineStart; d3_geo_pathCentroid.lineEnd = d3_geo_pathCentroidLineEnd; } }; function d3_geo_pathCentroidPoint(x, y) { d3_geo_centroidX0 += x; d3_geo_centroidY0 += y; ++d3_geo_centroidZ0; } function d3_geo_pathCentroidLineStart() { var x0, y0; d3_geo_pathCentroid.point = function(x, y) { d3_geo_pathCentroid.point = nextPoint; d3_geo_pathCentroidPoint(x0 = x, y0 = y); }; function nextPoint(x, y) { var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy); d3_geo_centroidX1 += z * (x0 + x) / 2; d3_geo_centroidY1 += z * (y0 + y) / 2; d3_geo_centroidZ1 += z; d3_geo_pathCentroidPoint(x0 = x, y0 = y); } } function d3_geo_pathCentroidLineEnd() { d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint; } function d3_geo_pathCentroidRingStart() { var x00, y00, x0, y0; d3_geo_pathCentroid.point = function(x, y) { d3_geo_pathCentroid.point = nextPoint; d3_geo_pathCentroidPoint(x00 = x0 = x, y00 = y0 = y); }; function nextPoint(x, y) { var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy); d3_geo_centroidX1 += z * (x0 + x) / 2; d3_geo_centroidY1 += z * (y0 + y) / 2; d3_geo_centroidZ1 += z; z = y0 * x - x0 * y; d3_geo_centroidX2 += z * (x0 + x); d3_geo_centroidY2 += z * (y0 + y); d3_geo_centroidZ2 += z * 3; d3_geo_pathCentroidPoint(x0 = x, y0 = y); } d3_geo_pathCentroid.lineEnd = function() { nextPoint(x00, y00); }; } function d3_geo_pathContext(context) { var pointRadius = 4.5; var stream = { point: point, lineStart: function() { stream.point = pointLineStart; }, lineEnd: lineEnd, polygonStart: function() { stream.lineEnd = lineEndPolygon; }, polygonEnd: function() { stream.lineEnd = lineEnd; stream.point = point; }, pointRadius: function(_) { pointRadius = _; return stream; }, result: d3_noop }; function point(x, y) { context.moveTo(x + pointRadius, y); context.arc(x, y, pointRadius, 0, τ); } function pointLineStart(x, y) { context.moveTo(x, y); stream.point = pointLine; } function pointLine(x, y) { context.lineTo(x, y); } function lineEnd() { stream.point = point; } function lineEndPolygon() { context.closePath(); } return stream; } function d3_geo_resample(project) { var δ2 = .5, cosMinDistance = Math.cos(30 * d3_radians), maxDepth = 16; function resample(stream) { return (maxDepth ? resampleRecursive : resampleNone)(stream); } function resampleNone(stream) { return d3_geo_transformPoint(stream, function(x, y) { x = project(x, y); stream.point(x[0], x[1]); }); } function resampleRecursive(stream) { var λ00, φ00, x00, y00, a00, b00, c00, λ0, x0, y0, a0, b0, c0; var resample = { point: point, lineStart: lineStart, lineEnd: lineEnd, polygonStart: function() { stream.polygonStart(); resample.lineStart = ringStart; }, polygonEnd: function() { stream.polygonEnd(); resample.lineStart = lineStart; } }; function point(x, y) { x = project(x, y); stream.point(x[0], x[1]); } function lineStart() { x0 = NaN; resample.point = linePoint; stream.lineStart(); } function linePoint(λ, φ) { var c = d3_geo_cartesian([ λ, φ ]), p = project(λ, φ); 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); stream.point(x0, y0); } function lineEnd() { resample.point = point; stream.lineEnd(); } function ringStart() { lineStart(); resample.point = ringPoint; resample.lineEnd = ringEnd; } function ringPoint(λ, φ) { linePoint(λ00 = λ, φ00 = φ), x00 = x0, y00 = y0, a00 = a0, b00 = b0, c00 = c0; resample.point = linePoint; } function ringEnd() { resampleLineTo(x0, y0, λ0, a0, b0, c0, x00, y00, λ00, a00, b00, c00, maxDepth, stream); resample.lineEnd = lineEnd; lineEnd(); } return resample; } function resampleLineTo(x0, y0, λ0, a0, b0, c0, x1, y1, λ1, a1, b1, c1, depth, stream) { var dx = x1 - x0, dy = y1 - y0, d2 = dx * dx + dy * dy; if (d2 > 4 * δ2 && depth--) { 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; if (dz * dz / d2 > δ2 || abs((dx * dx2 + dy * dy2) / d2 - .5) > .3 || a0 * a1 + b0 * b1 + c0 * c1 < cosMinDistance) { resampleLineTo(x0, y0, λ0, a0, b0, c0, x2, y2, λ2, a /= m, b /= m, c, depth, stream); stream.point(x2, y2); resampleLineTo(x2, y2, λ2, a, b, c, x1, y1, λ1, a1, b1, c1, depth, stream); } } } resample.precision = function(_) { if (!arguments.length) return Math.sqrt(δ2); maxDepth = (δ2 = _ * _) > 0 && 16; return resample; }; return resample; } d3.geo.path = function() { var pointRadius = 4.5, projection, context, projectStream, contextStream, cacheStream; function path(object) { if (object) { if (typeof pointRadius === "function") contextStream.pointRadius(+pointRadius.apply(this, arguments)); if (!cacheStream || !cacheStream.valid) cacheStream = projectStream(contextStream); d3.geo.stream(object, cacheStream); } return contextStream.result(); } path.area = function(object) { d3_geo_pathAreaSum = 0; d3.geo.stream(object, projectStream(d3_geo_pathArea)); return d3_geo_pathAreaSum; }; path.centroid = function(object) { 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; d3.geo.stream(object, projectStream(d3_geo_pathCentroid)); 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 ]; }; path.bounds = function(object) { d3_geo_pathBoundsX1 = d3_geo_pathBoundsY1 = -(d3_geo_pathBoundsX0 = d3_geo_pathBoundsY0 = Infinity); d3.geo.stream(object, projectStream(d3_geo_pathBounds)); return [ [ d3_geo_pathBoundsX0, d3_geo_pathBoundsY0 ], [ d3_geo_pathBoundsX1, d3_geo_pathBoundsY1 ] ]; }; path.projection = function(_) { if (!arguments.length) return projection; projectStream = (projection = _) ? _.stream || d3_geo_pathProjectStream(_) : d3_identity; return reset(); }; path.context = function(_) { if (!arguments.length) return context; contextStream = (context = _) == null ? new d3_geo_pathBuffer() : new d3_geo_pathContext(_); if (typeof pointRadius !== "function") contextStream.pointRadius(pointRadius); return reset(); }; path.pointRadius = function(_) { if (!arguments.length) return pointRadius; pointRadius = typeof _ === "function" ? _ : (contextStream.pointRadius(+_), +_); return path; }; function reset() { cacheStream = null; return path; } return path.projection(d3.geo.albersUsa()).context(null); }; function d3_geo_pathProjectStream(project) { var resample = d3_geo_resample(function(x, y) { return project([ x * d3_degrees, y * d3_degrees ]); }); return function(stream) { return d3_geo_projectionRadians(resample(stream)); }; } d3.geo.transform = function(methods) { return { stream: function(stream) { var transform = new d3_geo_transform(stream); for (var k in methods) transform[k] = methods[k]; return transform; } }; }; function d3_geo_transform(stream) { this.stream = stream; } d3_geo_transform.prototype = { point: function(x, y) { this.stream.point(x, y); }, 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(); } }; function d3_geo_transformPoint(stream, point) { return { point: point, sphere: function() { stream.sphere(); }, lineStart: function() { stream.lineStart(); }, lineEnd: function() { stream.lineEnd(); }, polygonStart: function() { stream.polygonStart(); }, polygonEnd: function() { stream.polygonEnd(); } }; } d3.geo.projection = d3_geo_projection; d3.geo.projectionMutator = d3_geo_projectionMutator; function d3_geo_projection(project) { return d3_geo_projectionMutator(function() { return project; })(); } function d3_geo_projectionMutator(projectAt) { var project, rotate, projectRotate, projectResample = d3_geo_resample(function(x, y) { x = project(x, y); return [ x[0] * k + δx, δy - x[1] * k ]; }), 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; function projection(point) { point = projectRotate(point[0] * d3_radians, point[1] * d3_radians); return [ point[0] * k + δx, δy - point[1] * k ]; } function invert(point) { point = projectRotate.invert((point[0] - δx) / k, (δy - point[1]) / k); return point && [ point[0] * d3_degrees, point[1] * d3_degrees ]; } projection.stream = function(output) { if (stream) stream.valid = false; stream = d3_geo_projectionRadians(preclip(rotate, projectResample(postclip(output)))); stream.valid = true; return stream; }; projection.clipAngle = function(_) { if (!arguments.length) return clipAngle; preclip = _ == null ? (clipAngle = _, d3_geo_clipAntimeridian) : d3_geo_clipCircle((clipAngle = +_) * d3_radians); return invalidate(); }; projection.clipExtent = function(_) { if (!arguments.length) return clipExtent; clipExtent = _; postclip = _ ? d3_geo_clipExtent(_[0][0], _[0][1], _[1][0], _[1][1]) : d3_identity; return invalidate(); }; projection.scale = function(_) { if (!arguments.length) return k; k = +_; return reset(); }; projection.translate = function(_) { if (!arguments.length) return [ x, y ]; x = +_[0]; y = +_[1]; return reset(); }; projection.center = function(_) { if (!arguments.length) return [ λ * d3_degrees, φ * d3_degrees ]; λ = _[0] % 360 * d3_radians; φ = _[1] % 360 * d3_radians; return reset(); }; projection.rotate = function(_) { if (!arguments.length) return [ δλ * d3_degrees, δφ * d3_degrees, δγ * d3_degrees ]; δλ = _[0] % 360 * d3_radians; δφ = _[1] % 360 * d3_radians; δγ = _.length > 2 ? _[2] % 360 * d3_radians : 0; return reset(); }; d3.rebind(projection, projectResample, "precision"); function reset() { projectRotate = d3_geo_compose(rotate = d3_geo_rotation(δλ, δφ, δγ), project); var center = project(λ, φ); δx = x - center[0] * k; δy = y + center[1] * k; return invalidate(); } function invalidate() { if (stream) stream.valid = false, stream = null; return projection; } return function() { project = projectAt.apply(this, arguments); projection.invert = project.invert && invert; return reset(); }; } function d3_geo_projectionRadians(stream) { return d3_geo_transformPoint(stream, function(x, y) { stream.point(x * d3_radians, y * d3_radians); }); } function d3_geo_equirectangular(λ, φ) { return [ λ, φ ]; } (d3.geo.equirectangular = function() { return d3_geo_projection(d3_geo_equirectangular); }).raw = d3_geo_equirectangular.invert = d3_geo_equirectangular; d3.geo.rotation = function(rotate) { rotate = d3_geo_rotation(rotate[0] % 360 * d3_radians, rotate[1] * d3_radians, rotate.length > 2 ? rotate[2] * d3_radians : 0); function forward(coordinates) { coordinates = rotate(coordinates[0] * d3_radians, coordinates[1] * d3_radians); return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates; } forward.invert = function(coordinates) { coordinates = rotate.invert(coordinates[0] * d3_radians, coordinates[1] * d3_radians); return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates; }; return forward; }; function d3_geo_identityRotation(λ, φ) { return [ λ > π ? λ - τ : λ < -π ? λ + τ : λ, φ ]; } d3_geo_identityRotation.invert = d3_geo_equirectangular; function d3_geo_rotation(δλ, δφ, δγ) { return δλ ? δφ || δγ ? d3_geo_compose(d3_geo_rotationλ(δλ), d3_geo_rotationφγ(δφ, δγ)) : d3_geo_rotationλ(δλ) : δφ || δγ ? d3_geo_rotationφγ(δφ, δγ) : d3_geo_identityRotation; } function d3_geo_forwardRotationλ(δλ) { return function(λ, φ) { return λ += δλ, [ λ > π ? λ - τ : λ < -π ? λ + τ : λ, φ ]; }; } function d3_geo_rotationλ(δλ) { var rotation = d3_geo_forwardRotationλ(δλ); rotation.invert = d3_geo_forwardRotationλ(-δλ); return rotation; } function d3_geo_rotationφγ(δφ, δγ) { var cosδφ = Math.cos(δφ), sinδφ = Math.sin(δφ), cosδγ = Math.cos(δγ), sinδγ = Math.sin(δγ); function rotation(λ, φ) { var cosφ = Math.cos(φ), x = Math.cos(λ) * cosφ, y = Math.sin(λ) * cosφ, z = Math.sin(φ), k = z * cosδφ + x * sinδφ; return [ Math.atan2(y * cosδγ - k * sinδγ, x * cosδφ - z * sinδφ), d3_asin(k * cosδγ + y * sinδγ) ]; } rotation.invert = function(λ, φ) { var cosφ = Math.cos(φ), x = Math.cos(λ) * cosφ, y = Math.sin(λ) * cosφ, z = Math.sin(φ), k = z * cosδγ - y * sinδγ; return [ Math.atan2(y * cosδγ + z * sinδγ, x * cosδφ + k * sinδφ), d3_asin(k * cosδφ - x * sinδφ) ]; }; return rotation; } d3.geo.circle = function() { var origin = [ 0, 0 ], angle, precision = 6, interpolate; function circle() { 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 = []; interpolate(null, null, 1, { point: function(x, y) { ring.push(x = rotate(x, y)); x[0] *= d3_degrees, x[1] *= d3_degrees; } }); return { type: "Polygon", coordinates: [ ring ] }; } circle.origin = function(x) { if (!arguments.length) return origin; origin = x; return circle; }; circle.angle = function(x) { if (!arguments.length) return angle; interpolate = d3_geo_circleInterpolate((angle = +x) * d3_radians, precision * d3_radians); return circle; }; circle.precision = function(_) { if (!arguments.length) return precision; interpolate = d3_geo_circleInterpolate(angle * d3_radians, (precision = +_) * d3_radians); return circle; }; return circle.angle(90); }; function d3_geo_circleInterpolate(radius, precision) { var cr = Math.cos(radius), sr = Math.sin(radius); return function(from, to, direction, listener) { var step = direction * precision; if (from != null) { from = d3_geo_circleAngle(cr, from); to = d3_geo_circleAngle(cr, to); if (direction > 0 ? from < to : from > to) from += direction * τ; } else { from = radius + direction * τ; to = radius - .5 * step; } for (var point, t = from; direction > 0 ? t > to : t < to; t -= step) { listener.point((point = d3_geo_spherical([ cr, -sr * Math.cos(t), -sr * Math.sin(t) ]))[0], point[1]); } }; } function d3_geo_circleAngle(cr, point) { var a = d3_geo_cartesian(point); a[0] -= cr; d3_geo_cartesianNormalize(a); var angle = d3_acos(-a[1]); return ((-a[2] < 0 ? -angle : angle) + 2 * Math.PI - ε) % (2 * Math.PI); } d3.geo.distance = function(a, b) { 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; 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Δλ); }; d3.geo.graticule = function() { var x1, x0, X1, X0, y1, y0, Y1, Y0, dx = 10, dy = dx, DX = 90, DY = 360, x, y, X, Y, precision = 2.5; function graticule() { return { type: "MultiLineString", coordinates: lines() }; } function lines() { 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) { return abs(x % DX) > ε; }).map(x)).concat(d3.range(Math.ceil(y0 / dy) * dy, y1, dy).filter(function(y) { return abs(y % DY) > ε; }).map(y)); } graticule.lines = function() { return lines().map(function(coordinates) { return { type: "LineString", coordinates: coordinates }; }); }; graticule.outline = function() { return { type: "Polygon", coordinates: [ X(X0).concat(Y(Y1).slice(1), X(X1).reverse().slice(1), Y(Y0).reverse().slice(1)) ] }; }; graticule.extent = function(_) { if (!arguments.length) return graticule.minorExtent(); return graticule.majorExtent(_).minorExtent(_); }; graticule.majorExtent = function(_) { if (!arguments.length) return [ [ X0, Y0 ], [ X1, Y1 ] ]; X0 = +_[0][0], X1 = +_[1][0]; Y0 = +_[0][1], Y1 = +_[1][1]; if (X0 > X1) _ = X0, X0 = X1, X1 = _; if (Y0 > Y1) _ = Y0, Y0 = Y1, Y1 = _; return graticule.precision(precision); }; graticule.minorExtent = function(_) { if (!arguments.length) return [ [ x0, y0 ], [ x1, y1 ] ]; x0 = +_[0][0], x1 = +_[1][0]; y0 = +_[0][1], y1 = +_[1][1]; if (x0 > x1) _ = x0, x0 = x1, x1 = _; if (y0 > y1) _ = y0, y0 = y1, y1 = _; return graticule.precision(precision); }; graticule.step = function(_) { if (!arguments.length) return graticule.minorStep(); return graticule.majorStep(_).minorStep(_); }; graticule.majorStep = function(_) { if (!arguments.length) return [ DX, DY ]; DX = +_[0], DY = +_[1]; return graticule; }; graticule.minorStep = function(_) { if (!arguments.length) return [ dx, dy ]; dx = +_[0], dy = +_[1]; return graticule; }; graticule.precision = function(_) { if (!arguments.length) return precision; precision = +_; x = d3_geo_graticuleX(y0, y1, 90); y = d3_geo_graticuleY(x0, x1, precision); X = d3_geo_graticuleX(Y0, Y1, 90); Y = d3_geo_graticuleY(X0, X1, precision); return graticule; }; return graticule.majorExtent([ [ -180, -90 + ε ], [ 180, 90 - ε ] ]).minorExtent([ [ -180, -80 - ε ], [ 180, 80 + ε ] ]); }; function d3_geo_graticuleX(y0, y1, dy) { var y = d3.range(y0, y1 - ε, dy).concat(y1); return function(x) { return y.map(function(y) { return [ x, y ]; }); }; } function d3_geo_graticuleY(x0, x1, dx) { var x = d3.range(x0, x1 - ε, dx).concat(x1); return function(y) { return x.map(function(x) { return [ x, y ]; }); }; } function d3_source(d) { return d.source; } function d3_target(d) { return d.target; } d3.geo.greatArc = function() { var source = d3_source, source_, target = d3_target, target_; function greatArc() { return { type: "LineString", coordinates: [ source_ || source.apply(this, arguments), target_ || target.apply(this, arguments) ] }; } greatArc.distance = function() { return d3.geo.distance(source_ || source.apply(this, arguments), target_ || target.apply(this, arguments)); }; greatArc.source = function(_) { if (!arguments.length) return source; source = _, source_ = typeof _ === "function" ? null : _; return greatArc; }; greatArc.target = function(_) { if (!arguments.length) return target; target = _, target_ = typeof _ === "function" ? null : _; return greatArc; }; greatArc.precision = function() { return arguments.length ? greatArc : 0; }; return greatArc; }; d3.geo.interpolate = function(source, target) { return d3_geo_interpolate(source[0] * d3_radians, source[1] * d3_radians, target[0] * d3_radians, target[1] * d3_radians); }; function d3_geo_interpolate(x0, y0, x1, y1) { 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); var interpolate = d ? function(t) { 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; return [ Math.atan2(y, x) * d3_degrees, Math.atan2(z, Math.sqrt(x * x + y * y)) * d3_degrees ]; } : function() { return [ x0 * d3_degrees, y0 * d3_degrees ]; }; interpolate.distance = d; return interpolate; } d3.geo.length = function(object) { d3_geo_lengthSum = 0; d3.geo.stream(object, d3_geo_length); return d3_geo_lengthSum; }; var d3_geo_lengthSum; var d3_geo_length = { sphere: d3_noop, point: d3_noop, lineStart: d3_geo_lengthLineStart, lineEnd: d3_noop, polygonStart: d3_noop, polygonEnd: d3_noop }; function d3_geo_lengthLineStart() { var λ0, sinφ0, cosφ0; d3_geo_length.point = function(λ, φ) { λ0 = λ * d3_radians, sinφ0 = Math.sin(φ *= d3_radians), cosφ0 = Math.cos(φ); d3_geo_length.point = nextPoint; }; d3_geo_length.lineEnd = function() { d3_geo_length.point = d3_geo_length.lineEnd = d3_noop; }; function nextPoint(λ, φ) { var sinφ = Math.sin(φ *= d3_radians), cosφ = Math.cos(φ), t = abs((λ *= d3_radians) - λ0), cosΔλ = Math.cos(t); 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Δλ); λ0 = λ, sinφ0 = sinφ, cosφ0 = cosφ; } } function d3_geo_azimuthal(scale, angle) { function azimuthal(λ, φ) { var cosλ = Math.cos(λ), cosφ = Math.cos(φ), k = scale(cosλ * cosφ); return [ k * cosφ * Math.sin(λ), k * Math.sin(φ) ]; } azimuthal.invert = function(x, y) { var ρ = Math.sqrt(x * x + y * y), c = angle(ρ), sinc = Math.sin(c), cosc = Math.cos(c); return [ Math.atan2(x * sinc, ρ * cosc), Math.asin(ρ && y * sinc / ρ) ]; }; return azimuthal; } var d3_geo_azimuthalEqualArea = d3_geo_azimuthal(function(cosλcosφ) { return Math.sqrt(2 / (1 + cosλcosφ)); }, function(ρ) { return 2 * Math.asin(ρ / 2); }); (d3.geo.azimuthalEqualArea = function() { return d3_geo_projection(d3_geo_azimuthalEqualArea); }).raw = d3_geo_azimuthalEqualArea; var d3_geo_azimuthalEquidistant = d3_geo_azimuthal(function(cosλcosφ) { var c = Math.acos(cosλcosφ); return c && c / Math.sin(c); }, d3_identity); (d3.geo.azimuthalEquidistant = function() { return d3_geo_projection(d3_geo_azimuthalEquidistant); }).raw = d3_geo_azimuthalEquidistant; function d3_geo_conicConformal(φ0, φ1) { var cosφ0 = Math.cos(φ0), t = function(φ) { return Math.tan(π / 4 + φ / 2); }, 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; if (!n) return d3_geo_mercator; function forward(λ, φ) { if (F > 0) { if (φ < -halfπ + ε) φ = -halfπ + ε; } else { if (φ > halfπ - ε) φ = halfπ - ε; } var ρ = F / Math.pow(t(φ), n); return [ ρ * Math.sin(n * λ), F - ρ * Math.cos(n * λ) ]; } forward.invert = function(x, y) { var ρ0_y = F - y, ρ = d3_sgn(n) * Math.sqrt(x * x + ρ0_y * ρ0_y); return [ Math.atan2(x, ρ0_y) / n, 2 * Math.atan(Math.pow(F / ρ, 1 / n)) - halfπ ]; }; return forward; } (d3.geo.conicConformal = function() { return d3_geo_conic(d3_geo_conicConformal); }).raw = d3_geo_conicConformal; function d3_geo_conicEquidistant(φ0, φ1) { var cosφ0 = Math.cos(φ0), n = φ0 === φ1 ? Math.sin(φ0) : (cosφ0 - Math.cos(φ1)) / (φ1 - φ0), G = cosφ0 / n + φ0; if (abs(n) < ε) return d3_geo_equirectangular; function forward(λ, φ) { var ρ = G - φ; return [ ρ * Math.sin(n * λ), G - ρ * Math.cos(n * λ) ]; } forward.invert = function(x, y) { var ρ0_y = G - y; return [ Math.atan2(x, ρ0_y) / n, G - d3_sgn(n) * Math.sqrt(x * x + ρ0_y * ρ0_y) ]; }; return forward; } (d3.geo.conicEquidistant = function() { return d3_geo_conic(d3_geo_conicEquidistant); }).raw = d3_geo_conicEquidistant; var d3_geo_gnomonic = d3_geo_azimuthal(function(cosλcosφ) { return 1 / cosλcosφ; }, Math.atan); (d3.geo.gnomonic = function() { return d3_geo_projection(d3_geo_gnomonic); }).raw = d3_geo_gnomonic; function d3_geo_mercator(λ, φ) { return [ λ, Math.log(Math.tan(π / 4 + φ / 2)) ]; } d3_geo_mercator.invert = function(x, y) { return [ x, 2 * Math.atan(Math.exp(y)) - halfπ ]; }; function d3_geo_mercatorProjection(project) { var m = d3_geo_projection(project), scale = m.scale, translate = m.translate, clipExtent = m.clipExtent, clipAuto; m.scale = function() { var v = scale.apply(m, arguments); return v === m ? clipAuto ? m.clipExtent(null) : m : v; }; m.translate = function() { var v = translate.apply(m, arguments); return v === m ? clipAuto ? m.clipExtent(null) : m : v; }; m.clipExtent = function(_) { var v = clipExtent.apply(m, arguments); if (v === m) { if (clipAuto = _ == null) { var k = π * scale(), t = translate(); clipExtent([ [ t[0] - k, t[1] - k ], [ t[0] + k, t[1] + k ] ]); } } else if (clipAuto) { v = null; } return v; }; return m.clipExtent(null); } (d3.geo.mercator = function() { return d3_geo_mercatorProjection(d3_geo_mercator); }).raw = d3_geo_mercator; var d3_geo_orthographic = d3_geo_azimuthal(function() { return 1; }, Math.asin); (d3.geo.orthographic = function() { return d3_geo_projection(d3_geo_orthographic); }).raw = d3_geo_orthographic; var d3_geo_stereographic = d3_geo_azimuthal(function(cosλcosφ) { return 1 / (1 + cosλcosφ); }, function(ρ) { return 2 * Math.atan(ρ); }); (d3.geo.stereographic = function() { return d3_geo_projection(d3_geo_stereographic); }).raw = d3_geo_stereographic; function d3_geo_transverseMercator(λ, φ) { return [ Math.log(Math.tan(π / 4 + φ / 2)), -λ ]; } d3_geo_transverseMercator.invert = function(x, y) { return [ -y, 2 * Math.atan(Math.exp(x)) - halfπ ]; }; (d3.geo.transverseMercator = function() { var projection = d3_geo_mercatorProjection(d3_geo_transverseMercator), center = projection.center, rotate = projection.rotate; projection.center = function(_) { return _ ? center([ -_[1], _[0] ]) : (_ = center(), [ _[1], -_[0] ]); }; projection.rotate = function(_) { return _ ? rotate([ _[0], _[1], _.length > 2 ? _[2] + 90 : 90 ]) : (_ = rotate(), [ _[0], _[1], _[2] - 90 ]); }; return rotate([ 0, 0, 90 ]); }).raw = d3_geo_transverseMercator; d3.geom = {}; function d3_geom_pointX(d) { return d[0]; } function d3_geom_pointY(d) { return d[1]; } d3.geom.hull = function(vertices) { var x = d3_geom_pointX, y = d3_geom_pointY; if (arguments.length) return hull(vertices); function hull(data) { if (data.length < 3) return []; var fx = d3_functor(x), fy = d3_functor(y), i, n = data.length, points = [], flippedPoints = []; for (i = 0; i < n; i++) { points.push([ +fx.call(this, data[i], i), +fy.call(this, data[i], i), i ]); } points.sort(d3_geom_hullOrder); for (i = 0; i < n; i++) flippedPoints.push([ points[i][0], -points[i][1] ]); var upper = d3_geom_hullUpper(points), lower = d3_geom_hullUpper(flippedPoints); var skipLeft = lower[0] === upper[0], skipRight = lower[lower.length - 1] === upper[upper.length - 1], polygon = []; for (i = upper.length - 1; i >= 0; --i) polygon.push(data[points[upper[i]][2]]); for (i = +skipLeft; i < lower.length - skipRight; ++i) polygon.push(data[points[lower[i]][2]]); return polygon; } hull.x = function(_) { return arguments.length ? (x = _, hull) : x; }; hull.y = function(_) { return arguments.length ? (y = _, hull) : y; }; return hull; }; function d3_geom_hullUpper(points) { var n = points.length, hull = [ 0, 1 ], hs = 2; for (var i = 2; i < n; i++) { while (hs > 1 && d3_cross2d(points[hull[hs - 2]], points[hull[hs - 1]], points[i]) <= 0) --hs; hull[hs++] = i; } return hull.slice(0, hs); } function d3_geom_hullOrder(a, b) { return a[0] - b[0] || a[1] - b[1]; } d3.geom.polygon = function(coordinates) { d3_subclass(coordinates, d3_geom_polygonPrototype); return coordinates; }; var d3_geom_polygonPrototype = d3.geom.polygon.prototype = []; d3_geom_polygonPrototype.area = function() { var i = -1, n = this.length, a, b = this[n - 1], area = 0; while (++i < n) { a = b; b = this[i]; area += a[1] * b[0] - a[0] * b[1]; } return area * .5; }; d3_geom_polygonPrototype.centroid = function(k) { var i = -1, n = this.length, x = 0, y = 0, a, b = this[n - 1], c; if (!arguments.length) k = -1 / (6 * this.area()); while (++i < n) { a = b; b = this[i]; c = a[0] * b[1] - b[0] * a[1]; x += (a[0] + b[0]) * c; y += (a[1] + b[1]) * c; } return [ x * k, y * k ]; }; d3_geom_polygonPrototype.clip = function(subject) { 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; while (++i < n) { input = subject.slice(); subject.length = 0; b = this[i]; c = input[(m = input.length - closed) - 1]; j = -1; while (++j < m) { d = input[j]; if (d3_geom_polygonInside(d, a, b)) { if (!d3_geom_polygonInside(c, a, b)) { subject.push(d3_geom_polygonIntersect(c, d, a, b)); } subject.push(d); } else if (d3_geom_polygonInside(c, a, b)) { subject.push(d3_geom_polygonIntersect(c, d, a, b)); } c = d; } if (closed) subject.push(subject[0]); a = b; } return subject; }; function d3_geom_polygonInside(p, a, b) { return (b[0] - a[0]) * (p[1] - a[1]) < (b[1] - a[1]) * (p[0] - a[0]); } function d3_geom_polygonIntersect(c, d, a, b) { 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); return [ x1 + ua * x21, y1 + ua * y21 ]; } function d3_geom_polygonClosed(coordinates) { var a = coordinates[0], b = coordinates[coordinates.length - 1]; return !(a[0] - b[0] || a[1] - b[1]); } var d3_geom_voronoiEdges, d3_geom_voronoiCells, d3_geom_voronoiBeaches, d3_geom_voronoiBeachPool = [], d3_geom_voronoiFirstCircle, d3_geom_voronoiCircles, d3_geom_voronoiCirclePool = []; function d3_geom_voronoiBeach() { d3_geom_voronoiRedBlackNode(this); this.edge = this.site = this.circle = null; } function d3_geom_voronoiCreateBeach(site) { var beach = d3_geom_voronoiBeachPool.pop() || new d3_geom_voronoiBeach(); beach.site = site; return beach; } function d3_geom_voronoiDetachBeach(beach) { d3_geom_voronoiDetachCircle(beach); d3_geom_voronoiBeaches.remove(beach); d3_geom_voronoiBeachPool.push(beach); d3_geom_voronoiRedBlackNode(beach); } function d3_geom_voronoiRemoveBeach(beach) { var circle = beach.circle, x = circle.x, y = circle.cy, vertex = { x: x, y: y }, previous = beach.P, next = beach.N, disappearing = [ beach ]; d3_geom_voronoiDetachBeach(beach); var lArc = previous; while (lArc.circle && abs(x - lArc.circle.x) < ε && abs(y - lArc.circle.cy) < ε) { previous = lArc.P; disappearing.unshift(lArc); d3_geom_voronoiDetachBeach(lArc); lArc = previous; } disappearing.unshift(lArc); d3_geom_voronoiDetachCircle(lArc); var rArc = next; while (rArc.circle && abs(x - rArc.circle.x) < ε && abs(y - rArc.circle.cy) < ε) { next = rArc.N; disappearing.push(rArc); d3_geom_voronoiDetachBeach(rArc); rArc = next; } disappearing.push(rArc); d3_geom_voronoiDetachCircle(rArc); var nArcs = disappearing.length, iArc; for (iArc = 1; iArc < nArcs; ++iArc) { rArc = disappearing[iArc]; lArc = disappearing[iArc - 1]; d3_geom_voronoiSetEdgeEnd(rArc.edge, lArc.site, rArc.site, vertex); } lArc = disappearing[0]; rArc = disappearing[nArcs - 1]; rArc.edge = d3_geom_voronoiCreateEdge(lArc.site, rArc.site, null, vertex); d3_geom_voronoiAttachCircle(lArc); d3_geom_voronoiAttachCircle(rArc); } function d3_geom_voronoiAddBeach(site) { var x = site.x, directrix = site.y, lArc, rArc, dxl, dxr, node = d3_geom_voronoiBeaches._; while (node) { dxl = d3_geom_voronoiLeftBreakPoint(node, directrix) - x; if (dxl > ε) node = node.L; else { dxr = x - d3_geom_voronoiRightBreakPoint(node, directrix); if (dxr > ε) { if (!node.R) { lArc = node; break; } node = node.R; } else { if (dxl > -ε) { lArc = node.P; rArc = node; } else if (dxr > -ε) { lArc = node; rArc = node.N; } else { lArc = rArc = node; } break; } } } var newArc = d3_geom_voronoiCreateBeach(site); d3_geom_voronoiBeaches.insert(lArc, newArc); if (!lArc && !rArc) return; if (lArc === rArc) { d3_geom_voronoiDetachCircle(lArc); rArc = d3_geom_voronoiCreateBeach(lArc.site); d3_geom_voronoiBeaches.insert(newArc, rArc); newArc.edge = rArc.edge = d3_geom_voronoiCreateEdge(lArc.site, newArc.site); d3_geom_voronoiAttachCircle(lArc); d3_geom_voronoiAttachCircle(rArc); return; } if (!rArc) { newArc.edge = d3_geom_voronoiCreateEdge(lArc.site, newArc.site); return; } d3_geom_voronoiDetachCircle(lArc); d3_geom_voronoiDetachCircle(rArc); 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 = { x: (cy * hb - by * hc) / d + ax, y: (bx * hc - cx * hb) / d + ay }; d3_geom_voronoiSetEdgeEnd(rArc.edge, lSite, rSite, vertex); newArc.edge = d3_geom_voronoiCreateEdge(lSite, site, null, vertex); rArc.edge = d3_geom_voronoiCreateEdge(site, rSite, null, vertex); d3_geom_voronoiAttachCircle(lArc); d3_geom_voronoiAttachCircle(rArc); } function d3_geom_voronoiLeftBreakPoint(arc, directrix) { var site = arc.site, rfocx = site.x, rfocy = site.y, pby2 = rfocy - directrix; if (!pby2) return rfocx; var lArc = arc.P; if (!lArc) return -Infinity; site = lArc.site; var lfocx = site.x, lfocy = site.y, plby2 = lfocy - directrix; if (!plby2) return lfocx; var hl = lfocx - rfocx, aby2 = 1 / pby2 - 1 / plby2, b = hl / plby2; if (aby2) return (-b + Math.sqrt(b * b - 2 * aby2 * (hl * hl / (-2 * plby2) - lfocy + plby2 / 2 + rfocy - pby2 / 2))) / aby2 + rfocx; return (rfocx + lfocx) / 2; } function d3_geom_voronoiRightBreakPoint(arc, directrix) { var rArc = arc.N; if (rArc) return d3_geom_voronoiLeftBreakPoint(rArc, directrix); var site = arc.site; return site.y === directrix ? site.x : Infinity; } function d3_geom_voronoiCell(site) { this.site = site; this.edges = []; } d3_geom_voronoiCell.prototype.prepare = function() { var halfEdges = this.edges, iHalfEdge = halfEdges.length, edge; while (iHalfEdge--) { edge = halfEdges[iHalfEdge].edge; if (!edge.b || !edge.a) halfEdges.splice(iHalfEdge, 1); } halfEdges.sort(d3_geom_voronoiHalfEdgeOrder); return halfEdges.length; }; function d3_geom_voronoiCloseCells(extent) { 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; while (iCell--) { cell = cells[iCell]; if (!cell || !cell.prepare()) continue; halfEdges = cell.edges; nHalfEdges = halfEdges.length; iHalfEdge = 0; while (iHalfEdge < nHalfEdges) { end = halfEdges[iHalfEdge].end(), x3 = end.x, y3 = end.y; start = halfEdges[++iHalfEdge % nHalfEdges].start(), x2 = start.x, y2 = start.y; if (abs(x3 - x2) > ε || abs(y3 - y2) > ε) { halfEdges.splice(iHalfEdge, 0, new d3_geom_voronoiHalfEdge(d3_geom_voronoiCreateBorderEdge(cell.site, end, abs(x3 - x0) < ε && y1 - y3 > ε ? { x: x0, y: abs(x2 - x0) < ε ? y2 : y1 } : abs(y3 - y1) < ε && x1 - x3 > ε ? { x: abs(y2 - y1) < ε ? x2 : x1, y: y1 } : abs(x3 - x1) < ε && y3 - y0 > ε ? { x: x1, y: abs(x2 - x1) < ε ? y2 : y0 } : abs(y3 - y0) < ε && x3 - x0 > ε ? { x: abs(y2 - y0) < ε ? x2 : x0, y: y0 } : null), cell.site, null)); ++nHalfEdges; } } } } function d3_geom_voronoiHalfEdgeOrder(a, b) { return b.angle - a.angle; } function d3_geom_voronoiCircle() { d3_geom_voronoiRedBlackNode(this); this.x = this.y = this.arc = this.site = this.cy = null; } function d3_geom_voronoiAttachCircle(arc) { var lArc = arc.P, rArc = arc.N; if (!lArc || !rArc) return; var lSite = lArc.site, cSite = arc.site, rSite = rArc.site; if (lSite === rSite) return; var bx = cSite.x, by = cSite.y, ax = lSite.x - bx, ay = lSite.y - by, cx = rSite.x - bx, cy = rSite.y - by; var d = 2 * (ax * cy - ay * cx); if (d >= -ε2) return; 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; var circle = d3_geom_voronoiCirclePool.pop() || new d3_geom_voronoiCircle(); circle.arc = arc; circle.site = cSite; circle.x = x + bx; circle.y = cy + Math.sqrt(x * x + y * y); circle.cy = cy; arc.circle = circle; var before = null, node = d3_geom_voronoiCircles._; while (node) { if (circle.y < node.y || circle.y === node.y && circle.x <= node.x) { if (node.L) node = node.L; else { before = node.P; break; } } else { if (node.R) node = node.R; else { before = node; break; } } } d3_geom_voronoiCircles.insert(before, circle); if (!before) d3_geom_voronoiFirstCircle = circle; } function d3_geom_voronoiDetachCircle(arc) { var circle = arc.circle; if (circle) { if (!circle.P) d3_geom_voronoiFirstCircle = circle.N; d3_geom_voronoiCircles.remove(circle); d3_geom_voronoiCirclePool.push(circle); d3_geom_voronoiRedBlackNode(circle); arc.circle = null; } } function d3_geom_voronoiClipEdges(extent) { 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; while (i--) { e = edges[i]; if (!d3_geom_voronoiConnectEdge(e, extent) || !clip(e) || abs(e.a.x - e.b.x) < ε && abs(e.a.y - e.b.y) < ε) { e.a = e.b = null; edges.splice(i, 1); } } } function d3_geom_voronoiConnectEdge(edge, extent) { var vb = edge.b; if (vb) return true; 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; if (ry === ly) { if (fx < x0 || fx >= x1) return; if (lx > rx) { if (!va) va = { x: fx, y: y0 }; else if (va.y >= y1) return; vb = { x: fx, y: y1 }; } else { if (!va) va = { x: fx, y: y1 }; else if (va.y < y0) return; vb = { x: fx, y: y0 }; } } else { fm = (lx - rx) / (ry - ly); fb = fy - fm * fx; if (fm < -1 || fm > 1) { if (lx > rx) { if (!va) va = { x: (y0 - fb) / fm, y: y0 }; else if (va.y >= y1) return; vb = { x: (y1 - fb) / fm, y: y1 }; } else { if (!va) va = { x: (y1 - fb) / fm, y: y1 }; else if (va.y < y0) return; vb = { x: (y0 - fb) / fm, y: y0 }; } } else { if (ly < ry) { if (!va) va = { x: x0, y: fm * x0 + fb }; else if (va.x >= x1) return; vb = { x: x1, y: fm * x1 + fb }; } else { if (!va) va = { x: x1, y: fm * x1 + fb }; else if (va.x < x0) return; vb = { x: x0, y: fm * x0 + fb }; } } } edge.a = va; edge.b = vb; return true; } function d3_geom_voronoiEdge(lSite, rSite) { this.l = lSite; this.r = rSite; this.a = this.b = null; } function d3_geom_voronoiCreateEdge(lSite, rSite, va, vb) { var edge = new d3_geom_voronoiEdge(lSite, rSite); d3_geom_voronoiEdges.push(edge); if (va) d3_geom_voronoiSetEdgeEnd(edge, lSite, rSite, va); if (vb) d3_geom_voronoiSetEdgeEnd(edge, rSite, lSite, vb); d3_geom_voronoiCells[lSite.i].edges.push(new d3_geom_voronoiHalfEdge(edge, lSite, rSite)); d3_geom_voronoiCells[rSite.i].edges.push(new d3_geom_voronoiHalfEdge(edge, rSite, lSite)); return edge; } function d3_geom_voronoiCreateBorderEdge(lSite, va, vb) { var edge = new d3_geom_voronoiEdge(lSite, null); edge.a = va; edge.b = vb; d3_geom_voronoiEdges.push(edge); return edge; } function d3_geom_voronoiSetEdgeEnd(edge, lSite, rSite, vertex) { if (!edge.a && !edge.b) { edge.a = vertex; edge.l = lSite; edge.r = rSite; } else if (edge.l === rSite) { edge.b = vertex; } else { edge.a = vertex; } } function d3_geom_voronoiHalfEdge(edge, lSite, rSite) { var va = edge.a, vb = edge.b; this.edge = edge; this.site = lSite; 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); } d3_geom_voronoiHalfEdge.prototype = { start: function() { return this.edge.l === this.site ? this.edge.a : this.edge.b; }, end: function() { return this.edge.l === this.site ? this.edge.b : this.edge.a; } }; function d3_geom_voronoiRedBlackTree() { this._ = null; } function d3_geom_voronoiRedBlackNode(node) { node.U = node.C = node.L = node.R = node.P = node.N = null; } d3_geom_voronoiRedBlackTree.prototype = { insert: function(after, node) { var parent, grandpa, uncle; if (after) { node.P = after; node.N = after.N; if (after.N) after.N.P = node; after.N = node; if (after.R) { after = after.R; while (after.L) after = after.L; after.L = node; } else { after.R = node; } parent = after; } else if (this._) { after = d3_geom_voronoiRedBlackFirst(this._); node.P = null; node.N = after; after.P = after.L = node; parent = after; } else { node.P = node.N = null; this._ = node; parent = null; } node.L = node.R = null; node.U = parent; node.C = true; after = node; while (parent && parent.C) { grandpa = parent.U; if (parent === grandpa.L) { uncle = grandpa.R; if (uncle && uncle.C) { parent.C = uncle.C = false; grandpa.C = true; after = grandpa; } else { if (after === parent.R) { d3_geom_voronoiRedBlackRotateLeft(this, parent); after = parent; parent = after.U; } parent.C = false; grandpa.C = true; d3_geom_voronoiRedBlackRotateRight(this, grandpa); } } else { uncle = grandpa.L; if (uncle && uncle.C) { parent.C = uncle.C = false; grandpa.C = true; after = grandpa; } else { if (after === parent.L) { d3_geom_voronoiRedBlackRotateRight(this, parent); after = parent; parent = after.U; } parent.C = false; grandpa.C = true; d3_geom_voronoiRedBlackRotateLeft(this, grandpa); } } parent = after.U; } this._.C = false; }, remove: function(node) { if (node.N) node.N.P = node.P; if (node.P) node.P.N = node.N; node.N = node.P = null; var parent = node.U, sibling, left = node.L, right = node.R, next, red; if (!left) next = right; else if (!right) next = left; else next = d3_geom_voronoiRedBlackFirst(right); if (parent) { if (parent.L === node) parent.L = next; else parent.R = next; } else { this._ = next; } if (left && right) { red = next.C; next.C = node.C; next.L = left; left.U = next; if (next !== right) { parent = next.U; next.U = node.U; node = next.R; parent.L = node; next.R = right; right.U = next; } else { next.U = parent; parent = next; node = next.R; } } else { red = node.C; node = next; } if (node) node.U = parent; if (red) return; if (node && node.C) { node.C = false; return; } do { if (node === this._) break; if (node === parent.L) { sibling = parent.R; if (sibling.C) { sibling.C = false; parent.C = true; d3_geom_voronoiRedBlackRotateLeft(this, parent); sibling = parent.R; } if (sibling.L && sibling.L.C || sibling.R && sibling.R.C) { if (!sibling.R || !sibling.R.C) { sibling.L.C = false; sibling.C = true; d3_geom_voronoiRedBlackRotateRight(this, sibling); sibling = parent.R; } sibling.C = parent.C; parent.C = sibling.R.C = false; d3_geom_voronoiRedBlackRotateLeft(this, parent); node = this._; break; } } else { sibling = parent.L; if (sibling.C) { sibling.C = false; parent.C = true; d3_geom_voronoiRedBlackRotateRight(this, parent); sibling = parent.L; } if (sibling.L && sibling.L.C || sibling.R && sibling.R.C) { if (!sibling.L || !sibling.L.C) { sibling.R.C = false; sibling.C = true; d3_geom_voronoiRedBlackRotateLeft(this, sibling); sibling = parent.L; } sibling.C = parent.C; parent.C = sibling.L.C = false; d3_geom_voronoiRedBlackRotateRight(this, parent); node = this._; break; } } sibling.C = true; node = parent; parent = parent.U; } while (!node.C); if (node) node.C = false; } }; function d3_geom_voronoiRedBlackRotateLeft(tree, node) { var p = node, q = node.R, parent = p.U; if (parent) { if (parent.L === p) parent.L = q; else parent.R = q; } else { tree._ = q; } q.U = parent; p.U = q; p.R = q.L; if (p.R) p.R.U = p; q.L = p; } function d3_geom_voronoiRedBlackRotateRight(tree, node) { var p = node, q = node.L, parent = p.U; if (parent) { if (parent.L === p) parent.L = q; else parent.R = q; } else { tree._ = q; } q.U = parent; p.U = q; p.L = q.R; if (p.L) p.L.U = p; q.R = p; } function d3_geom_voronoiRedBlackFirst(node) { while (node.L) node = node.L; return node; } function d3_geom_voronoi(sites, bbox) { var site = sites.sort(d3_geom_voronoiVertexOrder).pop(), x0, y0, circle; d3_geom_voronoiEdges = []; d3_geom_voronoiCells = new Array(sites.length); d3_geom_voronoiBeaches = new d3_geom_voronoiRedBlackTree(); d3_geom_voronoiCircles = new d3_geom_voronoiRedBlackTree(); while (true) { circle = d3_geom_voronoiFirstCircle; if (site && (!circle || site.y < circle.y || site.y === circle.y && site.x < circle.x)) { if (site.x !== x0 || site.y !== y0) { d3_geom_voronoiCells[site.i] = new d3_geom_voronoiCell(site); d3_geom_voronoiAddBeach(site); x0 = site.x, y0 = site.y; } site = sites.pop(); } else if (circle) { d3_geom_voronoiRemoveBeach(circle.arc); } else { break; } } if (bbox) d3_geom_voronoiClipEdges(bbox), d3_geom_voronoiCloseCells(bbox); var diagram = { cells: d3_geom_voronoiCells, edges: d3_geom_voronoiEdges }; d3_geom_voronoiBeaches = d3_geom_voronoiCircles = d3_geom_voronoiEdges = d3_geom_voronoiCells = null; return diagram; } function d3_geom_voronoiVertexOrder(a, b) { return b.y - a.y || b.x - a.x; } d3.geom.voronoi = function(points) { var x = d3_geom_pointX, y = d3_geom_pointY, fx = x, fy = y, clipExtent = d3_geom_voronoiClipExtent; if (points) return voronoi(points); function voronoi(data) { var polygons = new Array(data.length), x0 = clipExtent[0][0], y0 = clipExtent[0][1], x1 = clipExtent[1][0], y1 = clipExtent[1][1]; d3_geom_voronoi(sites(data), clipExtent).cells.forEach(function(cell, i) { var edges = cell.edges, site = cell.site, polygon = polygons[i] = edges.length ? edges.map(function(e) { var s = e.start(); return [ s.x, s.y ]; }) : site.x >= x0 && site.x <= x1 && site.y >= y0 && site.y <= y1 ? [ [ x0, y1 ], [ x1, y1 ], [ x1, y0 ], [ x0, y0 ] ] : []; polygon.point = data[i]; }); return polygons; } function sites(data) { return data.map(function(d, i) { return { x: Math.round(fx(d, i) / ε) * ε, y: Math.round(fy(d, i) / ε) * ε, i: i }; }); } voronoi.links = function(data) { return d3_geom_voronoi(sites(data)).edges.filter(function(edge) { return edge.l && edge.r; }).map(function(edge) { return { source: data[edge.l.i], target: data[edge.r.i] }; }); }; voronoi.triangles = function(data) { var triangles = []; d3_geom_voronoi(sites(data)).cells.forEach(function(cell, i) { 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; while (++j < m) { e0 = e1; s0 = s1; e1 = edges[j].edge; s1 = e1.l === site ? e1.r : e1.l; if (i < s0.i && i < s1.i && d3_geom_voronoiTriangleArea(site, s0, s1) < 0) { triangles.push([ data[i], data[s0.i], data[s1.i] ]); } } }); return triangles; }; voronoi.x = function(_) { return arguments.length ? (fx = d3_functor(x = _), voronoi) : x; }; voronoi.y = function(_) { return arguments.length ? (fy = d3_functor(y = _), voronoi) : y; }; voronoi.clipExtent = function(_) { if (!arguments.length) return clipExtent === d3_geom_voronoiClipExtent ? null : clipExtent; clipExtent = _ == null ? d3_geom_voronoiClipExtent : _; return voronoi; }; voronoi.size = function(_) { if (!arguments.length) return clipExtent === d3_geom_voronoiClipExtent ? null : clipExtent && clipExtent[1]; return voronoi.clipExtent(_ && [ [ 0, 0 ], _ ]); }; return voronoi; }; var d3_geom_voronoiClipExtent = [ [ -1e6, -1e6 ], [ 1e6, 1e6 ] ]; function d3_geom_voronoiTriangleArea(a, b, c) { return (a.x - c.x) * (b.y - a.y) - (a.x - b.x) * (c.y - a.y); } d3.geom.delaunay = function(vertices) { return d3.geom.voronoi().triangles(vertices); }; d3.geom.quadtree = function(points, x1, y1, x2, y2) { var x = d3_geom_pointX, y = d3_geom_pointY, compat; if (compat = arguments.length) { x = d3_geom_quadtreeCompatX; y = d3_geom_quadtreeCompatY; if (compat === 3) { y2 = y1; x2 = x1; y1 = x1 = 0; } return quadtree(points); } function quadtree(data) { var d, fx = d3_functor(x), fy = d3_functor(y), xs, ys, i, n, x1_, y1_, x2_, y2_; if (x1 != null) { x1_ = x1, y1_ = y1, x2_ = x2, y2_ = y2; } else { x2_ = y2_ = -(x1_ = y1_ = Infinity); xs = [], ys = []; n = data.length; if (compat) for (i = 0; i < n; ++i) { d = data[i]; if (d.x < x1_) x1_ = d.x; if (d.y < y1_) y1_ = d.y; if (d.x > x2_) x2_ = d.x; if (d.y > y2_) y2_ = d.y; xs.push(d.x); ys.push(d.y); } else for (i = 0; i < n; ++i) { var x_ = +fx(d = data[i], i), y_ = +fy(d, i); if (x_ < x1_) x1_ = x_; if (y_ < y1_) y1_ = y_; if (x_ > x2_) x2_ = x_; if (y_ > y2_) y2_ = y_; xs.push(x_); ys.push(y_); } } var dx = x2_ - x1_, dy = y2_ - y1_; if (dx > dy) y2_ = y1_ + dx; else x2_ = x1_ + dy; function insert(n, d, x, y, x1, y1, x2, y2) { if (isNaN(x) || isNaN(y)) return; if (n.leaf) { var nx = n.x, ny = n.y; if (nx != null) { if (abs(nx - x) + abs(ny - y) < .01) { insertChild(n, d, x, y, x1, y1, x2, y2); } else { var nPoint = n.point; n.x = n.y = n.point = null; insertChild(n, nPoint, nx, ny, x1, y1, x2, y2); insertChild(n, d, x, y, x1, y1, x2, y2); } } else { n.x = x, n.y = y, n.point = d; } } else { insertChild(n, d, x, y, x1, y1, x2, y2); } } function insertChild(n, d, x, y, x1, y1, x2, y2) { var xm = (x1 + x2) * .5, ym = (y1 + y2) * .5, right = x >= xm, below = y >= ym, i = below << 1 | right; n.leaf = false; n = n.nodes[i] || (n.nodes[i] = d3_geom_quadtreeNode()); if (right) x1 = xm; else x2 = xm; if (below) y1 = ym; else y2 = ym; insert(n, d, x, y, x1, y1, x2, y2); } var root = d3_geom_quadtreeNode(); root.add = function(d) { insert(root, d, +fx(d, ++i), +fy(d, i), x1_, y1_, x2_, y2_); }; root.visit = function(f) { d3_geom_quadtreeVisit(f, root, x1_, y1_, x2_, y2_); }; root.find = function(point) { return d3_geom_quadtreeFind(root, point[0], point[1], x1_, y1_, x2_, y2_); }; i = -1; if (x1 == null) { while (++i < n) { insert(root, data[i], xs[i], ys[i], x1_, y1_, x2_, y2_); } --i; } else data.forEach(root.add); xs = ys = data = d = null; return root; } quadtree.x = function(_) { return arguments.length ? (x = _, quadtree) : x; }; quadtree.y = function(_) { return arguments.length ? (y = _, quadtree) : y; }; quadtree.extent = function(_) { if (!arguments.length) return x1 == null ? null : [ [ x1, y1 ], [ x2, y2 ] ]; if (_ == null) x1 = y1 = x2 = y2 = null; else x1 = +_[0][0], y1 = +_[0][1], x2 = +_[1][0], y2 = +_[1][1]; return quadtree; }; quadtree.size = function(_) { if (!arguments.length) return x1 == null ? null : [ x2 - x1, y2 - y1 ]; if (_ == null) x1 = y1 = x2 = y2 = null; else x1 = y1 = 0, x2 = +_[0], y2 = +_[1]; return quadtree; }; return quadtree; }; function d3_geom_quadtreeCompatX(d) { return d.x; } function d3_geom_quadtreeCompatY(d) { return d.y; } function d3_geom_quadtreeNode() { return { leaf: true, nodes: [], point: null, x: null, y: null }; } function d3_geom_quadtreeVisit(f, node, x1, y1, x2, y2) { if (!f(node, x1, y1, x2, y2)) { var sx = (x1 + x2) * .5, sy = (y1 + y2) * .5, children = node.nodes; if (children[0]) d3_geom_quadtreeVisit(f, children[0], x1, y1, sx, sy); if (children[1]) d3_geom_quadtreeVisit(f, children[1], sx, y1, x2, sy); if (children[2]) d3_geom_quadtreeVisit(f, children[2], x1, sy, sx, y2); if (children[3]) d3_geom_quadtreeVisit(f, children[3], sx, sy, x2, y2); } } function d3_geom_quadtreeFind(root, x, y, x0, y0, x3, y3) { var minDistance2 = Infinity, closestPoint; (function find(node, x1, y1, x2, y2) { if (x1 > x3 || y1 > y3 || x2 < x0 || y2 < y0) return; if (point = node.point) { var point, dx = x - node.x, dy = y - node.y, distance2 = dx * dx + dy * dy; if (distance2 < minDistance2) { var distance = Math.sqrt(minDistance2 = distance2); x0 = x - distance, y0 = y - distance; x3 = x + distance, y3 = y + distance; closestPoint = point; } } var children = node.nodes, xm = (x1 + x2) * .5, ym = (y1 + y2) * .5, right = x >= xm, below = y >= ym; for (var i = below << 1 | right, j = i + 4; i < j; ++i) { if (node = children[i & 3]) switch (i & 3) { case 0: find(node, x1, y1, xm, ym); break; case 1: find(node, xm, y1, x2, ym); break; case 2: find(node, x1, ym, xm, y2); break; case 3: find(node, xm, ym, x2, y2); break; } } })(root, x0, y0, x3, y3); return closestPoint; } d3.interpolateRgb = d3_interpolateRgb; function d3_interpolateRgb(a, b) { a = d3.rgb(a); b = d3.rgb(b); var ar = a.r, ag = a.g, ab = a.b, br = b.r - ar, bg = b.g - ag, bb = b.b - ab; return function(t) { 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)); }; } d3.interpolateObject = d3_interpolateObject; function d3_interpolateObject(a, b) { var i = {}, c = {}, k; for (k in a) { if (k in b) { i[k] = d3_interpolate(a[k], b[k]); } else { c[k] = a[k]; } } for (k in b) { if (!(k in a)) { c[k] = b[k]; } } return function(t) { for (k in i) c[k] = i[k](t); return c; }; } d3.interpolateNumber = d3_interpolateNumber; function d3_interpolateNumber(a, b) { a = +a, b = +b; return function(t) { return a * (1 - t) + b * t; }; } d3.interpolateString = d3_interpolateString; function d3_interpolateString(a, b) { var bi = d3_interpolate_numberA.lastIndex = d3_interpolate_numberB.lastIndex = 0, am, bm, bs, i = -1, s = [], q = []; a = a + "", b = b + ""; while ((am = d3_interpolate_numberA.exec(a)) && (bm = d3_interpolate_numberB.exec(b))) { if ((bs = bm.index) > bi) { bs = b.slice(bi, bs); if (s[i]) s[i] += bs; else s[++i] = bs; } if ((am = am[0]) === (bm = bm[0])) { if (s[i]) s[i] += bm; else s[++i] = bm; } else { s[++i] = null; q.push({ i: i, x: d3_interpolateNumber(am, bm) }); } bi = d3_interpolate_numberB.lastIndex; } if (bi < b.length) { bs = b.slice(bi); if (s[i]) s[i] += bs; else s[++i] = bs; } return s.length < 2 ? q[0] ? (b = q[0].x, function(t) { return b(t) + ""; }) : function() { return b; } : (b = q.length, function(t) { for (var i = 0, o; i < b; ++i) s[(o = q[i]).i] = o.x(t); return s.join(""); }); } var d3_interpolate_numberA = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g, d3_interpolate_numberB = new RegExp(d3_interpolate_numberA.source, "g"); d3.interpolate = d3_interpolate; function d3_interpolate(a, b) { var i = d3.interpolators.length, f; while (--i >= 0 && !(f = d3.interpolators[i](a, b))) ; return f; } d3.interpolators = [ function(a, b) { var t = typeof b; 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); } ]; d3.interpolateArray = d3_interpolateArray; function d3_interpolateArray(a, b) { var x = [], c = [], na = a.length, nb = b.length, n0 = Math.min(a.length, b.length), i; for (i = 0; i < n0; ++i) x.push(d3_interpolate(a[i], b[i])); for (;i < na; ++i) c[i] = a[i]; for (;i < nb; ++i) c[i] = b[i]; return function(t) { for (i = 0; i < n0; ++i) c[i] = x[i](t); return c; }; } var d3_ease_default = function() { return d3_identity; }; var d3_ease = d3.map({ linear: d3_ease_default, poly: d3_ease_poly, quad: function() { return d3_ease_quad; }, cubic: function() { return d3_ease_cubic; }, sin: function() { return d3_ease_sin; }, exp: function() { return d3_ease_exp; }, circle: function() { return d3_ease_circle; }, elastic: d3_ease_elastic, back: d3_ease_back, bounce: function() { return d3_ease_bounce; } }); var d3_ease_mode = d3.map({ "in": d3_identity, out: d3_ease_reverse, "in-out": d3_ease_reflect, "out-in": function(f) { return d3_ease_reflect(d3_ease_reverse(f)); } }); d3.ease = function(name) { var i = name.indexOf("-"), t = i >= 0 ? name.slice(0, i) : name, m = i >= 0 ? name.slice(i + 1) : "in"; t = d3_ease.get(t) || d3_ease_default; m = d3_ease_mode.get(m) || d3_identity; return d3_ease_clamp(m(t.apply(null, d3_arraySlice.call(arguments, 1)))); }; function d3_ease_clamp(f) { return function(t) { return t <= 0 ? 0 : t >= 1 ? 1 : f(t); }; } function d3_ease_reverse(f) { return function(t) { return 1 - f(1 - t); }; } function d3_ease_reflect(f) { return function(t) { return .5 * (t < .5 ? f(2 * t) : 2 - f(2 - 2 * t)); }; } function d3_ease_quad(t) { return t * t; } function d3_ease_cubic(t) { return t * t * t; } function d3_ease_cubicInOut(t) { if (t <= 0) return 0; if (t >= 1) return 1; var t2 = t * t, t3 = t2 * t; return 4 * (t < .5 ? t3 : 3 * (t - t2) + t3 - .75); } function d3_ease_poly(e) { return function(t) { return Math.pow(t, e); }; } function d3_ease_sin(t) { return 1 - Math.cos(t * halfπ); } function d3_ease_exp(t) { return Math.pow(2, 10 * (t - 1)); } function d3_ease_circle(t) { return 1 - Math.sqrt(1 - t * t); } function d3_ease_elastic(a, p) { var s; if (arguments.length < 2) p = .45; if (arguments.length) s = p / τ * Math.asin(1 / a); else a = 1, s = p / 4; return function(t) { return 1 + a * Math.pow(2, -10 * t) * Math.sin((t - s) * τ / p); }; } function d3_ease_back(s) { if (!s) s = 1.70158; return function(t) { return t * t * ((s + 1) * t - s); }; } function d3_ease_bounce(t) { 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; } d3.interpolateHcl = d3_interpolateHcl; function d3_interpolateHcl(a, b) { a = d3.hcl(a); b = d3.hcl(b); var ah = a.h, ac = a.c, al = a.l, bh = b.h - ah, bc = b.c - ac, bl = b.l - al; if (isNaN(bc)) bc = 0, ac = isNaN(ac) ? b.c : ac; if (isNaN(bh)) bh = 0, ah = isNaN(ah) ? b.h : ah; else if (bh > 180) bh -= 360; else if (bh < -180) bh += 360; return function(t) { return d3_hcl_lab(ah + bh * t, ac + bc * t, al + bl * t) + ""; }; } d3.interpolateHsl = d3_interpolateHsl; function d3_interpolateHsl(a, b) { a = d3.hsl(a); b = d3.hsl(b); var ah = a.h, as = a.s, al = a.l, bh = b.h - ah, bs = b.s - as, bl = b.l - al; if (isNaN(bs)) bs = 0, as = isNaN(as) ? b.s : as; if (isNaN(bh)) bh = 0, ah = isNaN(ah) ? b.h : ah; else if (bh > 180) bh -= 360; else if (bh < -180) bh += 360; return function(t) { return d3_hsl_rgb(ah + bh * t, as + bs * t, al + bl * t) + ""; }; } d3.interpolateLab = d3_interpolateLab; function d3_interpolateLab(a, b) { a = d3.lab(a); b = d3.lab(b); var al = a.l, aa = a.a, ab = a.b, bl = b.l - al, ba = b.a - aa, bb = b.b - ab; return function(t) { return d3_lab_rgb(al + bl * t, aa + ba * t, ab + bb * t) + ""; }; } d3.interpolateRound = d3_interpolateRound; function d3_interpolateRound(a, b) { b -= a; return function(t) { return Math.round(a + b * t); }; } d3.transform = function(string) { var g = d3_document.createElementNS(d3.ns.prefix.svg, "g"); return (d3.transform = function(string) { if (string != null) { g.setAttribute("transform", string); var t = g.transform.baseVal.consolidate(); } return new d3_transform(t ? t.matrix : d3_transformIdentity); })(string); }; function d3_transform(m) { 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; if (r0[0] * r1[1] < r1[0] * r0[1]) { r0[0] *= -1; r0[1] *= -1; kx *= -1; kz *= -1; } this.rotate = (kx ? Math.atan2(r0[1], r0[0]) : Math.atan2(-r1[0], r1[1])) * d3_degrees; this.translate = [ m.e, m.f ]; this.scale = [ kx, ky ]; this.skew = ky ? Math.atan2(kz, ky) * d3_degrees : 0; } d3_transform.prototype.toString = function() { return "translate(" + this.translate + ")rotate(" + this.rotate + ")skewX(" + this.skew + ")scale(" + this.scale + ")"; }; function d3_transformDot(a, b) { return a[0] * b[0] + a[1] * b[1]; } function d3_transformNormalize(a) { var k = Math.sqrt(d3_transformDot(a, a)); if (k) { a[0] /= k; a[1] /= k; } return k; } function d3_transformCombine(a, b, k) { a[0] += k * b[0]; a[1] += k * b[1]; return a; } var d3_transformIdentity = { a: 1, b: 0, c: 0, d: 1, e: 0, f: 0 }; d3.interpolateTransform = d3_interpolateTransform; function d3_interpolateTransformPop(s) { return s.length ? s.pop() + "," : ""; } function d3_interpolateTranslate(ta, tb, s, q) { if (ta[0] !== tb[0] || ta[1] !== tb[1]) { var i = s.push("translate(", null, ",", null, ")"); q.push({ i: i - 4, x: d3_interpolateNumber(ta[0], tb[0]) }, { i: i - 2, x: d3_interpolateNumber(ta[1], tb[1]) }); } else if (tb[0] || tb[1]) { s.push("translate(" + tb + ")"); } } function d3_interpolateRotate(ra, rb, s, q) { if (ra !== rb) { if (ra - rb > 180) rb += 360; else if (rb - ra > 180) ra += 360; q.push({ i: s.push(d3_interpolateTransformPop(s) + "rotate(", null, ")") - 2, x: d3_interpolateNumber(ra, rb) }); } else if (rb) { s.push(d3_interpolateTransformPop(s) + "rotate(" + rb + ")"); } } function d3_interpolateSkew(wa, wb, s, q) { if (wa !== wb) { q.push({ i: s.push(d3_interpolateTransformPop(s) + "skewX(", null, ")") - 2, x: d3_interpolateNumber(wa, wb) }); } else if (wb) { s.push(d3_interpolateTransformPop(s) + "skewX(" + wb + ")"); } } function d3_interpolateScale(ka, kb, s, q) { if (ka[0] !== kb[0] || ka[1] !== kb[1]) { var i = s.push(d3_interpolateTransformPop(s) + "scale(", null, ",", null, ")"); q.push({ i: i - 4, x: d3_interpolateNumber(ka[0], kb[0]) }, { i: i - 2, x: d3_interpolateNumber(ka[1], kb[1]) }); } else if (kb[0] !== 1 || kb[1] !== 1) { s.push(d3_interpolateTransformPop(s) + "scale(" + kb + ")"); } } function d3_interpolateTransform(a, b) { var s = [], q = []; a = d3.transform(a), b = d3.transform(b); d3_interpolateTranslate(a.translate, b.translate, s, q); d3_interpolateRotate(a.rotate, b.rotate, s, q); d3_interpolateSkew(a.skew, b.skew, s, q); d3_interpolateScale(a.scale, b.scale, s, q); a = b = null; return function(t) { var i = -1, n = q.length, o; while (++i < n) s[(o = q[i]).i] = o.x(t); return s.join(""); }; } function d3_uninterpolateNumber(a, b) { b = (b -= a = +a) || 1 / b; return function(x) { return (x - a) / b; }; } function d3_uninterpolateClamp(a, b) { b = (b -= a = +a) || 1 / b; return function(x) { return Math.max(0, Math.min(1, (x - a) / b)); }; } d3.layout = {}; d3.layout.bundle = function() { return function(links) { var paths = [], i = -1, n = links.length; while (++i < n) paths.push(d3_layout_bundlePath(links[i])); return paths; }; }; function d3_layout_bundlePath(link) { var start = link.source, end = link.target, lca = d3_layout_bundleLeastCommonAncestor(start, end), points = [ start ]; while (start !== lca) { start = start.parent; points.push(start); } var k = points.length; while (end !== lca) { points.splice(k, 0, end); end = end.parent; } return points; } function d3_layout_bundleAncestors(node) { var ancestors = [], parent = node.parent; while (parent != null) { ancestors.push(node); node = parent; parent = parent.parent; } ancestors.push(node); return ancestors; } function d3_layout_bundleLeastCommonAncestor(a, b) { if (a === b) return a; var aNodes = d3_layout_bundleAncestors(a), bNodes = d3_layout_bundleAncestors(b), aNode = aNodes.pop(), bNode = bNodes.pop(), sharedNode = null; while (aNode === bNode) { sharedNode = aNode; aNode = aNodes.pop(); bNode = bNodes.pop(); } return sharedNode; } d3.layout.chord = function() { var chord = {}, chords, groups, matrix, n, padding = 0, sortGroups, sortSubgroups, sortChords; function relayout() { var subgroups = {}, groupSums = [], groupIndex = d3.range(n), subgroupIndex = [], k, x, x0, i, j; chords = []; groups = []; k = 0, i = -1; while (++i < n) { x = 0, j = -1; while (++j < n) { x += matrix[i][j]; } groupSums.push(x); subgroupIndex.push(d3.range(n)); k += x; } if (sortGroups) { groupIndex.sort(function(a, b) { return sortGroups(groupSums[a], groupSums[b]); }); } if (sortSubgroups) { subgroupIndex.forEach(function(d, i) { d.sort(function(a, b) { return sortSubgroups(matrix[i][a], matrix[i][b]); }); }); } k = (τ - padding * n) / k; x = 0, i = -1; while (++i < n) { x0 = x, j = -1; while (++j < n) { var di = groupIndex[i], dj = subgroupIndex[di][j], v = matrix[di][dj], a0 = x, a1 = x += v * k; subgroups[di + "-" + dj] = { index: di, subindex: dj, startAngle: a0, endAngle: a1, value: v }; } groups[di] = { index: di, startAngle: x0, endAngle: x, value: groupSums[di] }; x += padding; } i = -1; while (++i < n) { j = i - 1; while (++j < n) { var source = subgroups[i + "-" + j], target = subgroups[j + "-" + i]; if (source.value || target.value) { chords.push(source.value < target.value ? { source: target, target: source } : { source: source, target: target }); } } } if (sortChords) resort(); } function resort() { chords.sort(function(a, b) { return sortChords((a.source.value + a.target.value) / 2, (b.source.value + b.target.value) / 2); }); } chord.matrix = function(x) { if (!arguments.length) return matrix; n = (matrix = x) && matrix.length; chords = groups = null; return chord; }; chord.padding = function(x) { if (!arguments.length) return padding; padding = x; chords = groups = null; return chord; }; chord.sortGroups = function(x) { if (!arguments.length) return sortGroups; sortGroups = x; chords = groups = null; return chord; }; chord.sortSubgroups = function(x) { if (!arguments.length) return sortSubgroups; sortSubgroups = x; chords = null; return chord; }; chord.sortChords = function(x) { if (!arguments.length) return sortChords; sortChords = x; if (chords) resort(); return chord; }; chord.chords = function() { if (!chords) relayout(); return chords; }; chord.groups = function() { if (!groups) relayout(); return groups; }; return chord; }; d3.layout.force = function() { 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; function repulse(node) { return function(quad, x1, _, x2) { if (quad.point !== node) { var dx = quad.cx - node.x, dy = quad.cy - node.y, dw = x2 - x1, dn = dx * dx + dy * dy; if (dw * dw / theta2 < dn) { if (dn < chargeDistance2) { var k = quad.charge / dn; node.px -= dx * k; node.py -= dy * k; } return true; } if (quad.point && dn && dn < chargeDistance2) { var k = quad.pointCharge / dn; node.px -= dx * k; node.py -= dy * k; } } return !quad.charge; }; } force.tick = function() { if ((alpha *= .99) < .005) { timer = null; event.end({ type: "end", alpha: alpha = 0 }); return true; } var n = nodes.length, m = links.length, q, i, o, s, t, l, k, x, y; for (i = 0; i < m; ++i) { o = links[i]; s = o.source; t = o.target; x = t.x - s.x; y = t.y - s.y; if (l = x * x + y * y) { l = alpha * strengths[i] * ((l = Math.sqrt(l)) - distances[i]) / l; x *= l; y *= l; t.x -= x * (k = s.weight + t.weight ? s.weight / (s.weight + t.weight) : .5); t.y -= y * k; s.x += x * (k = 1 - k); s.y += y * k; } } if (k = alpha * gravity) { x = size[0] / 2; y = size[1] / 2; i = -1; if (k) while (++i < n) { o = nodes[i]; o.x += (x - o.x) * k; o.y += (y - o.y) * k; } } if (charge) { d3_layout_forceAccumulate(q = d3.geom.quadtree(nodes), alpha, charges); i = -1; while (++i < n) { if (!(o = nodes[i]).fixed) { q.visit(repulse(o)); } } } i = -1; while (++i < n) { o = nodes[i]; if (o.fixed) { o.x = o.px; o.y = o.py; } else { o.x -= (o.px - (o.px = o.x)) * friction; o.y -= (o.py - (o.py = o.y)) * friction; } } event.tick({ type: "tick", alpha: alpha }); }; force.nodes = function(x) { if (!arguments.length) return nodes; nodes = x; return force; }; force.links = function(x) { if (!arguments.length) return links; links = x; return force; }; force.size = function(x) { if (!arguments.length) return size; size = x; return force; }; force.linkDistance = function(x) { if (!arguments.length) return linkDistance; linkDistance = typeof x === "function" ? x : +x; return force; }; force.distance = force.linkDistance; force.linkStrength = function(x) { if (!arguments.length) return linkStrength; linkStrength = typeof x === "function" ? x : +x; return force; }; force.friction = function(x) { if (!arguments.length) return friction; friction = +x; return force; }; force.charge = function(x) { if (!arguments.length) return charge; charge = typeof x === "function" ? x : +x; return force; }; force.chargeDistance = function(x) { if (!arguments.length) return Math.sqrt(chargeDistance2); chargeDistance2 = x * x; return force; }; force.gravity = function(x) { if (!arguments.length) return gravity; gravity = +x; return force; }; force.theta = function(x) { if (!arguments.length) return Math.sqrt(theta2); theta2 = x * x; return force; }; force.alpha = function(x) { if (!arguments.length) return alpha; x = +x; if (alpha) { if (x > 0) { alpha = x; } else { timer.c = null, timer.t = NaN, timer = null; event.end({ type: "end", alpha: alpha = 0 }); } } else if (x > 0) { event.start({ type: "start", alpha: alpha = x }); timer = d3_timer(force.tick); } return force; }; force.start = function() { var i, n = nodes.length, m = links.length, w = size[0], h = size[1], neighbors, o; for (i = 0; i < n; ++i) { (o = nodes[i]).index = i; o.weight = 0; } for (i = 0; i < m; ++i) { o = links[i]; if (typeof o.source == "number") o.source = nodes[o.source]; if (typeof o.target == "number") o.target = nodes[o.target]; ++o.source.weight; ++o.target.weight; } for (i = 0; i < n; ++i) { o = nodes[i]; if (isNaN(o.x)) o.x = position("x", w); if (isNaN(o.y)) o.y = position("y", h); if (isNaN(o.px)) o.px = o.x; if (isNaN(o.py)) o.py = o.y; } distances = []; 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; strengths = []; 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; charges = []; 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; function position(dimension, size) { if (!neighbors) { neighbors = new Array(n); for (j = 0; j < n; ++j) { neighbors[j] = []; } for (j = 0; j < m; ++j) { var o = links[j]; neighbors[o.source.index].push(o.target); neighbors[o.target.index].push(o.source); } } var candidates = neighbors[i], j = -1, l = candidates.length, x; while (++j < l) if (!isNaN(x = candidates[j][dimension])) return x; return Math.random() * size; } return force.resume(); }; force.resume = function() { return force.alpha(.1); }; force.stop = function() { return force.alpha(0); }; force.drag = function() { 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); if (!arguments.length) return drag; this.on("mouseover.force", d3_layout_forceMouseover).on("mouseout.force", d3_layout_forceMouseout).call(drag); }; function dragmove(d) { d.px = d3.event.x, d.py = d3.event.y; force.resume(); } return d3.rebind(force, event, "on"); }; function d3_layout_forceDragstart(d) { d.fixed |= 2; } function d3_layout_forceDragend(d) { d.fixed &= ~6; } function d3_layout_forceMouseover(d) { d.fixed |= 4; d.px = d.x, d.py = d.y; } function d3_layout_forceMouseout(d) { d.fixed &= ~4; } function d3_layout_forceAccumulate(quad, alpha, charges) { var cx = 0, cy = 0; quad.charge = 0; if (!quad.leaf) { var nodes = quad.nodes, n = nodes.length, i = -1, c; while (++i < n) { c = nodes[i]; if (c == null) continue; d3_layout_forceAccumulate(c, alpha, charges); quad.charge += c.charge; cx += c.charge * c.cx; cy += c.charge * c.cy; } } if (quad.point) { if (!quad.leaf) { quad.point.x += Math.random() - .5; quad.point.y += Math.random() - .5; } var k = alpha * charges[quad.point.index]; quad.charge += quad.pointCharge = k; cx += k * quad.point.x; cy += k * quad.point.y; } quad.cx = cx / quad.charge; quad.cy = cy / quad.charge; } var d3_layout_forceLinkDistance = 20, d3_layout_forceLinkStrength = 1, d3_layout_forceChargeDistance2 = Infinity; d3.layout.hierarchy = function() { var sort = d3_layout_hierarchySort, children = d3_layout_hierarchyChildren, value = d3_layout_hierarchyValue; function hierarchy(root) { var stack = [ root ], nodes = [], node; root.depth = 0; while ((node = stack.pop()) != null) { nodes.push(node); if ((childs = children.call(hierarchy, node, node.depth)) && (n = childs.length)) { var n, childs, child; while (--n >= 0) { stack.push(child = childs[n]); child.parent = node; child.depth = node.depth + 1; } if (value) node.value = 0; node.children = childs; } else { if (value) node.value = +value.call(hierarchy, node, node.depth) || 0; delete node.children; } } d3_layout_hierarchyVisitAfter(root, function(node) { var childs, parent; if (sort && (childs = node.children)) childs.sort(sort); if (value && (parent = node.parent)) parent.value += node.value; }); return nodes; } hierarchy.sort = function(x) { if (!arguments.length) return sort; sort = x; return hierarchy; }; hierarchy.children = function(x) { if (!arguments.length) return children; children = x; return hierarchy; }; hierarchy.value = function(x) { if (!arguments.length) return value; value = x; return hierarchy; }; hierarchy.revalue = function(root) { if (value) { d3_layout_hierarchyVisitBefore(root, function(node) { if (node.children) node.value = 0; }); d3_layout_hierarchyVisitAfter(root, function(node) { var parent; if (!node.children) node.value = +value.call(hierarchy, node, node.depth) || 0; if (parent = node.parent) parent.value += node.value; }); } return root; }; return hierarchy; }; function d3_layout_hierarchyRebind(object, hierarchy) { d3.rebind(object, hierarchy, "sort", "children", "value"); object.nodes = object; object.links = d3_layout_hierarchyLinks; return object; } function d3_layout_hierarchyVisitBefore(node, callback) { var nodes = [ node ]; while ((node = nodes.pop()) != null) { callback(node); if ((children = node.children) && (n = children.length)) { var n, children; while (--n >= 0) nodes.push(children[n]); } } } function d3_layout_hierarchyVisitAfter(node, callback) { var nodes = [ node ], nodes2 = []; while ((node = nodes.pop()) != null) { nodes2.push(node); if ((children = node.children) && (n = children.length)) { var i = -1, n, children; while (++i < n) nodes.push(children[i]); } } while ((node = nodes2.pop()) != null) { callback(node); } } function d3_layout_hierarchyChildren(d) { return d.children; } function d3_layout_hierarchyValue(d) { return d.value; } function d3_layout_hierarchySort(a, b) { return b.value - a.value; } function d3_layout_hierarchyLinks(nodes) { return d3.merge(nodes.map(function(parent) { return (parent.children || []).map(function(child) { return { source: parent, target: child }; }); })); } d3.layout.partition = function() { var hierarchy = d3.layout.hierarchy(), size = [ 1, 1 ]; function position(node, x, dx, dy) { var children = node.children; node.x = x; node.y = node.depth * dy; node.dx = dx; node.dy = dy; if (children && (n = children.length)) { var i = -1, n, c, d; dx = node.value ? dx / node.value : 0; while (++i < n) { position(c = children[i], x, d = c.value * dx, dy); x += d; } } } function depth(node) { var children = node.children, d = 0; if (children && (n = children.length)) { var i = -1, n; while (++i < n) d = Math.max(d, depth(children[i])); } return 1 + d; } function partition(d, i) { var nodes = hierarchy.call(this, d, i); position(nodes[0], 0, size[0], size[1] / depth(nodes[0])); return nodes; } partition.size = function(x) { if (!arguments.length) return size; size = x; return partition; }; return d3_layout_hierarchyRebind(partition, hierarchy); }; d3.layout.pie = function() { var value = Number, sort = d3_layout_pieSortByValue, startAngle = 0, endAngle = τ, padAngle = 0; function pie(data) { var n = data.length, values = data.map(function(d, i) { return +value.call(pie, d, i); }), 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; if (sort != null) index.sort(sort === d3_layout_pieSortByValue ? function(i, j) { return values[j] - values[i]; } : function(i, j) { return sort(data[i], data[j]); }); index.forEach(function(i) { arcs[i] = { data: data[i], value: v = values[i], startAngle: a, endAngle: a += v * k + pa, padAngle: p }; }); return arcs; } pie.value = function(_) { if (!arguments.length) return value; value = _; return pie; }; pie.sort = function(_) { if (!arguments.length) return sort; sort = _; return pie; }; pie.startAngle = function(_) { if (!arguments.length) return startAngle; startAngle = _; return pie; }; pie.endAngle = function(_) { if (!arguments.length) return endAngle; endAngle = _; return pie; }; pie.padAngle = function(_) { if (!arguments.length) return padAngle; padAngle = _; return pie; }; return pie; }; var d3_layout_pieSortByValue = {}; d3.layout.stack = function() { var values = d3_identity, order = d3_layout_stackOrderDefault, offset = d3_layout_stackOffsetZero, out = d3_layout_stackOut, x = d3_layout_stackX, y = d3_layout_stackY; function stack(data, index) { if (!(n = data.length)) return data; var series = data.map(function(d, i) { return values.call(stack, d, i); }); var points = series.map(function(d) { return d.map(function(v, i) { return [ x.call(stack, v, i), y.call(stack, v, i) ]; }); }); var orders = order.call(stack, points, index); series = d3.permute(series, orders); points = d3.permute(points, orders); var offsets = offset.call(stack, points, index); var m = series[0].length, n, i, j, o; for (j = 0; j < m; ++j) { out.call(stack, series[0][j], o = offsets[j], points[0][j][1]); for (i = 1; i < n; ++i) { out.call(stack, series[i][j], o += points[i - 1][j][1], points[i][j][1]); } } return data; } stack.values = function(x) { if (!arguments.length) return values; values = x; return stack; }; stack.order = function(x) { if (!arguments.length) return order; order = typeof x === "function" ? x : d3_layout_stackOrders.get(x) || d3_layout_stackOrderDefault; return stack; }; stack.offset = function(x) { if (!arguments.length) return offset; offset = typeof x === "function" ? x : d3_layout_stackOffsets.get(x) || d3_layout_stackOffsetZero; return stack; }; stack.x = function(z) { if (!arguments.length) return x; x = z; return stack; }; stack.y = function(z) { if (!arguments.length) return y; y = z; return stack; }; stack.out = function(z) { if (!arguments.length) return out; out = z; return stack; }; return stack; }; function d3_layout_stackX(d) { return d.x; } function d3_layout_stackY(d) { return d.y; } function d3_layout_stackOut(d, y0, y) { d.y0 = y0; d.y = y; } var d3_layout_stackOrders = d3.map({ "inside-out": function(data) { 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) { return max[a] - max[b]; }), top = 0, bottom = 0, tops = [], bottoms = []; for (i = 0; i < n; ++i) { j = index[i]; if (top < bottom) { top += sums[j]; tops.push(j); } else { bottom += sums[j]; bottoms.push(j); } } return bottoms.reverse().concat(tops); }, reverse: function(data) { return d3.range(data.length).reverse(); }, "default": d3_layout_stackOrderDefault }); var d3_layout_stackOffsets = d3.map({ silhouette: function(data) { var n = data.length, m = data[0].length, sums = [], max = 0, i, j, o, y0 = []; for (j = 0; j < m; ++j) { for (i = 0, o = 0; i < n; i++) o += data[i][j][1]; if (o > max) max = o; sums.push(o); } for (j = 0; j < m; ++j) { y0[j] = (max - sums[j]) / 2; } return y0; }, wiggle: function(data) { var n = data.length, x = data[0], m = x.length, i, j, k, s1, s2, s3, dx, o, o0, y0 = []; y0[0] = o = o0 = 0; for (j = 1; j < m; ++j) { for (i = 0, s1 = 0; i < n; ++i) s1 += data[i][j][1]; for (i = 0, s2 = 0, dx = x[j][0] - x[j - 1][0]; i < n; ++i) { for (k = 0, s3 = (data[i][j][1] - data[i][j - 1][1]) / (2 * dx); k < i; ++k) { s3 += (data[k][j][1] - data[k][j - 1][1]) / dx; } s2 += s3 * data[i][j][1]; } y0[j] = o -= s1 ? s2 / s1 * dx : 0; if (o < o0) o0 = o; } for (j = 0; j < m; ++j) y0[j] -= o0; return y0; }, expand: function(data) { var n = data.length, m = data[0].length, k = 1 / n, i, j, o, y0 = []; for (j = 0; j < m; ++j) { for (i = 0, o = 0; i < n; i++) o += data[i][j][1]; 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; } for (j = 0; j < m; ++j) y0[j] = 0; return y0; }, zero: d3_layout_stackOffsetZero }); function d3_layout_stackOrderDefault(data) { return d3.range(data.length); } function d3_layout_stackOffsetZero(data) { var j = -1, m = data[0].length, y0 = []; while (++j < m) y0[j] = 0; return y0; } function d3_layout_stackMaxIndex(array) { var i = 1, j = 0, v = array[0][1], k, n = array.length; for (;i < n; ++i) { if ((k = array[i][1]) > v) { j = i; v = k; } } return j; } function d3_layout_stackReduceSum(d) { return d.reduce(d3_layout_stackSum, 0); } function d3_layout_stackSum(p, d) { return p + d[1]; } d3.layout.histogram = function() { var frequency = true, valuer = Number, ranger = d3_layout_histogramRange, binner = d3_layout_histogramBinSturges; function histogram(data, i) { 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; while (++i < m) { bin = bins[i] = []; bin.dx = thresholds[i + 1] - (bin.x = thresholds[i]); bin.y = 0; } if (m > 0) { i = -1; while (++i < n) { x = values[i]; if (x >= range[0] && x <= range[1]) { bin = bins[d3.bisect(thresholds, x, 1, m) - 1]; bin.y += k; bin.push(data[i]); } } } return bins; } histogram.value = function(x) { if (!arguments.length) return valuer; valuer = x; return histogram; }; histogram.range = function(x) { if (!arguments.length) return ranger; ranger = d3_functor(x); return histogram; }; histogram.bins = function(x) { if (!arguments.length) return binner; binner = typeof x === "number" ? function(range) { return d3_layout_histogramBinFixed(range, x); } : d3_functor(x); return histogram; }; histogram.frequency = function(x) { if (!arguments.length) return frequency; frequency = !!x; return histogram; }; return histogram; }; function d3_layout_histogramBinSturges(range, values) { return d3_layout_histogramBinFixed(range, Math.ceil(Math.log(values.length) / Math.LN2 + 1)); } function d3_layout_histogramBinFixed(range, n) { var x = -1, b = +range[0], m = (range[1] - b) / n, f = []; while (++x <= n) f[x] = m * x + b; return f; } function d3_layout_histogramRange(values) { return [ d3.min(values), d3.max(values) ]; } d3.layout.pack = function() { var hierarchy = d3.layout.hierarchy().sort(d3_layout_packSort), padding = 0, size = [ 1, 1 ], radius; function pack(d, i) { 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() { return radius; }; root.x = root.y = 0; d3_layout_hierarchyVisitAfter(root, function(d) { d.r = +r(d.value); }); d3_layout_hierarchyVisitAfter(root, d3_layout_packSiblings); if (padding) { var dr = padding * (radius ? 1 : Math.max(2 * root.r / w, 2 * root.r / h)) / 2; d3_layout_hierarchyVisitAfter(root, function(d) { d.r += dr; }); d3_layout_hierarchyVisitAfter(root, d3_layout_packSiblings); d3_layout_hierarchyVisitAfter(root, function(d) { d.r -= dr; }); } d3_layout_packTransform(root, w / 2, h / 2, radius ? 1 : 1 / Math.max(2 * root.r / w, 2 * root.r / h)); return nodes; } pack.size = function(_) { if (!arguments.length) return size; size = _; return pack; }; pack.radius = function(_) { if (!arguments.length) return radius; radius = _ == null || typeof _ === "function" ? _ : +_; return pack; }; pack.padding = function(_) { if (!arguments.length) return padding; padding = +_; return pack; }; return d3_layout_hierarchyRebind(pack, hierarchy); }; function d3_layout_packSort(a, b) { return a.value - b.value; } function d3_layout_packInsert(a, b) { var c = a._pack_next; a._pack_next = b; b._pack_prev = a; b._pack_next = c; c._pack_prev = b; } function d3_layout_packSplice(a, b) { a._pack_next = b; b._pack_prev = a; } function d3_layout_packIntersects(a, b) { var dx = b.x - a.x, dy = b.y - a.y, dr = a.r + b.r; return .999 * dr * dr > dx * dx + dy * dy; } function d3_layout_packSiblings(node) { if (!(nodes = node.children) || !(n = nodes.length)) return; var nodes, xMin = Infinity, xMax = -Infinity, yMin = Infinity, yMax = -Infinity, a, b, c, i, j, k, n; function bound(node) { xMin = Math.min(node.x - node.r, xMin); xMax = Math.max(node.x + node.r, xMax); yMin = Math.min(node.y - node.r, yMin); yMax = Math.max(node.y + node.r, yMax); } nodes.forEach(d3_layout_packLink); a = nodes[0]; a.x = -a.r; a.y = 0; bound(a); if (n > 1) { b = nodes[1]; b.x = b.r; b.y = 0; bound(b); if (n > 2) { c = nodes[2]; d3_layout_packPlace(a, b, c); bound(c); d3_layout_packInsert(a, c); a._pack_prev = c; d3_layout_packInsert(c, b); b = a._pack_next; for (i = 3; i < n; i++) { d3_layout_packPlace(a, b, c = nodes[i]); var isect = 0, s1 = 1, s2 = 1; for (j = b._pack_next; j !== b; j = j._pack_next, s1++) { if (d3_layout_packIntersects(j, c)) { isect = 1; break; } } if (isect == 1) { for (k = a._pack_prev; k !== j._pack_prev; k = k._pack_prev, s2++) { if (d3_layout_packIntersects(k, c)) { break; } } } if (isect) { if (s1 < s2 || s1 == s2 && b.r < a.r) d3_layout_packSplice(a, b = j); else d3_layout_packSplice(a = k, b); i--; } else { d3_layout_packInsert(a, c); b = c; bound(c); } } } } var cx = (xMin + xMax) / 2, cy = (yMin + yMax) / 2, cr = 0; for (i = 0; i < n; i++) { c = nodes[i]; c.x -= cx; c.y -= cy; cr = Math.max(cr, c.r + Math.sqrt(c.x * c.x + c.y * c.y)); } node.r = cr; nodes.forEach(d3_layout_packUnlink); } function d3_layout_packLink(node) { node._pack_next = node._pack_prev = node; } function d3_layout_packUnlink(node) { delete node._pack_next; delete node._pack_prev; } function d3_layout_packTransform(node, x, y, k) { var children = node.children; node.x = x += k * node.x; node.y = y += k * node.y; node.r *= k; if (children) { var i = -1, n = children.length; while (++i < n) d3_layout_packTransform(children[i], x, y, k); } } function d3_layout_packPlace(a, b, c) { var db = a.r + c.r, dx = b.x - a.x, dy = b.y - a.y; if (db && (dx || dy)) { var da = b.r + c.r, dc = dx * dx + dy * dy; da *= da; db *= db; var x = .5 + (db - da) / (2 * dc), y = Math.sqrt(Math.max(0, 2 * da * (db + dc) - (db -= dc) * db - da * da)) / (2 * dc); c.x = a.x + x * dx + y * dy; c.y = a.y + x * dy - y * dx; } else { c.x = a.x + db; c.y = a.y; } } d3.layout.tree = function() { var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ], nodeSize = null; function tree(d, i) { var nodes = hierarchy.call(this, d, i), root0 = nodes[0], root1 = wrapTree(root0); d3_layout_hierarchyVisitAfter(root1, firstWalk), root1.parent.m = -root1.z; d3_layout_hierarchyVisitBefore(root1, secondWalk); if (nodeSize) d3_layout_hierarchyVisitBefore(root0, sizeNode); else { var left = root0, right = root0, bottom = root0; d3_layout_hierarchyVisitBefore(root0, function(node) { if (node.x < left.x) left = node; if (node.x > right.x) right = node; if (node.depth > bottom.depth) bottom = node; }); var tx = separation(left, right) / 2 - left.x, kx = size[0] / (right.x + separation(right, left) / 2 + tx), ky = size[1] / (bottom.depth || 1); d3_layout_hierarchyVisitBefore(root0, function(node) { node.x = (node.x + tx) * kx; node.y = node.depth * ky; }); } return nodes; } function wrapTree(root0) { var root1 = { A: null, children: [ root0 ] }, queue = [ root1 ], node1; while ((node1 = queue.pop()) != null) { for (var children = node1.children, child, i = 0, n = children.length; i < n; ++i) { queue.push((children[i] = child = { _: children[i], parent: node1, children: (child = children[i].children) && child.slice() || [], A: null, a: null, z: 0, m: 0, c: 0, s: 0, t: null, i: i }).a = child); } } return root1.children[0]; } function firstWalk(v) { var children = v.children, siblings = v.parent.children, w = v.i ? siblings[v.i - 1] : null; if (children.length) { d3_layout_treeShift(v); var midpoint = (children[0].z + children[children.length - 1].z) / 2; if (w) { v.z = w.z + separation(v._, w._); v.m = v.z - midpoint; } else { v.z = midpoint; } } else if (w) { v.z = w.z + separation(v._, w._); } v.parent.A = apportion(v, w, v.parent.A || siblings[0]); } function secondWalk(v) { v._.x = v.z + v.parent.m; v.m += v.parent.m; } function apportion(v, w, ancestor) { if (w) { 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; while (vim = d3_layout_treeRight(vim), vip = d3_layout_treeLeft(vip), vim && vip) { vom = d3_layout_treeLeft(vom); vop = d3_layout_treeRight(vop); vop.a = v; shift = vim.z + sim - vip.z - sip + separation(vim._, vip._); if (shift > 0) { d3_layout_treeMove(d3_layout_treeAncestor(vim, v, ancestor), v, shift); sip += shift; sop += shift; } sim += vim.m; sip += vip.m; som += vom.m; sop += vop.m; } if (vim && !d3_layout_treeRight(vop)) { vop.t = vim; vop.m += sim - sop; } if (vip && !d3_layout_treeLeft(vom)) { vom.t = vip; vom.m += sip - som; ancestor = v; } } return ancestor; } function sizeNode(node) { node.x *= size[0]; node.y = node.depth * size[1]; } tree.separation = function(x) { if (!arguments.length) return separation; separation = x; return tree; }; tree.size = function(x) { if (!arguments.length) return nodeSize ? null : size; nodeSize = (size = x) == null ? sizeNode : null; return tree; }; tree.nodeSize = function(x) { if (!arguments.length) return nodeSize ? size : null; nodeSize = (size = x) == null ? null : sizeNode; return tree; }; return d3_layout_hierarchyRebind(tree, hierarchy); }; function d3_layout_treeSeparation(a, b) { return a.parent == b.parent ? 1 : 2; } function d3_layout_treeLeft(v) { var children = v.children; return children.length ? children[0] : v.t; } function d3_layout_treeRight(v) { var children = v.children, n; return (n = children.length) ? children[n - 1] : v.t; } function d3_layout_treeMove(wm, wp, shift) { var change = shift / (wp.i - wm.i); wp.c -= change; wp.s += shift; wm.c += change; wp.z += shift; wp.m += shift; } function d3_layout_treeShift(v) { var shift = 0, change = 0, children = v.children, i = children.length, w; while (--i >= 0) { w = children[i]; w.z += shift; w.m += shift; shift += w.s + (change += w.c); } } function d3_layout_treeAncestor(vim, v, ancestor) { return vim.a.parent === v.parent ? vim.a : ancestor; } d3.layout.cluster = function() { var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ], nodeSize = false; function cluster(d, i) { var nodes = hierarchy.call(this, d, i), root = nodes[0], previousNode, x = 0; d3_layout_hierarchyVisitAfter(root, function(node) { var children = node.children; if (children && children.length) { node.x = d3_layout_clusterX(children); node.y = d3_layout_clusterY(children); } else { node.x = previousNode ? x += separation(node, previousNode) : 0; node.y = 0; previousNode = node; } }); 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; d3_layout_hierarchyVisitAfter(root, nodeSize ? function(node) { node.x = (node.x - root.x) * size[0]; node.y = (root.y - node.y) * size[1]; } : function(node) { node.x = (node.x - x0) / (x1 - x0) * size[0]; node.y = (1 - (root.y ? node.y / root.y : 1)) * size[1]; }); return nodes; } cluster.separation = function(x) { if (!arguments.length) return separation; separation = x; return cluster; }; cluster.size = function(x) { if (!arguments.length) return nodeSize ? null : size; nodeSize = (size = x) == null; return cluster; }; cluster.nodeSize = function(x) { if (!arguments.length) return nodeSize ? size : null; nodeSize = (size = x) != null; return cluster; }; return d3_layout_hierarchyRebind(cluster, hierarchy); }; function d3_layout_clusterY(children) { return 1 + d3.max(children, function(child) { return child.y; }); } function d3_layout_clusterX(children) { return children.reduce(function(x, child) { return x + child.x; }, 0) / children.length; } function d3_layout_clusterLeft(node) { var children = node.children; return children && children.length ? d3_layout_clusterLeft(children[0]) : node; } function d3_layout_clusterRight(node) { var children = node.children, n; return children && (n = children.length) ? d3_layout_clusterRight(children[n - 1]) : node; } d3.layout.treemap = function() { 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)); function scale(children, k) { var i = -1, n = children.length, child, area; while (++i < n) { area = (child = children[i]).value * (k < 0 ? 0 : k); child.area = isNaN(area) || area <= 0 ? 0 : area; } } function squarify(node) { var children = node.children; if (children && children.length) { 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; scale(remaining, rect.dx * rect.dy / node.value); row.area = 0; while ((n = remaining.length) > 0) { row.push(child = remaining[n - 1]); row.area += child.area; if (mode !== "squarify" || (score = worst(row, u)) <= best) { remaining.pop(); best = score; } else { row.area -= row.pop().area; position(row, u, rect, false); u = Math.min(rect.dx, rect.dy); row.length = row.area = 0; best = Infinity; } } if (row.length) { position(row, u, rect, true); row.length = row.area = 0; } children.forEach(squarify); } } function stickify(node) { var children = node.children; if (children && children.length) { var rect = pad(node), remaining = children.slice(), child, row = []; scale(remaining, rect.dx * rect.dy / node.value); row.area = 0; while (child = remaining.pop()) { row.push(child); row.area += child.area; if (child.z != null) { position(row, child.z ? rect.dx : rect.dy, rect, !remaining.length); row.length = row.area = 0; } } children.forEach(stickify); } } function worst(row, u) { var s = row.area, r, rmax = 0, rmin = Infinity, i = -1, n = row.length; while (++i < n) { if (!(r = row[i].area)) continue; if (r < rmin) rmin = r; if (r > rmax) rmax = r; } s *= s; u *= u; return s ? Math.max(u * rmax * ratio / s, s / (u * rmin * ratio)) : Infinity; } function position(row, u, rect, flush) { var i = -1, n = row.length, x = rect.x, y = rect.y, v = u ? round(row.area / u) : 0, o; if (u == rect.dx) { if (flush || v > rect.dy) v = rect.dy; while (++i < n) { o = row[i]; o.x = x; o.y = y; o.dy = v; x += o.dx = Math.min(rect.x + rect.dx - x, v ? round(o.area / v) : 0); } o.z = true; o.dx += rect.x + rect.dx - x; rect.y += v; rect.dy -= v; } else { if (flush || v > rect.dx) v = rect.dx; while (++i < n) { o = row[i]; o.x = x; o.y = y; o.dx = v; y += o.dy = Math.min(rect.y + rect.dy - y, v ? round(o.area / v) : 0); } o.z = false; o.dy += rect.y + rect.dy - y; rect.x += v; rect.dx -= v; } } function treemap(d) { var nodes = stickies || hierarchy(d), root = nodes[0]; root.x = root.y = 0; if (root.value) root.dx = size[0], root.dy = size[1]; else root.dx = root.dy = 0; if (stickies) hierarchy.revalue(root); scale([ root ], root.dx * root.dy / root.value); (stickies ? stickify : squarify)(root); if (sticky) stickies = nodes; return nodes; } treemap.size = function(x) { if (!arguments.length) return size; size = x; return treemap; }; treemap.padding = function(x) { if (!arguments.length) return padding; function padFunction(node) { var p = x.call(treemap, node, node.depth); return p == null ? d3_layout_treemapPadNull(node) : d3_layout_treemapPad(node, typeof p === "number" ? [ p, p, p, p ] : p); } function padConstant(node) { return d3_layout_treemapPad(node, x); } var type; pad = (padding = x) == null ? d3_layout_treemapPadNull : (type = typeof x) === "function" ? padFunction : type === "number" ? (x = [ x, x, x, x ], padConstant) : padConstant; return treemap; }; treemap.round = function(x) { if (!arguments.length) return round != Number; round = x ? Math.round : Number; return treemap; }; treemap.sticky = function(x) { if (!arguments.length) return sticky; sticky = x; stickies = null; return treemap; }; treemap.ratio = function(x) { if (!arguments.length) return ratio; ratio = x; return treemap; }; treemap.mode = function(x) { if (!arguments.length) return mode; mode = x + ""; return treemap; }; return d3_layout_hierarchyRebind(treemap, hierarchy); }; function d3_layout_treemapPadNull(node) { return { x: node.x, y: node.y, dx: node.dx, dy: node.dy }; } function d3_layout_treemapPad(node, padding) { 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]; if (dx < 0) { x += dx / 2; dx = 0; } if (dy < 0) { y += dy / 2; dy = 0; } return { x: x, y: y, dx: dx, dy: dy }; } d3.random = { normal: function(µ, σ) { var n = arguments.length; if (n < 2) σ = 1; if (n < 1) µ = 0; return function() { var x, y, r; do { x = Math.random() * 2 - 1; y = Math.random() * 2 - 1; r = x * x + y * y; } while (!r || r > 1); return µ + σ * x * Math.sqrt(-2 * Math.log(r) / r); }; }, logNormal: function() { var random = d3.random.normal.apply(d3, arguments); return function() { return Math.exp(random()); }; }, bates: function(m) { var random = d3.random.irwinHall(m); return function() { return random() / m; }; }, irwinHall: function(m) { return function() { for (var s = 0, j = 0; j < m; j++) s += Math.random(); return s; }; } }; d3.scale = {}; function d3_scaleExtent(domain) { var start = domain[0], stop = domain[domain.length - 1]; return start < stop ? [ start, stop ] : [ stop, start ]; } function d3_scaleRange(scale) { return scale.rangeExtent ? scale.rangeExtent() : d3_scaleExtent(scale.range()); } function d3_scale_bilinear(domain, range, uninterpolate, interpolate) { var u = uninterpolate(domain[0], domain[1]), i = interpolate(range[0], range[1]); return function(x) { return i(u(x)); }; } function d3_scale_nice(domain, nice) { var i0 = 0, i1 = domain.length - 1, x0 = domain[i0], x1 = domain[i1], dx; if (x1 < x0) { dx = i0, i0 = i1, i1 = dx; dx = x0, x0 = x1, x1 = dx; } domain[i0] = nice.floor(x0); domain[i1] = nice.ceil(x1); return domain; } function d3_scale_niceStep(step) { return step ? { floor: function(x) { return Math.floor(x / step) * step; }, ceil: function(x) { return Math.ceil(x / step) * step; } } : d3_scale_niceIdentity; } var d3_scale_niceIdentity = { floor: d3_identity, ceil: d3_identity }; function d3_scale_polylinear(domain, range, uninterpolate, interpolate) { var u = [], i = [], j = 0, k = Math.min(domain.length, range.length) - 1; if (domain[k] < domain[0]) { domain = domain.slice().reverse(); range = range.slice().reverse(); } while (++j <= k) { u.push(uninterpolate(domain[j - 1], domain[j])); i.push(interpolate(range[j - 1], range[j])); } return function(x) { var j = d3.bisect(domain, x, 1, k) - 1; return i[j](u[j](x)); }; } d3.scale.linear = function() { return d3_scale_linear([ 0, 1 ], [ 0, 1 ], d3_interpolate, false); }; function d3_scale_linear(domain, range, interpolate, clamp) { var output, input; function rescale() { var linear = Math.min(domain.length, range.length) > 2 ? d3_scale_polylinear : d3_scale_bilinear, uninterpolate = clamp ? d3_uninterpolateClamp : d3_uninterpolateNumber; output = linear(domain, range, uninterpolate, interpolate); input = linear(range, domain, uninterpolate, d3_interpolate); return scale; } function scale(x) { return output(x); } scale.invert = function(y) { return input(y); }; scale.domain = function(x) { if (!arguments.length) return domain; domain = x.map(Number); return rescale(); }; scale.range = function(x) { if (!arguments.length) return range; range = x; return rescale(); }; scale.rangeRound = function(x) { return scale.range(x).interpolate(d3_interpolateRound); }; scale.clamp = function(x) { if (!arguments.length) return clamp; clamp = x; return rescale(); }; scale.interpolate = function(x) { if (!arguments.length) return interpolate; interpolate = x; return rescale(); }; scale.ticks = function(m) { return d3_scale_linearTicks(domain, m); }; scale.tickFormat = function(m, format) { return d3_scale_linearTickFormat(domain, m, format); }; scale.nice = function(m) { d3_scale_linearNice(domain, m); return rescale(); }; scale.copy = function() { return d3_scale_linear(domain, range, interpolate, clamp); }; return rescale(); } function d3_scale_linearRebind(scale, linear) { return d3.rebind(scale, linear, "range", "rangeRound", "interpolate", "clamp"); } function d3_scale_linearNice(domain, m) { d3_scale_nice(domain, d3_scale_niceStep(d3_scale_linearTickRange(domain, m)[2])); d3_scale_nice(domain, d3_scale_niceStep(d3_scale_linearTickRange(domain, m)[2])); return domain; } function d3_scale_linearTickRange(domain, m) { if (m == null) m = 10; 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; if (err <= .15) step *= 10; else if (err <= .35) step *= 5; else if (err <= .75) step *= 2; extent[0] = Math.ceil(extent[0] / step) * step; extent[1] = Math.floor(extent[1] / step) * step + step * .5; extent[2] = step; return extent; } function d3_scale_linearTicks(domain, m) { return d3.range.apply(d3, d3_scale_linearTickRange(domain, m)); } function d3_scale_linearTickFormat(domain, m, format) { var range = d3_scale_linearTickRange(domain, m); if (format) { var match = d3_format_re.exec(format); match.shift(); if (match[8] === "s") { var prefix = d3.formatPrefix(Math.max(abs(range[0]), abs(range[1]))); if (!match[7]) match[7] = "." + d3_scale_linearPrecision(prefix.scale(range[2])); match[8] = "f"; format = d3.format(match.join("")); return function(d) { return format(prefix.scale(d)) + prefix.symbol; }; } if (!match[7]) match[7] = "." + d3_scale_linearFormatPrecision(match[8], range); format = match.join(""); } else { format = ",." + d3_scale_linearPrecision(range[2]) + "f"; } return d3.format(format); } var d3_scale_linearFormatSignificant = { s: 1, g: 1, p: 1, r: 1, e: 1 }; function d3_scale_linearPrecision(value) { return -Math.floor(Math.log(value) / Math.LN10 + .01); } function d3_scale_linearFormatPrecision(type, range) { var p = d3_scale_linearPrecision(range[2]); 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; } d3.scale.log = function() { return d3_scale_log(d3.scale.linear().domain([ 0, 1 ]), 10, true, [ 1, 10 ]); }; function d3_scale_log(linear, base, positive, domain) { function log(x) { return (positive ? Math.log(x < 0 ? 0 : x) : -Math.log(x > 0 ? 0 : -x)) / Math.log(base); } function pow(x) { return positive ? Math.pow(base, x) : -Math.pow(base, -x); } function scale(x) { return linear(log(x)); } scale.invert = function(x) { return pow(linear.invert(x)); }; scale.domain = function(x) { if (!arguments.length) return domain; positive = x[0] >= 0; linear.domain((domain = x.map(Number)).map(log)); return scale; }; scale.base = function(_) { if (!arguments.length) return base; base = +_; linear.domain(domain.map(log)); return scale; }; scale.nice = function() { var niced = d3_scale_nice(domain.map(log), positive ? Math : d3_scale_logNiceNegative); linear.domain(niced); domain = niced.map(pow); return scale; }; scale.ticks = function() { 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; if (isFinite(j - i)) { if (positive) { for (;i < j; i++) for (var k = 1; k < n; k++) ticks.push(pow(i) * k); ticks.push(pow(i)); } else { ticks.push(pow(i)); for (;i++ < j; ) for (var k = n - 1; k > 0; k--) ticks.push(pow(i) * k); } for (i = 0; ticks[i] < u; i++) {} for (j = ticks.length; ticks[j - 1] > v; j--) {} ticks = ticks.slice(i, j); } return ticks; }; scale.tickFormat = function(n, format) { if (!arguments.length) return d3_scale_logFormat; if (arguments.length < 2) format = d3_scale_logFormat; else if (typeof format !== "function") format = d3.format(format); var k = Math.max(1, base * n / scale.ticks().length); return function(d) { var i = d / pow(Math.round(log(d))); if (i * base < base - .5) i *= base; return i <= k ? format(d) : ""; }; }; scale.copy = function() { return d3_scale_log(linear.copy(), base, positive, domain); }; return d3_scale_linearRebind(scale, linear); } var d3_scale_logFormat = d3.format(".0e"), d3_scale_logNiceNegative = { floor: function(x) { return -Math.ceil(-x); }, ceil: function(x) { return -Math.floor(-x); } }; d3.scale.pow = function() { return d3_scale_pow(d3.scale.linear(), 1, [ 0, 1 ]); }; function d3_scale_pow(linear, exponent, domain) { var powp = d3_scale_powPow(exponent), powb = d3_scale_powPow(1 / exponent); function scale(x) { return linear(powp(x)); } scale.invert = function(x) { return powb(linear.invert(x)); }; scale.domain = function(x) { if (!arguments.length) return domain; linear.domain((domain = x.map(Number)).map(powp)); return scale; }; scale.ticks = function(m) { return d3_scale_linearTicks(domain, m); }; scale.tickFormat = function(m, format) { return d3_scale_linearTickFormat(domain, m, format); }; scale.nice = function(m) { return scale.domain(d3_scale_linearNice(domain, m)); }; scale.exponent = function(x) { if (!arguments.length) return exponent; powp = d3_scale_powPow(exponent = x); powb = d3_scale_powPow(1 / exponent); linear.domain(domain.map(powp)); return scale; }; scale.copy = function() { return d3_scale_pow(linear.copy(), exponent, domain); }; return d3_scale_linearRebind(scale, linear); } function d3_scale_powPow(e) { return function(x) { return x < 0 ? -Math.pow(-x, e) : Math.pow(x, e); }; } d3.scale.sqrt = function() { return d3.scale.pow().exponent(.5); }; d3.scale.ordinal = function() { return d3_scale_ordinal([], { t: "range", a: [ [] ] }); }; function d3_scale_ordinal(domain, ranger) { var index, range, rangeBand; function scale(x) { return range[((index.get(x) || (ranger.t === "range" ? index.set(x, domain.push(x)) : NaN)) - 1) % range.length]; } function steps(start, step) { return d3.range(domain.length).map(function(i) { return start + step * i; }); } scale.domain = function(x) { if (!arguments.length) return domain; domain = []; index = new d3_Map(); var i = -1, n = x.length, xi; while (++i < n) if (!index.has(xi = x[i])) index.set(xi, domain.push(xi)); return scale[ranger.t].apply(scale, ranger.a); }; scale.range = function(x) { if (!arguments.length) return range; range = x; rangeBand = 0; ranger = { t: "range", a: arguments }; return scale; }; scale.rangePoints = function(x, padding) { if (arguments.length < 2) padding = 0; var start = x[0], stop = x[1], step = domain.length < 2 ? (start = (start + stop) / 2, 0) : (stop - start) / (domain.length - 1 + padding); range = steps(start + step * padding / 2, step); rangeBand = 0; ranger = { t: "rangePoints", a: arguments }; return scale; }; scale.rangeRoundPoints = function(x, padding) { if (arguments.length < 2) padding = 0; var start = x[0], stop = x[1], step = domain.length < 2 ? (start = stop = Math.round((start + stop) / 2), 0) : (stop - start) / (domain.length - 1 + padding) | 0; range = steps(start + Math.round(step * padding / 2 + (stop - start - (domain.length - 1 + padding) * step) / 2), step); rangeBand = 0; ranger = { t: "rangeRoundPoints", a: arguments }; return scale; }; scale.rangeBands = function(x, padding, outerPadding) { if (arguments.length < 2) padding = 0; if (arguments.length < 3) outerPadding = padding; var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step = (stop - start) / (domain.length - padding + 2 * outerPadding); range = steps(start + step * outerPadding, step); if (reverse) range.reverse(); rangeBand = step * (1 - padding); ranger = { t: "rangeBands", a: arguments }; return scale; }; scale.rangeRoundBands = function(x, padding, outerPadding) { if (arguments.length < 2) padding = 0; if (arguments.length < 3) outerPadding = padding; var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step = Math.floor((stop - start) / (domain.length - padding + 2 * outerPadding)); range = steps(start + Math.round((stop - start - (domain.length - padding) * step) / 2), step); if (reverse) range.reverse(); rangeBand = Math.round(step * (1 - padding)); ranger = { t: "rangeRoundBands", a: arguments }; return scale; }; scale.rangeBand = function() { return rangeBand; }; scale.rangeExtent = function() { return d3_scaleExtent(ranger.a[0]); }; scale.copy = function() { return d3_scale_ordinal(domain, ranger); }; return scale.domain(domain); } d3.scale.category10 = function() { return d3.scale.ordinal().range(d3_category10); }; d3.scale.category20 = function() { return d3.scale.ordinal().range(d3_category20); }; d3.scale.category20b = function() { return d3.scale.ordinal().range(d3_category20b); }; d3.scale.category20c = function() { return d3.scale.ordinal().range(d3_category20c); }; var d3_category10 = [ 2062260, 16744206, 2924588, 14034728, 9725885, 9197131, 14907330, 8355711, 12369186, 1556175 ].map(d3_rgbString); 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); 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); 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); d3.scale.quantile = function() { return d3_scale_quantile([], []); }; function d3_scale_quantile(domain, range) { var thresholds; function rescale() { var k = 0, q = range.length; thresholds = []; while (++k < q) thresholds[k - 1] = d3.quantile(domain, k / q); return scale; } function scale(x) { if (!isNaN(x = +x)) return range[d3.bisect(thresholds, x)]; } scale.domain = function(x) { if (!arguments.length) return domain; domain = x.map(d3_number).filter(d3_numeric).sort(d3_ascending); return rescale(); }; scale.range = function(x) { if (!arguments.length) return range; range = x; return rescale(); }; scale.quantiles = function() { return thresholds; }; scale.invertExtent = function(y) { y = range.indexOf(y); return y < 0 ? [ NaN, NaN ] : [ y > 0 ? thresholds[y - 1] : domain[0], y < thresholds.length ? thresholds[y] : domain[domain.length - 1] ]; }; scale.copy = function() { return d3_scale_quantile(domain, range); }; return rescale(); } d3.scale.quantize = function() { return d3_scale_quantize(0, 1, [ 0, 1 ]); }; function d3_scale_quantize(x0, x1, range) { var kx, i; function scale(x) { return range[Math.max(0, Math.min(i, Math.floor(kx * (x - x0))))]; } function rescale() { kx = range.length / (x1 - x0); i = range.length - 1; return scale; } scale.domain = function(x) { if (!arguments.length) return [ x0, x1 ]; x0 = +x[0]; x1 = +x[x.length - 1]; return rescale(); }; scale.range = function(x) { if (!arguments.length) return range; range = x; return rescale(); }; scale.invertExtent = function(y) { y = range.indexOf(y); y = y < 0 ? NaN : y / kx + x0; return [ y, y + 1 / kx ]; }; scale.copy = function() { return d3_scale_quantize(x0, x1, range); }; return rescale(); } d3.scale.threshold = function() { return d3_scale_threshold([ .5 ], [ 0, 1 ]); }; function d3_scale_threshold(domain, range) { function scale(x) { if (x <= x) return range[d3.bisect(domain, x)]; } scale.domain = function(_) { if (!arguments.length) return domain; domain = _; return scale; }; scale.range = function(_) { if (!arguments.length) return range; range = _; return scale; }; scale.invertExtent = function(y) { y = range.indexOf(y); return [ domain[y - 1], domain[y] ]; }; scale.copy = function() { return d3_scale_threshold(domain, range); }; return scale; } d3.scale.identity = function() { return d3_scale_identity([ 0, 1 ]); }; function d3_scale_identity(domain) { function identity(x) { return +x; } identity.invert = identity; identity.domain = identity.range = function(x) { if (!arguments.length) return domain; domain = x.map(identity); return identity; }; identity.ticks = function(m) { return d3_scale_linearTicks(domain, m); }; identity.tickFormat = function(m, format) { return d3_scale_linearTickFormat(domain, m, format); }; identity.copy = function() { return d3_scale_identity(domain); }; return identity; } d3.svg = {}; function d3_zero() { return 0; } d3.svg.arc = function() { 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; function arc() { 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; if (r1 < r0) rc = r1, r1 = r0, r0 = rc; if (da >= τε) return circleSegment(r1, cw) + (r0 ? circleSegment(r0, 1 - cw) : "") + "Z"; var rc, cr, rp, ap, p0 = 0, p1 = 0, x0, y0, x1, y1, x2, y2, x3, y3, path = []; if (ap = (+padAngle.apply(this, arguments) || 0) / 2) { rp = padRadius === d3_svg_arcAuto ? Math.sqrt(r0 * r0 + r1 * r1) : +padRadius.apply(this, arguments); if (!cw) p1 *= -1; if (r1) p1 = d3_asin(rp / r1 * Math.sin(ap)); if (r0) p0 = d3_asin(rp / r0 * Math.sin(ap)); } if (r1) { x0 = r1 * Math.cos(a0 + p1); y0 = r1 * Math.sin(a0 + p1); x1 = r1 * Math.cos(a1 - p1); y1 = r1 * Math.sin(a1 - p1); var l1 = Math.abs(a1 - a0 - 2 * p1) <= π ? 0 : 1; if (p1 && d3_svg_arcSweep(x0, y0, x1, y1) === cw ^ l1) { var h1 = (a0 + a1) / 2; x0 = r1 * Math.cos(h1); y0 = r1 * Math.sin(h1); x1 = y1 = null; } } else { x0 = y0 = 0; } if (r0) { x2 = r0 * Math.cos(a1 - p0); y2 = r0 * Math.sin(a1 - p0); x3 = r0 * Math.cos(a0 + p0); y3 = r0 * Math.sin(a0 + p0); var l0 = Math.abs(a0 - a1 + 2 * p0) <= π ? 0 : 1; if (p0 && d3_svg_arcSweep(x2, y2, x3, y3) === 1 - cw ^ l0) { var h0 = (a0 + a1) / 2; x2 = r0 * Math.cos(h0); y2 = r0 * Math.sin(h0); x3 = y3 = null; } } else { x2 = y2 = 0; } if (da > ε && (rc = Math.min(Math.abs(r1 - r0) / 2, +cornerRadius.apply(this, arguments))) > .001) { cr = r0 < r1 ^ cw ? 0 : 1; var rc1 = rc, rc0 = rc; if (da < π) { 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]); rc0 = Math.min(rc, (r0 - lc) / (kc - 1)); rc1 = Math.min(rc, (r1 - lc) / (kc + 1)); } if (x1 != null) { 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); if (rc === rc1) { 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]); } else { path.push("M", t30[0], "A", rc1, ",", rc1, " 0 1,", cr, " ", t12[0]); } } else { path.push("M", x0, ",", y0); } if (x3 != null) { 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); if (rc === rc0) { 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]); } else { path.push("L", t21[0], "A", rc0, ",", rc0, " 0 0,", cr, " ", t03[0]); } } else { path.push("L", x2, ",", y2); } } else { path.push("M", x0, ",", y0); if (x1 != null) path.push("A", r1, ",", r1, " 0 ", l1, ",", cw, " ", x1, ",", y1); path.push("L", x2, ",", y2); if (x3 != null) path.push("A", r0, ",", r0, " 0 ", l0, ",", 1 - cw, " ", x3, ",", y3); } path.push("Z"); return path.join(""); } function circleSegment(r1, cw) { return "M0," + r1 + "A" + r1 + "," + r1 + " 0 1," + cw + " 0," + -r1 + "A" + r1 + "," + r1 + " 0 1," + cw + " 0," + r1; } arc.innerRadius = function(v) { if (!arguments.length) return innerRadius; innerRadius = d3_functor(v); return arc; }; arc.outerRadius = function(v) { if (!arguments.length) return outerRadius; outerRadius = d3_functor(v); return arc; }; arc.cornerRadius = function(v) { if (!arguments.length) return cornerRadius; cornerRadius = d3_functor(v); return arc; }; arc.padRadius = function(v) { if (!arguments.length) return padRadius; padRadius = v == d3_svg_arcAuto ? d3_svg_arcAuto : d3_functor(v); return arc; }; arc.startAngle = function(v) { if (!arguments.length) return startAngle; startAngle = d3_functor(v); return arc; }; arc.endAngle = function(v) { if (!arguments.length) return endAngle; endAngle = d3_functor(v); return arc; }; arc.padAngle = function(v) { if (!arguments.length) return padAngle; padAngle = d3_functor(v); return arc; }; arc.centroid = function() { var r = (+innerRadius.apply(this, arguments) + +outerRadius.apply(this, arguments)) / 2, a = (+startAngle.apply(this, arguments) + +endAngle.apply(this, arguments)) / 2 - halfπ; return [ Math.cos(a) * r, Math.sin(a) * r ]; }; return arc; }; var d3_svg_arcAuto = "auto"; function d3_svg_arcInnerRadius(d) { return d.innerRadius; } function d3_svg_arcOuterRadius(d) { return d.outerRadius; } function d3_svg_arcStartAngle(d) { return d.startAngle; } function d3_svg_arcEndAngle(d) { return d.endAngle; } function d3_svg_arcPadAngle(d) { return d && d.padAngle; } function d3_svg_arcSweep(x0, y0, x1, y1) { return (x0 - x1) * y0 - (y0 - y1) * x0 > 0 ? 0 : 1; } function d3_svg_arcCornerTangents(p0, p1, r1, rc, cw) { 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; if (dx0 * dx0 + dy0 * dy0 > dx1 * dx1 + dy1 * dy1) cx0 = cx1, cy0 = cy1; return [ [ cx0 - ox, cy0 - oy ], [ cx0 * r1 / r, cy0 * r1 / r ] ]; } function d3_svg_line(projection) { var x = d3_geom_pointX, y = d3_geom_pointY, defined = d3_true, interpolate = d3_svg_lineLinear, interpolateKey = interpolate.key, tension = .7; function line(data) { var segments = [], points = [], i = -1, n = data.length, d, fx = d3_functor(x), fy = d3_functor(y); function segment() { segments.push("M", interpolate(projection(points), tension)); } while (++i < n) { if (defined.call(this, d = data[i], i)) { points.push([ +fx.call(this, d, i), +fy.call(this, d, i) ]); } else if (points.length) { segment(); points = []; } } if (points.length) segment(); return segments.length ? segments.join("") : null; } line.x = function(_) { if (!arguments.length) return x; x = _; return line; }; line.y = function(_) { if (!arguments.length) return y; y = _; return line; }; line.defined = function(_) { if (!arguments.length) return defined; defined = _; return line; }; line.interpolate = function(_) { if (!arguments.length) return interpolateKey; if (typeof _ === "function") interpolateKey = interpolate = _; else interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) || d3_svg_lineLinear).key; return line; }; line.tension = function(_) { if (!arguments.length) return tension; tension = _; return line; }; return line; } d3.svg.line = function() { return d3_svg_line(d3_identity); }; var d3_svg_lineInterpolators = d3.map({ linear: d3_svg_lineLinear, "linear-closed": d3_svg_lineLinearClosed, step: d3_svg_lineStep, "step-before": d3_svg_lineStepBefore, "step-after": d3_svg_lineStepAfter, basis: d3_svg_lineBasis, "basis-open": d3_svg_lineBasisOpen, "basis-closed": d3_svg_lineBasisClosed, bundle: d3_svg_lineBundle, cardinal: d3_svg_lineCardinal, "cardinal-open": d3_svg_lineCardinalOpen, "cardinal-closed": d3_svg_lineCardinalClosed, monotone: d3_svg_lineMonotone }); d3_svg_lineInterpolators.forEach(function(key, value) { value.key = key; value.closed = /-closed$/.test(key); }); function d3_svg_lineLinear(points) { return points.length > 1 ? points.join("L") : points + "Z"; } function d3_svg_lineLinearClosed(points) { return points.join("L") + "Z"; } function d3_svg_lineStep(points) { var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ]; while (++i < n) path.push("H", (p[0] + (p = points[i])[0]) / 2, "V", p[1]); if (n > 1) path.push("H", p[0]); return path.join(""); } function d3_svg_lineStepBefore(points) { var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ]; while (++i < n) path.push("V", (p = points[i])[1], "H", p[0]); return path.join(""); } function d3_svg_lineStepAfter(points) { var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ]; while (++i < n) path.push("H", (p = points[i])[0], "V", p[1]); return path.join(""); } function d3_svg_lineCardinalOpen(points, tension) { return points.length < 4 ? d3_svg_lineLinear(points) : points[1] + d3_svg_lineHermite(points.slice(1, -1), d3_svg_lineCardinalTangents(points, tension)); } function d3_svg_lineCardinalClosed(points, tension) { return points.length < 3 ? d3_svg_lineLinearClosed(points) : points[0] + d3_svg_lineHermite((points.push(points[0]), points), d3_svg_lineCardinalTangents([ points[points.length - 2] ].concat(points, [ points[1] ]), tension)); } function d3_svg_lineCardinal(points, tension) { return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite(points, d3_svg_lineCardinalTangents(points, tension)); } function d3_svg_lineHermite(points, tangents) { if (tangents.length < 1 || points.length != tangents.length && points.length != tangents.length + 2) { return d3_svg_lineLinear(points); } var quad = points.length != tangents.length, path = "", p0 = points[0], p = points[1], t0 = tangents[0], t = t0, pi = 1; if (quad) { path += "Q" + (p[0] - t0[0] * 2 / 3) + "," + (p[1] - t0[1] * 2 / 3) + "," + p[0] + "," + p[1]; p0 = points[1]; pi = 2; } if (tangents.length > 1) { t = tangents[1]; p = points[pi]; pi++; path += "C" + (p0[0] + t0[0]) + "," + (p0[1] + t0[1]) + "," + (p[0] - t[0]) + "," + (p[1] - t[1]) + "," + p[0] + "," + p[1]; for (var i = 2; i < tangents.length; i++, pi++) { p = points[pi]; t = tangents[i]; path += "S" + (p[0] - t[0]) + "," + (p[1] - t[1]) + "," + p[0] + "," + p[1]; } } if (quad) { var lp = points[pi]; path += "Q" + (p[0] + t[0] * 2 / 3) + "," + (p[1] + t[1] * 2 / 3) + "," + lp[0] + "," + lp[1]; } return path; } function d3_svg_lineCardinalTangents(points, tension) { var tangents = [], a = (1 - tension) / 2, p0, p1 = points[0], p2 = points[1], i = 1, n = points.length; while (++i < n) { p0 = p1; p1 = p2; p2 = points[i]; tangents.push([ a * (p2[0] - p0[0]), a * (p2[1] - p0[1]) ]); } return tangents; } function d3_svg_lineBasis(points) { if (points.length < 3) return d3_svg_lineLinear(points); 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) ]; points.push(points[n - 1]); while (++i <= n) { pi = points[i]; px.shift(); px.push(pi[0]); py.shift(); py.push(pi[1]); d3_svg_lineBasisBezier(path, px, py); } points.pop(); path.push("L", pi); return path.join(""); } function d3_svg_lineBasisOpen(points) { if (points.length < 4) return d3_svg_lineLinear(points); var path = [], i = -1, n = points.length, pi, px = [ 0 ], py = [ 0 ]; while (++i < 3) { pi = points[i]; px.push(pi[0]); py.push(pi[1]); } path.push(d3_svg_lineDot4(d3_svg_lineBasisBezier3, px) + "," + d3_svg_lineDot4(d3_svg_lineBasisBezier3, py)); --i; while (++i < n) { pi = points[i]; px.shift(); px.push(pi[0]); py.shift(); py.push(pi[1]); d3_svg_lineBasisBezier(path, px, py); } return path.join(""); } function d3_svg_lineBasisClosed(points) { var path, i = -1, n = points.length, m = n + 4, pi, px = [], py = []; while (++i < 4) { pi = points[i % n]; px.push(pi[0]); py.push(pi[1]); } path = [ d3_svg_lineDot4(d3_svg_lineBasisBezier3, px), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, py) ]; --i; while (++i < m) { pi = points[i % n]; px.shift(); px.push(pi[0]); py.shift(); py.push(pi[1]); d3_svg_lineBasisBezier(path, px, py); } return path.join(""); } function d3_svg_lineBundle(points, tension) { var n = points.length - 1; if (n) { var x0 = points[0][0], y0 = points[0][1], dx = points[n][0] - x0, dy = points[n][1] - y0, i = -1, p, t; while (++i <= n) { p = points[i]; t = i / n; p[0] = tension * p[0] + (1 - tension) * (x0 + t * dx); p[1] = tension * p[1] + (1 - tension) * (y0 + t * dy); } } return d3_svg_lineBasis(points); } function d3_svg_lineDot4(a, b) { return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]; } 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 ]; function d3_svg_lineBasisBezier(path, x, y) { 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)); } function d3_svg_lineSlope(p0, p1) { return (p1[1] - p0[1]) / (p1[0] - p0[0]); } function d3_svg_lineFiniteDifferences(points) { var i = 0, j = points.length - 1, m = [], p0 = points[0], p1 = points[1], d = m[0] = d3_svg_lineSlope(p0, p1); while (++i < j) { m[i] = (d + (d = d3_svg_lineSlope(p0 = p1, p1 = points[i + 1]))) / 2; } m[i] = d; return m; } function d3_svg_lineMonotoneTangents(points) { var tangents = [], d, a, b, s, m = d3_svg_lineFiniteDifferences(points), i = -1, j = points.length - 1; while (++i < j) { d = d3_svg_lineSlope(points[i], points[i + 1]); if (abs(d) < ε) { m[i] = m[i + 1] = 0; } else { a = m[i] / d; b = m[i + 1] / d; s = a * a + b * b; if (s > 9) { s = d * 3 / Math.sqrt(s); m[i] = s * a; m[i + 1] = s * b; } } } i = -1; while (++i <= j) { s = (points[Math.min(j, i + 1)][0] - points[Math.max(0, i - 1)][0]) / (6 * (1 + m[i] * m[i])); tangents.push([ s || 0, m[i] * s || 0 ]); } return tangents; } function d3_svg_lineMonotone(points) { return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite(points, d3_svg_lineMonotoneTangents(points)); } d3.svg.line.radial = function() { var line = d3_svg_line(d3_svg_lineRadial); line.radius = line.x, delete line.x; line.angle = line.y, delete line.y; return line; }; function d3_svg_lineRadial(points) { var point, i = -1, n = points.length, r, a; while (++i < n) { point = points[i]; r = point[0]; a = point[1] - halfπ; point[0] = r * Math.cos(a); point[1] = r * Math.sin(a); } return points; } function d3_svg_area(projection) { 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; function area(data) { var segments = [], points0 = [], points1 = [], i = -1, n = data.length, d, fx0 = d3_functor(x0), fy0 = d3_functor(y0), fx1 = x0 === x1 ? function() { return x; } : d3_functor(x1), fy1 = y0 === y1 ? function() { return y; } : d3_functor(y1), x, y; function segment() { segments.push("M", interpolate(projection(points1), tension), L, interpolateReverse(projection(points0.reverse()), tension), "Z"); } while (++i < n) { if (defined.call(this, d = data[i], i)) { points0.push([ x = +fx0.call(this, d, i), y = +fy0.call(this, d, i) ]); points1.push([ +fx1.call(this, d, i), +fy1.call(this, d, i) ]); } else if (points0.length) { segment(); points0 = []; points1 = []; } } if (points0.length) segment(); return segments.length ? segments.join("") : null; } area.x = function(_) { if (!arguments.length) return x1; x0 = x1 = _; return area; }; area.x0 = function(_) { if (!arguments.length) return x0; x0 = _; return area; }; area.x1 = function(_) { if (!arguments.length) return x1; x1 = _; return area; }; area.y = function(_) { if (!arguments.length) return y1; y0 = y1 = _; return area; }; area.y0 = function(_) { if (!arguments.length) return y0; y0 = _; return area; }; area.y1 = function(_) { if (!arguments.length) return y1; y1 = _; return area; }; area.defined = function(_) { if (!arguments.length) return defined; defined = _; return area; }; area.interpolate = function(_) { if (!arguments.length) return interpolateKey; if (typeof _ === "function") interpolateKey = interpolate = _; else interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) || d3_svg_lineLinear).key; interpolateReverse = interpolate.reverse || interpolate; L = interpolate.closed ? "M" : "L"; return area; }; area.tension = function(_) { if (!arguments.length) return tension; tension = _; return area; }; return area; } d3_svg_lineStepBefore.reverse = d3_svg_lineStepAfter; d3_svg_lineStepAfter.reverse = d3_svg_lineStepBefore; d3.svg.area = function() { return d3_svg_area(d3_identity); }; d3.svg.area.radial = function() { var area = d3_svg_area(d3_svg_lineRadial); area.radius = area.x, delete area.x; area.innerRadius = area.x0, delete area.x0; area.outerRadius = area.x1, delete area.x1; area.angle = area.y, delete area.y; area.startAngle = area.y0, delete area.y0; area.endAngle = area.y1, delete area.y1; return area; }; d3.svg.chord = function() { var source = d3_source, target = d3_target, radius = d3_svg_chordRadius, startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle; function chord(d, i) { var s = subgroup(this, source, d, i), t = subgroup(this, target, d, i); 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"; } function subgroup(self, f, d, i) { 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π; return { r: r, a0: a0, a1: a1, p0: [ r * Math.cos(a0), r * Math.sin(a0) ], p1: [ r * Math.cos(a1), r * Math.sin(a1) ] }; } function equals(a, b) { return a.a0 == b.a0 && a.a1 == b.a1; } function arc(r, p, a) { return "A" + r + "," + r + " 0 " + +(a > π) + ",1 " + p; } function curve(r0, p0, r1, p1) { return "Q 0,0 " + p1; } chord.radius = function(v) { if (!arguments.length) return radius; radius = d3_functor(v); return chord; }; chord.source = function(v) { if (!arguments.length) return source; source = d3_functor(v); return chord; }; chord.target = function(v) { if (!arguments.length) return target; target = d3_functor(v); return chord; }; chord.startAngle = function(v) { if (!arguments.length) return startAngle; startAngle = d3_functor(v); return chord; }; chord.endAngle = function(v) { if (!arguments.length) return endAngle; endAngle = d3_functor(v); return chord; }; return chord; }; function d3_svg_chordRadius(d) { return d.radius; } d3.svg.diagonal = function() { var source = d3_source, target = d3_target, projection = d3_svg_diagonalProjection; function diagonal(d, i) { var p0 = source.call(this, d, i), p3 = target.call(this, d, i), m = (p0.y + p3.y) / 2, p = [ p0, { x: p0.x, y: m }, { x: p3.x, y: m }, p3 ]; p = p.map(projection); return "M" + p[0] + "C" + p[1] + " " + p[2] + " " + p[3]; } diagonal.source = function(x) { if (!arguments.length) return source; source = d3_functor(x); return diagonal; }; diagonal.target = function(x) { if (!arguments.length) return target; target = d3_functor(x); return diagonal; }; diagonal.projection = function(x) { if (!arguments.length) return projection; projection = x; return diagonal; }; return diagonal; }; function d3_svg_diagonalProjection(d) { return [ d.x, d.y ]; } d3.svg.diagonal.radial = function() { var diagonal = d3.svg.diagonal(), projection = d3_svg_diagonalProjection, projection_ = diagonal.projection; diagonal.projection = function(x) { return arguments.length ? projection_(d3_svg_diagonalRadialProjection(projection = x)) : projection; }; return diagonal; }; function d3_svg_diagonalRadialProjection(projection) { return function() { var d = projection.apply(this, arguments), r = d[0], a = d[1] - halfπ; return [ r * Math.cos(a), r * Math.sin(a) ]; }; } d3.svg.symbol = function() { var type = d3_svg_symbolType, size = d3_svg_symbolSize; function symbol(d, i) { return (d3_svg_symbols.get(type.call(this, d, i)) || d3_svg_symbolCircle)(size.call(this, d, i)); } symbol.type = function(x) { if (!arguments.length) return type; type = d3_functor(x); return symbol; }; symbol.size = function(x) { if (!arguments.length) return size; size = d3_functor(x); return symbol; }; return symbol; }; function d3_svg_symbolSize() { return 64; } function d3_svg_symbolType() { return "circle"; } function d3_svg_symbolCircle(size) { var r = Math.sqrt(size / π); return "M0," + r + "A" + r + "," + r + " 0 1,1 0," + -r + "A" + r + "," + r + " 0 1,1 0," + r + "Z"; } var d3_svg_symbols = d3.map({ circle: d3_svg_symbolCircle, cross: function(size) { var r = Math.sqrt(size / 5) / 2; 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"; }, diamond: function(size) { var ry = Math.sqrt(size / (2 * d3_svg_symbolTan30)), rx = ry * d3_svg_symbolTan30; return "M0," + -ry + "L" + rx + ",0" + " 0," + ry + " " + -rx + ",0" + "Z"; }, square: function(size) { var r = Math.sqrt(size) / 2; return "M" + -r + "," + -r + "L" + r + "," + -r + " " + r + "," + r + " " + -r + "," + r + "Z"; }, "triangle-down": function(size) { var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2; return "M0," + ry + "L" + rx + "," + -ry + " " + -rx + "," + -ry + "Z"; }, "triangle-up": function(size) { var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2; return "M0," + -ry + "L" + rx + "," + ry + " " + -rx + "," + ry + "Z"; } }); d3.svg.symbolTypes = d3_svg_symbols.keys(); var d3_svg_symbolSqrt3 = Math.sqrt(3), d3_svg_symbolTan30 = Math.tan(30 * d3_radians); d3_selectionPrototype.transition = function(name) { var id = d3_transitionInheritId || ++d3_transitionId, ns = d3_transitionNamespace(name), subgroups = [], subgroup, node, transition = d3_transitionInherit || { time: Date.now(), ease: d3_ease_cubicInOut, delay: 0, duration: 250 }; for (var j = -1, m = this.length; ++j < m; ) { subgroups.push(subgroup = []); for (var group = this[j], i = -1, n = group.length; ++i < n; ) { if (node = group[i]) d3_transitionNode(node, i, ns, id, transition); subgroup.push(node); } } return d3_transition(subgroups, ns, id); }; d3_selectionPrototype.interrupt = function(name) { return this.each(name == null ? d3_selection_interrupt : d3_selection_interruptNS(d3_transitionNamespace(name))); }; var d3_selection_interrupt = d3_selection_interruptNS(d3_transitionNamespace()); function d3_selection_interruptNS(ns) { return function() { var lock, activeId, active; if ((lock = this[ns]) && (active = lock[activeId = lock.active])) { active.timer.c = null; active.timer.t = NaN; if (--lock.count) delete lock[activeId]; else delete this[ns]; lock.active += .5; active.event && active.event.interrupt.call(this, this.__data__, active.index); } }; } function d3_transition(groups, ns, id) { d3_subclass(groups, d3_transitionPrototype); groups.namespace = ns; groups.id = id; return groups; } var d3_transitionPrototype = [], d3_transitionId = 0, d3_transitionInheritId, d3_transitionInherit; d3_transitionPrototype.call = d3_selectionPrototype.call; d3_transitionPrototype.empty = d3_selectionPrototype.empty; d3_transitionPrototype.node = d3_selectionPrototype.node; d3_transitionPrototype.size = d3_selectionPrototype.size; d3.transition = function(selection, name) { return selection && selection.transition ? d3_transitionInheritId ? selection.transition(name) : selection : d3.selection().transition(selection); }; d3.transition.prototype = d3_transitionPrototype; d3_transitionPrototype.select = function(selector) { var id = this.id, ns = this.namespace, subgroups = [], subgroup, subnode, node; selector = d3_selection_selector(selector); for (var j = -1, m = this.length; ++j < m; ) { subgroups.push(subgroup = []); for (var group = this[j], i = -1, n = group.length; ++i < n; ) { if ((node = group[i]) && (subnode = selector.call(node, node.__data__, i, j))) { if ("__data__" in node) subnode.__data__ = node.__data__; d3_transitionNode(subnode, i, ns, id, node[ns][id]); subgroup.push(subnode); } else { subgroup.push(null); } } } return d3_transition(subgroups, ns, id); }; d3_transitionPrototype.selectAll = function(selector) { var id = this.id, ns = this.namespace, subgroups = [], subgroup, subnodes, node, subnode, transition; selector = d3_selection_selectorAll(selector); for (var j = -1, m = this.length; ++j < m; ) { for (var group = this[j], i = -1, n = group.length; ++i < n; ) { if (node = group[i]) { transition = node[ns][id]; subnodes = selector.call(node, node.__data__, i, j); subgroups.push(subgroup = []); for (var k = -1, o = subnodes.length; ++k < o; ) { if (subnode = subnodes[k]) d3_transitionNode(subnode, k, ns, id, transition); subgroup.push(subnode); } } } } return d3_transition(subgroups, ns, id); }; d3_transitionPrototype.filter = function(filter) { var subgroups = [], subgroup, group, node; if (typeof filter !== "function") filter = d3_selection_filter(filter); for (var j = 0, m = this.length; j < m; j++) { subgroups.push(subgroup = []); for (var group = this[j], i = 0, n = group.length; i < n; i++) { if ((node = group[i]) && filter.call(node, node.__data__, i, j)) { subgroup.push(node); } } } return d3_transition(subgroups, this.namespace, this.id); }; d3_transitionPrototype.tween = function(name, tween) { var id = this.id, ns = this.namespace; if (arguments.length < 2) return this.node()[ns][id].tween.get(name); return d3_selection_each(this, tween == null ? function(node) { node[ns][id].tween.remove(name); } : function(node) { node[ns][id].tween.set(name, tween); }); }; function d3_transition_tween(groups, name, value, tween) { var id = groups.id, ns = groups.namespace; return d3_selection_each(groups, typeof value === "function" ? function(node, i, j) { node[ns][id].tween.set(name, tween(value.call(node, node.__data__, i, j))); } : (value = tween(value), function(node) { node[ns][id].tween.set(name, value); })); } d3_transitionPrototype.attr = function(nameNS, value) { if (arguments.length < 2) { for (value in nameNS) this.attr(value, nameNS[value]); return this; } var interpolate = nameNS == "transform" ? d3_interpolateTransform : d3_interpolate, name = d3.ns.qualify(nameNS); function attrNull() { this.removeAttribute(name); } function attrNullNS() { this.removeAttributeNS(name.space, name.local); } function attrTween(b) { return b == null ? attrNull : (b += "", function() { var a = this.getAttribute(name), i; return a !== b && (i = interpolate(a, b), function(t) { this.setAttribute(name, i(t)); }); }); } function attrTweenNS(b) { return b == null ? attrNullNS : (b += "", function() { var a = this.getAttributeNS(name.space, name.local), i; return a !== b && (i = interpolate(a, b), function(t) { this.setAttributeNS(name.space, name.local, i(t)); }); }); } return d3_transition_tween(this, "attr." + nameNS, value, name.local ? attrTweenNS : attrTween); }; d3_transitionPrototype.attrTween = function(nameNS, tween) { var name = d3.ns.qualify(nameNS); function attrTween(d, i) { var f = tween.call(this, d, i, this.getAttribute(name)); return f && function(t) { this.setAttribute(name, f(t)); }; } function attrTweenNS(d, i) { var f = tween.call(this, d, i, this.getAttributeNS(name.space, name.local)); return f && function(t) { this.setAttributeNS(name.space, name.local, f(t)); }; } return this.tween("attr." + nameNS, name.local ? attrTweenNS : attrTween); }; d3_transitionPrototype.style = function(name, value, priority) { var n = arguments.length; if (n < 3) { if (typeof name !== "string") { if (n < 2) value = ""; for (priority in name) this.style(priority, name[priority], value); return this; } priority = ""; } function styleNull() { this.style.removeProperty(name); } function styleString(b) { return b == null ? styleNull : (b += "", function() { var a = d3_window(this).getComputedStyle(this, null).getPropertyValue(name), i; return a !== b && (i = d3_interpolate(a, b), function(t) { this.style.setProperty(name, i(t), priority); }); }); } return d3_transition_tween(this, "style." + name, value, styleString); }; d3_transitionPrototype.styleTween = function(name, tween, priority) { if (arguments.length < 3) priority = ""; function styleTween(d, i) { var f = tween.call(this, d, i, d3_window(this).getComputedStyle(this, null).getPropertyValue(name)); return f && function(t) { this.style.setProperty(name, f(t), priority); }; } return this.tween("style." + name, styleTween); }; d3_transitionPrototype.text = function(value) { return d3_transition_tween(this, "text", value, d3_transition_text); }; function d3_transition_text(b) { if (b == null) b = ""; return function() { this.textContent = b; }; } d3_transitionPrototype.remove = function() { var ns = this.namespace; return this.each("end.transition", function() { var p; if (this[ns].count < 2 && (p = this.parentNode)) p.removeChild(this); }); }; d3_transitionPrototype.ease = function(value) { var id = this.id, ns = this.namespace; if (arguments.length < 1) return this.node()[ns][id].ease; if (typeof value !== "function") value = d3.ease.apply(d3, arguments); return d3_selection_each(this, function(node) { node[ns][id].ease = value; }); }; d3_transitionPrototype.delay = function(value) { var id = this.id, ns = this.namespace; if (arguments.length < 1) return this.node()[ns][id].delay; return d3_selection_each(this, typeof value === "function" ? function(node, i, j) { node[ns][id].delay = +value.call(node, node.__data__, i, j); } : (value = +value, function(node) { node[ns][id].delay = value; })); }; d3_transitionPrototype.duration = function(value) { var id = this.id, ns = this.namespace; if (arguments.length < 1) return this.node()[ns][id].duration; return d3_selection_each(this, typeof value === "function" ? function(node, i, j) { node[ns][id].duration = Math.max(1, value.call(node, node.__data__, i, j)); } : (value = Math.max(1, value), function(node) { node[ns][id].duration = value; })); }; d3_transitionPrototype.each = function(type, listener) { var id = this.id, ns = this.namespace; if (arguments.length < 2) { var inherit = d3_transitionInherit, inheritId = d3_transitionInheritId; try { d3_transitionInheritId = id; d3_selection_each(this, function(node, i, j) { d3_transitionInherit = node[ns][id]; type.call(node, node.__data__, i, j); }); } finally { d3_transitionInherit = inherit; d3_transitionInheritId = inheritId; } } else { d3_selection_each(this, function(node) { var transition = node[ns][id]; (transition.event || (transition.event = d3.dispatch("start", "end", "interrupt"))).on(type, listener); }); } return this; }; d3_transitionPrototype.transition = function() { var id0 = this.id, id1 = ++d3_transitionId, ns = this.namespace, subgroups = [], subgroup, group, node, transition; for (var j = 0, m = this.length; j < m; j++) { subgroups.push(subgroup = []); for (var group = this[j], i = 0, n = group.length; i < n; i++) { if (node = group[i]) { transition = node[ns][id0]; d3_transitionNode(node, i, ns, id1, { time: transition.time, ease: transition.ease, delay: transition.delay + transition.duration, duration: transition.duration }); } subgroup.push(node); } } return d3_transition(subgroups, ns, id1); }; function d3_transitionNamespace(name) { return name == null ? "__transition__" : "__transition_" + name + "__"; } function d3_transitionNode(node, i, ns, id, inherit) { var lock = node[ns] || (node[ns] = { active: 0, count: 0 }), transition = lock[id], time, timer, duration, ease, tweens; function schedule(elapsed) { var delay = transition.delay; timer.t = delay + time; if (delay <= elapsed) return start(elapsed - delay); timer.c = start; } function start(elapsed) { var activeId = lock.active, active = lock[activeId]; if (active) { active.timer.c = null; active.timer.t = NaN; --lock.count; delete lock[activeId]; active.event && active.event.interrupt.call(node, node.__data__, active.index); } for (var cancelId in lock) { if (+cancelId < id) { var cancel = lock[cancelId]; cancel.timer.c = null; cancel.timer.t = NaN; --lock.count; delete lock[cancelId]; } } timer.c = tick; d3_timer(function() { if (timer.c && tick(elapsed || 1)) { timer.c = null; timer.t = NaN; } return 1; }, 0, time); lock.active = id; transition.event && transition.event.start.call(node, node.__data__, i); tweens = []; transition.tween.forEach(function(key, value) { if (value = value.call(node, node.__data__, i)) { tweens.push(value); } }); ease = transition.ease; duration = transition.duration; } function tick(elapsed) { var t = elapsed / duration, e = ease(t), n = tweens.length; while (n > 0) { tweens[--n].call(node, e); } if (t >= 1) { transition.event && transition.event.end.call(node, node.__data__, i); if (--lock.count) delete lock[id]; else delete node[ns]; return 1; } } if (!transition) { time = inherit.time; timer = d3_timer(schedule, 0, time); transition = lock[id] = { tween: new d3_Map(), time: time, timer: timer, delay: inherit.delay, duration: inherit.duration, ease: inherit.ease, index: i }; inherit = null; ++lock.count; } } d3.svg.axis = function() { var scale = d3.scale.linear(), orient = d3_svg_axisDefaultOrient, innerTickSize = 6, outerTickSize = 6, tickPadding = 3, tickArguments_ = [ 10 ], tickValues = null, tickFormat_; function axis(g) { g.each(function() { var g = d3.select(this); var scale0 = this.__chart__ || scale, scale1 = this.__chart__ = scale.copy(); 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; var range = d3_scaleRange(scale1), path = g.selectAll(".domain").data([ 0 ]), pathUpdate = (path.enter().append("path").attr("class", "domain"), d3.transition(path)); tickEnter.append("line"); tickEnter.append("text"); 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; if (orient === "bottom" || orient === "top") { tickTransform = d3_svg_axisX, x1 = "x", y1 = "y", x2 = "x2", y2 = "y2"; text.attr("dy", sign < 0 ? "0em" : ".71em").style("text-anchor", "middle"); pathUpdate.attr("d", "M" + range[0] + "," + sign * outerTickSize + "V0H" + range[1] + "V" + sign * outerTickSize); } else { tickTransform = d3_svg_axisY, x1 = "y", y1 = "x", x2 = "y2", y2 = "x2"; text.attr("dy", ".32em").style("text-anchor", sign < 0 ? "end" : "start"); pathUpdate.attr("d", "M" + sign * outerTickSize + "," + range[0] + "H0V" + range[1] + "H" + sign * outerTickSize); } lineEnter.attr(y2, sign * innerTickSize); textEnter.attr(y1, sign * tickSpacing); lineUpdate.attr(x2, 0).attr(y2, sign * innerTickSize); textUpdate.attr(x1, 0).attr(y1, sign * tickSpacing); if (scale1.rangeBand) { var x = scale1, dx = x.rangeBand() / 2; scale0 = scale1 = function(d) { return x(d) + dx; }; } else if (scale0.rangeBand) { scale0 = scale1; } else { tickExit.call(tickTransform, scale1, scale0); } tickEnter.call(tickTransform, scale0, scale1); tickUpdate.call(tickTransform, scale1, scale1); }); } axis.scale = function(x) { if (!arguments.length) return scale; scale = x; return axis; }; axis.orient = function(x) { if (!arguments.length) return orient; orient = x in d3_svg_axisOrients ? x + "" : d3_svg_axisDefaultOrient; return axis; }; axis.ticks = function() { if (!arguments.length) return tickArguments_; tickArguments_ = d3_array(arguments); return axis; }; axis.tickValues = function(x) { if (!arguments.length) return tickValues; tickValues = x; return axis; }; axis.tickFormat = function(x) { if (!arguments.length) return tickFormat_; tickFormat_ = x; return axis; }; axis.tickSize = function(x) { var n = arguments.length; if (!n) return innerTickSize; innerTickSize = +x; outerTickSize = +arguments[n - 1]; return axis; }; axis.innerTickSize = function(x) { if (!arguments.length) return innerTickSize; innerTickSize = +x; return axis; }; axis.outerTickSize = function(x) { if (!arguments.length) return outerTickSize; outerTickSize = +x; return axis; }; axis.tickPadding = function(x) { if (!arguments.length) return tickPadding; tickPadding = +x; return axis; }; axis.tickSubdivide = function() { return arguments.length && axis; }; return axis; }; var d3_svg_axisDefaultOrient = "bottom", d3_svg_axisOrients = { top: 1, right: 1, bottom: 1, left: 1 }; function d3_svg_axisX(selection, x0, x1) { selection.attr("transform", function(d) { var v0 = x0(d); return "translate(" + (isFinite(v0) ? v0 : x1(d)) + ",0)"; }); } function d3_svg_axisY(selection, y0, y1) { selection.attr("transform", function(d) { var v0 = y0(d); return "translate(0," + (isFinite(v0) ? v0 : y1(d)) + ")"; }); } d3.svg.brush = function() { 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]; function brush(g) { g.each(function() { 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); var background = g.selectAll(".background").data([ 0 ]); background.enter().append("rect").attr("class", "background").style("visibility", "hidden").style("cursor", "crosshair"); g.selectAll(".extent").data([ 0 ]).enter().append("rect").attr("class", "extent").style("cursor", "move"); var resize = g.selectAll(".resize").data(resizes, d3_identity); resize.exit().remove(); resize.enter().append("g").attr("class", function(d) { return "resize " + d; }).style("cursor", function(d) { return d3_svg_brushCursor[d]; }).append("rect").attr("x", function(d) { return /[ew]$/.test(d) ? -3 : null; }).attr("y", function(d) { return /^[ns]/.test(d) ? -3 : null; }).attr("width", 6).attr("height", 6).style("visibility", "hidden"); resize.style("display", brush.empty() ? "none" : null); var gUpdate = d3.transition(g), backgroundUpdate = d3.transition(background), range; if (x) { range = d3_scaleRange(x); backgroundUpdate.attr("x", range[0]).attr("width", range[1] - range[0]); redrawX(gUpdate); } if (y) { range = d3_scaleRange(y); backgroundUpdate.attr("y", range[0]).attr("height", range[1] - range[0]); redrawY(gUpdate); } redraw(gUpdate); }); } brush.event = function(g) { g.each(function() { var event_ = event.of(this, arguments), extent1 = { x: xExtent, y: yExtent, i: xExtentDomain, j: yExtentDomain }, extent0 = this.__chart__ || extent1; this.__chart__ = extent1; if (d3_transitionInheritId) { d3.select(this).transition().each("start.brush", function() { xExtentDomain = extent0.i; yExtentDomain = extent0.j; xExtent = extent0.x; yExtent = extent0.y; event_({ type: "brushstart" }); }).tween("brush:brush", function() { var xi = d3_interpolateArray(xExtent, extent1.x), yi = d3_interpolateArray(yExtent, extent1.y); xExtentDomain = yExtentDomain = null; return function(t) { xExtent = extent1.x = xi(t); yExtent = extent1.y = yi(t); event_({ type: "brush", mode: "resize" }); }; }).each("end.brush", function() { xExtentDomain = extent1.i; yExtentDomain = extent1.j; event_({ type: "brush", mode: "resize" }); event_({ type: "brushend" }); }); } else { event_({ type: "brushstart" }); event_({ type: "brush", mode: "resize" }); event_({ type: "brushend" }); } }); }; function redraw(g) { g.selectAll(".resize").attr("transform", function(d) { return "translate(" + xExtent[+/e$/.test(d)] + "," + yExtent[+/^s/.test(d)] + ")"; }); } function redrawX(g) { g.select(".extent").attr("x", xExtent[0]); g.selectAll(".extent,.n>rect,.s>rect").attr("width", xExtent[1] - xExtent[0]); } function redrawY(g) { g.select(".extent").attr("y", yExtent[0]); g.selectAll(".extent,.e>rect,.w>rect").attr("height", yExtent[1] - yExtent[0]); } function brushstart() { 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; var w = d3.select(d3_window(target)).on("keydown.brush", keydown).on("keyup.brush", keyup); if (d3.event.changedTouches) { w.on("touchmove.brush", brushmove).on("touchend.brush", brushend); } else { w.on("mousemove.brush", brushmove).on("mouseup.brush", brushend); } g.interrupt().selectAll("*").interrupt(); if (dragging) { origin[0] = xExtent[0] - origin[0]; origin[1] = yExtent[0] - origin[1]; } else if (resizing) { var ex = +/w$/.test(resizing), ey = +/^n/.test(resizing); offset = [ xExtent[1 - ex] - origin[0], yExtent[1 - ey] - origin[1] ]; origin[0] = xExtent[ex]; origin[1] = yExtent[ey]; } else if (d3.event.altKey) center = origin.slice(); g.style("pointer-events", "none").selectAll(".resize").style("display", null); d3.select("body").style("cursor", eventTarget.style("cursor")); event_({ type: "brushstart" }); brushmove(); function keydown() { if (d3.event.keyCode == 32) { if (!dragging) { center = null; origin[0] -= xExtent[1]; origin[1] -= yExtent[1]; dragging = 2; } d3_eventPreventDefault(); } } function keyup() { if (d3.event.keyCode == 32 && dragging == 2) { origin[0] += xExtent[1]; origin[1] += yExtent[1]; dragging = 0; d3_eventPreventDefault(); } } function brushmove() { var point = d3.mouse(target), moved = false; if (offset) { point[0] += offset[0]; point[1] += offset[1]; } if (!dragging) { if (d3.event.altKey) { if (!center) center = [ (xExtent[0] + xExtent[1]) / 2, (yExtent[0] + yExtent[1]) / 2 ]; origin[0] = xExtent[+(point[0] < center[0])]; origin[1] = yExtent[+(point[1] < center[1])]; } else center = null; } if (resizingX && move1(point, x, 0)) { redrawX(g); moved = true; } if (resizingY && move1(point, y, 1)) { redrawY(g); moved = true; } if (moved) { redraw(g); event_({ type: "brush", mode: dragging ? "move" : "resize" }); } } function move1(point, scale, i) { 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; if (dragging) { r0 -= position; r1 -= size + position; } min = (i ? yClamp : xClamp) ? Math.max(r0, Math.min(r1, point[i])) : point[i]; if (dragging) { max = (min += position) + size; } else { if (center) position = Math.max(r0, Math.min(r1, 2 * center[i] - min)); if (position < min) { max = min; min = position; } else { max = position; } } if (extent[0] != min || extent[1] != max) { if (i) yExtentDomain = null; else xExtentDomain = null; extent[0] = min; extent[1] = max; return true; } } function brushend() { brushmove(); g.style("pointer-events", "all").selectAll(".resize").style("display", brush.empty() ? "none" : null); d3.select("body").style("cursor", null); 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); dragRestore(); event_({ type: "brushend" }); } } brush.x = function(z) { if (!arguments.length) return x; x = z; resizes = d3_svg_brushResizes[!x << 1 | !y]; return brush; }; brush.y = function(z) { if (!arguments.length) return y; y = z; resizes = d3_svg_brushResizes[!x << 1 | !y]; return brush; }; brush.clamp = function(z) { if (!arguments.length) return x && y ? [ xClamp, yClamp ] : x ? xClamp : y ? yClamp : null; if (x && y) xClamp = !!z[0], yClamp = !!z[1]; else if (x) xClamp = !!z; else if (y) yClamp = !!z; return brush; }; brush.extent = function(z) { var x0, x1, y0, y1, t; if (!arguments.length) { if (x) { if (xExtentDomain) { x0 = xExtentDomain[0], x1 = xExtentDomain[1]; } else { x0 = xExtent[0], x1 = xExtent[1]; if (x.invert) x0 = x.invert(x0), x1 = x.invert(x1); if (x1 < x0) t = x0, x0 = x1, x1 = t; } } if (y) { if (yExtentDomain) { y0 = yExtentDomain[0], y1 = yExtentDomain[1]; } else { y0 = yExtent[0], y1 = yExtent[1]; if (y.invert) y0 = y.invert(y0), y1 = y.invert(y1); if (y1 < y0) t = y0, y0 = y1, y1 = t; } } return x && y ? [ [ x0, y0 ], [ x1, y1 ] ] : x ? [ x0, x1 ] : y && [ y0, y1 ]; } if (x) { x0 = z[0], x1 = z[1]; if (y) x0 = x0[0], x1 = x1[0]; xExtentDomain = [ x0, x1 ]; if (x.invert) x0 = x(x0), x1 = x(x1); if (x1 < x0) t = x0, x0 = x1, x1 = t; if (x0 != xExtent[0] || x1 != xExtent[1]) xExtent = [ x0, x1 ]; } if (y) { y0 = z[0], y1 = z[1]; if (x) y0 = y0[1], y1 = y1[1]; yExtentDomain = [ y0, y1 ]; if (y.invert) y0 = y(y0), y1 = y(y1); if (y1 < y0) t = y0, y0 = y1, y1 = t; if (y0 != yExtent[0] || y1 != yExtent[1]) yExtent = [ y0, y1 ]; } return brush; }; brush.clear = function() { if (!brush.empty()) { xExtent = [ 0, 0 ], yExtent = [ 0, 0 ]; xExtentDomain = yExtentDomain = null; } return brush; }; brush.empty = function() { return !!x && xExtent[0] == xExtent[1] || !!y && yExtent[0] == yExtent[1]; }; return d3.rebind(brush, event, "on"); }; var d3_svg_brushCursor = { n: "ns-resize", e: "ew-resize", s: "ns-resize", w: "ew-resize", nw: "nwse-resize", ne: "nesw-resize", se: "nwse-resize", sw: "nesw-resize" }; var d3_svg_brushResizes = [ [ "n", "e", "s", "w", "nw", "ne", "se", "sw" ], [ "e", "w" ], [ "n", "s" ], [] ]; var d3_time_format = d3_time.format = d3_locale_enUS.timeFormat; var d3_time_formatUtc = d3_time_format.utc; var d3_time_formatIso = d3_time_formatUtc("%Y-%m-%dT%H:%M:%S.%LZ"); d3_time_format.iso = Date.prototype.toISOString && +new Date("2000-01-01T00:00:00.000Z") ? d3_time_formatIsoNative : d3_time_formatIso; function d3_time_formatIsoNative(date) { return date.toISOString(); } d3_time_formatIsoNative.parse = function(string) { var date = new Date(string); return isNaN(date) ? null : date; }; d3_time_formatIsoNative.toString = d3_time_formatIso.toString; d3_time.second = d3_time_interval(function(date) { return new d3_date(Math.floor(date / 1e3) * 1e3); }, function(date, offset) { date.setTime(date.getTime() + Math.floor(offset) * 1e3); }, function(date) { return date.getSeconds(); }); d3_time.seconds = d3_time.second.range; d3_time.seconds.utc = d3_time.second.utc.range; d3_time.minute = d3_time_interval(function(date) { return new d3_date(Math.floor(date / 6e4) * 6e4); }, function(date, offset) { date.setTime(date.getTime() + Math.floor(offset) * 6e4); }, function(date) { return date.getMinutes(); }); d3_time.minutes = d3_time.minute.range; d3_time.minutes.utc = d3_time.minute.utc.range; d3_time.hour = d3_time_interval(function(date) { var timezone = date.getTimezoneOffset() / 60; return new d3_date((Math.floor(date / 36e5 - timezone) + timezone) * 36e5); }, function(date, offset) { date.setTime(date.getTime() + Math.floor(offset) * 36e5); }, function(date) { return date.getHours(); }); d3_time.hours = d3_time.hour.range; d3_time.hours.utc = d3_time.hour.utc.range; d3_time.month = d3_time_interval(function(date) { date = d3_time.day(date); date.setDate(1); return date; }, function(date, offset) { date.setMonth(date.getMonth() + offset); }, function(date) { return date.getMonth(); }); d3_time.months = d3_time.month.range; d3_time.months.utc = d3_time.month.utc.range; function d3_time_scale(linear, methods, format) { function scale(x) { return linear(x); } scale.invert = function(x) { return d3_time_scaleDate(linear.invert(x)); }; scale.domain = function(x) { if (!arguments.length) return linear.domain().map(d3_time_scaleDate); linear.domain(x); return scale; }; function tickMethod(extent, count) { var span = extent[1] - extent[0], target = span / count, i = d3.bisect(d3_time_scaleSteps, target); return i == d3_time_scaleSteps.length ? [ methods.year, d3_scale_linearTickRange(extent.map(function(d) { return d / 31536e6; }), 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]; } scale.nice = function(interval, skip) { var domain = scale.domain(), extent = d3_scaleExtent(domain), method = interval == null ? tickMethod(extent, 10) : typeof interval === "number" && tickMethod(extent, interval); if (method) interval = method[0], skip = method[1]; function skipped(date) { return !isNaN(date) && !interval.range(date, d3_time_scaleDate(+date + 1), skip).length; } return scale.domain(d3_scale_nice(domain, skip > 1 ? { floor: function(date) { while (skipped(date = interval.floor(date))) date = d3_time_scaleDate(date - 1); return date; }, ceil: function(date) { while (skipped(date = interval.ceil(date))) date = d3_time_scaleDate(+date + 1); return date; } } : interval)); }; scale.ticks = function(interval, skip) { var extent = d3_scaleExtent(scale.domain()), method = interval == null ? tickMethod(extent, 10) : typeof interval === "number" ? tickMethod(extent, interval) : !interval.range && [ { range: interval }, skip ]; if (method) interval = method[0], skip = method[1]; return interval.range(extent[0], d3_time_scaleDate(+extent[1] + 1), skip < 1 ? 1 : skip); }; scale.tickFormat = function() { return format; }; scale.copy = function() { return d3_time_scale(linear.copy(), methods, format); }; return d3_scale_linearRebind(scale, linear); } function d3_time_scaleDate(t) { return new Date(t); } var d3_time_scaleSteps = [ 1e3, 5e3, 15e3, 3e4, 6e4, 3e5, 9e5, 18e5, 36e5, 108e5, 216e5, 432e5, 864e5, 1728e5, 6048e5, 2592e6, 7776e6, 31536e6 ]; 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 ] ]; var d3_time_scaleLocalFormat = d3_time_format.multi([ [ ".%L", function(d) { return d.getMilliseconds(); } ], [ ":%S", function(d) { return d.getSeconds(); } ], [ "%I:%M", function(d) { return d.getMinutes(); } ], [ "%I %p", function(d) { return d.getHours(); } ], [ "%a %d", function(d) { return d.getDay() && d.getDate() != 1; } ], [ "%b %d", function(d) { return d.getDate() != 1; } ], [ "%B", function(d) { return d.getMonth(); } ], [ "%Y", d3_true ] ]); var d3_time_scaleMilliseconds = { range: function(start, stop, step) { return d3.range(Math.ceil(start / step) * step, +stop, step).map(d3_time_scaleDate); }, floor: d3_identity, ceil: d3_identity }; d3_time_scaleLocalMethods.year = d3_time.year; d3_time.scale = function() { return d3_time_scale(d3.scale.linear(), d3_time_scaleLocalMethods, d3_time_scaleLocalFormat); }; var d3_time_scaleUtcMethods = d3_time_scaleLocalMethods.map(function(m) { return [ m[0].utc, m[1] ]; }); var d3_time_scaleUtcFormat = d3_time_formatUtc.multi([ [ ".%L", function(d) { return d.getUTCMilliseconds(); } ], [ ":%S", function(d) { return d.getUTCSeconds(); } ], [ "%I:%M", function(d) { return d.getUTCMinutes(); } ], [ "%I %p", function(d) { return d.getUTCHours(); } ], [ "%a %d", function(d) { return d.getUTCDay() && d.getUTCDate() != 1; } ], [ "%b %d", function(d) { return d.getUTCDate() != 1; } ], [ "%B", function(d) { return d.getUTCMonth(); } ], [ "%Y", d3_true ] ]); d3_time_scaleUtcMethods.year = d3_time.year.utc; d3_time.scale.utc = function() { return d3_time_scale(d3.scale.linear(), d3_time_scaleUtcMethods, d3_time_scaleUtcFormat); }; d3.text = d3_xhrType(function(request) { return request.responseText; }); d3.json = function(url, callback) { return d3_xhr(url, "application/json", d3_json, callback); }; function d3_json(request) { return JSON.parse(request.responseText); } d3.html = function(url, callback) { return d3_xhr(url, "text/html", d3_html, callback); }; function d3_html(request) { var range = d3_document.createRange(); range.selectNode(d3_document.body); return range.createContextualFragment(request.responseText); } d3.xml = d3_xhrType(function(request) { return request.responseXML; }); 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; }(); ================================================ FILE: code/web/d3test.html ================================================ D3 Test n stuff

Click me to randomize (add, delete, update) values.

Click me to add a value.

Click me to delete a value.

================================================ FILE: code/web/docker-compose.yml ================================================ version: '2' services: web: build: context: . dockerfile: ./Dockerfile ports: - "8000:8000" entrypoint: http-server -p 8000 -c-1 /app/ # interactive: true #environment: # DOCKER_CACHING_TIME: 5 # NODE_PORT: 4458 # NODE_DEBUGGER: 0 ================================================ FILE: code/web/entrypoint.sh ================================================ #!/usr/bin/env bash set -e; # first use first program parameter, if not set use $PORT, if that is undefined use default 8000. PORT=${PORT:-8000} PORT=${1:-$PORT} API_URL=${API_URL:-http://localhost} JS_PATH=${JS_PATH:-/app/} SECRET_FILE='src/config.js' echo "'use strict';" > $SECRET_FILE; echo "" >> $SECRET_FILE; echo "var _API_URL = \"$API_URL\";" >> $SECRET_FILE; echo "Starting server on port $PORT (\$PORT), serving path \"$JS_PATH\" (\$JS_PATH)." echo "The browser will connect to the API at \"$API_URL\" (\$API_URL)." COMMAND="http-server -p $PORT -c-1 $JS_PATH" echo "\$ $COMMAND" $COMMAND ================================================ FILE: code/web/example/api/v2/get_timeline/index.html ================================================ { "events": [ { "action": "send", "data": { "node": 1, "sequence_no": 298111723, "type": 1, "value": 7.23430061340332 }, "id": { "send": 68317 }, "nodes": { "send": 1 }, "timestamps": { "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.079226 } }, "type": "init" }, { "action": "acknowledge", "data": { "node": 1, "sequence_no": 298111723, "type": 1, "value": 7.23430061340332 }, "id": { "receive": 68318, "send": 68317 }, "nodes": { "receive": 1, "send": 1 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.117529 }, "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.079226 } }, "type": "init" }, { "action": "acknowledge", "data": { "node": 1, "sequence_no": 298111723, "type": 1, "value": 7.23430061340332 }, "id": { "receive": 68319, "send": 68317 }, "nodes": { "receive": 3, "send": 1 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.146206 }, "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.079226 } }, "type": "init" }, { "action": "acknowledge", "data": { "node": 1, "sequence_no": 298111723, "type": 1, "value": 7.23430061340332 }, "id": { "receive": 68320, "send": 68317 }, "nodes": { "receive": 4, "send": 1 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.160484 }, "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.079226 } }, "type": "init" }, { "action": "acknowledge", "data": { "node": 1, "sequence_no": 298111723, "type": 1, "value": 7.23430061340332 }, "id": { "receive": 68321, "send": 68317 }, "nodes": { "receive": 2, "send": 1 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.172507 }, "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.079226 } }, "type": "init" }, { "action": "send", "data": { "leader": 1, "node": 1, "proposal": 6.1647744178772, "sequence_no": 298111723, "type": 2, "value_store": [ { "node": 3, "sequence_no": 298111722, "type": 1, "value": 6.164774417877197 }, { "node": 2, "sequence_no": 298111722, "type": 1, "value": 3.569486618041992 }, { "node": 4, "sequence_no": 298111722, "type": 1, "value": 2.458043336868286 }, { "node": 1, "sequence_no": 298111722, "type": 1, "value": 6.970949649810791 }, { "node": 1, "sequence_no": 298111723, "type": 1, "value": 7.23430061340332 } ] }, "id": { "send": 68322 }, "nodes": { "send": 1 }, "timestamps": { "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.184613 } }, "type": "propose" }, { "action": "acknowledge", "data": { "leader": 1, "node": 1, "proposal": 6.164774417877197, "sequence_no": 298111723, "type": 2, "value_store": [ { "node": 3, "sequence_no": 298111722, "type": 1, "value": 6.164774417877197 }, { "node": 2, "sequence_no": 298111722, "type": 1, "value": 3.569486618041992 }, { "node": 4, "sequence_no": 298111722, "type": 1, "value": 2.458043336868286 }, { "node": 1, "sequence_no": 298111722, "type": 1, "value": 6.970949649810791 }, { "node": 1, "sequence_no": 298111723, "type": 1, "value": 7.23430061340332 } ] }, "id": { "receive": 68323, "send": 68322 }, "nodes": { "receive": 4, "send": 1 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.223817 }, "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.184613 } }, "type": "propose" }, { "action": "acknowledge", "data": { "leader": 1, "node": 1, "proposal": 6.164774417877197, "sequence_no": 298111723, "type": 2, "value_store": [ { "node": 3, "sequence_no": 298111722, "type": 1, "value": 6.164774417877197 }, { "node": 2, "sequence_no": 298111722, "type": 1, "value": 3.569486618041992 }, { "node": 4, "sequence_no": 298111722, "type": 1, "value": 2.458043336868286 }, { "node": 1, "sequence_no": 298111722, "type": 1, "value": 6.970949649810791 }, { "node": 1, "sequence_no": 298111723, "type": 1, "value": 7.23430061340332 } ] }, "id": { "receive": 68324, "send": 68322 }, "nodes": { "receive": 3, "send": 1 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.238699 }, "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.184613 } }, "type": "propose" }, { "action": "acknowledge", "data": { "leader": 1, "node": 1, "proposal": 6.164774417877197, "sequence_no": 298111723, "type": 2, "value_store": [ { "node": 3, "sequence_no": 298111722, "type": 1, "value": 6.164774417877197 }, { "node": 2, "sequence_no": 298111722, "type": 1, "value": 3.569486618041992 }, { "node": 4, "sequence_no": 298111722, "type": 1, "value": 2.458043336868286 }, { "node": 1, "sequence_no": 298111722, "type": 1, "value": 6.970949649810791 }, { "node": 1, "sequence_no": 298111723, "type": 1, "value": 7.23430061340332 } ] }, "id": { "receive": 68325, "send": 68322 }, "nodes": { "receive": 2, "send": 1 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.251722 }, "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.184613 } }, "type": "propose" }, { "action": "send", "data": { "leader": 1, "node": 1, "sequence_no": 298111723, "type": 3, "value": 6.1647744178772 }, "id": { "send": 68326 }, "nodes": { "send": 1 }, "timestamps": { "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.263576 } }, "type": "prevote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 1, "sequence_no": 298111723, "type": 3, "value": 6.164774417877197 }, "id": { "receive": 68327, "send": 68326 }, "nodes": { "receive": 4, "send": 1 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.297539 }, "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.263576 } }, "type": "prevote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 1, "sequence_no": 298111723, "type": 3, "value": 6.164774417877197 }, "id": { "receive": 68328, "send": 68326 }, "nodes": { "receive": 3, "send": 1 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.32096 }, "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.263576 } }, "type": "prevote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 1, "sequence_no": 298111723, "type": 3, "value": 6.164774417877197 }, "id": { "receive": 68329, "send": 68326 }, "nodes": { "receive": 2, "send": 1 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.348517 }, "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.263576 } }, "type": "prevote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 1, "proposal": 6.164774417877197, "sequence_no": 298111723, "type": 2, "value_store": [ { "node": 3, "sequence_no": 298111722, "type": 1, "value": 6.164774417877197 }, { "node": 2, "sequence_no": 298111722, "type": 1, "value": 3.569486618041992 }, { "node": 4, "sequence_no": 298111722, "type": 1, "value": 2.458043336868286 }, { "node": 1, "sequence_no": 298111722, "type": 1, "value": 6.970949649810791 }, { "node": 1, "sequence_no": 298111723, "type": 1, "value": 7.23430061340332 } ] }, "id": { "receive": 68330, "send": 68322 }, "nodes": { "receive": 1, "send": 1 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.370485 }, "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.184613 } }, "type": "propose" }, { "action": "send", "data": { "node": 3, "sequence_no": 298111723, "type": 1, "value": 0.694884359836578 }, "id": { "send": 68331 }, "nodes": { "send": 3 }, "timestamps": { "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.384545 } }, "type": "init" }, { "action": "acknowledge", "data": { "leader": 1, "node": 1, "sequence_no": 298111723, "type": 3, "value": 6.164774417877197 }, "id": { "receive": 68332, "send": 68326 }, "nodes": { "receive": 1, "send": 1 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.424323 }, "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.263576 } }, "type": "prevote" }, { "action": "acknowledge", "data": { "node": 3, "sequence_no": 298111723, "type": 1, "value": 0.6948843598365784 }, "id": { "receive": 68333, "send": 68331 }, "nodes": { "receive": 4, "send": 3 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.468844 }, "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.384545 } }, "type": "init" }, { "action": "acknowledge", "data": { "node": 3, "sequence_no": 298111723, "type": 1, "value": 0.6948843598365784 }, "id": { "receive": 68334, "send": 68331 }, "nodes": { "receive": 2, "send": 3 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.499564 }, "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.384545 } }, "type": "init" }, { "action": "acknowledge", "data": { "node": 3, "sequence_no": 298111723, "type": 1, "value": 0.6948843598365784 }, "id": { "receive": 68335, "send": 68331 }, "nodes": { "receive": 3, "send": 3 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.513264 }, "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.384545 } }, "type": "init" }, { "action": "send", "data": { "node": 4, "sequence_no": 298111723, "type": 1, "value": 7.75692510604858 }, "id": { "send": 68336 }, "nodes": { "send": 4 }, "timestamps": { "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.531546 } }, "type": "init" }, { "action": "send", "data": { "node": 2, "sequence_no": 298111723, "type": 1, "value": 1.71371591091156 }, "id": { "send": 68337 }, "nodes": { "send": 2 }, "timestamps": { "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.559259 } }, "type": "init" }, { "action": "acknowledge", "data": { "node": 3, "sequence_no": 298111723, "type": 1, "value": 0.6948843598365784 }, "id": { "receive": 68338, "send": 68331 }, "nodes": { "receive": 1, "send": 3 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.57986 }, "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.384545 } }, "type": "init" }, { "action": "send", "data": { "leader": 1, "node": 3, "sequence_no": 298111723, "type": 3, "value": 6.1647744178772 }, "id": { "send": 68339 }, "nodes": { "send": 3 }, "timestamps": { "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.598602 } }, "type": "prevote" }, { "action": "acknowledge", "data": { "node": 4, "sequence_no": 298111723, "type": 1, "value": 7.756925106048584 }, "id": { "receive": 68340, "send": 68336 }, "nodes": { "receive": 2, "send": 4 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.636808 }, "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.531546 } }, "type": "init" }, { "action": "acknowledge", "data": { "node": 4, "sequence_no": 298111723, "type": 1, "value": 7.756925106048584 }, "id": { "receive": 68341, "send": 68336 }, "nodes": { "receive": 4, "send": 4 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.680829 }, "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.531546 } }, "type": "init" }, { "action": "send", "data": { "leader": 1, "node": 2, "sequence_no": 298111723, "type": 3, "value": 6.1647744178772 }, "id": { "send": 68342 }, "nodes": { "send": 2 }, "timestamps": { "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.718341 } }, "type": "prevote" }, { "action": "acknowledge", "data": { "node": 4, "sequence_no": 298111723, "type": 1, "value": 7.756925106048584 }, "id": { "receive": 68343, "send": 68336 }, "nodes": { "receive": 1, "send": 4 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.74658 }, "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.531546 } }, "type": "init" }, { "action": "acknowledge", "data": { "node": 4, "sequence_no": 298111723, "type": 1, "value": 7.756925106048584 }, "id": { "receive": 68344, "send": 68336 }, "nodes": { "receive": 3, "send": 4 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.789794 }, "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.531546 } }, "type": "init" }, { "action": "send", "data": { "leader": 1, "node": 4, "sequence_no": 298111723, "type": 3, "value": 6.1647744178772 }, "id": { "send": 68345 }, "nodes": { "send": 4 }, "timestamps": { "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.825813 } }, "type": "prevote" }, { "action": "acknowledge", "data": { "node": 2, "sequence_no": 298111723, "type": 1, "value": 1.71371591091156 }, "id": { "receive": 68346, "send": 68337 }, "nodes": { "receive": 2, "send": 2 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.857244 }, "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.559259 } }, "type": "init" }, { "action": "acknowledge", "data": { "node": 2, "sequence_no": 298111723, "type": 1, "value": 1.71371591091156 }, "id": { "receive": 68347, "send": 68337 }, "nodes": { "receive": 3, "send": 2 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.894072 }, "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.559259 } }, "type": "init" }, { "action": "send", "data": { "leader": 1, "node": 1, "sequence_no": 298111723, "type": 4, "value": 6.1647744178772 }, "id": { "send": 68348 }, "nodes": { "send": 1 }, "timestamps": { "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.933549 } }, "type": "vote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 3, "sequence_no": 298111723, "type": 3, "value": 6.164774417877197 }, "id": { "receive": 68349, "send": 68339 }, "nodes": { "receive": 2, "send": 3 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.993445 }, "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.598602 } }, "type": "prevote" }, { "action": "acknowledge", "data": { "node": 2, "sequence_no": 298111723, "type": 1, "value": 1.71371591091156 }, "id": { "receive": 68350, "send": 68337 }, "nodes": { "receive": 4, "send": 2 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:36 GMT", "unix": 1490558616.036265 }, "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.559259 } }, "type": "init" }, { "action": "acknowledge", "data": { "leader": 1, "node": 3, "sequence_no": 298111723, "type": 3, "value": 6.164774417877197 }, "id": { "receive": 68351, "send": 68339 }, "nodes": { "receive": 3, "send": 3 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:36 GMT", "unix": 1490558616.113367 }, "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.598602 } }, "type": "prevote" }, { "action": "acknowledge", "data": { "node": 2, "sequence_no": 298111723, "type": 1, "value": 1.71371591091156 }, "id": { "receive": 68352, "send": 68337 }, "nodes": { "receive": 1, "send": 2 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:36 GMT", "unix": 1490558616.176518 }, "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.559259 } }, "type": "init" }, { "action": "acknowledge", "data": { "leader": 1, "node": 2, "sequence_no": 298111723, "type": 3, "value": 6.164774417877197 }, "id": { "receive": 68353, "send": 68342 }, "nodes": { "receive": 2, "send": 2 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:36 GMT", "unix": 1490558616.208524 }, "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.718341 } }, "type": "prevote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 3, "sequence_no": 298111723, "type": 3, "value": 6.164774417877197 }, "id": { "receive": 68354, "send": 68339 }, "nodes": { "receive": 4, "send": 3 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:36 GMT", "unix": 1490558616.242285 }, "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.598602 } }, "type": "prevote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 3, "sequence_no": 298111723, "type": 3, "value": 6.164774417877197 }, "id": { "receive": 68355, "send": 68339 }, "nodes": { "receive": 1, "send": 3 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:36 GMT", "unix": 1490558616.281475 }, "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.598602 } }, "type": "prevote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 2, "sequence_no": 298111723, "type": 3, "value": 6.164774417877197 }, "id": { "receive": 68356, "send": 68342 }, "nodes": { "receive": 3, "send": 2 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:36 GMT", "unix": 1490558616.319874 }, "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.718341 } }, "type": "prevote" }, { "action": "send", "data": { "leader": 1, "node": 2, "sequence_no": 298111723, "type": 4, "value": 6.1647744178772 }, "id": { "send": 68357 }, "nodes": { "send": 2 }, "timestamps": { "send": { "string": "Sun, 26 Mar 2017 20:03:36 GMT", "unix": 1490558616.344503 } }, "type": "vote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 2, "sequence_no": 298111723, "type": 3, "value": 6.164774417877197 }, "id": { "receive": 68358, "send": 68342 }, "nodes": { "receive": 1, "send": 2 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:36 GMT", "unix": 1490558616.368168 }, "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.718341 } }, "type": "prevote" }, { "action": "send", "data": { "leader": 1, "node": 4, "sequence_no": 298111723, "type": 4, "value": 6.1647744178772 }, "id": { "send": 68359 }, "nodes": { "send": 4 }, "timestamps": { "send": { "string": "Sun, 26 Mar 2017 20:03:36 GMT", "unix": 1490558616.422657 } }, "type": "vote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 4, "sequence_no": 298111723, "type": 3, "value": 6.164774417877197 }, "id": { "receive": 68360, "send": 68345 }, "nodes": { "receive": 2, "send": 4 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:36 GMT", "unix": 1490558616.446184 }, "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.825813 } }, "type": "prevote" }, { "action": "send", "data": { "leader": 1, "node": 3, "sequence_no": 298111723, "type": 4, "value": 6.1647744178772 }, "id": { "send": 68361 }, "nodes": { "send": 3 }, "timestamps": { "send": { "string": "Sun, 26 Mar 2017 20:03:36 GMT", "unix": 1490558616.46845 } }, "type": "vote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 4, "sequence_no": 298111723, "type": 3, "value": 6.164774417877197 }, "id": { "receive": 68362, "send": 68345 }, "nodes": { "receive": 1, "send": 4 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:36 GMT", "unix": 1490558616.50039 }, "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.825813 } }, "type": "prevote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 2, "sequence_no": 298111723, "type": 3, "value": 6.164774417877197 }, "id": { "receive": 68363, "send": 68342 }, "nodes": { "receive": 4, "send": 2 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:36 GMT", "unix": 1490558616.531405 }, "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.718341 } }, "type": "prevote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 1, "sequence_no": 298111723, "type": 4, "value": 6.164774417877197 }, "id": { "receive": 68364, "send": 68348 }, "nodes": { "receive": 2, "send": 1 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:36 GMT", "unix": 1490558616.549436 }, "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.933549 } }, "type": "vote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 4, "sequence_no": 298111723, "type": 3, "value": 6.164774417877197 }, "id": { "receive": 68365, "send": 68345 }, "nodes": { "receive": 3, "send": 4 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:36 GMT", "unix": 1490558616.568338 }, "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.825813 } }, "type": "prevote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 1, "sequence_no": 298111723, "type": 4, "value": 6.164774417877197 }, "id": { "receive": 68366, "send": 68348 }, "nodes": { "receive": 1, "send": 1 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:36 GMT", "unix": 1490558616.587922 }, "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.933549 } }, "type": "vote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 4, "sequence_no": 298111723, "type": 3, "value": 6.164774417877197 }, "id": { "receive": 68367, "send": 68345 }, "nodes": { "receive": 4, "send": 4 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:36 GMT", "unix": 1490558616.613553 }, "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.825813 } }, "type": "prevote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 2, "sequence_no": 298111723, "type": 4, "value": 6.164774417877197 }, "id": { "receive": 68368, "send": 68357 }, "nodes": { "receive": 2, "send": 2 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:36 GMT", "unix": 1490558616.65048 }, "send": { "string": "Sun, 26 Mar 2017 20:03:36 GMT", "unix": 1490558616.344503 } }, "type": "vote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 1, "sequence_no": 298111723, "type": 4, "value": 6.164774417877197 }, "id": { "receive": 68369, "send": 68348 }, "nodes": { "receive": 3, "send": 1 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:36 GMT", "unix": 1490558616.668285 }, "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.933549 } }, "type": "vote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 1, "sequence_no": 298111723, "type": 4, "value": 6.164774417877197 }, "id": { "receive": 68370, "send": 68348 }, "nodes": { "receive": 4, "send": 1 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:36 GMT", "unix": 1490558616.695515 }, "send": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.933549 } }, "type": "vote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 2, "sequence_no": 298111723, "type": 4, "value": 6.164774417877197 }, "id": { "receive": 68371, "send": 68357 }, "nodes": { "receive": 1, "send": 2 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:36 GMT", "unix": 1490558616.729508 }, "send": { "string": "Sun, 26 Mar 2017 20:03:36 GMT", "unix": 1490558616.344503 } }, "type": "vote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 4, "sequence_no": 298111723, "type": 4, "value": 6.164774417877197 }, "id": { "receive": 68372, "send": 68359 }, "nodes": { "receive": 2, "send": 4 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:36 GMT", "unix": 1490558616.772382 }, "send": { "string": "Sun, 26 Mar 2017 20:03:36 GMT", "unix": 1490558616.422657 } }, "type": "vote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 2, "sequence_no": 298111723, "type": 4, "value": 6.164774417877197 }, "id": { "receive": 68373, "send": 68357 }, "nodes": { "receive": 3, "send": 2 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:36 GMT", "unix": 1490558616.808814 }, "send": { "string": "Sun, 26 Mar 2017 20:03:36 GMT", "unix": 1490558616.344503 } }, "type": "vote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 2, "sequence_no": 298111723, "type": 4, "value": 6.164774417877197 }, "id": { "receive": 68374, "send": 68357 }, "nodes": { "receive": 4, "send": 2 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:36 GMT", "unix": 1490558616.849705 }, "send": { "string": "Sun, 26 Mar 2017 20:03:36 GMT", "unix": 1490558616.344503 } }, "type": "vote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 4, "sequence_no": 298111723, "type": 4, "value": 6.164774417877197 }, "id": { "receive": 68375, "send": 68359 }, "nodes": { "receive": 1, "send": 4 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:36 GMT", "unix": 1490558616.912457 }, "send": { "string": "Sun, 26 Mar 2017 20:03:36 GMT", "unix": 1490558616.422657 } }, "type": "vote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 4, "sequence_no": 298111723, "type": 4, "value": 6.164774417877197 }, "id": { "receive": 68376, "send": 68359 }, "nodes": { "receive": 3, "send": 4 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:36 GMT", "unix": 1490558616.978688 }, "send": { "string": "Sun, 26 Mar 2017 20:03:36 GMT", "unix": 1490558616.422657 } }, "type": "vote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 4, "sequence_no": 298111723, "type": 4, "value": 6.164774417877197 }, "id": { "receive": 68377, "send": 68359 }, "nodes": { "receive": 4, "send": 4 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:37 GMT", "unix": 1490558617.066265 }, "send": { "string": "Sun, 26 Mar 2017 20:03:36 GMT", "unix": 1490558616.422657 } }, "type": "vote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 3, "sequence_no": 298111723, "type": 4, "value": 6.164774417877197 }, "id": { "receive": 68378, "send": 68361 }, "nodes": { "receive": 1, "send": 3 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:37 GMT", "unix": 1490558617.110159 }, "send": { "string": "Sun, 26 Mar 2017 20:03:36 GMT", "unix": 1490558616.46845 } }, "type": "vote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 3, "sequence_no": 298111723, "type": 4, "value": 6.164774417877197 }, "id": { "receive": 68379, "send": 68361 }, "nodes": { "receive": 3, "send": 3 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:37 GMT", "unix": 1490558617.167484 }, "send": { "string": "Sun, 26 Mar 2017 20:03:36 GMT", "unix": 1490558616.46845 } }, "type": "vote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 3, "sequence_no": 298111723, "type": 4, "value": 6.164774417877197 }, "id": { "receive": 68380, "send": 68361 }, "nodes": { "receive": 2, "send": 3 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:37 GMT", "unix": 1490558617.179415 }, "send": { "string": "Sun, 26 Mar 2017 20:03:36 GMT", "unix": 1490558616.46845 } }, "type": "vote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 3, "sequence_no": 298111723, "type": 4, "value": 6.164774417877197 }, "id": { "receive": 68381, "send": 68361 }, "nodes": { "receive": 4, "send": 3 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:37 GMT", "unix": 1490558617.190296 }, "send": { "string": "Sun, 26 Mar 2017 20:03:36 GMT", "unix": 1490558616.46845 } }, "type": "vote" }, { "action": "send", "data": { "node": 1, "sequence_no": 298111724, "type": 1, "value": 4.35809087753296 }, "id": { "send": 68382 }, "nodes": { "send": 1 }, "timestamps": { "send": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.060954 } }, "type": "init" }, { "action": "acknowledge", "data": { "node": 1, "sequence_no": 298111724, "type": 1, "value": 4.358090877532959 }, "id": { "receive": 68383, "send": 68382 }, "nodes": { "receive": 1, "send": 1 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.0892 }, "send": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.060954 } }, "type": "init" }, { "action": "acknowledge", "data": { "node": 1, "sequence_no": 298111724, "type": 1, "value": 4.358090877532959 }, "id": { "receive": 68384, "send": 68382 }, "nodes": { "receive": 4, "send": 1 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.125562 }, "send": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.060954 } }, "type": "init" }, { "action": "acknowledge", "data": { "node": 1, "sequence_no": 298111724, "type": 1, "value": 4.358090877532959 }, "id": { "receive": 68385, "send": 68382 }, "nodes": { "receive": 2, "send": 1 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.171997 }, "send": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.060954 } }, "type": "init" }, { "action": "acknowledge", "data": { "node": 1, "sequence_no": 298111724, "type": 1, "value": 4.358090877532959 }, "id": { "receive": 68386, "send": 68382 }, "nodes": { "receive": 3, "send": 1 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.203967 }, "send": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.060954 } }, "type": "init" }, { "action": "send", "data": { "node": 3, "sequence_no": 298111724, "type": 1, "value": 7.8886079788208 }, "id": { "send": 68387 }, "nodes": { "send": 3 }, "timestamps": { "send": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.222616 } }, "type": "init" }, { "action": "send", "data": { "leader": 1, "node": 1, "proposal": 4.35809087753296, "sequence_no": 298111724, "type": 2, "value_store": [ { "node": 1, "sequence_no": 298111723, "type": 1, "value": 7.23430061340332 }, { "node": 3, "sequence_no": 298111723, "type": 1, "value": 0.6948843598365784 }, { "node": 4, "sequence_no": 298111723, "type": 1, "value": 7.756925106048584 }, { "node": 2, "sequence_no": 298111723, "type": 1, "value": 1.71371591091156 }, { "node": 1, "sequence_no": 298111724, "type": 1, "value": 4.358090877532959 } ] }, "id": { "send": 68388 }, "nodes": { "send": 1 }, "timestamps": { "send": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.25346 } }, "type": "propose" }, { "action": "send", "data": { "node": 2, "sequence_no": 298111724, "type": 1, "value": 9.73530006408691 }, "id": { "send": 68389 }, "nodes": { "send": 2 }, "timestamps": { "send": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.2805 } }, "type": "init" }, { "action": "send", "data": { "node": 4, "sequence_no": 298111724, "type": 1, "value": 0.359470218420029 }, "id": { "send": 68390 }, "nodes": { "send": 4 }, "timestamps": { "send": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.306264 } }, "type": "init" }, { "action": "acknowledge", "data": { "node": 3, "sequence_no": 298111724, "type": 1, "value": 7.888607978820801 }, "id": { "receive": 68391, "send": 68387 }, "nodes": { "receive": 4, "send": 3 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.333955 }, "send": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.222616 } }, "type": "init" }, { "action": "acknowledge", "data": { "node": 3, "sequence_no": 298111724, "type": 1, "value": 7.888607978820801 }, "id": { "receive": 68392, "send": 68387 }, "nodes": { "receive": 3, "send": 3 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.352303 }, "send": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.222616 } }, "type": "init" }, { "action": "acknowledge", "data": { "node": 3, "sequence_no": 298111724, "type": 1, "value": 7.888607978820801 }, "id": { "receive": 68393, "send": 68387 }, "nodes": { "receive": 2, "send": 3 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.376673 }, "send": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.222616 } }, "type": "init" }, { "action": "send", "data": { "leader": 1, "node": 1, "sequence_no": 298111724, "type": 3, "value": 4.35809087753296 }, "id": { "send": 68394 }, "nodes": { "send": 1 }, "timestamps": { "send": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.409385 } }, "type": "prevote" }, { "action": "acknowledge", "data": { "node": 2, "sequence_no": 298111724, "type": 1, "value": 9.735300064086914 }, "id": { "receive": 68395, "send": 68389 }, "nodes": { "receive": 4, "send": 2 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.437733 }, "send": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.2805 } }, "type": "init" }, { "action": "acknowledge", "data": { "node": 2, "sequence_no": 298111724, "type": 1, "value": 9.735300064086914 }, "id": { "receive": 68396, "send": 68389 }, "nodes": { "receive": 3, "send": 2 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.485383 }, "send": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.2805 } }, "type": "init" }, { "action": "acknowledge", "data": { "node": 2, "sequence_no": 298111724, "type": 1, "value": 9.735300064086914 }, "id": { "receive": 68397, "send": 68389 }, "nodes": { "receive": 2, "send": 2 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.536161 }, "send": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.2805 } }, "type": "init" }, { "action": "send", "data": { "leader": 1, "node": 4, "sequence_no": 298111724, "type": 3, "value": 4.35809087753296 }, "id": { "send": 68398 }, "nodes": { "send": 4 }, "timestamps": { "send": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.564023 } }, "type": "prevote" }, { "action": "acknowledge", "data": { "node": 3, "sequence_no": 298111724, "type": 1, "value": 7.888607978820801 }, "id": { "receive": 68399, "send": 68387 }, "nodes": { "receive": 1, "send": 3 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.587171 }, "send": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.222616 } }, "type": "init" }, { "action": "send", "data": { "leader": 1, "node": 3, "sequence_no": 298111724, "type": 3, "value": 4.35809087753296 }, "id": { "send": 68400 }, "nodes": { "send": 3 }, "timestamps": { "send": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.602183 } }, "type": "prevote" }, { "action": "send", "data": { "leader": 1, "node": 2, "sequence_no": 298111724, "type": 3, "value": 4.35809087753296 }, "id": { "send": 68401 }, "nodes": { "send": 2 }, "timestamps": { "send": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.729595 } }, "type": "prevote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 1, "proposal": 4.358090877532959, "sequence_no": 298111724, "type": 2, "value_store": [ { "node": 1, "sequence_no": 298111723, "type": 1, "value": 7.23430061340332 }, { "node": 3, "sequence_no": 298111723, "type": 1, "value": 0.6948843598365784 }, { "node": 4, "sequence_no": 298111723, "type": 1, "value": 7.756925106048584 }, { "node": 2, "sequence_no": 298111723, "type": 1, "value": 1.71371591091156 }, { "node": 1, "sequence_no": 298111724, "type": 1, "value": 4.358090877532959 } ] }, "id": { "receive": 68402, "send": 68388 }, "nodes": { "receive": 2, "send": 1 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.959672 }, "send": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.25346 } }, "type": "propose" }, { "action": "acknowledge", "data": { "leader": 1, "node": 1, "proposal": 4.358090877532959, "sequence_no": 298111724, "type": 2, "value_store": [ { "node": 1, "sequence_no": 298111723, "type": 1, "value": 7.23430061340332 }, { "node": 3, "sequence_no": 298111723, "type": 1, "value": 0.6948843598365784 }, { "node": 4, "sequence_no": 298111723, "type": 1, "value": 7.756925106048584 }, { "node": 2, "sequence_no": 298111723, "type": 1, "value": 1.71371591091156 }, { "node": 1, "sequence_no": 298111724, "type": 1, "value": 4.358090877532959 } ] }, "id": { "receive": 68403, "send": 68388 }, "nodes": { "receive": 3, "send": 1 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:41 GMT", "unix": 1490558621.036251 }, "send": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.25346 } }, "type": "propose" }, { "action": "acknowledge", "data": { "node": 2, "sequence_no": 298111724, "type": 1, "value": 9.735300064086914 }, "id": { "receive": 68404, "send": 68389 }, "nodes": { "receive": 1, "send": 2 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:41 GMT", "unix": 1490558621.114397 }, "send": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.2805 } }, "type": "init" }, { "action": "acknowledge", "data": { "node": 4, "sequence_no": 298111724, "type": 1, "value": 0.3594702184200287 }, "id": { "receive": 68405, "send": 68390 }, "nodes": { "receive": 2, "send": 4 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:41 GMT", "unix": 1490558621.148923 }, "send": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.306264 } }, "type": "init" }, { "action": "send", "data": { "leader": 1, "node": 3, "sequence_no": 298111724, "type": 4, "value": 6.1647744178772 }, "id": { "send": 68406 }, "nodes": { "send": 3 }, "timestamps": { "send": { "string": "Sun, 26 Mar 2017 20:03:41 GMT", "unix": 1490558621.209692 } }, "type": "vote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 1, "sequence_no": 298111724, "type": 3, "value": 4.358090877532959 }, "id": { "receive": 68407, "send": 68394 }, "nodes": { "receive": 2, "send": 1 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:41 GMT", "unix": 1490558621.318121 }, "send": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.409385 } }, "type": "prevote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 1, "proposal": 4.358090877532959, "sequence_no": 298111724, "type": 2, "value_store": [ { "node": 1, "sequence_no": 298111723, "type": 1, "value": 7.23430061340332 }, { "node": 3, "sequence_no": 298111723, "type": 1, "value": 0.6948843598365784 }, { "node": 4, "sequence_no": 298111723, "type": 1, "value": 7.756925106048584 }, { "node": 2, "sequence_no": 298111723, "type": 1, "value": 1.71371591091156 }, { "node": 1, "sequence_no": 298111724, "type": 1, "value": 4.358090877532959 } ] }, "id": { "receive": 68408, "send": 68388 }, "nodes": { "receive": 4, "send": 1 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:41 GMT", "unix": 1490558621.413337 }, "send": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.25346 } }, "type": "propose" }, { "action": "acknowledge", "data": { "node": 4, "sequence_no": 298111724, "type": 1, "value": 0.3594702184200287 }, "id": { "receive": 68409, "send": 68390 }, "nodes": { "receive": 3, "send": 4 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:41 GMT", "unix": 1490558621.464501 }, "send": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.306264 } }, "type": "init" }, { "action": "send", "data": { "leader": 1, "node": 1, "sequence_no": 298111724, "type": 4, "value": 6.1647744178772 }, "id": { "send": 68410 }, "nodes": { "send": 1 }, "timestamps": { "send": { "string": "Sun, 26 Mar 2017 20:03:41 GMT", "unix": 1490558621.524051 } }, "type": "vote" }, { "action": "send", "data": { "leader": 1, "node": 2, "sequence_no": 298111724, "type": 4, "value": 6.1647744178772 }, "id": { "send": 68411 }, "nodes": { "send": 2 }, "timestamps": { "send": { "string": "Sun, 26 Mar 2017 20:03:41 GMT", "unix": 1490558621.553096 } }, "type": "vote" }, { "action": "send", "data": { "leader": 1, "node": 4, "sequence_no": 298111724, "type": 4, "value": 6.1647744178772 }, "id": { "send": 68412 }, "nodes": { "send": 4 }, "timestamps": { "send": { "string": "Sun, 26 Mar 2017 20:03:41 GMT", "unix": 1490558621.609441 } }, "type": "vote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 1, "sequence_no": 298111724, "type": 3, "value": 4.358090877532959 }, "id": { "receive": 68413, "send": 68394 }, "nodes": { "receive": 3, "send": 1 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:41 GMT", "unix": 1490558621.664591 }, "send": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.409385 } }, "type": "prevote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 1, "proposal": 4.358090877532959, "sequence_no": 298111724, "type": 2, "value_store": [ { "node": 1, "sequence_no": 298111723, "type": 1, "value": 7.23430061340332 }, { "node": 3, "sequence_no": 298111723, "type": 1, "value": 0.6948843598365784 }, { "node": 4, "sequence_no": 298111723, "type": 1, "value": 7.756925106048584 }, { "node": 2, "sequence_no": 298111723, "type": 1, "value": 1.71371591091156 }, { "node": 1, "sequence_no": 298111724, "type": 1, "value": 4.358090877532959 } ] }, "id": { "receive": 68414, "send": 68388 }, "nodes": { "receive": 1, "send": 1 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:41 GMT", "unix": 1490558621.703477 }, "send": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.25346 } }, "type": "propose" }, { "action": "acknowledge", "data": { "leader": 1, "node": 4, "sequence_no": 298111724, "type": 3, "value": 4.358090877532959 }, "id": { "receive": 68415, "send": 68398 }, "nodes": { "receive": 2, "send": 4 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:41 GMT", "unix": 1490558621.732756 }, "send": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.564023 } }, "type": "prevote" }, { "action": "acknowledge", "data": { "node": 4, "sequence_no": 298111724, "type": 1, "value": 0.3594702184200287 }, "id": { "receive": 68416, "send": 68390 }, "nodes": { "receive": 4, "send": 4 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:41 GMT", "unix": 1490558621.788268 }, "send": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.306264 } }, "type": "init" }, { "action": "acknowledge", "data": { "leader": 1, "node": 4, "sequence_no": 298111724, "type": 3, "value": 4.358090877532959 }, "id": { "receive": 68417, "send": 68398 }, "nodes": { "receive": 3, "send": 4 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:41 GMT", "unix": 1490558621.822536 }, "send": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.564023 } }, "type": "prevote" }, { "action": "acknowledge", "data": { "node": 4, "sequence_no": 298111724, "type": 1, "value": 0.3594702184200287 }, "id": { "receive": 68418, "send": 68390 }, "nodes": { "receive": 1, "send": 4 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:41 GMT", "unix": 1490558621.864831 }, "send": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.306264 } }, "type": "init" }, { "action": "acknowledge", "data": { "leader": 1, "node": 3, "sequence_no": 298111724, "type": 3, "value": 4.358090877532959 }, "id": { "receive": 68419, "send": 68400 }, "nodes": { "receive": 2, "send": 3 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:41 GMT", "unix": 1490558621.9004 }, "send": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.602183 } }, "type": "prevote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 1, "sequence_no": 298111724, "type": 3, "value": 4.358090877532959 }, "id": { "receive": 68420, "send": 68394 }, "nodes": { "receive": 4, "send": 1 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:41 GMT", "unix": 1490558621.94405 }, "send": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.409385 } }, "type": "prevote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 3, "sequence_no": 298111724, "type": 3, "value": 4.358090877532959 }, "id": { "receive": 68421, "send": 68400 }, "nodes": { "receive": 3, "send": 3 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:41 GMT", "unix": 1490558621.976853 }, "send": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.602183 } }, "type": "prevote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 1, "sequence_no": 298111724, "type": 3, "value": 4.358090877532959 }, "id": { "receive": 68422, "send": 68394 }, "nodes": { "receive": 1, "send": 1 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:42 GMT", "unix": 1490558622.015507 }, "send": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.409385 } }, "type": "prevote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 2, "sequence_no": 298111724, "type": 3, "value": 4.358090877532959 }, "id": { "receive": 68423, "send": 68401 }, "nodes": { "receive": 2, "send": 2 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:42 GMT", "unix": 1490558622.044734 }, "send": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.729595 } }, "type": "prevote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 4, "sequence_no": 298111724, "type": 3, "value": 4.358090877532959 }, "id": { "receive": 68424, "send": 68398 }, "nodes": { "receive": 4, "send": 4 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:42 GMT", "unix": 1490558622.082456 }, "send": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.564023 } }, "type": "prevote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 2, "sequence_no": 298111724, "type": 3, "value": 4.358090877532959 }, "id": { "receive": 68425, "send": 68401 }, "nodes": { "receive": 3, "send": 2 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:42 GMT", "unix": 1490558622.112521 }, "send": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.729595 } }, "type": "prevote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 4, "sequence_no": 298111724, "type": 3, "value": 4.358090877532959 }, "id": { "receive": 68426, "send": 68398 }, "nodes": { "receive": 1, "send": 4 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:42 GMT", "unix": 1490558622.152662 }, "send": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.564023 } }, "type": "prevote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 3, "sequence_no": 298111724, "type": 4, "value": 6.164774417877197 }, "id": { "receive": 68427, "send": 68406 }, "nodes": { "receive": 2, "send": 3 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:42 GMT", "unix": 1490558622.180283 }, "send": { "string": "Sun, 26 Mar 2017 20:03:41 GMT", "unix": 1490558621.209692 } }, "type": "vote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 3, "sequence_no": 298111724, "type": 3, "value": 4.358090877532959 }, "id": { "receive": 68428, "send": 68400 }, "nodes": { "receive": 4, "send": 3 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:42 GMT", "unix": 1490558622.260693 }, "send": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.602183 } }, "type": "prevote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 3, "sequence_no": 298111724, "type": 4, "value": 6.164774417877197 }, "id": { "receive": 68429, "send": 68406 }, "nodes": { "receive": 3, "send": 3 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:42 GMT", "unix": 1490558622.293036 }, "send": { "string": "Sun, 26 Mar 2017 20:03:41 GMT", "unix": 1490558621.209692 } }, "type": "vote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 3, "sequence_no": 298111724, "type": 3, "value": 4.358090877532959 }, "id": { "receive": 68430, "send": 68400 }, "nodes": { "receive": 1, "send": 3 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:42 GMT", "unix": 1490558622.341159 }, "send": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.602183 } }, "type": "prevote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 1, "sequence_no": 298111724, "type": 4, "value": 6.164774417877197 }, "id": { "receive": 68431, "send": 68410 }, "nodes": { "receive": 2, "send": 1 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:42 GMT", "unix": 1490558622.42285 }, "send": { "string": "Sun, 26 Mar 2017 20:03:41 GMT", "unix": 1490558621.524051 } }, "type": "vote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 2, "sequence_no": 298111724, "type": 3, "value": 4.358090877532959 }, "id": { "receive": 68432, "send": 68401 }, "nodes": { "receive": 4, "send": 2 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:42 GMT", "unix": 1490558622.474849 }, "send": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.729595 } }, "type": "prevote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 1, "sequence_no": 298111724, "type": 4, "value": 6.164774417877197 }, "id": { "receive": 68433, "send": 68410 }, "nodes": { "receive": 3, "send": 1 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:42 GMT", "unix": 1490558622.534648 }, "send": { "string": "Sun, 26 Mar 2017 20:03:41 GMT", "unix": 1490558621.524051 } }, "type": "vote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 2, "sequence_no": 298111724, "type": 3, "value": 4.358090877532959 }, "id": { "receive": 68434, "send": 68401 }, "nodes": { "receive": 1, "send": 2 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:42 GMT", "unix": 1490558622.575433 }, "send": { "string": "Sun, 26 Mar 2017 20:03:40 GMT", "unix": 1490558620.729595 } }, "type": "prevote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 2, "sequence_no": 298111724, "type": 4, "value": 6.164774417877197 }, "id": { "receive": 68435, "send": 68411 }, "nodes": { "receive": 2, "send": 2 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:42 GMT", "unix": 1490558622.616609 }, "send": { "string": "Sun, 26 Mar 2017 20:03:41 GMT", "unix": 1490558621.553096 } }, "type": "vote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 3, "sequence_no": 298111724, "type": 4, "value": 6.164774417877197 }, "id": { "receive": 68436, "send": 68406 }, "nodes": { "receive": 4, "send": 3 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:42 GMT", "unix": 1490558622.655002 }, "send": { "string": "Sun, 26 Mar 2017 20:03:41 GMT", "unix": 1490558621.209692 } }, "type": "vote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 2, "sequence_no": 298111724, "type": 4, "value": 6.164774417877197 }, "id": { "receive": 68437, "send": 68411 }, "nodes": { "receive": 3, "send": 2 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:42 GMT", "unix": 1490558622.705866 }, "send": { "string": "Sun, 26 Mar 2017 20:03:41 GMT", "unix": 1490558621.553096 } }, "type": "vote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 3, "sequence_no": 298111724, "type": 4, "value": 6.164774417877197 }, "id": { "receive": 68438, "send": 68406 }, "nodes": { "receive": 1, "send": 3 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:42 GMT", "unix": 1490558622.753005 }, "send": { "string": "Sun, 26 Mar 2017 20:03:41 GMT", "unix": 1490558621.209692 } }, "type": "vote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 4, "sequence_no": 298111724, "type": 4, "value": 6.164774417877197 }, "id": { "receive": 68439, "send": 68412 }, "nodes": { "receive": 2, "send": 4 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:42 GMT", "unix": 1490558622.790398 }, "send": { "string": "Sun, 26 Mar 2017 20:03:41 GMT", "unix": 1490558621.609441 } }, "type": "vote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 1, "sequence_no": 298111724, "type": 4, "value": 6.164774417877197 }, "id": { "receive": 68440, "send": 68410 }, "nodes": { "receive": 4, "send": 1 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:42 GMT", "unix": 1490558622.820384 }, "send": { "string": "Sun, 26 Mar 2017 20:03:41 GMT", "unix": 1490558621.524051 } }, "type": "vote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 4, "sequence_no": 298111724, "type": 4, "value": 6.164774417877197 }, "id": { "receive": 68441, "send": 68412 }, "nodes": { "receive": 3, "send": 4 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:42 GMT", "unix": 1490558622.866261 }, "send": { "string": "Sun, 26 Mar 2017 20:03:41 GMT", "unix": 1490558621.609441 } }, "type": "vote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 2, "sequence_no": 298111724, "type": 4, "value": 6.164774417877197 }, "id": { "receive": 68442, "send": 68411 }, "nodes": { "receive": 4, "send": 2 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:42 GMT", "unix": 1490558622.885713 }, "send": { "string": "Sun, 26 Mar 2017 20:03:41 GMT", "unix": 1490558621.553096 } }, "type": "vote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 1, "sequence_no": 298111724, "type": 4, "value": 6.164774417877197 }, "id": { "receive": 68443, "send": 68410 }, "nodes": { "receive": 1, "send": 1 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:42 GMT", "unix": 1490558622.922574 }, "send": { "string": "Sun, 26 Mar 2017 20:03:41 GMT", "unix": 1490558621.524051 } }, "type": "vote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 4, "sequence_no": 298111724, "type": 4, "value": 6.164774417877197 }, "id": { "receive": 68444, "send": 68412 }, "nodes": { "receive": 4, "send": 4 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:42 GMT", "unix": 1490558622.952755 }, "send": { "string": "Sun, 26 Mar 2017 20:03:41 GMT", "unix": 1490558621.609441 } }, "type": "vote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 2, "sequence_no": 298111724, "type": 4, "value": 6.164774417877197 }, "id": { "receive": 68445, "send": 68411 }, "nodes": { "receive": 1, "send": 2 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:42 GMT", "unix": 1490558622.982509 }, "send": { "string": "Sun, 26 Mar 2017 20:03:41 GMT", "unix": 1490558621.553096 } }, "type": "vote" }, { "action": "acknowledge", "data": { "leader": 1, "node": 4, "sequence_no": 298111724, "type": 4, "value": 6.164774417877197 }, "id": { "receive": 68446, "send": 68412 }, "nodes": { "receive": 1, "send": 4 }, "timestamps": { "receive": { "string": "Sun, 26 Mar 2017 20:03:43 GMT", "unix": 1490558623.041606 }, "send": { "string": "Sun, 26 Mar 2017 20:03:41 GMT", "unix": 1490558621.609441 } }, "type": "vote" } ], "nodes": [ 1, 2, 3, 4 ], "timestamps": { "max": { "string": "Sun, 26 Mar 2017 20:03:43 GMT", "unix": 1490558623.041606 }, "min": { "string": "Sun, 26 Mar 2017 20:03:35 GMT", "unix": 1490558615.079226 } } } ================================================ FILE: code/web/example/nodes.json ================================================ [{ "id": 1, "value": 0.5, "primary": true }, { "id": 2, "value": 0.6, "primary": false }, { "id": 3, "value": 0.5, "primary": false }, { "id": 4, "value": 0.5, "primary": false }, { "id": "summary", "value": 0.5 }] ================================================ FILE: code/web/index.html ================================================ pbft gui

Summary

Agreed Value:
???

Node 1

Value:
???

Node 2

Value:
???

Node 3

Value:
???

Node 4

Value:
???
================================================ FILE: code/web/js.js ================================================ /** * Created by luckydonald on 25/10/16. */ $( document ).ready(function(){ setInterval( function () { $.getJSON("http://localhost/get_value/", function (data) { //TODO host var container = $("#nodearea"); container.empty(); console.log(data); var node = $("
"); node.addClass("node").addClass("summary"); node.append($("

").text("Summary")); node.append("

Agreed Value:
"); if("summary" in data) { node.append($("").text(data["summary"]).addClass("value")); } else { node.append($("").text("No recent agreement").addClass("value")); } container.prepend(node); Object.keys(data).forEach(function (key, value) { if (key === "summary") { return; } var node = $("
"); node.addClass("node"); node.append($("

").text("Node " + key)); node.append("

Value:
"); node.append($("").text(this[key]).addClass("value")); container.append(node); }, data); }); }, 100); }); ================================================ FILE: code/web/package.json ================================================ { "name": "pbft-gui", "private": true, "version": "0.0.0", "description": "Web GUI for PBFT", "repository": "https://github.com/luckydonald/pbft", "license": "MIT", "devDependencies": { "bower": "^1.7.7", "http-server": "^0.9.0" }, "scripts": { "postinstall": "bower install", "prestart": "npm install", "start": "http-server -p 8000 -c-1 /code" } } ================================================ FILE: code/web/src/app.animations.css ================================================ .view-frame { position: relative; } .view-frame.ng-enter, .view-frame.ng-leave { position: absolute; left: 0; right: 0; top: inherit; } .view-frame.ng-enter { animation: 0.5s fade-in; z-index: 100; } .view-frame.ng-leave { animation: 0.5s fade-out; z-index: 99; } @keyframes fade-in { from { opacity: 0; } to { opacity: 1; } } @keyframes fade-out { from { opacity: 1; } to { opacity: 0; } } .node.ng-enter, .node.ng-leave, .node.ng-move { transition: 0.25s linear all; } .node.ng-enter, .node.ng-move { width: 0; opacity: 0; overflow: hidden; } .node.ng-enter.ng-enter-active, .node.ng-move.ng-move-active { width: 120px; opacity: 1; } .node.ng-leave { opacity: 1; overflow: hidden; } .node.ng-leave.ng-leave-active { width: 0; opacity: 0; padding: 0; } ================================================ FILE: code/web/src/app.animations.js ================================================ /** * Created by PlayingBacon on 30.10.2016. */ ================================================ FILE: code/web/src/app.animations.less ================================================ .view-frame { position: relative; &.ng-enter, &.ng-leave { position: absolute; left: 0; right: 0; top: inherit; } &.ng-enter { animation: 0.5s fade-in; z-index: 100; } &.ng-leave { animation: 0.5s fade-out; z-index: 99; } } @keyframes fade-in { from {opacity: 0;} to {opacity: 1;} } @keyframes fade-out { from {opacity: 1;} to {opacity: 0;} } .node { &.ng-enter, &.ng-leave, &.ng-move { transition: 0.25s linear all; } &.ng-enter, &.ng-move { width: 0; opacity: 0; overflow: hidden; } &.ng-enter.ng-enter-active, &.ng-move.ng-move-active { width: 120px; opacity: 1; } &.ng-leave { opacity: 1; overflow: hidden; &.ng-leave-active { width: 0; opacity: 0; padding: 0; } } } ================================================ FILE: code/web/src/app.config.js ================================================ /** * Created by PlayingBacon on 27.10.2016. */ 'use strict'; angular. module('pbftGui'). config(['$locationProvider', '$routeProvider', function($locationProvider, $routeProvider, $routeParams) { $locationProvider.hashPrefix('!'); $routeProvider. when('/nodes', { template: '' }). when('/failures', { template: '' }). when('/nodes/:nodeid', { template: function($routeParams) { return ""; } //
This is a detailed view of node " +$routeParams.nodeid+ "!
Return }). otherwise({redirectTo: '/nodes'}); }]); ================================================ FILE: code/web/src/app.css ================================================ /* app css stylesheet */ body { margin: 0; font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; font-variant: small-caps; } th, td { padding: 5px; border: 1px dashed white; } input { color: black; } #container { width: 100%; height: 100vh; margin: 0 auto 0 auto; border: 0 solid transparent; background-color: #124; } #menubar { width: 100%; padding-top: 2vh; background-color: lightgray; margin: 0 auto 0 auto; display: table; border-spacing: 10px 0; text-align: center; } #menubar a { background-color: #124; height: 5vh; vertical-align: middle; border-width: 0 5px 0 5px; border-radius: 7px 7px 0 0; margin: 0 3% 0 3%; padding: 1%; display: inline-block; color: white; text-decoration: none; width: 40%; } #menubar a:hover { background-color: #126; color: #7cf1ca; } #main { width: 100%; background-color: #124; color: white; } #footer { width: 100%; display: block; height: 5vh; position: fixed; bottom: 0; background-color: #124; } #footer .footer-fillin { width: 10%; height: 100%; float: left; } #footer #footer-content { width: 80%; height: 100%; float: left; text-align: center; color: white; border-top: 1px solid white; } #nodearea { margin: 0 auto; width: 100%; box-sizing: border-box; padding: 3% 10px; background-color: #124; } #nodearea .no_data { text-align: center; width: 100%; padding-top: 2em; } #nodearea, #nodearea .node-list { display: flex; flex-wrap: wrap; width: 100%; } #nodearea .node { flex: 1 0 auto; display: inline-block; position: relative; opacity: 1; text-align: center; margin-right: 1%; margin-left: 1%; margin-bottom: 2.1em; box-sizing: border-box; color: black; -webkit-transition: width 0.3s ease-out, height 0.2s ease-out; -moz-transition: width 0.3s ease-out, height 0.2s ease-out; -o-transition: width 0.3s ease-out, height 0.2s ease-out; transition: width 0.3s ease-out, height 0.2s ease-out; } #nodearea .node a, #nodearea .node a:visited { color: black; text-decoration: none; } #nodearea .node .node-main { border-color: transparent; border-radius: 0.5em; border-width: 0 5px 0 5px; border-style: solid; background-color: cornflowerblue; box-sizing: border-box; padding: 0.5em 1%; } #nodearea .node h3, #nodearea .node h5 { margin-bottom: 0; margin-top: 0; -webkit-transition: font-size 0.3s ease-out, opacity 0.3s ease-out; -moz-transition: font-size 0.3s ease-out, opacity 0.3s ease-out; -o-transition: font-size 0.3s ease-out, opacity 0.3s ease-out; transition: font-size 0.3s ease-out, opacity 0.3s ease-out; } #nodearea .node .click-hint-wrapper { height: 1.4em; margin-top: -0.5em; } #nodearea .node .click-hint-wrapper .click-hint { display: block; white-space: nowrap; padding: 0 0.3em; -webkit-transition: width 0.3s ease-out, height 0.2s ease-in-out; -moz-transition: width 0.3s ease-out, height 0.2s ease-in-out; -o-transition: width 0.3s ease-out, height 0.2s ease-in-out; transition: width 0.3s ease-out, height 0.2s ease-in-out; } #nodearea .node.upscaled { width: 100%; text-align: left; margin: 0; height: 70vh; } #nodearea .node.upscaled h3.id-label { font-size: 2em; } #nodearea .node.upscaled div.node-main { height: 100%; } #nodearea .node.reduced { display: none; } #nodearea .node.non-upscaled:hover .node-main { border-bottom-left-radius: 0; border-bottom-right-radius: 0; background-color: #1972ff; } #nodearea .node.non-upscaled:hover .click-hint { color: black; height: 1.4em; background-color: #1972ff; -webkit-transition: height 0.2s ease-in-out, width 0.2s ease-in-out, color 0.2s ease-in-out; -moz-transition: height 0.2s ease-in-out, width 0.2s ease-in-out, color 0.2s ease-in-out; -o-transition: height 0.2s ease-in-out, width 0.2s ease-in-out, color 0.2s ease-in-out; transition: height 0.2s ease-in-out, width 0.2s ease-in-out, color 0.2s ease-in-out; } #nodearea .node.non-upscaled .overview { display: block; } #nodearea .node.non-upscaled .details { display: none; } #nodearea .node.upscaled { width: 98%; } #nodearea .node.upscaled .overview { display: none; } #nodearea .node.upscaled .overview .click-hint { height: 0; } #nodearea .node.upscaled .details { display: block; } #nodearea .node.upscaled .details .value-graph { width: 100%; height: 100%; text-align: center; } #nodearea .node.leader .node-main { border-color: #c4e3f3; } #nodearea .node.leader:hover .node-main, #nodearea .node.leader:hover .click-hint { border-color: #7cf1ca; } #nodearea .node.leader:hover .leader-label { color: #7cf1ca; } #nodearea .node.leader .leader-label { font-style: italic; font-size: 0.8em; color: #c4e3f3; } #nodearea .node.summary { color: white; } #nodearea .node.summary .node-main { background-color: cadetblue; } #nodearea .node.summary.non-upscaled:hover .node-main, #nodearea .node.summary.non-upscaled:hover .click-hint { background-color: #7cf1ca; color: white; } #nodearea .node .click-hint { color: transparent; overflow: hidden; height: 0; position: relative; border-color: transparent; border-width: 0 5px 0 5px; border-style: solid; border-bottom-left-radius: 0.5em; border-bottom-right-radius: 0.5em; box-sizing: border-box; padding: 0 1%; -webkit-transition: height 0.2s ease-in-out, width 0.2s ease-in-out, color 0.2s ease-in-out; -moz-transition: height 0.2s ease-in-out, width 0.2s ease-in-out, color 0.2s ease-in-out; -o-transition: height 0.2s ease-in-out, width 0.2s ease-in-out, color 0.2s ease-in-out; transition: height 0.2s ease-in-out, width 0.2s ease-in-out, color 0.2s ease-in-out; } #nodearea .node .click-hint-wrapper { border-bottom-left-radius: 0.5em; border-bottom-right-radius: 0.5em; } #nodearea .node .leader-edge { width: 0; height: 0; } #failure-table { width: 100%; margin: 5vh 0 0 0; font-variant: small-caps; } #failure-table h3 { margin: 0 auto 5px auto; text-align: center; width: 50%; /*height: 5vh;*/ min-height: 30px; border-bottom: 1px solid white; } #failure-table div#refresher { width: 30%; margin: 0 auto; } #failure-table div#refresher button { color: black; } #failure-table #symbology { float: left; width: 8%; padding: 2%; height: 70vh; margin: 0; vertical-align: top; } #failure-table #symbology div.sym-section { width: 100%; float: left; margin-bottom: 5px; } #failure-table #symbology div.sym-section div.circle { margin-right: 5px; float: left; width: 24px; height: 24px; -moz-border-radius: 12px; -webkit-border-radius: 12px; border-radius: 12px; } #failure-table #symbology div.sym-section div.circle.type-init { background: #7cf1cb; } #failure-table #symbology div.sym-section div.circle.type-propose { background: #85b9f0; } #failure-table #symbology div.sym-section div.circle.type-prevote { background: #ffcd83; } #failure-table #symbology div.sym-section div.circle.type-vote { background: #ffad83; } #failure-table #symbology div.sym-section div.circle div.ringHole { margin: 6px; width: 12px; height: 12px; -moz-border-radius: 6px; -webkit-border-radius: 6px; border-radius: 6px; background: #124; } #failure-table #symbology div.sym-section div.arrow { float: left; width: 24px; height: 24px; } #failure-table #symbology div.sym-section div.arrow div.head { float: left; margin: 6px 0; width: 0; height: 0; border-top: 6px solid transparent; border-bottom: 6px solid transparent; } #failure-table #symbology div.sym-section div.arrow div.head.type-init { border-left: 12px solid #7cf1cb; } #failure-table #symbology div.sym-section div.arrow div.head.type-propose { border-left: 12px solid #85b9f0; } #failure-table #symbology div.sym-section div.arrow div.head.type-prevote { border-left: 12px solid #ffcd83; } #failure-table #symbology div.sym-section div.arrow div.head.type-vote { border-left: 12px solid #ffad83; } #failure-table #symbology div.sym-section div.arrow div.shaft { float: left; margin: 10px 0; width: 12px; height: 4px; } #failure-table #symbology div.sym-section div.arrow div.shaft.type-init { background: #7cf1cb; } #failure-table #symbology div.sym-section div.arrow div.shaft.type-propose { background: #85b9f0; } #failure-table #symbology div.sym-section div.arrow div.shaft.type-prevote { background: #ffcd83; } #failure-table #symbology div.sym-section div.arrow div.shaft.type-vote { background: #ffad83; } #failure-table #symbology div.top-label { width: 100%; font-variant: small-caps; font-size: 1.5em; } #failure-table #symbology div.sym-label { width: 100%; font-variant: small-caps; } #failure-table #timeline { float: left; width: 80%; height: 70vh; margin: 0 auto; vertical-align: top; overflow-y: scroll; } #failure-table #timeline .svg-content { display: inline-block; position: absolute; top: 0; left: 0; } #failure-table #timeline svg .arrow.type-init, #failure-table #timeline svg circle.type-init { stroke: #7cf1cb; } #failure-table #timeline svg .arrow.type-prevote, #failure-table #timeline svg circle.type-prevote { stroke: #ffcd83; } #failure-table #timeline svg .arrow.type-propose, #failure-table #timeline svg circle.type-propose { stroke: #85b9f0; } #failure-table #timeline svg .arrow.type-vote, #failure-table #timeline svg circle.type-vote { stroke: #ffad83; } #failure-table #timeline svg .arrow { stroke-width: 2px; fill: none; } #failure-table #timeline svg circle.action-acknowledge.type-init { fill: #7cf1cb; } #failure-table #timeline svg circle.action-acknowledge.type-prevote { fill: #ffcd83; } #failure-table #timeline svg circle.action-acknowledge.type-propose { fill: #85b9f0; } #failure-table #timeline svg circle.action-acknowledge.type-vote { fill: #ffad83; } #failure-table #timeline svg circle.action-send { fill-opacity: 0.0; stroke-width: 3; } .tooltipster-content p.type, .tooltipster-content div.type { text-align: center; font-size: 0.5em; margin-bottom: -0.5em; margin-top: 0; } .tooltipster-content p.type span, .tooltipster-content div.type span { font-weight: bold; text-transform: capitalize; } .tooltipster-content p.value_store label span .node.different { text-decoration: line-through; } .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-init.tooltipster-top .tooltipster-box, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-init.tooltipster-top .tooltipster-box, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-init.tooltipster-bottom .tooltipster-box, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-init.tooltipster-bottom .tooltipster-box { border-left: 0 none #2a2a2a; border-right: 0 none #2a2a2a; border-bottom: 3px solid #7cf1cb; border-top: 3px solid #7cf1cb; } .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-init.tooltipster-top .tooltipster-arrow-border, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-init.tooltipster-top .tooltipster-arrow-border, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-init.tooltipster-bottom .tooltipster-arrow-border, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-init.tooltipster-bottom .tooltipster-arrow-border { border-bottom-color: #7cf1cb; border-top-color: #7cf1cb; } .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-init.tooltipster-left .tooltipster-box, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-init.tooltipster-left .tooltipster-box, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-init.tooltipster-right .tooltipster-box, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-init.tooltipster-right .tooltipster-box { border-top: 0 none #2a2a2a; border-bottom: 0 none #2a2a2a; border-left: 3px solid #7cf1cb; border-right: 3px solid #7cf1cb; } .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-init.tooltipster-left .tooltipster-arrow-border, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-init.tooltipster-left .tooltipster-arrow-border, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-init.tooltipster-right .tooltipster-arrow-border, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-init.tooltipster-right .tooltipster-arrow-border { border-left-color: #7cf1cb; border-right-color: #7cf1cb; } .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-init .tooltipster-content, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-init .tooltipster-content { color: #7cf1cb; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-variant: normal; } .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-propose.tooltipster-top .tooltipster-box, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-propose.tooltipster-top .tooltipster-box, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-propose.tooltipster-bottom .tooltipster-box, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-propose.tooltipster-bottom .tooltipster-box { border-left: 0 none #2a2a2a; border-right: 0 none #2a2a2a; border-bottom: 3px solid #85b9f0; border-top: 3px solid #85b9f0; } .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-propose.tooltipster-top .tooltipster-arrow-border, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-propose.tooltipster-top .tooltipster-arrow-border, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-propose.tooltipster-bottom .tooltipster-arrow-border, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-propose.tooltipster-bottom .tooltipster-arrow-border { border-bottom-color: #85b9f0; border-top-color: #85b9f0; } .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-propose.tooltipster-left .tooltipster-box, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-propose.tooltipster-left .tooltipster-box, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-propose.tooltipster-right .tooltipster-box, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-propose.tooltipster-right .tooltipster-box { border-top: 0 none #2a2a2a; border-bottom: 0 none #2a2a2a; border-left: 3px solid #85b9f0; border-right: 3px solid #85b9f0; } .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-propose.tooltipster-left .tooltipster-arrow-border, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-propose.tooltipster-left .tooltipster-arrow-border, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-propose.tooltipster-right .tooltipster-arrow-border, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-propose.tooltipster-right .tooltipster-arrow-border { border-left-color: #85b9f0; border-right-color: #85b9f0; } .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-propose .tooltipster-content, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-propose .tooltipster-content { color: #85b9f0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-variant: normal; } .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-prevote.tooltipster-top .tooltipster-box, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-prevote.tooltipster-top .tooltipster-box, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-prevote.tooltipster-bottom .tooltipster-box, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-prevote.tooltipster-bottom .tooltipster-box { border-left: 0 none #2a2a2a; border-right: 0 none #2a2a2a; border-bottom: 3px solid #ffcd83; border-top: 3px solid #ffcd83; } .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-prevote.tooltipster-top .tooltipster-arrow-border, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-prevote.tooltipster-top .tooltipster-arrow-border, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-prevote.tooltipster-bottom .tooltipster-arrow-border, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-prevote.tooltipster-bottom .tooltipster-arrow-border { border-bottom-color: #ffcd83; border-top-color: #ffcd83; } .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-prevote.tooltipster-left .tooltipster-box, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-prevote.tooltipster-left .tooltipster-box, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-prevote.tooltipster-right .tooltipster-box, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-prevote.tooltipster-right .tooltipster-box { border-top: 0 none #2a2a2a; border-bottom: 0 none #2a2a2a; border-left: 3px solid #ffcd83; border-right: 3px solid #ffcd83; } .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-prevote.tooltipster-left .tooltipster-arrow-border, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-prevote.tooltipster-left .tooltipster-arrow-border, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-prevote.tooltipster-right .tooltipster-arrow-border, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-prevote.tooltipster-right .tooltipster-arrow-border { border-left-color: #ffcd83; border-right-color: #ffcd83; } .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-prevote .tooltipster-content, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-prevote .tooltipster-content { color: #ffcd83; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-variant: normal; } .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-vote.tooltipster-top .tooltipster-box, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-vote.tooltipster-top .tooltipster-box, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-vote.tooltipster-bottom .tooltipster-box, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-vote.tooltipster-bottom .tooltipster-box { border-left: 0 none #2a2a2a; border-right: 0 none #2a2a2a; border-bottom: 3px solid #ffad83; border-top: 3px solid #ffad83; } .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-vote.tooltipster-top .tooltipster-arrow-border, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-vote.tooltipster-top .tooltipster-arrow-border, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-vote.tooltipster-bottom .tooltipster-arrow-border, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-vote.tooltipster-bottom .tooltipster-arrow-border { border-bottom-color: #ffad83; border-top-color: #ffad83; } .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-vote.tooltipster-left .tooltipster-box, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-vote.tooltipster-left .tooltipster-box, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-vote.tooltipster-right .tooltipster-box, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-vote.tooltipster-right .tooltipster-box { border-top: 0 none #2a2a2a; border-bottom: 0 none #2a2a2a; border-left: 3px solid #ffad83; border-right: 3px solid #ffad83; } .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-vote.tooltipster-left .tooltipster-arrow-border, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-vote.tooltipster-left .tooltipster-arrow-border, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-vote.tooltipster-right .tooltipster-arrow-border, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-vote.tooltipster-right .tooltipster-arrow-border { border-left-color: #ffad83; border-right-color: #ffad83; } .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-acknowledge-vote .tooltipster-content, .tooltipster-sidetip.tooltipster-punk.tooltipster-punk-send-vote .tooltipster-content { color: #ffad83; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-variant: normal; } ================================================ FILE: code/web/src/app.js ================================================ 'use strict'; // Declare app level module which depends on views, and components angular.module('myApp', [ 'ngRoute', 'myApp.view1', 'myApp.view2', 'myApp.version' ]). config(['$locationProvider', '$routeProvider', function($locationProvider, $routeProvider) { $locationProvider.hashPrefix('!'); $routeProvider.otherwise({redirectTo: '/view1'}); }]); ================================================ FILE: code/web/src/app.less ================================================ // MACROS .transition(...) { // http://stackoverflow.com/a/14988517/3423324 @props: ~`"@{arguments}".replace(/[\[\]]/g, '')`; -webkit-transition: @props; -moz-transition: @props; -o-transition: @props; transition: @props; } // COLORS @node-highlight: cadetblue; @node-highlight-hover: #7cf1ca; @node-normal: cornflowerblue; @node-normal-hover: #1972ff; @node-leader: #c4e3f3; @node-leader-hover: @node-highlight-hover; @bg-color: #124; // Colors for Message Types @msg-type1: #7cf1cb; @msg-type2: #85b9f0; @msg-type3: #ffcd83; @msg-type4: #ffad83; @msg-init: @msg-type1; @msg-propose: @msg-type2; @msg-prevote: @msg-type3; @msg-vote: @msg-type4; // STYLES /* app css stylesheet */ body { margin: 0; font-family: "Lucida Sans Unicode","Lucida Grande",sans-serif; font-variant: small-caps; } //.menu { // list-style: none; // border-bottom: 0.1em solid black; // margin-bottom: 2em; // padding: 0 0 0.5em; //} // //.menu:before { // content: "["; //} // //.menu:after { // content: "]"; //} // //.menu > li { // display: inline; //} // //.menu > li + li:before { // content: "|"; // padding-right: 0.3em; //} th, td { padding: 5px; border: 1px dashed white; } input { color: black; } #container { width: 100%; height: 100vh; margin: 0 auto 0 auto; border: 0 solid transparent; background-color: @bg-color; } #menubar { width: 100%; padding-top: 2vh; background-color: lightgray; margin: 0 auto 0 auto; display: table; border-spacing: 10px 0; text-align: center; a { background-color: @bg-color; height: 5vh; vertical-align: middle; border-width: 0 5px 0 5px; border-radius: 7px 7px 0 0; margin: 0 3% 0 3%; padding: 1%; display: inline-block; color: white; text-decoration: none; width: 40%; &:hover { background-color: #126; color: @node-highlight-hover; } } } #main { width: 100%; background-color: @bg-color; color: white; } #footer { width: 100%; display: block; height: 5vh; position: fixed; bottom: 0; background-color: @bg-color; .footer-fillin { width: 10%; height: 100%; float: left; } #footer-content { width: 80%; height: 100%; float: left; text-align: center; color: white; border-top: 1px solid white; } } #nodearea { margin: 0 auto; width: 100%; box-sizing: border-box; padding: 3% 10px; //top+bottom left+right background-color: @bg-color; .no_data { text-align: center; width: 100%; padding-top: 2em; } &, .node-list { display: flex; flex-wrap: wrap; width: 100%; } .node { flex: 1 0 auto; display: inline-block; position: relative; opacity: 1; text-align: center; //width: 18%; margin-right: 1%; margin-left: 1%; margin-bottom: 2.1em; //margin: 3% 1% 1% 1%; box-sizing: border-box; color: black; .transition(width .3s ease-out, height .2s ease-out); a, a:visited { color: black; text-decoration: none; } .node-main { border-color: transparent; border-radius: 0.5em; border-width: 0 5px 0 5px; border-style: solid; background-color: @node-normal; box-sizing: border-box; padding: 0.5em 1%; } h3, h5 { margin-bottom: 0; margin-top: 0; .transition(font-size .3s ease-out, opacity .3s ease-out); } .click-hint-wrapper { height: 1.4em; margin-top: -0.5em; .click-hint { display: block; white-space: nowrap; padding: 0 0.3em; .transition(width .3s ease-out, height .2s ease-in-out); } } // One clicked -> Detail view. // The clicked one, in foreground &.upscaled { width: 100%; text-align: left; margin: 0; height: 70vh; h3.id-label { font-size: 2em; } div.node-main { height: 100%; } } // One clicked -> Detail view. // The not-clicked ones, hidden &.reduced { display: none; } // None clicked -> Overview. // Display all nodes. &.non-upscaled { &:hover { .node-main { border-bottom-left-radius: 0; border-bottom-right-radius: 0; background-color: @node-normal-hover; } .click-hint { color: black; height: 1.4em; background-color: @node-normal-hover; .transition(height .2s ease-in-out, width .2s ease-in-out, color .2s ease-in-out); } } .overview { display: block; } .details { display: none; } } &.upscaled { width: 100%-2%; .overview { display: none; .click-hint { height: 0; // opacity: 0; } } .details { display: block; .value-graph { width: 100%; height: 100%; text-align: center; } } } &.leader { .node-main { border-color: @node-leader; } &:hover { .node-main, .click-hint { border-color: @node-leader-hover; } .leader-label { color: @node-leader-hover; } } .leader-label { font-style: italic; font-size: 0.8em; color: @node-leader; } } &.summary { color: white; .node-main { background-color: @node-highlight; } &.non-upscaled:hover { .node-main, .click-hint { background-color: @node-highlight-hover; color: white; } } } .click-hint { color: transparent; overflow: hidden; height: 0; position: relative; border-color: transparent; border-width: 0 5px 0 5px; border-style: solid; border-bottom-left-radius: 0.5em; border-bottom-right-radius: 0.5em; box-sizing: border-box; padding: 0 1%; .transition(height .2s ease-in-out, width .2s ease-in-out, color .2s ease-in-out); } .click-hint-wrapper { border-bottom-left-radius: 0.5em; border-bottom-right-radius: 0.5em; } .leader-edge { width: 0; height: 0; } } } #failure-table { width: 100%; margin: 5vh 0 0 0; font-variant: small-caps; h3 { margin: 0 auto 5px auto; text-align: center; width: 50%; /*height: 5vh;*/ min-height: 30px; border-bottom: 1px solid white; } div#refresher { width: 30%; margin: 0 auto; button { color: black; } } #symbology { float:left; width: 8%; padding: 2%; height: 70vh; margin: 0; vertical-align: top; div.sym-section { width: 100%; float: left; margin-bottom: 5px; div.circle { margin-right: 5px; float: left; width: 24px; height: 24px; -moz-border-radius: 12px; -webkit-border-radius: 12px; border-radius: 12px; // half of width and height -> circle &.type-init { background: @msg-init; } &.type-propose { background: @msg-propose; } &.type-prevote { background: @msg-prevote; } &.type-vote { background: @msg-vote; } div.ringHole { // a circle contained in another circle to give the illusion of a ring margin: 6px; width: 12px; height: 12px; -moz-border-radius: 6px; -webkit-border-radius: 6px; border-radius: 6px; background: @bg-color; } } div.arrow { float: left; width: 24px; // full space the arrow occupies height: 24px; // " div.head { // head of an arrow float: left; margin: 6px 0; // top and bottom margin = (arrowAreaHeight - borderLeftHeight)/2 width: 0; height: 0; border-top: 6px solid transparent; border-bottom: 6px solid transparent; &.type-init { border-left: 12px solid @msg-init; // arrow shall be half as big as the circles } &.type-propose { border-left: 12px solid @msg-propose; } &.type-prevote { border-left: 12px solid @msg-prevote; } &.type-vote { border-left: 12px solid @msg-vote; } } div.shaft { // shaft / "stick" of an arrow float: left; margin: 10px 0; // top and bottom margin = (arrowAreaHeight - shaftHeight)/2 width: 12px; // half of the total arrow area height: 4px; // doesn't follow any particular rule, tried out what looks best &.type-init { background: @msg-init; } &.type-propose { background: @msg-propose; } &.type-prevote { background: @msg-prevote; } &.type-vote { background: @msg-vote; } } } } div.top-label { width: 100%; font-variant: small-caps; font-size: 1.5em; // I think it looks good this way.. } div.sym-label { width: 100%; font-variant: small-caps; } } #timeline { float: left; width: 80%; height: 70vh; margin: 0 auto; vertical-align: top; overflow-y: scroll; .svg-content { display: inline-block; position: absolute; top: 0; left: 0; } svg { .arrow, circle { &.type-init { stroke: @msg-init; } &.type-prevote { stroke: @msg-prevote; } &.type-propose { stroke: @msg-propose; } &.type-vote { stroke: @msg-vote; } } .arrow { stroke-width: 2px; fill: none; } circle { &.action-acknowledge { &.type-init { fill: @msg-init; } &.type-prevote { fill: @msg-prevote; } &.type-propose { fill: @msg-propose; } &.type-vote { fill: @msg-vote; } } &.action-send { fill-opacity: 0.0; stroke-width: 3; } } } } } // TOOLTIPS .tooltipster-content { p.type, div.type { text-align: center; font-size: 0.5em; margin-bottom: -0.5em; margin-top: 0; span { font-weight: bold; text-transform: capitalize; } } p.value_store label span .node.different { text-decoration: line-through; } } // THEME .makro_tooltipster_color(@color) { &.tooltipster-top, &.tooltipster-bottom { .tooltipster-box { border-left: 0 none #2a2a2a; border-right: 0 none #2a2a2a; border-bottom: 3px solid @color; border-top: 3px solid @color; } .tooltipster-arrow-border { border-bottom-color: @color; border-top-color: @color; } } &.tooltipster-left, &.tooltipster-right { .tooltipster-box { border-top: 0 none #2a2a2a; border-bottom: 0 none #2a2a2a; border-left: 3px solid @color; border-right: 3px solid @color; } .tooltipster-arrow-border { border-left-color: @color; border-right-color: @color; } } .tooltipster-content { color: @color; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-variant: normal; } } .tooltipster-sidetip.tooltipster-punk { &.tooltipster-punk-acknowledge-init, &.tooltipster-punk-send-init { .makro_tooltipster_color(@msg-init); } &.tooltipster-punk-acknowledge-propose, &.tooltipster-punk-send-propose { .makro_tooltipster_color(@msg-propose); } &.tooltipster-punk-acknowledge-prevote, &.tooltipster-punk-send-prevote { .makro_tooltipster_color(@msg-prevote); } &.tooltipster-punk-acknowledge-vote, &.tooltipster-punk-send-vote { .makro_tooltipster_color(@msg-vote); } } ================================================ FILE: code/web/src/app.module.js ================================================ 'use strict'; // Declare app level module which depends on views, and components angular.module('pbftGui', [ 'ngAnimate', 'ngRoute', 'ngResource', 'core', 'nodeList', 'valueGraph', 'nodeListView', 'failureTable', 'failureTableView' ]); ================================================ FILE: code/web/src/config.js ================================================ 'use strict'; // WARNING // If you use docker, to start this // this file will be overwritten on startup. // This happens in entrypoint.sh, // _API_URL is set to $API_URL. // WARNING var _API_URL = "http://192.168.99.100"; ================================================ FILE: code/web/src/core/core.module.js ================================================ /** * Created by PlayingBacon on 30.10.2016. */ 'use strict'; angular.module('core', [ 'core.node', 'core.d3Factory' //'core.d3Directive', //'core.recompile' ]); ================================================ FILE: code/web/src/core/d3/d3.directive.js ================================================ /** * Created by PlayingBacon on 15.11.2016. */ (function() { 'use strict'; angular.module('core.d3Directive') .directive('d3Directive', ['d3Factory', function (d3) { return { restrict: 'EA', scope: {}, link: function (scope, iElement, iAttrs) { var svg = d3.select(iElement[0]) .append("svg") .attr("width", "100%") .attr("height", "100%"); // dummy data scope.data = [ /*{name: "Greg", score: 98}, {name: "Ari", score: 96}, {name: "Loser", score: 48}, {name: "Me", score: 66}, {name: "Rita", score: 20}, {name: "Nameless", score: 75}*/ 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 ]; // on window resize, re-render d3 canvas window.onresize = function () { return scope.$apply(); }; scope.$watch(function () { return angular.element(window)[0].innerWidth; }, function () { return scope.render(scope.data); }); // define render function scope.render = function (data) { // remove all previous items before render svg.selectAll("*").remove(); // setup variables var str = "Output |"; /*var classes = d3.select(iElement[0]).attr("class"); for (var i = 0; i < classes.length; i++) { str = str+ "| " +classes[i]+ " "; } console.log(str);*/ /* var elements = d3.select(iElement[0]); for (var i = 0; i < elements.length; i++) { str = str + "| ::(" +i+ ") " for (var j = 0; j < elements[i].length; j++) { str = str + "| " +elements[i][j]+ " "; } } console.log(str);*/ console.log("Bounding rect (div): " +d3.select(iElement[0]).node().getBoundingClientRect().width); console.log("svg.width: " +svg.select("svg").offsetWidth); var divs = d3.selectAll("div"); for (var i = 0; i < divs.length; i++) { console.log(divs.attr("class")); /*for (var j = 0; j < divs[i].length; j++) { console.log("(" +i+ ") Class: " +divs[i][j].attr("class")+ " || Width: " +divs[i][j].node().getBoundingClientRect().width); }*/ } var width, height, max; width = d3.select(iElement[0])[0][0];/*d3.select(iElement[0])[0][0].offsetWidth - 20;*/ // 20 is for margins console.log("iElement[0]: " +d3.select(iElement[0])+ " | offsetWidth: " +d3.select(iElement[0]).offsetWidth); console.log("(iElement[0])[0][0]: " +d3.select(iElement[0])[0][0]+ " | (iElement[0])[0][0].offsetWidth: " +d3.select(iElement[0])[0][0].offsetWidth); height = scope.data.length * 35; // 35 = bar height (30) + margin (5) max = 98; // just some value var parent = svg.node().parentNode; console.log("PARENT :: element : " +parent+ " ; offsetWidth : " +parent.offsetWidth+ " ; clientWidth : " +parent.clientWidth+ " ; scrollWidth : " +parent.scrollWidth); var xScale = d3.scale.linear() .domain([0,d3.max(scope.data,function(d){return d;})]) .range([0,/*WIDTH, die ich nicht berechnet kriege! WAH!*/]); var yScale = d3.scale.linear() .domain([0,d3.max(scope.data,function(d){return d;})]) .range([0,height]); svg.attr("height", height); svg.selectAll("circle") .data(data) .enter() /*.append("rect") .attr("height", 30) .attr("width", 0) .attr("x", 10) .attr("y", function (d, i) { return i * 35; })*/ .append("circle") .attr("cx",function(d,i){return i*100+100;}) .attr("cy",function(d,i){return ;}) .attr("r",10) .attr("fill",function(d){return "rgb(" +(d+100)+ "," +(d+50)+ "," +d+ ")";}); /*.transition() .duration(1000) .attr("width", function (d) { return d.score / (max / width); })*/ svg.append("text") .text("D3 funktioniert! Theoretisch!") .attr("x","0px") .attr("y","100px") .attr("font-family","sans-serif") .attr("font-size","20px") .attr("color", "white"); 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); } } // directive code }; }]); }()); ================================================ FILE: code/web/src/core/d3/d3.directive.module.js ================================================ /** * Created by PlayingBacon on 15.11.2016. */ 'use strict'; angular.module('core.d3Directive', ['core.d3Factory']); ================================================ FILE: code/web/src/core/d3/d3.factory.js ================================================ /** * Created by PlayingBacon on 15.11.2016. */ 'use strict'; angular.module('core.d3Factory') .factory('d3Factory',[function() { var d3; // https://d3js.org Version 4.3.0. Copyright 2016 Mike Bostock. 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;++ue;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])&&++t0&&(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.time8?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();++ua;++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=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];++r1&&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)=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)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?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]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)A;if(!N&&E>k&&(_=E,E=k,k=_),T?N?E+k>0^b[1]<(Math.abs(b[0]-w)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)0?0:3:Math.abs(r[0]-e)0?2:1:Math.abs(r[1]-t)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)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)=n;var r=n/t;if(t>0){if(r>e[1])return!1;r>e[0]&&(e[0]=r)}else{if(rn&&(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)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)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]];++t1){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;l9&&(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.yt.y?1:n.xt.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=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)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.yg.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(ar;++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]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;++ie;++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;++i0&&(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=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.ro;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;++iu&&(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]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++0;h--)o.push(i(l)*h);for(l=0;o[l]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;++ae?[0/0,0/0]:[e>0?u[e-1]:n[0],et?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;++ue?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;++aa;){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;++en?"-":"",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]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=e);)e=void 0;for(;++ur&&(e=r)}else{for(;++u=e);)e=void 0;for(;++ur&&(e=r)}return e},mo.max=function(n,t){var e,r,u=-1,i=n.length;if(1===arguments.length){for(;++u=e);)e=void 0;for(;++ue&&(e=r)}else{for(;++u=e);)e=void 0;for(;++ue&&(e=r)}return e},mo.extent=function(n,t){var e,r,u,i=-1,o=n.length;if(1===arguments.length){for(;++i=e);)e=u=void 0;for(;++ir&&(e=r),r>u&&(u=r))}else{for(;++i=e);)e=void 0;for(;++ir&&(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(;++i1&&(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)r;){var i=r+u>>>1;er?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);++nr)for(;(u=n+r*++a)>t;)i.push(u/o);else for(;(u=n+r*++a)=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=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=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=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(;++ur){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;++rr;++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);++oi;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=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;++tn;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;++ar){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++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;++rn?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]:nDa?(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 }).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]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;++ta;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)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)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=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.xm&&(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=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(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(;++e0?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;++or;++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;++fg;++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;++i0)for(i=-1;++i=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;++h0&&(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;++ut?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;++oe&&(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);++ie.dx)&&(s=e.dx);++ie&&(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;++oi;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)) })})}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]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}(); return d3; }]); ================================================ FILE: code/web/src/core/d3/d3.factory.module.js ================================================ /** * Created by PlayingBacon on 15.11.2016. */ 'use strict'; angular.module('core.d3Factory', []); ================================================ FILE: code/web/src/core/node/node.module.js ================================================ /** * Created by PlayingBacon on 28.10.2016. */ 'use strict'; angular.module('core.node', ['ngResource']); ================================================ FILE: code/web/src/core/node/node.service.js ================================================ /** * Created by PlayingBacon on 28.10.2016. */ 'use strict'; angular. module('core.node'). factory('Node', ['$resource', function($resource) { return $resource('nodes.json'/*'http://HOSTNAME/get_value/'*/, {}, { query: { method: 'GET', //params: {nodeId: 'nodes'}, isArray: true } }); } ]); ================================================ FILE: code/web/src/core/recompile/recompile.directive.js ================================================ /** * Created by PlayingBacon on 23.11.2016. */ 'use strict'; angular.module('core.recompile') .directive('recompile', function($compile) { return { restrict: 'AE', link: function(scope, ele, attr) { /* this should watch if the state of an HTML object changes, f.e. when its inner text gets changed or * the objects attributes get changed, and, if so, call a function to compile the new HTML for Angular * execution. * In our specific case: when a value graph object gets inserted into a node it should be set up for * compilation by Angular.*/ scope.$watch(/*<1st param: attribute, what should be watched>, <2nd param: function, what happens if watched stuff changes state>*/); } } }); ================================================ FILE: code/web/src/core/recompile/recompile.directive.module.js ================================================ /** * Created by PlayingBacon on 23.11.2016. */ 'use strict'; angular.module('core.recompile',[]); ================================================ FILE: code/web/src/desktop.css ================================================ .node { width: auto; } @media only screen and (min-width: 481px) and (max-width: 600px) { .node { width: 48%; } } @media only screen and (min-width: 601px) and (max-width: 900px) { .node { width: 31.33333333%; } } ================================================ FILE: code/web/src/desktop.less ================================================ .node { width: auto; @media only screen and (min-width: 481px) and (max-width: 600px) { width: (100%/2) - 2%; } @media only screen and (min-width: 601px) and (max-width: 900px) { width: (100%/3) - 2%; } } ================================================ FILE: code/web/src/failure-table/failure-table.component.js ================================================ /** * Created by PlayingBacon on 27.10.2016. */ 'use strict'; angular. module('failureTable'). component('failureTable', { templateUrl: 'failure-table/failure-table.template.html', controller: ['$http','$compile','$scope', '$interval', function FailureTableController($http,$compile,$scope,$interval) { var self = this; var svg = null; var svgWidth = 0; var svgHeight = 0; var nW = 0; // node width, will be set in method setupNodeElements var nH = 50; // node height var nC = "white"; // node color var gap = 0; // gap between nodes, will be set in method setupNodeElements var tlPositions = []; var circleLog = []; // logs at which position there have already been drawn circles to prevent stacking them var idLog = []; self.startstamp = 0; // first timestamp that appears in the timeline var yProgress = 0; var arrowOffset = 18; // offset for drawing arrowheads of lines correctly var eHeight = 0; // height that gets occupied by all elements contained in the svg var scale = 1000; var EL_MAX = 200; // maximum of how many elements can be present in the svg at the same time var isSetup = false; //var logInfoStore = []; var colors = ["#7cf1cb","#85b9f0","#ffcd83","#ffad83"]; self.nodes = [/*1, 2, 3, 4*/]; // Nodes are added dynamically. var tlData = null; self.pollValues = (function() { if (isSetup) { clearSvg(); } //$http.get('../example/api/v2/get_timeline/index.html').success(function(response){ d3.selectAll("span#refresh-label")[0][0].append("Polling for values ..."); out("Polling for values ..."); $http.get(_API_URL+"/api/v2/get_timeline/").success(function(response){ tlData = response; self.startstamp = tlData.timestamps.min.unix; if (!isSetup) { self.nodes = tlData.nodes; self.setupTimeline(null,false); } handleTimelineInput(tlData); drawTimeBar(); d3.select("span#refresh-label").html(""); }); }); self.pollValues(); /*var promise = $interval(pollValues, 10000); $scope.$on('$destroy',function(){ if(promise) $interval.cancel(promise); });*/ self.setupTimeline = (function(data, help) { d3.select("div#timeline").select("*").remove(); data = self.nodes; svg = d3.select("div#timeline") .append("svg") .attr("width","100%").attr("height","400px"); setupSvgDefs(svg); var minW = data.length*80; var tl = d3.select("div#timeline")[0][0]; var width = tl.offsetWidth; svgWidth = maxVal(minW,width); svgHeight = tl.offsetHeight; window.onresize = (function() { var oldWidth = svgWidth; width = tl.offsetWidth; svgWidth = maxVal(minW,width); repositionSvgContent(oldWidth,svgWidth); svgHeight = tl.offsetHeight; }); setupBackground(parseInt(svg.attr("height"),10)); if (help) { setupHelpMeasurements(svgHeight); } self.setupNodeElements(svgHeight); isSetup = true; }); // removes everything except the defs and arrows ^-^ function clearSvg() { //svg.selectAll("rect").remove(); //svg.selectAll("text").remove(); svg.selectAll("circle").remove(); svg.selectAll("line:not(.nodeLine)").remove(); svg.selectAll("text.tbLabel").remove(); svg.selectAll("polyline").remove(); svg.selectAll("path:not(.norem)").remove(); } function setupSvgDefs(svg) { // as of now it's not possible to reference the fill color // of the element from within the marker declaration // http://bl.ocks.org/mbostock/1153292 var lel = {init: 0, propose: 1, prevote: 2, vote: 3}; svg.append("defs").selectAll("marker") .data(Object.keys(lel)) .enter().append("marker") .attr("id", function(d) { return d + "Arrow"; }) .attr("viewBox", "0 -5 10 10") .attr("refX", 15) .attr("refY", 0) .attr("markerWidth", 6) .attr("markerHeight", 6) .attr("orient", "auto") .append("path") .attr("d", "M0,-5L10,0L0,5") .attr("fill", function(d) { return colors[lel[d]]; }); } function setupBackground(svgHeight) { out("### SVG HEIGHT FOR BG: " +svgHeight); var selection = svg.select("rect.svgBg"); if (selection[0][0] != undefined && selection[0][0] != null) { //selection[0][0].height.baseVal.value = Math.floor(svgHeight); selection[0][0].height.baseVal.newValueSpecifiedUnits(1,svgHeight); } else { svg.append("rect") .attr("class","svgBg") .attr("x",0).attr("y",0) .attr("width",svgWidth).attr("height",svgHeight) .attr("fill","transparent"); } } self.setupNodeElements = function (svgHeight) { //isAnim selects if node entry should be animated or not var len = self.nodes.length; nW = svgWidth/(len*len); // node width gap = (svgWidth-(nW*len))/(len+1); // one gap := ( - ) / () // NOTE: every node has one gap to it's left and right var y = svgHeight*0.1; for (var i = 0; i < len; i++) { var x = i*nW+(i+1)*gap; svg.append("rect") .attr("x",x).attr("y",y) .attr("width",nW).attr("height",nH) .attr("fill",nC); var txtW = getTextWidth("Node " +self.nodes); if (nW > txtW+10) { var text = svg.append("text") .text("Node " +self.nodes) .attr("x",x+(nW/2-txtW/2)).attr("y",(y+nH/2)) .attr("fill"," #124") .attr("font-family","Verdana") .attr("font-weight","bold"); } else { txtW = getTextWidth(self.nodes[i]); var text = svg.append("text") .text(self.nodes[i]) .attr("x",x+(nW/2-txtW/2)).attr("y",(y+nH/2)) .attr("fill"," #124") .attr("font-family","Verdana") .attr("font-weight","bold"); } tlPositions[self.nodes[i]] = x+(nW/2); yProgress = y+nH+30; drawNodeLine(x,y); } eHeight = nH + y; }; function drawNodeLine(x,y) { svg.append("line") .classed("nodeLine","true") .attr("x1",(x+(nW/2))).attr("y1",y+(nH/2)) .attr("x2",(x+(nW/2))).attr("y2",svg.attr("height")) .attr("stroke",nC).attr("stroke-width",1).attr("stroke-linecap","round").attr("stroke-dasharray","1,5"); } function handleTimelineInput(data) { for (var i = 0; i < minVal(data.events.length,EL_MAX); i++) { var event = data.events[i]; //var yHeight = 0; if (event.action === "acknowledge") { if (((event.timestamps.send.unix-self.startstamp)*scale+yProgress) >= yProgress && !(areIn(idLog,event.id.send,event.id.receive))) { drawEndLine(event); } } else { if (!(isIn(idLog,event.id.send))) { drawStartingCircle(event); } } circleLog = []; } //printIdLog(); //deOverflow(); var circles = svg.selectAll("circle"); eHeight = circles[0][circles[0].length-1].cy.baseVal.value + 28 + 50; // eHeight + (margin from last phase or nodes) + (span of two circles) + (additional margin) //eHeight = eHeight + ((data.events[data.events.length-1].timestamps.receive.unix-self.startstamp)*scale-eHeight) + 28 + 50; //if(eHeight > parseInt(svg.attr("height"),10)) { svg.attr("height",(eHeight+"px")); setupBackground(eHeight); var content = svg.selectAll("line.nodeLine"); for (var k = 0; k < self.nodes.length; k++) { var line = content[0][k]; line.y2.baseVal.value = eHeight; } //} /*var circles = svg.selectAll("circle.new"); for (var j = 0; j < circles[0].length; j++) { $compile(circles[0][j])($scope); //var cls = getAttrValue(circles[0][j],"class").split(" "); //setAttrValue(circles[0][j],"class",(cls[0])) } circles.classed("new","false");*/ } function drawTimeBar() { svg.append("line") .attr("x1",svgWidth*0.05).attr("y1",yProgress) .attr("x2",svgWidth*0.05).attr("y2",eHeight) .attr("stroke",nC).attr("stroke-width",2); svg.append("text") .text("ms") .attr("x",svgWidth*0.04).attr("y",yProgress-5) .attr("fill","#fff") .attr("font-family","Verdana") .attr("font-size","10pt"); for (var i = 0; i < eHeight; i+=100) { svg.append("line") .attr("x1",svgWidth*0.04).attr("y1",i+yProgress) .attr("x2",svgWidth*0.05).attr("y2",i+yProgress) .attr("stroke",nC).attr("stroke-width",1); svg.append("text") .classed("tbLabel","true") .text(i) .attr("x",svgWidth*0.06).attr("y",i+yProgress+5) .attr("fill","#fff") .attr("font-family","Verdana") .attr("font-size","10pt"); } } function drawStartingCircle(event) { var cy = (event.timestamps.send.unix-self.startstamp)*scale+yProgress; var id_string = "i"+event.id.send; if (!(isIn(idLog,id_string)) && cy > yProgress) { out("new startp circle with id " +event.id.send); svg.append("circle") .classed("action-"+event.action, "true") .classed("type-"+event.type, "true") .classed(id_string, "true") .attr("cId",id_string) .attr("tSt","t"+event.timestamps.send.unix) .attr("cx",tlPositions[event.nodes.send]) .attr("cy",cy) .attr("r",7); idLog.push(id_string); } //var logInfoObj = {id:(""+event.id.send), cx:tlPositions[event.nodes.send], cy:(event.timestamps.send.unix-self.startstamp)*scale+yProgress, timestamp:(""+event.timestamps.send)}; //logInfoStore.push(logInfoObj); // eHeight + (margin from last phase or nodes) + (span of two circles) + (additional margin) //eHeight = eHeight + ((event.timestamps.send.unix-self.startstamp)*scale-eHeight) + 28 + 50; } function drawEndLine(event) { var arrow = event.type+"Arrow"; var cy = (event.timestamps.receive.unix-self.startstamp)*scale+yProgress; var id_receive_string = "i"+event.id.receive; if (!(isIn(idLog,id_receive_string)) && cy > yProgress) { out("new endp circle with id " +event.id.receive); var circle = svg.append("circle") .classed("action-"+event.action, "true").classed("type-"+event.type, "true") .classed("tooltip","true").classed(id_receive_string, "true") .attr("cId",id_receive_string) .attr("tSt","t"+event.timestamps.receive.unix) .attr("cx",tlPositions[event.nodes.receive]) .attr("cy",cy) .attr("r",7) // end .attr("data-meta", JSON.stringify(event)); $(circle).tooltipster({functionInit: tooltipContent, interactive: true, theme: ['tooltipster-punk', 'tooltipster-punk-' + event.action + '-' + event.type], trigger: 'click'}); var x_send = tlPositions[event.nodes.send]; var x_receive = tlPositions[event.nodes.receive]; var y_send = (event.timestamps.send.unix-self.startstamp)*scale+yProgress; var y_receive = (event.timestamps.receive.unix-self.startstamp)*scale+yProgress; var id_send_string = "i"+event.id.send; if (x_send == x_receive) { // create three lines that act as one line with two 90° angles svg.append("polyline") .attr("points", (x_send ) +","+ y_send +" "+ (x_send+30) +","+ y_send +" "+ (x_send+30) +","+ y_receive +" "+ (x_send ) +","+ y_receive +" " ) .attr("sId",id_send_string).attr("rId",id_receive_string) .classed("arrow", true).classed("type-" + event.type, true) .classed(id_receive_string, "true").classed(id_send_string, "true") .attr("marker-end",("url(#"+arrow+")")); } else { svg.append("line") .attr("sId",id_send_string).attr("rId",id_receive_string) .classed("arrow", true).classed("type-" + event.type, true) .classed(id_receive_string, "true").classed(id_send_string, "true") .attr("x1",x_send).attr("y1",y_send) .attr("x2",x_receive).attr("y2",y_receive) .attr("marker-end",("url(#"+arrow+")")); } idLog.push(id_receive_string); } // eHeight + (margin from last phase or nodes) + (span of two circles) + (additional margin) //eHeight = eHeight + ((event.timestamps.receive.unix-self.startstamp)*scale-eHeight) + 28 + 50; } function repositionSvgContent(oldWidth,newWidth) { //out("old width:"+oldWidth+" -> new width:"+newWidth); if (oldWidth != newWidth) { var perc = (newWidth/(oldWidth/100))/100; //percentage where 1.0 equals 100%, how many % is newWidth to oldWidth gap = gap*perc; var content = svg.selectAll("*:not(text)"); for (var i = 0; i < content[0].length; i++) { if (content[0][i].tagName === "rect") { if (content[0][i].attributes.class === undefined || !(content[0][i].attributes.class.nodeValue === "svgBg")) { var rect = content[0][i]; rect.x.baseVal.value = rect.x.baseVal.value * perc; rect.width.baseVal.value = rect.width.baseVal.value * perc; nW = rect.width.baseVal.value; } else { var bg = content[0][i]; bg.width.baseVal.value = bg.width.baseVal.value * perc; } } else if (content[0][i].tagName === "circle") { var circle = content[0][i]; circle.cx.baseVal.value = circle.cx.baseVal.value * perc; // change cx value in log info store too! var classes = circle.attributes.class.nodeValue.split(" "); for (var j = 0; j < classes.length; j++) { if (classes[j][0] === "c") { var cid = parseInt(classes[j].split("_")[1]); //TODO: is cid not format "i123"? logInfoStore[cid].cx = circle.cx.baseVal.value; //TODO: is logInfoStore undefined? } } } else if (content[0][i].tagName === "line") { var line = content[0][i]; if (content[0][i].attributes.class === undefined || !(content[0][i].attributes.class.nodeValue === "nodeLine")) { line.x1.baseVal.value = line.x1.baseVal.value * perc; line.x2.baseVal.value = line.x2.baseVal.value * perc; } else { line.x1.baseVal.value = line.x1.baseVal.value * perc; line.x2.baseVal.value = line.x2.baseVal.value * perc; } } else if (content[0][i].tagName === "polyline") { var polyline = content[0][i]; //var classes = polyline.attributes.class.nodeValue.split(" "); var points = polyline.attributes.points.nodeValue.split(" "); var new_points = []; for (var j = 0; j < points.length; j++) { var coords = points[j].split(","); if (coords[0].length == 0) { continue; } var new_x = parseFloat(coords[0]) * perc; if (new_x == 0 || isNaN(new_x)) { console.log("new_x", new_x) } coords[0] = "" + (new_x); // change x coordinate new_points.push(coords.join(",")); } polyline.attributes.points.nodeValue = new_points.join(" "); } } content = svg.selectAll("text"); for (var i = 0; i < content[0].length; i++) { var text = content[0][i]; //var x = i*nW+(i+1)*gap; //x+(nW/2-txtW/2) if (getTextWidth((text.innerHTML.length > 1 ? text.innerHTML : "Node "+text.innerHTML))+10 >= nW) { text.innerHTML = delFromString(text.innerHTML,"Node "); } else { text.innerHTML = (text.innerHTML.length > 1 ? text.innerHTML : "Node "+text.innerHTML); } var x = i*nW+(i+1)*gap; text.x.baseVal[0].value = x+(nW/2-getTextWidth(text.innerHTML)/2); } } } function deOverflow() { out("idLog length " +idLog.length); if (idLog.length < EL_MAX) { return; } else { do { var delId = idLog.shift(); svg.selectAll("." + delId).remove(); } while (idLog.length >= EL_MAX); var circles = svg.selectAll("circle"); var nonpoly = svg.selectAll("line:not(.nodeLine)"); var poly = svg.selectAll("polyline"); var len = maxVal(maxVal(circles[0].length,nonpoly[0].length),poly[0].length); var offset = circles[0][0].attributes[4].value-yProgress; for (var j = 0; j < len; j++) { if (j < circles[0].length) { out("---\noffset:"+offset+"\nold circle cy:"+circles[0][j].cy.baseVal.value +" ; new circle cy:"+(circles[0][j].cy.baseVal.value-offset)+"\ntstmp:"+circles[0][j].attributes[2].value+" ; startstamp:"+self.startstamp+"\n---"); circles[0][j].cy.baseVal.value = circles[0][j].cy.baseVal.value - offset; if (j === circles[0].length-1) { self.startstamp = (circles[0][j].attributes[2].value).split("t")[1]; // new startstamp = tSt (timestamp) of last circle } } if (j < nonpoly[0].length) { nonpoly[0][j].y1.baseVal.value = nonpoly[0][j].y1.baseVal.value - offset; nonpoly[0][j].y2.baseVal.value = nonpoly[0][j].y2.baseVal.value - offset; } if (j < poly[0].length) { poly[0][j].points[0].y = poly[0][j].points[0].y - offset; poly[0][j].points[1].y = poly[0][j].points[1].y - offset; poly[0][j].points[2].y = poly[0][j].points[2].y - offset; poly[0][j].points[3].y = poly[0][j].points[3].y - offset; } } /*out("to high, do shifting!"); var delId = idLog.shift(); var lines = svg.selectAll("[sId="+delId+"]"); if (lines[0].length > 0) { for (var i = 0; i < lines[0].length; i++) { out("currently:: lines with "+delId+" ; deleting circles "+lines[0][i].attributes[1].value+" and "+lines[0][i].attributes[2].value); svg.selectAll("[cId="+lines[0][i].attributes[1].value+"]").remove(); svg.selectAll("[cId="+lines[0][i].attributes[2].value+"]").remove(); lines[0][i].remove(); idLog.shift(); } } if (!(isIn(idLog,"i"+id))) { idLog.push("i"+id); }*/ } } function getTextWidth(str) { var temp = d3.select("body") .append("svg"); temp.append("text").text(str).attr("x",0).attr("y",20).attr("font-family","Verdana").attr("font-weight","bold"); var tW = temp.node().getBBox().width; temp.remove(); return tW; } function getAttrValue(elem,attr) { for (var i = 0; i < elem.attributes.length; i++) { var splitted = elem.attributes[i].split("="); if (splitted[0] === attr) { return splitted[1]; } } return "NOTFOUND"; } function setAttrValue(elem,attr,val) { for (var i = 0; i < elem.attributes.length; i++) { if (elem.attributes[i].split("=")[0] === attr) { elem.attributes[i].value = val; } } } function setupHelpMeasurements(svgHeight) { // setup vertical line at svg middle svg.append("line") .attr("x1",(svgWidth/2)).attr("y1",0) .attr("x2",(svgWidth/2)).attr("y2",svgHeight) .attr("stroke","black").attr("stroke-width",2); // setup horizontal line at svg relative top svg.append("line") .attr("x1",0).attr("y1",(svgHeight*0.05)) .attr("x2",svgWidth).attr("y2",(svgHeight*0.05)) .attr("stroke","black").attr("stroke-width",2); // add additional vertical lines with marking text to horizontal line for (var i = 0; i < (svgWidth/200); i++) { svg.append("line") .attr("x1",(svgWidth/2-(i*100))).attr("y1",(svgHeight*0.05)) // lines to the left of the middle .attr("x2",(svgWidth/2-(i*100))).attr("y2",(svgHeight*0.06)) // " .attr("stroke","black").attr("stroke-width",2); svg.append("text") .text(i*100) .attr("x",(svgWidth/2-(i*100))).attr("y",(svgHeight*0.025)) .attr("font-family","Verdana").attr("font-size","10px") .attr("fill","black"); } for (var i = 1; i < (svgWidth/200); i++) { svg.append("line") .attr("x1",(svgWidth/2+(i*100))).attr("y1",(svgHeight*0.05)) // lines to the right of the middle .attr("x2",(svgWidth/2+(i*100))).attr("y2",(svgHeight*0.06)) // " .attr("stroke","black").attr("stroke-width",2); svg.append("text") .text(i*100) .attr("x",(svgWidth/2+(i*100))).attr("y",(svgHeight*0.025)) .attr("font-family","Verdana").attr("font-size","10px") .attr("fill","black"); } // and also setup this weird little thingie // i*nW+(i+1)*gap /*var len = self.nodes.length; var nW = svgWidth/(len*4); // node width var gap = (svgWidth-(nW*len))/(len+1); for (var i = 0; i < len; i++) { var x = i*nW+(i+1)*gap; // i*nW .. svg.append("line") .attr("x1",(i*x)).attr("y1",(svgHeight*0.25)) .attr("x2",(i*x)+(i*nW)).attr("y2",svgHeight*0.25) .attr("stroke","blue").attr("stroke-width",2); svg.append("line") .attr("x1",(i*x)).attr("y1",(svgHeight*0.25)) .attr("x2",(i*x)).attr("y2",(svgHeight*0.3)) .attr("stroke","blue").attr("stroke-width",1); svg.append("line") .attr("x1",(i*x)+(i*nW)).attr("y1",(svgHeight*0.25)) .attr("x2",(i*x)+(i*nW)).attr("y2",(svgHeight*0.3)) .attr("stroke","blue").attr("stroke-width",1); // + (i+1)*gap svg.append("line") .attr("x1",(i*x)+(i*nW)).attr("y1",(svgHeight*0.35)) .attr("x2",(i*x)+(i*nW+(i+1)*gap)).attr("y2",svgHeight*0.35) .attr("stroke","orange").attr("stroke-width",2); svg.append("line") .attr("x1",(i*x)+(i*nW)).attr("y1",(svgHeight*0.35)) .attr("x2",(i*x)+(i*nW)).attr("y2",(svgHeight*0.4)) .attr("stroke","orange").attr("stroke-width",1); svg.append("line") .attr("x1",(i*x)+(i*nW+(i+1)*gap)).attr("y1",(svgHeight*0.35)) .attr("x2",(i*x)+(i*nW+(i+1)*gap)).attr("y2",(svgHeight*0.4)) .attr("stroke","orange").attr("stroke-width",1); }*/ } function calculateYCoordinate(startP,endP,x) { // y = m*x+b out("start-x: " +startP.x+ "; start-y: " +startP.y+ "; end-x: " +endP.x+ "; end-y: " +endP.y); var m = (endP.y-startP.y)/(endP.x-startP.x); if (isNaN(m)) { console.log(NaN) } var b = startP.y - m*startP.x; if (isNaN(b)) { console.log(NaN) } if (isNaN(m*x+b)) { console.log(NaN) } return (m*x+b); } function isIn(arr,val) { for (var i = 0; i < arr.length; i++) { if (arr[i] === val) { return true; } } return false; } function areIn(arr,val1,val2) { var bool1, bool2; for (var i = 0; i < arr.length; i++) { bool1 = (arr[i] === val1); bool2 = (arr[i] === val2); if (bool1 && bool2) { return true; } } return false; } function isAtIndex(arr,val) { for (var i = 0; i < arr.val; i++) { if (arr[i] === val) { return i; } } return undefined; } function printIdLog() { out("length:"+idLog.length); for (var i = 0; i < idLog.length; i++) { out("[i:"+i+"]-> id:"+idLog[i]+"\n"); } } function minVal(n1,n2) { return n1 <= n2 ? n1 : n2; } function maxVal(n1,n2) { return n1 <= n2 ? n2 : n1; } function delFromString(str,substr) { var res = ""; for (var i = 0; i < str.length; i++) { if (str[i] == substr[0]) { var k = i+1; for (var j = 1; j < substr.length; j++) { if (str[k] == substr[j]) { if (j == substr.length-1) { i = k; break; } k++; } else { break; } } } else { res = res+str[i]; } } return res; } function printArray(array) { var str = ""; for (var i = 0; i < array.length; i++) { str = str +array[i]+ " " } return str; } function out(str) { console.log(str); } }] }); ================================================ FILE: code/web/src/failure-table/failure-table.module.js ================================================ /** * Created by PlayingBacon on 27.10.2016. */ 'use strict'; angular.module('failureTable', []); ================================================ FILE: code/web/src/failure-table/failure-table.template.html ================================================

Timeline for Message Flow of Nodes

Symbols:
Init
Pre-Prepare
Prepare
Commit
================================================ FILE: code/web/src/failure-table-view/failure-table-view.component.js ================================================ /** * Created by PlayingBacon on 30.10.2016. */ 'use strict'; angular. module('failureTableView'). component('failureTableView', { templateUrl: 'failure-table-view/failure-table-view.template.html', controller: function FailureTableViewController() { } }); ================================================ FILE: code/web/src/failure-table-view/failure-table-view.module.js ================================================ 'use strict'; angular.module('failureTableView', ['failureTable']); ================================================ FILE: code/web/src/failure-table-view/failure-table-view.template.html ================================================ ================================================ FILE: code/web/src/hover-effect.js ================================================ /** * Created by PlayingBacon on 01.11.2016. */ /*$(document).ready(function() { $('.node').hover(function() { $('.click-hint').show(); }, function() { $('.click-hint').hide(); }); });*/ function toggleDisplay(elements) { var element; elements = elements.length ? elements : [elements]; for (var i = 0; i < elements.length; i++) { element = elements[i]; if (isHidden(element)) { element.style.display = 'block'; //element.style.visibility = 'visible'; } else { element.style.display = 'none'; //element.style.visibility = 'hidden'; } } function isHidden(element) { return window.getComputedStyle(element, null).getPropertyValue('visibility') === 'hidden'; } } function getClickHintElement(element) { var childs = element.childNodes; for (var x in childs) { if (x.classList.item(0) === 'click-hint') { alert('Eyup.'); } } //return element.getElementsByClassName('click-hint')[0]; } ================================================ FILE: code/web/src/index-async.html ================================================ My AngularJS App
Angular seed app: v
================================================ FILE: code/web/src/index.html ================================================ Practical Byzantine Fault Tolerance GUI
================================================ FILE: code/web/src/mobile.css ================================================ .node { width: 100%; } .node .click-hint { content: 'tap for details'; } ================================================ FILE: code/web/src/mobile.less ================================================ .node { width: 100%; .click-hint { content: 'tap for details'; } } ================================================ FILE: code/web/src/node-handling.js ================================================ /** * Created by PlayingBacon on 03.11.2016. */ function handleNodeScaling(element) { var classes = element.classList; if (!classes.contains('clicked')) { classes.add('clicked'); } toggleBigSmall(element, getUnclickedNodes()); classes.remove('clicked'); } function toggleBigSmall(element, otherElements) { var classes = element.classList; if (classes.contains('reduced')) { return; } if (classes.contains('upscaled')) { var vl = getChildByClassName(element, 'value-graph'); vl.removeChild(vl.getElementsByTagName("value-graph")[0]); classes.remove('upscaled'); classes.add('non-upscaled'); for (var i = 0; i < otherElements.length; i++) { otherClasses = otherElements[i].classList; if (!otherClasses.contains('reduced')) { return; } else { otherClasses.remove('reduced'); } } } else { classes.add('upscaled'); classes.remove('non-upscaled'); var vl = getChildByClassName(element, 'value-graph'); vl.appendChild(document.createElement("value-graph")); for (var i = 0; i < otherElements.length; i++) { otherClasses = otherElements[i].classList; if (otherClasses.contains('reduced')) { return; } else { otherClasses.add('reduced'); } } } } function getUnclickedNodes() { var nodes = document.getElementsByClassName('node'); var unclickedNodes = []; for (var i = 0; i < nodes.length; i++) { classes = nodes[i].classList; if (classes.contains('clicked')) { continue; } else { unclickedNodes.push(nodes[i]); } } return unclickedNodes; } function toggleVisibility(element) { if (element.parentNode.classList.contains('reduced')) { console.log("reduced, don't toggle."); return; } else if (!element.parentNode.classList.contains('non-upscaled')) { element.style.visibility = 'hidden'; } else if (!element.style.length > 0) { element.style.visibility = 'visible'; } else { element.style.visibility = (element.style.visibility === 'hidden' ? 'visible' : 'hidden'); } } function toggleDisplay(element, defaultval) { if (!element.style.length > 0) { element.style.display = ''; //initialising console.log('setting to default.'); element.style.display = defaultval; } else { console.log('toggling.'); element.style.display = (element.style.display === 'none' ? 'block' : 'none'); } } function toggleDisplayForChildren(parent) { children = parent.childNodes; for (var i = 0; i < children.length; i++) { if (children[i].nodeType != 1 || children[i].classList.contains('value-graph')) { continue; } if (!children[i].style.length > 0) { children[i].style.display = 'block'; } children[i].style.display = (children[i].style.display === 'none' ? 'block' : 'none'); } } function getChildByClassName(parent,className) { var children = parent.childNodes; var result = null; for (var i = 0; i < children.length && result == null; i++) { //console.log("element: " +children[i]); if (children[i].nodeType != 1) { continue; } var chClasses = children[i].classList; //console.log(" > classes: " +chClasses+ " :: requested class name: " +className); if (chClasses.contains(className)) { //console.log("found it!"); return children[i]; } else { //console.log("going deeper.."); result = getChildByClassName(children[i],className); } } return result; } ================================================ FILE: code/web/src/node-list/node-list.component.js ================================================ /** * Created by PlayingBacon on 27.10.2016. */ 'use strict'; angular. module('nodeList'). component('nodeList', { templateUrl: 'node-list/node-list.template.html', /*controller: ['Node', function NodeListController(Node) { this.nodes = Node.query(); } ]*/ controller: ['$http','$scope','$interval', function NodeListController($http,$scope,$interval) { var self = this; self.summary = null; self.nodes = []; self.leader = -1; var touched = false; /* $scope.intervalFunction = function(){ $timeout(function() { $scope.pollValues(); $scope.intervalFunction(); }, 5000) }; // Kick off the interval $scope.intervalFunction(); */ var pollValues = function() { $http.get(_API_URL+"/api/v2/get_value/").success(function (json) { var data = { "summary": 0.5, // or null "leader": 1, "nodes": [ {"node": "1", "value": 0.5}, {"node": "2", "value": 0.6}, {"node": "5", "value": 0.5}, {"node": "6", "value": 0.5}, {"node": "5", "value": 0.5} ] }; console.log("JSON:", json); data = json; touched = !touched; // this is a flag to check if it was updated yet (?) self.summary = data.summary; self.leader = data.leader; for (var i = 0; i < data.nodes.length; i++) { var node = data.nodes[i]; var searchedIndex; searchedIndex = searchIndex(self.nodes,node.node); // check if already exists. if (searchedIndex == -1) { // does not exists. self.nodes.push({ id:node.node, value:node.value, name:node.id, touched:touched }); console.log("Added", node.node); } else { self.nodes[searchedIndex].value = node.value; self.nodes[searchedIndex].touched = touched; console.log("Updated", node.node); } } for (var i = 0; i < self.nodes.length; i++) { if (self.nodes[i].touched != touched) { self.nodes.splice(i,1); // delete 1 element at index i. console.log("Removed", self.nodes[i].id); } } console.log(self.nodes.length); sortNodes(); }); }; var promise = $interval(pollValues, 5000); $scope.$on('$destroy',function(){ if(promise) $interval.cancel(promise); }); /*$.getJSON(url+"/get_data/?limit=10").done(function (json) { // do stuff self.nodes = []; for (var node in json) { if (json.hasOwnProperty(node)) { for (var timestamp in json[node]) { if (json[node].hasOwnProperty(timestamp)) { var value=json[node][timestamp]; self.nodes.push({id:node,value:value}); break; } } } } console.log(self.nodes.length); //self.nodes = json[]; for (var i = 0; i < self.nodes.length; i++) { console.log("i:"+i+",id:"+self.nodes[i].id+",value:"+self.nodes[i].value); sortNode(i); } }).fail(console.error);*/ function sortNodes() { /** * Sorts the nodes (in self.nodes) by their ID, ascending. */ for (var i = 0; i < self.nodes.length-1; i++) { for (var j = 0; j < self.nodes.length-1; j++) { if (self.nodes[j].id > self.nodes[j+1].id) { var temp = self.nodes[j]; self.nodes[j] = self.nodes[j+1]; self.nodes[j+1] = temp; } } } } function searchIndex(arr, id) { /** * searches array arr for an element with given (node) id. * * @returns Element index of array, or -1 if not found. **/ for (var i = 0; i < arr.length; i++) { if (arr[i].id === id) { return i; } } return -1; } }] }); ================================================ FILE: code/web/src/node-list/node-list.module.js ================================================ /** * Created by PlayingBacon on 27.10.2016. */ 'use strict'; angular. module('nodeList',[ 'core.node', 'valueGraph' ]); ================================================ FILE: code/web/src/node-list/node-list.template.html ================================================
No recent events
================================================ FILE: code/web/src/node-list-view/node-list-view.component.js ================================================ /** * Created by PlayingBacon on 30.10.2016. */ 'use strict'; angular. module('nodeListView'). component('nodeListView', { templateUrl: 'node-list-view/node-list-view.template.html', controller: function NodeListViewController() { } }); ================================================ FILE: code/web/src/node-list-view/node-list-view.module.js ================================================ 'use strict'; angular.module('nodeListView', ['nodeList']); ================================================ FILE: code/web/src/node-list-view/node-list-view.template.html ================================================
================================================ FILE: code/web/src/nodes.json ================================================ [{ "id": 1, "value": 0.5, "leader": true }, { "id": 2, "value": 0.6, "leader": false }, { "id": 3, "value": 0.5, "leader": false }, { "id": 4, "value": 0.5, "leader": false }, { "id": 5, "value": 0.5, "leader": false }, { "id": 6, "value": 0.5, "leader": false }, { "id": 7, "value": 0.8, "leader": false }, { "id": 8, "value": 0.5, "leader": false }, { "id": "summary", "value": 0.5 }] ================================================ FILE: code/web/src/test_timeline.json ================================================ { "events": [ { "action": "send", "data": { "node": 4, "sequence_no": 148847745, "type": 1, "value": 7.63133525848389 }, "id": { "send": 126277 }, "nodes": { "send": 4 }, "timestamps": { "send": { "string": "Thu, 02 Mar 2017 17:57:30 GMT", "unix": 1488477450.563605 } }, "type": "init" }, { "action": "acknowledge", "data": { "node": 4, "sequence_no": 148847745, "type": 1, "value": 7.631335258483887 }, "id": { "receive": 126278, "send": 126277 }, "nodes": { "receive": 4, "send": 4 }, "timestamps": { "receive": { "string": "Thu, 02 Mar 2017 17:57:30 GMT", "unix": 1488477450.576458 }, "send": { "string": "Thu, 02 Mar 2017 17:57:30 GMT", "unix": 1488477450.563605 } }, "type": "init" }, { "action": "send", "data": { "node": 3, "sequence_no": 148847745, "type": 1, "value": 1.97469127178192 }, "id": { "send": 126279 }, "nodes": { "send": 3 }, "timestamps": { "send": { "string": "Thu, 02 Mar 2017 17:57:30 GMT", "unix": 1488477450.680981 } }, "type": "init" }, { "action": "acknowledge", "data": { "node": 4, "sequence_no": 148847745, "type": 1, "value": 7.631335258483887 }, "id": { "receive": 126280, "send": 126277 }, "nodes": { "receive": 2, "send": 4 }, "timestamps": { "receive": { "string": "Thu, 02 Mar 2017 17:57:30 GMT", "unix": 1488477450.698291 }, "send": { "string": "Thu, 02 Mar 2017 17:57:30 GMT", "unix": 1488477450.563605 } }, "type": "init" }, { "action": "acknowledge", "data": { "node": 4, "sequence_no": 148847745, "type": 1, "value": 7.631335258483887 }, "id": { "receive": 126281, "send": 126277 }, "nodes": { "receive": 1, "send": 4 }, "timestamps": { "receive": { "string": "Thu, 02 Mar 2017 17:57:30 GMT", "unix": 1488477450.714077 }, "send": { "string": "Thu, 02 Mar 2017 17:57:30 GMT", "unix": 1488477450.563605 } }, "type": "init" }, { "action": "acknowledge", "data": { "node": 4, "sequence_no": 148847745, "type": 1, "value": 7.631335258483887 }, "id": { "receive": 126282, "send": 126277 }, "nodes": { "receive": 3, "send": 4 }, "timestamps": { "receive": { "string": "Thu, 02 Mar 2017 17:57:30 GMT", "unix": 1488477450.724045 }, "send": { "string": "Thu, 02 Mar 2017 17:57:30 GMT", "unix": 1488477450.563605 } }, "type": "init" }, { "action": "acknowledge", "data": { "node": 3, "sequence_no": 148847745, "type": 1, "value": 1.9746912717819214 }, "id": { "receive": 126283, "send": 126279 }, "nodes": { "receive": 4, "send": 3 }, "timestamps": { "receive": { "string": "Thu, 02 Mar 2017 17:57:30 GMT", "unix": 1488477450.735215 }, "send": { "string": "Thu, 02 Mar 2017 17:57:30 GMT", "unix": 1488477450.680981 } }, "type": "init" }, { "action": "send", "data": { "node": 2, "sequence_no": 148847745, "type": 1, "value": 0.883936822414398 }, "id": { "send": 126284 }, "nodes": { "send": 2 }, "timestamps": { "send": { "string": "Thu, 02 Mar 2017 17:57:30 GMT", "unix": 1488477450.751479 } }, "type": "init" }, { "action": "acknowledge", "data": { "node": 3, "sequence_no": 148847745, "type": 1, "value": 1.9746912717819214 }, "id": { "receive": 126285, "send": 126279 }, "nodes": { "receive": 2, "send": 3 }, "timestamps": { "receive": { "string": "Thu, 02 Mar 2017 17:57:30 GMT", "unix": 1488477450.761778 }, "send": { "string": "Thu, 02 Mar 2017 17:57:30 GMT", "unix": 1488477450.680981 } }, "type": "init" }, { "action": "acknowledge", "data": { "node": 3, "sequence_no": 148847745, "type": 1, "value": 1.9746912717819214 }, "id": { "receive": 126286, "send": 126279 }, "nodes": { "receive": 1, "send": 3 }, "timestamps": { "receive": { "string": "Thu, 02 Mar 2017 17:57:30 GMT", "unix": 1488477450.780048 }, "send": { "string": "Thu, 02 Mar 2017 17:57:30 GMT", "unix": 1488477450.680981 } }, "type": "init" }, { "action": "acknowledge", "data": { "node": 3, "sequence_no": 148847745, "type": 1, "value": 1.9746912717819214 }, "id": { "receive": 126287, "send": 126279 }, "nodes": { "receive": 3, "send": 3 }, "timestamps": { "receive": { "string": "Thu, 02 Mar 2017 17:57:30 GMT", "unix": 1488477450.796575 }, "send": { "string": "Thu, 02 Mar 2017 17:57:30 GMT", "unix": 1488477450.680981 } }, "type": "init" }, { "action": "acknowledge", "data": { "node": 2, "sequence_no": 148847745, "type": 1, "value": 0.8839368224143982 }, "id": { "receive": 126288, "send": 126284 }, "nodes": { "receive": 4, "send": 2 }, "timestamps": { "receive": { "string": "Thu, 02 Mar 2017 17:57:30 GMT", "unix": 1488477450.809868 }, "send": { "string": "Thu, 02 Mar 2017 17:57:30 GMT", "unix": 1488477450.751479 } }, "type": "init" }, { "action": "acknowledge", "data": { "node": 2, "sequence_no": 148847745, "type": 1, "value": 0.8839368224143982 }, "id": { "receive": 126289, "send": 126284 }, "nodes": { "receive": 2, "send": 2 }, "timestamps": { "receive": { "string": "Thu, 02 Mar 2017 17:57:30 GMT", "unix": 1488477450.827377 }, "send": { "string": "Thu, 02 Mar 2017 17:57:30 GMT", "unix": 1488477450.751479 } }, "type": "init" }, { "action": "acknowledge", "data": { "node": 2, "sequence_no": 148847745, "type": 1, "value": 0.8839368224143982 }, "id": { "receive": 126290, "send": 126284 }, "nodes": { "receive": 1, "send": 2 }, "timestamps": { "receive": { "string": "Thu, 02 Mar 2017 17:57:30 GMT", "unix": 1488477450.845287 }, "send": { "string": "Thu, 02 Mar 2017 17:57:30 GMT", "unix": 1488477450.751479 } }, "type": "init" }, { "action": "acknowledge", "data": { "node": 2, "sequence_no": 148847745, "type": 1, "value": 0.8839368224143982 }, "id": { "receive": 126291, "send": 126284 }, "nodes": { "receive": 3, "send": 2 }, "timestamps": { "receive": { "string": "Thu, 02 Mar 2017 17:57:30 GMT", "unix": 1488477450.861022 }, "send": { "string": "Thu, 02 Mar 2017 17:57:30 GMT", "unix": 1488477450.751479 } }, "type": "init" }, { "action": "send", "data": { "node": 1, "sequence_no": 148847745, "type": 1, "value": 0.957314074039459 }, "id": { "send": 126292 }, "nodes": { "send": 1 }, "timestamps": { "send": { "string": "Thu, 02 Mar 2017 17:57:31 GMT", "unix": 1488477451.097073 } }, "type": "init" }, { "action": "acknowledge", "data": { "node": 1, "sequence_no": 148847745, "type": 1, "value": 0.9573140740394592 }, "id": { "receive": 126293, "send": 126292 }, "nodes": { "receive": 1, "send": 1 }, "timestamps": { "receive": { "string": "Thu, 02 Mar 2017 17:57:31 GMT", "unix": 1488477451.116111 }, "send": { "string": "Thu, 02 Mar 2017 17:57:31 GMT", "unix": 1488477451.097073 } }, "type": "init" }, { "action": "acknowledge", "data": { "node": 1, "sequence_no": 148847745, "type": 1, "value": 0.9573140740394592 }, "id": { "receive": 126294, "send": 126292 }, "nodes": { "receive": 2, "send": 1 }, "timestamps": { "receive": { "string": "Thu, 02 Mar 2017 17:57:31 GMT", "unix": 1488477451.122682 }, "send": { "string": "Thu, 02 Mar 2017 17:57:31 GMT", "unix": 1488477451.097073 } }, "type": "init" }, { "action": "acknowledge", "data": { "node": 1, "sequence_no": 148847745, "type": 1, "value": 0.9573140740394592 }, "id": { "receive": 126295, "send": 126292 }, "nodes": { "receive": 4, "send": 1 }, "timestamps": { "receive": { "string": "Thu, 02 Mar 2017 17:57:31 GMT", "unix": 1488477451.128667 }, "send": { "string": "Thu, 02 Mar 2017 17:57:31 GMT", "unix": 1488477451.097073 } }, "type": "init" }, { "action": "acknowledge", "data": { "node": 1, "sequence_no": 148847745, "type": 1, "value": 0.9573140740394592 }, "id": { "receive": 126296, "send": 126292 }, "nodes": { "receive": 3, "send": 1 }, "timestamps": { "receive": { "string": "Thu, 02 Mar 2017 17:57:31 GMT", "unix": 1488477451.134851 }, "send": { "string": "Thu, 02 Mar 2017 17:57:31 GMT", "unix": 1488477451.097073 } }, "type": "init" }, { "action": "acknowledge", "data": { "leader": 1, "node": 1, "proposal": 3.57743239402771, "sequence_no": 148847745, "type": 2, "value_store": [ { "node": 1, "sequence_no": 148847744, "type": 1, "value": 1.2020764350891113 }, { "node": 2, "sequence_no": 148847744, "type": 1, "value": 5.357077121734619 }, { "node": 3, "sequence_no": 148847744, "type": 1, "value": 3.57743239402771 }, { "node": 4, "sequence_no": 148847744, "type": 1, "value": 5.470797538757324 } ] }, "id": { "receive": 126297, "send": 126299 }, "nodes": { "receive": 4, "send": 1 }, "timestamps": { "receive": { "string": "Thu, 02 Mar 2017 17:57:31 GMT", "unix": 1488477451.177011 }, "send": { "string": "Thu, 02 Mar 2017 17:57:31 GMT", "unix": 1488477451.190611 } }, "type": "propose" }, { "action": "acknowledge", "data": { "leader": 1, "node": 1, "proposal": 3.57743239402771, "sequence_no": 148847745, "type": 2, "value_store": [ { "node": 1, "sequence_no": 148847744, "type": 1, "value": 1.2020764350891113 }, { "node": 2, "sequence_no": 148847744, "type": 1, "value": 5.357077121734619 }, { "node": 3, "sequence_no": 148847744, "type": 1, "value": 3.57743239402771 }, { "node": 4, "sequence_no": 148847744, "type": 1, "value": 5.470797538757324 } ] }, "id": { "receive": 126298, "send": 126299 }, "nodes": { "receive": 3, "send": 1 }, "timestamps": { "receive": { "string": "Thu, 02 Mar 2017 17:57:31 GMT", "unix": 1488477451.184246 }, "send": { "string": "Thu, 02 Mar 2017 17:57:31 GMT", "unix": 1488477451.190611 } }, "type": "propose" }, { "action": "send", "data": { "leader": 1, "node": 1, "proposal": 3.57743239402771, "sequence_no": 148847745, "type": 2, "value_store": [ { "node": 1, "sequence_no": 148847744, "type": 1, "value": 1.2020764350891113 }, { "node": 2, "sequence_no": 148847744, "type": 1, "value": 5.357077121734619 }, { "node": 3, "sequence_no": 148847744, "type": 1, "value": 3.57743239402771 }, { "node": 4, "sequence_no": 148847744, "type": 1, "value": 5.470797538757324 } ] }, "id": { "send": 126299 }, "nodes": { "send": 1 }, "timestamps": { "send": { "string": "Thu, 02 Mar 2017 17:57:31 GMT", "unix": 1488477451.190611 } }, "type": "propose" } ], "nodes": [ 1, 2, 3, 4 ], "timestamps": { "max": { "string": "Thu, 02 Mar 2017 17:57:31 GMT", "unix": 1488477451.190611 }, "min": { "string": "Thu, 02 Mar 2017 17:57:30 GMT", "unix": 1488477450.563605 } } } ================================================ FILE: code/web/src/value-graph/value-graph.component.js ================================================ /** * Created by PlayingBacon on 07.11.2016. */ 'use strict'; angular. module('valueGraph'). component('valueGraph', { templateUrl: 'value-graph/value-graph.template.html', bindings: { nodeid: '=' }, controller: ['$http','$scope','$interval', function ValueGraphController($http,$scope,$interval) { var self = this; self.nodeData = {}; var myChart = null; self.series = null; var pollGraphs = function() { var url; if (self.nodeid === 'summary' || self.nodeid == undefined) { url = _API_URL + "/get_data/?limit=40"; } else { url = _API_URL + "/get_data/?limit=10&node="+self.nodeid; } $http.get(url).then(function (json) { for (var node in json.data) { if (json.data.hasOwnProperty(node)) { self.nodeData[node] = []; for (var timestamp in json.data[node]) { if (json.data[node].hasOwnProperty(timestamp)) { var value=json.data[node][timestamp]; self.nodeData[node][self.nodeData[node].length] = {timestamp:timestamp,value:value}; } } } } if (myChart == null) { constructVG(self.nodeData); } drawGraphs(self.nodeData); }, function(json) { out("Yeah, that did not work, at all."); }, function(json) { out("What does this even do?"); }) }; var promise = $interval(pollGraphs, 5000); $scope.$on('$destroy',function(){ if(promise) $interval.cancel(promise); }); out("data outer :: " +self.nodeData); function dataToValues(nodeData){ var list = []; for (var node in nodeData) { if (!nodeData.hasOwnProperty(node)) { continue; } list[list.length] = { name: 'Node ' + node, data: [nodeData[node]] } } return list; } function constructVG(data) { console.log("CONSTRUCT STUFF: ",data); setHighchartsTheme(); var chart_data = dataToValues(data); myChart = Highcharts.chart('value-graph-container', { chart: { type: 'spline', events: { load: function() { self.series = this.series; } } }, title: { text: 'Values over Time' }, xAxis: { type: 'datetime', title: { text: 'time' } }, yAxis: { title: { text: 'values' } }, series: chart_data }); d3.select("text.highcharts-credits").remove(); /*var svg = d3.select("div.value-graph") .append("svg") .attr("width", "100%") .attr("height", "100%") .attr("preserveAspectRatio","xMidYMin"); var vg = d3.select("div.value-graph")[0][0]; var max = data.length; var width = vg.offsetWidth; var height = vg.offsetHeight; out("### MEASUREMENTS :: width " +width+ " height " +height+ " max " +max); window.onresize = (function(){ width = vg.offsetWidth; height = vg.offsetHeight; drawGraphs(null); console.log("resize!"); });*/ /*var xScale = d3.scale.linear() .domain([0,d3.max()]) .range(); var yScale = d3.scale.linear() .domain() .range();*/ } function drawGraphs(nodes) { for (var node in nodes) { var d = []; for (var i = 0; i < nodes[node].length; i++) { var date = new Date(parseInt(nodes[node][i].timestamp,10)*1000); d[i] = [date, nodes[node][i].value]; } for (var i = 0; i < self.series.length; i++) { if (self.series[i].name === 'Node ' + node) { self.series[i].update({data: d}, true); } } } /*svg.selectAll("*").remove(); svg.append("rect").attr("width",width).attr("height",height).attr("fill","blue"); svg.selectAll("circle") .data(data) .enter() .append("circle") .attr("cx", function(d,i){return i*(width/max)+((width/2)/max);}) .attr("cy", function(){return height/2;}) .attr("r", function(d){return d.value*30;}) .attr("fill", "white"); */ /*var lineFunction = d3.svg.line() .x(function(d){return d.x;}) .y(function(d){return d.y;}) .interpolate("linear"); svg.selectAll("*").remove(); svg.append("rect").attr("width",width).attr("height",height).attr("fill","blue"); svg.append("path") .attr("d", lineFunction(data)) .attr("stroke", "black") .attr("stroke-width", 2) .attr("fill", "none"); */ } function setHighchartsTheme() { Highcharts.theme = { colors: ['#ffffff', '#fff3e2', '#ffcd83', '#ffad32', 'ffa51f', '#ff0066', '#eeaaee', '#55BF3B', '#DF5353', '#7798BF', '#aaeeee'], chart: { backgroundColor: 'transparent', style: { fontFamily: '\'Unica One\', sans-serif' }, plotBorderColor: '#606063' }, title: { style: { color: '#124', fontSize: '20px' } }, subtitle: { style: { color: '#323d51' } }, xAxis: { gridLineColor: '#323d51', labels: { style: { color: '#124' } }, lineColor: '#323d51', minorGridLineColor: '#124', tickColor: '#323d51', title: { style: { color: '#124' } } }, yAxis: { gridLineColor: '#323d51', labels: { style: { color: '#124' } }, lineColor: '#323d51', minorGridLineColor: '#124', tickColor: '#323d51', tickWidth: 1, title: { style: { color: '#124' } } }, tooltip: { backgroundColor: '#124', style: { color: '#F0F0F0' } } }; // Apply the theme Highcharts.setOptions(Highcharts.theme); } // I'm a lazy fuck. function out(str) { console.log(str); } }] }); ================================================ FILE: code/web/src/value-graph/value-graph.d3.js ================================================ /** * Created by PlayingBacon on 15.11.2016. */ 'use strict'; angular. module('valueGraph'). component('valueGraphD3', { template: '', bindings: { data: '=' }, controller: ['d3Factory', '$http', function ValueGraphD3Controller(d3, $http) { }] }); ================================================ FILE: code/web/src/value-graph/value-graph.module.js ================================================ /** * Created by PlayingBacon on 07.11.2016. */ 'use strict'; angular.module('valueGraph',[ 'core.d3Factory', 'nodeList' ]); ================================================ FILE: code/web/src/value-graph/value-graph.template.html ================================================ ================================================ FILE: code/web/styles.css ================================================ body { background-color: darkgrey; margin: 0; font-family: "Lucida Sans Unicode","Lucida Grande",sans-serif; } h3, h5 { font-variant: small-caps; margin-bottom: 0px; } #container { width: 100%; min-width: 550px; height: 98vh; margin: 0 auto 0 auto; background-color: black; border-style: solid; border-color: transparent; border-width: 2vh 0vh 0vh 0vh; } #menubar { width: 40%; height: 5%; margin: 0 auto 0 auto; color: aliceblue; display: table; border-spacing: 10px 0px; } #main { width: 100%; height: 90%; margin: 0% auto 0% auto; background-color: #124; overflow: hidden; } #nodearea { } #footer { width: 100%; height: 5%; margin: 0% auto 0% auto; text-align: center; background-color: gold; } .menuitem { text-align: center; display: table-cell; vertical-align: middle; width: 44%; font-size: 0.7em; height: 100%; margin: 0 3% 0 3%; border-width: 0 5px 0 5px; background-color: #124; border-radius: 7px 7px 0 0; } .node { float: left; text-align: center; width: 15%; height: 18%; margin: 3% 1% 1% 1%; padding: 1%; background-color: cornflowerblue; border-color: transparent; border-radius: 0.5em; border-width: 0 5px 0 5px; border-style: solid; } .node:hover { background-color: #1972ff; } .node.primary { border-color: cadetblue; } .node.primary:hover { border-color: #7cf1ca; } .primary-label { font-style: italic; color: midnightblue; } .primary-edge { width: 0; height: 0; } .node.summary { background-color: cadetblue; color: white; } .node.summary:hover { background-color: #7cf1ca; color: black; } .value { } ================================================ FILE: docker-compose.yml ================================================ version: '2' services: # # Python node # node: # extends: # file: node.docker-compose.yml # service: node # volumes: # - /var/run/docker.sock:/var/run/docker.sock # environment: # NODE_DEBUGGER: "False" # # # entrypoint: ["/bin/bash"] # # # docker run -ti --entrypoint /bin/bash 9b6a81855c06 # # d-c run --entrypoint /bin/bash node-3 # # NODE_ID=3 NODE_TOTAL=4 POSSIBLE_FAILURES=1 NODE_HOST=teamproject16_node-{i}_1 NODE_PORT=4458 python main_node.py node: extends: file: code/node_java/docker-compose.yml service: node_java volumes: - /var/run/docker.sock:/var/run/docker.sock environment: NODE_DEBUGGER: "False" NODE_DEBUG: "False" # API_HOST: "http://192.168.0.42" API_HOST: ${API_HOST} api: extends: file: api.docker-compose.yml service: api ports: - "80:80" restart: "no" command: ["python", "main_api.py"] #entrypoint: [] #command: ["ls", "-la"] web: extends: file: code/web/docker-compose.yml service: web environment: PORT: 8000 # API_URL: "http://192.168.0.42" API_URL: ${API_HOST} ports: - "8000:8000" entrypoint: ["/entrypoint.sh"] web_static: extends: file: code/web/docker-compose.yml service: web environment: PORT: 8001 API_URL: "http://localhost:8001/example/" # `${VM_HOST:-localhost}` will evaluate to `localhost` if $VM_HOST is unset or empty in the environment. ports: - "8001:8001" entrypoint: ["/entrypoint.sh"] postgres: extends: file: api.docker-compose.yml service: postgres #volumes: # - /data/postgres:/data/postgres postgres_browser: extends: file: api.docker-compose.yml service: postgres_browser ports: - "8080:80" ================================================ FILE: node.docker-compose.yml ================================================ version: '2' services: node: build: context: . dockerfile: ./Dockerfile command: ["main_node.py"] environment: DOCKER_CACHING_TIME: 5 NODE_PORT: 4458 NODE_DEBUGGER: 0 ================================================ FILE: requirements.txt ================================================ luckydonald-utils==0.51 docker-py # api flask # api pony # db