Full Code of luckydonald/pbft for AI

master a7d39515bb2a cached
95 files
815.6 KB
255.1k tokens
1109 symbols
1 requests
Download .txt
Showing preview only (854K chars total). Download the full file or copy to clipboard to get everything.
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. <http://fsf.org/>
 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 <http://www.gnu.org/licenses/>.

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
<http://www.gnu.org/licenses/>.

  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
<http://www.gnu.org/philosophy/why-not-lgpl.html>.


================================================
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:|<PREVOTE,cid,·,„,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.app
Download .txt
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
Download .txt
SYMBOL INDEX (1109 symbols across 21 files)

FILE: code/api/database.py
  class DBMessage (line 24) | class DBMessage(db.Entity):
    method from_db (line 36) | def from_db(self):
    method to_db (line 43) | def to_db(cls, msg):
  class DBInitMessage (line 49) | class DBInitMessage(DBMessage):
    method from_db (line 52) | def from_db(self):
    method to_db (line 57) | def to_db(cls, msg):
  class DBProposeMessage (line 64) | class DBProposeMessage(DBMessage):
    method from_db (line 69) | def from_db(self):
    method to_db (line 77) | def to_db(cls, msg):
  class DBPrevoteMessage (line 84) | class DBPrevoteMessage(DBMessage):
    method to_db (line 88) | def to_db(cls, msg):
    method from_db (line 93) | def from_db(self):
  class DBVoteMessage (line 99) | class DBVoteMessage(DBMessage):
    method to_db (line 103) | def to_db(cls, msg):
    method from_db (line 108) | def from_db(self):
  class DBAcknowledge (line 114) | class DBAcknowledge(DBMessage):
    method to_db (line 118) | def to_db(cls, msg):
    method from_db (line 123) | def from_db(self):
  function to_db (line 140) | def to_db(msg):

FILE: code/api/main.py
  function dump_to_db (line 34) | def dump_to_db():
  function get_value (line 54) | def get_value():
  function get_value_v2 (line 87) | def get_value_v2():
  function get_timeline (line 129) | def get_timeline():
  function generate_date_data (line 201) | def generate_date_data(datetime_obj):
  function generate_msg_data (line 210) | def generate_msg_data(msg):
  function get_data (line 222) | def get_data():
  function test (line 253) | def test():
  function console (line 264) | def console():
  function root (line 270) | def root():

FILE: code/api/utils.py
  function jsonify (line 11) | def jsonify(data, allow_all_origin=False):

FILE: code/main_api.py
  function setup_logging (line 12) | def setup_logging():

FILE: code/node/algo.py
  class BFT_ARM (line 56) | class BFT_ARM():
    method __init__ (line 60) | def __init__(self, sequence_number=None, receiver=None):
    method MsgCollect (line 83) | def MsgCollect(self):
    method task_normal_case (line 98) | def task_normal_case(self):
    method stop (line 157) | def stop(self):
    method new_sequence (line 165) | def new_sequence(self):
    method buffer_incomming (line 175) | def buffer_incomming(self, msg, buffer):
    method verify_proposal (line 184) | def verify_proposal(self, msg):
    method get_specific_message_type (line 209) | def get_specific_message_type(self, *classes_or_types, sequence_number...
    method nodes_total (line 234) | def nodes_total(self):
    method nodes_faulty (line 241) | def nodes_faulty(self):
    method node_number (line 246) | def node_number(self):
    method get_receiver (line 251) | def get_receiver(self):

FILE: code/node/dockerus.py
  class ServiceInfos (line 15) | class ServiceInfos(object, metaclass=Singleton):
    method __init__ (line 25) | def __init__(self, caching_time=None):
    method cli (line 45) | def cli(self):
    method hostname_env (line 51) | def hostname_env(self):
    method me (line 58) | def me(self):
    method id (line 64) | def id(self):
    method service (line 70) | def service(self):
    method name (line 76) | def name(self):
    method project (line 82) | def project(self):
    method number (line 88) | def number(self):
    method containers (line 93) | def containers(self, exclude_self=False):
    method hostname (line 112) | def hostname(self):
    method other_hostnames (line 122) | def other_hostnames(self, exclude_self=False):
    method other_numbers (line 134) | def other_numbers(self, exclude_self=False):

FILE: code/node/functions.py
  function flatten_list (line 8) | def flatten_list(args):

FILE: code/node/main.py
  function main (line 15) | def main():
  function setup_cleanup (line 34) | def setup_cleanup(algo):
  function setup_logging (line 51) | def setup_logging():

FILE: code/node/message_queue.py
  class LockedQueue (line 16) | class LockedQueue(object):
    method __init__ (line 17) | def __init__(self, clazz):
    method pop_message (line 24) | def pop_message(self):
    method get_message (line 45) | def get_message(self, sequence_number=None):
    method append_message (line 64) | def append_message(self, message):
    method queue_length (line 76) | def queue_length(self):
    method has_message (line 84) | def has_message(self):
  class MessageQueueReceiver (line 92) | class MessageQueueReceiver(Receiver):
    method _add_message (line 100) | def _add_message(self, text):

FILE: code/node/messages.py
  class Message (line 10) | class Message(object):
    method __init__ (line 11) | def __init__(self, type, sequence_no, node):
    method from_dict (line 22) | def from_dict(cls, data):
    method to_dict (line 51) | def to_dict(self):
    method __str__ (line 59) | def __str__(self):
  class InitMessage (line 68) | class InitMessage(Message):
    method __init__ (line 69) | def __init__(self, sequence_no, node, value):
    method from_dict (line 75) | def from_dict(cls, data):
    method to_dict (line 84) | def to_dict(self):
  class LeaderChangeMessage (line 92) | class LeaderChangeMessage(Message):  # pragma: no cover
    method __init__ (line 93) | def __init__(self, sequence_no, node_num, leader, P):
    method from_dict (line 99) | def from_dict(cls, data):
    method to_dict (line 108) | def to_dict(self):
  class ProposeMessage (line 118) | class ProposeMessage(Message):
    method __init__ (line 119) | def __init__(self, sequence_no, node, leader, proposal, value_store):
    method from_dict (line 127) | def from_dict(cls, data):
    method to_dict (line 144) | def to_dict(self):
  class PrevoteMessage (line 154) | class PrevoteMessage(Message):
    method __init__ (line 155) | def __init__(self, sequence_no, node, leader, value):
    method from_dict (line 162) | def from_dict(cls, data):
    method to_dict (line 173) | def to_dict(self):
  class VoteMessage (line 182) | class VoteMessage(Message):
    method __init__ (line 183) | def __init__(self, sequence_no, node, leader, value):
    method from_dict (line 190) | def from_dict(cls, data):
    method to_dict (line 200) | def to_dict(self):
  class NewLeaderMessage (line 209) | class NewLeaderMessage(Message): # pragma: no cover
    method __init__ (line 210) | def __init__(self, sequence_no, node, leader, value):
  class Acknowledge (line 218) | class Acknowledge(Message):
    method __init__ (line 219) | def __init__(self, sequence_no, node, sender, raw):
    method from_dict (line 226) | def from_dict(cls, data):
    method to_dict (line 236) | def to_dict(self):

FILE: code/node/networks/receiver.py
  class Receiver (line 24) | class Receiver(object):
    method __init__ (line 29) | def __init__(self):
    method __receiver_logging_wrapper (line 35) | def __receiver_logging_wrapper(self):
    method _receiver (line 43) | def _receiver(self):
    method reset_client (line 134) | def reset_client(self):
    method reset_socket (line 141) | def reset_socket(self):
    method _add_message (line 149) | def _add_message(self, text):
    method parse_message (line 170) | def parse_message(self, dict):
    method start (line 174) | def start(self):
    method stop (line 186) | def stop(self):
    method pop_message (line 207) | def pop_message(self):

FILE: code/node/networks/sender.py
  function send_message (line 17) | def send_message(msg):
  function broadcast (line 40) | def broadcast(message):

FILE: code/node/tests.py
  class TestJsonToObject (line 14) | class TestJsonToObject(unittest.TestCase):
    method check_InitMessage (line 22) | def check_InitMessage(self, msg, data):
    method test_InitMessage_toObject (line 30) | def test_InitMessage_toObject(self):
    method test_Message_toObject_InitMessage (line 35) | def test_Message_toObject_InitMessage(self):
    method test_InitMessage_toDict (line 40) | def test_InitMessage_toDict(self):
    method test_InitMessage_toString (line 47) | def test_InitMessage_toString(self):
    method check_ProposeMessage (line 61) | def check_ProposeMessage(self, msg):
    method test_ProposeMessage_toObject (line 70) | def test_ProposeMessage_toObject(self):
    method test_Message_toObject_ProposeMessage (line 76) | def test_Message_toObject_ProposeMessage(self):
    method test_ProposeMessage_toDict (line 82) | def test_ProposeMessage_toDict(self):
    method test_ProposeMessage_toString (line 90) | def test_ProposeMessage_toString(self):
    method test_ProposeMessage_with_InitMessage (line 104) | def test_ProposeMessage_with_InitMessage(self):
    method check_PrevoteMessage (line 119) | def check_PrevoteMessage(self, msg):
    method test_PrevoteMessage_toObject (line 128) | def test_PrevoteMessage_toObject(self):
    method test_Message_toObject_PrevoteMessage (line 133) | def test_Message_toObject_PrevoteMessage(self):
    method test_PrevoteMessage_toDict (line 138) | def test_PrevoteMessage_toDict(self):
    method test_PrevoteMessage_toString (line 145) | def test_PrevoteMessage_toString(self):
    method check_VoteMessage (line 158) | def check_VoteMessage(self, msg):
    method test_VoteMessage_toObject (line 167) | def test_VoteMessage_toObject(self):
    method test_Message_toObject_VoteMessage (line 172) | def test_Message_toObject_VoteMessage(self):
    method test_VoteMessage_toDict (line 177) | def test_VoteMessage_toDict(self):
    method test_VoteMessage_toString (line 184) | def test_VoteMessage_toString(self):
    method check_Acknowledge (line 197) | def check_Acknowledge(self, msg):
    method test_Acknowledge_toObject (line 206) | def test_Acknowledge_toObject(self):
    method test_Message_Acknowledge_toObject (line 211) | def test_Message_Acknowledge_toObject(self):
    method test_Acknowledge_toDict (line 216) | def test_Acknowledge_toDict(self):
    method test_Acknowledge_toString (line 223) | def test_Acknowledge_toString(self):
    method test_Init_unknown_type1_toObject (line 236) | def test_Init_unknown_type1_toObject(self):
    method test_Init_unknown_type2_toObject (line 253) | def test_Init_unknown_type2_toObject(self):
    method test_Message_new (line 257) | def test_Message_new(self):
    method test_Message_new_toString (line 265) | def test_Message_new_toString(self):

FILE: code/node/todo.py
  function get_sensor_value (line 8) | def get_sensor_value():
  function timeout (line 16) | def timeout():

FILE: code/web/d3/d3.v3.js
  function d3_documentElement (line 9) | function d3_documentElement(node) {
  function d3_window (line 12) | function d3_window(node) {
  function d3_ascending (line 46) | function d3_ascending(a, b) {
  function d3_number (line 109) | function d3_number(x) {
  function d3_numeric (line 112) | function d3_numeric(x) {
  function d3_bisector (line 171) | function d3_bisector(compare) {
  function d3_transposeLength (line 232) | function d3_transposeLength(d) {
  function d3_range_integerScale (line 284) | function d3_range_integerScale(x) {
  function d3_class (line 289) | function d3_class(ctor, properties) {
  function d3_Map (line 311) | function d3_Map() {
  function d3_map_escape (line 344) | function d3_map_escape(key) {
  function d3_map_unescape (line 347) | function d3_map_unescape(key) {
  function d3_map_has (line 350) | function d3_map_has(key) {
  function d3_map_remove (line 353) | function d3_map_remove(key) {
  function d3_map_keys (line 356) | function d3_map_keys() {
  function d3_map_size (line 361) | function d3_map_size() {
  function d3_map_empty (line 366) | function d3_map_empty() {
  function map (line 372) | function map(mapType, array, depth) {
  function entries (line 396) | function entries(map, depth) {
  function d3_Set (line 438) | function d3_Set() {
  function d3_identity (line 456) | function d3_identity(d) {
  function d3_rebind (line 464) | function d3_rebind(target, source, method) {
  function d3_vendorSymbol (line 470) | function d3_vendorSymbol(object, name) {
  function d3_noop (line 479) | function d3_noop() {}
  function d3_dispatch (line 485) | function d3_dispatch() {}
  function d3_dispatch_event (line 500) | function d3_dispatch_event(dispatch) {
  function d3_eventPreventDefault (line 523) | function d3_eventPreventDefault() {
  function d3_eventSource (line 526) | function d3_eventSource() {
  function d3_eventDispatch (line 531) | function d3_eventDispatch(target) {
  function d3_selection (line 557) | function d3_selection(groups) {
  function d3_selection_selector (line 600) | function d3_selection_selector(selector) {
  function d3_selection_selectorAll (line 618) | function d3_selection_selectorAll(selector) {
  function d3_selection_attr (line 654) | function d3_selection_attr(name, value) {
  function d3_collapse (line 678) | function d3_collapse(s) {
  function d3_selection_classedRe (line 698) | function d3_selection_classedRe(name) {
  function d3_selection_classes (line 701) | function d3_selection_classes(name) {
  function d3_selection_classed (line 704) | function d3_selection_classed(name, value) {
  function d3_selection_classedName (line 717) | function d3_selection_classedName(name) {
  function d3_selection_style (line 746) | function d3_selection_style(name, value, priority) {
  function d3_selection_property (line 767) | function d3_selection_property(name, value) {
  function d3_selection_creator (line 806) | function d3_selection_creator(name) {
  function d3_selectionRemove (line 826) | function d3_selectionRemove() {
  function bind (line 841) | function bind(group, groupData) {
  function d3_selection_dataNode (line 911) | function d3_selection_dataNode(data) {
  function d3_selection_filter (line 933) | function d3_selection_filter(selector) {
  function d3_selection_sortComparator (line 954) | function d3_selection_sortComparator(comparator) {
  function d3_selection_each (line 965) | function d3_selection_each(groups, callback) {
  function d3_selection_enter (line 997) | function d3_selection_enter(selection) {
  function d3_selection_enterInsertBefore (line 1030) | function d3_selection_enterInsertBefore(enter) {
  function d3_selection_on (line 1075) | function d3_selection_on(type, listener, capture) {
  function d3_selection_onListener (line 1114) | function d3_selection_onListener(listener, argumentz) {
  function d3_selection_onFilter (line 1126) | function d3_selection_onFilter(listener, argumentz) {
  function d3_event_dragSuppress (line 1136) | function d3_event_dragSuppress(node) {
  function d3_mousePoint (line 1164) | function d3_mousePoint(container, e) {
  function drag (line 1203) | function drag() {
  function dragstart (line 1206) | function dragstart(id, position, subject, move, end) {
  function d3_behavior_dragTouchId (line 1250) | function d3_behavior_dragTouchId() {
  function d3_sgn (line 1262) | function d3_sgn(x) {
  function d3_cross2d (line 1265) | function d3_cross2d(a, b, c) {
  function d3_acos (line 1268) | function d3_acos(x) {
  function d3_asin (line 1271) | function d3_asin(x) {
  function d3_sinh (line 1274) | function d3_sinh(x) {
  function d3_cosh (line 1277) | function d3_cosh(x) {
  function d3_tanh (line 1280) | function d3_tanh(x) {
  function d3_haversin (line 1283) | function d3_haversin(x) {
  function zoom (line 1320) | function zoom(g) {
  function location (line 1421) | function location(p) {
  function point (line 1424) | function point(l) {
  function scaleTo (line 1427) | function scaleTo(s) {
  function translateTo (line 1430) | function translateTo(p, l) {
  function zoomTo (line 1435) | function zoomTo(that, p, l, k) {
  function rescale (line 1447) | function rescale() {
  function zoomstarted (line 1455) | function zoomstarted(dispatch) {
  function zoomed (line 1460) | function zoomed(dispatch) {
  function zoomended (line 1468) | function zoomended(dispatch) {
  function mousedowned (line 1473) | function mousedowned() {
  function touchstarted (line 1488) | function touchstarted() {
  function mousewheeled (line 1558) | function mousewheeled() {
  function dblclicked (line 1571) | function dblclicked() {
  function d3_color (line 1579) | function d3_color() {}
  function d3_hsl (line 1584) | function d3_hsl(h, s, l) {
  function d3_hsl_rgb (line 1599) | function d3_hsl_rgb(h, s, l) {
  function d3_hcl (line 1619) | function d3_hcl(h, c, l) {
  function d3_hcl_lab (line 1632) | function d3_hcl_lab(h, c, l) {
  function d3_lab (line 1638) | function d3_lab(l, a, b) {
  function d3_lab_rgb (line 1653) | function d3_lab_rgb(l, a, b) {
  function d3_lab_hcl (line 1660) | function d3_lab_hcl(l, a, b) {
  function d3_lab_xyz (line 1663) | function d3_lab_xyz(x) {
  function d3_xyz_lab (line 1666) | function d3_xyz_lab(x) {
  function d3_xyz_rgb (line 1669) | function d3_xyz_rgb(r) {
  function d3_rgb (line 1673) | function d3_rgb(r, g, b) {
  function d3_rgbNumber (line 1676) | function d3_rgbNumber(value) {
  function d3_rgbString (line 1679) | function d3_rgbString(value) {
  function d3_rgb_hex (line 1702) | function d3_rgb_hex(v) {
  function d3_rgb_parse (line 1705) | function d3_rgb_parse(format, rgb, hsl) {
  function d3_rgb_hsl (line 1741) | function d3_rgb_hsl(r, g, b) {
  function d3_rgb_lab (line 1753) | function d3_rgb_lab(r, g, b) {
  function d3_rgb_xyz (line 1760) | function d3_rgb_xyz(r) {
  function d3_rgb_parseNumber (line 1763) | function d3_rgb_parseNumber(c) {
  function d3_functor (line 1920) | function d3_functor(v) {
  function d3_xhrType (line 1927) | function d3_xhrType(response) {
  function d3_xhr (line 1934) | function d3_xhr(url, mimeType, response, callback) {
  function d3_xhr_fixCallback (line 2009) | function d3_xhr_fixCallback(callback) {
  function d3_xhrHasResponse (line 2014) | function d3_xhrHasResponse(request) {
  function dsv (line 2020) | function dsv(url, row, callback) {
  function response (line 2028) | function response(request) {
  function typedResponse (line 2031) | function typedResponse(f) {
  function token (line 2050) | function token() {
  function formatRow (line 2112) | function formatRow(row) {
  function formatValue (line 2115) | function formatValue(text) {
  function d3_timer (line 2128) | function d3_timer(callback, delay, then) {
  function d3_timer_step (line 2146) | function d3_timer_step() {
  function d3_timer_mark (line 2163) | function d3_timer_mark() {
  function d3_timer_sweep (line 2171) | function d3_timer_sweep() {
  function d3_format_precision (line 2184) | function d3_format_precision(x, p) {
  function d3_formatPrefix (line 2201) | function d3_formatPrefix(d, i) {
  function d3_locale_numberFormat (line 2212) | function d3_locale_numberFormat(locale) {
  function d3_format_typeDefault (line 2333) | function d3_format_typeDefault(x) {
  function d3_date_utc (line 2337) | function d3_date_utc() {
  function d3_time_interval (line 2403) | function d3_time_interval(local, step, number) {
  function d3_time_interval_utc (line 2451) | function d3_time_interval_utc(method) {
  function d3_locale_timeFormat (line 2511) | function d3_locale_timeFormat(locale) {
  function d3_time_formatPad (line 2732) | function d3_time_formatPad(value, fill, width) {
  function d3_time_formatRe (line 2736) | function d3_time_formatRe(names) {
  function d3_time_formatLookup (line 2739) | function d3_time_formatLookup(names) {
  function d3_time_parseWeekdayNumber (line 2744) | function d3_time_parseWeekdayNumber(date, string, i) {
  function d3_time_parseWeekNumberSunday (line 2749) | function d3_time_parseWeekNumberSunday(date, string, i) {
  function d3_time_parseWeekNumberMonday (line 2754) | function d3_time_parseWeekNumberMonday(date, string, i) {
  function d3_time_parseFullYear (line 2759) | function d3_time_parseFullYear(date, string, i) {
  function d3_time_parseYear (line 2764) | function d3_time_parseYear(date, string, i) {
  function d3_time_parseZone (line 2769) | function d3_time_parseZone(date, string, i) {
  function d3_time_expandYear (line 2773) | function d3_time_expandYear(d) {
  function d3_time_parseMonthNumber (line 2776) | function d3_time_parseMonthNumber(date, string, i) {
  function d3_time_parseDay (line 2781) | function d3_time_parseDay(date, string, i) {
  function d3_time_parseDayOfYear (line 2786) | function d3_time_parseDayOfYear(date, string, i) {
  function d3_time_parseHour24 (line 2791) | function d3_time_parseHour24(date, string, i) {
  function d3_time_parseMinutes (line 2796) | function d3_time_parseMinutes(date, string, i) {
  function d3_time_parseSeconds (line 2801) | function d3_time_parseSeconds(date, string, i) {
  function d3_time_parseMilliseconds (line 2806) | function d3_time_parseMilliseconds(date, string, i) {
  function d3_time_zone (line 2811) | function d3_time_zone(d) {
  function d3_time_parseLiteralPercent (line 2815) | function d3_time_parseLiteralPercent(date, string, i) {
  function d3_time_formatMulti (line 2820) | function d3_time_formatMulti(formats) {
  function d3_adder (line 2851) | function d3_adder() {}
  function d3_adderSum (line 2868) | function d3_adderSum(a, b, o) {
  function d3_geo_streamGeometry (line 2879) | function d3_geo_streamGeometry(geometry, listener) {
  function d3_geo_streamLine (line 2924) | function d3_geo_streamLine(coordinates, listener, closed) {
  function d3_geo_streamPolygon (line 2930) | function d3_geo_streamPolygon(coordinates, listener) {
  function d3_geo_areaRingStart (line 2959) | function d3_geo_areaRingStart() {
  function d3_geo_cartesian (line 2977) | function d3_geo_cartesian(spherical) {
  function d3_geo_cartesianDot (line 2981) | function d3_geo_cartesianDot(a, b) {
  function d3_geo_cartesianCross (line 2984) | function d3_geo_cartesianCross(a, b) {
  function d3_geo_cartesianAdd (line 2987) | function d3_geo_cartesianAdd(a, b) {
  function d3_geo_cartesianScale (line 2992) | function d3_geo_cartesianScale(vector, k) {
  function d3_geo_cartesianNormalize (line 2995) | function d3_geo_cartesianNormalize(d) {
  function d3_geo_spherical (line 3001) | function d3_geo_spherical(cartesian) {
  function d3_geo_sphericalEqual (line 3004) | function d3_geo_sphericalEqual(a, b) {
  function point (line 3029) | function point(λ, φ) {
  function linePoint (line 3034) | function linePoint(λ, φ) {
  function lineStart (line 3074) | function lineStart() {
  function lineEnd (line 3077) | function lineEnd() {
  function ringPoint (line 3082) | function ringPoint(λ, φ) {
  function ringStart (line 3090) | function ringStart() {
  function ringEnd (line 3093) | function ringEnd() {
  function angle (line 3100) | function angle(λ0, λ1) {
  function compareRanges (line 3103) | function compareRanges(a, b) {
  function withinRange (line 3106) | function withinRange(x, range) {
  function d3_geo_centroidPoint (line 3160) | function d3_geo_centroidPoint(λ, φ) {
  function d3_geo_centroidPointXYZ (line 3165) | function d3_geo_centroidPointXYZ(x, y, z) {
  function d3_geo_centroidLineStart (line 3171) | function d3_geo_centroidLineStart() {
  function d3_geo_centroidLineEnd (line 3192) | function d3_geo_centroidLineEnd() {
  function d3_geo_centroidRingStart (line 3195) | function d3_geo_centroidRingStart() {
  function d3_geo_compose (line 3225) | function d3_geo_compose(a, b) {
  function d3_true (line 3234) | function d3_true() {
  function d3_geo_clipPolygon (line 3237) | function d3_geo_clipPolygon(segments, compare, clipStartInside, interpol...
  function d3_geo_clipPolygonLinkCircular (line 3296) | function d3_geo_clipPolygonLinkCircular(array) {
  function d3_geo_clipPolygonIntersection (line 3307) | function d3_geo_clipPolygonIntersection(point, points, other, entry) {
  function d3_geo_clip (line 3315) | function d3_geo_clip(pointVisible, clipLine, interpolate, clipStart) {
  function d3_geo_clipSegmentLength1 (line 3407) | function d3_geo_clipSegmentLength1(segment) {
  function d3_geo_clipBufferListener (line 3410) | function d3_geo_clipBufferListener() {
  function d3_geo_clipSort (line 3431) | function d3_geo_clipSort(a, b) {
  function d3_geo_clipAntimeridianLine (line 3435) | function d3_geo_clipAntimeridianLine(listener) {
  function d3_geo_clipAntimeridianIntersect (line 3474) | function d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1) {
  function d3_geo_clipAntimeridianInterpolate (line 3478) | function d3_geo_clipAntimeridianInterpolate(from, to, direction, listene...
  function d3_geo_pointInPolygon (line 3501) | function d3_geo_pointInPolygon(point, polygon) {
  function d3_geo_clipCircle (line 3530) | function d3_geo_clipCircle(radius) {
  function d3_geom_clipLine (line 3626) | function d3_geom_clipLine(x0, y0, x1, y1) {
  function d3_geo_clipExtent (line 3698) | function d3_geo_clipExtent(x0, y0, x1, y1) {
  function d3_geo_conic (line 3832) | function d3_geo_conic(projectAt) {
  function d3_geo_conicEqualArea (line 3840) | function d3_geo_conicEqualArea(φ0, φ1) {
  function albersUsa (line 3867) | function albersUsa(coordinates) {
  function d3_geo_pathAreaRingStart (line 3949) | function d3_geo_pathAreaRingStart() {
  function d3_geo_pathBoundsPoint (line 3971) | function d3_geo_pathBoundsPoint(x, y) {
  function d3_geo_pathBuffer (line 3977) | function d3_geo_pathBuffer() {
  function d3_geo_pathBufferCircle (line 4022) | function d3_geo_pathBufferCircle(radius) {
  function d3_geo_pathCentroidPoint (line 4038) | function d3_geo_pathCentroidPoint(x, y) {
  function d3_geo_pathCentroidLineStart (line 4043) | function d3_geo_pathCentroidLineStart() {
  function d3_geo_pathCentroidLineEnd (line 4057) | function d3_geo_pathCentroidLineEnd() {
  function d3_geo_pathCentroidRingStart (line 4060) | function d3_geo_pathCentroidRingStart() {
  function d3_geo_pathContext (line 4081) | function d3_geo_pathContext(context) {
  function d3_geo_resample (line 4121) | function d3_geo_resample(project) {
  function path (line 4201) | function path(object) {
  function reset (line 4240) | function reset() {
  function d3_geo_pathProjectStream (line 4246) | function d3_geo_pathProjectStream(project) {
  function d3_geo_transform (line 4263) | function d3_geo_transform(stream) {
  function d3_geo_transformPoint (line 4286) | function d3_geo_transformPoint(stream, point) {
  function d3_geo_projection (line 4308) | function d3_geo_projection(project) {
  function d3_geo_projectionMutator (line 4313) | function d3_geo_projectionMutator(projectAt) {
  function d3_geo_projectionRadians (line 4385) | function d3_geo_projectionRadians(stream) {
  function d3_geo_equirectangular (line 4390) | function d3_geo_equirectangular(λ, φ) {
  function forward (line 4398) | function forward(coordinates) {
  function d3_geo_identityRotation (line 4408) | function d3_geo_identityRotation(λ, φ) {
  function d3_geo_rotation (line 4412) | function d3_geo_rotation(δλ, δφ, δγ) {
  function d3_geo_forwardRotationλ (line 4415) | function d3_geo_forwardRotationλ(δλ) {
  function d3_geo_rotationλ (line 4420) | function d3_geo_rotationλ(δλ) {
  function d3_geo_rotationφγ (line 4425) | function d3_geo_rotationφγ(δφ, δγ) {
  function circle (line 4439) | function circle() {
  function d3_geo_circleInterpolate (line 4469) | function d3_geo_circleInterpolate(radius, precision) {
  function d3_geo_circleAngle (line 4486) | function d3_geo_circleAngle(cr, point) {
  function graticule (line 4499) | function graticule() {
  function lines (line 4505) | function lines() {
  function d3_geo_graticuleX (line 4571) | function d3_geo_graticuleX(y0, y1, dy) {
  function d3_geo_graticuleY (line 4579) | function d3_geo_graticuleY(x0, x1, dx) {
  function d3_source (line 4587) | function d3_source(d) {
  function d3_target (line 4590) | function d3_target(d) {
  function greatArc (line 4595) | function greatArc() {
  function d3_geo_interpolate (line 4622) | function d3_geo_interpolate(x0, y0, x1, y1) {
  function d3_geo_lengthLineStart (line 4647) | function d3_geo_lengthLineStart() {
  function d3_geo_azimuthal (line 4662) | function d3_geo_azimuthal(scale, angle) {
  function d3_geo_conicConformal (line 4688) | function d3_geo_conicConformal(φ0, φ1) {
  function d3_geo_conicEquidistant (line 4711) | function d3_geo_conicEquidistant(φ0, φ1) {
  function d3_geo_mercator (line 4733) | function d3_geo_mercator(λ, φ) {
  function d3_geo_mercatorProjection (line 4739) | function d3_geo_mercatorProjection(project) {
  function d3_geo_transverseMercator (line 4780) | function d3_geo_transverseMercator(λ, φ) {
  function d3_geom_pointX (line 4798) | function d3_geom_pointX(d) {
  function d3_geom_pointY (line 4801) | function d3_geom_pointY(d) {
  function hull (line 4807) | function hull(data) {
  function d3_geom_hullUpper (line 4829) | function d3_geom_hullUpper(points) {
  function d3_geom_hullOrder (line 4837) | function d3_geom_hullOrder(a, b) {
  function d3_geom_polygonInside (line 4891) | function d3_geom_polygonInside(p, a, b) {
  function d3_geom_polygonIntersect (line 4894) | function d3_geom_polygonIntersect(c, d, a, b) {
  function d3_geom_polygonClosed (line 4898) | function d3_geom_polygonClosed(coordinates) {
  function d3_geom_voronoiBeach (line 4903) | function d3_geom_voronoiBeach() {
  function d3_geom_voronoiCreateBeach (line 4907) | function d3_geom_voronoiCreateBeach(site) {
  function d3_geom_voronoiDetachBeach (line 4912) | function d3_geom_voronoiDetachBeach(beach) {
  function d3_geom_voronoiRemoveBeach (line 4918) | function d3_geom_voronoiRemoveBeach(beach) {
  function d3_geom_voronoiAddBeach (line 4954) | function d3_geom_voronoiAddBeach(site) {
  function d3_geom_voronoiLeftBreakPoint (line 5008) | function d3_geom_voronoiLeftBreakPoint(arc, directrix) {
  function d3_geom_voronoiRightBreakPoint (line 5020) | function d3_geom_voronoiRightBreakPoint(arc, directrix) {
  function d3_geom_voronoiCell (line 5026) | function d3_geom_voronoiCell(site) {
  function d3_geom_voronoiCloseCells (line 5039) | function d3_geom_voronoiCloseCells(extent) {
  function d3_geom_voronoiHalfEdgeOrder (line 5069) | function d3_geom_voronoiHalfEdgeOrder(a, b) {
  function d3_geom_voronoiCircle (line 5072) | function d3_geom_voronoiCircle() {
  function d3_geom_voronoiAttachCircle (line 5076) | function d3_geom_voronoiAttachCircle(arc) {
  function d3_geom_voronoiDetachCircle (line 5109) | function d3_geom_voronoiDetachCircle(arc) {
  function d3_geom_voronoiClipEdges (line 5119) | function d3_geom_voronoiClipEdges(extent) {
  function d3_geom_voronoiConnectEdge (line 5129) | function d3_geom_voronoiConnectEdge(edge, extent) {
  function d3_geom_voronoiEdge (line 5203) | function d3_geom_voronoiEdge(lSite, rSite) {
  function d3_geom_voronoiCreateEdge (line 5208) | function d3_geom_voronoiCreateEdge(lSite, rSite, va, vb) {
  function d3_geom_voronoiCreateBorderEdge (line 5217) | function d3_geom_voronoiCreateBorderEdge(lSite, va, vb) {
  function d3_geom_voronoiSetEdgeEnd (line 5224) | function d3_geom_voronoiSetEdgeEnd(edge, lSite, rSite, vertex) {
  function d3_geom_voronoiHalfEdge (line 5235) | function d3_geom_voronoiHalfEdge(edge, lSite, rSite) {
  function d3_geom_voronoiRedBlackTree (line 5249) | function d3_geom_voronoiRedBlackTree() {
  function d3_geom_voronoiRedBlackNode (line 5252) | function d3_geom_voronoiRedBlackNode(node) {
  function d3_geom_voronoiRedBlackRotateLeft (line 5415) | function d3_geom_voronoiRedBlackRotateLeft(tree, node) {
  function d3_geom_voronoiRedBlackRotateRight (line 5428) | function d3_geom_voronoiRedBlackRotateRight(tree, node) {
  function d3_geom_voronoiRedBlackFirst (line 5441) | function d3_geom_voronoiRedBlackFirst(node) {
  function d3_geom_voronoi (line 5445) | function d3_geom_voronoi(sites, bbox) {
  function d3_geom_voronoiVertexOrder (line 5474) | function d3_geom_voronoiVertexOrder(a, b) {
  function voronoi (line 5480) | function voronoi(data) {
  function sites (line 5491) | function sites(data) {
  function d3_geom_voronoiTriangleArea (line 5544) | function d3_geom_voronoiTriangleArea(a, b, c) {
  function quadtree (line 5562) | function quadtree(data) {
  function d3_geom_quadtreeCompatX (line 5657) | function d3_geom_quadtreeCompatX(d) {
  function d3_geom_quadtreeCompatY (line 5660) | function d3_geom_quadtreeCompatY(d) {
  function d3_geom_quadtreeNode (line 5663) | function d3_geom_quadtreeNode() {
  function d3_geom_quadtreeVisit (line 5672) | function d3_geom_quadtreeVisit(f, node, x1, y1, x2, y2) {
  function d3_geom_quadtreeFind (line 5681) | function d3_geom_quadtreeFind(root, x, y, x0, y0, x3, y3) {
  function d3_interpolateRgb (line 5718) | function d3_interpolateRgb(a, b) {
  function d3_interpolateObject (line 5727) | function d3_interpolateObject(a, b) {
  function d3_interpolateNumber (line 5747) | function d3_interpolateNumber(a, b) {
  function d3_interpolateString (line 5754) | function d3_interpolateString(a, b) {
  function d3_interpolate (line 5788) | function d3_interpolate(a, b) {
  function d3_interpolateArray (line 5798) | function d3_interpolateArray(a, b) {
  function d3_ease_clamp (line 5849) | function d3_ease_clamp(f) {
  function d3_ease_reverse (line 5854) | function d3_ease_reverse(f) {
  function d3_ease_reflect (line 5859) | function d3_ease_reflect(f) {
  function d3_ease_quad (line 5864) | function d3_ease_quad(t) {
  function d3_ease_cubic (line 5867) | function d3_ease_cubic(t) {
  function d3_ease_cubicInOut (line 5870) | function d3_ease_cubicInOut(t) {
  function d3_ease_poly (line 5876) | function d3_ease_poly(e) {
  function d3_ease_sin (line 5881) | function d3_ease_sin(t) {
  function d3_ease_exp (line 5884) | function d3_ease_exp(t) {
  function d3_ease_circle (line 5887) | function d3_ease_circle(t) {
  function d3_ease_elastic (line 5890) | function d3_ease_elastic(a, p) {
  function d3_ease_back (line 5898) | function d3_ease_back(s) {
  function d3_ease_bounce (line 5904) | function d3_ease_bounce(t) {
  function d3_interpolateHcl (line 5908) | function d3_interpolateHcl(a, b) {
  function d3_interpolateHsl (line 5919) | function d3_interpolateHsl(a, b) {
  function d3_interpolateLab (line 5930) | function d3_interpolateLab(a, b) {
  function d3_interpolateRound (line 5939) | function d3_interpolateRound(a, b) {
  function d3_transform (line 5955) | function d3_transform(m) {
  function d3_transformDot (line 5971) | function d3_transformDot(a, b) {
  function d3_transformNormalize (line 5974) | function d3_transformNormalize(a) {
  function d3_transformCombine (line 5982) | function d3_transformCombine(a, b, k) {
  function d3_interpolateTransformPop (line 5996) | function d3_interpolateTransformPop(s) {
  function d3_interpolateTranslate (line 5999) | function d3_interpolateTranslate(ta, tb, s, q) {
  function d3_interpolateRotate (line 6013) | function d3_interpolateRotate(ra, rb, s, q) {
  function d3_interpolateSkew (line 6024) | function d3_interpolateSkew(wa, wb, s, q) {
  function d3_interpolateScale (line 6034) | function d3_interpolateScale(ka, kb, s, q) {
  function d3_interpolateTransform (line 6048) | function d3_interpolateTransform(a, b) {
  function d3_uninterpolateNumber (line 6062) | function d3_uninterpolateNumber(a, b) {
  function d3_uninterpolateClamp (line 6068) | function d3_uninterpolateClamp(a, b) {
  function d3_layout_bundlePath (line 6082) | function d3_layout_bundlePath(link) {
  function d3_layout_bundleAncestors (line 6095) | function d3_layout_bundleAncestors(node) {
  function d3_layout_bundleLeastCommonAncestor (line 6105) | function d3_layout_bundleLeastCommonAncestor(a, b) {
  function relayout (line 6117) | function relayout() {
  function resort (line 6183) | function resort() {
  function repulse (line 6230) | function repulse(node) {
  function position (line 6411) | function position(dimension, size) {
  function dragmove (line 6440) | function dragmove(d) {
  function d3_layout_forceDragstart (line 6446) | function d3_layout_forceDragstart(d) {
  function d3_layout_forceDragend (line 6449) | function d3_layout_forceDragend(d) {
  function d3_layout_forceMouseover (line 6452) | function d3_layout_forceMouseover(d) {
  function d3_layout_forceMouseout (line 6456) | function d3_layout_forceMouseout(d) {
  function d3_layout_forceAccumulate (line 6459) | function d3_layout_forceAccumulate(quad, alpha, charges) {
  function hierarchy (line 6489) | function hierarchy(root) {
  function d3_layout_hierarchyRebind (line 6545) | function d3_layout_hierarchyRebind(object, hierarchy) {
  function d3_layout_hierarchyVisitBefore (line 6551) | function d3_layout_hierarchyVisitBefore(node, callback) {
  function d3_layout_hierarchyVisitAfter (line 6561) | function d3_layout_hierarchyVisitAfter(node, callback) {
  function d3_layout_hierarchyChildren (line 6574) | function d3_layout_hierarchyChildren(d) {
  function d3_layout_hierarchyValue (line 6577) | function d3_layout_hierarchyValue(d) {
  function d3_layout_hierarchySort (line 6580) | function d3_layout_hierarchySort(a, b) {
  function d3_layout_hierarchyLinks (line 6583) | function d3_layout_hierarchyLinks(nodes) {
  function position (line 6595) | function position(node, x, dx, dy) {
  function depth (line 6610) | function depth(node) {
  function partition (line 6618) | function partition(d, i) {
  function pie (line 6632) | function pie(data) {
  function stack (line 6682) | function stack(data, index) {
  function d3_layout_stackX (line 6737) | function d3_layout_stackX(d) {
  function d3_layout_stackY (line 6740) | function d3_layout_stackY(d) {
  function d3_layout_stackOut (line 6743) | function d3_layout_stackOut(d, y0, y) {
  function d3_layout_stackOrderDefault (line 6810) | function d3_layout_stackOrderDefault(data) {
  function d3_layout_stackOffsetZero (line 6813) | function d3_layout_stackOffsetZero(data) {
  function d3_layout_stackMaxIndex (line 6818) | function d3_layout_stackMaxIndex(array) {
  function d3_layout_stackReduceSum (line 6828) | function d3_layout_stackReduceSum(d) {
  function d3_layout_stackSum (line 6831) | function d3_layout_stackSum(p, d) {
  function histogram (line 6836) | function histogram(data, i) {
  function d3_layout_histogramBinSturges (line 6880) | function d3_layout_histogramBinSturges(range, values) {
  function d3_layout_histogramBinFixed (line 6883) | function d3_layout_histogramBinFixed(range, n) {
  function d3_layout_histogramRange (line 6888) | function d3_layout_histogramRange(values) {
  function pack (line 6893) | function pack(d, i) {
  function d3_layout_packSort (line 6932) | function d3_layout_packSort(a, b) {
  function d3_layout_packInsert (line 6935) | function d3_layout_packInsert(a, b) {
  function d3_layout_packSplice (line 6942) | function d3_layout_packSplice(a, b) {
  function d3_layout_packIntersects (line 6946) | function d3_layout_packIntersects(a, b) {
  function d3_layout_packSiblings (line 6950) | function d3_layout_packSiblings(node) {
  function d3_layout_packLink (line 7014) | function d3_layout_packLink(node) {
  function d3_layout_packUnlink (line 7017) | function d3_layout_packUnlink(node) {
  function d3_layout_packTransform (line 7021) | function d3_layout_packTransform(node, x, y, k) {
  function d3_layout_packPlace (line 7031) | function d3_layout_packPlace(a, b, c) {
  function tree (line 7047) | function tree(d, i) {
  function wrapTree (line 7066) | function wrapTree(root0) {
  function firstWalk (line 7090) | function firstWalk(v) {
  function secondWalk (line 7106) | function secondWalk(v) {
  function apportion (line 7110) | function apportion(v, w, ancestor) {
  function sizeNode (line 7140) | function sizeNode(node) {
  function d3_layout_treeSeparation (line 7161) | function d3_layout_treeSeparation(a, b) {
  function d3_layout_treeLeft (line 7164) | function d3_layout_treeLeft(v) {
  function d3_layout_treeRight (line 7168) | function d3_layout_treeRight(v) {
  function d3_layout_treeMove (line 7172) | function d3_layout_treeMove(wm, wp, shift) {
  function d3_layout_treeShift (line 7180) | function d3_layout_treeShift(v) {
  function d3_layout_treeAncestor (line 7189) | function d3_layout_treeAncestor(vim, v, ancestor) {
  function cluster (line 7194) | function cluster(d, i) {
  function d3_layout_clusterY (line 7234) | function d3_layout_clusterY(children) {
  function d3_layout_clusterX (line 7239) | function d3_layout_clusterX(children) {
  function d3_layout_clusterLeft (line 7244) | function d3_layout_clusterLeft(node) {
  function d3_layout_clusterRight (line 7248) | function d3_layout_clusterRight(node) {
  function scale (line 7254) | function scale(children, k) {
  function squarify (line 7261) | function squarify(node) {
  function stickify (line 7288) | function stickify(node) {
  function worst (line 7305) | function worst(row, u) {
  function position (line 7316) | function position(row, u, rect, flush) {
  function treemap (line 7346) | function treemap(d) {
  function padFunction (line 7363) | function padFunction(node) {
  function padConstant (line 7367) | function padConstant(node) {
  function d3_layout_treemapPadNull (line 7398) | function d3_layout_treemapPadNull(node) {
  function d3_layout_treemapPad (line 7406) | function d3_layout_treemapPad(node, padding) {
  function d3_scaleExtent (line 7458) | function d3_scaleExtent(domain) {
  function d3_scaleRange (line 7462) | function d3_scaleRange(scale) {
  function d3_scale_bilinear (line 7465) | function d3_scale_bilinear(domain, range, uninterpolate, interpolate) {
  function d3_scale_nice (line 7471) | function d3_scale_nice(domain, nice) {
  function d3_scale_niceStep (line 7481) | function d3_scale_niceStep(step) {
  function d3_scale_polylinear (line 7495) | function d3_scale_polylinear(domain, range, uninterpolate, interpolate) {
  function d3_scale_linear (line 7513) | function d3_scale_linear(domain, range, interpolate, clamp) {
  function d3_scale_linearRebind (line 7565) | function d3_scale_linearRebind(scale, linear) {
  function d3_scale_linearNice (line 7568) | function d3_scale_linearNice(domain, m) {
  function d3_scale_linearTickRange (line 7573) | function d3_scale_linearTickRange(domain, m) {
  function d3_scale_linearTicks (line 7582) | function d3_scale_linearTicks(domain, m) {
  function d3_scale_linearTickFormat (line 7585) | function d3_scale_linearTickFormat(domain, m, format) {
  function d3_scale_linearPrecision (line 7613) | function d3_scale_linearPrecision(value) {
  function d3_scale_linearFormatPrecision (line 7616) | function d3_scale_linearFormatPrecision(type, range) {
  function d3_scale_log (line 7623) | function d3_scale_log(linear, base, positive, domain) {
  function d3_scale_pow (line 7696) | function d3_scale_pow(linear, exponent, domain) {
  function d3_scale_powPow (line 7730) | function d3_scale_powPow(e) {
  function d3_scale_ordinal (line 7744) | function d3_scale_ordinal(domain, ranger) {
  function d3_scale_quantile (line 7852) | function d3_scale_quantile(domain, range) {
  function d3_scale_quantize (line 7888) | function d3_scale_quantize(x0, x1, range) {
  function d3_scale_threshold (line 7922) | function d3_scale_threshold(domain, range) {
  function d3_scale_identity (line 7948) | function d3_scale_identity(domain) {
  function d3_zero (line 7970) | function d3_zero() {
  function arc (line 7975) | function arc() {
  function circleSegment (line 8053) | function circleSegment(r1, cw) {
  function d3_svg_arcInnerRadius (line 8098) | function d3_svg_arcInnerRadius(d) {
  function d3_svg_arcOuterRadius (line 8101) | function d3_svg_arcOuterRadius(d) {
  function d3_svg_arcStartAngle (line 8104) | function d3_svg_arcStartAngle(d) {
  function d3_svg_arcEndAngle (line 8107) | function d3_svg_arcEndAngle(d) {
  function d3_svg_arcPadAngle (line 8110) | function d3_svg_arcPadAngle(d) {
  function d3_svg_arcSweep (line 8113) | function d3_svg_arcSweep(x0, y0, x1, y1) {
  function d3_svg_arcCornerTangents (line 8116) | function d3_svg_arcCornerTangents(p0, p1, r1, rc, cw) {
  function d3_svg_line (line 8121) | function d3_svg_line(projection) {
  function d3_svg_lineLinear (line 8188) | function d3_svg_lineLinear(points) {
  function d3_svg_lineLinearClosed (line 8191) | function d3_svg_lineLinearClosed(points) {
  function d3_svg_lineStep (line 8194) | function d3_svg_lineStep(points) {
  function d3_svg_lineStepBefore (line 8200) | function d3_svg_lineStepBefore(points) {
  function d3_svg_lineStepAfter (line 8205) | function d3_svg_lineStepAfter(points) {
  function d3_svg_lineCardinalOpen (line 8210) | function d3_svg_lineCardinalOpen(points, tension) {
  function d3_svg_lineCardinalClosed (line 8213) | function d3_svg_lineCardinalClosed(points, tension) {
  function d3_svg_lineCardinal (line 8217) | function d3_svg_lineCardinal(points, tension) {
  function d3_svg_lineHermite (line 8220) | function d3_svg_lineHermite(points, tangents) {
  function d3_svg_lineCardinalTangents (line 8247) | function d3_svg_lineCardinalTangents(points, tension) {
  function d3_svg_lineBasis (line 8257) | function d3_svg_lineBasis(points) {
  function d3_svg_lineBasisOpen (line 8273) | function d3_svg_lineBasisOpen(points) {
  function d3_svg_lineBasisClosed (line 8293) | function d3_svg_lineBasisClosed(points) {
  function d3_svg_lineBundle (line 8312) | function d3_svg_lineBundle(points, tension) {
  function d3_svg_lineDot4 (line 8325) | function d3_svg_lineDot4(a, b) {
  function d3_svg_lineBasisBezier (line 8329) | function d3_svg_lineBasisBezier(path, x, y) {
  function d3_svg_lineSlope (line 8332) | function d3_svg_lineSlope(p0, p1) {
  function d3_svg_lineFiniteDifferences (line 8335) | function d3_svg_lineFiniteDifferences(points) {
  function d3_svg_lineMonotoneTangents (line 8343) | function d3_svg_lineMonotoneTangents(points) {
  function d3_svg_lineMonotone (line 8367) | function d3_svg_lineMonotone(points) {
  function d3_svg_lineRadial (line 8376) | function d3_svg_lineRadial(points) {
  function d3_svg_area (line 8387) | function d3_svg_area(projection) {
  function chord (line 8477) | function chord(d, i) {
  function subgroup (line 8481) | function subgroup(self, f, d, i) {
  function equals (line 8491) | function equals(a, b) {
  function arc (line 8494) | function arc(r, p, a) {
  function curve (line 8497) | function curve(r0, p0, r1, p1) {
  function d3_svg_chordRadius (line 8527) | function d3_svg_chordRadius(d) {
  function diagonal (line 8532) | function diagonal(d, i) {
  function d3_svg_diagonalProjection (line 8560) | function d3_svg_diagonalProjection(d) {
  function d3_svg_diagonalRadialProjection (line 8570) | function d3_svg_diagonalRadialProjection(projection) {
  function symbol (line 8578) | function symbol(d, i) {
  function d3_svg_symbolSize (line 8593) | function d3_svg_symbolSize() {
  function d3_svg_symbolType (line 8596) | function d3_svg_symbolType() {
  function d3_svg_symbolCircle (line 8599) | function d3_svg_symbolCircle(size) {
  function d3_selection_interruptNS (line 8648) | function d3_selection_interruptNS(ns) {
  function d3_transition (line 8660) | function d3_transition(groups, ns, id) {
  function d3_transition_tween (line 8732) | function d3_transition_tween(groups, name, value, tween) {
  function attrNull (line 8746) | function attrNull() {
  function attrNullNS (line 8749) | function attrNullNS() {
  function attrTween (line 8752) | function attrTween(b) {
  function attrTweenNS (line 8760) | function attrTweenNS(b) {
  function attrTween (line 8772) | function attrTween(d, i) {
  function attrTweenNS (line 8778) | function attrTweenNS(d, i) {
  function styleNull (line 8796) | function styleNull() {
  function styleString (line 8799) | function styleString(b) {
  function styleTween (line 8811) | function styleTween(d, i) {
  function d3_transition_text (line 8822) | function d3_transition_text(b) {
  function d3_transitionNamespace (line 8902) | function d3_transitionNamespace(name) {
  function d3_transitionNode (line 8905) | function d3_transitionNode(node, i, ns, id, inherit) {
  function axis (line 8982) | function axis(g) {
  function d3_svg_axisX (line 9077) | function d3_svg_axisX(selection, x0, x1) {
  function d3_svg_axisY (line 9083) | function d3_svg_axisY(selection, y0, y1) {
  function brush (line 9091) | function brush(g) {
  function redraw (line 9177) | function redraw(g) {
  function redrawX (line 9182) | function redrawX(g) {
  function redrawY (line 9186) | function redrawY(g) {
  function brushstart (line 9190) | function brushstart() {
  function d3_time_formatIsoNative (line 9383) | function d3_time_formatIsoNative(date) {
  function d3_time_scale (line 9430) | function d3_time_scale(linear, methods, format) {
  function d3_time_scaleDate (line 9480) | function d3_time_scaleDate(t) {
  function d3_json (line 9539) | function d3_json(request) {
  function d3_html (line 9545) | function d3_html(request) {

FILE: code/web/src/core/d3/d3.factory.js
  function n (line 10) | function n(n){return null!=n&&!isNaN(n)}
  function t (line 10) | function t(n){return n.length}
  function e (line 10) | function e(n){for(var t=1;n*t%1;)t*=10;return t}
  function r (line 10) | function r(n,t){try{for(var e in t)Object.defineProperty(n.prototype,e,{...
  function u (line 10) | function u(){}
  function i (line 10) | function i(){}
  function o (line 10) | function o(n,t,e){return function(){var r=e.apply(t,arguments);return r=...
  function a (line 10) | function a(n,t){if(t in n)return t;t=t.charAt(0).toUpperCase()+t.substri...
  function c (line 10) | function c(){}
  function l (line 10) | function l(){}
  function s (line 10) | function s(n){function t(){for(var t,r=e,u=-1,i=r.length;++u<i;)(t=r[u]....
  function f (line 10) | function f(){mo.event.preventDefault()}
  function h (line 10) | function h(){for(var n,t=mo.event;n=t.sourceEvent;)t=n;return t}
  function g (line 10) | function g(n){for(var t=new l,e=0,r=arguments.length;++e<r;)t[arguments[...
  function p (line 10) | function p(n){return Lo(n,Ro),n}
  function d (line 10) | function d(n){return"function"==typeof n?n:function(){return Ho(n,this)}}
  function v (line 10) | function v(n){return"function"==typeof n?n:function(){return Fo(n,this)}}
  function m (line 10) | function m(n,t){function e(){this.removeAttribute(n)}function r(){this.r...
  function y (line 10) | function y(n){return n.trim().replace(/\s+/g," ")}
  function M (line 10) | function M(n){return new RegExp("(?:^|\\s+)"+mo.requote(n)+"(?:\\s+|$)",...
  function x (line 10) | function x(n,t){function e(){for(var e=-1;++e<u;)n[e](this,t)}function r...
  function b (line 10) | function b(n){var t=M(n);return function(e,r){if(u=e.classList)return r?...
  function _ (line 10) | function _(n,t,e){function r(){this.style.removeProperty(n)}function u()...
  function w (line 10) | function w(n,t){function e(){delete this[n]}function r(){this[n]=t}funct...
  function S (line 10) | function S(n){return"function"==typeof n?n:(n=mo.ns.qualify(n)).local?fu...
  function E (line 10) | function E(n){return{__data__:n}}
  function k (line 10) | function k(n){return function(){return Oo(this,n)}}
  function A (line 10) | function A(n){return arguments.length||(n=mo.ascending),function(t,e){re...
  function N (line 10) | function N(n,t){for(var e=0,r=n.length;r>e;e++)for(var u,i=n[e],o=0,a=i....
  function T (line 10) | function T(n){return Lo(n,Io),n}
  function q (line 10) | function q(n){var t,e;return function(r,u,i){var o,a=n[i].update,c=a.len...
  function z (line 10) | function z(){var n=this.__transition__;n&&++n.active}
  function C (line 10) | function C(n,t,e){function r(){var t=this[o];t&&(this.removeEventListene...
  function D (line 10) | function D(n,t){return function(e){var r=mo.event;mo.event=e,t[0]=this._...
  function j (line 10) | function j(n,t){var e=D(n,t);return function(n){var t=this,r=n.relatedTa...
  function L (line 10) | function L(){var n=".dragsuppress-"+ ++Xo,t="touchmove"+n,e="selectstart...
  function H (line 10) | function H(n,t){t.changedTouches&&(t=t.changedTouches[0]);var e=n.ownerS...
  function F (line 10) | function F(n){return n>0?1:0>n?-1:0}
  function P (line 10) | function P(n){return n>1?0:-1>n?Bo:Math.acos(n)}
  function O (line 10) | function O(n){return n>1?Bo/2:-1>n?-Bo/2:Math.asin(n)}
  function R (line 10) | function R(n){return(Math.exp(n)-Math.exp(-n))/2}
  function Y (line 10) | function Y(n){return(Math.exp(n)+Math.exp(-n))/2}
  function I (line 10) | function I(n){return R(n)/Y(n)}
  function U (line 10) | function U(n){return(n=Math.sin(n/2))*n}
  function Z (line 10) | function Z(){}
  function V (line 10) | function V(n,t,e){return new X(n,t,e)}
  function X (line 10) | function X(n,t,e){this.h=n,this.s=t,this.l=e}
  function $ (line 10) | function $(n,t,e){function r(n){return n>360?n-=360:0>n&&(n+=360),60>n?i...
  function B (line 10) | function B(n,t,e){return new W(n,t,e)}
  function W (line 10) | function W(n,t,e){this.h=n,this.c=t,this.l=e}
  function J (line 10) | function J(n,t,e){return isNaN(n)&&(n=0),isNaN(t)&&(t=0),G(e,Math.cos(n*...
  function G (line 10) | function G(n,t,e){return new K(n,t,e)}
  function K (line 10) | function K(n,t,e){this.l=n,this.a=t,this.b=e}
  function Q (line 10) | function Q(n,t,e){var r=(n+16)/116,u=r+t/500,i=r-e/200;return u=tt(u)*ca...
  function nt (line 10) | function nt(n,t,e){return n>0?B(Math.atan2(e,t)*Ko,Math.sqrt(t*t+e*e),n)...
  function tt (line 10) | function tt(n){return n>.206893034?n*n*n:(n-4/29)/7.787037}
  function et (line 10) | function et(n){return n>.008856?Math.pow(n,1/3):7.787037*n+4/29}
  function rt (line 10) | function rt(n){return Math.round(255*(.00304>=n?12.92*n:1.055*Math.pow(n...
  function ut (line 10) | function ut(n){return ot(n>>16,255&n>>8,255&n)}
  function it (line 10) | function it(n){return ut(n)+""}
  function ot (line 10) | function ot(n,t,e){return new at(n,t,e)}
  function at (line 10) | function at(n,t,e){this.r=n,this.g=t,this.b=e}
  function ct (line 10) | function ct(n){return 16>n?"0"+Math.max(0,n).toString(16):Math.min(255,n...
  function lt (line 10) | function lt(n,t,e){var r,u,i,o=0,a=0,c=0;if(r=/([a-z]+)\((.*)\)/i.exec(n...
  function st (line 10) | function st(n,t,e){var r,u,i=Math.min(n/=255,t/=255,e/=255),o=Math.max(n...
  function ft (line 10) | function ft(n,t,e){n=ht(n),t=ht(t),e=ht(e);var r=et((.4124564*n+.3575761...
  function ht (line 10) | function ht(n){return(n/=255)<=.04045?n/12.92:Math.pow((n+.055)/1.055,2.4)}
  function gt (line 10) | function gt(n){var t=parseFloat(n);return"%"===n.charAt(n.length-1)?Math...
  function pt (line 10) | function pt(n){return"function"==typeof n?n:function(){return n}}
  function dt (line 10) | function dt(n){return n}
  function vt (line 10) | function vt(n){return function(t,e,r){return 2===arguments.length&&"func...
  function mt (line 10) | function mt(n,t,e,r){function u(){var n,t=c.status;if(!t&&c.responseText...
  function yt (line 10) | function yt(n){return 1===n.length?function(t,e){n(null==t?e:null)}:n}
  function Mt (line 10) | function Mt(){var n=bt(),t=_t()-n;t>24?(isFinite(t)&&(clearTimeout(ma),m...
  function xt (line 10) | function xt(n,t,e){var r=arguments.length;2>r&&(t=0),3>r&&(e=Date.now())...
  function bt (line 10) | function bt(){var n=Date.now();for(ya=pa;ya;)n>=ya.time&&(ya.flush=ya.ca...
  function _t (line 10) | function _t(){for(var n,t=pa,e=1/0;t;)t.flush?t=n?n.next=t.next:pa=t.nex...
  function wt (line 10) | function wt(n,t){var e=Math.pow(10,3*Math.abs(8-t));return{scale:t>8?fun...
  function St (line 10) | function St(n,t){return t-(n?Math.ceil(Math.log(n)/Math.LN10):1)}
  function Et (line 10) | function Et(n){return n+""}
  function kt (line 10) | function kt(){}
  function At (line 10) | 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 (line 10) | function Nt(n,t){n&&za.hasOwnProperty(n.type)&&za[n.type](n,t)}
  function Tt (line 10) | function Tt(n,t,e){var r,u=-1,i=n.length-e;for(t.lineStart();++u<i;)r=n[...
  function qt (line 10) | function qt(n,t){var e=-1,r=n.length;for(t.polygonStart();++e<r;)Tt(n[e]...
  function zt (line 10) | function zt(){function n(n,t){n*=Go,t=t*Go/2+Bo/4;var e=n-r,o=Math.cos(t...
  function Ct (line 10) | function Ct(n){var t=n[0],e=n[1],r=Math.cos(e);return[r*Math.cos(t),r*Ma...
  function Dt (line 10) | function Dt(n,t){return n[0]*t[0]+n[1]*t[1]+n[2]*t[2]}
  function jt (line 10) | function jt(n,t){return[n[1]*t[2]-n[2]*t[1],n[2]*t[0]-n[0]*t[2],n[0]*t[1...
  function Lt (line 10) | function Lt(n,t){n[0]+=t[0],n[1]+=t[1],n[2]+=t[2]}
  function Ht (line 10) | function Ht(n,t){return[n[0]*t,n[1]*t,n[2]*t]}
  function Ft (line 10) | function Ft(n){var t=Math.sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]);n[0]/=t,n[...
  function Pt (line 10) | function Pt(n){return[Math.atan2(n[1],n[0]),O(n[2])]}
  function Ot (line 10) | function Ot(n,t){return Math.abs(n[0]-t[0])<Wo&&Math.abs(n[1]-t[1])<Wo}
  function Rt (line 10) | function Rt(n,t){n*=Go;var e=Math.cos(t*=Go);Yt(e*Math.cos(n),e*Math.sin...
  function Yt (line 10) | function Yt(n,t,e){++La,Fa+=(n-Fa)/La,Pa+=(t-Pa)/La,Oa+=(e-Oa)/La}
  function It (line 10) | function It(){function n(n,u){n*=Go;var i=Math.cos(u*=Go),o=i*Math.cos(n...
  function Ut (line 10) | function Ut(){Xa.point=Rt}
  function Zt (line 10) | function Zt(){function n(n,t){n*=Go;var e=Math.cos(t*=Go),o=e*Math.cos(n...
  function Vt (line 10) | function Vt(){return!0}
  function Xt (line 10) | function Xt(n,t,e,r,u){var i=[],o=[];if(n.forEach(function(n){if(!((t=n....
  function $t (line 10) | function $t(n){if(t=n.length){for(var t,e,r=0,u=n[0];++r<t;)u.next=e=n[r...
  function Bt (line 10) | function Bt(n,t,e,r){return function(u){function i(t,e){n(t,e)&&u.point(...
  function Wt (line 10) | function Wt(n){return n.length>1}
  function Jt (line 10) | function Jt(){var n,t=[];return{lineStart:function(){t.push(n=[])},point...
  function Gt (line 10) | function Gt(n,t){return((n=n.point)[0]<0?n[1]-Bo/2-Wo:Bo/2-n[1])-((t=t.p...
  function Kt (line 10) | function Kt(n,t){var e=n[0],r=n[1],u=[Math.sin(e),-Math.cos(e),0],i=0,o=...
  function Qt (line 10) | function Qt(n){var t,e=0/0,r=0/0,u=0/0;return{lineStart:function(){n.lin...
  function ne (line 10) | function ne(n,t,e,r){var u,i,o=Math.sin(n-e);return Math.abs(o)>Wo?Math....
  function te (line 10) | function te(n,t,e,r){var u;if(null==n)u=e*Bo/2,r.point(-Bo,u),r.point(0,...
  function ee (line 10) | function ee(n){return Kt(Ba,n)}
  function re (line 10) | function re(n){function t(n,t){return Math.cos(n)*Math.cos(t)>o}function...
  function ue (line 10) | function ue(n,t,e,r){function u(r,u){return Math.abs(r[0]-n)<Wo?u>0?0:3:...
  function ie (line 10) | function ie(n,t,e){if(Math.abs(t)<Wo)return 0>=n;var r=n/t;if(t>0){if(r>...
  function oe (line 10) | function oe(n,t){function e(e,r){return e=n(e,r),t(e[0],e[1])}return n.i...
  function ae (line 10) | function ae(n){var t=0,e=Bo/3,r=_e(n),u=r(t,e);return u.parallels=functi...
  function ce (line 10) | function ce(n,t){function e(n,t){var e=Math.sqrt(i-2*u*Math.sin(t))/u;re...
  function le (line 10) | function le(){function n(n,t){Ga+=u*n-r*t,r=n,u=t}var t,e,r,u;ec.point=f...
  function se (line 10) | function se(n,t){Ka>n&&(Ka=n),n>nc&&(nc=n),Qa>t&&(Qa=t),t>tc&&(tc=t)}
  function fe (line 10) | function fe(){function n(n,t){o.push("M",n,",",t,i)}function t(n,t){o.pu...
  function he (line 10) | function he(n){return"m0,"+n+"a"+n+","+n+" 0 1,1 0,"+-2*n+"a"+n+","+n+" ...
  function ge (line 10) | function ge(n,t){Fa+=n,Pa+=t,++Oa}
  function pe (line 10) | function pe(){function n(n,r){var u=n-t,i=r-e,o=Math.sqrt(u*u+i*i);Ra+=o...
  function de (line 10) | function de(){uc.point=ge}
  function ve (line 10) | function ve(){function n(n,t){var e=n-r,i=t-u,o=Math.sqrt(e*e+i*i);Ra+=o...
  function me (line 10) | function me(n){function t(t,e){n.moveTo(t,e),n.arc(t,e,o,0,2*Bo)}functio...
  function ye (line 10) | function ye(n){function t(t){function r(e,r){e=n(e,r),t.point(e[0],e[1])...
  function Me (line 10) | function Me(n){this.stream=n}
  function xe (line 10) | function xe(n){var t=ye(function(t,e){return n([t*Ko,e*Ko])});return fun...
  function be (line 10) | function be(n){return _e(function(){return n})()}
  function _e (line 10) | function _e(n){function t(n){return n=a(n[0]*Go,n[1]*Go),[n[0]*h+c,l-n[1...
  function we (line 10) | function we(n,t){var e=new Me(t);return e.point=function(e,r){r=n(e*Go,r...
  function Se (line 10) | function Se(n,t){return[n,t]}
  function Ee (line 10) | 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 (line 10) | function ke(n){return function(t,e){return t+=n,[t>Bo?t-2*Bo:-Bo>t?t+2*B...
  function Ae (line 10) | function Ae(n){var t=ke(n);return t.invert=ke(-n),t}
  function Ne (line 10) | function Ne(n,t){function e(n,t){var e=Math.cos(t),a=Math.cos(n)*e,c=Mat...
  function Te (line 10) | function Te(n,t){var e=Math.cos(n),r=Math.sin(n);return function(u,i,o,a...
  function qe (line 10) | function qe(n,t){var e=Ct(t);e[0]-=n,Ft(e);var r=P(-e[1]);return((-e[2]<...
  function ze (line 10) | function ze(n,t,e){var r=mo.range(n,t-Wo,e).concat(t);return function(n)...
  function Ce (line 10) | function Ce(n,t,e){var r=mo.range(n,t-Wo,e).concat(t);return function(n)...
  function De (line 10) | function De(n){return n.source}
  function je (line 10) | function je(n){return n.target}
  function Le (line 10) | function Le(n,t,e,r){var u=Math.cos(t),i=Math.sin(t),o=Math.cos(r),a=Mat...
  function He (line 10) | function He(){function n(n,u){var i=Math.sin(u*=Go),o=Math.cos(u),a=Math...
  function Fe (line 10) | function Fe(n,t){function e(t,e){var r=Math.cos(t),u=Math.cos(e),i=n(r*u...
  function Pe (line 10) | function Pe(n,t){function e(n,t){var e=Math.abs(Math.abs(t)-Bo/2)<Wo?0:o...
  function Oe (line 10) | function Oe(n,t){function e(n,t){var e=i-t;return[e*Math.sin(u*n),i-e*Ma...
  function Re (line 10) | function Re(n,t){return[n,Math.log(Math.tan(Bo/4+t/2))]}
  function Ye (line 10) | function Ye(n){var t,e=be(n),r=e.scale,u=e.translate,i=e.clipExtent;retu...
  function Ie (line 10) | function Ie(n,t){var e=Math.cos(t)*Math.sin(n);return[Math.log((1+e)/(1-...
  function Ue (line 10) | function Ue(n){function t(t){function o(){l.push("M",i(n(s),a))}for(var ...
  function Ze (line 10) | function Ze(n){return n[0]}
  function Ve (line 10) | function Ve(n){return n[1]}
  function Xe (line 10) | function Xe(n){return n.join("L")}
  function $e (line 10) | function $e(n){return Xe(n)+"Z"}
  function Be (line 10) | function Be(n){for(var t=0,e=n.length,r=n[0],u=[r[0],",",r[1]];++t<e;)u....
  function We (line 10) | function We(n){for(var t=0,e=n.length,r=n[0],u=[r[0],",",r[1]];++t<e;)u....
  function Je (line 10) | function Je(n){for(var t=0,e=n.length,r=n[0],u=[r[0],",",r[1]];++t<e;)u....
  function Ge (line 10) | function Ge(n,t){return n.length<4?Xe(n):n[1]+nr(n.slice(1,n.length-1),t...
  function Ke (line 10) | function Ke(n,t){return n.length<3?Xe(n):n[0]+nr((n.push(n[0]),n),tr([n[...
  function Qe (line 10) | function Qe(n,t){return n.length<3?Xe(n):n[0]+nr(n,tr(n,t))}
  function nr (line 10) | function nr(n,t){if(t.length<1||n.length!=t.length&&n.length!=t.length+2...
  function tr (line 10) | function tr(n,t){for(var e,r=[],u=(1-t)/2,i=n[0],o=n[1],a=1,c=n.length;+...
  function er (line 10) | function er(n){if(n.length<3)return Xe(n);var t=1,e=n.length,r=n[0],u=r[...
  function rr (line 10) | function rr(n){if(n.length<4)return Xe(n);for(var t,e=[],r=-1,u=n.length...
  function ur (line 10) | function ur(n){for(var t,e,r=-1,u=n.length,i=u+4,o=[],a=[];++r<4;)e=n[r%...
  function ir (line 10) | function ir(n,t){var e=n.length-1;if(e)for(var r,u,i=n[0][0],o=n[0][1],a...
  function or (line 10) | function or(n,t){return n[0]*t[0]+n[1]*t[1]+n[2]*t[2]+n[3]*t[3]}
  function ar (line 10) | function ar(n,t,e){n.push("C",or(gc,t),",",or(gc,e),",",or(pc,t),",",or(...
  function cr (line 10) | function cr(n,t){return(t[1]-n[1])/(t[0]-n[0])}
  function lr (line 10) | function lr(n){for(var t=0,e=n.length-1,r=[],u=n[0],i=n[1],o=r[0]=cr(u,i...
  function sr (line 11) | function sr(n){for(var t,e,r,u,i=[],o=lr(n),a=-1,c=n.length-1;++a<c;)t=c...
  function fr (line 11) | function fr(n){return n.length<3?Xe(n):n[0]+nr(n,sr(n))}
  function hr (line 11) | 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...
  function gr (line 11) | function gr(n,t,e){return(e[0]-t[0])*(n[1]-t[1])<(e[1]-t[1])*(n[0]-t[0])}
  function pr (line 11) | 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...
  function dr (line 11) | function dr(n){var t=n[0],e=n[n.length-1];return!(t[0]-e[0]||t[1]-e[1])}
  function vr (line 11) | function vr(n,t){var e={list:n.map(function(n,t){return{index:t,x:n[0],y...
  function mr (line 11) | function mr(n){return n.x}
  function yr (line 11) | function yr(n){return n.y}
  function Mr (line 11) | function Mr(){return{leaf:!0,nodes:[],point:null,x:null,y:null}}
  function xr (line 11) | 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...
  function br (line 11) | 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...
  function _r (line 11) | function _r(n,t){var e,r={},u={};for(e in n)e in t?r[e]=Er(n[e],t[e]):u[...
  function wr (line 11) | function wr(n,t){return t-=n=+n,function(e){return n+t*e}}
  function Sr (line 11) | function Sr(n,t){var e,r,u,i,o,a=0,c=0,l=[],s=[];for(n+="",t+="",yc.last...
  function Er (line 11) | function Er(n,t){for(var e,r=mo.interpolators.length;--r>=0&&!(e=mo.inte...
  function kr (line 11) | function kr(n,t){var e,r=[],u=[],i=n.length,o=t.length,a=Math.min(n.leng...
  function Ar (line 11) | function Ar(n){return function(t){return 0>=t?0:t>=1?1:n(t)}}
  function Nr (line 11) | function Nr(n){return function(t){return 1-n(1-t)}}
  function Tr (line 11) | function Tr(n){return function(t){return.5*(.5>t?n(2*t):2-n(2-2*t))}}
  function qr (line 11) | function qr(n){return n*n}
  function zr (line 11) | function zr(n){return n*n*n}
  function Cr (line 11) | function Cr(n){if(0>=n)return 0;if(n>=1)return 1;var t=n*n,e=t*n;return ...
  function Dr (line 11) | function Dr(n){return function(t){return Math.pow(t,n)}}
  function jr (line 11) | function jr(n){return 1-Math.cos(n*Bo/2)}
  function Lr (line 11) | function Lr(n){return Math.pow(2,10*(n-1))}
  function Hr (line 11) | function Hr(n){return 1-Math.sqrt(1-n*n)}
  function Fr (line 11) | function Fr(n,t){var e;return arguments.length<2&&(t=.45),arguments.leng...
  function Pr (line 11) | function Pr(n){return n||(n=1.70158),function(t){return t*t*((n+1)*t-n)}}
  function Or (line 11) | function Or(n){return 1/2.75>n?7.5625*n*n:2/2.75>n?7.5625*(n-=1.5/2.75)*...
  function Rr (line 11) | 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...
  function Yr (line 11) | 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...
  function Ir (line 11) | 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...
  function Ur (line 11) | function Ur(n,t){return t-=n,function(e){return Math.round(n+t*e)}}
  function Zr (line 11) | 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...
  function Vr (line 11) | function Vr(n,t){return n[0]*t[0]+n[1]*t[1]}
  function Xr (line 11) | function Xr(n){var t=Math.sqrt(Vr(n,n));return t&&(n[0]/=t,n[1]/=t),t}
  function $r (line 11) | function $r(n,t,e){return n[0]+=e*t[0],n[1]+=e*t[1],n}
  function Br (line 11) | function Br(n,t){var e,r=[],u=[],i=mo.transform(n),o=mo.transform(t),a=i...
  function Wr (line 11) | function Wr(n,t){return t=t-(n=+n)?1/(t-n):0,function(e){return(e-n)*t}}
  function Jr (line 11) | function Jr(n,t){return t=t-(n=+n)?1/(t-n):0,function(e){return Math.max...
  function Gr (line 11) | function Gr(n){for(var t=n.source,e=n.target,r=Qr(t,e),u=[t];t!==r;)t=t....
  function Kr (line 11) | function Kr(n){for(var t=[],e=n.parent;null!=e;)t.push(n),n=e,e=e.parent...
  function Qr (line 11) | function Qr(n,t){if(n===t)return n;for(var e=Kr(n),r=Kr(t),u=e.pop(),i=r...
  function nu (line 11) | function nu(n){n.fixed|=2}
  function tu (line 11) | function tu(n){n.fixed&=-7}
  function eu (line 11) | function eu(n){n.fixed|=4,n.px=n.x,n.py=n.y}
  function ru (line 11) | function ru(n){n.fixed&=-5}
  function uu (line 11) | function uu(n,t,e){var r=0,u=0;if(n.charge=0,!n.leaf)for(var i,o=n.nodes...
  function iu (line 11) | function iu(n,t){return mo.rebind(n,t,"sort","children","value"),n.nodes...
  function ou (line 11) | function ou(n){return n.children}
  function au (line 11) | function au(n){return n.value}
  function cu (line 11) | function cu(n,t){return t.value-n.value}
  function lu (line 11) | function lu(n){return mo.merge(n.map(function(n){return(n.children||[])....
  function su (line 11) | function su(n){return n.x}
  function fu (line 11) | function fu(n){return n.y}
  function hu (line 11) | function hu(n,t,e){n.y0=t,n.y=e}
  function gu (line 11) | function gu(n){return mo.range(n.length)}
  function pu (line 11) | function pu(n){for(var t=-1,e=n[0].length,r=[];++t<e;)r[t]=0;return r}
  function du (line 11) | function du(n){for(var t,e=1,r=0,u=n[0][1],i=n.length;i>e;++e)(t=n[e][1]...
  function vu (line 11) | function vu(n){return n.reduce(mu,0)}
  function mu (line 11) | function mu(n,t){return n+t[1]}
  function yu (line 11) | function yu(n,t){return Mu(n,Math.ceil(Math.log(t.length)/Math.LN2+1))}
  function Mu (line 11) | function Mu(n,t){for(var e=-1,r=+n[0],u=(n[1]-r)/t,i=[];++e<=t;)i[e]=u*e...
  function xu (line 11) | function xu(n){return[mo.min(n),mo.max(n)]}
  function bu (line 11) | function bu(n,t){return n.parent==t.parent?1:2}
  function _u (line 11) | function _u(n){var t=n.children;return t&&t.length?t[0]:n._tree.thread}
  function wu (line 11) | function wu(n){var t,e=n.children;return e&&(t=e.length)?e[t-1]:n._tree....
  function Su (line 11) | function Su(n,t){var e=n.children;if(e&&(u=e.length))for(var r,u,i=-1;++...
  function Eu (line 11) | function Eu(n,t){return n.x-t.x}
  function ku (line 11) | function ku(n,t){return t.x-n.x}
  function Au (line 11) | function Au(n,t){return n.depth-t.depth}
  function Nu (line 11) | function Nu(n,t){function e(n,r){var u=n.children;if(u&&(o=u.length))for...
  function Tu (line 11) | function Tu(n){for(var t,e=0,r=0,u=n.children,i=u.length;--i>=0;)t=u[i]....
  function qu (line 11) | function qu(n,t,e){n=n._tree,t=t._tree;var r=e/(t.number-n.number);n.cha...
  function zu (line 11) | function zu(n,t,e){return n._tree.ancestor.parent==t.parent?n._tree.ance...
  function Cu (line 11) | function Cu(n,t){return n.value-t.value}
  function Du (line 11) | function Du(n,t){var e=n._pack_next;n._pack_next=t,t._pack_prev=n,t._pac...
  function ju (line 11) | function ju(n,t){n._pack_next=t,t._pack_prev=n}
  function Lu (line 11) | 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 (line 11) | function Hu(n){function t(n){s=Math.min(n.x-n.r,s),f=Math.max(n.x+n.r,f)...
  function Fu (line 11) | function Fu(n){n._pack_next=n._pack_prev=n}
  function Pu (line 11) | function Pu(n){delete n._pack_next,delete n._pack_prev}
  function Ou (line 11) | 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*=...
  function Ru (line 11) | function Ru(n,t,e){var r=n.r+e.r,u=t.x-n.x,i=t.y-n.y;if(r&&(u||i)){var o...
  function Yu (line 11) | function Yu(n){return 1+mo.max(n,function(n){return n.y})}
  function Iu (line 11) | function Iu(n){return n.reduce(function(n,t){return n+t.x},0)/n.length}
  function Uu (line 11) | function Uu(n){var t=n.children;return t&&t.length?Uu(t[0]):n}
  function Zu (line 11) | function Zu(n){var t,e=n.children;return e&&(t=e.length)?Zu(e[t-1]):n}
  function Vu (line 11) | function Vu(n){return{x:n.x,y:n.y,dx:n.dx,dy:n.dy}}
  function Xu (line 11) | function Xu(n,t){var e=n.x+t[3],r=n.y+t[0],u=n.dx-t[1]-t[3],i=n.dy-t[0]-...
  function $u (line 11) | function $u(n){var t=n[0],e=n[n.length-1];return e>t?[t,e]:[e,t]}
  function Bu (line 11) | function Bu(n){return n.rangeExtent?n.rangeExtent():$u(n.range())}
  function Wu (line 11) | function Wu(n,t,e,r){var u=e(n[0],n[1]),i=r(t[0],t[1]);return function(n...
  function Ju (line 11) | function Ju(n,t){var e,r=0,u=n.length-1,i=n[r],o=n[u];return i>o&&(e=r,r...
  function Gu (line 11) | function Gu(n){return n?{floor:function(t){return Math.floor(t/n)*n},cei...
  function Ku (line 11) | function Ku(n,t,e,r){var u=[],i=[],o=0,a=Math.min(n.length,t.length)-1;f...
  function Qu (line 11) | function Qu(n,t,e,r){function u(){var u=Math.min(n.length,t.length)>2?Ku...
  function ni (line 11) | function ni(n,t){return mo.rebind(n,t,"range","rangeRound","interpolate"...
  function ti (line 11) | function ti(n,t){return Ju(n,Gu(ei(n,t)[2]))}
  function ei (line 11) | function ei(n,t){null==t&&(t=10);var e=$u(n),r=e[1]-e[0],u=Math.pow(10,M...
  function ri (line 11) | function ri(n,t){return mo.range.apply(mo,ei(n,t))}
  function ui (line 11) | function ui(n,t,e){var r=-Math.floor(Math.log(ei(n,t)[2])/Math.LN10+.01)...
  function ii (line 11) | function ii(n,t,e,r){function u(n){return(e?Math.log(0>n?0:n):-Math.log(...
  function oi (line 11) | function oi(n,t,e){function r(t){return n(u(t))}var u=ai(t),i=ai(1/t);re...
  function ai (line 11) | function ai(n){return function(t){return 0>t?-Math.pow(-t,n):Math.pow(t,...
  function ci (line 11) | function ci(n,t){function e(t){return o[((i.get(t)||i.set(t,n.push(t)))-...
  function li (line 11) | function li(n,t){function e(){var e=0,i=t.length;for(u=[];++e<i;)u[e-1]=...
  function si (line 11) | function si(n,t,e){function r(t){return e[Math.max(0,Math.min(o,Math.flo...
  function fi (line 11) | function fi(n,t){function e(e){return e>=e?t[mo.bisect(n,e)]:void 0}retu...
  function hi (line 11) | function hi(n){function t(n){return+n}return t.invert=t,t.domain=t.range...
  function gi (line 11) | function gi(n){return n.innerRadius}
  function pi (line 11) | function pi(n){return n.outerRadius}
  function di (line 11) | function di(n){return n.startAngle}
  function vi (line 11) | function vi(n){return n.endAngle}
  function mi (line 11) | function mi(n){for(var t,e,r,u=-1,i=n.length;++u<i;)t=n[u],e=t[0],r=t[1]...
  function yi (line 11) | function yi(n){function t(t){function c(){d.push("M",a(n(m),f),s,l(n(v.r...
  function Mi (line 11) | function Mi(n){return n.radius}
  function xi (line 11) | function xi(n){return[n.x,n.y]}
  function bi (line 11) | function bi(n){return function(){var t=n.apply(this,arguments),e=t[0],r=...
  function _i (line 11) | function _i(){return 64}
  function wi (line 11) | function wi(){return"circle"}
  function Si (line 11) | function Si(n){var t=Math.sqrt(n/Bo);return"M0,"+t+"A"+t+","+t+" 0 1,1 0...
  function Ei (line 11) | function Ei(n,t){return Lo(n,Ic),n.id=t,n}
  function ki (line 11) | function ki(n,t,e,r){var u=n.id;return N(n,"function"==typeof e?function...
  function Ai (line 11) | function Ai(n){return null==n&&(n=""),function(){this.textContent=n}}
  function Ni (line 11) | function Ni(n,t,e,r){var i=n.__transition__||(n.__transition__={active:0...
  function Ti (line 11) | function Ti(n,t){n.attr("transform",function(n){return"translate("+t(n)+...
  function qi (line 11) | function qi(n,t){n.attr("transform",function(n){return"translate(0,"+t(n...
  function zi (line 11) | function zi(){this._=new Date(arguments.length>1?Date.UTC.apply(this,arg...
  function Ci (line 11) | function Ci(n,t,e){function r(t){var e=n(t),r=i(e,1);return r-t>t-e?e:r}...
  function Di (line 11) | function Di(n){return function(t,e){try{Wc=zi;var r=new zi;return r._=t,...
  function ji (line 11) | function ji(n){function t(t){for(var r,u,i,o=[],a=-1,c=0;++a<e;)37===n.c...
  function Li (line 11) | function Li(n,t,e,r){for(var u,i,o,a=0,c=t.length,l=e.length;c>a;){if(r>...
  function Hi (line 11) | function Hi(n){return new RegExp("^(?:"+n.map(mo.requote).join("|")+")",...
  function Fi (line 11) | function Fi(n){for(var t=new u,e=-1,r=n.length;++e<r;)t.set(n[e].toLower...
  function Pi (line 11) | function Pi(n,t,e){var r=0>n?"-":"",u=(r?-n:n)+"",i=u.length;return r+(e...
  function Oi (line 11) | function Oi(n,t,e){al.lastIndex=0;var r=al.exec(t.substring(e));return r...
  function Ri (line 11) | function Ri(n,t,e){il.lastIndex=0;var r=il.exec(t.substring(e));return r...
  function Yi (line 11) | function Yi(n,t,e){ml.lastIndex=0;var r=ml.exec(t.substring(e,e+1));retu...
  function Ii (line 11) | function Ii(n,t,e){ml.lastIndex=0;var r=ml.exec(t.substring(e));return r...
  function Ui (line 11) | function Ui(n,t,e){ml.lastIndex=0;var r=ml.exec(t.substring(e));return r...
  function Zi (line 11) | function Zi(n,t,e){fl.lastIndex=0;var r=fl.exec(t.substring(e));return r...
  function Vi (line 11) | function Vi(n,t,e){ll.lastIndex=0;var r=ll.exec(t.substring(e));return r...
  function Xi (line 11) | function Xi(n,t,e){return Li(n,dl.c.toString(),t,e)}
  function $i (line 11) | function $i(n,t,e){return Li(n,dl.x.toString(),t,e)}
  function Bi (line 11) | function Bi(n,t,e){return Li(n,dl.X.toString(),t,e)}
  function Wi (line 11) | function Wi(n,t,e){ml.lastIndex=0;var r=ml.exec(t.substring(e,e+4));retu...
  function Ji (line 11) | function Ji(n,t,e){ml.lastIndex=0;var r=ml.exec(t.substring(e,e+2));retu...
  function Gi (line 11) | function Gi(n,t,e){return/^[+-]\d{4}$/.test(t=t.substring(e,e+5))?(n.Z=+...
  function Ki (line 11) | function Ki(n){return n+(n>68?1900:2e3)}
  function Qi (line 11) | function Qi(n,t,e){ml.lastIndex=0;var r=ml.exec(t.substring(e,e+2));retu...
  function no (line 11) | function no(n,t,e){ml.lastIndex=0;var r=ml.exec(t.substring(e,e+2));retu...
  function to (line 11) | function to(n,t,e){ml.lastIndex=0;var r=ml.exec(t.substring(e,e+3));retu...
  function eo (line 11) | function eo(n,t,e){ml.lastIndex=0;var r=ml.exec(t.substring(e,e+2));retu...
  function ro (line 11) | function ro(n,t,e){ml.lastIndex=0;var r=ml.exec(t.substring(e,e+2));retu...
  function uo (line 11) | function uo(n,t,e){ml.lastIndex=0;var r=ml.exec(t.substring(e,e+2));retu...
  function io (line 11) | function io(n,t,e){ml.lastIndex=0;var r=ml.exec(t.substring(e,e+3));retu...
  function oo (line 11) | function oo(n,t,e){var r=yl.get(t.substring(e,e+=2).toLowerCase());retur...
  function ao (line 11) | function ao(n){var t=n.getTimezoneOffset(),e=t>0?"-":"+",r=~~(Math.abs(t...
  function co (line 11) | function co(n,t,e){gl.lastIndex=0;var r=gl.exec(t.substring(e,e+1));retu...
  function lo (line 11) | function lo(n){function t(n){try{Wc=zi;var t=new Wc;return t._=n,e(t)}fi...
  function so (line 11) | function so(n){return n.toISOString()}
  function fo (line 11) | function fo(n,t,e){function r(t){return n(t)}function u(n,e){var r=n[1]-...
  function ho (line 11) | function ho(n){return new Date(n)}
  function go (line 11) | function go(n){return function(t){for(var e=n.length-1,r=n[e];!r[1](t);)...
  function po (line 11) | function po(n){return JSON.parse(n.responseText)}
  function vo (line 11) | function vo(n){var t=xo.createRange();return t.selectNode(xo.body),t.cre...
  function n (line 12) | function n(t,a,c){if(c>=o.length)return r?r.call(i,a):e?a.sort(e):a;for(...
  function t (line 12) | function t(n,e){if(e>=o.length)return n;var r=[],u=a[e++];return n.forEa...
  function e (line 12) | function e(n,e){var r,i,o,a=n.length,f=e.length,h=Math.min(a,f),g=new Ar...
  function n (line 12) | function n(){this.on("mousedown.drag",o).on("touchstart.drag",a)}
  function t (line 12) | function t(){return mo.event.changedTouches[0].identifier}
  function e (line 12) | function e(n,t){return mo.touches(n).filter(function(n){return n.identif...
  function r (line 12) | function r(n,t,e,r){return function(){function o(){if(!s)return a();var ...
  function e (line 12) | function e(n){var t=n*y;if(m){var e=Y(d),o=i/(na*h)*(e*I(Qo*t+d)-R(d));r...
  function n (line 12) | function n(n){n.on(A,l).on(ua+".zoom",h).on(N,p).on("dblclick.zoom",d).o...
  function t (line 12) | function t(n){return[(n[0]-S.x)/S.k,(n[1]-S.y)/S.k]}
  function e (line 12) | function e(n){return[n[0]*S.k+S.x,n[1]*S.k+S.y]}
  function r (line 12) | function r(n){S.k=Math.max(k[0],Math.min(k[1],n))}
  function u (line 12) | function u(n,t){t=e(t),S.x+=n[0]-t[0],S.y+=n[1]-t[1]}
  function i (line 12) | function i(){b&&b.domain(x.range().map(function(n){return(n-S.x)/S.k}).m...
  function o (line 12) | function o(n){n({type:"zoomstart"})}
  function a (line 12) | function a(n){i(),n({type:"zoom",scale:S.k,translate:[S.x,S.y]})}
  function c (line 12) | function c(n){n({type:"zoomend"})}
  function l (line 12) | function l(){function n(){s=1,u(mo.mouse(r),h),a(i)}function e(){f.on(N,...
  function s (line 12) | function s(){function n(){var n=mo.touches(p);return g=S.k,n.forEach(fun...
  function h (line 12) | function h(){var n=C.of(this,arguments);y?clearTimeout(y):(z.call(this),...
  function p (line 12) | function p(){v=null}
  function d (line 12) | function d(){var n=C.of(this,arguments),e=mo.mouse(this),i=t(e),l=Math.l...
  function e (line 12) | function e(n,e,i){arguments.length<3&&(i=e,e=null);var o=mo.xhr(n,t,i);r...
  function r (line 12) | function r(n){return e.parse(n.responseText)}
  function u (line 12) | function u(n){return function(t){return e.parse(t.responseText,n)}}
  function o (line 12) | function o(t){return t.map(a).join(n)}
  function a (line 12) | function a(n){return c.test(n)?'"'+n.replace(/\"/g,'""')+'"':n}
  function e (line 12) | function e(){if(s>=c)return o;if(u)return u=!1,i;var t=s;if(34===n.charC...
  function n (line 12) | function n(n,t){M.push(x=[s=n,h=n]),f>t&&(f=t),t>g&&(g=t)}
  function t (line 12) | function t(t,e){var r=Ct([t*Go,e*Go]);if(m){var u=jt(m,r),i=[u[1],-u[0],...
  function e (line 12) | function e(){b.point=t}
  function r (line 12) | function r(){x[0]=s,x[1]=h,b.point=n,m=null}
  function u (line 12) | function u(n,e){if(m){var r=n-p;y+=Math.abs(r)>180?r+(r>0?360:-360):r}el...
  function i (line 12) | function i(){ja.lineStart()}
  function o (line 12) | function o(){u(d,v),ja.lineEnd(),Math.abs(y)>Wo&&(s=-(h=180)),x[0]=s,x[1...
  function a (line 12) | function a(n,t){return(t-=n)<0?t+360:t}
  function c (line 12) | function c(n,t){return n[0]-t[0]}
  function l (line 12) | function l(n,t){return t[0]<=t[1]?t[0]<=n&&n<=t[1]:n<t[0]||t[1]<n}
  function n (line 12) | function n(n){var i=n[0],o=n[1];return t=null,e(i,o),t||(r(i,o),t)||u(i,...
  function n (line 12) | function n(n){return n&&("function"==typeof a&&i.pointRadius(+a.apply(th...
  function t (line 12) | function t(){return o=null,n}
  function t (line 12) | function t(t){return t=n(t[0]*Go,t[1]*Go),t[0]*=Ko,t[1]*=Ko,t}
  function n (line 12) | function n(){var n="function"==typeof r?r.apply(this,arguments):r,t=Ee(-...
  function n (line 12) | function n(){return{type:"MultiLineString",coordinates:t()}}
  function t (line 12) | function t(){return mo.range(Math.ceil(i/v)*v,u,v).map(h).concat(mo.rang...
  function n (line 13) | function n(){return{type:"LineString",coordinates:[t||r.apply(this,argum...
  function t (line 13) | function t(n){if(n.length<3)return[];var t,u,i,o,a,c,l,s,f,h,g,p,d=pt(e)...
  function t (line 13) | function t(n){var t,i,o,a=n.map(function(){return[]}),c=pt(e),l=pt(r),s=...
  function i (line 13) | function i(n){function i(n,t,e,r,u,i,o,a){if(!isNaN(e)&&!isNaN(r))if(n.l...
  function n (line 13) | function n(){var n,l,f,h,g,p={},d=[],v=mo.range(i),m=[];for(e=[],r=[],n=...
  function t (line 13) | function t(){e.sort(function(n,t){return c((n.source.value+n.target.valu...
  function n (line 13) | function n(n){return function(t,e,r,u){if(t.point!==n){var i=t.cx-n.x,o=...
  function t (line 13) | function t(n){n.px=mo.event.x,n.py=mo.event.y,a.resume()}
  function n (line 13) | function n(n,r){for(var u,i=t(e),o=-1,a=i.length;++o<a;)if(!isNaN(u=i[o]...
  function t (line 13) | function t(){if(!c){for(c=[],r=0;p>r;++r)c[r]=[];for(r=0;d>r;++r){var n=...
  function n (line 13) | function n(t,o,a){var c=u.call(e,t,o);if(t.depth=o,a.push(t),c&&(l=c.len...
  function t (line 13) | function t(n,r){var u=n.children,o=0;if(u&&(a=u.length))for(var a,c=-1,l...
  function e (line 13) | function e(t){var e=[];return n(t,0,e),e}
  function n (line 13) | function n(t,e,r,u){var i=t.children;if(t.x=e,t.y=t.depth*u,t.dx=r,t.dy=...
  function t (line 13) | function t(n){var e=n.children,r=0;if(e&&(u=e.length))for(var u,i=-1;++i...
  function e (line 13) | function e(e,i){var o=r.call(this,e,i);return n(o[0],0,u[0],u[1]/t(o[0])...
  function n (line 13) | function n(i){var o=i.map(function(e,r){return+t.call(n,e,r)}),a=+("func...
  function n (line 13) | function n(a,c){var l=a.map(function(e,r){return t.call(n,e,r)}),s=l.map...
  function n (line 13) | function n(n,i){for(var o,a,c=[],l=n.map(e,this),s=r.call(this,l,i),f=u....
  function n (line 13) | function n(n,i){function o(n,t){var r=n.children,u=n._tree;if(r&&(i=r.le...
  function n (line 13) | function n(n,i){var o=e.call(this,n,i),a=o[0],c=u[0],l=u[1],s=null==t?Ma...
  function n (line 13) | function n(n,i){var o,a=t.call(this,n,i),c=a[0],l=0;Nu(c,function(n){var...
  function n (line 13) | function n(n,t){for(var e,r,u=-1,i=n.length;++u<i;)r=(e=n[u]).value*(0>t...
  function t (line 13) | function t(e){var i=e.children;if(i&&i.length){var o,a,c,l=f(e),s=[],h=i...
  function e (line 13) | function e(t){var r=t.children;if(r&&r.length){var i,o=f(t),a=r.slice(),...
  function r (line 13) | function r(n,t){for(var e,r=n.area,u=0,i=1/0,o=-1,a=n.length;++o<a;)(e=n...
  function u (line 13) | 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;...
  function i (line 13) | function i(r){var u=o||a(r),i=u[0];return i.x=0,i.y=0,i.dx=l[0],i.dy=l[1...
  function t (line 13) | function t(t){var e=n.call(i,t,t.depth);return null==e?Vu(t):Xu(t,"numbe...
  function e (line 13) | function e(t){return Xu(t,n)}
  function n (line 13) | function n(){var n=t.apply(this,arguments),i=e.apply(this,arguments),o=r...
  function n (line 13) | function n(n,a){var c=t(this,i,n,a),l=t(this,o,n,a);return"M"+c.p0+r(c.r...
  function t (line 13) | 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)+...
  function e (line 13) | function e(n,t){return n.a0==t.a0&&n.a1==t.a1}
  function r (line 13) | function r(n,t,e){return"A"+n+","+n+" 0 "+ +(e>Bo)+",1 "+t}
  function u (line 13) | function u(n,t,e,r){return"Q 0,0 "+r}
  function n (line 13) | function n(n,u){var i=t.call(this,n,u),o=e.call(this,n,u),a=(i.y+o.y)/2,...
  function n (line 13) | function n(n,r){return(Fc.get(t.call(this,n,r))||Si)(e.call(this,n,r))}
  function e (line 13) | function e(){this.removeAttribute(a)}
  function r (line 13) | function r(){this.removeAttributeNS(a.space,a.local)}
  function u (line 13) | function u(n){return null==n?e:(n+="",function(){var t,e=this.getAttribu...
  function i (line 13) | function i(n){return null==n?r:(n+="",function(){var t,e=this.getAttribu...
  function e (line 14) | function e(n,e){var r=t.call(this,n,e,this.getAttribute(u));return r&&fu...
  function r (line 14) | function r(n,e){var r=t.call(this,n,e,this.getAttributeNS(u.space,u.loca...
  function r (line 14) | function r(){this.style.removeProperty(n)}
  function u (line 14) | function u(t){return null==t?r:(t+="",function(){var r,u=_o.getComputedS...
  function r (line 14) | function r(r,u){var i=t.call(this,r,u,_o.getComputedStyle(this,null).get...
  function n (line 14) | function n(n){n.each(function(){var n,l=mo.select(this),s=null==c?e.tick...
  function n (line 14) | function n(i){i.each(function(){var i=mo.select(this).style("pointer-eve...
  function t (line 14) | function t(n){n.selectAll(".resize").attr("transform",function(n){return...
  function e (line 14) | function e(n){n.select(".extent").attr("x",s[0]),n.selectAll(".extent,.n...
  function r (line 14) | function r(n){n.select(".extent").attr("y",h[0]),n.selectAll(".extent,.e...
  function u (line 14) | function u(){function u(){32==mo.event.keyCode&&(N||(M=null,q[0]-=s[1],q...

FILE: code/web/src/failure-table/failure-table.component.js
  function clearSvg (line 97) | function clearSvg() {
  function setupSvgDefs (line 107) | function setupSvgDefs(svg) {
  function setupBackground (line 128) | function setupBackground(svgHeight) {
  function drawNodeLine (line 183) | function drawNodeLine(x,y) {
  function handleTimelineInput (line 191) | function handleTimelineInput(data) {
  function drawTimeBar (line 235) | function drawTimeBar() {
  function drawStartingCircle (line 261) | function drawStartingCircle(event) {
  function drawEndLine (line 287) | function drawEndLine(event) {
  function repositionSvgContent (line 340) | function repositionSvgContent(oldWidth,newWidth) {
  function deOverflow (line 415) | function deOverflow() {
  function getTextWidth (line 471) | function getTextWidth(str) {
  function getAttrValue (line 481) | function getAttrValue(elem,attr) {
  function setAttrValue (line 491) | function setAttrValue(elem,attr,val) {
  function setupHelpMeasurements (line 499) | function setupHelpMeasurements(svgHeight) {
  function calculateYCoordinate (line 573) | function calculateYCoordinate(startP,endP,x) {
  function isIn (line 590) | function isIn(arr,val) {
  function areIn (line 599) | function areIn(arr,val1,val2) {
  function isAtIndex (line 611) | function isAtIndex(arr,val) {
  function printIdLog (line 620) | function printIdLog() {
  function minVal (line 627) | function minVal(n1,n2) {
  function maxVal (line 631) | function maxVal(n1,n2) {
  function delFromString (line 635) | function delFromString(str,substr) {
  function printArray (line 658) | function printArray(array) {
  function out (line 666) | function out(str) {

FILE: code/web/src/hover-effect.js
  function toggleDisplay (line 13) | function toggleDisplay(elements) {
  function getClickHintElement (line 34) | function getClickHintElement(element) {

FILE: code/web/src/node-handling.js
  function handleNodeScaling (line 5) | function handleNodeScaling(element) {
  function toggleBigSmall (line 14) | function toggleBigSmall(element, otherElements) {
  function getUnclickedNodes (line 48) | function getUnclickedNodes() {
  function toggleVisibility (line 64) | function toggleVisibility(element) {
  function toggleDisplay (line 77) | function toggleDisplay(element, defaultval) {
  function toggleDisplayForChildren (line 88) | function toggleDisplayForChildren(parent) {
  function getChildByClassName (line 101) | function getChildByClassName(parent,className) {

FILE: code/web/src/node-list/node-list.component.js
  function sortNodes (line 112) | function sortNodes() {
  function searchIndex (line 127) | function searchIndex(arr, id) {

FILE: code/web/src/value-graph/value-graph.component.js
  function dataToValues (line 58) | function dataToValues(nodeData){
  function constructVG (line 72) | function constructVG(data) {
  function drawGraphs (line 130) | function drawGraphs(nodes) {
  function setHighchartsTheme (line 170) | function setHighchartsTheme() {
  function out (line 239) | function out(str) {
Condensed preview — 95 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (879K chars).
[
  {
    "path": ".gitignore",
    "chars": 2372,
    "preview": "# Created by .ignore support plugin (hsz.mobi)\n### Example user template\n\n# IntelliJ project files\n.idea\n*.iml\nout\ngen##"
  },
  {
    "path": ".gitmodules",
    "chars": 242,
    "preview": "[submodule \"extras/phppgadmin-docker\"]\n\tpath = extras/phppgadmin-docker\n\turl = https://github.com/luckydonald-forks/phpp"
  },
  {
    "path": ".travis.yml",
    "chars": 748,
    "preview": "language: python\n\npython:\n  - \"3.5\"\n  - \"3.6\"\n  - \"nightly\"\n\nmatrix:\n  allow_failures:\n    - python: nightly\n\n# command "
  },
  {
    "path": "Dockerfile",
    "chars": 344,
    "preview": "FROM python:3.5\n\n# dependencies:\nRUN mkdir /code\nWORKDIR /code/\n\n# libs\nRUN mkdir /code/libs/\nADD ./extras/libs/ /code/l"
  },
  {
    "path": "LICENSE",
    "chars": 35141,
    "preview": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free "
  },
  {
    "path": "Makefile",
    "chars": 324,
    "preview": "update:\n\tgit log -1\n\tgit status\n\tgit pull origin master\n\tgit submodule foreach git pull origin master\n\nstart:\n\tdocker-co"
  },
  {
    "path": "README.md",
    "chars": 3344,
    "preview": "# pbft\nImplementation of the ~~Peters~~ Practical Byzantine Fault Tolerant Algorithm    \n\n\n## Web GUI\n\nThis project supp"
  },
  {
    "path": "api.Dockerfile",
    "chars": 243,
    "preview": "FROM tiangolo/uwsgi-nginx-flask:flask-python3.5\n\nRUN mkdir -p /app/code\nWORKDIR /app/\nCOPY ./code/api/requirements.txt /"
  },
  {
    "path": "api.docker-compose.yml",
    "chars": 813,
    "preview": "version: '2'\nservices:\n  api:\n    build:\n      context: .\n      dockerfile: ./api.Dockerfile\n    restart: \"unless-stoppe"
  },
  {
    "path": "code/api/README.md",
    "chars": 3166,
    "preview": "# The events\n\n\n| Type \\ Class    | Message | Init | Propose | Prevote | Vote | Ack |\n| --------------- | ------- | ---- "
  },
  {
    "path": "code/api/database.py",
    "chars": 4065,
    "preview": "from datetime import datetime\nfrom pony import orm\nimport logging\n\nfrom node import messages\nfrom node.enums import UNSE"
  },
  {
    "path": "code/api/enums.py",
    "chars": 284,
    "preview": "# -*- coding: utf-8 -*-\nfrom luckydonaldUtils.logger import logging\nfrom node.enums import INIT, PROPOSE,PREVOTE, VOTE\n_"
  },
  {
    "path": "code/api/env.py",
    "chars": 492,
    "preview": "# -*- coding: utf-8 -*-\nimport os\n\nfrom luckydonaldUtils.logger import logging\n\n__author__ = 'luckydonald'\nlogger = logg"
  },
  {
    "path": "code/api/main.py",
    "chars": 9212,
    "preview": "# -*- coding: utf-8 -*-\nfrom datetime import datetime\n\nfrom DictObject import DictObject\nfrom flask import Flask, reques"
  },
  {
    "path": "code/api/requirements.txt",
    "chars": 77,
    "preview": "luckydonald-utils==0.51\ndocker-py\n\nflask  # api\npony  # db\npsycopg2cffi  # db"
  },
  {
    "path": "code/api/timeline.json",
    "chars": 1222,
    "preview": "{\n    \"nodes\": [\"1\", \"2\", \"3\", \"4\"],\n    \"timestamps\": {\"min\": \"23428001\", \"max\": \"23428013\"},\n    \"events\": [\n        {"
  },
  {
    "path": "code/api/utils.py",
    "chars": 704,
    "preview": "# -*- coding: utf-8 -*-\nfrom flask import request\nfrom luckydonaldUtils.logger import logging\n\n__author__ = 'luckydonald"
  },
  {
    "path": "code/api/uwsgi.ini",
    "chars": 40,
    "preview": "[uwsgi]\nmodule = main_api\ncallable = app"
  },
  {
    "path": "code/main_api.py",
    "chars": 650,
    "preview": "# -*- coding: utf-8 -*-\nfrom luckydonaldUtils.logger import logging, LevelByNameFilter\n\n__author__ = 'luckydonald'\nlogge"
  },
  {
    "path": "code/main_node.py",
    "chars": 284,
    "preview": "# -*- coding: utf-8 -*-\nfrom luckydonaldUtils.logger import logging\n\nfrom node.main import setup_logging, main\n\n__author"
  },
  {
    "path": "code/node/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "code/node/algo.py",
    "chars": 9546,
    "preview": "# -*- coding: utf-8 -*-\n\n# built in modules\nimport sys\nfrom datetime import timedelta\nfrom statistics import median\n\n# d"
  },
  {
    "path": "code/node/dockerus.py",
    "chars": 4304,
    "preview": "# -*- coding: utf-8 -*-\n\nfrom DictObject import DictObject\nfrom luckydonaldUtils.logger import logging\nfrom luckydonaldU"
  },
  {
    "path": "code/node/enums.py",
    "chars": 393,
    "preview": "# -*- coding: utf-8 -*-\nfrom luckydonaldUtils.logger import logging\n\n__author__ = 'luckydonald'\nlogger = logging.getLogg"
  },
  {
    "path": "code/node/env.py",
    "chars": 747,
    "preview": "# -*- coding: utf-8 -*-\nimport os\nfrom datetime import timedelta\n\nfrom luckydonaldUtils.logger import logging\n\n__author_"
  },
  {
    "path": "code/node/functions.py",
    "chars": 526,
    "preview": "# -*- coding: utf-8 -*-\nfrom luckydonaldUtils.logger import logging\n\n__author__ = 'luckydonald'\nlogger = logging.getLogg"
  },
  {
    "path": "code/node/main.py",
    "chars": 1369,
    "preview": "# -*- coding: utf-8 -*-\nfrom time import sleep\n\nfrom luckydonaldUtils.logger import logging, LevelByNameFilter\n\nfrom .al"
  },
  {
    "path": "code/node/message_queue.py",
    "chars": 4303,
    "preview": "# -*- coding: utf-8 -*-\nimport threading\nfrom collections import deque\n\nfrom DictObject import DictObject\nimport json\nfr"
  },
  {
    "path": "code/node/messages.py",
    "chars": 6562,
    "preview": "# -*- coding: utf-8 -*-\nfrom luckydonaldUtils.logger import logging\n\nfrom .enums import UNSET, INIT, LEADER_CHANGE, PROP"
  },
  {
    "path": "code/node/networks/__init__.py",
    "chars": 133,
    "preview": "# -*- coding: utf-8 -*-\nfrom luckydonaldUtils.logger import logging\n\n__author__ = 'luckydonald'\nlogger = logging.getLogg"
  },
  {
    "path": "code/node/networks/receiver.py",
    "chars": 8615,
    "preview": "# -*- coding: utf-8 -*-\nimport json\nimport threading\nfrom collections import deque\n\nfrom DictObject import DictObject\nfr"
  },
  {
    "path": "code/node/networks/sender.py",
    "chars": 2335,
    "preview": "# -*- coding: utf-8 -*-\nimport socket\nfrom time import sleep\n\nfrom luckydonaldUtils.logger import logging\n\nfrom ..env im"
  },
  {
    "path": "code/node/tests.py",
    "chars": 9494,
    "preview": "# -*- coding: utf-8 -*-\nfrom luckydonaldUtils.logger import logging\n\nimport unittest\nfrom .messages import Message, Init"
  },
  {
    "path": "code/node/todo.py",
    "chars": 296,
    "preview": "# -*- coding: utf-8 -*-\nfrom luckydonaldUtils.logger import logging\n\n__author__ = 'luckydonald'\nlogger = logging.getLogg"
  },
  {
    "path": "code/tests.py",
    "chars": 118,
    "preview": "import unittest\nfrom node.tests import *\n\n\nif __name__ == '__main__':  # pragma: no cover\n    unittest.main()\n# end if"
  },
  {
    "path": "code/web/.bowerrc",
    "chars": 42,
    "preview": "{\n  \"directory\": \"/app/bower_components\"\n}"
  },
  {
    "path": "code/web/Dockerfile",
    "chars": 505,
    "preview": "FROM node\nEXPOSE 8000\n\n# Code Dir\nRUN mkdir -p /app/code\nWORKDIR /app/\n\n# Node lib dir\nRUN npm config set prefix /app/li"
  },
  {
    "path": "code/web/bower.json",
    "chars": 662,
    "preview": "{\n  \"name\": \"pbft-gui\",\n  \"description\": \"A starter project for AngularJS\",\n  \"version\": \"0.0.0\",\n  \"homepage\": \"https:/"
  },
  {
    "path": "code/web/d3/d3.v3.js",
    "chars": 336821,
    "preview": "!function() {\n  var d3 = {\n    version: \"3.5.17\"\n  };\n  var d3_arraySlice = [].slice, d3_array = function(list) {\n    re"
  },
  {
    "path": "code/web/d3test.html",
    "chars": 15979,
    "preview": "<!DOCTYPE html>\n<html lang=\"de\">\n    <head>\n        <meta charset=\"utf-8\">\n        <title>D3 Test n stuff</title>\n      "
  },
  {
    "path": "code/web/docker-compose.yml",
    "chars": 286,
    "preview": "version: '2'\nservices:\n  web:\n    build:\n      context: .\n      dockerfile: ./Dockerfile\n    ports:\n      - \"8000:8000\"\n"
  },
  {
    "path": "code/web/entrypoint.sh",
    "chars": 603,
    "preview": "#!/usr/bin/env bash\nset -e;\n\n# first use first program parameter, if not set use $PORT, if that is undefined use default"
  },
  {
    "path": "code/web/example/api/v2/get_timeline/index.html",
    "chars": 83845,
    "preview": "{\n  \"events\": [\n    {\n      \"action\": \"send\",\n      \"data\": {\n        \"node\": 1,\n        \"sequence_no\": 298111723,\n     "
  },
  {
    "path": "code/web/example/nodes.json",
    "chars": 228,
    "preview": "[{\n\t\"id\": 1,\n\t\"value\": 0.5,\n\t\"primary\": true\n}, {\n\t\"id\": 2,\n\t\"value\": 0.6,\n\t\"primary\": false\n}, {\n\t\"id\": 3,\n\t\"value\": 0."
  },
  {
    "path": "code/web/index.html",
    "chars": 1666,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <link rel=\"stylesheet\" href=\"styles.css\"/>\n    <t"
  },
  {
    "path": "code/web/js.js",
    "chars": 1268,
    "preview": "/**\n * Created by luckydonald on 25/10/16.\n */\n\n$( document ).ready(function(){\n    setInterval( function () {\n        $"
  },
  {
    "path": "code/web/package.json",
    "chars": 391,
    "preview": "{\n  \"name\": \"pbft-gui\",\n  \"private\": true,\n  \"version\": \"0.0.0\",\n  \"description\": \"Web GUI for PBFT\",\n  \"repository\": \"h"
  },
  {
    "path": "code/web/src/app.animations.css",
    "chars": 826,
    "preview": ".view-frame {\n  position: relative;\n}\n.view-frame.ng-enter,\n.view-frame.ng-leave {\n  position: absolute;\n  left: 0;\n  ri"
  },
  {
    "path": "code/web/src/app.animations.js",
    "chars": 50,
    "preview": "/**\n * Created by PlayingBacon on 30.10.2016.\n */\n"
  },
  {
    "path": "code/web/src/app.animations.less",
    "chars": 816,
    "preview": ".view-frame {\n  position: relative;\n\n  &.ng-enter, &.ng-leave {\n    position: absolute;\n    left: 0;\n    right: 0;\n    t"
  },
  {
    "path": "code/web/src/app.config.js",
    "chars": 888,
    "preview": "/**\n * Created by PlayingBacon on 27.10.2016.\n */\n'use strict';\n\nangular.\n    module('pbftGui').\n    config(['$locationP"
  },
  {
    "path": "code/web/src/app.css",
    "chars": 20476,
    "preview": "/* app css stylesheet */\nbody {\n  margin: 0;\n  font-family: \"Lucida Sans Unicode\", \"Lucida Grande\", sans-serif;\n  font-v"
  },
  {
    "path": "code/web/src/app.js",
    "chars": 365,
    "preview": "'use strict';\n\n// Declare app level module which depends on views, and components\nangular.module('myApp', [\n  'ngRoute',"
  },
  {
    "path": "code/web/src/app.less",
    "chars": 12165,
    "preview": "// MACROS\n.transition(...) {  // http://stackoverflow.com/a/14988517/3423324\n@props: ~`\"@{arguments}\".replace(/[\\[\\]]/g,"
  },
  {
    "path": "code/web/src/app.module.js",
    "chars": 255,
    "preview": "'use strict';\n\n// Declare app level module which depends on views, and components\nangular.module('pbftGui', [\n  'ngAnima"
  },
  {
    "path": "code/web/src/config.js",
    "chars": 224,
    "preview": "'use strict';\n\n// WARNING\n// If you use docker, to start this\n// this file will be overwritten on startup.\n// This happe"
  },
  {
    "path": "code/web/src/core/core.module.js",
    "chars": 181,
    "preview": "/**\n * Created by PlayingBacon on 30.10.2016.\n */\n'use strict';\n\nangular.module('core', [\n    'core.node',\n    'core.d3F"
  },
  {
    "path": "code/web/src/core/d3/d3.directive.js",
    "chars": 6195,
    "preview": "/**\n * Created by PlayingBacon on 15.11.2016.\n */\n(function() {\n    'use strict';\n\n    angular.module('core.d3Directive'"
  },
  {
    "path": "code/web/src/core/d3/d3.directive.module.js",
    "chars": 120,
    "preview": "/**\n * Created by PlayingBacon on 15.11.2016.\n */\n'use strict';\n\nangular.module('core.d3Directive', ['core.d3Factory']);"
  },
  {
    "path": "code/web/src/core/d3/d3.factory.js",
    "chars": 145112,
    "preview": "/**\n * Created by PlayingBacon on 15.11.2016.\n */\n'use strict';\n\nangular.module('core.d3Factory')\n    .factory('d3Factor"
  },
  {
    "path": "code/web/src/core/d3/d3.factory.module.js",
    "chars": 102,
    "preview": "/**\n * Created by PlayingBacon on 15.11.2016.\n */\n'use strict';\n\nangular.module('core.d3Factory', []);"
  },
  {
    "path": "code/web/src/core/node/node.module.js",
    "chars": 110,
    "preview": "/**\n * Created by PlayingBacon on 28.10.2016.\n */\n'use strict';\n\nangular.module('core.node', ['ngResource']);\n"
  },
  {
    "path": "code/web/src/core/node/node.service.js",
    "chars": 439,
    "preview": "/**\n * Created by PlayingBacon on 28.10.2016.\n */\n'use strict';\n\nangular.\n    module('core.node').\n    factory('Node', ["
  },
  {
    "path": "code/web/src/core/recompile/recompile.directive.js",
    "chars": 849,
    "preview": "/**\n * Created by PlayingBacon on 23.11.2016.\n */\n'use strict';\n\nangular.module('core.recompile')\n    .directive('recomp"
  },
  {
    "path": "code/web/src/core/recompile/recompile.directive.module.js",
    "chars": 101,
    "preview": "/**\n * Created by PlayingBacon on 23.11.2016.\n */\n'use strict';\n\nangular.module('core.recompile',[]);"
  },
  {
    "path": "code/web/src/desktop.css",
    "chars": 232,
    "preview": ".node {\n  width: auto;\n}\n@media only screen and (min-width: 481px) and (max-width: 600px) {\n  .node {\n    width: 48%;\n  "
  },
  {
    "path": "code/web/src/desktop.less",
    "chars": 234,
    "preview": ".node {\n  width: auto;\n    @media only screen and (min-width: 481px) and (max-width: 600px) {\n      width: (100%/2) - 2%"
  },
  {
    "path": "code/web/src/failure-table/failure-table.component.js",
    "chars": 32747,
    "preview": "/**\n * Created by PlayingBacon on 27.10.2016.\n */\n'use strict';\n\nangular.\n    module('failureTable').\n    component('fai"
  },
  {
    "path": "code/web/src/failure-table/failure-table.module.js",
    "chars": 100,
    "preview": "/**\n * Created by PlayingBacon on 27.10.2016.\n */\n'use strict';\n\nangular.module('failureTable', []);"
  },
  {
    "path": "code/web/src/failure-table/failure-table.template.html",
    "chars": 5656,
    "preview": "<div id=\"failure-table\" xmlns=\"http://www.w3.org/1999/html\">\n    <h3>Timeline for Message Flow of Nodes</h3>\n    <div id"
  },
  {
    "path": "code/web/src/failure-table-view/failure-table-view.component.js",
    "chars": 304,
    "preview": "/**\n * Created by PlayingBacon on 30.10.2016.\n */\n'use strict';\n\nangular.\n    module('failureTableView').\n    component("
  },
  {
    "path": "code/web/src/failure-table-view/failure-table-view.module.js",
    "chars": 68,
    "preview": "'use strict';\n\nangular.module('failureTableView', ['failureTable']);"
  },
  {
    "path": "code/web/src/failure-table-view/failure-table-view.template.html",
    "chars": 212,
    "preview": "<!--<div style=\"width: 400px; margin: 0 auto 0 auto;\"><img src=\"resources/img/nope.gif\" alt=\"nope.avi\"></div>\n<h5 style="
  },
  {
    "path": "code/web/src/hover-effect.js",
    "chars": 1073,
    "preview": "/**\n * Created by PlayingBacon on 01.11.2016.\n */\n\n/*$(document).ready(function() {\n    $('.node').hover(function() {\n  "
  },
  {
    "path": "code/web/src/index-async.html",
    "chars": 3030,
    "preview": "<!doctype html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"utf-8\">\n  <link rel=\"stylesheet\" href=\"bower_components/html5-b"
  },
  {
    "path": "code/web/src/index.html",
    "chars": 5496,
    "preview": "<!DOCTYPE html>\n<!--[if lt IE 7]>      <html lang=\"en\" ng-app=\"pbftGui\" class=\"no-js lt-ie9 lt-ie8 lt-ie7\"> <![endif]-->"
  },
  {
    "path": "code/web/src/mobile.css",
    "chars": 77,
    "preview": ".node {\n  width: 100%;\n}\n.node .click-hint {\n  content: 'tap for details';\n}\n"
  },
  {
    "path": "code/web/src/mobile.less",
    "chars": 77,
    "preview": ".node {\n  width: 100%;\n  .click-hint {\n    content: 'tap for details';\n  }\n}\n"
  },
  {
    "path": "code/web/src/node-handling.js",
    "chars": 3858,
    "preview": "/**\n * Created by PlayingBacon on 03.11.2016.\n */\n\nfunction handleNodeScaling(element) {\n    var classes = element.class"
  },
  {
    "path": "code/web/src/node-list/node-list.component.js",
    "chars": 5458,
    "preview": "/**\n * Created by PlayingBacon on 27.10.2016.\n */\n'use strict';\n\nangular.\n    module('nodeList').\n    component('nodeLis"
  },
  {
    "path": "code/web/src/node-list/node-list.module.js",
    "chars": 148,
    "preview": "/**\n * Created by PlayingBacon on 27.10.2016.\n */\n'use strict';\n\nangular.\n    module('nodeList',[\n        'core.node',\n "
  },
  {
    "path": "code/web/src/node-list/node-list.template.html",
    "chars": 2026,
    "preview": "<div ng-show=\"$ctrl.summary && !$ctrl.nodes.length\" class=\"no_data\">No recent events</div>\n\n<div class=\"node summary non"
  },
  {
    "path": "code/web/src/node-list-view/node-list-view.component.js",
    "chars": 285,
    "preview": "/**\n * Created by PlayingBacon on 30.10.2016.\n */\n'use strict';\n\nangular.\n    module('nodeListView').\n    component('nod"
  },
  {
    "path": "code/web/src/node-list-view/node-list-view.module.js",
    "chars": 60,
    "preview": "'use strict';\n\nangular.module('nodeListView', ['nodeList']);"
  },
  {
    "path": "code/web/src/node-list-view/node-list-view.template.html",
    "chars": 72,
    "preview": "<div id=\"nodearea\">\n    <node-list class=\"node-list\"></node-list>\n</div>"
  },
  {
    "path": "code/web/src/nodes.json",
    "chars": 412,
    "preview": "[{\n\t\"id\": 1,\n\t\"value\": 0.5,\n\t\"leader\": true\n}, {\n\t\"id\": 2,\n\t\"value\": 0.6,\n\t\"leader\": false\n}, {\n\t\"id\": 3,\n\t\"value\": 0.5,"
  },
  {
    "path": "code/web/src/test_timeline.json",
    "chars": 15288,
    "preview": "{\n  \"events\": [\n    {\n      \"action\": \"send\",\n      \"data\": {\n        \"node\": 4,\n        \"sequence_no\": 148847745,\n     "
  },
  {
    "path": "code/web/src/value-graph/value-graph.component.js",
    "chars": 9055,
    "preview": "/**\n * Created by PlayingBacon on 07.11.2016.\n */\n'use strict';\n\nangular.\n    module('valueGraph').\n    component('value"
  },
  {
    "path": "code/web/src/value-graph/value-graph.d3.js",
    "chars": 322,
    "preview": "/**\n * Created by PlayingBacon on 15.11.2016.\n */\n'use strict';\n\nangular.\n    module('valueGraph').\n    component('value"
  },
  {
    "path": "code/web/src/value-graph/value-graph.module.js",
    "chars": 136,
    "preview": "/**\n * Created by PlayingBacon on 07.11.2016.\n */\n'use strict';\n\nangular.module('valueGraph',[\n    'core.d3Factory',\n   "
  },
  {
    "path": "code/web/src/value-graph/value-graph.template.html",
    "chars": 777,
    "preview": "<div id=\"nodearea\">\n    <div class=\"node upscaled {{( node.leader == true) ? 'leader' : ''}}\">\n        <a href=\"#!/nodes"
  },
  {
    "path": "code/web/styles.css",
    "chars": 1783,
    "preview": "body {\n    background-color: darkgrey;\n    margin: 0;\n    font-family: \"Lucida Sans Unicode\",\"Lucida Grande\",sans-serif;"
  },
  {
    "path": "docker-compose.yml",
    "chars": 1872,
    "preview": "version: '2'\nservices:\n  # # Python node\n  # node:\n  #   extends:\n  #     file: node.docker-compose.yml\n  #     service:"
  },
  {
    "path": "node.docker-compose.yml",
    "chars": 211,
    "preview": "version: '2'\nservices:\n  node:\n    build:\n      context: .\n      dockerfile: ./Dockerfile\n    command: [\"main_node.py\"]\n"
  },
  {
    "path": "requirements.txt",
    "chars": 65,
    "preview": "luckydonald-utils==0.51\ndocker-py\n\n# api\nflask  # api\npony   # db"
  }
]

About this extraction

This page contains the full source code of the luckydonald/pbft GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 95 files (815.6 KB), approximately 255.1k tokens, and a symbol index with 1109 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!