diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..1d5fa2a1d --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +.DS_Store +*.pyc +venv/ +web/data.json +.coverage +htmlcov/ diff --git a/.pylintrc b/.pylintrc new file mode 100644 index 000000000..826bfd653 --- /dev/null +++ b/.pylintrc @@ -0,0 +1,425 @@ +[MASTER] + +# A comma-separated list of package or module names from where C extensions may +# be loaded. Extensions are loading into the active Python interpreter and may +# run arbitrary code +extension-pkg-whitelist= + +# Add files or directories to the blacklist. They should be base names, not +# paths. +ignore=CVS + +# Add files or directories matching the regex patterns to the blacklist. The +# regex matches against base names, not paths. +ignore-patterns= + +# Python code to execute, usually for sys.path manipulation such as +# pygtk.require(). +#init-hook= + +# Use multiple processes to speed up Pylint. +jobs=4 + +# List of plugins (as comma separated values of python modules names) to load, +# usually to register additional checkers. +load-plugins= + +# Pickle collected data for later comparisons. +persistent=yes + +# Specify a configuration file. +#rcfile= + +# Allow loading of arbitrary C extensions. Extensions are imported into the +# active Python interpreter and may run arbitrary code. +unsafe-load-any-extension=no + + +[MESSAGES CONTROL] + +# Only show warnings with the listed confidence levels. Leave empty to show +# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED +confidence= + +# Disable the message, report, category or checker with the given id(s). You +# can either give multiple identifiers separated by comma (,) or put this +# option multiple times (only on the command line, not in the configuration +# file where it should appear only once).You can also use "--disable=all" to +# disable everything first and then reenable specific checks. For example, if +# you want to run only the similarities checker, you can use "--disable=all +# --enable=similarities". If you want to run only the classes checker, but have +# no Warning level messages displayed, use"--disable=all --enable=classes +# --disable=W" +disable=fixme,I0011,E1102 + +# Enable the message, report, category or checker with the given id(s). You can +# either give multiple identifier separated by comma (,) or put this option +# multiple time (only on the command line, not in the configuration file where +# it should appear only once). See also the "--disable" option for examples. +enable= + + +[REPORTS] + +# Python expression which should return a note less than 10 (10 is the highest +# note). You have access to the variables errors warning, statement which +# respectively contain the number of errors / warnings messages and the total +# number of statements analyzed. This is used by the global evaluation report +# (RP0004). +evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) + +# Template used to display messages. This is a python new-style format string +# used to format the message information. See doc for all details +#msg-template= + +# Set the output format. Available formats are text, parseable, colorized, json +# and msvs (visual studio).You can also give a reporter class, eg +# mypackage.mymodule.MyReporterClass. +output-format=text + +# Tells whether to display a full report or only the messages +reports=no + +# Activate the evaluation score. +score=yes + + +[REFACTORING] + +# Maximum number of nested blocks for function / method body +max-nested-blocks=5 + + +[BASIC] + +# Naming hint for argument names +argument-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ + +# Regular expression matching correct argument names +argument-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ + +# Naming hint for attribute names +attr-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ + +# Regular expression matching correct attribute names +attr-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ + +# Bad variable names which should always be refused, separated by a comma +bad-names=foo,bar,baz,toto,tutu,tata + +# Naming hint for class attribute names +class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ + +# Regular expression matching correct class attribute names +class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ + +# Naming hint for class names +class-name-hint=[A-Z_][a-zA-Z0-9]+$ + +# Regular expression matching correct class names +class-rgx=[A-Z_][a-zA-Z0-9]+$ + +# Naming hint for constant names +const-name-hint=(([a-zA-Z_][a-zA-Z0-9_]*)|(__.*__))$ + +# Regular expression matching correct constant names +const-rgx=(([a-zA-Z_][a-zA-Z0-9_]*)|(__.*__))$ + +# Minimum line length for functions/classes that require docstrings, shorter +# ones are exempt. +docstring-min-length=2 + +# Naming hint for function names +function-name-hint=(([a-z][a-z0-9_]{2,50})|(_[a-z0-9_]*))$ + +# Regular expression matching correct function names +function-rgx=(([a-z][a-z0-9_]{2,50})|(_[a-z0-9_]*))$ + +# Good variable names which should always be accepted, separated by a comma +good-names=e,f,i,j,k,ex,Run,_ + +# Include a hint for the correct naming format with invalid-name +include-naming-hint=no + +# Naming hint for inline iteration names +inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$ + +# Regular expression matching correct inline iteration names +inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ + +# Naming hint for method names +method-name-hint=(([a-z][a-z0-9_]{2,50})|(_[a-z0-9_]*))$ + +# Regular expression matching correct method names +method-rgx=(([a-z][a-z0-9_]{2,50})|(_[a-z0-9_]*))$ + +# Naming hint for module names +module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ + +# Regular expression matching correct module names +module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ + +# Colon-delimited sets of names that determine each other's naming style when +# the name regexes allow several styles. +name-group= + +# Regular expression which should only match function or class names that do +# not require a docstring. +no-docstring-rgx=^_ + +# List of decorators that produce properties, such as abc.abstractproperty. Add +# to this list to register other decorators that produce valid properties. +property-classes=abc.abstractproperty + +# Naming hint for variable names +variable-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ + +# Regular expression matching correct variable names +variable-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ + + +[FORMAT] + +# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. +expected-line-ending-format= + +# Regexp for a line that is allowed to be longer than the limit. +ignore-long-lines=^\s*(# )??$ + +# Number of spaces of indent required inside a hanging or continued line. +indent-after-paren=4 + +# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 +# tab). +indent-string=' ' + +# Maximum number of characters on a single line. +max-line-length=120 + +# Maximum number of lines in a module +max-module-lines=1000 + +# List of optional constructs for which whitespace checking is disabled. `dict- +# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. +# `trailing-comma` allows a space between comma and closing bracket: (a, ). +# `empty-line` allows space-only lines. +no-space-check=trailing-comma,dict-separator + +# Allow the body of a class to be on the same line as the declaration if body +# contains single statement. +single-line-class-stmt=no + +# Allow the body of an if to be on the same line as the test if there is no +# else. +single-line-if-stmt=no + + +[LOGGING] + +# Logging modules to check that the string format arguments are in logging +# function parameter format +logging-modules=logging + + +[MISCELLANEOUS] + +# List of note tags to take in consideration, separated by a comma. +notes=FIXME,XXX,TODO + + +[SIMILARITIES] + +# Ignore comments when computing similarities. +ignore-comments=yes + +# Ignore docstrings when computing similarities. +ignore-docstrings=yes + +# Ignore imports when computing similarities. +ignore-imports=no + +# Minimum lines number of a similarity. +min-similarity-lines=4 + + +[SPELLING] + +# Spelling dictionary name. Available dictionaries: none. To make it working +# install python-enchant package. +spelling-dict= + +# List of comma separated words that should not be checked. +spelling-ignore-words= + +# A path to a file that contains private dictionary; one word per line. +spelling-private-dict-file= + +# Tells whether to store unknown words to indicated private dictionary in +# --spelling-private-dict-file option instead of raising a message. +spelling-store-unknown-words=no + + +[TYPECHECK] + +# List of decorators that produce context managers, such as +# contextlib.contextmanager. Add to this list to register other decorators that +# produce valid context managers. +contextmanager-decorators=contextlib.contextmanager + +# List of members which are set dynamically and missed by pylint inference +# system, and so shouldn't trigger E1101 when accessed. Python regular +# expressions are accepted. +generated-members= + +# Tells whether missing members accessed in mixin class should be ignored. A +# mixin class is detected if its name ends with "mixin" (case insensitive). +ignore-mixin-members=yes + +# This flag controls whether pylint should warn about no-member and similar +# checks whenever an opaque object is returned when inferring. The inference +# can return multiple potential results while evaluating a Python object, but +# some branches might not be evaluated, which results in partial inference. In +# that case, it might be useful to still emit no-member and other checks for +# the rest of the inferred objects. +ignore-on-opaque-inference=yes + +# List of class names for which member attributes should not be checked (useful +# for classes with dynamically set attributes). This supports the use of +# qualified names. +ignored-classes=optparse.Values,thread._local,_thread._local + +# List of module names for which member attributes should not be checked +# (useful for modules/projects where namespaces are manipulated during runtime +# and thus existing member attributes cannot be deduced by static analysis. It +# supports qualified module names, as well as Unix pattern matching. +ignored-modules= + +# Show a hint with possible names when a member name was not found. The aspect +# of finding the hint is based on edit distance. +missing-member-hint=yes + +# The minimum edit distance a name should have in order to be considered a +# similar match for a missing member name. +missing-member-hint-distance=1 + +# The total number of similar names that should be taken in consideration when +# showing a hint for a missing member. +missing-member-max-choices=1 + + +[VARIABLES] + +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid to define new builtins when possible. +additional-builtins= + +# Tells whether unused global variables should be treated as a violation. +allow-global-unused-variables=yes + +# List of strings which can identify a callback function by name. A callback +# name must start or end with one of those strings. +callbacks=cb_,_cb + +# A regular expression matching the name of dummy variables (i.e. expectedly +# not used). +dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ + +# Argument names that match this expression will be ignored. Default to name +# with leading underscore +ignored-argument-names=_.*|^ignored_|^unused_ + +# Tells whether we should check for unused import in __init__ files. +init-import=no + +# List of qualified module names which can have objects that can redefine +# builtins. +redefining-builtins-modules=six.moves,future.builtins + + +[CLASSES] + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__,__new__,setUp + +# List of member names, which should be excluded from the protected access +# warning. +exclude-protected=_asdict,_fields,_replace,_source,_make + +# List of valid names for the first argument in a class method. +valid-classmethod-first-arg=cls + +# List of valid names for the first argument in a metaclass class method. +valid-metaclass-classmethod-first-arg=mcs + + +[DESIGN] + +# Maximum number of arguments for function / method +max-args=5 + +# Maximum number of attributes for a class (see R0902). +max-attributes=10 + +# Maximum number of boolean expressions in a if statement +max-bool-expr=5 + +# Maximum number of branch for function / method body +max-branches=25 + +# Maximum number of locals for function / method body +max-locals=25 + +# Maximum number of parents for a class (see R0901). +max-parents=7 + +# Maximum number of public methods for a class (see R0904). +max-public-methods=30 + +# Maximum number of return / yield for function / method body +max-returns=10 + +# Maximum number of statements in function / method body +max-statements=50 + +# Minimum number of public methods for a class (see R0903). +min-public-methods=0 + + +[IMPORTS] + +# Allow wildcard imports from modules that define __all__. +allow-wildcard-with-all=no + +# Analyse import fallback blocks. This can be used to support both Python 2 and +# 3 compatible code, which means that the block might have code that exists +# only in one or another interpreter, leading to false positives when analysed. +analyse-fallback-blocks=no + +# Deprecated modules which should not be used, separated by a comma +deprecated-modules=optparse,tkinter.tix + +# Create a graph of external dependencies in the given file (report RP0402 must +# not be disabled) +ext-import-graph= + +# Create a graph of every (i.e. internal and external) dependencies in the +# given file (report RP0402 must not be disabled) +import-graph= + +# Create a graph of internal dependencies in the given file (report RP0402 must +# not be disabled) +int-import-graph= + +# Force import order to recognize a module as part of the standard +# compatibility libraries. +known-standard-library= + +# Force import order to recognize a module as part of a third party library. +known-third-party=enchant + + +[EXCEPTIONS] + +# Exceptions that will emit a warning when being caught. Defaults to +# "Exception" +overgeneral-exceptions=Exception \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..c65e30f3f --- /dev/null +++ b/LICENSE @@ -0,0 +1,11 @@ +Copyright 2018 Duo Security + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 000000000..5ee46486e --- /dev/null +++ b/README.md @@ -0,0 +1,133 @@ +CloudMapper +======== +CloudMapper generates network diagrams of Amazon Web Services (AWS) environments and display them via your browser. It helps you understand visually what exists in your accounts and identify possible network misconfigurations. + +![Demo screenshot](docs/images/ideal_layout.png "Demo screenshot") + +There are three stages to using CloudMapper: +1. Collect information about an AWS account via a shell script that uses the AWS CLI. +2. Convert that data into a format usable by the web browser. +3. Run a simple web server to view the collected data in your browser. + + +Installation +----------- +On macOS: + +``` +# Install pre-reqs for pyjq +brew install autoconf automake libtool +virtualenv venv +source venv/bin/activate +pip install -r requirements.txt +``` + +On Linux: +``` +sudo yum install autoconf automake libtool python-dev +virtualenv venv +source venv/bin/activate +pip install -r requirements.txt +``` + + +Running +======= + +1. Collect data about the account +--------------------------------- +This step uses the CLI to make `describe` calls and records the json in the folder you specify (in this case, named `my_account`). You must have AWS credentials configured that can be used by the CLI. You must have read-only permissions on the account. This can be granted via the `SecurityAuditor` policy, or can be reduced to an even more minimal set of permissions if desired. + +``` +./collect_data.sh --account my_account +``` + +`my_account` is just a name for your account (ex. "prod"). You should now have a directory with .json files describing your account. + +Copy the `config.json.demo` to `config.json` and edit it to include your account ID and name (ex. "prod"), along with any external CIDR names. + +2. Prepare the data +------------------- + +This step converts the collected AWS data into a format that can be displayed in the browser by generating a `web/data.json` file. +``` +python cloudmapper.py prepare --acount my_account +``` + +3. Run a webserver +------------------ + +You can host the `web` directory with your webserver of choice, or just run: + +``` +python cloudmapper.py serve +``` + + + +Using the UI +============ + +Mouse actions +------------- +- Pan and zoom can be done with the UI controls, or arrow keys and -/+ keys. +- Clicking on a node selects it (background turns yellow). Double-clicking a node makes it's deleted neighbors visible again. +- Unselect a node by clicking on a new one, or holding shift and clicking on the selected node again. +- Holding down shift can be used to select multiple nodes. Holding shift, clicking, and dragging over an area, selects all nodes that overlap that area. +- Click on a node and drag it to move it around. + +![Command icons](docs/images/command_icons.png "Command icons") + +Commands +-------- +- Delete (d): Select a node and click the eye with a slash through it to delete (ie. hide) it. Click the eye to undelete (unhide) all deleted nodes. All nodes connected to a deleted node will get a black border. If you double-click on a node with a black border, it's deleted neighbors will be undeleted. +![Deleted node](docs/images/deleted_node.png "Deleted node") + +- Highlight (h): Select a node and click the symbol of the connected nodes to highlight the neighbors of a node. Click the inverse symbol to unhighligh the neighbors. Highlight neighbors makes it easier to see which nodes are connected. +![Highlighted neighbors](docs/images/highlight_neighbors.png "Highlighted neighbors") + +- Collapse all: Click the icon of the arrows pointed toward each other to collapse all nodes. Click the symbol of the arrows pointed away to uncollapse all collapsed node. +![Collapsed node](docs/images/collapsed_node.png "Collapsed node") + +- Collapse (c/e): The "minus" symbol will collapse a node, and the "plus" symbol will expand it. +- Randomize layout (r): The hammer symbol will randomly layout the diagram in a new way. +- Save image: The camera symbol will save a high resolution image of the diagram. This is helpful when your diagram has many nodes such that you must be zoomed out, so a screenshot would not get the same level of detail. +- Import/Export: This will save the layout as a json file that you can then upload. This is helpful if you've moved nodes or made other changes and wish to "save" your work. Re-opening saved files does have some bugs. + + +When you first start, the initial layout is never ideal. We use what is believed to be the best layout algorithm for compound node diagrams [CoSE](https://github.com/cytoscape/cytoscape.js-cose-bilkent), but this will still require manual editing by moving nodes around. + +Here is the layout you'll likely see initially when you view the demo: +![Initial layout](docs/images/initial_layout.png "Initial layout") + + +Licenses +-------- +- cytoscape.js: MIT + https://github.com/cytoscape/cytoscape.js/blob/master/LICENSE +- cytoscape.js-qtip: MIT + https://github.com/cytoscape/cytoscape.js-qtip/blob/master/LICENSE +- cytoscape.js-grid-guide: MIT + https://github.com/iVis-at-Bilkent/cytoscape.js-grid-guide +- cytoscape.js-panzoom: MIT + https://github.com/cytoscape/cytoscape.js-panzoom/blob/master/LICENSE +- jquery: JS Foundation + https://github.com/jquery/jquery/blob/master/LICENSE.txt +- jquery.qtip: MIT + https://github.com/qTip2/qTip2/blob/master/LICENSE +- cytoscape-navigator: MIT + https://github.com/cytoscape/cytoscape.js-navigator/blob/c249bd1551c8948613573b470b30a471def401c5/bower.json#L24 +- cytoscape.js-autopan-on-drag: MIT + https://github.com/iVis-at-Bilkent/cytoscape.js-autopan-on-drag +- font-awesome: MIT + http://fontawesome.io/ +- FileSave.js: MIT + https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md +- circular-json: MIT + https://github.com/WebReflection/circular-json/blob/master/LICENSE.txt +- rstacruz/nprogress: MIT + https://github.com/rstacruz/nprogress/blob/master/License.md +- mousetrap: Apache + https://github.com/ccampbell/mousetrap/blob/master/LICENSE +- akkordion MIT + https://github.com/TrySound/akkordion/blob/master/LICENSE \ No newline at end of file diff --git a/cloudmapper.py b/cloudmapper.py new file mode 100755 index 000000000..eaa920124 --- /dev/null +++ b/cloudmapper.py @@ -0,0 +1,121 @@ +#! /usr/bin/env python +""" +Copyright 2018 Duo Security + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------- + +This script manages CloudMapper, a tool for creating network diagrams of AWS environments. +""" + +import json +import argparse +import sys +from cloudmapper.webserver import run_webserver + + +def get_account(account_name, config): + for account in config["accounts"]: + if account["name"] == account_name: + return account + # Could not find account + raise Exception("Account named \"{}\" not found".format(account_name)) + + +def run_prepare(arguments): + from cloudmapper.prepare import prepare + + # Parse arguments + parser = argparse.ArgumentParser() + parser.add_argument("--config", help="Config file name", + default="config.json", type=str) + parser.add_argument("--account-name", help="Account to collect from", + required=True, type=str) + parser.add_argument("--regions", help="Regions to restrict to (ex. us-east-1,us-west-2)", + default=None, type=str) + parser.add_argument("--internal-edges", help="Show all connections (default)", + dest='internal_edges', action='store_true') + parser.add_argument("--no-internal-edges", help="Only show connections to external CIDRs", + dest='internal_edges', action='store_false') + parser.add_argument("--inter-rds-edges", help="Show connections between RDS instances", + dest='inter_rds_edges', action='store_true') + parser.add_argument("--no-inter-rds-edges", help="Do not show connections between RDS instances (default)", + dest='inter_rds_edges', action='store_false') + parser.add_argument("--read-replicas", help="Show RDS read replicas (default)", + dest='read_replicas', action='store_true') + parser.add_argument("--no-read-replicas", help="Do not show RDS read replicas", + dest='read_replicas', action='store_false') + parser.add_argument("--azs", help="Show availability zones (default)", + dest='azs', action='store_true') + parser.add_argument("--no-azs", help="Do not show availability zones", + dest='azs', action='store_false') + parser.add_argument("--collapse-by-tag", help="Collapse nodes with the same tag to a single node", + dest='collapse_by_tag', default=None, type=str) + + parser.set_defaults(internal_edges=True) + parser.set_defaults(inter_rds_edges=False) + parser.set_defaults(read_replicas=True) + parser.set_defaults(azs=True) + + args = parser.parse_args(arguments) + + outputfilter = {} + if args.regions: + # Regions are given as 'us-east-1,us-west-2'. Split this by the comma, + # wrap each with quotes, and add the comma back. This is needed for how we do filtering. + outputfilter["regions"] = ','.join(map(lambda r: '"' + r + '"', args.regions.split(','))) + outputfilter["internal_edges"] = args.internal_edges + outputfilter["read_replicas"] = args.read_replicas + outputfilter["inter_rds_edges"] = args.inter_rds_edges + outputfilter["azs"] = args.azs + outputfilter["collapse_by_tag"] = args.collapse_by_tag + + # Read accounts file + try: + config = json.load(open(args.config)) + except IOError: + exit("ERROR: Unable to load config file \"{}\"".format(args.config)) + except ValueError as e: + exit("ERROR: Config file \"{}\" could not be loaded ({}), see config.json.demo for an example".format(args.config, e)) + account = get_account(args.account_name, config) + + prepare(account, config, outputfilter) + + +def show_help(): + print "usage: {} [prepare|serve] [...]".format(sys.argv[0]) + print " prepare: Prepares the data for viewing" + print " serve: Runs a local webserver for viewing the data" + exit(-1) + + +def main(): + """Entry point for the CLI.""" + + # Parse command + if len(sys.argv) <= 1: + show_help() + + command = sys.argv[1] + arguments = sys.argv[2:] + + if command == "prepare": + run_prepare(arguments) + elif command == "serve": + run_webserver(arguments) + else: + show_help() + + print "Complete" + + +if __name__ == "__main__": + main() diff --git a/cloudmapper/__init__.py b/cloudmapper/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/cloudmapper/nodes.py b/cloudmapper/nodes.py new file mode 100644 index 000000000..90cad7e78 --- /dev/null +++ b/cloudmapper/nodes.py @@ -0,0 +1,409 @@ +""" +Copyright 2018 Duo Security + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------- +""" + +import pyjq +from abc import ABCMeta +from netaddr import IPNetwork, IPAddress + + +def truncate(string): + return (string[:19] + '..') if len(string) > 20 else string + + +def get_name(node, default): + try: + for tag in node["Tags"]: + if tag["Key"] == "Name": + return truncate(tag["Value"]) + except Exception: + # If the keys in tag don't exist, just return the default + pass + return node[default] + + +def is_public_ip(ip): + ip = IPAddress(ip) + if ( + ip in IPNetwork("10.0.0.0/8") or + ip in IPNetwork("172.16.0.0/12") or + ip in IPNetwork("192.168.0.0/16") + ): + return False + return True + + +class Node(object): + __metaclass__ = ABCMeta + + _arn = "" + _local_id = "" # Ex. InstanceId + _name = "" + _type = "" + + _parent = None + _json_blob = "" + + _isLeaf = False + + _children = None + + def __key(self): + return self._arn + + def __init__(self, parent, json_blob): + self._parent = parent + self._json_blob = json_blob + self._children = {} + + @property + def arn(self): + return self._arn + + @property + def local_id(self): + return self._local_id + + @property + def name(self): + return self._name + + @property + def node_type(self): + return self._type + + @property + def isLeaf(self): + return self._isLeaf + + @property + def account(self): + if self._type == "account": + return self + else: + return self.parent.account + + @property + def region(self): + if self._type == "region": + return self + else: + return self.parent.region + + @property + def vpc(self): + if self._type == "vpc": + return self + else: + return self.parent.vpc + + @property + def az(self): + if self._type == "az": + return self + else: + return self.parent.az + + @property + def subnet(self): + if self._type == "subnet": + return self + else: + return self.parent.subnet + + @property + def parent(self): + return self._parent + + @property + def json(self): + return self._json_blob + + def addChild(self, child): + self._children[child.local_id] = child + + @property + def children(self): + return self._children.values() + + @property + def has_leaves(self): + # TODO: This can be optimized + if self.isLeaf: + return True + else: + for child in self.children: + if child.has_leaves: + return True + return False + + @property + def leaves(self): + if self.isLeaf: + return [self] + else: + # TODO: Use iterators + leaves = [] + for child in self.children: + leaves.extend(child.leaves) + return leaves + + def cytoscape_data(self): + response = {"data": { + "id": self.arn, + "name": self.name, + "type": self.node_type, + "local_id": self.local_id, + "node_data": self.json + }} + if self.parent: + response["data"]["parent"] = self.parent.arn + + return response + + +class Account(Node): + def __init__(self, parent, json_blob): + self._local_id = json_blob["id"] + self._arn = "arn:aws:::{}:".format(self._local_id) + self._name = json_blob["name"] + self._type = "account" + super(Account, self).__init__(parent, json_blob) + + +class Region(Node): + def __init__(self, parent, json_blob): + self._local_id = json_blob["RegionName"] + self._arn = "arn:aws::{}:{}:".format(self.local_id, parent.account.local_id) + self._name = json_blob["RegionName"] + self._type = "region" + super(Region, self).__init__(parent, json_blob) + + +class Vpc(Node): + _peering_connections = None + + def addPeer(self, vpc): + self._peering_connections.append(vpc) + + @property + def peers(self): + return self._peering_connections + + @property + def cidr(self): + return self._json_blob["CidrBlock"] + + def __init__(self, parent, json_blob): + # arn:aws:ec2:region:account-id:vpc/vpc-id + self._local_id = json_blob["VpcId"] + self._arn = "arn:aws::{}:{}:vpc/{}".format(parent.region.name, parent.account.local_id, self._local_id) + self._name = get_name(json_blob, "VpcId") + self._type = "vpc" + + self._peering_connections = [] + + super(Vpc, self).__init__(parent, json_blob) + + +class Az(Node): + def __init__(self, parent, json_blob): + self._local_id = json_blob["ZoneName"] + self._arn = "arn:aws::{}:{}:vpc/{}/az/{}".format(parent.region.local_id, parent.account.local_id, parent.local_id, self._local_id) + self._name = json_blob["ZoneName"] + self._type = "az" + super(Az, self).__init__(parent, json_blob) + + +class Subnet(Node): + def __init__(self, parent, json_blob): + # arn:aws:ec2:region:account-id:subnet/subnet-id + self._local_id = json_blob["SubnetId"] + self._arn = "arn:aws::{}:{}:subnet/{}".format(parent.region.name, parent.account.local_id, self._local_id) + self._name = get_name(json_blob, "SubnetId") + self._type = "subnet" + super(Subnet, self).__init__(parent, json_blob) + + +class Leaf(Node): + __metaclass__ = ABCMeta + + def __init__(self, parent, json_blob): + self._isLeaf = True + super(Leaf, self).__init__(parent, json_blob) + + +class Ec2(Leaf): + _ips = None + + @property + def is_public(self): + for ip in self.ips: + if is_public_ip(ip): + return True + return False + + @property + def ips(self): + if self._ips is None: + # Autoscaling groups are going to make this get a lot of IPs, but since we're only graphing + # connections, we'll assume that each autoscaling instance would have the same connections + # as others + self._ips = [] + private_ips = pyjq.all('.NetworkInterfaces[].PrivateIpAddresses[].PrivateIpAddress', self._json_blob) + self._ips.extend(filter(lambda x: x is not None, private_ips)) + public_ips = pyjq.all('.NetworkInterfaces[].PrivateIpAddresses[].Association.PublicIp', self._json_blob) + self._ips.extend(filter(lambda x: x is not None, public_ips)) + return self._ips + + def security_groups(self): + return pyjq.all('.SecurityGroups[].GroupId', self._json_blob) + + def __init__(self, parent, json_blob, collapse_by_tag=None): + autoscaling_name = pyjq.all('.Tags[] | select(.Key == "aws:autoscaling:groupName") | .Value', json_blob) + collapse_by_tag_value = [] + if collapse_by_tag: + collapse_by_tag_value = pyjq.all('.Tags[] | select(.Key == "{}") | .Value'.format(collapse_by_tag), json_blob) + if autoscaling_name != []: + self._type = "autoscaling" + self._local_id = autoscaling_name[0] + elif collapse_by_tag_value != []: + self._type = "grouped_ec2" + self._local_id = "grouped_ec2_{}".format(collapse_by_tag_value[0]) + else: + self._type = "ec2" + self._local_id = json_blob["InstanceId"] + + self._arn = "arn:aws:ec2:{}:{}:instance/{}".format(parent.region.name, parent.account.local_id, self._local_id) + self._name = get_name(json_blob, "InstanceId") + super(Ec2, self).__init__(parent, json_blob) + + +class Elb(Leaf): + @property + def ips(self): + # ELB's don't have IPs + return [] + + @property + def is_public(self): + scheme = pyjq.all('.Scheme', self._json_blob)[0] + if scheme == "internet-facing": + return True + return False + + def security_groups(self): + return pyjq.all('.SecurityGroups[]', self._json_blob) + + def __init__(self, parent, json_blob): + self._type = "elb" + self._local_id = json_blob["LoadBalancerName"] + self._arn = "arn:aws:ec2:{}:{}:instance/{}/{}".format( + parent.region.name, + parent.account.local_id, + self._local_id, + parent.local_id) + self._name = json_blob["LoadBalancerName"] + super(Elb, self).__init__(parent, json_blob) + + +class Rds(Leaf): + @property + def ips(self): + # RDS instances don't have IPs + return [] + + @property + def is_public(self): + return pyjq.all('.PubliclyAccessible', self._json_blob)[0] + + def security_groups(self): + return pyjq.all('.VpcSecurityGroups[].VpcSecurityGroupId', self._json_blob) + + def __init__(self, parent, json_blob): + self._type = "rds" + + # Check if this is a read-replicable + if pyjq.all('.ReadReplicaSourceDBInstanceIdentifier', json_blob) != [None]: + self._type = "rds_rr" + + # I am making up this ARN, because RDS uses "arn:aws:rds:region:account-id:db:db-instance-name", + # but that doesn't tell the subnet + self._local_id = json_blob["DBInstanceIdentifier"] + self._arn = "arn:aws:rds:{}:{}:db-instance/{}/{}".format( + parent.region.name, + parent.account.local_id, + self._local_id, + parent.local_id + ) + self._name = truncate(json_blob["DBInstanceIdentifier"]) + super(Rds, self).__init__(parent, json_blob) + + +class Cidr(Leaf): + def ips(self): + return [self._local_id] + + def __init__(self, cidr, name=None): + self._type = "ip" + self._arn = cidr + self._local_id = cidr + if name: + self._name = name + else: + self._name = cidr + + if cidr == "0.0.0.0/0": + self._name = "Public" + self._type = "cloud" + + # For determining if this IP is actually connected to anything + self.is_used = False + + super(Cidr, self).__init__(None, cidr) + + +class Connection(object): + _source = None + _target = None + _json = None + + @property + def source(self): + return self._source + + @property + def target(self): + return self._target + + def __key(self): + return (self._source.arn, self._target.arn) + + def __eq__(self, x, y): + return x.__key() == y.__key() + + def __hash__(self): + return hash(self.__key()) + + def __init__(self, source, target): + self._source = source + self._target = target + self._json = [] + + def cytoscape_data(self): + return {"data": { + "source": self._source.arn, + "target": self._target.arn, + "type": "edge", + "node_data": self._json}} diff --git a/cloudmapper/prepare.py b/cloudmapper/prepare.py new file mode 100644 index 000000000..6e06721ed --- /dev/null +++ b/cloudmapper/prepare.py @@ -0,0 +1,342 @@ +""" +Copyright 2018 Duo Security + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------- +""" + +import json +import itertools +import pyjq +from netaddr import IPNetwork, IPAddress +from cloudmapper.nodes import Account, Region, Vpc, Az, Subnet, Ec2, Elb, Rds, Cidr, Connection + + +def query_aws(account, query, region=None): + if not region: + file_name = "{}/{}.json".format(account.name, query) + else: + file_name = "{}/{}/{}.json".format(account.name, region.name, query) + return json.load(open(file_name)) + + +def get_regions(account, outputfilter): + # aws ec2 describe-regions + region_data = query_aws(account, "describe-regions") + + region_filter = "" + if "regions" in outputfilter: + region_filter = "| select(.RegionName | contains({}))".format(outputfilter["regions"]) + + regions = pyjq.all('.Regions[]{}'.format(region_filter), region_data) + return regions + + +def get_vpcs(region): + try: + vpcs = query_aws(region.account, "describe-vpcs", region) + return pyjq.all('.Vpcs[]', vpcs) + except BaseException: + return None + + +def get_azs(vpc): + azs = query_aws(vpc.account, "describe-availability-zones", vpc.region) + resource_filter = '.AvailabilityZones[]' + return pyjq.all(resource_filter, azs) + + +def get_vpc_peerings(region): + vpc_peerings = query_aws(region.account, "describe-vpc-peering-connections", region) + resource_filter = '.VpcPeeringConnections[]' + return pyjq.all(resource_filter, vpc_peerings) + + +def get_subnets(az): + subnets = query_aws(az.account, "describe-subnets", az.region) + resource_filter = '.Subnets[] | select(.VpcId == "{}") | select(.AvailabilityZone == "{}")' + return pyjq.all(resource_filter.format(az.vpc.local_id, az.local_id), subnets) + + +def get_ec2s(subnet): + instances = query_aws(subnet.account, "describe-instances", subnet.region) + resource_filter = '.Reservations[].Instances[] | select(.SubnetId == "{}") | select(.State.Name == "running")' + return pyjq.all(resource_filter.format(subnet.local_id), instances) + + +def get_elbs(subnet): + instances = query_aws(subnet.account, "describe-load-balancers", subnet.region) + resource_filter = '.LoadBalancerDescriptions[] | select(.VPCId == "{}") | select(.Subnets[] == "{}")' + return pyjq.all(resource_filter.format(subnet.vpc.local_id, subnet.local_id), instances) + + +def get_rds_instances(subnet): + instances = query_aws(subnet.account, "describe-db-instances", subnet.region) + resource_filter = '.DBInstances[] | select(.DBSubnetGroup.Subnets[].SubnetIdentifier == "{}")' + return pyjq.all(resource_filter.format(subnet.local_id), instances) + + +def get_sgs(vpc): + sgs = query_aws(vpc.account, "describe-security-groups", vpc.region) + return pyjq.all('.SecurityGroups[] | select(.VpcId == "{}")'.format(vpc.local_id), sgs) + + +def is_external_cidr(cidr): + ipnetwork = IPNetwork(cidr) + if ( + ipnetwork in IPNetwork("10.0.0.0/8") or + ipnetwork in IPNetwork("172.16.0.0/12") or + ipnetwork in IPNetwork("192.168.0.0/16") + ): + return False + return True + + +def get_external_cidrs(account, config): + external_cidrs = [] + unique_cidrs = {} + for region in account.children: + for vpc in region.children: + sgs = get_sgs(vpc) + + # Get external IPs + for sg in sgs: + cidrs = pyjq.all('.IpPermissions[].IpRanges[].CidrIp', sg) + for cidr in cidrs: + unique_cidrs[cidr] = 1 + + # Remove private CIDR ranges + for cidr in unique_cidrs.keys(): + if is_external_cidr(cidr): + # It's something else, so add it + external_cidrs.append(Cidr(cidr, get_cidr_name(cidr, config))) + return external_cidrs + + +def get_cidr_name(cidr, config): + return config["cidrs"].get(cidr, {}).get("name", None) + + +def add_connection(connections, source, target, reason): + reasons = connections.get(Connection(source, target), []) + reasons.append(reason) + connections[Connection(source, target)] = reasons + + +def get_connections(cidrs, vpc, outputfilter): + """ + For a VPC, for each instance, find all of the other instances that can connect to it, + including those in peered VPCs. + Note I do not consider subnet ACLs, routing tables, or some other network concepts. + """ + connections = {} + + # Get mapping of security group names to nodes that have that security group + sg_to_instance_mapping = {} + for instance in vpc.leaves: + for sg in instance.security_groups(): + sg_to_instance_mapping.setdefault(sg, {})[instance] = True + + # For each security group, find all the instances that are allowed to connect to instances + # within that group. + for sg in get_sgs(vpc): + # Get the CIDRs that are allowed to connect + for cidr in pyjq.all('.IpPermissions[].IpRanges[].CidrIp', sg): + if not is_external_cidr(cidr): + # This is a private IP, ex. 10.0.0.0/16 + + # See if we should skip this + if not outputfilter["internal_edges"]: + continue + + # Find all instances in this VPC and peered VPCs that are in this CIDR + for sourceVpc in itertools.chain(vpc.peers, (vpc,)): + + # Ensure it is possible for instances in this VPC to be in the CIDR + if not (IPNetwork(sourceVpc.cidr) in IPNetwork(cidr) or + IPNetwork(cidr) in IPNetwork(sourceVpc.cidr)): + # The CIDR from the security group does not overlap with the CIDR of the VPC, + # so skip it + continue + + # For each instance, check if one of its IPs is within the CIDR + for sourceInstance in sourceVpc.leaves: + for ip in sourceInstance.ips: + if IPAddress(ip) in IPNetwork(cidr): + # Instance found that can connect to instances in the SG + # So connect this instance (sourceInstance) to every instance + # in the SG. + for targetInstance in sg_to_instance_mapping.get(sg["GroupId"], {}): + add_connection(connections, sourceInstance, targetInstance, sg) + + else: + # This is an external IP (ie. not in a private range). + for instance in sg_to_instance_mapping.get(sg["GroupId"], {}): + # Ensure it has a public IP, as resources with only private IPs can't be reached + if instance.is_public: + cidrs[cidr].is_used = True + add_connection(connections, cidrs[cidr], instance, sg) + + if outputfilter["internal_edges"]: + # Connect allowed in Security Groups + for ingress_sg in pyjq.all('.IpPermissions[].UserIdGroupPairs[].GroupId', sg): + # We have an SG and a list of SG's it allows in + for target in sg_to_instance_mapping.get(sg["GroupId"], {}): + # We have an instance and a list of SG's it allows in + for source in sg_to_instance_mapping.get(ingress_sg, {}): + if (not outputfilter["inter_rds_edges"] and + (source.node_type == "rds" or source.node_type == "rds_rr") and + (target.node_type == "rds" or target.node_type == "rds_rr")): + continue + add_connection(connections, source, target, sg) + + return connections + + +def build_data_structure(account_data, config, outputfilter): + cytoscape_json = [] + + account = Account(None, account_data) + print "Building data for account {} ({})".format(account.name, account.local_id) + + cytoscape_json.append(account.cytoscape_data()) + for region_json in get_regions(account, outputfilter): + node_count_per_region = 0 + region = Region(account, region_json) + + for vpc_json in get_vpcs(region): + vpc = Vpc(region, vpc_json) + + for az_json in get_azs(vpc): + # Availibility zones are not a per VPC construct, but VPC's can span AZ's, + # so I make VPC a higher level construct + az = Az(vpc, az_json) + + for subnet_json in get_subnets(az): + # If we ignore AZz, then tie the subnets up the VPC as the parent + if outputfilter["azs"]: + parent = az + else: + parent = vpc + + subnet = Subnet(parent, subnet_json) + + # Get EC2's + for ec2_json in get_ec2s(subnet): + ec2 = Ec2(subnet, ec2_json, outputfilter["collapse_by_tag"]) + subnet.addChild(ec2) + + # Get RDS's + for rds_json in get_rds_instances(subnet): + rds = Rds(subnet, rds_json) + if not outputfilter["read_replicas"] and rds.node_type == "rds_rr": + continue + subnet.addChild(rds) + + # Get ELB's + for elb_json in get_elbs(subnet): + elb = Elb(subnet, elb_json) + subnet.addChild(elb) + + # If there are leaves, then add this subnet to the final graph + if len(subnet.leaves) > 0: + node_count_per_region += len(subnet.leaves) + for leaf in subnet.leaves: + cytoscape_json.append(leaf.cytoscape_data()) + cytoscape_json.append(subnet.cytoscape_data()) + az.addChild(subnet) + + if az.has_leaves: + if outputfilter["azs"]: + cytoscape_json.append(az.cytoscape_data()) + vpc.addChild(az) + + if vpc.has_leaves: + cytoscape_json.append(vpc.cytoscape_data()) + region.addChild(vpc) + + if region.has_leaves: + cytoscape_json.append(region.cytoscape_data()) + account.addChild(region) + + print "- {} nodes built in region {}".format(node_count_per_region, region.local_id) + + # Get VPC peerings + for region in account.children: + for vpc_peering in get_vpc_peerings(region): + # For each peering, find the accepter and the requester + accepter_id = vpc_peering["AccepterVpcInfo"]["VpcId"] + requester_id = vpc_peering["RequesterVpcInfo"]["VpcId"] + accepter = None + requester = None + for vpc in region.children: + if accepter_id == vpc.local_id: + accepter = vpc + if requester_id == vpc.local_id: + requester = vpc + # If both have been found, add each as peers to one another + if accepter and requester: + accepter.addPeer(requester) + requester.addPeer(accepter) + + # Get external cidr nodes + cidrs = {} + for cidr in get_external_cidrs(account, config): + cidrs[cidr.arn] = cidr + + # Find connections between nodes + # Only looking at Security Groups currently, which are a VPC level construct + connections = {} + for region in account.children: + for vpc in region.children: + for c, reasons in get_connections(cidrs, vpc, outputfilter).iteritems(): + r = connections.get(c, []) + r.extend(reasons) + connections[c] = r + + # Add external cidr nodes + used_cidrs = 0 + for _, cidr in cidrs.iteritems(): + if cidr.is_used: + used_cidrs += 1 + cytoscape_json.append(cidr.cytoscape_data()) + print "- {} external CIDRs built".format(used_cidrs) + + total_number_of_nodes = len(cytoscape_json) + + # Add the mapping to our graph + for c, reasons in connections.iteritems(): + if c.source == c.target: + # Ensure we don't add connections with the same nodes on either side + continue + c._json = reasons + cytoscape_json.append(c.cytoscape_data()) + print "- {} connections built".format(len(connections)) + + # Check if we have a lot of data, and if so, show a warning + # Numbers chosen here are arbitrary + MAX_NODES_FOR_WARNING = 200 + MAX_EDGES_FOR_WARNING = 500 + if total_number_of_nodes > MAX_NODES_FOR_WARNING or len(connections) > MAX_EDGES_FOR_WARNING: + print "WARNING: There are {} total nodes and {} total edges.".format(total_number_of_nodes, len(connections)) + print " This will be difficult to display and may be too complex to make sense of." + print " Consider reducing the number of items in the diagram by viewing a single" + print " region, ignoring internal edges, or other filtering." + + return cytoscape_json + + +def prepare(account, config, outputfilter): + """Collect the data and write it to a file""" + cytoscape_json = build_data_structure(account, config, outputfilter) + + with open('web/data.json', 'w') as outfile: + json.dump(cytoscape_json, outfile, indent=4) diff --git a/cloudmapper/webserver.py b/cloudmapper/webserver.py new file mode 100644 index 000000000..d3f38e50a --- /dev/null +++ b/cloudmapper/webserver.py @@ -0,0 +1,67 @@ +""" +Copyright 2018 Duo Security + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +""" +import SimpleHTTPServer +from BaseHTTPServer import HTTPServer +import argparse +import os +import posixpath +import urllib + + +class RootedHTTPServer(HTTPServer): + def __init__(self, base_path, *args, **kwargs): + HTTPServer.__init__(self, *args, **kwargs) + self.RequestHandlerClass.base_path = base_path + + +class MyHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): + def translate_path(self, path): + path = posixpath.normpath(urllib.unquote(path)) + words = path.split('/') + words = filter(None, words) + path = self.base_path + for word in words: + drive, word = os.path.splitdrive(word) + head, word = os.path.split(word) + if word in (os.curdir, os.pardir): + continue + if '?' in word: + word = word[0:word.index('?')] + path = os.path.join(path, word) + return path + + def end_headers(self): + self.send_my_headers() + SimpleHTTPServer.SimpleHTTPRequestHandler.end_headers(self) + + def send_my_headers(self): + self.send_header("Cache-Control", "no-cache, no-store, must-revalidate") + self.send_header("Pragma", "no-cache") + self.send_header("Expires", "0") + + +def run_webserver(arguments): + parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter) + parser.add_argument("--port", help="Port to listen on", default=8000, type=int) + parser.add_argument("--public", dest='is_public', help="Allow connections from 0.0.0.0 as opposed to only localhost", action='store_true') + parser.set_defaults(is_public=False) + args = parser.parse_args(arguments) + + if args.is_public: + listening_host = '0.0.0.0' + else: + listening_host = '127.0.0.1' + + httpd = RootedHTTPServer("web", (listening_host, args.port), MyHTTPRequestHandler) + httpd.serve_forever() diff --git a/collect_data.sh b/collect_data.sh new file mode 100755 index 000000000..4c5d762f6 --- /dev/null +++ b/collect_data.sh @@ -0,0 +1,68 @@ +#!/bin/bash +set -euo pipefail + +echo "* Startup checks" + +if [ $# -ne 2 ] || [ "$1" != "--account" ] ; then + echo "ERROR: No account name specified" + echo "Usage:" + echo " $0 --account my_account" + exit -1 +fi + +# Ensure the aws cli exists +aws --version > /dev/null 2>&1 +if [ $? -ne 0 ]; then + echo "ERROR: Install the aws cli" + exit -1 +fi + +# Ensure we have AWS credentials +aws sts get-caller-identity > /dev/null +if [ $? -ne 0 ]; then + echo "ERROR: No AWS credentials set" + exit -1 +fi + +# Ensure jq exists +jq --help > /dev/null +if [ $? -ne 0 ]; then + echo "ERROR: jq not found" + exit -1 +fi + +account=$2 +mkdir -p "$account" +cd $account + +echo "* Getting region names" +aws ec2 describe-regions > describe-regions.json +# Create directory for each region name +cat describe-regions.json | jq -r '.Regions[].RegionName' | xargs -I{} sh -c 'mkdir -p $1' -- {} + +echo "* Getting VPC info" +cat describe-regions.json | jq -r '.Regions[].RegionName' | xargs -I{} sh -c 'aws ec2 --region "$1" describe-vpcs > "$1/describe-vpcs.json"' -- {} + +echo "* Getting AZ info" +cat describe-regions.json | jq -r '.Regions[].RegionName' | xargs -I{} sh -c 'aws ec2 --region "$1" describe-availability-zones > "$1/describe-availability-zones.json"' -- {} + +echo "* Getting subnet info" +cat describe-regions.json | jq -r '.Regions[].RegionName' | xargs -I{} sh -c 'aws ec2 --region "$1" describe-subnets > "$1/describe-subnets.json"' -- {} + +echo "* Getting EC2 info" +cat describe-regions.json | jq -r '.Regions[].RegionName' | xargs -I{} sh -c 'aws ec2 --region "$1" describe-instances > "$1/describe-instances.json"' -- {} + +echo "* Getting RDS info" +cat describe-regions.json | jq -r '.Regions[].RegionName' | xargs -I{} sh -c 'aws rds --region "$1" describe-db-instances > "$1/describe-db-instances.json"' -- {} + +echo "* Getting ELB info" +cat describe-regions.json | jq -r '.Regions[].RegionName' | xargs -I{} sh -c 'aws elb --region "$1" describe-load-balancers > "$1/describe-load-balancers.json"' -- {} + +echo "* Getting security group info" +cat describe-regions.json | jq -r '.Regions[].RegionName' | xargs -I{} sh -c 'aws ec2 --region "$1" describe-security-groups > "$1/describe-security-groups.json"' -- {} + +echo "* Getting network interface info" +cat describe-regions.json | jq -r '.Regions[].RegionName' | xargs -I{} sh -c 'aws ec2 --region "$1" describe-network-interfaces > "$1/describe-network-interfaces.json"' -- {} + +echo "* Getting VPC peering info" +cat describe-regions.json | jq -r '.Regions[].RegionName' | xargs -I{} sh -c 'aws ec2 --region "$1" describe-vpc-peering-connections > "$1/describe-vpc-peering-connections.json"' -- {} \ No newline at end of file diff --git a/config.json.demo b/config.json.demo new file mode 100644 index 000000000..e26d842b1 --- /dev/null +++ b/config.json.demo @@ -0,0 +1,11 @@ +{ "accounts": + [ + {"id": 123456789012, "name": "demo"} + ], + "cidrs": + { + "1.1.1.1/32": {"name": "SF Office"}, + "2.2.2.2/28": {"name": "NY Office"} + } +} + diff --git a/demo/ap-northeast-1/describe-availability-zones.json b/demo/ap-northeast-1/describe-availability-zones.json new file mode 100644 index 000000000..5b98be585 --- /dev/null +++ b/demo/ap-northeast-1/describe-availability-zones.json @@ -0,0 +1,16 @@ +{ + "AvailabilityZones": [ + { + "State": "available", + "ZoneName": "ap-northeast-1a", + "Messages": [], + "RegionName": "ap-northeast-1" + }, + { + "State": "available", + "ZoneName": "ap-northeast-1c", + "Messages": [], + "RegionName": "ap-northeast-1" + } + ] +} diff --git a/demo/ap-northeast-1/describe-db-instances.json b/demo/ap-northeast-1/describe-db-instances.json new file mode 100644 index 000000000..8f850cfde --- /dev/null +++ b/demo/ap-northeast-1/describe-db-instances.json @@ -0,0 +1,3 @@ +{ + "DBInstances": [] +} diff --git a/demo/ap-northeast-1/describe-instances.json b/demo/ap-northeast-1/describe-instances.json new file mode 100644 index 000000000..2cb4c9491 --- /dev/null +++ b/demo/ap-northeast-1/describe-instances.json @@ -0,0 +1,3 @@ +{ + "Reservations": [] +} diff --git a/demo/ap-northeast-1/describe-load-balancers.json b/demo/ap-northeast-1/describe-load-balancers.json new file mode 100644 index 000000000..1849201d0 --- /dev/null +++ b/demo/ap-northeast-1/describe-load-balancers.json @@ -0,0 +1,3 @@ +{ + "LoadBalancerDescriptions": [] +} diff --git a/demo/ap-northeast-1/describe-network-interfaces.json b/demo/ap-northeast-1/describe-network-interfaces.json new file mode 100644 index 000000000..34a8f88f4 --- /dev/null +++ b/demo/ap-northeast-1/describe-network-interfaces.json @@ -0,0 +1,3 @@ +{ + "NetworkInterfaces": [] +} diff --git a/demo/ap-northeast-1/describe-security-groups.json b/demo/ap-northeast-1/describe-security-groups.json new file mode 100644 index 000000000..94e386d14 --- /dev/null +++ b/demo/ap-northeast-1/describe-security-groups.json @@ -0,0 +1,38 @@ +{ + "SecurityGroups": [ + { + "IpPermissionsEgress": [ + { + "IpProtocol": "-1", + "PrefixListIds": [], + "IpRanges": [ + { + "CidrIp": "0.0.0.0/0" + } + ], + "UserIdGroupPairs": [], + "Ipv6Ranges": [] + } + ], + "Description": "default VPC security group", + "IpPermissions": [ + { + "IpProtocol": "-1", + "PrefixListIds": [], + "IpRanges": [], + "UserIdGroupPairs": [ + { + "UserId": "123456789012", + "GroupId": "sg-00000001" + } + ], + "Ipv6Ranges": [] + } + ], + "GroupName": "default", + "VpcId": "vpc-12345678", + "OwnerId": "123456789012", + "GroupId": "sg-00000001" + } + ] +} diff --git a/demo/ap-northeast-1/describe-subnets.json b/demo/ap-northeast-1/describe-subnets.json new file mode 100644 index 000000000..aff65587c --- /dev/null +++ b/demo/ap-northeast-1/describe-subnets.json @@ -0,0 +1,28 @@ +{ + "Subnets": [ + { + "AvailabilityZone": "ap-northeast-1c", + "AvailableIpAddressCount": 4091, + "DefaultForAz": true, + "Ipv6CidrBlockAssociationSet": [], + "VpcId": "vpc-12345678", + "State": "available", + "MapPublicIpOnLaunch": true, + "SubnetId": "subnet-00000001", + "CidrBlock": "172.31.0.0/20", + "AssignIpv6AddressOnCreation": false + }, + { + "AvailabilityZone": "ap-northeast-1a", + "AvailableIpAddressCount": 4091, + "DefaultForAz": true, + "Ipv6CidrBlockAssociationSet": [], + "VpcId": "vpc-12345678", + "State": "available", + "MapPublicIpOnLaunch": true, + "SubnetId": "subnet-00000002", + "CidrBlock": "172.31.16.0/20", + "AssignIpv6AddressOnCreation": false + } + ] +} diff --git a/demo/ap-northeast-1/describe-vpc-peering-connections.json b/demo/ap-northeast-1/describe-vpc-peering-connections.json new file mode 100644 index 000000000..19d619ca9 --- /dev/null +++ b/demo/ap-northeast-1/describe-vpc-peering-connections.json @@ -0,0 +1,3 @@ +{ + "VpcPeeringConnections": [] +} diff --git a/demo/ap-northeast-1/describe-vpcs.json b/demo/ap-northeast-1/describe-vpcs.json new file mode 100644 index 000000000..91059b8c2 --- /dev/null +++ b/demo/ap-northeast-1/describe-vpcs.json @@ -0,0 +1,21 @@ +{ + "Vpcs": [ + { + "VpcId": "vpc-12345678", + "InstanceTenancy": "default", + "CidrBlockAssociationSet": [ + { + "AssociationId": "vpc-cidr-assoc-12345678", + "CidrBlock": "172.31.0.0/16", + "CidrBlockState": { + "State": "associated" + } + } + ], + "State": "available", + "DhcpOptionsId": "dopt-12345678", + "CidrBlock": "172.31.0.0/16", + "IsDefault": true + } + ] +} diff --git a/demo/ap-northeast-2/describe-availability-zones.json b/demo/ap-northeast-2/describe-availability-zones.json new file mode 100644 index 000000000..bed29daf2 --- /dev/null +++ b/demo/ap-northeast-2/describe-availability-zones.json @@ -0,0 +1,16 @@ +{ + "AvailabilityZones": [ + { + "State": "available", + "ZoneName": "ap-northeast-2a", + "Messages": [], + "RegionName": "ap-northeast-2" + }, + { + "State": "available", + "ZoneName": "ap-northeast-2c", + "Messages": [], + "RegionName": "ap-northeast-2" + } + ] +} diff --git a/demo/ap-northeast-2/describe-db-instances.json b/demo/ap-northeast-2/describe-db-instances.json new file mode 100644 index 000000000..8f850cfde --- /dev/null +++ b/demo/ap-northeast-2/describe-db-instances.json @@ -0,0 +1,3 @@ +{ + "DBInstances": [] +} diff --git a/demo/ap-northeast-2/describe-instances.json b/demo/ap-northeast-2/describe-instances.json new file mode 100644 index 000000000..2cb4c9491 --- /dev/null +++ b/demo/ap-northeast-2/describe-instances.json @@ -0,0 +1,3 @@ +{ + "Reservations": [] +} diff --git a/demo/ap-northeast-2/describe-load-balancers.json b/demo/ap-northeast-2/describe-load-balancers.json new file mode 100644 index 000000000..1849201d0 --- /dev/null +++ b/demo/ap-northeast-2/describe-load-balancers.json @@ -0,0 +1,3 @@ +{ + "LoadBalancerDescriptions": [] +} diff --git a/demo/ap-northeast-2/describe-network-interfaces.json b/demo/ap-northeast-2/describe-network-interfaces.json new file mode 100644 index 000000000..34a8f88f4 --- /dev/null +++ b/demo/ap-northeast-2/describe-network-interfaces.json @@ -0,0 +1,3 @@ +{ + "NetworkInterfaces": [] +} diff --git a/demo/ap-northeast-2/describe-security-groups.json b/demo/ap-northeast-2/describe-security-groups.json new file mode 100644 index 000000000..94e386d14 --- /dev/null +++ b/demo/ap-northeast-2/describe-security-groups.json @@ -0,0 +1,38 @@ +{ + "SecurityGroups": [ + { + "IpPermissionsEgress": [ + { + "IpProtocol": "-1", + "PrefixListIds": [], + "IpRanges": [ + { + "CidrIp": "0.0.0.0/0" + } + ], + "UserIdGroupPairs": [], + "Ipv6Ranges": [] + } + ], + "Description": "default VPC security group", + "IpPermissions": [ + { + "IpProtocol": "-1", + "PrefixListIds": [], + "IpRanges": [], + "UserIdGroupPairs": [ + { + "UserId": "123456789012", + "GroupId": "sg-00000001" + } + ], + "Ipv6Ranges": [] + } + ], + "GroupName": "default", + "VpcId": "vpc-12345678", + "OwnerId": "123456789012", + "GroupId": "sg-00000001" + } + ] +} diff --git a/demo/ap-northeast-2/describe-subnets.json b/demo/ap-northeast-2/describe-subnets.json new file mode 100644 index 000000000..13155a8f2 --- /dev/null +++ b/demo/ap-northeast-2/describe-subnets.json @@ -0,0 +1,28 @@ +{ + "Subnets": [ + { + "AvailabilityZone": "ap-northeast-2c", + "AvailableIpAddressCount": 4091, + "DefaultForAz": true, + "Ipv6CidrBlockAssociationSet": [], + "VpcId": "vpc-12345678", + "State": "available", + "MapPublicIpOnLaunch": true, + "SubnetId": "subnet-00000001", + "CidrBlock": "172.31.0.0/20", + "AssignIpv6AddressOnCreation": false + }, + { + "AvailabilityZone": "ap-northeast-2a", + "AvailableIpAddressCount": 4091, + "DefaultForAz": true, + "Ipv6CidrBlockAssociationSet": [], + "VpcId": "vpc-12345678", + "State": "available", + "MapPublicIpOnLaunch": true, + "SubnetId": "subnet-00000002", + "CidrBlock": "172.31.16.0/20", + "AssignIpv6AddressOnCreation": false + } + ] +} diff --git a/demo/ap-northeast-2/describe-vpc-peering-connections.json b/demo/ap-northeast-2/describe-vpc-peering-connections.json new file mode 100644 index 000000000..19d619ca9 --- /dev/null +++ b/demo/ap-northeast-2/describe-vpc-peering-connections.json @@ -0,0 +1,3 @@ +{ + "VpcPeeringConnections": [] +} diff --git a/demo/ap-northeast-2/describe-vpcs.json b/demo/ap-northeast-2/describe-vpcs.json new file mode 100644 index 000000000..91059b8c2 --- /dev/null +++ b/demo/ap-northeast-2/describe-vpcs.json @@ -0,0 +1,21 @@ +{ + "Vpcs": [ + { + "VpcId": "vpc-12345678", + "InstanceTenancy": "default", + "CidrBlockAssociationSet": [ + { + "AssociationId": "vpc-cidr-assoc-12345678", + "CidrBlock": "172.31.0.0/16", + "CidrBlockState": { + "State": "associated" + } + } + ], + "State": "available", + "DhcpOptionsId": "dopt-12345678", + "CidrBlock": "172.31.0.0/16", + "IsDefault": true + } + ] +} diff --git a/demo/ap-south-1/describe-availability-zones.json b/demo/ap-south-1/describe-availability-zones.json new file mode 100644 index 000000000..a0caf4278 --- /dev/null +++ b/demo/ap-south-1/describe-availability-zones.json @@ -0,0 +1,16 @@ +{ + "AvailabilityZones": [ + { + "State": "available", + "ZoneName": "ap-south-1a", + "Messages": [], + "RegionName": "ap-south-1" + }, + { + "State": "available", + "ZoneName": "ap-south-1b", + "Messages": [], + "RegionName": "ap-south-1" + } + ] +} diff --git a/demo/ap-south-1/describe-db-instances.json b/demo/ap-south-1/describe-db-instances.json new file mode 100644 index 000000000..8f850cfde --- /dev/null +++ b/demo/ap-south-1/describe-db-instances.json @@ -0,0 +1,3 @@ +{ + "DBInstances": [] +} diff --git a/demo/ap-south-1/describe-instances.json b/demo/ap-south-1/describe-instances.json new file mode 100644 index 000000000..2cb4c9491 --- /dev/null +++ b/demo/ap-south-1/describe-instances.json @@ -0,0 +1,3 @@ +{ + "Reservations": [] +} diff --git a/demo/ap-south-1/describe-load-balancers.json b/demo/ap-south-1/describe-load-balancers.json new file mode 100644 index 000000000..1849201d0 --- /dev/null +++ b/demo/ap-south-1/describe-load-balancers.json @@ -0,0 +1,3 @@ +{ + "LoadBalancerDescriptions": [] +} diff --git a/demo/ap-south-1/describe-network-interfaces.json b/demo/ap-south-1/describe-network-interfaces.json new file mode 100644 index 000000000..34a8f88f4 --- /dev/null +++ b/demo/ap-south-1/describe-network-interfaces.json @@ -0,0 +1,3 @@ +{ + "NetworkInterfaces": [] +} diff --git a/demo/ap-south-1/describe-security-groups.json b/demo/ap-south-1/describe-security-groups.json new file mode 100644 index 000000000..94e386d14 --- /dev/null +++ b/demo/ap-south-1/describe-security-groups.json @@ -0,0 +1,38 @@ +{ + "SecurityGroups": [ + { + "IpPermissionsEgress": [ + { + "IpProtocol": "-1", + "PrefixListIds": [], + "IpRanges": [ + { + "CidrIp": "0.0.0.0/0" + } + ], + "UserIdGroupPairs": [], + "Ipv6Ranges": [] + } + ], + "Description": "default VPC security group", + "IpPermissions": [ + { + "IpProtocol": "-1", + "PrefixListIds": [], + "IpRanges": [], + "UserIdGroupPairs": [ + { + "UserId": "123456789012", + "GroupId": "sg-00000001" + } + ], + "Ipv6Ranges": [] + } + ], + "GroupName": "default", + "VpcId": "vpc-12345678", + "OwnerId": "123456789012", + "GroupId": "sg-00000001" + } + ] +} diff --git a/demo/ap-south-1/describe-subnets.json b/demo/ap-south-1/describe-subnets.json new file mode 100644 index 000000000..51daee939 --- /dev/null +++ b/demo/ap-south-1/describe-subnets.json @@ -0,0 +1,28 @@ +{ + "Subnets": [ + { + "AvailabilityZone": "ap-south-1a", + "AvailableIpAddressCount": 4091, + "DefaultForAz": true, + "Ipv6CidrBlockAssociationSet": [], + "VpcId": "vpc-12345678", + "State": "available", + "MapPublicIpOnLaunch": true, + "SubnetId": "subnet-00000001", + "CidrBlock": "172.31.0.0/20", + "AssignIpv6AddressOnCreation": false + }, + { + "AvailabilityZone": "ap-south-1b", + "AvailableIpAddressCount": 4091, + "DefaultForAz": true, + "Ipv6CidrBlockAssociationSet": [], + "VpcId": "vpc-12345678", + "State": "available", + "MapPublicIpOnLaunch": true, + "SubnetId": "subnet-00000002", + "CidrBlock": "172.31.16.0/20", + "AssignIpv6AddressOnCreation": false + } + ] +} diff --git a/demo/ap-south-1/describe-vpc-peering-connections.json b/demo/ap-south-1/describe-vpc-peering-connections.json new file mode 100644 index 000000000..19d619ca9 --- /dev/null +++ b/demo/ap-south-1/describe-vpc-peering-connections.json @@ -0,0 +1,3 @@ +{ + "VpcPeeringConnections": [] +} diff --git a/demo/ap-south-1/describe-vpcs.json b/demo/ap-south-1/describe-vpcs.json new file mode 100644 index 000000000..91059b8c2 --- /dev/null +++ b/demo/ap-south-1/describe-vpcs.json @@ -0,0 +1,21 @@ +{ + "Vpcs": [ + { + "VpcId": "vpc-12345678", + "InstanceTenancy": "default", + "CidrBlockAssociationSet": [ + { + "AssociationId": "vpc-cidr-assoc-12345678", + "CidrBlock": "172.31.0.0/16", + "CidrBlockState": { + "State": "associated" + } + } + ], + "State": "available", + "DhcpOptionsId": "dopt-12345678", + "CidrBlock": "172.31.0.0/16", + "IsDefault": true + } + ] +} diff --git a/demo/ap-southeast-1/describe-availability-zones.json b/demo/ap-southeast-1/describe-availability-zones.json new file mode 100644 index 000000000..568cf5415 --- /dev/null +++ b/demo/ap-southeast-1/describe-availability-zones.json @@ -0,0 +1,16 @@ +{ + "AvailabilityZones": [ + { + "State": "available", + "ZoneName": "ap-southeast-1a", + "Messages": [], + "RegionName": "ap-southeast-1" + }, + { + "State": "available", + "ZoneName": "ap-southeast-1b", + "Messages": [], + "RegionName": "ap-southeast-1" + } + ] +} diff --git a/demo/ap-southeast-1/describe-db-instances.json b/demo/ap-southeast-1/describe-db-instances.json new file mode 100644 index 000000000..8f850cfde --- /dev/null +++ b/demo/ap-southeast-1/describe-db-instances.json @@ -0,0 +1,3 @@ +{ + "DBInstances": [] +} diff --git a/demo/ap-southeast-1/describe-instances.json b/demo/ap-southeast-1/describe-instances.json new file mode 100644 index 000000000..2cb4c9491 --- /dev/null +++ b/demo/ap-southeast-1/describe-instances.json @@ -0,0 +1,3 @@ +{ + "Reservations": [] +} diff --git a/demo/ap-southeast-1/describe-load-balancers.json b/demo/ap-southeast-1/describe-load-balancers.json new file mode 100644 index 000000000..1849201d0 --- /dev/null +++ b/demo/ap-southeast-1/describe-load-balancers.json @@ -0,0 +1,3 @@ +{ + "LoadBalancerDescriptions": [] +} diff --git a/demo/ap-southeast-1/describe-network-interfaces.json b/demo/ap-southeast-1/describe-network-interfaces.json new file mode 100644 index 000000000..34a8f88f4 --- /dev/null +++ b/demo/ap-southeast-1/describe-network-interfaces.json @@ -0,0 +1,3 @@ +{ + "NetworkInterfaces": [] +} diff --git a/demo/ap-southeast-1/describe-security-groups.json b/demo/ap-southeast-1/describe-security-groups.json new file mode 100644 index 000000000..94e386d14 --- /dev/null +++ b/demo/ap-southeast-1/describe-security-groups.json @@ -0,0 +1,38 @@ +{ + "SecurityGroups": [ + { + "IpPermissionsEgress": [ + { + "IpProtocol": "-1", + "PrefixListIds": [], + "IpRanges": [ + { + "CidrIp": "0.0.0.0/0" + } + ], + "UserIdGroupPairs": [], + "Ipv6Ranges": [] + } + ], + "Description": "default VPC security group", + "IpPermissions": [ + { + "IpProtocol": "-1", + "PrefixListIds": [], + "IpRanges": [], + "UserIdGroupPairs": [ + { + "UserId": "123456789012", + "GroupId": "sg-00000001" + } + ], + "Ipv6Ranges": [] + } + ], + "GroupName": "default", + "VpcId": "vpc-12345678", + "OwnerId": "123456789012", + "GroupId": "sg-00000001" + } + ] +} diff --git a/demo/ap-southeast-1/describe-subnets.json b/demo/ap-southeast-1/describe-subnets.json new file mode 100644 index 000000000..6b9f0e171 --- /dev/null +++ b/demo/ap-southeast-1/describe-subnets.json @@ -0,0 +1,28 @@ +{ + "Subnets": [ + { + "AvailabilityZone": "ap-southeast-1a", + "AvailableIpAddressCount": 4091, + "DefaultForAz": true, + "Ipv6CidrBlockAssociationSet": [], + "VpcId": "vpc-12345678", + "State": "available", + "MapPublicIpOnLaunch": true, + "SubnetId": "subnet-00000001", + "CidrBlock": "172.31.0.0/20", + "AssignIpv6AddressOnCreation": false + }, + { + "AvailabilityZone": "ap-southeast-1b", + "AvailableIpAddressCount": 4091, + "DefaultForAz": true, + "Ipv6CidrBlockAssociationSet": [], + "VpcId": "vpc-12345678", + "State": "available", + "MapPublicIpOnLaunch": true, + "SubnetId": "subnet-00000002", + "CidrBlock": "172.31.16.0/20", + "AssignIpv6AddressOnCreation": false + } + ] +} diff --git a/demo/ap-southeast-1/describe-vpc-peering-connections.json b/demo/ap-southeast-1/describe-vpc-peering-connections.json new file mode 100644 index 000000000..19d619ca9 --- /dev/null +++ b/demo/ap-southeast-1/describe-vpc-peering-connections.json @@ -0,0 +1,3 @@ +{ + "VpcPeeringConnections": [] +} diff --git a/demo/ap-southeast-1/describe-vpcs.json b/demo/ap-southeast-1/describe-vpcs.json new file mode 100644 index 000000000..91059b8c2 --- /dev/null +++ b/demo/ap-southeast-1/describe-vpcs.json @@ -0,0 +1,21 @@ +{ + "Vpcs": [ + { + "VpcId": "vpc-12345678", + "InstanceTenancy": "default", + "CidrBlockAssociationSet": [ + { + "AssociationId": "vpc-cidr-assoc-12345678", + "CidrBlock": "172.31.0.0/16", + "CidrBlockState": { + "State": "associated" + } + } + ], + "State": "available", + "DhcpOptionsId": "dopt-12345678", + "CidrBlock": "172.31.0.0/16", + "IsDefault": true + } + ] +} diff --git a/demo/ap-southeast-2/describe-availability-zones.json b/demo/ap-southeast-2/describe-availability-zones.json new file mode 100644 index 000000000..52f297d79 --- /dev/null +++ b/demo/ap-southeast-2/describe-availability-zones.json @@ -0,0 +1,22 @@ +{ + "AvailabilityZones": [ + { + "State": "available", + "ZoneName": "ap-southeast-2a", + "Messages": [], + "RegionName": "ap-southeast-2" + }, + { + "State": "available", + "ZoneName": "ap-southeast-2b", + "Messages": [], + "RegionName": "ap-southeast-2" + }, + { + "State": "available", + "ZoneName": "ap-southeast-2c", + "Messages": [], + "RegionName": "ap-southeast-2" + } + ] +} diff --git a/demo/ap-southeast-2/describe-db-instances.json b/demo/ap-southeast-2/describe-db-instances.json new file mode 100644 index 000000000..8f850cfde --- /dev/null +++ b/demo/ap-southeast-2/describe-db-instances.json @@ -0,0 +1,3 @@ +{ + "DBInstances": [] +} diff --git a/demo/ap-southeast-2/describe-instances.json b/demo/ap-southeast-2/describe-instances.json new file mode 100644 index 000000000..2cb4c9491 --- /dev/null +++ b/demo/ap-southeast-2/describe-instances.json @@ -0,0 +1,3 @@ +{ + "Reservations": [] +} diff --git a/demo/ap-southeast-2/describe-load-balancers.json b/demo/ap-southeast-2/describe-load-balancers.json new file mode 100644 index 000000000..1849201d0 --- /dev/null +++ b/demo/ap-southeast-2/describe-load-balancers.json @@ -0,0 +1,3 @@ +{ + "LoadBalancerDescriptions": [] +} diff --git a/demo/ap-southeast-2/describe-network-interfaces.json b/demo/ap-southeast-2/describe-network-interfaces.json new file mode 100644 index 000000000..34a8f88f4 --- /dev/null +++ b/demo/ap-southeast-2/describe-network-interfaces.json @@ -0,0 +1,3 @@ +{ + "NetworkInterfaces": [] +} diff --git a/demo/ap-southeast-2/describe-security-groups.json b/demo/ap-southeast-2/describe-security-groups.json new file mode 100644 index 000000000..94e386d14 --- /dev/null +++ b/demo/ap-southeast-2/describe-security-groups.json @@ -0,0 +1,38 @@ +{ + "SecurityGroups": [ + { + "IpPermissionsEgress": [ + { + "IpProtocol": "-1", + "PrefixListIds": [], + "IpRanges": [ + { + "CidrIp": "0.0.0.0/0" + } + ], + "UserIdGroupPairs": [], + "Ipv6Ranges": [] + } + ], + "Description": "default VPC security group", + "IpPermissions": [ + { + "IpProtocol": "-1", + "PrefixListIds": [], + "IpRanges": [], + "UserIdGroupPairs": [ + { + "UserId": "123456789012", + "GroupId": "sg-00000001" + } + ], + "Ipv6Ranges": [] + } + ], + "GroupName": "default", + "VpcId": "vpc-12345678", + "OwnerId": "123456789012", + "GroupId": "sg-00000001" + } + ] +} diff --git a/demo/ap-southeast-2/describe-subnets.json b/demo/ap-southeast-2/describe-subnets.json new file mode 100644 index 000000000..bd628a2db --- /dev/null +++ b/demo/ap-southeast-2/describe-subnets.json @@ -0,0 +1,28 @@ +{ + "Subnets": [ + { + "AvailabilityZone": "ap-southeast-2a", + "AvailableIpAddressCount": 4091, + "DefaultForAz": true, + "Ipv6CidrBlockAssociationSet": [], + "VpcId": "vpc-12345678", + "State": "available", + "MapPublicIpOnLaunch": true, + "SubnetId": "subnet-00000001", + "CidrBlock": "172.31.0.0/20", + "AssignIpv6AddressOnCreation": false + }, + { + "AvailabilityZone": "ap-southeast-2b", + "AvailableIpAddressCount": 4091, + "DefaultForAz": true, + "Ipv6CidrBlockAssociationSet": [], + "VpcId": "vpc-12345678", + "State": "available", + "MapPublicIpOnLaunch": true, + "SubnetId": "subnet-00000002", + "CidrBlock": "172.31.16.0/20", + "AssignIpv6AddressOnCreation": false + } + ] +} diff --git a/demo/ap-southeast-2/describe-vpc-peering-connections.json b/demo/ap-southeast-2/describe-vpc-peering-connections.json new file mode 100644 index 000000000..19d619ca9 --- /dev/null +++ b/demo/ap-southeast-2/describe-vpc-peering-connections.json @@ -0,0 +1,3 @@ +{ + "VpcPeeringConnections": [] +} diff --git a/demo/ap-southeast-2/describe-vpcs.json b/demo/ap-southeast-2/describe-vpcs.json new file mode 100644 index 000000000..91059b8c2 --- /dev/null +++ b/demo/ap-southeast-2/describe-vpcs.json @@ -0,0 +1,21 @@ +{ + "Vpcs": [ + { + "VpcId": "vpc-12345678", + "InstanceTenancy": "default", + "CidrBlockAssociationSet": [ + { + "AssociationId": "vpc-cidr-assoc-12345678", + "CidrBlock": "172.31.0.0/16", + "CidrBlockState": { + "State": "associated" + } + } + ], + "State": "available", + "DhcpOptionsId": "dopt-12345678", + "CidrBlock": "172.31.0.0/16", + "IsDefault": true + } + ] +} diff --git a/demo/ca-central-1/describe-availability-zones.json b/demo/ca-central-1/describe-availability-zones.json new file mode 100644 index 000000000..d7c417e55 --- /dev/null +++ b/demo/ca-central-1/describe-availability-zones.json @@ -0,0 +1,16 @@ +{ + "AvailabilityZones": [ + { + "State": "available", + "ZoneName": "ca-central-1a", + "Messages": [], + "RegionName": "ca-central-1" + }, + { + "State": "available", + "ZoneName": "ca-central-1b", + "Messages": [], + "RegionName": "ca-central-1" + } + ] +} diff --git a/demo/ca-central-1/describe-db-instances.json b/demo/ca-central-1/describe-db-instances.json new file mode 100644 index 000000000..8f850cfde --- /dev/null +++ b/demo/ca-central-1/describe-db-instances.json @@ -0,0 +1,3 @@ +{ + "DBInstances": [] +} diff --git a/demo/ca-central-1/describe-instances.json b/demo/ca-central-1/describe-instances.json new file mode 100644 index 000000000..2cb4c9491 --- /dev/null +++ b/demo/ca-central-1/describe-instances.json @@ -0,0 +1,3 @@ +{ + "Reservations": [] +} diff --git a/demo/ca-central-1/describe-load-balancers.json b/demo/ca-central-1/describe-load-balancers.json new file mode 100644 index 000000000..1849201d0 --- /dev/null +++ b/demo/ca-central-1/describe-load-balancers.json @@ -0,0 +1,3 @@ +{ + "LoadBalancerDescriptions": [] +} diff --git a/demo/ca-central-1/describe-network-interfaces.json b/demo/ca-central-1/describe-network-interfaces.json new file mode 100644 index 000000000..34a8f88f4 --- /dev/null +++ b/demo/ca-central-1/describe-network-interfaces.json @@ -0,0 +1,3 @@ +{ + "NetworkInterfaces": [] +} diff --git a/demo/ca-central-1/describe-security-groups.json b/demo/ca-central-1/describe-security-groups.json new file mode 100644 index 000000000..94e386d14 --- /dev/null +++ b/demo/ca-central-1/describe-security-groups.json @@ -0,0 +1,38 @@ +{ + "SecurityGroups": [ + { + "IpPermissionsEgress": [ + { + "IpProtocol": "-1", + "PrefixListIds": [], + "IpRanges": [ + { + "CidrIp": "0.0.0.0/0" + } + ], + "UserIdGroupPairs": [], + "Ipv6Ranges": [] + } + ], + "Description": "default VPC security group", + "IpPermissions": [ + { + "IpProtocol": "-1", + "PrefixListIds": [], + "IpRanges": [], + "UserIdGroupPairs": [ + { + "UserId": "123456789012", + "GroupId": "sg-00000001" + } + ], + "Ipv6Ranges": [] + } + ], + "GroupName": "default", + "VpcId": "vpc-12345678", + "OwnerId": "123456789012", + "GroupId": "sg-00000001" + } + ] +} diff --git a/demo/ca-central-1/describe-subnets.json b/demo/ca-central-1/describe-subnets.json new file mode 100644 index 000000000..6e0d15554 --- /dev/null +++ b/demo/ca-central-1/describe-subnets.json @@ -0,0 +1,28 @@ +{ + "Subnets": [ + { + "AvailabilityZone": "ca-central-1a", + "AvailableIpAddressCount": 4091, + "DefaultForAz": true, + "Ipv6CidrBlockAssociationSet": [], + "VpcId": "vpc-12345678", + "State": "available", + "MapPublicIpOnLaunch": true, + "SubnetId": "subnet-00000001", + "CidrBlock": "172.31.0.0/20", + "AssignIpv6AddressOnCreation": false + }, + { + "AvailabilityZone": "ca-central-1b", + "AvailableIpAddressCount": 4091, + "DefaultForAz": true, + "Ipv6CidrBlockAssociationSet": [], + "VpcId": "vpc-12345678", + "State": "available", + "MapPublicIpOnLaunch": true, + "SubnetId": "subnet-00000002", + "CidrBlock": "172.31.16.0/20", + "AssignIpv6AddressOnCreation": false + } + ] +} diff --git a/demo/ca-central-1/describe-vpc-peering-connections.json b/demo/ca-central-1/describe-vpc-peering-connections.json new file mode 100644 index 000000000..19d619ca9 --- /dev/null +++ b/demo/ca-central-1/describe-vpc-peering-connections.json @@ -0,0 +1,3 @@ +{ + "VpcPeeringConnections": [] +} diff --git a/demo/ca-central-1/describe-vpcs.json b/demo/ca-central-1/describe-vpcs.json new file mode 100644 index 000000000..91059b8c2 --- /dev/null +++ b/demo/ca-central-1/describe-vpcs.json @@ -0,0 +1,21 @@ +{ + "Vpcs": [ + { + "VpcId": "vpc-12345678", + "InstanceTenancy": "default", + "CidrBlockAssociationSet": [ + { + "AssociationId": "vpc-cidr-assoc-12345678", + "CidrBlock": "172.31.0.0/16", + "CidrBlockState": { + "State": "associated" + } + } + ], + "State": "available", + "DhcpOptionsId": "dopt-12345678", + "CidrBlock": "172.31.0.0/16", + "IsDefault": true + } + ] +} diff --git a/demo/describe-regions.json b/demo/describe-regions.json new file mode 100644 index 000000000..bc193a189 --- /dev/null +++ b/demo/describe-regions.json @@ -0,0 +1,60 @@ +{ + "Regions": [ + { + "Endpoint": "ec2.ap-south-1.amazonaws.com", + "RegionName": "ap-south-1" + }, + { + "Endpoint": "ec2.eu-west-2.amazonaws.com", + "RegionName": "eu-west-2" + }, + { + "Endpoint": "ec2.eu-west-1.amazonaws.com", + "RegionName": "eu-west-1" + }, + { + "Endpoint": "ec2.ap-northeast-2.amazonaws.com", + "RegionName": "ap-northeast-2" + }, + { + "Endpoint": "ec2.ap-northeast-1.amazonaws.com", + "RegionName": "ap-northeast-1" + }, + { + "Endpoint": "ec2.sa-east-1.amazonaws.com", + "RegionName": "sa-east-1" + }, + { + "Endpoint": "ec2.ca-central-1.amazonaws.com", + "RegionName": "ca-central-1" + }, + { + "Endpoint": "ec2.ap-southeast-1.amazonaws.com", + "RegionName": "ap-southeast-1" + }, + { + "Endpoint": "ec2.ap-southeast-2.amazonaws.com", + "RegionName": "ap-southeast-2" + }, + { + "Endpoint": "ec2.eu-central-1.amazonaws.com", + "RegionName": "eu-central-1" + }, + { + "Endpoint": "ec2.us-east-1.amazonaws.com", + "RegionName": "us-east-1" + }, + { + "Endpoint": "ec2.us-east-2.amazonaws.com", + "RegionName": "us-east-2" + }, + { + "Endpoint": "ec2.us-west-1.amazonaws.com", + "RegionName": "us-west-1" + }, + { + "Endpoint": "ec2.us-west-2.amazonaws.com", + "RegionName": "us-west-2" + } + ] +} diff --git a/demo/eu-central-1/describe-availability-zones.json b/demo/eu-central-1/describe-availability-zones.json new file mode 100644 index 000000000..14f96dcd9 --- /dev/null +++ b/demo/eu-central-1/describe-availability-zones.json @@ -0,0 +1,22 @@ +{ + "AvailabilityZones": [ + { + "State": "available", + "ZoneName": "eu-central-1a", + "Messages": [], + "RegionName": "eu-central-1" + }, + { + "State": "available", + "ZoneName": "eu-central-1b", + "Messages": [], + "RegionName": "eu-central-1" + }, + { + "State": "available", + "ZoneName": "eu-central-1c", + "Messages": [], + "RegionName": "eu-central-1" + } + ] +} diff --git a/demo/eu-central-1/describe-db-instances.json b/demo/eu-central-1/describe-db-instances.json new file mode 100644 index 000000000..8f850cfde --- /dev/null +++ b/demo/eu-central-1/describe-db-instances.json @@ -0,0 +1,3 @@ +{ + "DBInstances": [] +} diff --git a/demo/eu-central-1/describe-instances.json b/demo/eu-central-1/describe-instances.json new file mode 100644 index 000000000..2cb4c9491 --- /dev/null +++ b/demo/eu-central-1/describe-instances.json @@ -0,0 +1,3 @@ +{ + "Reservations": [] +} diff --git a/demo/eu-central-1/describe-load-balancers.json b/demo/eu-central-1/describe-load-balancers.json new file mode 100644 index 000000000..1849201d0 --- /dev/null +++ b/demo/eu-central-1/describe-load-balancers.json @@ -0,0 +1,3 @@ +{ + "LoadBalancerDescriptions": [] +} diff --git a/demo/eu-central-1/describe-network-interfaces.json b/demo/eu-central-1/describe-network-interfaces.json new file mode 100644 index 000000000..34a8f88f4 --- /dev/null +++ b/demo/eu-central-1/describe-network-interfaces.json @@ -0,0 +1,3 @@ +{ + "NetworkInterfaces": [] +} diff --git a/demo/eu-central-1/describe-security-groups.json b/demo/eu-central-1/describe-security-groups.json new file mode 100644 index 000000000..94e386d14 --- /dev/null +++ b/demo/eu-central-1/describe-security-groups.json @@ -0,0 +1,38 @@ +{ + "SecurityGroups": [ + { + "IpPermissionsEgress": [ + { + "IpProtocol": "-1", + "PrefixListIds": [], + "IpRanges": [ + { + "CidrIp": "0.0.0.0/0" + } + ], + "UserIdGroupPairs": [], + "Ipv6Ranges": [] + } + ], + "Description": "default VPC security group", + "IpPermissions": [ + { + "IpProtocol": "-1", + "PrefixListIds": [], + "IpRanges": [], + "UserIdGroupPairs": [ + { + "UserId": "123456789012", + "GroupId": "sg-00000001" + } + ], + "Ipv6Ranges": [] + } + ], + "GroupName": "default", + "VpcId": "vpc-12345678", + "OwnerId": "123456789012", + "GroupId": "sg-00000001" + } + ] +} diff --git a/demo/eu-central-1/describe-subnets.json b/demo/eu-central-1/describe-subnets.json new file mode 100644 index 000000000..1f114c68e --- /dev/null +++ b/demo/eu-central-1/describe-subnets.json @@ -0,0 +1,28 @@ +{ + "Subnets": [ + { + "AvailabilityZone": "eu-central-1a", + "AvailableIpAddressCount": 4091, + "DefaultForAz": true, + "Ipv6CidrBlockAssociationSet": [], + "VpcId": "vpc-12345678", + "State": "available", + "MapPublicIpOnLaunch": true, + "SubnetId": "subnet-00000001", + "CidrBlock": "172.31.0.0/20", + "AssignIpv6AddressOnCreation": false + }, + { + "AvailabilityZone": "eu-central-1b", + "AvailableIpAddressCount": 4091, + "DefaultForAz": true, + "Ipv6CidrBlockAssociationSet": [], + "VpcId": "vpc-12345678", + "State": "available", + "MapPublicIpOnLaunch": true, + "SubnetId": "subnet-00000002", + "CidrBlock": "172.31.16.0/20", + "AssignIpv6AddressOnCreation": false + } + ] +} diff --git a/demo/eu-central-1/describe-vpc-peering-connections.json b/demo/eu-central-1/describe-vpc-peering-connections.json new file mode 100644 index 000000000..19d619ca9 --- /dev/null +++ b/demo/eu-central-1/describe-vpc-peering-connections.json @@ -0,0 +1,3 @@ +{ + "VpcPeeringConnections": [] +} diff --git a/demo/eu-central-1/describe-vpcs.json b/demo/eu-central-1/describe-vpcs.json new file mode 100644 index 000000000..91059b8c2 --- /dev/null +++ b/demo/eu-central-1/describe-vpcs.json @@ -0,0 +1,21 @@ +{ + "Vpcs": [ + { + "VpcId": "vpc-12345678", + "InstanceTenancy": "default", + "CidrBlockAssociationSet": [ + { + "AssociationId": "vpc-cidr-assoc-12345678", + "CidrBlock": "172.31.0.0/16", + "CidrBlockState": { + "State": "associated" + } + } + ], + "State": "available", + "DhcpOptionsId": "dopt-12345678", + "CidrBlock": "172.31.0.0/16", + "IsDefault": true + } + ] +} diff --git a/demo/eu-west-1/describe-availability-zones.json b/demo/eu-west-1/describe-availability-zones.json new file mode 100644 index 000000000..f438cb6f2 --- /dev/null +++ b/demo/eu-west-1/describe-availability-zones.json @@ -0,0 +1,22 @@ +{ + "AvailabilityZones": [ + { + "State": "available", + "ZoneName": "eu-west-1a", + "Messages": [], + "RegionName": "eu-west-1" + }, + { + "State": "available", + "ZoneName": "eu-west-1b", + "Messages": [], + "RegionName": "eu-west-1" + }, + { + "State": "available", + "ZoneName": "eu-west-1c", + "Messages": [], + "RegionName": "eu-west-1" + } + ] +} diff --git a/demo/eu-west-1/describe-db-instances.json b/demo/eu-west-1/describe-db-instances.json new file mode 100644 index 000000000..8f850cfde --- /dev/null +++ b/demo/eu-west-1/describe-db-instances.json @@ -0,0 +1,3 @@ +{ + "DBInstances": [] +} diff --git a/demo/eu-west-1/describe-instances.json b/demo/eu-west-1/describe-instances.json new file mode 100644 index 000000000..2cb4c9491 --- /dev/null +++ b/demo/eu-west-1/describe-instances.json @@ -0,0 +1,3 @@ +{ + "Reservations": [] +} diff --git a/demo/eu-west-1/describe-load-balancers.json b/demo/eu-west-1/describe-load-balancers.json new file mode 100644 index 000000000..1849201d0 --- /dev/null +++ b/demo/eu-west-1/describe-load-balancers.json @@ -0,0 +1,3 @@ +{ + "LoadBalancerDescriptions": [] +} diff --git a/demo/eu-west-1/describe-network-interfaces.json b/demo/eu-west-1/describe-network-interfaces.json new file mode 100644 index 000000000..34a8f88f4 --- /dev/null +++ b/demo/eu-west-1/describe-network-interfaces.json @@ -0,0 +1,3 @@ +{ + "NetworkInterfaces": [] +} diff --git a/demo/eu-west-1/describe-security-groups.json b/demo/eu-west-1/describe-security-groups.json new file mode 100644 index 000000000..94e386d14 --- /dev/null +++ b/demo/eu-west-1/describe-security-groups.json @@ -0,0 +1,38 @@ +{ + "SecurityGroups": [ + { + "IpPermissionsEgress": [ + { + "IpProtocol": "-1", + "PrefixListIds": [], + "IpRanges": [ + { + "CidrIp": "0.0.0.0/0" + } + ], + "UserIdGroupPairs": [], + "Ipv6Ranges": [] + } + ], + "Description": "default VPC security group", + "IpPermissions": [ + { + "IpProtocol": "-1", + "PrefixListIds": [], + "IpRanges": [], + "UserIdGroupPairs": [ + { + "UserId": "123456789012", + "GroupId": "sg-00000001" + } + ], + "Ipv6Ranges": [] + } + ], + "GroupName": "default", + "VpcId": "vpc-12345678", + "OwnerId": "123456789012", + "GroupId": "sg-00000001" + } + ] +} diff --git a/demo/eu-west-1/describe-subnets.json b/demo/eu-west-1/describe-subnets.json new file mode 100644 index 000000000..b52be9202 --- /dev/null +++ b/demo/eu-west-1/describe-subnets.json @@ -0,0 +1,28 @@ +{ + "Subnets": [ + { + "AvailabilityZone": "eu-west-1a", + "AvailableIpAddressCount": 4091, + "DefaultForAz": true, + "Ipv6CidrBlockAssociationSet": [], + "VpcId": "vpc-12345678", + "State": "available", + "MapPublicIpOnLaunch": true, + "SubnetId": "subnet-00000001", + "CidrBlock": "172.31.0.0/20", + "AssignIpv6AddressOnCreation": false + }, + { + "AvailabilityZone": "eu-west-1b", + "AvailableIpAddressCount": 4091, + "DefaultForAz": true, + "Ipv6CidrBlockAssociationSet": [], + "VpcId": "vpc-12345678", + "State": "available", + "MapPublicIpOnLaunch": true, + "SubnetId": "subnet-00000002", + "CidrBlock": "172.31.16.0/20", + "AssignIpv6AddressOnCreation": false + } + ] +} diff --git a/demo/eu-west-1/describe-vpc-peering-connections.json b/demo/eu-west-1/describe-vpc-peering-connections.json new file mode 100644 index 000000000..19d619ca9 --- /dev/null +++ b/demo/eu-west-1/describe-vpc-peering-connections.json @@ -0,0 +1,3 @@ +{ + "VpcPeeringConnections": [] +} diff --git a/demo/eu-west-1/describe-vpcs.json b/demo/eu-west-1/describe-vpcs.json new file mode 100644 index 000000000..91059b8c2 --- /dev/null +++ b/demo/eu-west-1/describe-vpcs.json @@ -0,0 +1,21 @@ +{ + "Vpcs": [ + { + "VpcId": "vpc-12345678", + "InstanceTenancy": "default", + "CidrBlockAssociationSet": [ + { + "AssociationId": "vpc-cidr-assoc-12345678", + "CidrBlock": "172.31.0.0/16", + "CidrBlockState": { + "State": "associated" + } + } + ], + "State": "available", + "DhcpOptionsId": "dopt-12345678", + "CidrBlock": "172.31.0.0/16", + "IsDefault": true + } + ] +} diff --git a/demo/eu-west-2/describe-availability-zones.json b/demo/eu-west-2/describe-availability-zones.json new file mode 100644 index 000000000..fb073cd1f --- /dev/null +++ b/demo/eu-west-2/describe-availability-zones.json @@ -0,0 +1,16 @@ +{ + "AvailabilityZones": [ + { + "State": "available", + "ZoneName": "eu-west-2a", + "Messages": [], + "RegionName": "eu-west-2" + }, + { + "State": "available", + "ZoneName": "eu-west-2b", + "Messages": [], + "RegionName": "eu-west-2" + } + ] +} diff --git a/demo/eu-west-2/describe-db-instances.json b/demo/eu-west-2/describe-db-instances.json new file mode 100644 index 000000000..8f850cfde --- /dev/null +++ b/demo/eu-west-2/describe-db-instances.json @@ -0,0 +1,3 @@ +{ + "DBInstances": [] +} diff --git a/demo/eu-west-2/describe-instances.json b/demo/eu-west-2/describe-instances.json new file mode 100644 index 000000000..2cb4c9491 --- /dev/null +++ b/demo/eu-west-2/describe-instances.json @@ -0,0 +1,3 @@ +{ + "Reservations": [] +} diff --git a/demo/eu-west-2/describe-load-balancers.json b/demo/eu-west-2/describe-load-balancers.json new file mode 100644 index 000000000..1849201d0 --- /dev/null +++ b/demo/eu-west-2/describe-load-balancers.json @@ -0,0 +1,3 @@ +{ + "LoadBalancerDescriptions": [] +} diff --git a/demo/eu-west-2/describe-network-interfaces.json b/demo/eu-west-2/describe-network-interfaces.json new file mode 100644 index 000000000..34a8f88f4 --- /dev/null +++ b/demo/eu-west-2/describe-network-interfaces.json @@ -0,0 +1,3 @@ +{ + "NetworkInterfaces": [] +} diff --git a/demo/eu-west-2/describe-security-groups.json b/demo/eu-west-2/describe-security-groups.json new file mode 100644 index 000000000..94e386d14 --- /dev/null +++ b/demo/eu-west-2/describe-security-groups.json @@ -0,0 +1,38 @@ +{ + "SecurityGroups": [ + { + "IpPermissionsEgress": [ + { + "IpProtocol": "-1", + "PrefixListIds": [], + "IpRanges": [ + { + "CidrIp": "0.0.0.0/0" + } + ], + "UserIdGroupPairs": [], + "Ipv6Ranges": [] + } + ], + "Description": "default VPC security group", + "IpPermissions": [ + { + "IpProtocol": "-1", + "PrefixListIds": [], + "IpRanges": [], + "UserIdGroupPairs": [ + { + "UserId": "123456789012", + "GroupId": "sg-00000001" + } + ], + "Ipv6Ranges": [] + } + ], + "GroupName": "default", + "VpcId": "vpc-12345678", + "OwnerId": "123456789012", + "GroupId": "sg-00000001" + } + ] +} diff --git a/demo/eu-west-2/describe-subnets.json b/demo/eu-west-2/describe-subnets.json new file mode 100644 index 000000000..d8d3df5f3 --- /dev/null +++ b/demo/eu-west-2/describe-subnets.json @@ -0,0 +1,28 @@ +{ + "Subnets": [ + { + "AvailabilityZone": "eu-west-2a", + "AvailableIpAddressCount": 4091, + "DefaultForAz": true, + "Ipv6CidrBlockAssociationSet": [], + "VpcId": "vpc-12345678", + "State": "available", + "MapPublicIpOnLaunch": true, + "SubnetId": "subnet-00000001", + "CidrBlock": "172.31.0.0/20", + "AssignIpv6AddressOnCreation": false + }, + { + "AvailabilityZone": "eu-west-2b", + "AvailableIpAddressCount": 4091, + "DefaultForAz": true, + "Ipv6CidrBlockAssociationSet": [], + "VpcId": "vpc-12345678", + "State": "available", + "MapPublicIpOnLaunch": true, + "SubnetId": "subnet-00000002", + "CidrBlock": "172.31.16.0/20", + "AssignIpv6AddressOnCreation": false + } + ] +} diff --git a/demo/eu-west-2/describe-vpc-peering-connections.json b/demo/eu-west-2/describe-vpc-peering-connections.json new file mode 100644 index 000000000..19d619ca9 --- /dev/null +++ b/demo/eu-west-2/describe-vpc-peering-connections.json @@ -0,0 +1,3 @@ +{ + "VpcPeeringConnections": [] +} diff --git a/demo/eu-west-2/describe-vpcs.json b/demo/eu-west-2/describe-vpcs.json new file mode 100644 index 000000000..91059b8c2 --- /dev/null +++ b/demo/eu-west-2/describe-vpcs.json @@ -0,0 +1,21 @@ +{ + "Vpcs": [ + { + "VpcId": "vpc-12345678", + "InstanceTenancy": "default", + "CidrBlockAssociationSet": [ + { + "AssociationId": "vpc-cidr-assoc-12345678", + "CidrBlock": "172.31.0.0/16", + "CidrBlockState": { + "State": "associated" + } + } + ], + "State": "available", + "DhcpOptionsId": "dopt-12345678", + "CidrBlock": "172.31.0.0/16", + "IsDefault": true + } + ] +} diff --git a/demo/sa-east-1/describe-availability-zones.json b/demo/sa-east-1/describe-availability-zones.json new file mode 100644 index 000000000..f0541cee0 --- /dev/null +++ b/demo/sa-east-1/describe-availability-zones.json @@ -0,0 +1,16 @@ +{ + "AvailabilityZones": [ + { + "State": "available", + "ZoneName": "sa-east-1a", + "Messages": [], + "RegionName": "sa-east-1" + }, + { + "State": "available", + "ZoneName": "sa-east-1c", + "Messages": [], + "RegionName": "sa-east-1" + } + ] +} diff --git a/demo/sa-east-1/describe-db-instances.json b/demo/sa-east-1/describe-db-instances.json new file mode 100644 index 000000000..8f850cfde --- /dev/null +++ b/demo/sa-east-1/describe-db-instances.json @@ -0,0 +1,3 @@ +{ + "DBInstances": [] +} diff --git a/demo/sa-east-1/describe-instances.json b/demo/sa-east-1/describe-instances.json new file mode 100644 index 000000000..2cb4c9491 --- /dev/null +++ b/demo/sa-east-1/describe-instances.json @@ -0,0 +1,3 @@ +{ + "Reservations": [] +} diff --git a/demo/sa-east-1/describe-load-balancers.json b/demo/sa-east-1/describe-load-balancers.json new file mode 100644 index 000000000..1849201d0 --- /dev/null +++ b/demo/sa-east-1/describe-load-balancers.json @@ -0,0 +1,3 @@ +{ + "LoadBalancerDescriptions": [] +} diff --git a/demo/sa-east-1/describe-network-interfaces.json b/demo/sa-east-1/describe-network-interfaces.json new file mode 100644 index 000000000..34a8f88f4 --- /dev/null +++ b/demo/sa-east-1/describe-network-interfaces.json @@ -0,0 +1,3 @@ +{ + "NetworkInterfaces": [] +} diff --git a/demo/sa-east-1/describe-security-groups.json b/demo/sa-east-1/describe-security-groups.json new file mode 100644 index 000000000..94e386d14 --- /dev/null +++ b/demo/sa-east-1/describe-security-groups.json @@ -0,0 +1,38 @@ +{ + "SecurityGroups": [ + { + "IpPermissionsEgress": [ + { + "IpProtocol": "-1", + "PrefixListIds": [], + "IpRanges": [ + { + "CidrIp": "0.0.0.0/0" + } + ], + "UserIdGroupPairs": [], + "Ipv6Ranges": [] + } + ], + "Description": "default VPC security group", + "IpPermissions": [ + { + "IpProtocol": "-1", + "PrefixListIds": [], + "IpRanges": [], + "UserIdGroupPairs": [ + { + "UserId": "123456789012", + "GroupId": "sg-00000001" + } + ], + "Ipv6Ranges": [] + } + ], + "GroupName": "default", + "VpcId": "vpc-12345678", + "OwnerId": "123456789012", + "GroupId": "sg-00000001" + } + ] +} diff --git a/demo/sa-east-1/describe-subnets.json b/demo/sa-east-1/describe-subnets.json new file mode 100644 index 000000000..83b851591 --- /dev/null +++ b/demo/sa-east-1/describe-subnets.json @@ -0,0 +1,28 @@ +{ + "Subnets": [ + { + "AvailabilityZone": "sa-east-1a", + "AvailableIpAddressCount": 4091, + "DefaultForAz": true, + "Ipv6CidrBlockAssociationSet": [], + "VpcId": "vpc-12345678", + "State": "available", + "MapPublicIpOnLaunch": true, + "SubnetId": "subnet-00000001", + "CidrBlock": "172.31.0.0/20", + "AssignIpv6AddressOnCreation": false + }, + { + "AvailabilityZone": "sa-east-1c", + "AvailableIpAddressCount": 4091, + "DefaultForAz": true, + "Ipv6CidrBlockAssociationSet": [], + "VpcId": "vpc-12345678", + "State": "available", + "MapPublicIpOnLaunch": true, + "SubnetId": "subnet-00000002", + "CidrBlock": "172.31.16.0/20", + "AssignIpv6AddressOnCreation": false + } + ] +} diff --git a/demo/sa-east-1/describe-vpc-peering-connections.json b/demo/sa-east-1/describe-vpc-peering-connections.json new file mode 100644 index 000000000..19d619ca9 --- /dev/null +++ b/demo/sa-east-1/describe-vpc-peering-connections.json @@ -0,0 +1,3 @@ +{ + "VpcPeeringConnections": [] +} diff --git a/demo/sa-east-1/describe-vpcs.json b/demo/sa-east-1/describe-vpcs.json new file mode 100644 index 000000000..91059b8c2 --- /dev/null +++ b/demo/sa-east-1/describe-vpcs.json @@ -0,0 +1,21 @@ +{ + "Vpcs": [ + { + "VpcId": "vpc-12345678", + "InstanceTenancy": "default", + "CidrBlockAssociationSet": [ + { + "AssociationId": "vpc-cidr-assoc-12345678", + "CidrBlock": "172.31.0.0/16", + "CidrBlockState": { + "State": "associated" + } + } + ], + "State": "available", + "DhcpOptionsId": "dopt-12345678", + "CidrBlock": "172.31.0.0/16", + "IsDefault": true + } + ] +} diff --git a/demo/us-east-1/describe-availability-zones.json b/demo/us-east-1/describe-availability-zones.json new file mode 100644 index 000000000..b9ce5f618 --- /dev/null +++ b/demo/us-east-1/describe-availability-zones.json @@ -0,0 +1,40 @@ +{ + "AvailabilityZones": [ + { + "State": "available", + "ZoneName": "us-east-1a", + "Messages": [], + "RegionName": "us-east-1" + }, + { + "State": "available", + "ZoneName": "us-east-1b", + "Messages": [], + "RegionName": "us-east-1" + }, + { + "State": "available", + "ZoneName": "us-east-1c", + "Messages": [], + "RegionName": "us-east-1" + }, + { + "State": "available", + "ZoneName": "us-east-1d", + "Messages": [], + "RegionName": "us-east-1" + }, + { + "State": "available", + "ZoneName": "us-east-1e", + "Messages": [], + "RegionName": "us-east-1" + }, + { + "State": "available", + "ZoneName": "us-east-1f", + "Messages": [], + "RegionName": "us-east-1" + } + ] +} diff --git a/demo/us-east-1/describe-db-instances.json b/demo/us-east-1/describe-db-instances.json new file mode 100644 index 000000000..e114947ee --- /dev/null +++ b/demo/us-east-1/describe-db-instances.json @@ -0,0 +1,86 @@ +{ + "DBInstances": [ + { + "PubliclyAccessible": false, + "MasterUsername": "master", + "MonitoringInterval": 60, + "LicenseModel": "postgresql-license", + "VpcSecurityGroups": [ + { + "Status": "active", + "VpcSecurityGroupId": "sg-00000005" + } + ], + "InstanceCreateTime": "2017-12-01T00:00:00.000Z", + "CopyTagsToSnapshot": false, + "OptionGroupMemberships": [ + { + "Status": "in-sync", + "OptionGroupName": "default:postgres-9-6" + } + ], + "PendingModifiedValues": {}, + "Engine": "postgres", + "MultiAZ": false, + "LatestRestorableTime": "2017-12-01T00:00:00Z", + "DBSecurityGroups": [], + "DBParameterGroups": [ + { + "DBParameterGroupName": "default.postgres9.6", + "ParameterApplyStatus": "in-sync" + } + ], + "PerformanceInsightsEnabled": false, + "AutoMinorVersionUpgrade": true, + "PreferredBackupWindow": "00:00-01:00", + "DBSubnetGroup": { + "Subnets": [ + { + "SubnetStatus": "Active", + "SubnetIdentifier": "subnet-00000004", + "SubnetAvailabilityZone": { + "Name": "us-east-2b" + } + }, + { + "SubnetStatus": "Active", + "SubnetIdentifier": "subnet-00000003", + "SubnetAvailabilityZone": { + "Name": "us-east-2a" + } + } + ], + "DBSubnetGroupName": "db subnet", + "VpcId": "vpc-12345678", + "DBSubnetGroupDescription": "Private", + "SubnetGroupStatus": "Complete" + }, + "ReadReplicaDBInstanceIdentifiers": [], + "AllocatedStorage": 100, + "DBInstanceArn": "arn:aws:rds:us-east-1:123456789012:db:securitymonkey", + "BackupRetentionPeriod": 7, + "DBName": "database", + "PreferredMaintenanceWindow": "fri:00:00-fri:01:00", + "Endpoint": { + "HostedZoneId": "Z2XHWR1WZ565X2", + "Port": 5432, + "Address": "database.abcdefghijkl.us-east-1.rds.amazonaws.com" + }, + "DBInstanceStatus": "available", + "IAMDatabaseAuthenticationEnabled": false, + "EngineVersion": "9.6.2", + "EnhancedMonitoringResourceArn": "arn:aws:logs:us-east-2:123456789012:log-group:RDSOSMetrics:log-stream:db-00000000000000000000000000", + "AvailabilityZone": "us-east-2a", + "DomainMemberships": [], + "MonitoringRoleArn": "arn:aws:iam::123456789012:role/rds-monitoring-role", + "StorageType": "gp2", + "DbiResourceId": "db-00000000000000000000000000", + "CACertificateIdentifier": "rds-ca-2015", + "KmsKeyId": "arn:aws:kms:us-east-1:123456789012:key/ca455c06-8a9f-4057-949d-b13d298d478b", + "StorageEncrypted": true, + "DBInstanceClass": "db.t2.micro", + "DbInstancePort": 0, + "DBInstanceIdentifier": "database" + } + ] +} diff --git a/demo/us-east-1/describe-instances.json b/demo/us-east-1/describe-instances.json new file mode 100644 index 000000000..be8b65521 --- /dev/null +++ b/demo/us-east-1/describe-instances.json @@ -0,0 +1,299 @@ +{ + "Reservations": [ + { + "Instances": [ + { + "Monitoring": { + "State": "enabled" + }, + "PublicDnsName": "ec2-1-2-3-4.compute-1.amazonaws.com", + "State": { + "Code": 16, + "Name": "running" + }, + "EbsOptimized": true, + "LaunchTime": "2017-12-01T00:00:00.000Z", + "PublicIpAddress": "1.2.3.4", + "PrivateIpAddress": "10.0.0.1", + "VpcId": "vpc-12345678", + "StateTransitionReason": "", + "InstanceId": "i-00000000000000000", + "EnaSupport": true, + "ImageId": "ami-00000000", + "PrivateDnsName": "ip-10-0-0-1.ec2.internal", + "KeyName": "bastion", + "SecurityGroups": [ + { + "GroupName": "Restricted SSH Access", + "GroupId": "sg-00000002" + } + ], + "ClientToken": "00000000000000000", + "SubnetId": "subnet-00000001", + "InstanceType": "t2.micro", + "NetworkInterfaces": [ + { + "Status": "in-use", + "MacAddress": "0e:d7:00:00:00:00", + "SourceDestCheck": true, + "VpcId": "vpc-12345678", + "Description": "Primary network interface", + "NetworkInterfaceId": "eni-00000000", + "PrivateIpAddresses": [ + { + "PrivateDnsName": "ip-10-0-0-1.ec2.internal", + "PrivateIpAddress": "10.0.0.1", + "Primary": true, + "Association": { + "PublicIp": "1.2.3.4", + "PublicDnsName": "ec2-1-2-3-4.compute-1.amazonaws.com", + "IpOwnerId": "amazon" + } + } + ], + "PrivateDnsName": "ip-10-0-0-1.ec2.internal", + "Attachment": { + "Status": "attached", + "DeviceIndex": 0, + "DeleteOnTermination": true, + "AttachmentId": "eni-attach-00000000", + "AttachTime": "2017-12-01T00:00:00.000Z" + }, + "Groups": [ + { + "GroupName": "Bastion", + "GroupId": "sg-00000002" + } + ], + "Ipv6Addresses": [], + "OwnerId": "123456789012", + "PrivateIpAddress": "10.0.0.1", + "SubnetId": "subnet-00000001", + "Association": { + "PublicIp": "1.2.3.4", + "PublicDnsName": "ec2-1-2-3-4.compute-1.amazonaws.com", + "IpOwnerId": "amazon" + } + } + ], + "SourceDestCheck": true, + "Placement": { + "Tenancy": "default", + "GroupName": "", + "AvailabilityZone": "us-east-1a" + }, + "Hypervisor": "xen", + "BlockDeviceMappings": [ + { + "DeviceName": "/dev/sda1", + "Ebs": { + "Status": "attached", + "DeleteOnTermination": true, + "VolumeId": "vol-00000000000000000", + "AttachTime": "2017-12-01T00:00:00.000Z" + } + } + ], + "Architecture": "x86_64", + "RootDeviceType": "ebs", + "RootDeviceName": "/dev/sda1", + "VirtualizationType": "hvm", + "Tags": [ + { + "Value": "Bastion", + "Key": "Name" + } + ], + "AmiLaunchIndex": 0 + }, + { + "Monitoring": { + "State": "enabled" + }, + "State": { + "Code": 16, + "Name": "running" + }, + "EbsOptimized": true, + "LaunchTime": "2017-12-01T00:00:00.000Z", + "PrivateIpAddress": "10.0.2.1", + "VpcId": "vpc-12345678", + "StateTransitionReason": "", + "InstanceId": "i-00000000000000001", + "EnaSupport": true, + "ImageId": "ami-00000001", + "PrivateDnsName": "ip-10-0-2-1.ec2.internal", + "KeyName": "web2", + "SecurityGroups": [ + { + "GroupName": "Internal web", + "GroupId": "sg-00000004" + } + ], + "ClientToken": "00000000000000000", + "SubnetId": "subnet-00000003", + "InstanceType": "t2.micro", + "NetworkInterfaces": [ + { + "Status": "in-use", + "MacAddress": "0e:d7:00:00:00:00", + "SourceDestCheck": true, + "VpcId": "vpc-12345678", + "Description": "Primary network interface", + "NetworkInterfaceId": "eni-00000000", + "PrivateIpAddresses": [ + { + "PrivateDnsName": "ip-10-0-2-1.ec2.internal", + "PrivateIpAddress": "10.0.2.1", + "Primary": true + } + ], + "PrivateDnsName": "ip-10-0-0-1.ec2.internal", + "Attachment": { + "Status": "attached", + "DeviceIndex": 0, + "DeleteOnTermination": true, + "AttachmentId": "eni-attach-00000000", + "AttachTime": "2017-12-01T00:00:00.000Z" + }, + "Groups": [ + { + "GroupName": "Internal web", + "GroupId": "sg-00000004" + } + ], + "Ipv6Addresses": [], + "OwnerId": "123456789012", + "PrivateIpAddress": "10.0.2.1", + "SubnetId": "subnet-00000003" + } + ], + "SourceDestCheck": true, + "Placement": { + "Tenancy": "default", + "GroupName": "", + "AvailabilityZone": "us-east-1a" + }, + "Hypervisor": "xen", + "BlockDeviceMappings": [ + { + "DeviceName": "/dev/sda1", + "Ebs": { + "Status": "attached", + "DeleteOnTermination": true, + "VolumeId": "vol-00000000000000001", + "AttachTime": "2017-12-01T00:00:00.000Z" + } + } + ], + "Architecture": "x86_64", + "RootDeviceType": "ebs", + "RootDeviceName": "/dev/sda1", + "VirtualizationType": "hvm", + "Tags": [ + { + "Value": "Web1", + "Key": "Name" + } + ], + "AmiLaunchIndex": 0 + }, + { + "Monitoring": { + "State": "enabled" + }, + "State": { + "Code": 16, + "Name": "running" + }, + "EbsOptimized": true, + "LaunchTime": "2017-12-01T00:00:00.000Z", + "PrivateIpAddress": "10.0.3.1", + "VpcId": "vpc-12345678", + "StateTransitionReason": "", + "InstanceId": "i-00000000000000002", + "EnaSupport": true, + "ImageId": "ami-00000001", + "PrivateDnsName": "ip-10-0-3-1.ec2.internal", + "KeyName": "web2", + "SecurityGroups": [ + { + "GroupName": "Internal web", + "GroupId": "sg-00000004" + } + ], + "ClientToken": "00000000000000000", + "SubnetId": "subnet-00000004", + "InstanceType": "t2.micro", + "NetworkInterfaces": [ + { + "Status": "in-use", + "MacAddress": "0e:d7:00:00:00:00", + "SourceDestCheck": true, + "VpcId": "vpc-12345678", + "Description": "Primary network interface", + "NetworkInterfaceId": "eni-00000000", + "PrivateIpAddresses": [ + { + "PrivateDnsName": "ip-10-0-3-1.ec2.internal", + "PrivateIpAddress": "10.0.3.1", + "Primary": true + } + ], + "PrivateDnsName": "ip-10-0-3-1.ec2.internal", + "Attachment": { + "Status": "attached", + "DeviceIndex": 0, + "DeleteOnTermination": true, + "AttachmentId": "eni-attach-00000000", + "AttachTime": "2017-12-01T00:00:00.000Z" + }, + "Groups": [ + { + "GroupName": "Internal web", + "GroupId": "sg-00000004" + } + ], + "Ipv6Addresses": [], + "OwnerId": "123456789012", + "PrivateIpAddress": "10.0.3.1", + "SubnetId": "subnet-00000004" + } + ], + "SourceDestCheck": true, + "Placement": { + "Tenancy": "default", + "GroupName": "", + "AvailabilityZone": "us-east-1b" + }, + "Hypervisor": "xen", + "BlockDeviceMappings": [ + { + "DeviceName": "/dev/sda1", + "Ebs": { + "Status": "attached", + "DeleteOnTermination": true, + "VolumeId": "vol-00000000000000003", + "AttachTime": "2017-12-01T00:00:00.000Z" + } + } + ], + "Architecture": "x86_64", + "RootDeviceType": "ebs", + "RootDeviceName": "/dev/sda1", + "VirtualizationType": "hvm", + "Tags": [ + { + "Value": "Web2", + "Key": "Name" + } + ], + "AmiLaunchIndex": 0 + } + ], + "ReservationId": "r-00000000000000000", + "Groups": [], + "OwnerId": "123456789012" + } + ] +} \ No newline at end of file diff --git a/demo/us-east-1/describe-load-balancers.json b/demo/us-east-1/describe-load-balancers.json new file mode 100644 index 000000000..a9207f327 --- /dev/null +++ b/demo/us-east-1/describe-load-balancers.json @@ -0,0 +1,60 @@ +{ + "LoadBalancerDescriptions": [ + { + "Subnets": [ + "subnet-00000001", + "subnet-00000002" + ], + "CanonicalHostedZoneNameID": "0000000000000", + "CanonicalHostedZoneName": "weblb-0000000000.us-east-1.elb.amazonaws.com", + "ListenerDescriptions": [ + { + "Listener": { + "InstancePort": 8000, + "LoadBalancerPort": 8000, + "Protocol": "HTTP", + "InstanceProtocol": "HTTP" + }, + "PolicyNames": [] + } + ], + "HealthCheck": { + "HealthyThreshold": 2, + "Interval": 30, + "Target": "TCP:8000", + "Timeout": 5, + "UnhealthyThreshold": 2 + }, + "VPCId": "vpc-12345678", + "BackendServerDescriptions": [], + "Instances": [ + { + "InstanceId": "i-00000000000000002" + }, + { + "InstanceId": "i-00000000000000003" + } + ], + "DNSName": "weblb.us-west-2.elb.amazonaws.com", + "SecurityGroups": [ + "sg-00000003" + ], + "Policies": { + "LBCookieStickinessPolicies": [], + "AppCookieStickinessPolicies": [], + "OtherPolicies": [] + }, + "LoadBalancerName": "weblb", + "CreatedTime": "2017-12-01T00:00:00.000Z", + "AvailabilityZones": [ + "us-east-1a", + "us-east-1b" + ], + "Scheme": "internet-facing", + "SourceSecurityGroup": { + "OwnerAlias": "12345789012", + "GroupName": "Web LB" + } + } + ] +} diff --git a/demo/us-east-1/describe-network-interfaces.json b/demo/us-east-1/describe-network-interfaces.json new file mode 100644 index 000000000..34a8f88f4 --- /dev/null +++ b/demo/us-east-1/describe-network-interfaces.json @@ -0,0 +1,3 @@ +{ + "NetworkInterfaces": [] +} diff --git a/demo/us-east-1/describe-security-groups.json b/demo/us-east-1/describe-security-groups.json new file mode 100644 index 000000000..2d964ca52 --- /dev/null +++ b/demo/us-east-1/describe-security-groups.json @@ -0,0 +1,187 @@ +{ + "SecurityGroups": [ + { + "IpPermissionsEgress": [ + { + "IpProtocol": "-1", + "PrefixListIds": [], + "IpRanges": [ + { + "CidrIp": "0.0.0.0/0" + } + ], + "UserIdGroupPairs": [], + "Ipv6Ranges": [] + } + ], + "Description": "Database", + "IpPermissions": [ + { + "PrefixListIds": [], + "FromPort": 5432, + "IpRanges": [], + "ToPort": 5432, + "IpProtocol": "tcp", + "UserIdGroupPairs": [ + { + "UserId": "123456789012", + "GroupId": "sg-00000004" + } + ], + "Ipv6Ranges": [] + } + ], + "GroupName": "Database", + "VpcId": "vpc-12345678", + "OwnerId": "123456789012", + "GroupId": "sg-00000005" + }, + { + "IpPermissionsEgress": [ + { + "IpProtocol": "-1", + "PrefixListIds": [], + "IpRanges": [ + { + "CidrIp": "0.0.0.0/0" + } + ], + "UserIdGroupPairs": [], + "Ipv6Ranges": [] + } + ], + "Description": "Internal web", + "IpPermissions": [ + { + "PrefixListIds": [], + "FromPort": 8000, + "IpRanges": [], + "ToPort": 8000, + "IpProtocol": "tcp", + "UserIdGroupPairs": [ + { + "UserId": "123456789012", + "GroupId": "sg-00000003" + }, + { + "UserId": "123456789012", + "GroupId": "sg-00000002" + } + ], + "Ipv6Ranges": [] + } + ], + "GroupName": "Internal web", + "VpcId": "vpc-12345678", + "OwnerId": "123456789012", + "GroupId": "sg-00000004" + }, + { + "IpPermissionsEgress": [ + { + "IpProtocol": "-1", + "PrefixListIds": [], + "IpRanges": [ + { + "CidrIp": "0.0.0.0/0" + } + ], + "UserIdGroupPairs": [], + "Ipv6Ranges": [] + } + ], + "Description": "Public web access", + "IpPermissions": [ + { + "PrefixListIds": [], + "FromPort": 443, + "IpRanges": [ + { + "CidrIp": "0.0.0.0/0" + } + ], + "ToPort": 443, + "IpProtocol": "tcp", + "UserIdGroupPairs": [], + "Ipv6Ranges": [] + } + ], + "GroupName": "Public web", + "VpcId": "vpc-12345678", + "OwnerId": "123456789012", + "GroupId": "sg-00000003" + }, + { + "IpPermissionsEgress": [ + { + "IpProtocol": "-1", + "PrefixListIds": [], + "IpRanges": [ + { + "CidrIp": "0.0.0.0/0" + } + ], + "UserIdGroupPairs": [], + "Ipv6Ranges": [] + } + ], + "Description": "Only allow SSH from the offices", + "IpPermissions": [ + { + "PrefixListIds": [], + "FromPort": 22, + "IpRanges": [ + { + "CidrIp": "1.1.1.1/32" + }, + { + "CidrIp": "2.2.2.2/28" + } + ], + "ToPort": 22, + "IpProtocol": "tcp", + "UserIdGroupPairs": [], + "Ipv6Ranges": [] + } + ], + "GroupName": "Bastion", + "VpcId": "vpc-12345678", + "OwnerId": "123456789012", + "GroupId": "sg-00000002" + }, + { + "IpPermissionsEgress": [ + { + "IpProtocol": "-1", + "PrefixListIds": [], + "IpRanges": [ + { + "CidrIp": "0.0.0.0/0" + } + ], + "UserIdGroupPairs": [], + "Ipv6Ranges": [] + } + ], + "Description": "default VPC security group", + "IpPermissions": [ + { + "IpProtocol": "-1", + "PrefixListIds": [], + "IpRanges": [], + "UserIdGroupPairs": [ + { + "UserId": "123456789012", + "GroupId": "sg-00000001" + } + ], + "Ipv6Ranges": [] + } + ], + "GroupName": "default", + "VpcId": "vpc-12345678", + "OwnerId": "123456789012", + "GroupId": "sg-00000001" + } + ] +} diff --git a/demo/us-east-1/describe-subnets.json b/demo/us-east-1/describe-subnets.json new file mode 100644 index 000000000..40c8122d1 --- /dev/null +++ b/demo/us-east-1/describe-subnets.json @@ -0,0 +1,76 @@ +{ + "Subnets": [ + { + "AvailabilityZone": "us-east-1a", + "Tags": [ + { + "Value": "Public 1a", + "Key": "Name" + } + ], + "AvailableIpAddressCount": 4091, + "DefaultForAz": true, + "Ipv6CidrBlockAssociationSet": [], + "VpcId": "vpc-12345678", + "State": "available", + "MapPublicIpOnLaunch": true, + "SubnetId": "subnet-00000001", + "CidrBlock": "10.0.0.0/24", + "AssignIpv6AddressOnCreation": false + }, + { + "AvailabilityZone": "us-east-1b", + "Tags": [ + { + "Value": "Public 1b", + "Key": "Name" + } + ], + "AvailableIpAddressCount": 4091, + "DefaultForAz": true, + "Ipv6CidrBlockAssociationSet": [], + "VpcId": "vpc-12345678", + "State": "available", + "MapPublicIpOnLaunch": true, + "SubnetId": "subnet-00000002", + "CidrBlock": "10.0.1.0/24", + "AssignIpv6AddressOnCreation": false + }, + { + "AvailabilityZone": "us-east-1a", + "Tags": [ + { + "Value": "Private 1a", + "Key": "Name" + } + ], + "AvailableIpAddressCount": 4091, + "DefaultForAz": true, + "Ipv6CidrBlockAssociationSet": [], + "VpcId": "vpc-12345678", + "State": "available", + "MapPublicIpOnLaunch": false, + "SubnetId": "subnet-00000003", + "CidrBlock": "10.0.2.0/24", + "AssignIpv6AddressOnCreation": false + }, + { + "AvailabilityZone": "us-east-1b", + "Tags": [ + { + "Value": "Private 1b", + "Key": "Name" + } + ], + "AvailableIpAddressCount": 4091, + "DefaultForAz": true, + "Ipv6CidrBlockAssociationSet": [], + "VpcId": "vpc-12345678", + "State": "available", + "MapPublicIpOnLaunch": false, + "SubnetId": "subnet-00000004", + "CidrBlock": "10.0.3.0/24", + "AssignIpv6AddressOnCreation": false + } + ] +} diff --git a/demo/us-east-1/describe-vpc-peering-connections.json b/demo/us-east-1/describe-vpc-peering-connections.json new file mode 100644 index 000000000..19d619ca9 --- /dev/null +++ b/demo/us-east-1/describe-vpc-peering-connections.json @@ -0,0 +1,3 @@ +{ + "VpcPeeringConnections": [] +} diff --git a/demo/us-east-1/describe-vpcs.json b/demo/us-east-1/describe-vpcs.json new file mode 100644 index 000000000..0e01cdc49 --- /dev/null +++ b/demo/us-east-1/describe-vpcs.json @@ -0,0 +1,27 @@ +{ + "Vpcs": [ + { + "VpcId": "vpc-12345678", + "Tags": [ + { + "Value": "Prod", + "Key": "Name" + } + ], + "InstanceTenancy": "default", + "CidrBlockAssociationSet": [ + { + "AssociationId": "vpc-cidr-assoc-12345678", + "CidrBlock": "10.0.0.0/16", + "CidrBlockState": { + "State": "associated" + } + } + ], + "State": "available", + "DhcpOptionsId": "dopt-12345678", + "CidrBlock": "10.0.0.0/16", + "IsDefault": true + } + ] +} diff --git a/demo/us-east-2/describe-availability-zones.json b/demo/us-east-2/describe-availability-zones.json new file mode 100644 index 000000000..45fe1bf21 --- /dev/null +++ b/demo/us-east-2/describe-availability-zones.json @@ -0,0 +1,22 @@ +{ + "AvailabilityZones": [ + { + "State": "available", + "ZoneName": "us-east-2a", + "Messages": [], + "RegionName": "us-east-2" + }, + { + "State": "available", + "ZoneName": "us-east-2b", + "Messages": [], + "RegionName": "us-east-2" + }, + { + "State": "available", + "ZoneName": "us-east-2c", + "Messages": [], + "RegionName": "us-east-2" + } + ] +} diff --git a/demo/us-east-2/describe-db-instances.json b/demo/us-east-2/describe-db-instances.json new file mode 100644 index 000000000..8f850cfde --- /dev/null +++ b/demo/us-east-2/describe-db-instances.json @@ -0,0 +1,3 @@ +{ + "DBInstances": [] +} diff --git a/demo/us-east-2/describe-instances.json b/demo/us-east-2/describe-instances.json new file mode 100644 index 000000000..2cb4c9491 --- /dev/null +++ b/demo/us-east-2/describe-instances.json @@ -0,0 +1,3 @@ +{ + "Reservations": [] +} diff --git a/demo/us-east-2/describe-load-balancers.json b/demo/us-east-2/describe-load-balancers.json new file mode 100644 index 000000000..1849201d0 --- /dev/null +++ b/demo/us-east-2/describe-load-balancers.json @@ -0,0 +1,3 @@ +{ + "LoadBalancerDescriptions": [] +} diff --git a/demo/us-east-2/describe-network-interfaces.json b/demo/us-east-2/describe-network-interfaces.json new file mode 100644 index 000000000..34a8f88f4 --- /dev/null +++ b/demo/us-east-2/describe-network-interfaces.json @@ -0,0 +1,3 @@ +{ + "NetworkInterfaces": [] +} diff --git a/demo/us-east-2/describe-security-groups.json b/demo/us-east-2/describe-security-groups.json new file mode 100644 index 000000000..94e386d14 --- /dev/null +++ b/demo/us-east-2/describe-security-groups.json @@ -0,0 +1,38 @@ +{ + "SecurityGroups": [ + { + "IpPermissionsEgress": [ + { + "IpProtocol": "-1", + "PrefixListIds": [], + "IpRanges": [ + { + "CidrIp": "0.0.0.0/0" + } + ], + "UserIdGroupPairs": [], + "Ipv6Ranges": [] + } + ], + "Description": "default VPC security group", + "IpPermissions": [ + { + "IpProtocol": "-1", + "PrefixListIds": [], + "IpRanges": [], + "UserIdGroupPairs": [ + { + "UserId": "123456789012", + "GroupId": "sg-00000001" + } + ], + "Ipv6Ranges": [] + } + ], + "GroupName": "default", + "VpcId": "vpc-12345678", + "OwnerId": "123456789012", + "GroupId": "sg-00000001" + } + ] +} diff --git a/demo/us-east-2/describe-subnets.json b/demo/us-east-2/describe-subnets.json new file mode 100644 index 000000000..9b6242d5c --- /dev/null +++ b/demo/us-east-2/describe-subnets.json @@ -0,0 +1,28 @@ +{ + "Subnets": [ + { + "AvailabilityZone": "us-east-2a", + "AvailableIpAddressCount": 4091, + "DefaultForAz": true, + "Ipv6CidrBlockAssociationSet": [], + "VpcId": "vpc-12345678", + "State": "available", + "MapPublicIpOnLaunch": true, + "SubnetId": "subnet-00000001", + "CidrBlock": "172.31.0.0/20", + "AssignIpv6AddressOnCreation": false + }, + { + "AvailabilityZone": "us-east-2b", + "AvailableIpAddressCount": 4091, + "DefaultForAz": true, + "Ipv6CidrBlockAssociationSet": [], + "VpcId": "vpc-12345678", + "State": "available", + "MapPublicIpOnLaunch": true, + "SubnetId": "subnet-00000002", + "CidrBlock": "172.31.16.0/20", + "AssignIpv6AddressOnCreation": false + } + ] +} diff --git a/demo/us-east-2/describe-vpc-peering-connections.json b/demo/us-east-2/describe-vpc-peering-connections.json new file mode 100644 index 000000000..19d619ca9 --- /dev/null +++ b/demo/us-east-2/describe-vpc-peering-connections.json @@ -0,0 +1,3 @@ +{ + "VpcPeeringConnections": [] +} diff --git a/demo/us-east-2/describe-vpcs.json b/demo/us-east-2/describe-vpcs.json new file mode 100644 index 000000000..91059b8c2 --- /dev/null +++ b/demo/us-east-2/describe-vpcs.json @@ -0,0 +1,21 @@ +{ + "Vpcs": [ + { + "VpcId": "vpc-12345678", + "InstanceTenancy": "default", + "CidrBlockAssociationSet": [ + { + "AssociationId": "vpc-cidr-assoc-12345678", + "CidrBlock": "172.31.0.0/16", + "CidrBlockState": { + "State": "associated" + } + } + ], + "State": "available", + "DhcpOptionsId": "dopt-12345678", + "CidrBlock": "172.31.0.0/16", + "IsDefault": true + } + ] +} diff --git a/demo/us-west-1/describe-availability-zones.json b/demo/us-west-1/describe-availability-zones.json new file mode 100644 index 000000000..125c105a7 --- /dev/null +++ b/demo/us-west-1/describe-availability-zones.json @@ -0,0 +1,16 @@ +{ + "AvailabilityZones": [ + { + "State": "available", + "ZoneName": "us-west-1a", + "Messages": [], + "RegionName": "us-west-1" + }, + { + "State": "available", + "ZoneName": "us-west-1b", + "Messages": [], + "RegionName": "us-west-1" + } + ] +} diff --git a/demo/us-west-1/describe-db-instances.json b/demo/us-west-1/describe-db-instances.json new file mode 100644 index 000000000..8f850cfde --- /dev/null +++ b/demo/us-west-1/describe-db-instances.json @@ -0,0 +1,3 @@ +{ + "DBInstances": [] +} diff --git a/demo/us-west-1/describe-instances.json b/demo/us-west-1/describe-instances.json new file mode 100644 index 000000000..2cb4c9491 --- /dev/null +++ b/demo/us-west-1/describe-instances.json @@ -0,0 +1,3 @@ +{ + "Reservations": [] +} diff --git a/demo/us-west-1/describe-load-balancers.json b/demo/us-west-1/describe-load-balancers.json new file mode 100644 index 000000000..1849201d0 --- /dev/null +++ b/demo/us-west-1/describe-load-balancers.json @@ -0,0 +1,3 @@ +{ + "LoadBalancerDescriptions": [] +} diff --git a/demo/us-west-1/describe-network-interfaces.json b/demo/us-west-1/describe-network-interfaces.json new file mode 100644 index 000000000..34a8f88f4 --- /dev/null +++ b/demo/us-west-1/describe-network-interfaces.json @@ -0,0 +1,3 @@ +{ + "NetworkInterfaces": [] +} diff --git a/demo/us-west-1/describe-security-groups.json b/demo/us-west-1/describe-security-groups.json new file mode 100644 index 000000000..94e386d14 --- /dev/null +++ b/demo/us-west-1/describe-security-groups.json @@ -0,0 +1,38 @@ +{ + "SecurityGroups": [ + { + "IpPermissionsEgress": [ + { + "IpProtocol": "-1", + "PrefixListIds": [], + "IpRanges": [ + { + "CidrIp": "0.0.0.0/0" + } + ], + "UserIdGroupPairs": [], + "Ipv6Ranges": [] + } + ], + "Description": "default VPC security group", + "IpPermissions": [ + { + "IpProtocol": "-1", + "PrefixListIds": [], + "IpRanges": [], + "UserIdGroupPairs": [ + { + "UserId": "123456789012", + "GroupId": "sg-00000001" + } + ], + "Ipv6Ranges": [] + } + ], + "GroupName": "default", + "VpcId": "vpc-12345678", + "OwnerId": "123456789012", + "GroupId": "sg-00000001" + } + ] +} diff --git a/demo/us-west-1/describe-subnets.json b/demo/us-west-1/describe-subnets.json new file mode 100644 index 000000000..e33c17b1d --- /dev/null +++ b/demo/us-west-1/describe-subnets.json @@ -0,0 +1,28 @@ +{ + "Subnets": [ + { + "AvailabilityZone": "us-west-1a", + "AvailableIpAddressCount": 4091, + "DefaultForAz": true, + "Ipv6CidrBlockAssociationSet": [], + "VpcId": "vpc-12345678", + "State": "available", + "MapPublicIpOnLaunch": true, + "SubnetId": "subnet-00000001", + "CidrBlock": "172.31.0.0/20", + "AssignIpv6AddressOnCreation": false + }, + { + "AvailabilityZone": "us-west-1b", + "AvailableIpAddressCount": 4091, + "DefaultForAz": true, + "Ipv6CidrBlockAssociationSet": [], + "VpcId": "vpc-12345678", + "State": "available", + "MapPublicIpOnLaunch": true, + "SubnetId": "subnet-00000002", + "CidrBlock": "172.31.16.0/20", + "AssignIpv6AddressOnCreation": false + } + ] +} diff --git a/demo/us-west-1/describe-vpc-peering-connections.json b/demo/us-west-1/describe-vpc-peering-connections.json new file mode 100644 index 000000000..19d619ca9 --- /dev/null +++ b/demo/us-west-1/describe-vpc-peering-connections.json @@ -0,0 +1,3 @@ +{ + "VpcPeeringConnections": [] +} diff --git a/demo/us-west-1/describe-vpcs.json b/demo/us-west-1/describe-vpcs.json new file mode 100644 index 000000000..91059b8c2 --- /dev/null +++ b/demo/us-west-1/describe-vpcs.json @@ -0,0 +1,21 @@ +{ + "Vpcs": [ + { + "VpcId": "vpc-12345678", + "InstanceTenancy": "default", + "CidrBlockAssociationSet": [ + { + "AssociationId": "vpc-cidr-assoc-12345678", + "CidrBlock": "172.31.0.0/16", + "CidrBlockState": { + "State": "associated" + } + } + ], + "State": "available", + "DhcpOptionsId": "dopt-12345678", + "CidrBlock": "172.31.0.0/16", + "IsDefault": true + } + ] +} diff --git a/demo/us-west-2/describe-availability-zones.json b/demo/us-west-2/describe-availability-zones.json new file mode 100644 index 000000000..1f73cbc49 --- /dev/null +++ b/demo/us-west-2/describe-availability-zones.json @@ -0,0 +1,22 @@ +{ + "AvailabilityZones": [ + { + "State": "available", + "ZoneName": "us-west-2a", + "Messages": [], + "RegionName": "us-west-2" + }, + { + "State": "available", + "ZoneName": "us-west-2b", + "Messages": [], + "RegionName": "us-west-2" + }, + { + "State": "available", + "ZoneName": "us-west-2c", + "Messages": [], + "RegionName": "us-west-2" + } + ] +} diff --git a/demo/us-west-2/describe-db-instances.json b/demo/us-west-2/describe-db-instances.json new file mode 100644 index 000000000..8f850cfde --- /dev/null +++ b/demo/us-west-2/describe-db-instances.json @@ -0,0 +1,3 @@ +{ + "DBInstances": [] +} diff --git a/demo/us-west-2/describe-instances.json b/demo/us-west-2/describe-instances.json new file mode 100644 index 000000000..2cb4c9491 --- /dev/null +++ b/demo/us-west-2/describe-instances.json @@ -0,0 +1,3 @@ +{ + "Reservations": [] +} diff --git a/demo/us-west-2/describe-load-balancers.json b/demo/us-west-2/describe-load-balancers.json new file mode 100644 index 000000000..1849201d0 --- /dev/null +++ b/demo/us-west-2/describe-load-balancers.json @@ -0,0 +1,3 @@ +{ + "LoadBalancerDescriptions": [] +} diff --git a/demo/us-west-2/describe-network-interfaces.json b/demo/us-west-2/describe-network-interfaces.json new file mode 100644 index 000000000..34a8f88f4 --- /dev/null +++ b/demo/us-west-2/describe-network-interfaces.json @@ -0,0 +1,3 @@ +{ + "NetworkInterfaces": [] +} diff --git a/demo/us-west-2/describe-security-groups.json b/demo/us-west-2/describe-security-groups.json new file mode 100644 index 000000000..94e386d14 --- /dev/null +++ b/demo/us-west-2/describe-security-groups.json @@ -0,0 +1,38 @@ +{ + "SecurityGroups": [ + { + "IpPermissionsEgress": [ + { + "IpProtocol": "-1", + "PrefixListIds": [], + "IpRanges": [ + { + "CidrIp": "0.0.0.0/0" + } + ], + "UserIdGroupPairs": [], + "Ipv6Ranges": [] + } + ], + "Description": "default VPC security group", + "IpPermissions": [ + { + "IpProtocol": "-1", + "PrefixListIds": [], + "IpRanges": [], + "UserIdGroupPairs": [ + { + "UserId": "123456789012", + "GroupId": "sg-00000001" + } + ], + "Ipv6Ranges": [] + } + ], + "GroupName": "default", + "VpcId": "vpc-12345678", + "OwnerId": "123456789012", + "GroupId": "sg-00000001" + } + ] +} diff --git a/demo/us-west-2/describe-subnets.json b/demo/us-west-2/describe-subnets.json new file mode 100644 index 000000000..68082df67 --- /dev/null +++ b/demo/us-west-2/describe-subnets.json @@ -0,0 +1,28 @@ +{ + "Subnets": [ + { + "AvailabilityZone": "us-west-2a", + "AvailableIpAddressCount": 4091, + "DefaultForAz": true, + "Ipv6CidrBlockAssociationSet": [], + "VpcId": "vpc-12345678", + "State": "available", + "MapPublicIpOnLaunch": true, + "SubnetId": "subnet-00000001", + "CidrBlock": "172.31.0.0/20", + "AssignIpv6AddressOnCreation": false + }, + { + "AvailabilityZone": "us-west-2b", + "AvailableIpAddressCount": 4091, + "DefaultForAz": true, + "Ipv6CidrBlockAssociationSet": [], + "VpcId": "vpc-12345678", + "State": "available", + "MapPublicIpOnLaunch": true, + "SubnetId": "subnet-00000002", + "CidrBlock": "172.31.16.0/20", + "AssignIpv6AddressOnCreation": false + } + ] +} diff --git a/demo/us-west-2/describe-vpc-peering-connections.json b/demo/us-west-2/describe-vpc-peering-connections.json new file mode 100644 index 000000000..19d619ca9 --- /dev/null +++ b/demo/us-west-2/describe-vpc-peering-connections.json @@ -0,0 +1,3 @@ +{ + "VpcPeeringConnections": [] +} diff --git a/demo/us-west-2/describe-vpcs.json b/demo/us-west-2/describe-vpcs.json new file mode 100644 index 000000000..91059b8c2 --- /dev/null +++ b/demo/us-west-2/describe-vpcs.json @@ -0,0 +1,21 @@ +{ + "Vpcs": [ + { + "VpcId": "vpc-12345678", + "InstanceTenancy": "default", + "CidrBlockAssociationSet": [ + { + "AssociationId": "vpc-cidr-assoc-12345678", + "CidrBlock": "172.31.0.0/16", + "CidrBlockState": { + "State": "associated" + } + } + ], + "State": "available", + "DhcpOptionsId": "dopt-12345678", + "CidrBlock": "172.31.0.0/16", + "IsDefault": true + } + ] +} diff --git a/docs/images/collapsed_node.png b/docs/images/collapsed_node.png new file mode 100644 index 000000000..ac6ba9625 Binary files /dev/null and b/docs/images/collapsed_node.png differ diff --git a/docs/images/command_icons.png b/docs/images/command_icons.png new file mode 100644 index 000000000..234ad345f Binary files /dev/null and b/docs/images/command_icons.png differ diff --git a/docs/images/deleted_node.png b/docs/images/deleted_node.png new file mode 100644 index 000000000..6706be195 Binary files /dev/null and b/docs/images/deleted_node.png differ diff --git a/docs/images/highlight_neighbors.png b/docs/images/highlight_neighbors.png new file mode 100644 index 000000000..e8fcfbeb0 Binary files /dev/null and b/docs/images/highlight_neighbors.png differ diff --git a/docs/images/ideal_layout.png b/docs/images/ideal_layout.png new file mode 100644 index 000000000..096b46321 Binary files /dev/null and b/docs/images/ideal_layout.png differ diff --git a/docs/images/initial_layout.png b/docs/images/initial_layout.png new file mode 100644 index 000000000..abccd8435 Binary files /dev/null and b/docs/images/initial_layout.png differ diff --git a/requirements-dev.txt b/requirements-dev.txt new file mode 100644 index 000000000..a2f6013cb --- /dev/null +++ b/requirements-dev.txt @@ -0,0 +1,8 @@ +pyjq==2.1.0 +netaddr==0.7.19 +autoflake==0.7 +autopep8==1.3.1 +nose==1.3.7 +coverage==4.4.2 +mock==2.0.0 +pylint==1.8.1 \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 000000000..0497658ae --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +pyjq==2.1.0 +netaddr==0.7.19 diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/scripts/pylint.sh b/tests/scripts/pylint.sh new file mode 100755 index 000000000..a9f1df89f --- /dev/null +++ b/tests/scripts/pylint.sh @@ -0,0 +1,3 @@ +#! /bin/bash +echo 'Starting pylint script' +find . -name '*.py' -not -path './docs/source/*' -not -path './venv/*' -exec pylint '{}' + diff --git a/tests/scripts/unit_tests.sh b/tests/scripts/unit_tests.sh new file mode 100755 index 000000000..d8d9b8c5b --- /dev/null +++ b/tests/scripts/unit_tests.sh @@ -0,0 +1,11 @@ +#! /bin/bash +if [ -f .coverage ]; then + rm .coverage +fi + +nosetests tests/unit \ +--with-coverage \ +--cover-package=cloudmapper \ +--cover-min-percentage=85 \ +--cover-html \ +--cover-html-dir=htmlcov \ No newline at end of file diff --git a/tests/unit/test_nodes.py b/tests/unit/test_nodes.py new file mode 100644 index 000000000..67814cec9 --- /dev/null +++ b/tests/unit/test_nodes.py @@ -0,0 +1,44 @@ +""" +Copyright 2018 Duo Security + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------- +""" + +import unittest +from nose.tools import assert_equal, assert_true, assert_false + +from cloudmapper.nodes import truncate, get_name, is_public_ip, Account + + +class TestNodes(unittest.TestCase): + """Test class for nodes""" + + def test_truncate(self): + assert_equal("hello", truncate("hello")) + assert_equal("0123456789012345678..", truncate("012345678901234567890123456789")) + + def test_is_public_ip(self): + assert_true(is_public_ip("1.1.1.1")) + assert_false(is_public_ip("10.0.0.0")) + + def test_Account(self): + json_blob = {u'id': 111111111111, u'name': u'prod'} + account = Account(None, json_blob) + assert_equal(111111111111, account.local_id) + assert_equal("prod", account.name) + assert_equal("account", account.node_type) + assert_equal("arn:aws:::111111111111:", account.arn) + assert_false(account.isLeaf) + assert_equal("prod", get_name(json_blob, "name")) + assert_false(account.has_leaves) + assert_equal([], account.leaves) + assert_equal({'data': {'node_data': {u'id': 111111111111, u'name': u'prod'}, 'local_id': 111111111111, 'type': 'account', 'id': 'arn:aws:::111111111111:', 'name': u'prod'}}, account.cytoscape_data()) diff --git a/tests/unit/test_prepare.py b/tests/unit/test_prepare.py new file mode 100644 index 000000000..23b66dd4d --- /dev/null +++ b/tests/unit/test_prepare.py @@ -0,0 +1,71 @@ +""" +Copyright 2018 Duo Security + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------- +""" + +import unittest +from mock import patch +from nose.tools import assert_equal, assert_true, assert_false +import pyjq + +from cloudmapper.prepare import is_external_cidr, get_regions, get_vpcs, build_data_structure +from cloudmapper.nodes import Account, Region + + +class TestPrepare(unittest.TestCase): + """Test class for prepare""" + + def test_is_external_cidr(self): + assert_true(is_external_cidr("1.1.1.1/32")) + assert_false(is_external_cidr("10.0.0.0/32")) + + @patch('cloudmapper.prepare.query_aws') + def test_get_regions(self, mock_query_aws): + # Just testing something without reading the file system + mock_query_aws.return_value = {"Regions": [{"Endpoint": "ec2.us-east-1.amazonaws.com", "RegionName": "us-east-1"}, {"Endpoint": "ec2.us-west-2.amazonaws.com", "RegionName": "us-west-2"}]} + assert_equal([{"Endpoint": "ec2.us-east-1.amazonaws.com", "RegionName": "us-east-1"}, {"Endpoint": "ec2.us-west-2.amazonaws.com", "RegionName": "us-west-2"}], get_regions("demo", {})) + + def test_get_vpcs(self): + # This actually uses the demo data files provided + json_blob = {u'id': 111111111111, u'name': u'demo'} + account = Account(None, json_blob) + region = Region(account, {"Endpoint": "ec2.us-east-1.amazonaws.com", "RegionName": "us-east-1"}) + assert_equal([{"VpcId": "vpc-12345678", "Tags": [{"Value": "Prod", "Key": "Name"}], "InstanceTenancy": "default", "CidrBlockAssociationSet": [{"AssociationId": "vpc-cidr-assoc-12345678", "CidrBlock": "10.0.0.0/16", "CidrBlockState": {"State": "associated"}}], "State": "available", "DhcpOptionsId": "dopt-12345678", "CidrBlock": "10.0.0.0/16", "IsDefault": True}], get_vpcs(region)) + + def test_build_data_structure(self): + # Build the entire demo data set + json_blob = {u'id': 111111111111, u'name': u'demo'} + + outputfilter = {} + outputfilter["internal_edges"] = True + outputfilter["read_replicas"] = True + outputfilter["inter_rds_edges"] = True + outputfilter["azs"] = False + outputfilter["collapse_by_tag"] = False + + config = {"accounts": [{"id": 123456789012, "name": "demo"}], "cidrs": {"1.1.1.1/32": {"name": "SF Office"}, "2.2.2.2/28": {"name": "NY Office"}}} + + cytoscape_json = build_data_structure(json_blob, config, outputfilter) + + # Now check it + # Check number of connections + assert_equal(14, len(pyjq.all('.[].data|select(.type == "edge")|keys', cytoscape_json))) + + # Check number of nodes + assert_equal(2, len(pyjq.all('.[].data|select(.type == "ip")|keys', cytoscape_json))) + assert_equal(2, len(pyjq.all('.[].data|select(.type == "rds")|keys', cytoscape_json))) + assert_equal(3, len(pyjq.all('.[].data|select(.type == "ec2")|keys', cytoscape_json))) + assert_equal(2, len(pyjq.all('.[].data|select(.type == "elb")|keys', cytoscape_json))) + assert_equal(4, len(pyjq.all('.[].data|select(.type == "subnet")|keys', cytoscape_json))) + assert_equal(1, len(pyjq.all('.[].data|select(.type == "region")|keys', cytoscape_json))) + assert_equal(1, len(pyjq.all('.[].data|select(.type == "vpc")|keys', cytoscape_json))) diff --git a/web/css/akkordion.css b/web/css/akkordion.css new file mode 100644 index 000000000..b77c41d5d --- /dev/null +++ b/web/css/akkordion.css @@ -0,0 +1,56 @@ +/*! + * akkordion 0.2.5 + * Accordion UI Element + * https://github.com/TrySound/akkordion + * + * Released under the MIT license + * Copyright (c) 2015, Bogdan Chadkin + */ + +.akkordion-title { + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.akkordion-outer { + overflow: hidden; + height: 0; + transition: height cubic-bezier(0.165, 0.84, 0.44, 1); + will-change: height; +} + +.akkordion-content { + box-sizing: border-box; + overflow: hidden; + height: 0; + transition: opacity 500ms cubic-bezier(0.165, 0.84, 0.44, 1), -webkit-transform 500ms cubic-bezier(0.165, 0.84, 0.44, 1); + transition: opacity 500ms cubic-bezier(0.165, 0.84, 0.44, 1), transform 500ms cubic-bezier(0.165, 0.84, 0.44, 1); + will-change: opacity, transform; +} + +.akkordion-active { + height: auto; +} + +.akkordion-fade .akkordion-content { + opacity: 0; +} + +.akkordion-shiftY .akkordion-content { + -webkit-transform: translateY(30px); + transform: translateY(30px); +} + +.akkordion-shiftX .akkordion-content { + -webkit-transform: translateX(100px); + transform: translateX(100px); +} + +.akkordion-content[data-akkordion-active] { + opacity: 1; + -webkit-transform: none; + transform: none; +} diff --git a/web/css/cloudmap.css b/web/css/cloudmap.css new file mode 100644 index 000000000..605fa7e9c --- /dev/null +++ b/web/css/cloudmap.css @@ -0,0 +1,225 @@ +body { + background-color: #f0f0f0; +} + +html, body {margin: 0; height: 100%; overflow: hidden} + +#menu { + color: #666; + padding-top: 5px; +} + +#cy { + width: 100%; + height: 100%; + position: absolute; + top: 30px; + left: 0px; + background-color: #fff; + opacity: 100%; +} + + +#nodeInfo { + position:absolute; + z-index: 9999; + top: 0; + + right: 0; + left: 0; + overflow: hidden; + font-family:monospace,monospace; + font-size:0.75em; + color: #555; + padding: 0; + margin: 0; + height: auto; + + padding-left: 12px; + margin-left: 60%; +} + +#nodeLocation { + text-align: right; + padding-right: 5px; + padding-left: 2px; + padding-top: -1px; + border-radius: 2px; + font-size:0.9em; +} + +.nodeParentSeparater{ + color:#222; + font-weight: bold; +} + +.nodeParent { + /*background-color: #d0d0d0;*/ +} + +.nodeLink, .siblingLink, .neighborLink, .childLink { + cursor: pointer; + text-decoration: underline; + text-decoration-color: #555; +} + +#nodeDescriptionHolder { + right: 0; + float: right; + width: 100%; +} + +.akkordion-outer { + padding: 0; +} + +.nodeHeader { + background-color: #444; + color: #aaa; + padding: 2px; + border-radius: 2px 0px 0px 2px; + border: 1px solid #000; +} + +.nodeHeader::before { + font: normal normal normal 14px/1 FontAwesome; + padding-right: 4px; + content: "\f152"; +} + +.nodeHeader[data-akkordion-active='true'] { + border-radius: 2px 0px 0px 0px; +} + +.nodeHeader[data-akkordion-active='true']::before { + font: normal normal normal 14px/1 FontAwesome; + padding-right: 4px; + content: "\f150"; +} + +#nodeDescription { + background-color: #d0d0d0; + padding-right: 10px; + right: 0; + float: right; + border: 1px solid #555; + border-radius: 0px 0px 0px 2px; + box-shadow: 5px 5px 7px grey; + width: 100%; + height: 100%; + overflow-y: auto; + max-height: 600px; + margin-bottom: 10px; + padding: 2px; + + /* I can't get this div to not overflow as much as it wants */ + max-height: 600px; + height:auto !important; + height:600px; +} + +#nodeDescription .akkordion-title { + background-color: #444; + color: #aaa; + padding: 2px; + border-radius: 0px 0px 0px 0px; + border: 1px solid #000; +} + +#nodeDescription .akkordion-content { + padding-bottom: 5px; +} + + +#nodeNeighbors, #nodeSiblings, #nodeChildren { + background-color: #d0d0d0; + overflow-y: scroll; + max-height:200px; + padding-right: 5px; +} + +#nodeDetails { + height: auto; + max-height: 200px; + overflow: scroll; + + margin: 0px; + + background-color: #bbb; + color: #444; + font-size:1.2em; + + margin-top: 2px; + + word-break: normal !important; + word-wrap: normal !important; + white-space: pre !important; +} + + +.frame { + overflow-y: auto; + border: 1px solid black; + line-height: 1em; +} + +.frame::-webkit-scrollbar { + -webkit-appearance: none; +} + +.frame::-webkit-scrollbar:vertical { + width: 5px; +} + +.frame::-webkit-scrollbar:horizontal { + height: 5px; +} + +.frame::-webkit-scrollbar-thumb { + border-radius: 4px; + border: 0px solid white; /* should match background, can't be transparent */ + background-color: rgba(0, 0, 0, .3); +} + +#nodeDescription > div > div > div > ul { + margin: 0; + padding-left: 5px; + list-style-type: none; +} +#nodeDescription > div > div > div > ul > li { + text-indent: 0px; +} +#nodeDescription > div > div > div > ul > li:before { + content: "-"; + text-indent: -5px; +} + + +.tooltip { + cursor: pointer; + position: relative; + display: inline-block; +} + +.tooltip .tooltiptext { + visibility: hidden; + font-family:monospace,monospace; + background-color: #444; + color: #aaa; + text-align: center; + border-radius: 3px; + padding: 3px; + font-size:0.6em; + margin-top: 20px; + margin-left: -10px; + + /* Position the tooltip */ + position: absolute; + z-index: 1000000; +} + +.tooltip:hover .tooltiptext { + visibility: visible; +} + + diff --git a/web/css/cytoscape.js-navigator.css b/web/css/cytoscape.js-navigator.css new file mode 100644 index 000000000..c36d490e5 --- /dev/null +++ b/web/css/cytoscape.js-navigator.css @@ -0,0 +1,44 @@ +.cytoscape-navigator{ + position: fixed; + border: 1px solid #000; + background: #fff; + z-index: 99999; + width: 200px; + height: 200px; + bottom: 0; + right: 0; + overflow: hidden; +} + +.cytoscape-navigator > img{ + max-width: 100%; + max-height: 100%; +} + +.cytoscape-navigator > canvas{ + position: absolute; + top: 0; + left: 0; + z-index: 101; +} + +.cytoscape-navigatorView{ + position: absolute; + top: 0; + left: 0; + cursor: move; + background: #B7E1ED; + -moz-opacity: 0.50; + opacity: 0.50; + -ms-filter:"progid:DXImageTransform.Microsoft.Alpha"(Opacity=50); + z-index: 102; +} + +.cytoscape-navigatorOverlay{ + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 103; +} diff --git a/web/css/cytoscape.js-panzoom.css b/web/css/cytoscape.js-panzoom.css new file mode 100644 index 000000000..9b6bae14a --- /dev/null +++ b/web/css/cytoscape.js-panzoom.css @@ -0,0 +1,220 @@ +.cy-panzoom { + position: absolute; + font-size: 12px; + color: #fff; + font-family: arial, helvetica, sans-serif; + line-height: 1; + color: #666; + font-size: 11px; + z-index: 99999; + box-sizing: content-box; +} + +.cy-panzoom-zoom-button { + cursor: pointer; + padding: 3px; + text-align: center; + position: absolute; + border-radius: 3px; + width: 10px; + height: 10px; + left: 16px; + background: #fff; + border: 1px solid #999; + margin-left: -1px; + margin-top: -1px; + z-index: 1; + box-sizing: content-box; +} + +.cy-panzoom-zoom-button:active, +.cy-panzoom-slider-handle:active, +.cy-panzoom-slider-handle.active { + background: #ddd; + box-sizing: content-box; +} + +.cy-panzoom-pan-button { + position: absolute; + z-index: 1; + height: 16px; + width: 16px; + box-sizing: content-box; +} + +.cy-panzoom-reset { + top: 55px; + box-sizing: content-box; +} + +.cy-panzoom-zoom-in { + top: 80px; + box-sizing: content-box; +} + +.cy-panzoom-zoom-out { + top: 197px; + box-sizing: content-box; +} + +.cy-panzoom-pan-up { + top: 0; + left: 50%; + margin-left: -5px; + width: 0; + height: 0; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-bottom: 5px solid #666; + box-sizing: content-box; +} + +.cy-panzoom-pan-down { + bottom: 0; + left: 50%; + margin-left: -5px; + width: 0; + height: 0; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid #666; + box-sizing: content-box; +} + +.cy-panzoom-pan-left { + top: 50%; + left: 0; + margin-top: -5px; + width: 0; + height: 0; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-right: 5px solid #666; + box-sizing: content-box; +} + +.cy-panzoom-pan-right { + top: 50%; + right: 0; + margin-top: -5px; + width: 0; + height: 0; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid #666; + box-sizing: content-box; +} + +.cy-panzoom-pan-indicator { + position: absolute; + left: 0; + top: 0; + width: 8px; + height: 8px; + border-radius: 8px; + background: #000; + border-radius: 8px; + margin-left: -5px; + margin-top: -5px; + display: none; + z-index: 999; + opacity: 0.6; + box-sizing: content-box; +} + +.cy-panzoom-slider { + position: absolute; + top: 97px; + left: 17px; + height: 100px; + width: 15px; + box-sizing: content-box; +} + +.cy-panzoom-slider-background { + position: absolute; + top: 0; + width: 2px; + height: 100px; + left: 5px; + background: #fff; + border-left: 1px solid #999; + border-right: 1px solid #999; + box-sizing: content-box; +} + +.cy-panzoom-slider-handle { + position: absolute; + width: 16px; + height: 8px; + background: #fff; + border: 1px solid #999; + border-radius: 2px; + margin-left: -2px; + z-index: 999; + line-height: 8px; + cursor: default; + box-sizing: content-box; +} + +.cy-panzoom-slider-handle .icon { + margin: 0 4px; + line-height: 10px; + box-sizing: content-box; +} + +.cy-panzoom-no-zoom-tick { + position: absolute; + background: #666; + border: 1px solid #fff; + border-radius: 2px; + margin-left: -1px; + width: 8px; + height: 2px; + left: 3px; + z-index: 1; + margin-top: 3px; + box-sizing: content-box; +} + +.cy-panzoom-panner { + position: absolute; + left: 5px; + top: 5px; + height: 40px; + width: 40px; + background: #fff; + border: 1px solid #999; + border-radius: 40px; + margin-left: -1px; + box-sizing: content-box; +} + +.cy-panzoom-panner-handle { + position: absolute; + left: 0; + top: 0; + outline: none; + height: 40px; + width: 40px; + position: absolute; + z-index: 999; + box-sizing: content-box; +} + +.cy-panzoom-zoom-only .cy-panzoom-slider, +.cy-panzoom-zoom-only .cy-panzoom-panner { + display: none; +} + +.cy-panzoom-zoom-only .cy-panzoom-reset { + top: 20px; +} + +.cy-panzoom-zoom-only .cy-panzoom-zoom-in { + top: 45px; +} + +.cy-panzoom-zoom-only .cy-panzoom-zoom-out { + top: 70px; +} diff --git a/web/css/font-awesome-4.7.0/HELP-US-OUT.txt b/web/css/font-awesome-4.7.0/HELP-US-OUT.txt new file mode 100644 index 000000000..83d083dd7 --- /dev/null +++ b/web/css/font-awesome-4.7.0/HELP-US-OUT.txt @@ -0,0 +1,7 @@ +I hope you love Font Awesome. If you've found it useful, please do me a favor and check out my latest project, +Fort Awesome (https://fortawesome.com). It makes it easy to put the perfect icons on your website. Choose from our awesome, +comprehensive icon sets or copy and paste your own. + +Please. Check it out. + +-Dave Gandy diff --git a/web/css/font-awesome-4.7.0/css/font-awesome.css b/web/css/font-awesome-4.7.0/css/font-awesome.css new file mode 100644 index 000000000..ee906a819 --- /dev/null +++ b/web/css/font-awesome-4.7.0/css/font-awesome.css @@ -0,0 +1,2337 @@ +/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */ +/* FONT PATH + * -------------------------- */ +@font-face { + font-family: 'FontAwesome'; + src: url('../fonts/fontawesome-webfont.eot?v=4.7.0'); + src: url('../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff2?v=4.7.0') format('woff2'), url('../fonts/fontawesome-webfont.woff?v=4.7.0') format('woff'), url('../fonts/fontawesome-webfont.ttf?v=4.7.0') format('truetype'), url('../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular') format('svg'); + font-weight: normal; + font-style: normal; +} +.fa { + display: inline-block; + font: normal normal normal 14px/1 FontAwesome; + font-size: inherit; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +/* makes the font 33% larger relative to the icon container */ +.fa-lg { + font-size: 1.33333333em; + line-height: 0.75em; + vertical-align: -15%; +} +.fa-2x { + font-size: 2em; +} +.fa-3x { + font-size: 3em; +} +.fa-4x { + font-size: 4em; +} +.fa-5x { + font-size: 5em; +} +.fa-fw { + width: 1.28571429em; + text-align: center; +} +.fa-ul { + padding-left: 0; + margin-left: 2.14285714em; + list-style-type: none; +} +.fa-ul > li { + position: relative; +} +.fa-li { + position: absolute; + left: -2.14285714em; + width: 2.14285714em; + top: 0.14285714em; + text-align: center; +} +.fa-li.fa-lg { + left: -1.85714286em; +} +.fa-border { + padding: .2em .25em .15em; + border: solid 0.08em #eeeeee; + border-radius: .1em; +} +.fa-pull-left { + float: left; +} +.fa-pull-right { + float: right; +} +.fa.fa-pull-left { + margin-right: .3em; +} +.fa.fa-pull-right { + margin-left: .3em; +} +/* Deprecated as of 4.4.0 */ +.pull-right { + float: right; +} +.pull-left { + float: left; +} +.fa.pull-left { + margin-right: .3em; +} +.fa.pull-right { + margin-left: .3em; +} +.fa-spin { + -webkit-animation: fa-spin 2s infinite linear; + animation: fa-spin 2s infinite linear; +} +.fa-pulse { + -webkit-animation: fa-spin 1s infinite steps(8); + animation: fa-spin 1s infinite steps(8); +} +@-webkit-keyframes fa-spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} +@keyframes fa-spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} +.fa-rotate-90 { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=1)"; + -webkit-transform: rotate(90deg); + -ms-transform: rotate(90deg); + transform: rotate(90deg); +} +.fa-rotate-180 { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2)"; + -webkit-transform: rotate(180deg); + -ms-transform: rotate(180deg); + transform: rotate(180deg); +} +.fa-rotate-270 { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=3)"; + -webkit-transform: rotate(270deg); + -ms-transform: rotate(270deg); + transform: rotate(270deg); +} +.fa-flip-horizontal { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)"; + -webkit-transform: scale(-1, 1); + -ms-transform: scale(-1, 1); + transform: scale(-1, 1); +} +.fa-flip-vertical { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"; + -webkit-transform: scale(1, -1); + -ms-transform: scale(1, -1); + transform: scale(1, -1); +} +:root .fa-rotate-90, +:root .fa-rotate-180, +:root .fa-rotate-270, +:root .fa-flip-horizontal, +:root .fa-flip-vertical { + filter: none; +} +.fa-stack { + position: relative; + display: inline-block; + width: 2em; + height: 2em; + line-height: 2em; + vertical-align: middle; +} +.fa-stack-1x, +.fa-stack-2x { + position: absolute; + left: 0; + width: 100%; + text-align: center; +} +.fa-stack-1x { + line-height: inherit; +} +.fa-stack-2x { + font-size: 2em; +} +.fa-inverse { + color: #ffffff; +} +/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen + readers do not read off random characters that represent icons */ +.fa-glass:before { + content: "\f000"; +} +.fa-music:before { + content: "\f001"; +} +.fa-search:before { + content: "\f002"; +} +.fa-envelope-o:before { + content: "\f003"; +} +.fa-heart:before { + content: "\f004"; +} +.fa-star:before { + content: "\f005"; +} +.fa-star-o:before { + content: "\f006"; +} +.fa-user:before { + content: "\f007"; +} +.fa-film:before { + content: "\f008"; +} +.fa-th-large:before { + content: "\f009"; +} +.fa-th:before { + content: "\f00a"; +} +.fa-th-list:before { + content: "\f00b"; +} +.fa-check:before { + content: "\f00c"; +} +.fa-remove:before, +.fa-close:before, +.fa-times:before { + content: "\f00d"; +} +.fa-search-plus:before { + content: "\f00e"; +} +.fa-search-minus:before { + content: "\f010"; +} +.fa-power-off:before { + content: "\f011"; +} +.fa-signal:before { + content: "\f012"; +} +.fa-gear:before, +.fa-cog:before { + content: "\f013"; +} +.fa-trash-o:before { + content: "\f014"; +} +.fa-home:before { + content: "\f015"; +} +.fa-file-o:before { + content: "\f016"; +} +.fa-clock-o:before { + content: "\f017"; +} +.fa-road:before { + content: "\f018"; +} +.fa-download:before { + content: "\f019"; +} +.fa-arrow-circle-o-down:before { + content: "\f01a"; +} +.fa-arrow-circle-o-up:before { + content: "\f01b"; +} +.fa-inbox:before { + content: "\f01c"; +} +.fa-play-circle-o:before { + content: "\f01d"; +} +.fa-rotate-right:before, +.fa-repeat:before { + content: "\f01e"; +} +.fa-refresh:before { + content: "\f021"; +} +.fa-list-alt:before { + content: "\f022"; +} +.fa-lock:before { + content: "\f023"; +} +.fa-flag:before { + content: "\f024"; +} +.fa-headphones:before { + content: "\f025"; +} +.fa-volume-off:before { + content: "\f026"; +} +.fa-volume-down:before { + content: "\f027"; +} +.fa-volume-up:before { + content: "\f028"; +} +.fa-qrcode:before { + content: "\f029"; +} +.fa-barcode:before { + content: "\f02a"; +} +.fa-tag:before { + content: "\f02b"; +} +.fa-tags:before { + content: "\f02c"; +} +.fa-book:before { + content: "\f02d"; +} +.fa-bookmark:before { + content: "\f02e"; +} +.fa-print:before { + content: "\f02f"; +} +.fa-camera:before { + content: "\f030"; +} +.fa-font:before { + content: "\f031"; +} +.fa-bold:before { + content: "\f032"; +} +.fa-italic:before { + content: "\f033"; +} +.fa-text-height:before { + content: "\f034"; +} +.fa-text-width:before { + content: "\f035"; +} +.fa-align-left:before { + content: "\f036"; +} +.fa-align-center:before { + content: "\f037"; +} +.fa-align-right:before { + content: "\f038"; +} +.fa-align-justify:before { + content: "\f039"; +} +.fa-list:before { + content: "\f03a"; +} +.fa-dedent:before, +.fa-outdent:before { + content: "\f03b"; +} +.fa-indent:before { + content: "\f03c"; +} +.fa-video-camera:before { + content: "\f03d"; +} +.fa-photo:before, +.fa-image:before, +.fa-picture-o:before { + content: "\f03e"; +} +.fa-pencil:before { + content: "\f040"; +} +.fa-map-marker:before { + content: "\f041"; +} +.fa-adjust:before { + content: "\f042"; +} +.fa-tint:before { + content: "\f043"; +} +.fa-edit:before, +.fa-pencil-square-o:before { + content: "\f044"; +} +.fa-share-square-o:before { + content: "\f045"; +} +.fa-check-square-o:before { + content: "\f046"; +} +.fa-arrows:before { + content: "\f047"; +} +.fa-step-backward:before { + content: "\f048"; +} +.fa-fast-backward:before { + content: "\f049"; +} +.fa-backward:before { + content: "\f04a"; +} +.fa-play:before { + content: "\f04b"; +} +.fa-pause:before { + content: "\f04c"; +} +.fa-stop:before { + content: "\f04d"; +} +.fa-forward:before { + content: "\f04e"; +} +.fa-fast-forward:before { + content: "\f050"; +} +.fa-step-forward:before { + content: "\f051"; +} +.fa-eject:before { + content: "\f052"; +} +.fa-chevron-left:before { + content: "\f053"; +} +.fa-chevron-right:before { + content: "\f054"; +} +.fa-plus-circle:before { + content: "\f055"; +} +.fa-minus-circle:before { + content: "\f056"; +} +.fa-times-circle:before { + content: "\f057"; +} +.fa-check-circle:before { + content: "\f058"; +} +.fa-question-circle:before { + content: "\f059"; +} +.fa-info-circle:before { + content: "\f05a"; +} +.fa-crosshairs:before { + content: "\f05b"; +} +.fa-times-circle-o:before { + content: "\f05c"; +} +.fa-check-circle-o:before { + content: "\f05d"; +} +.fa-ban:before { + content: "\f05e"; +} +.fa-arrow-left:before { + content: "\f060"; +} +.fa-arrow-right:before { + content: "\f061"; +} +.fa-arrow-up:before { + content: "\f062"; +} +.fa-arrow-down:before { + content: "\f063"; +} +.fa-mail-forward:before, +.fa-share:before { + content: "\f064"; +} +.fa-expand:before { + content: "\f065"; +} +.fa-compress:before { + content: "\f066"; +} +.fa-plus:before { + content: "\f067"; +} +.fa-minus:before { + content: "\f068"; +} +.fa-asterisk:before { + content: "\f069"; +} +.fa-exclamation-circle:before { + content: "\f06a"; +} +.fa-gift:before { + content: "\f06b"; +} +.fa-leaf:before { + content: "\f06c"; +} +.fa-fire:before { + content: "\f06d"; +} +.fa-eye:before { + content: "\f06e"; +} +.fa-eye-slash:before { + content: "\f070"; +} +.fa-warning:before, +.fa-exclamation-triangle:before { + content: "\f071"; +} +.fa-plane:before { + content: "\f072"; +} +.fa-calendar:before { + content: "\f073"; +} +.fa-random:before { + content: "\f074"; +} +.fa-comment:before { + content: "\f075"; +} +.fa-magnet:before { + content: "\f076"; +} +.fa-chevron-up:before { + content: "\f077"; +} +.fa-chevron-down:before { + content: "\f078"; +} +.fa-retweet:before { + content: "\f079"; +} +.fa-shopping-cart:before { + content: "\f07a"; +} +.fa-folder:before { + content: "\f07b"; +} +.fa-folder-open:before { + content: "\f07c"; +} +.fa-arrows-v:before { + content: "\f07d"; +} +.fa-arrows-h:before { + content: "\f07e"; +} +.fa-bar-chart-o:before, +.fa-bar-chart:before { + content: "\f080"; +} +.fa-twitter-square:before { + content: "\f081"; +} +.fa-facebook-square:before { + content: "\f082"; +} +.fa-camera-retro:before { + content: "\f083"; +} +.fa-key:before { + content: "\f084"; +} +.fa-gears:before, +.fa-cogs:before { + content: "\f085"; +} +.fa-comments:before { + content: "\f086"; +} +.fa-thumbs-o-up:before { + content: "\f087"; +} +.fa-thumbs-o-down:before { + content: "\f088"; +} +.fa-star-half:before { + content: "\f089"; +} +.fa-heart-o:before { + content: "\f08a"; +} +.fa-sign-out:before { + content: "\f08b"; +} +.fa-linkedin-square:before { + content: "\f08c"; +} +.fa-thumb-tack:before { + content: "\f08d"; +} +.fa-external-link:before { + content: "\f08e"; +} +.fa-sign-in:before { + content: "\f090"; +} +.fa-trophy:before { + content: "\f091"; +} +.fa-github-square:before { + content: "\f092"; +} +.fa-upload:before { + content: "\f093"; +} +.fa-lemon-o:before { + content: "\f094"; +} +.fa-phone:before { + content: "\f095"; +} +.fa-square-o:before { + content: "\f096"; +} +.fa-bookmark-o:before { + content: "\f097"; +} +.fa-phone-square:before { + content: "\f098"; +} +.fa-twitter:before { + content: "\f099"; +} +.fa-facebook-f:before, +.fa-facebook:before { + content: "\f09a"; +} +.fa-github:before { + content: "\f09b"; +} +.fa-unlock:before { + content: "\f09c"; +} +.fa-credit-card:before { + content: "\f09d"; +} +.fa-feed:before, +.fa-rss:before { + content: "\f09e"; +} +.fa-hdd-o:before { + content: "\f0a0"; +} +.fa-bullhorn:before { + content: "\f0a1"; +} +.fa-bell:before { + content: "\f0f3"; +} +.fa-certificate:before { + content: "\f0a3"; +} +.fa-hand-o-right:before { + content: "\f0a4"; +} +.fa-hand-o-left:before { + content: "\f0a5"; +} +.fa-hand-o-up:before { + content: "\f0a6"; +} +.fa-hand-o-down:before { + content: "\f0a7"; +} +.fa-arrow-circle-left:before { + content: "\f0a8"; +} +.fa-arrow-circle-right:before { + content: "\f0a9"; +} +.fa-arrow-circle-up:before { + content: "\f0aa"; +} +.fa-arrow-circle-down:before { + content: "\f0ab"; +} +.fa-globe:before { + content: "\f0ac"; +} +.fa-wrench:before { + content: "\f0ad"; +} +.fa-tasks:before { + content: "\f0ae"; +} +.fa-filter:before { + content: "\f0b0"; +} +.fa-briefcase:before { + content: "\f0b1"; +} +.fa-arrows-alt:before { + content: "\f0b2"; +} +.fa-group:before, +.fa-users:before { + content: "\f0c0"; +} +.fa-chain:before, +.fa-link:before { + content: "\f0c1"; +} +.fa-cloud:before { + content: "\f0c2"; +} +.fa-flask:before { + content: "\f0c3"; +} +.fa-cut:before, +.fa-scissors:before { + content: "\f0c4"; +} +.fa-copy:before, +.fa-files-o:before { + content: "\f0c5"; +} +.fa-paperclip:before { + content: "\f0c6"; +} +.fa-save:before, +.fa-floppy-o:before { + content: "\f0c7"; +} +.fa-square:before { + content: "\f0c8"; +} +.fa-navicon:before, +.fa-reorder:before, +.fa-bars:before { + content: "\f0c9"; +} +.fa-list-ul:before { + content: "\f0ca"; +} +.fa-list-ol:before { + content: "\f0cb"; +} +.fa-strikethrough:before { + content: "\f0cc"; +} +.fa-underline:before { + content: "\f0cd"; +} +.fa-table:before { + content: "\f0ce"; +} +.fa-magic:before { + content: "\f0d0"; +} +.fa-truck:before { + content: "\f0d1"; +} +.fa-pinterest:before { + content: "\f0d2"; +} +.fa-pinterest-square:before { + content: "\f0d3"; +} +.fa-google-plus-square:before { + content: "\f0d4"; +} +.fa-google-plus:before { + content: "\f0d5"; +} +.fa-money:before { + content: "\f0d6"; +} +.fa-caret-down:before { + content: "\f0d7"; +} +.fa-caret-up:before { + content: "\f0d8"; +} +.fa-caret-left:before { + content: "\f0d9"; +} +.fa-caret-right:before { + content: "\f0da"; +} +.fa-columns:before { + content: "\f0db"; +} +.fa-unsorted:before, +.fa-sort:before { + content: "\f0dc"; +} +.fa-sort-down:before, +.fa-sort-desc:before { + content: "\f0dd"; +} +.fa-sort-up:before, +.fa-sort-asc:before { + content: "\f0de"; +} +.fa-envelope:before { + content: "\f0e0"; +} +.fa-linkedin:before { + content: "\f0e1"; +} +.fa-rotate-left:before, +.fa-undo:before { + content: "\f0e2"; +} +.fa-legal:before, +.fa-gavel:before { + content: "\f0e3"; +} +.fa-dashboard:before, +.fa-tachometer:before { + content: "\f0e4"; +} +.fa-comment-o:before { + content: "\f0e5"; +} +.fa-comments-o:before { + content: "\f0e6"; +} +.fa-flash:before, +.fa-bolt:before { + content: "\f0e7"; +} +.fa-sitemap:before { + content: "\f0e8"; +} +.fa-umbrella:before { + content: "\f0e9"; +} +.fa-paste:before, +.fa-clipboard:before { + content: "\f0ea"; +} +.fa-lightbulb-o:before { + content: "\f0eb"; +} +.fa-exchange:before { + content: "\f0ec"; +} +.fa-cloud-download:before { + content: "\f0ed"; +} +.fa-cloud-upload:before { + content: "\f0ee"; +} +.fa-user-md:before { + content: "\f0f0"; +} +.fa-stethoscope:before { + content: "\f0f1"; +} +.fa-suitcase:before { + content: "\f0f2"; +} +.fa-bell-o:before { + content: "\f0a2"; +} +.fa-coffee:before { + content: "\f0f4"; +} +.fa-cutlery:before { + content: "\f0f5"; +} +.fa-file-text-o:before { + content: "\f0f6"; +} +.fa-building-o:before { + content: "\f0f7"; +} +.fa-hospital-o:before { + content: "\f0f8"; +} +.fa-ambulance:before { + content: "\f0f9"; +} +.fa-medkit:before { + content: "\f0fa"; +} +.fa-fighter-jet:before { + content: "\f0fb"; +} +.fa-beer:before { + content: "\f0fc"; +} +.fa-h-square:before { + content: "\f0fd"; +} +.fa-plus-square:before { + content: "\f0fe"; +} +.fa-angle-double-left:before { + content: "\f100"; +} +.fa-angle-double-right:before { + content: "\f101"; +} +.fa-angle-double-up:before { + content: "\f102"; +} +.fa-angle-double-down:before { + content: "\f103"; +} +.fa-angle-left:before { + content: "\f104"; +} +.fa-angle-right:before { + content: "\f105"; +} +.fa-angle-up:before { + content: "\f106"; +} +.fa-angle-down:before { + content: "\f107"; +} +.fa-desktop:before { + content: "\f108"; +} +.fa-laptop:before { + content: "\f109"; +} +.fa-tablet:before { + content: "\f10a"; +} +.fa-mobile-phone:before, +.fa-mobile:before { + content: "\f10b"; +} +.fa-circle-o:before { + content: "\f10c"; +} +.fa-quote-left:before { + content: "\f10d"; +} +.fa-quote-right:before { + content: "\f10e"; +} +.fa-spinner:before { + content: "\f110"; +} +.fa-circle:before { + content: "\f111"; +} +.fa-mail-reply:before, +.fa-reply:before { + content: "\f112"; +} +.fa-github-alt:before { + content: "\f113"; +} +.fa-folder-o:before { + content: "\f114"; +} +.fa-folder-open-o:before { + content: "\f115"; +} +.fa-smile-o:before { + content: "\f118"; +} +.fa-frown-o:before { + content: "\f119"; +} +.fa-meh-o:before { + content: "\f11a"; +} +.fa-gamepad:before { + content: "\f11b"; +} +.fa-keyboard-o:before { + content: "\f11c"; +} +.fa-flag-o:before { + content: "\f11d"; +} +.fa-flag-checkered:before { + content: "\f11e"; +} +.fa-terminal:before { + content: "\f120"; +} +.fa-code:before { + content: "\f121"; +} +.fa-mail-reply-all:before, +.fa-reply-all:before { + content: "\f122"; +} +.fa-star-half-empty:before, +.fa-star-half-full:before, +.fa-star-half-o:before { + content: "\f123"; +} +.fa-location-arrow:before { + content: "\f124"; +} +.fa-crop:before { + content: "\f125"; +} +.fa-code-fork:before { + content: "\f126"; +} +.fa-unlink:before, +.fa-chain-broken:before { + content: "\f127"; +} +.fa-question:before { + content: "\f128"; +} +.fa-info:before { + content: "\f129"; +} +.fa-exclamation:before { + content: "\f12a"; +} +.fa-superscript:before { + content: "\f12b"; +} +.fa-subscript:before { + content: "\f12c"; +} +.fa-eraser:before { + content: "\f12d"; +} +.fa-puzzle-piece:before { + content: "\f12e"; +} +.fa-microphone:before { + content: "\f130"; +} +.fa-microphone-slash:before { + content: "\f131"; +} +.fa-shield:before { + content: "\f132"; +} +.fa-calendar-o:before { + content: "\f133"; +} +.fa-fire-extinguisher:before { + content: "\f134"; +} +.fa-rocket:before { + content: "\f135"; +} +.fa-maxcdn:before { + content: "\f136"; +} +.fa-chevron-circle-left:before { + content: "\f137"; +} +.fa-chevron-circle-right:before { + content: "\f138"; +} +.fa-chevron-circle-up:before { + content: "\f139"; +} +.fa-chevron-circle-down:before { + content: "\f13a"; +} +.fa-html5:before { + content: "\f13b"; +} +.fa-css3:before { + content: "\f13c"; +} +.fa-anchor:before { + content: "\f13d"; +} +.fa-unlock-alt:before { + content: "\f13e"; +} +.fa-bullseye:before { + content: "\f140"; +} +.fa-ellipsis-h:before { + content: "\f141"; +} +.fa-ellipsis-v:before { + content: "\f142"; +} +.fa-rss-square:before { + content: "\f143"; +} +.fa-play-circle:before { + content: "\f144"; +} +.fa-ticket:before { + content: "\f145"; +} +.fa-minus-square:before { + content: "\f146"; +} +.fa-minus-square-o:before { + content: "\f147"; +} +.fa-level-up:before { + content: "\f148"; +} +.fa-level-down:before { + content: "\f149"; +} +.fa-check-square:before { + content: "\f14a"; +} +.fa-pencil-square:before { + content: "\f14b"; +} +.fa-external-link-square:before { + content: "\f14c"; +} +.fa-share-square:before { + content: "\f14d"; +} +.fa-compass:before { + content: "\f14e"; +} +.fa-toggle-down:before, +.fa-caret-square-o-down:before { + content: "\f150"; +} +.fa-toggle-up:before, +.fa-caret-square-o-up:before { + content: "\f151"; +} +.fa-toggle-right:before, +.fa-caret-square-o-right:before { + content: "\f152"; +} +.fa-euro:before, +.fa-eur:before { + content: "\f153"; +} +.fa-gbp:before { + content: "\f154"; +} +.fa-dollar:before, +.fa-usd:before { + content: "\f155"; +} +.fa-rupee:before, +.fa-inr:before { + content: "\f156"; +} +.fa-cny:before, +.fa-rmb:before, +.fa-yen:before, +.fa-jpy:before { + content: "\f157"; +} +.fa-ruble:before, +.fa-rouble:before, +.fa-rub:before { + content: "\f158"; +} +.fa-won:before, +.fa-krw:before { + content: "\f159"; +} +.fa-bitcoin:before, +.fa-btc:before { + content: "\f15a"; +} +.fa-file:before { + content: "\f15b"; +} +.fa-file-text:before { + content: "\f15c"; +} +.fa-sort-alpha-asc:before { + content: "\f15d"; +} +.fa-sort-alpha-desc:before { + content: "\f15e"; +} +.fa-sort-amount-asc:before { + content: "\f160"; +} +.fa-sort-amount-desc:before { + content: "\f161"; +} +.fa-sort-numeric-asc:before { + content: "\f162"; +} +.fa-sort-numeric-desc:before { + content: "\f163"; +} +.fa-thumbs-up:before { + content: "\f164"; +} +.fa-thumbs-down:before { + content: "\f165"; +} +.fa-youtube-square:before { + content: "\f166"; +} +.fa-youtube:before { + content: "\f167"; +} +.fa-xing:before { + content: "\f168"; +} +.fa-xing-square:before { + content: "\f169"; +} +.fa-youtube-play:before { + content: "\f16a"; +} +.fa-dropbox:before { + content: "\f16b"; +} +.fa-stack-overflow:before { + content: "\f16c"; +} +.fa-instagram:before { + content: "\f16d"; +} +.fa-flickr:before { + content: "\f16e"; +} +.fa-adn:before { + content: "\f170"; +} +.fa-bitbucket:before { + content: "\f171"; +} +.fa-bitbucket-square:before { + content: "\f172"; +} +.fa-tumblr:before { + content: "\f173"; +} +.fa-tumblr-square:before { + content: "\f174"; +} +.fa-long-arrow-down:before { + content: "\f175"; +} +.fa-long-arrow-up:before { + content: "\f176"; +} +.fa-long-arrow-left:before { + content: "\f177"; +} +.fa-long-arrow-right:before { + content: "\f178"; +} +.fa-apple:before { + content: "\f179"; +} +.fa-windows:before { + content: "\f17a"; +} +.fa-android:before { + content: "\f17b"; +} +.fa-linux:before { + content: "\f17c"; +} +.fa-dribbble:before { + content: "\f17d"; +} +.fa-skype:before { + content: "\f17e"; +} +.fa-foursquare:before { + content: "\f180"; +} +.fa-trello:before { + content: "\f181"; +} +.fa-female:before { + content: "\f182"; +} +.fa-male:before { + content: "\f183"; +} +.fa-gittip:before, +.fa-gratipay:before { + content: "\f184"; +} +.fa-sun-o:before { + content: "\f185"; +} +.fa-moon-o:before { + content: "\f186"; +} +.fa-archive:before { + content: "\f187"; +} +.fa-bug:before { + content: "\f188"; +} +.fa-vk:before { + content: "\f189"; +} +.fa-weibo:before { + content: "\f18a"; +} +.fa-renren:before { + content: "\f18b"; +} +.fa-pagelines:before { + content: "\f18c"; +} +.fa-stack-exchange:before { + content: "\f18d"; +} +.fa-arrow-circle-o-right:before { + content: "\f18e"; +} +.fa-arrow-circle-o-left:before { + content: "\f190"; +} +.fa-toggle-left:before, +.fa-caret-square-o-left:before { + content: "\f191"; +} +.fa-dot-circle-o:before { + content: "\f192"; +} +.fa-wheelchair:before { + content: "\f193"; +} +.fa-vimeo-square:before { + content: "\f194"; +} +.fa-turkish-lira:before, +.fa-try:before { + content: "\f195"; +} +.fa-plus-square-o:before { + content: "\f196"; +} +.fa-space-shuttle:before { + content: "\f197"; +} +.fa-slack:before { + content: "\f198"; +} +.fa-envelope-square:before { + content: "\f199"; +} +.fa-wordpress:before { + content: "\f19a"; +} +.fa-openid:before { + content: "\f19b"; +} +.fa-institution:before, +.fa-bank:before, +.fa-university:before { + content: "\f19c"; +} +.fa-mortar-board:before, +.fa-graduation-cap:before { + content: "\f19d"; +} +.fa-yahoo:before { + content: "\f19e"; +} +.fa-google:before { + content: "\f1a0"; +} +.fa-reddit:before { + content: "\f1a1"; +} +.fa-reddit-square:before { + content: "\f1a2"; +} +.fa-stumbleupon-circle:before { + content: "\f1a3"; +} +.fa-stumbleupon:before { + content: "\f1a4"; +} +.fa-delicious:before { + content: "\f1a5"; +} +.fa-digg:before { + content: "\f1a6"; +} +.fa-pied-piper-pp:before { + content: "\f1a7"; +} +.fa-pied-piper-alt:before { + content: "\f1a8"; +} +.fa-drupal:before { + content: "\f1a9"; +} +.fa-joomla:before { + content: "\f1aa"; +} +.fa-language:before { + content: "\f1ab"; +} +.fa-fax:before { + content: "\f1ac"; +} +.fa-building:before { + content: "\f1ad"; +} +.fa-child:before { + content: "\f1ae"; +} +.fa-paw:before { + content: "\f1b0"; +} +.fa-spoon:before { + content: "\f1b1"; +} +.fa-cube:before { + content: "\f1b2"; +} +.fa-cubes:before { + content: "\f1b3"; +} +.fa-behance:before { + content: "\f1b4"; +} +.fa-behance-square:before { + content: "\f1b5"; +} +.fa-steam:before { + content: "\f1b6"; +} +.fa-steam-square:before { + content: "\f1b7"; +} +.fa-recycle:before { + content: "\f1b8"; +} +.fa-automobile:before, +.fa-car:before { + content: "\f1b9"; +} +.fa-cab:before, +.fa-taxi:before { + content: "\f1ba"; +} +.fa-tree:before { + content: "\f1bb"; +} +.fa-spotify:before { + content: "\f1bc"; +} +.fa-deviantart:before { + content: "\f1bd"; +} +.fa-soundcloud:before { + content: "\f1be"; +} +.fa-database:before { + content: "\f1c0"; +} +.fa-file-pdf-o:before { + content: "\f1c1"; +} +.fa-file-word-o:before { + content: "\f1c2"; +} +.fa-file-excel-o:before { + content: "\f1c3"; +} +.fa-file-powerpoint-o:before { + content: "\f1c4"; +} +.fa-file-photo-o:before, +.fa-file-picture-o:before, +.fa-file-image-o:before { + content: "\f1c5"; +} +.fa-file-zip-o:before, +.fa-file-archive-o:before { + content: "\f1c6"; +} +.fa-file-sound-o:before, +.fa-file-audio-o:before { + content: "\f1c7"; +} +.fa-file-movie-o:before, +.fa-file-video-o:before { + content: "\f1c8"; +} +.fa-file-code-o:before { + content: "\f1c9"; +} +.fa-vine:before { + content: "\f1ca"; +} +.fa-codepen:before { + content: "\f1cb"; +} +.fa-jsfiddle:before { + content: "\f1cc"; +} +.fa-life-bouy:before, +.fa-life-buoy:before, +.fa-life-saver:before, +.fa-support:before, +.fa-life-ring:before { + content: "\f1cd"; +} +.fa-circle-o-notch:before { + content: "\f1ce"; +} +.fa-ra:before, +.fa-resistance:before, +.fa-rebel:before { + content: "\f1d0"; +} +.fa-ge:before, +.fa-empire:before { + content: "\f1d1"; +} +.fa-git-square:before { + content: "\f1d2"; +} +.fa-git:before { + content: "\f1d3"; +} +.fa-y-combinator-square:before, +.fa-yc-square:before, +.fa-hacker-news:before { + content: "\f1d4"; +} +.fa-tencent-weibo:before { + content: "\f1d5"; +} +.fa-qq:before { + content: "\f1d6"; +} +.fa-wechat:before, +.fa-weixin:before { + content: "\f1d7"; +} +.fa-send:before, +.fa-paper-plane:before { + content: "\f1d8"; +} +.fa-send-o:before, +.fa-paper-plane-o:before { + content: "\f1d9"; +} +.fa-history:before { + content: "\f1da"; +} +.fa-circle-thin:before { + content: "\f1db"; +} +.fa-header:before { + content: "\f1dc"; +} +.fa-paragraph:before { + content: "\f1dd"; +} +.fa-sliders:before { + content: "\f1de"; +} +.fa-share-alt:before { + content: "\f1e0"; +} +.fa-share-alt-square:before { + content: "\f1e1"; +} +.fa-bomb:before { + content: "\f1e2"; +} +.fa-soccer-ball-o:before, +.fa-futbol-o:before { + content: "\f1e3"; +} +.fa-tty:before { + content: "\f1e4"; +} +.fa-binoculars:before { + content: "\f1e5"; +} +.fa-plug:before { + content: "\f1e6"; +} +.fa-slideshare:before { + content: "\f1e7"; +} +.fa-twitch:before { + content: "\f1e8"; +} +.fa-yelp:before { + content: "\f1e9"; +} +.fa-newspaper-o:before { + content: "\f1ea"; +} +.fa-wifi:before { + content: "\f1eb"; +} +.fa-calculator:before { + content: "\f1ec"; +} +.fa-paypal:before { + content: "\f1ed"; +} +.fa-google-wallet:before { + content: "\f1ee"; +} +.fa-cc-visa:before { + content: "\f1f0"; +} +.fa-cc-mastercard:before { + content: "\f1f1"; +} +.fa-cc-discover:before { + content: "\f1f2"; +} +.fa-cc-amex:before { + content: "\f1f3"; +} +.fa-cc-paypal:before { + content: "\f1f4"; +} +.fa-cc-stripe:before { + content: "\f1f5"; +} +.fa-bell-slash:before { + content: "\f1f6"; +} +.fa-bell-slash-o:before { + content: "\f1f7"; +} +.fa-trash:before { + content: "\f1f8"; +} +.fa-copyright:before { + content: "\f1f9"; +} +.fa-at:before { + content: "\f1fa"; +} +.fa-eyedropper:before { + content: "\f1fb"; +} +.fa-paint-brush:before { + content: "\f1fc"; +} +.fa-birthday-cake:before { + content: "\f1fd"; +} +.fa-area-chart:before { + content: "\f1fe"; +} +.fa-pie-chart:before { + content: "\f200"; +} +.fa-line-chart:before { + content: "\f201"; +} +.fa-lastfm:before { + content: "\f202"; +} +.fa-lastfm-square:before { + content: "\f203"; +} +.fa-toggle-off:before { + content: "\f204"; +} +.fa-toggle-on:before { + content: "\f205"; +} +.fa-bicycle:before { + content: "\f206"; +} +.fa-bus:before { + content: "\f207"; +} +.fa-ioxhost:before { + content: "\f208"; +} +.fa-angellist:before { + content: "\f209"; +} +.fa-cc:before { + content: "\f20a"; +} +.fa-shekel:before, +.fa-sheqel:before, +.fa-ils:before { + content: "\f20b"; +} +.fa-meanpath:before { + content: "\f20c"; +} +.fa-buysellads:before { + content: "\f20d"; +} +.fa-connectdevelop:before { + content: "\f20e"; +} +.fa-dashcube:before { + content: "\f210"; +} +.fa-forumbee:before { + content: "\f211"; +} +.fa-leanpub:before { + content: "\f212"; +} +.fa-sellsy:before { + content: "\f213"; +} +.fa-shirtsinbulk:before { + content: "\f214"; +} +.fa-simplybuilt:before { + content: "\f215"; +} +.fa-skyatlas:before { + content: "\f216"; +} +.fa-cart-plus:before { + content: "\f217"; +} +.fa-cart-arrow-down:before { + content: "\f218"; +} +.fa-diamond:before { + content: "\f219"; +} +.fa-ship:before { + content: "\f21a"; +} +.fa-user-secret:before { + content: "\f21b"; +} +.fa-motorcycle:before { + content: "\f21c"; +} +.fa-street-view:before { + content: "\f21d"; +} +.fa-heartbeat:before { + content: "\f21e"; +} +.fa-venus:before { + content: "\f221"; +} +.fa-mars:before { + content: "\f222"; +} +.fa-mercury:before { + content: "\f223"; +} +.fa-intersex:before, +.fa-transgender:before { + content: "\f224"; +} +.fa-transgender-alt:before { + content: "\f225"; +} +.fa-venus-double:before { + content: "\f226"; +} +.fa-mars-double:before { + content: "\f227"; +} +.fa-venus-mars:before { + content: "\f228"; +} +.fa-mars-stroke:before { + content: "\f229"; +} +.fa-mars-stroke-v:before { + content: "\f22a"; +} +.fa-mars-stroke-h:before { + content: "\f22b"; +} +.fa-neuter:before { + content: "\f22c"; +} +.fa-genderless:before { + content: "\f22d"; +} +.fa-facebook-official:before { + content: "\f230"; +} +.fa-pinterest-p:before { + content: "\f231"; +} +.fa-whatsapp:before { + content: "\f232"; +} +.fa-server:before { + content: "\f233"; +} +.fa-user-plus:before { + content: "\f234"; +} +.fa-user-times:before { + content: "\f235"; +} +.fa-hotel:before, +.fa-bed:before { + content: "\f236"; +} +.fa-viacoin:before { + content: "\f237"; +} +.fa-train:before { + content: "\f238"; +} +.fa-subway:before { + content: "\f239"; +} +.fa-medium:before { + content: "\f23a"; +} +.fa-yc:before, +.fa-y-combinator:before { + content: "\f23b"; +} +.fa-optin-monster:before { + content: "\f23c"; +} +.fa-opencart:before { + content: "\f23d"; +} +.fa-expeditedssl:before { + content: "\f23e"; +} +.fa-battery-4:before, +.fa-battery:before, +.fa-battery-full:before { + content: "\f240"; +} +.fa-battery-3:before, +.fa-battery-three-quarters:before { + content: "\f241"; +} +.fa-battery-2:before, +.fa-battery-half:before { + content: "\f242"; +} +.fa-battery-1:before, +.fa-battery-quarter:before { + content: "\f243"; +} +.fa-battery-0:before, +.fa-battery-empty:before { + content: "\f244"; +} +.fa-mouse-pointer:before { + content: "\f245"; +} +.fa-i-cursor:before { + content: "\f246"; +} +.fa-object-group:before { + content: "\f247"; +} +.fa-object-ungroup:before { + content: "\f248"; +} +.fa-sticky-note:before { + content: "\f249"; +} +.fa-sticky-note-o:before { + content: "\f24a"; +} +.fa-cc-jcb:before { + content: "\f24b"; +} +.fa-cc-diners-club:before { + content: "\f24c"; +} +.fa-clone:before { + content: "\f24d"; +} +.fa-balance-scale:before { + content: "\f24e"; +} +.fa-hourglass-o:before { + content: "\f250"; +} +.fa-hourglass-1:before, +.fa-hourglass-start:before { + content: "\f251"; +} +.fa-hourglass-2:before, +.fa-hourglass-half:before { + content: "\f252"; +} +.fa-hourglass-3:before, +.fa-hourglass-end:before { + content: "\f253"; +} +.fa-hourglass:before { + content: "\f254"; +} +.fa-hand-grab-o:before, +.fa-hand-rock-o:before { + content: "\f255"; +} +.fa-hand-stop-o:before, +.fa-hand-paper-o:before { + content: "\f256"; +} +.fa-hand-scissors-o:before { + content: "\f257"; +} +.fa-hand-lizard-o:before { + content: "\f258"; +} +.fa-hand-spock-o:before { + content: "\f259"; +} +.fa-hand-pointer-o:before { + content: "\f25a"; +} +.fa-hand-peace-o:before { + content: "\f25b"; +} +.fa-trademark:before { + content: "\f25c"; +} +.fa-registered:before { + content: "\f25d"; +} +.fa-creative-commons:before { + content: "\f25e"; +} +.fa-gg:before { + content: "\f260"; +} +.fa-gg-circle:before { + content: "\f261"; +} +.fa-tripadvisor:before { + content: "\f262"; +} +.fa-odnoklassniki:before { + content: "\f263"; +} +.fa-odnoklassniki-square:before { + content: "\f264"; +} +.fa-get-pocket:before { + content: "\f265"; +} +.fa-wikipedia-w:before { + content: "\f266"; +} +.fa-safari:before { + content: "\f267"; +} +.fa-chrome:before { + content: "\f268"; +} +.fa-firefox:before { + content: "\f269"; +} +.fa-opera:before { + content: "\f26a"; +} +.fa-internet-explorer:before { + content: "\f26b"; +} +.fa-tv:before, +.fa-television:before { + content: "\f26c"; +} +.fa-contao:before { + content: "\f26d"; +} +.fa-500px:before { + content: "\f26e"; +} +.fa-amazon:before { + content: "\f270"; +} +.fa-calendar-plus-o:before { + content: "\f271"; +} +.fa-calendar-minus-o:before { + content: "\f272"; +} +.fa-calendar-times-o:before { + content: "\f273"; +} +.fa-calendar-check-o:before { + content: "\f274"; +} +.fa-industry:before { + content: "\f275"; +} +.fa-map-pin:before { + content: "\f276"; +} +.fa-map-signs:before { + content: "\f277"; +} +.fa-map-o:before { + content: "\f278"; +} +.fa-map:before { + content: "\f279"; +} +.fa-commenting:before { + content: "\f27a"; +} +.fa-commenting-o:before { + content: "\f27b"; +} +.fa-houzz:before { + content: "\f27c"; +} +.fa-vimeo:before { + content: "\f27d"; +} +.fa-black-tie:before { + content: "\f27e"; +} +.fa-fonticons:before { + content: "\f280"; +} +.fa-reddit-alien:before { + content: "\f281"; +} +.fa-edge:before { + content: "\f282"; +} +.fa-credit-card-alt:before { + content: "\f283"; +} +.fa-codiepie:before { + content: "\f284"; +} +.fa-modx:before { + content: "\f285"; +} +.fa-fort-awesome:before { + content: "\f286"; +} +.fa-usb:before { + content: "\f287"; +} +.fa-product-hunt:before { + content: "\f288"; +} +.fa-mixcloud:before { + content: "\f289"; +} +.fa-scribd:before { + content: "\f28a"; +} +.fa-pause-circle:before { + content: "\f28b"; +} +.fa-pause-circle-o:before { + content: "\f28c"; +} +.fa-stop-circle:before { + content: "\f28d"; +} +.fa-stop-circle-o:before { + content: "\f28e"; +} +.fa-shopping-bag:before { + content: "\f290"; +} +.fa-shopping-basket:before { + content: "\f291"; +} +.fa-hashtag:before { + content: "\f292"; +} +.fa-bluetooth:before { + content: "\f293"; +} +.fa-bluetooth-b:before { + content: "\f294"; +} +.fa-percent:before { + content: "\f295"; +} +.fa-gitlab:before { + content: "\f296"; +} +.fa-wpbeginner:before { + content: "\f297"; +} +.fa-wpforms:before { + content: "\f298"; +} +.fa-envira:before { + content: "\f299"; +} +.fa-universal-access:before { + content: "\f29a"; +} +.fa-wheelchair-alt:before { + content: "\f29b"; +} +.fa-question-circle-o:before { + content: "\f29c"; +} +.fa-blind:before { + content: "\f29d"; +} +.fa-audio-description:before { + content: "\f29e"; +} +.fa-volume-control-phone:before { + content: "\f2a0"; +} +.fa-braille:before { + content: "\f2a1"; +} +.fa-assistive-listening-systems:before { + content: "\f2a2"; +} +.fa-asl-interpreting:before, +.fa-american-sign-language-interpreting:before { + content: "\f2a3"; +} +.fa-deafness:before, +.fa-hard-of-hearing:before, +.fa-deaf:before { + content: "\f2a4"; +} +.fa-glide:before { + content: "\f2a5"; +} +.fa-glide-g:before { + content: "\f2a6"; +} +.fa-signing:before, +.fa-sign-language:before { + content: "\f2a7"; +} +.fa-low-vision:before { + content: "\f2a8"; +} +.fa-viadeo:before { + content: "\f2a9"; +} +.fa-viadeo-square:before { + content: "\f2aa"; +} +.fa-snapchat:before { + content: "\f2ab"; +} +.fa-snapchat-ghost:before { + content: "\f2ac"; +} +.fa-snapchat-square:before { + content: "\f2ad"; +} +.fa-pied-piper:before { + content: "\f2ae"; +} +.fa-first-order:before { + content: "\f2b0"; +} +.fa-yoast:before { + content: "\f2b1"; +} +.fa-themeisle:before { + content: "\f2b2"; +} +.fa-google-plus-circle:before, +.fa-google-plus-official:before { + content: "\f2b3"; +} +.fa-fa:before, +.fa-font-awesome:before { + content: "\f2b4"; +} +.fa-handshake-o:before { + content: "\f2b5"; +} +.fa-envelope-open:before { + content: "\f2b6"; +} +.fa-envelope-open-o:before { + content: "\f2b7"; +} +.fa-linode:before { + content: "\f2b8"; +} +.fa-address-book:before { + content: "\f2b9"; +} +.fa-address-book-o:before { + content: "\f2ba"; +} +.fa-vcard:before, +.fa-address-card:before { + content: "\f2bb"; +} +.fa-vcard-o:before, +.fa-address-card-o:before { + content: "\f2bc"; +} +.fa-user-circle:before { + content: "\f2bd"; +} +.fa-user-circle-o:before { + content: "\f2be"; +} +.fa-user-o:before { + content: "\f2c0"; +} +.fa-id-badge:before { + content: "\f2c1"; +} +.fa-drivers-license:before, +.fa-id-card:before { + content: "\f2c2"; +} +.fa-drivers-license-o:before, +.fa-id-card-o:before { + content: "\f2c3"; +} +.fa-quora:before { + content: "\f2c4"; +} +.fa-free-code-camp:before { + content: "\f2c5"; +} +.fa-telegram:before { + content: "\f2c6"; +} +.fa-thermometer-4:before, +.fa-thermometer:before, +.fa-thermometer-full:before { + content: "\f2c7"; +} +.fa-thermometer-3:before, +.fa-thermometer-three-quarters:before { + content: "\f2c8"; +} +.fa-thermometer-2:before, +.fa-thermometer-half:before { + content: "\f2c9"; +} +.fa-thermometer-1:before, +.fa-thermometer-quarter:before { + content: "\f2ca"; +} +.fa-thermometer-0:before, +.fa-thermometer-empty:before { + content: "\f2cb"; +} +.fa-shower:before { + content: "\f2cc"; +} +.fa-bathtub:before, +.fa-s15:before, +.fa-bath:before { + content: "\f2cd"; +} +.fa-podcast:before { + content: "\f2ce"; +} +.fa-window-maximize:before { + content: "\f2d0"; +} +.fa-window-minimize:before { + content: "\f2d1"; +} +.fa-window-restore:before { + content: "\f2d2"; +} +.fa-times-rectangle:before, +.fa-window-close:before { + content: "\f2d3"; +} +.fa-times-rectangle-o:before, +.fa-window-close-o:before { + content: "\f2d4"; +} +.fa-bandcamp:before { + content: "\f2d5"; +} +.fa-grav:before { + content: "\f2d6"; +} +.fa-etsy:before { + content: "\f2d7"; +} +.fa-imdb:before { + content: "\f2d8"; +} +.fa-ravelry:before { + content: "\f2d9"; +} +.fa-eercast:before { + content: "\f2da"; +} +.fa-microchip:before { + content: "\f2db"; +} +.fa-snowflake-o:before { + content: "\f2dc"; +} +.fa-superpowers:before { + content: "\f2dd"; +} +.fa-wpexplorer:before { + content: "\f2de"; +} +.fa-meetup:before { + content: "\f2e0"; +} +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + border: 0; +} +.sr-only-focusable:active, +.sr-only-focusable:focus { + position: static; + width: auto; + height: auto; + margin: 0; + overflow: visible; + clip: auto; +} diff --git a/web/css/font-awesome-4.7.0/css/font-awesome.min.css b/web/css/font-awesome-4.7.0/css/font-awesome.min.css new file mode 100644 index 000000000..540440ce8 --- /dev/null +++ b/web/css/font-awesome-4.7.0/css/font-awesome.min.css @@ -0,0 +1,4 @@ +/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.7.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.7.0') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.7.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.7.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-resistance:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-intersex:before,.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-genderless:before{content:"\f22d"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.fa-yc:before,.fa-y-combinator:before{content:"\f23b"}.fa-optin-monster:before{content:"\f23c"}.fa-opencart:before{content:"\f23d"}.fa-expeditedssl:before{content:"\f23e"}.fa-battery-4:before,.fa-battery:before,.fa-battery-full:before{content:"\f240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-battery-2:before,.fa-battery-half:before{content:"\f242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-mouse-pointer:before{content:"\f245"}.fa-i-cursor:before{content:"\f246"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-sticky-note:before{content:"\f249"}.fa-sticky-note-o:before{content:"\f24a"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-diners-club:before{content:"\f24c"}.fa-clone:before{content:"\f24d"}.fa-balance-scale:before{content:"\f24e"}.fa-hourglass-o:before{content:"\f250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass:before{content:"\f254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:"\f256"}.fa-hand-scissors-o:before{content:"\f257"}.fa-hand-lizard-o:before{content:"\f258"}.fa-hand-spock-o:before{content:"\f259"}.fa-hand-pointer-o:before{content:"\f25a"}.fa-hand-peace-o:before{content:"\f25b"}.fa-trademark:before{content:"\f25c"}.fa-registered:before{content:"\f25d"}.fa-creative-commons:before{content:"\f25e"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-tripadvisor:before{content:"\f262"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-get-pocket:before{content:"\f265"}.fa-wikipedia-w:before{content:"\f266"}.fa-safari:before{content:"\f267"}.fa-chrome:before{content:"\f268"}.fa-firefox:before{content:"\f269"}.fa-opera:before{content:"\f26a"}.fa-internet-explorer:before{content:"\f26b"}.fa-tv:before,.fa-television:before{content:"\f26c"}.fa-contao:before{content:"\f26d"}.fa-500px:before{content:"\f26e"}.fa-amazon:before{content:"\f270"}.fa-calendar-plus-o:before{content:"\f271"}.fa-calendar-minus-o:before{content:"\f272"}.fa-calendar-times-o:before{content:"\f273"}.fa-calendar-check-o:before{content:"\f274"}.fa-industry:before{content:"\f275"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-map-o:before{content:"\f278"}.fa-map:before{content:"\f279"}.fa-commenting:before{content:"\f27a"}.fa-commenting-o:before{content:"\f27b"}.fa-houzz:before{content:"\f27c"}.fa-vimeo:before{content:"\f27d"}.fa-black-tie:before{content:"\f27e"}.fa-fonticons:before{content:"\f280"}.fa-reddit-alien:before{content:"\f281"}.fa-edge:before{content:"\f282"}.fa-credit-card-alt:before{content:"\f283"}.fa-codiepie:before{content:"\f284"}.fa-modx:before{content:"\f285"}.fa-fort-awesome:before{content:"\f286"}.fa-usb:before{content:"\f287"}.fa-product-hunt:before{content:"\f288"}.fa-mixcloud:before{content:"\f289"}.fa-scribd:before{content:"\f28a"}.fa-pause-circle:before{content:"\f28b"}.fa-pause-circle-o:before{content:"\f28c"}.fa-stop-circle:before{content:"\f28d"}.fa-stop-circle-o:before{content:"\f28e"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-hashtag:before{content:"\f292"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-percent:before{content:"\f295"}.fa-gitlab:before{content:"\f296"}.fa-wpbeginner:before{content:"\f297"}.fa-wpforms:before{content:"\f298"}.fa-envira:before{content:"\f299"}.fa-universal-access:before{content:"\f29a"}.fa-wheelchair-alt:before{content:"\f29b"}.fa-question-circle-o:before{content:"\f29c"}.fa-blind:before{content:"\f29d"}.fa-audio-description:before{content:"\f29e"}.fa-volume-control-phone:before{content:"\f2a0"}.fa-braille:before{content:"\f2a1"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asl-interpreting:before,.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-deafness:before,.fa-hard-of-hearing:before,.fa-deaf:before{content:"\f2a4"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-signing:before,.fa-sign-language:before{content:"\f2a7"}.fa-low-vision:before{content:"\f2a8"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-pied-piper:before{content:"\f2ae"}.fa-first-order:before{content:"\f2b0"}.fa-yoast:before{content:"\f2b1"}.fa-themeisle:before{content:"\f2b2"}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:"\f2b3"}.fa-fa:before,.fa-font-awesome:before{content:"\f2b4"}.fa-handshake-o:before{content:"\f2b5"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-o:before{content:"\f2b7"}.fa-linode:before{content:"\f2b8"}.fa-address-book:before{content:"\f2b9"}.fa-address-book-o:before{content:"\f2ba"}.fa-vcard:before,.fa-address-card:before{content:"\f2bb"}.fa-vcard-o:before,.fa-address-card-o:before{content:"\f2bc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-circle-o:before{content:"\f2be"}.fa-user-o:before{content:"\f2c0"}.fa-id-badge:before{content:"\f2c1"}.fa-drivers-license:before,.fa-id-card:before{content:"\f2c2"}.fa-drivers-license-o:before,.fa-id-card-o:before{content:"\f2c3"}.fa-quora:before{content:"\f2c4"}.fa-free-code-camp:before{content:"\f2c5"}.fa-telegram:before{content:"\f2c6"}.fa-thermometer-4:before,.fa-thermometer:before,.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-thermometer-2:before,.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:"\f2cb"}.fa-shower:before{content:"\f2cc"}.fa-bathtub:before,.fa-s15:before,.fa-bath:before{content:"\f2cd"}.fa-podcast:before{content:"\f2ce"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-times-rectangle:before,.fa-window-close:before{content:"\f2d3"}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:"\f2d4"}.fa-bandcamp:before{content:"\f2d5"}.fa-grav:before{content:"\f2d6"}.fa-etsy:before{content:"\f2d7"}.fa-imdb:before{content:"\f2d8"}.fa-ravelry:before{content:"\f2d9"}.fa-eercast:before{content:"\f2da"}.fa-microchip:before{content:"\f2db"}.fa-snowflake-o:before{content:"\f2dc"}.fa-superpowers:before{content:"\f2dd"}.fa-wpexplorer:before{content:"\f2de"}.fa-meetup:before{content:"\f2e0"}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto} diff --git a/web/css/font-awesome-4.7.0/fonts/FontAwesome.otf b/web/css/font-awesome-4.7.0/fonts/FontAwesome.otf new file mode 100644 index 000000000..401ec0f36 Binary files /dev/null and b/web/css/font-awesome-4.7.0/fonts/FontAwesome.otf differ diff --git a/web/css/font-awesome-4.7.0/fonts/fontawesome-webfont.eot b/web/css/font-awesome-4.7.0/fonts/fontawesome-webfont.eot new file mode 100644 index 000000000..e9f60ca95 Binary files /dev/null and b/web/css/font-awesome-4.7.0/fonts/fontawesome-webfont.eot differ diff --git a/web/css/font-awesome-4.7.0/fonts/fontawesome-webfont.svg b/web/css/font-awesome-4.7.0/fonts/fontawesome-webfont.svg new file mode 100644 index 000000000..855c845e5 --- /dev/null +++ b/web/css/font-awesome-4.7.0/fonts/fontawesome-webfont.svg @@ -0,0 +1,2671 @@ + + + + +Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 + By ,,, +Copyright Dave Gandy 2016. All rights reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/css/font-awesome-4.7.0/fonts/fontawesome-webfont.ttf b/web/css/font-awesome-4.7.0/fonts/fontawesome-webfont.ttf new file mode 100644 index 000000000..35acda2fa Binary files /dev/null and b/web/css/font-awesome-4.7.0/fonts/fontawesome-webfont.ttf differ diff --git a/web/css/font-awesome-4.7.0/fonts/fontawesome-webfont.woff b/web/css/font-awesome-4.7.0/fonts/fontawesome-webfont.woff new file mode 100644 index 000000000..400014a4b Binary files /dev/null and b/web/css/font-awesome-4.7.0/fonts/fontawesome-webfont.woff differ diff --git a/web/css/font-awesome-4.7.0/fonts/fontawesome-webfont.woff2 b/web/css/font-awesome-4.7.0/fonts/fontawesome-webfont.woff2 new file mode 100644 index 000000000..4d13fc604 Binary files /dev/null and b/web/css/font-awesome-4.7.0/fonts/fontawesome-webfont.woff2 differ diff --git a/web/css/font-awesome-4.7.0/less/animated.less b/web/css/font-awesome-4.7.0/less/animated.less new file mode 100644 index 000000000..66ad52a5b --- /dev/null +++ b/web/css/font-awesome-4.7.0/less/animated.less @@ -0,0 +1,34 @@ +// Animated Icons +// -------------------------- + +.@{fa-css-prefix}-spin { + -webkit-animation: fa-spin 2s infinite linear; + animation: fa-spin 2s infinite linear; +} + +.@{fa-css-prefix}-pulse { + -webkit-animation: fa-spin 1s infinite steps(8); + animation: fa-spin 1s infinite steps(8); +} + +@-webkit-keyframes fa-spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} + +@keyframes fa-spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} diff --git a/web/css/font-awesome-4.7.0/less/bordered-pulled.less b/web/css/font-awesome-4.7.0/less/bordered-pulled.less new file mode 100644 index 000000000..f1c8ad75f --- /dev/null +++ b/web/css/font-awesome-4.7.0/less/bordered-pulled.less @@ -0,0 +1,25 @@ +// Bordered & Pulled +// ------------------------- + +.@{fa-css-prefix}-border { + padding: .2em .25em .15em; + border: solid .08em @fa-border-color; + border-radius: .1em; +} + +.@{fa-css-prefix}-pull-left { float: left; } +.@{fa-css-prefix}-pull-right { float: right; } + +.@{fa-css-prefix} { + &.@{fa-css-prefix}-pull-left { margin-right: .3em; } + &.@{fa-css-prefix}-pull-right { margin-left: .3em; } +} + +/* Deprecated as of 4.4.0 */ +.pull-right { float: right; } +.pull-left { float: left; } + +.@{fa-css-prefix} { + &.pull-left { margin-right: .3em; } + &.pull-right { margin-left: .3em; } +} diff --git a/web/css/font-awesome-4.7.0/less/core.less b/web/css/font-awesome-4.7.0/less/core.less new file mode 100644 index 000000000..c577ac84a --- /dev/null +++ b/web/css/font-awesome-4.7.0/less/core.less @@ -0,0 +1,12 @@ +// Base Class Definition +// ------------------------- + +.@{fa-css-prefix} { + display: inline-block; + font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration + font-size: inherit; // can't have font-size inherit on line above, so need to override + text-rendering: auto; // optimizelegibility throws things off #1094 + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + +} diff --git a/web/css/font-awesome-4.7.0/less/fixed-width.less b/web/css/font-awesome-4.7.0/less/fixed-width.less new file mode 100644 index 000000000..110289f2f --- /dev/null +++ b/web/css/font-awesome-4.7.0/less/fixed-width.less @@ -0,0 +1,6 @@ +// Fixed Width Icons +// ------------------------- +.@{fa-css-prefix}-fw { + width: (18em / 14); + text-align: center; +} diff --git a/web/css/font-awesome-4.7.0/less/font-awesome.less b/web/css/font-awesome-4.7.0/less/font-awesome.less new file mode 100644 index 000000000..c3677def3 --- /dev/null +++ b/web/css/font-awesome-4.7.0/less/font-awesome.less @@ -0,0 +1,18 @@ +/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */ + +@import "variables.less"; +@import "mixins.less"; +@import "path.less"; +@import "core.less"; +@import "larger.less"; +@import "fixed-width.less"; +@import "list.less"; +@import "bordered-pulled.less"; +@import "animated.less"; +@import "rotated-flipped.less"; +@import "stacked.less"; +@import "icons.less"; +@import "screen-reader.less"; diff --git a/web/css/font-awesome-4.7.0/less/icons.less b/web/css/font-awesome-4.7.0/less/icons.less new file mode 100644 index 000000000..159d60042 --- /dev/null +++ b/web/css/font-awesome-4.7.0/less/icons.less @@ -0,0 +1,789 @@ +/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen + readers do not read off random characters that represent icons */ + +.@{fa-css-prefix}-glass:before { content: @fa-var-glass; } +.@{fa-css-prefix}-music:before { content: @fa-var-music; } +.@{fa-css-prefix}-search:before { content: @fa-var-search; } +.@{fa-css-prefix}-envelope-o:before { content: @fa-var-envelope-o; } +.@{fa-css-prefix}-heart:before { content: @fa-var-heart; } +.@{fa-css-prefix}-star:before { content: @fa-var-star; } +.@{fa-css-prefix}-star-o:before { content: @fa-var-star-o; } +.@{fa-css-prefix}-user:before { content: @fa-var-user; } +.@{fa-css-prefix}-film:before { content: @fa-var-film; } +.@{fa-css-prefix}-th-large:before { content: @fa-var-th-large; } +.@{fa-css-prefix}-th:before { content: @fa-var-th; } +.@{fa-css-prefix}-th-list:before { content: @fa-var-th-list; } +.@{fa-css-prefix}-check:before { content: @fa-var-check; } +.@{fa-css-prefix}-remove:before, +.@{fa-css-prefix}-close:before, +.@{fa-css-prefix}-times:before { content: @fa-var-times; } +.@{fa-css-prefix}-search-plus:before { content: @fa-var-search-plus; } +.@{fa-css-prefix}-search-minus:before { content: @fa-var-search-minus; } +.@{fa-css-prefix}-power-off:before { content: @fa-var-power-off; } +.@{fa-css-prefix}-signal:before { content: @fa-var-signal; } +.@{fa-css-prefix}-gear:before, +.@{fa-css-prefix}-cog:before { content: @fa-var-cog; } +.@{fa-css-prefix}-trash-o:before { content: @fa-var-trash-o; } +.@{fa-css-prefix}-home:before { content: @fa-var-home; } +.@{fa-css-prefix}-file-o:before { content: @fa-var-file-o; } +.@{fa-css-prefix}-clock-o:before { content: @fa-var-clock-o; } +.@{fa-css-prefix}-road:before { content: @fa-var-road; } +.@{fa-css-prefix}-download:before { content: @fa-var-download; } +.@{fa-css-prefix}-arrow-circle-o-down:before { content: @fa-var-arrow-circle-o-down; } +.@{fa-css-prefix}-arrow-circle-o-up:before { content: @fa-var-arrow-circle-o-up; } +.@{fa-css-prefix}-inbox:before { content: @fa-var-inbox; } +.@{fa-css-prefix}-play-circle-o:before { content: @fa-var-play-circle-o; } +.@{fa-css-prefix}-rotate-right:before, +.@{fa-css-prefix}-repeat:before { content: @fa-var-repeat; } +.@{fa-css-prefix}-refresh:before { content: @fa-var-refresh; } +.@{fa-css-prefix}-list-alt:before { content: @fa-var-list-alt; } +.@{fa-css-prefix}-lock:before { content: @fa-var-lock; } +.@{fa-css-prefix}-flag:before { content: @fa-var-flag; } +.@{fa-css-prefix}-headphones:before { content: @fa-var-headphones; } +.@{fa-css-prefix}-volume-off:before { content: @fa-var-volume-off; } +.@{fa-css-prefix}-volume-down:before { content: @fa-var-volume-down; } +.@{fa-css-prefix}-volume-up:before { content: @fa-var-volume-up; } +.@{fa-css-prefix}-qrcode:before { content: @fa-var-qrcode; } +.@{fa-css-prefix}-barcode:before { content: @fa-var-barcode; } +.@{fa-css-prefix}-tag:before { content: @fa-var-tag; } +.@{fa-css-prefix}-tags:before { content: @fa-var-tags; } +.@{fa-css-prefix}-book:before { content: @fa-var-book; } +.@{fa-css-prefix}-bookmark:before { content: @fa-var-bookmark; } +.@{fa-css-prefix}-print:before { content: @fa-var-print; } +.@{fa-css-prefix}-camera:before { content: @fa-var-camera; } +.@{fa-css-prefix}-font:before { content: @fa-var-font; } +.@{fa-css-prefix}-bold:before { content: @fa-var-bold; } +.@{fa-css-prefix}-italic:before { content: @fa-var-italic; } +.@{fa-css-prefix}-text-height:before { content: @fa-var-text-height; } +.@{fa-css-prefix}-text-width:before { content: @fa-var-text-width; } +.@{fa-css-prefix}-align-left:before { content: @fa-var-align-left; } +.@{fa-css-prefix}-align-center:before { content: @fa-var-align-center; } +.@{fa-css-prefix}-align-right:before { content: @fa-var-align-right; } +.@{fa-css-prefix}-align-justify:before { content: @fa-var-align-justify; } +.@{fa-css-prefix}-list:before { content: @fa-var-list; } +.@{fa-css-prefix}-dedent:before, +.@{fa-css-prefix}-outdent:before { content: @fa-var-outdent; } +.@{fa-css-prefix}-indent:before { content: @fa-var-indent; } +.@{fa-css-prefix}-video-camera:before { content: @fa-var-video-camera; } +.@{fa-css-prefix}-photo:before, +.@{fa-css-prefix}-image:before, +.@{fa-css-prefix}-picture-o:before { content: @fa-var-picture-o; } +.@{fa-css-prefix}-pencil:before { content: @fa-var-pencil; } +.@{fa-css-prefix}-map-marker:before { content: @fa-var-map-marker; } +.@{fa-css-prefix}-adjust:before { content: @fa-var-adjust; } +.@{fa-css-prefix}-tint:before { content: @fa-var-tint; } +.@{fa-css-prefix}-edit:before, +.@{fa-css-prefix}-pencil-square-o:before { content: @fa-var-pencil-square-o; } +.@{fa-css-prefix}-share-square-o:before { content: @fa-var-share-square-o; } +.@{fa-css-prefix}-check-square-o:before { content: @fa-var-check-square-o; } +.@{fa-css-prefix}-arrows:before { content: @fa-var-arrows; } +.@{fa-css-prefix}-step-backward:before { content: @fa-var-step-backward; } +.@{fa-css-prefix}-fast-backward:before { content: @fa-var-fast-backward; } +.@{fa-css-prefix}-backward:before { content: @fa-var-backward; } +.@{fa-css-prefix}-play:before { content: @fa-var-play; } +.@{fa-css-prefix}-pause:before { content: @fa-var-pause; } +.@{fa-css-prefix}-stop:before { content: @fa-var-stop; } +.@{fa-css-prefix}-forward:before { content: @fa-var-forward; } +.@{fa-css-prefix}-fast-forward:before { content: @fa-var-fast-forward; } +.@{fa-css-prefix}-step-forward:before { content: @fa-var-step-forward; } +.@{fa-css-prefix}-eject:before { content: @fa-var-eject; } +.@{fa-css-prefix}-chevron-left:before { content: @fa-var-chevron-left; } +.@{fa-css-prefix}-chevron-right:before { content: @fa-var-chevron-right; } +.@{fa-css-prefix}-plus-circle:before { content: @fa-var-plus-circle; } +.@{fa-css-prefix}-minus-circle:before { content: @fa-var-minus-circle; } +.@{fa-css-prefix}-times-circle:before { content: @fa-var-times-circle; } +.@{fa-css-prefix}-check-circle:before { content: @fa-var-check-circle; } +.@{fa-css-prefix}-question-circle:before { content: @fa-var-question-circle; } +.@{fa-css-prefix}-info-circle:before { content: @fa-var-info-circle; } +.@{fa-css-prefix}-crosshairs:before { content: @fa-var-crosshairs; } +.@{fa-css-prefix}-times-circle-o:before { content: @fa-var-times-circle-o; } +.@{fa-css-prefix}-check-circle-o:before { content: @fa-var-check-circle-o; } +.@{fa-css-prefix}-ban:before { content: @fa-var-ban; } +.@{fa-css-prefix}-arrow-left:before { content: @fa-var-arrow-left; } +.@{fa-css-prefix}-arrow-right:before { content: @fa-var-arrow-right; } +.@{fa-css-prefix}-arrow-up:before { content: @fa-var-arrow-up; } +.@{fa-css-prefix}-arrow-down:before { content: @fa-var-arrow-down; } +.@{fa-css-prefix}-mail-forward:before, +.@{fa-css-prefix}-share:before { content: @fa-var-share; } +.@{fa-css-prefix}-expand:before { content: @fa-var-expand; } +.@{fa-css-prefix}-compress:before { content: @fa-var-compress; } +.@{fa-css-prefix}-plus:before { content: @fa-var-plus; } +.@{fa-css-prefix}-minus:before { content: @fa-var-minus; } +.@{fa-css-prefix}-asterisk:before { content: @fa-var-asterisk; } +.@{fa-css-prefix}-exclamation-circle:before { content: @fa-var-exclamation-circle; } +.@{fa-css-prefix}-gift:before { content: @fa-var-gift; } +.@{fa-css-prefix}-leaf:before { content: @fa-var-leaf; } +.@{fa-css-prefix}-fire:before { content: @fa-var-fire; } +.@{fa-css-prefix}-eye:before { content: @fa-var-eye; } +.@{fa-css-prefix}-eye-slash:before { content: @fa-var-eye-slash; } +.@{fa-css-prefix}-warning:before, +.@{fa-css-prefix}-exclamation-triangle:before { content: @fa-var-exclamation-triangle; } +.@{fa-css-prefix}-plane:before { content: @fa-var-plane; } +.@{fa-css-prefix}-calendar:before { content: @fa-var-calendar; } +.@{fa-css-prefix}-random:before { content: @fa-var-random; } +.@{fa-css-prefix}-comment:before { content: @fa-var-comment; } +.@{fa-css-prefix}-magnet:before { content: @fa-var-magnet; } +.@{fa-css-prefix}-chevron-up:before { content: @fa-var-chevron-up; } +.@{fa-css-prefix}-chevron-down:before { content: @fa-var-chevron-down; } +.@{fa-css-prefix}-retweet:before { content: @fa-var-retweet; } +.@{fa-css-prefix}-shopping-cart:before { content: @fa-var-shopping-cart; } +.@{fa-css-prefix}-folder:before { content: @fa-var-folder; } +.@{fa-css-prefix}-folder-open:before { content: @fa-var-folder-open; } +.@{fa-css-prefix}-arrows-v:before { content: @fa-var-arrows-v; } +.@{fa-css-prefix}-arrows-h:before { content: @fa-var-arrows-h; } +.@{fa-css-prefix}-bar-chart-o:before, +.@{fa-css-prefix}-bar-chart:before { content: @fa-var-bar-chart; } +.@{fa-css-prefix}-twitter-square:before { content: @fa-var-twitter-square; } +.@{fa-css-prefix}-facebook-square:before { content: @fa-var-facebook-square; } +.@{fa-css-prefix}-camera-retro:before { content: @fa-var-camera-retro; } +.@{fa-css-prefix}-key:before { content: @fa-var-key; } +.@{fa-css-prefix}-gears:before, +.@{fa-css-prefix}-cogs:before { content: @fa-var-cogs; } +.@{fa-css-prefix}-comments:before { content: @fa-var-comments; } +.@{fa-css-prefix}-thumbs-o-up:before { content: @fa-var-thumbs-o-up; } +.@{fa-css-prefix}-thumbs-o-down:before { content: @fa-var-thumbs-o-down; } +.@{fa-css-prefix}-star-half:before { content: @fa-var-star-half; } +.@{fa-css-prefix}-heart-o:before { content: @fa-var-heart-o; } +.@{fa-css-prefix}-sign-out:before { content: @fa-var-sign-out; } +.@{fa-css-prefix}-linkedin-square:before { content: @fa-var-linkedin-square; } +.@{fa-css-prefix}-thumb-tack:before { content: @fa-var-thumb-tack; } +.@{fa-css-prefix}-external-link:before { content: @fa-var-external-link; } +.@{fa-css-prefix}-sign-in:before { content: @fa-var-sign-in; } +.@{fa-css-prefix}-trophy:before { content: @fa-var-trophy; } +.@{fa-css-prefix}-github-square:before { content: @fa-var-github-square; } +.@{fa-css-prefix}-upload:before { content: @fa-var-upload; } +.@{fa-css-prefix}-lemon-o:before { content: @fa-var-lemon-o; } +.@{fa-css-prefix}-phone:before { content: @fa-var-phone; } +.@{fa-css-prefix}-square-o:before { content: @fa-var-square-o; } +.@{fa-css-prefix}-bookmark-o:before { content: @fa-var-bookmark-o; } +.@{fa-css-prefix}-phone-square:before { content: @fa-var-phone-square; } +.@{fa-css-prefix}-twitter:before { content: @fa-var-twitter; } +.@{fa-css-prefix}-facebook-f:before, +.@{fa-css-prefix}-facebook:before { content: @fa-var-facebook; } +.@{fa-css-prefix}-github:before { content: @fa-var-github; } +.@{fa-css-prefix}-unlock:before { content: @fa-var-unlock; } +.@{fa-css-prefix}-credit-card:before { content: @fa-var-credit-card; } +.@{fa-css-prefix}-feed:before, +.@{fa-css-prefix}-rss:before { content: @fa-var-rss; } +.@{fa-css-prefix}-hdd-o:before { content: @fa-var-hdd-o; } +.@{fa-css-prefix}-bullhorn:before { content: @fa-var-bullhorn; } +.@{fa-css-prefix}-bell:before { content: @fa-var-bell; } +.@{fa-css-prefix}-certificate:before { content: @fa-var-certificate; } +.@{fa-css-prefix}-hand-o-right:before { content: @fa-var-hand-o-right; } +.@{fa-css-prefix}-hand-o-left:before { content: @fa-var-hand-o-left; } +.@{fa-css-prefix}-hand-o-up:before { content: @fa-var-hand-o-up; } +.@{fa-css-prefix}-hand-o-down:before { content: @fa-var-hand-o-down; } +.@{fa-css-prefix}-arrow-circle-left:before { content: @fa-var-arrow-circle-left; } +.@{fa-css-prefix}-arrow-circle-right:before { content: @fa-var-arrow-circle-right; } +.@{fa-css-prefix}-arrow-circle-up:before { content: @fa-var-arrow-circle-up; } +.@{fa-css-prefix}-arrow-circle-down:before { content: @fa-var-arrow-circle-down; } +.@{fa-css-prefix}-globe:before { content: @fa-var-globe; } +.@{fa-css-prefix}-wrench:before { content: @fa-var-wrench; } +.@{fa-css-prefix}-tasks:before { content: @fa-var-tasks; } +.@{fa-css-prefix}-filter:before { content: @fa-var-filter; } +.@{fa-css-prefix}-briefcase:before { content: @fa-var-briefcase; } +.@{fa-css-prefix}-arrows-alt:before { content: @fa-var-arrows-alt; } +.@{fa-css-prefix}-group:before, +.@{fa-css-prefix}-users:before { content: @fa-var-users; } +.@{fa-css-prefix}-chain:before, +.@{fa-css-prefix}-link:before { content: @fa-var-link; } +.@{fa-css-prefix}-cloud:before { content: @fa-var-cloud; } +.@{fa-css-prefix}-flask:before { content: @fa-var-flask; } +.@{fa-css-prefix}-cut:before, +.@{fa-css-prefix}-scissors:before { content: @fa-var-scissors; } +.@{fa-css-prefix}-copy:before, +.@{fa-css-prefix}-files-o:before { content: @fa-var-files-o; } +.@{fa-css-prefix}-paperclip:before { content: @fa-var-paperclip; } +.@{fa-css-prefix}-save:before, +.@{fa-css-prefix}-floppy-o:before { content: @fa-var-floppy-o; } +.@{fa-css-prefix}-square:before { content: @fa-var-square; } +.@{fa-css-prefix}-navicon:before, +.@{fa-css-prefix}-reorder:before, +.@{fa-css-prefix}-bars:before { content: @fa-var-bars; } +.@{fa-css-prefix}-list-ul:before { content: @fa-var-list-ul; } +.@{fa-css-prefix}-list-ol:before { content: @fa-var-list-ol; } +.@{fa-css-prefix}-strikethrough:before { content: @fa-var-strikethrough; } +.@{fa-css-prefix}-underline:before { content: @fa-var-underline; } +.@{fa-css-prefix}-table:before { content: @fa-var-table; } +.@{fa-css-prefix}-magic:before { content: @fa-var-magic; } +.@{fa-css-prefix}-truck:before { content: @fa-var-truck; } +.@{fa-css-prefix}-pinterest:before { content: @fa-var-pinterest; } +.@{fa-css-prefix}-pinterest-square:before { content: @fa-var-pinterest-square; } +.@{fa-css-prefix}-google-plus-square:before { content: @fa-var-google-plus-square; } +.@{fa-css-prefix}-google-plus:before { content: @fa-var-google-plus; } +.@{fa-css-prefix}-money:before { content: @fa-var-money; } +.@{fa-css-prefix}-caret-down:before { content: @fa-var-caret-down; } +.@{fa-css-prefix}-caret-up:before { content: @fa-var-caret-up; } +.@{fa-css-prefix}-caret-left:before { content: @fa-var-caret-left; } +.@{fa-css-prefix}-caret-right:before { content: @fa-var-caret-right; } +.@{fa-css-prefix}-columns:before { content: @fa-var-columns; } +.@{fa-css-prefix}-unsorted:before, +.@{fa-css-prefix}-sort:before { content: @fa-var-sort; } +.@{fa-css-prefix}-sort-down:before, +.@{fa-css-prefix}-sort-desc:before { content: @fa-var-sort-desc; } +.@{fa-css-prefix}-sort-up:before, +.@{fa-css-prefix}-sort-asc:before { content: @fa-var-sort-asc; } +.@{fa-css-prefix}-envelope:before { content: @fa-var-envelope; } +.@{fa-css-prefix}-linkedin:before { content: @fa-var-linkedin; } +.@{fa-css-prefix}-rotate-left:before, +.@{fa-css-prefix}-undo:before { content: @fa-var-undo; } +.@{fa-css-prefix}-legal:before, +.@{fa-css-prefix}-gavel:before { content: @fa-var-gavel; } +.@{fa-css-prefix}-dashboard:before, +.@{fa-css-prefix}-tachometer:before { content: @fa-var-tachometer; } +.@{fa-css-prefix}-comment-o:before { content: @fa-var-comment-o; } +.@{fa-css-prefix}-comments-o:before { content: @fa-var-comments-o; } +.@{fa-css-prefix}-flash:before, +.@{fa-css-prefix}-bolt:before { content: @fa-var-bolt; } +.@{fa-css-prefix}-sitemap:before { content: @fa-var-sitemap; } +.@{fa-css-prefix}-umbrella:before { content: @fa-var-umbrella; } +.@{fa-css-prefix}-paste:before, +.@{fa-css-prefix}-clipboard:before { content: @fa-var-clipboard; } +.@{fa-css-prefix}-lightbulb-o:before { content: @fa-var-lightbulb-o; } +.@{fa-css-prefix}-exchange:before { content: @fa-var-exchange; } +.@{fa-css-prefix}-cloud-download:before { content: @fa-var-cloud-download; } +.@{fa-css-prefix}-cloud-upload:before { content: @fa-var-cloud-upload; } +.@{fa-css-prefix}-user-md:before { content: @fa-var-user-md; } +.@{fa-css-prefix}-stethoscope:before { content: @fa-var-stethoscope; } +.@{fa-css-prefix}-suitcase:before { content: @fa-var-suitcase; } +.@{fa-css-prefix}-bell-o:before { content: @fa-var-bell-o; } +.@{fa-css-prefix}-coffee:before { content: @fa-var-coffee; } +.@{fa-css-prefix}-cutlery:before { content: @fa-var-cutlery; } +.@{fa-css-prefix}-file-text-o:before { content: @fa-var-file-text-o; } +.@{fa-css-prefix}-building-o:before { content: @fa-var-building-o; } +.@{fa-css-prefix}-hospital-o:before { content: @fa-var-hospital-o; } +.@{fa-css-prefix}-ambulance:before { content: @fa-var-ambulance; } +.@{fa-css-prefix}-medkit:before { content: @fa-var-medkit; } +.@{fa-css-prefix}-fighter-jet:before { content: @fa-var-fighter-jet; } +.@{fa-css-prefix}-beer:before { content: @fa-var-beer; } +.@{fa-css-prefix}-h-square:before { content: @fa-var-h-square; } +.@{fa-css-prefix}-plus-square:before { content: @fa-var-plus-square; } +.@{fa-css-prefix}-angle-double-left:before { content: @fa-var-angle-double-left; } +.@{fa-css-prefix}-angle-double-right:before { content: @fa-var-angle-double-right; } +.@{fa-css-prefix}-angle-double-up:before { content: @fa-var-angle-double-up; } +.@{fa-css-prefix}-angle-double-down:before { content: @fa-var-angle-double-down; } +.@{fa-css-prefix}-angle-left:before { content: @fa-var-angle-left; } +.@{fa-css-prefix}-angle-right:before { content: @fa-var-angle-right; } +.@{fa-css-prefix}-angle-up:before { content: @fa-var-angle-up; } +.@{fa-css-prefix}-angle-down:before { content: @fa-var-angle-down; } +.@{fa-css-prefix}-desktop:before { content: @fa-var-desktop; } +.@{fa-css-prefix}-laptop:before { content: @fa-var-laptop; } +.@{fa-css-prefix}-tablet:before { content: @fa-var-tablet; } +.@{fa-css-prefix}-mobile-phone:before, +.@{fa-css-prefix}-mobile:before { content: @fa-var-mobile; } +.@{fa-css-prefix}-circle-o:before { content: @fa-var-circle-o; } +.@{fa-css-prefix}-quote-left:before { content: @fa-var-quote-left; } +.@{fa-css-prefix}-quote-right:before { content: @fa-var-quote-right; } +.@{fa-css-prefix}-spinner:before { content: @fa-var-spinner; } +.@{fa-css-prefix}-circle:before { content: @fa-var-circle; } +.@{fa-css-prefix}-mail-reply:before, +.@{fa-css-prefix}-reply:before { content: @fa-var-reply; } +.@{fa-css-prefix}-github-alt:before { content: @fa-var-github-alt; } +.@{fa-css-prefix}-folder-o:before { content: @fa-var-folder-o; } +.@{fa-css-prefix}-folder-open-o:before { content: @fa-var-folder-open-o; } +.@{fa-css-prefix}-smile-o:before { content: @fa-var-smile-o; } +.@{fa-css-prefix}-frown-o:before { content: @fa-var-frown-o; } +.@{fa-css-prefix}-meh-o:before { content: @fa-var-meh-o; } +.@{fa-css-prefix}-gamepad:before { content: @fa-var-gamepad; } +.@{fa-css-prefix}-keyboard-o:before { content: @fa-var-keyboard-o; } +.@{fa-css-prefix}-flag-o:before { content: @fa-var-flag-o; } +.@{fa-css-prefix}-flag-checkered:before { content: @fa-var-flag-checkered; } +.@{fa-css-prefix}-terminal:before { content: @fa-var-terminal; } +.@{fa-css-prefix}-code:before { content: @fa-var-code; } +.@{fa-css-prefix}-mail-reply-all:before, +.@{fa-css-prefix}-reply-all:before { content: @fa-var-reply-all; } +.@{fa-css-prefix}-star-half-empty:before, +.@{fa-css-prefix}-star-half-full:before, +.@{fa-css-prefix}-star-half-o:before { content: @fa-var-star-half-o; } +.@{fa-css-prefix}-location-arrow:before { content: @fa-var-location-arrow; } +.@{fa-css-prefix}-crop:before { content: @fa-var-crop; } +.@{fa-css-prefix}-code-fork:before { content: @fa-var-code-fork; } +.@{fa-css-prefix}-unlink:before, +.@{fa-css-prefix}-chain-broken:before { content: @fa-var-chain-broken; } +.@{fa-css-prefix}-question:before { content: @fa-var-question; } +.@{fa-css-prefix}-info:before { content: @fa-var-info; } +.@{fa-css-prefix}-exclamation:before { content: @fa-var-exclamation; } +.@{fa-css-prefix}-superscript:before { content: @fa-var-superscript; } +.@{fa-css-prefix}-subscript:before { content: @fa-var-subscript; } +.@{fa-css-prefix}-eraser:before { content: @fa-var-eraser; } +.@{fa-css-prefix}-puzzle-piece:before { content: @fa-var-puzzle-piece; } +.@{fa-css-prefix}-microphone:before { content: @fa-var-microphone; } +.@{fa-css-prefix}-microphone-slash:before { content: @fa-var-microphone-slash; } +.@{fa-css-prefix}-shield:before { content: @fa-var-shield; } +.@{fa-css-prefix}-calendar-o:before { content: @fa-var-calendar-o; } +.@{fa-css-prefix}-fire-extinguisher:before { content: @fa-var-fire-extinguisher; } +.@{fa-css-prefix}-rocket:before { content: @fa-var-rocket; } +.@{fa-css-prefix}-maxcdn:before { content: @fa-var-maxcdn; } +.@{fa-css-prefix}-chevron-circle-left:before { content: @fa-var-chevron-circle-left; } +.@{fa-css-prefix}-chevron-circle-right:before { content: @fa-var-chevron-circle-right; } +.@{fa-css-prefix}-chevron-circle-up:before { content: @fa-var-chevron-circle-up; } +.@{fa-css-prefix}-chevron-circle-down:before { content: @fa-var-chevron-circle-down; } +.@{fa-css-prefix}-html5:before { content: @fa-var-html5; } +.@{fa-css-prefix}-css3:before { content: @fa-var-css3; } +.@{fa-css-prefix}-anchor:before { content: @fa-var-anchor; } +.@{fa-css-prefix}-unlock-alt:before { content: @fa-var-unlock-alt; } +.@{fa-css-prefix}-bullseye:before { content: @fa-var-bullseye; } +.@{fa-css-prefix}-ellipsis-h:before { content: @fa-var-ellipsis-h; } +.@{fa-css-prefix}-ellipsis-v:before { content: @fa-var-ellipsis-v; } +.@{fa-css-prefix}-rss-square:before { content: @fa-var-rss-square; } +.@{fa-css-prefix}-play-circle:before { content: @fa-var-play-circle; } +.@{fa-css-prefix}-ticket:before { content: @fa-var-ticket; } +.@{fa-css-prefix}-minus-square:before { content: @fa-var-minus-square; } +.@{fa-css-prefix}-minus-square-o:before { content: @fa-var-minus-square-o; } +.@{fa-css-prefix}-level-up:before { content: @fa-var-level-up; } +.@{fa-css-prefix}-level-down:before { content: @fa-var-level-down; } +.@{fa-css-prefix}-check-square:before { content: @fa-var-check-square; } +.@{fa-css-prefix}-pencil-square:before { content: @fa-var-pencil-square; } +.@{fa-css-prefix}-external-link-square:before { content: @fa-var-external-link-square; } +.@{fa-css-prefix}-share-square:before { content: @fa-var-share-square; } +.@{fa-css-prefix}-compass:before { content: @fa-var-compass; } +.@{fa-css-prefix}-toggle-down:before, +.@{fa-css-prefix}-caret-square-o-down:before { content: @fa-var-caret-square-o-down; } +.@{fa-css-prefix}-toggle-up:before, +.@{fa-css-prefix}-caret-square-o-up:before { content: @fa-var-caret-square-o-up; } +.@{fa-css-prefix}-toggle-right:before, +.@{fa-css-prefix}-caret-square-o-right:before { content: @fa-var-caret-square-o-right; } +.@{fa-css-prefix}-euro:before, +.@{fa-css-prefix}-eur:before { content: @fa-var-eur; } +.@{fa-css-prefix}-gbp:before { content: @fa-var-gbp; } +.@{fa-css-prefix}-dollar:before, +.@{fa-css-prefix}-usd:before { content: @fa-var-usd; } +.@{fa-css-prefix}-rupee:before, +.@{fa-css-prefix}-inr:before { content: @fa-var-inr; } +.@{fa-css-prefix}-cny:before, +.@{fa-css-prefix}-rmb:before, +.@{fa-css-prefix}-yen:before, +.@{fa-css-prefix}-jpy:before { content: @fa-var-jpy; } +.@{fa-css-prefix}-ruble:before, +.@{fa-css-prefix}-rouble:before, +.@{fa-css-prefix}-rub:before { content: @fa-var-rub; } +.@{fa-css-prefix}-won:before, +.@{fa-css-prefix}-krw:before { content: @fa-var-krw; } +.@{fa-css-prefix}-bitcoin:before, +.@{fa-css-prefix}-btc:before { content: @fa-var-btc; } +.@{fa-css-prefix}-file:before { content: @fa-var-file; } +.@{fa-css-prefix}-file-text:before { content: @fa-var-file-text; } +.@{fa-css-prefix}-sort-alpha-asc:before { content: @fa-var-sort-alpha-asc; } +.@{fa-css-prefix}-sort-alpha-desc:before { content: @fa-var-sort-alpha-desc; } +.@{fa-css-prefix}-sort-amount-asc:before { content: @fa-var-sort-amount-asc; } +.@{fa-css-prefix}-sort-amount-desc:before { content: @fa-var-sort-amount-desc; } +.@{fa-css-prefix}-sort-numeric-asc:before { content: @fa-var-sort-numeric-asc; } +.@{fa-css-prefix}-sort-numeric-desc:before { content: @fa-var-sort-numeric-desc; } +.@{fa-css-prefix}-thumbs-up:before { content: @fa-var-thumbs-up; } +.@{fa-css-prefix}-thumbs-down:before { content: @fa-var-thumbs-down; } +.@{fa-css-prefix}-youtube-square:before { content: @fa-var-youtube-square; } +.@{fa-css-prefix}-youtube:before { content: @fa-var-youtube; } +.@{fa-css-prefix}-xing:before { content: @fa-var-xing; } +.@{fa-css-prefix}-xing-square:before { content: @fa-var-xing-square; } +.@{fa-css-prefix}-youtube-play:before { content: @fa-var-youtube-play; } +.@{fa-css-prefix}-dropbox:before { content: @fa-var-dropbox; } +.@{fa-css-prefix}-stack-overflow:before { content: @fa-var-stack-overflow; } +.@{fa-css-prefix}-instagram:before { content: @fa-var-instagram; } +.@{fa-css-prefix}-flickr:before { content: @fa-var-flickr; } +.@{fa-css-prefix}-adn:before { content: @fa-var-adn; } +.@{fa-css-prefix}-bitbucket:before { content: @fa-var-bitbucket; } +.@{fa-css-prefix}-bitbucket-square:before { content: @fa-var-bitbucket-square; } +.@{fa-css-prefix}-tumblr:before { content: @fa-var-tumblr; } +.@{fa-css-prefix}-tumblr-square:before { content: @fa-var-tumblr-square; } +.@{fa-css-prefix}-long-arrow-down:before { content: @fa-var-long-arrow-down; } +.@{fa-css-prefix}-long-arrow-up:before { content: @fa-var-long-arrow-up; } +.@{fa-css-prefix}-long-arrow-left:before { content: @fa-var-long-arrow-left; } +.@{fa-css-prefix}-long-arrow-right:before { content: @fa-var-long-arrow-right; } +.@{fa-css-prefix}-apple:before { content: @fa-var-apple; } +.@{fa-css-prefix}-windows:before { content: @fa-var-windows; } +.@{fa-css-prefix}-android:before { content: @fa-var-android; } +.@{fa-css-prefix}-linux:before { content: @fa-var-linux; } +.@{fa-css-prefix}-dribbble:before { content: @fa-var-dribbble; } +.@{fa-css-prefix}-skype:before { content: @fa-var-skype; } +.@{fa-css-prefix}-foursquare:before { content: @fa-var-foursquare; } +.@{fa-css-prefix}-trello:before { content: @fa-var-trello; } +.@{fa-css-prefix}-female:before { content: @fa-var-female; } +.@{fa-css-prefix}-male:before { content: @fa-var-male; } +.@{fa-css-prefix}-gittip:before, +.@{fa-css-prefix}-gratipay:before { content: @fa-var-gratipay; } +.@{fa-css-prefix}-sun-o:before { content: @fa-var-sun-o; } +.@{fa-css-prefix}-moon-o:before { content: @fa-var-moon-o; } +.@{fa-css-prefix}-archive:before { content: @fa-var-archive; } +.@{fa-css-prefix}-bug:before { content: @fa-var-bug; } +.@{fa-css-prefix}-vk:before { content: @fa-var-vk; } +.@{fa-css-prefix}-weibo:before { content: @fa-var-weibo; } +.@{fa-css-prefix}-renren:before { content: @fa-var-renren; } +.@{fa-css-prefix}-pagelines:before { content: @fa-var-pagelines; } +.@{fa-css-prefix}-stack-exchange:before { content: @fa-var-stack-exchange; } +.@{fa-css-prefix}-arrow-circle-o-right:before { content: @fa-var-arrow-circle-o-right; } +.@{fa-css-prefix}-arrow-circle-o-left:before { content: @fa-var-arrow-circle-o-left; } +.@{fa-css-prefix}-toggle-left:before, +.@{fa-css-prefix}-caret-square-o-left:before { content: @fa-var-caret-square-o-left; } +.@{fa-css-prefix}-dot-circle-o:before { content: @fa-var-dot-circle-o; } +.@{fa-css-prefix}-wheelchair:before { content: @fa-var-wheelchair; } +.@{fa-css-prefix}-vimeo-square:before { content: @fa-var-vimeo-square; } +.@{fa-css-prefix}-turkish-lira:before, +.@{fa-css-prefix}-try:before { content: @fa-var-try; } +.@{fa-css-prefix}-plus-square-o:before { content: @fa-var-plus-square-o; } +.@{fa-css-prefix}-space-shuttle:before { content: @fa-var-space-shuttle; } +.@{fa-css-prefix}-slack:before { content: @fa-var-slack; } +.@{fa-css-prefix}-envelope-square:before { content: @fa-var-envelope-square; } +.@{fa-css-prefix}-wordpress:before { content: @fa-var-wordpress; } +.@{fa-css-prefix}-openid:before { content: @fa-var-openid; } +.@{fa-css-prefix}-institution:before, +.@{fa-css-prefix}-bank:before, +.@{fa-css-prefix}-university:before { content: @fa-var-university; } +.@{fa-css-prefix}-mortar-board:before, +.@{fa-css-prefix}-graduation-cap:before { content: @fa-var-graduation-cap; } +.@{fa-css-prefix}-yahoo:before { content: @fa-var-yahoo; } +.@{fa-css-prefix}-google:before { content: @fa-var-google; } +.@{fa-css-prefix}-reddit:before { content: @fa-var-reddit; } +.@{fa-css-prefix}-reddit-square:before { content: @fa-var-reddit-square; } +.@{fa-css-prefix}-stumbleupon-circle:before { content: @fa-var-stumbleupon-circle; } +.@{fa-css-prefix}-stumbleupon:before { content: @fa-var-stumbleupon; } +.@{fa-css-prefix}-delicious:before { content: @fa-var-delicious; } +.@{fa-css-prefix}-digg:before { content: @fa-var-digg; } +.@{fa-css-prefix}-pied-piper-pp:before { content: @fa-var-pied-piper-pp; } +.@{fa-css-prefix}-pied-piper-alt:before { content: @fa-var-pied-piper-alt; } +.@{fa-css-prefix}-drupal:before { content: @fa-var-drupal; } +.@{fa-css-prefix}-joomla:before { content: @fa-var-joomla; } +.@{fa-css-prefix}-language:before { content: @fa-var-language; } +.@{fa-css-prefix}-fax:before { content: @fa-var-fax; } +.@{fa-css-prefix}-building:before { content: @fa-var-building; } +.@{fa-css-prefix}-child:before { content: @fa-var-child; } +.@{fa-css-prefix}-paw:before { content: @fa-var-paw; } +.@{fa-css-prefix}-spoon:before { content: @fa-var-spoon; } +.@{fa-css-prefix}-cube:before { content: @fa-var-cube; } +.@{fa-css-prefix}-cubes:before { content: @fa-var-cubes; } +.@{fa-css-prefix}-behance:before { content: @fa-var-behance; } +.@{fa-css-prefix}-behance-square:before { content: @fa-var-behance-square; } +.@{fa-css-prefix}-steam:before { content: @fa-var-steam; } +.@{fa-css-prefix}-steam-square:before { content: @fa-var-steam-square; } +.@{fa-css-prefix}-recycle:before { content: @fa-var-recycle; } +.@{fa-css-prefix}-automobile:before, +.@{fa-css-prefix}-car:before { content: @fa-var-car; } +.@{fa-css-prefix}-cab:before, +.@{fa-css-prefix}-taxi:before { content: @fa-var-taxi; } +.@{fa-css-prefix}-tree:before { content: @fa-var-tree; } +.@{fa-css-prefix}-spotify:before { content: @fa-var-spotify; } +.@{fa-css-prefix}-deviantart:before { content: @fa-var-deviantart; } +.@{fa-css-prefix}-soundcloud:before { content: @fa-var-soundcloud; } +.@{fa-css-prefix}-database:before { content: @fa-var-database; } +.@{fa-css-prefix}-file-pdf-o:before { content: @fa-var-file-pdf-o; } +.@{fa-css-prefix}-file-word-o:before { content: @fa-var-file-word-o; } +.@{fa-css-prefix}-file-excel-o:before { content: @fa-var-file-excel-o; } +.@{fa-css-prefix}-file-powerpoint-o:before { content: @fa-var-file-powerpoint-o; } +.@{fa-css-prefix}-file-photo-o:before, +.@{fa-css-prefix}-file-picture-o:before, +.@{fa-css-prefix}-file-image-o:before { content: @fa-var-file-image-o; } +.@{fa-css-prefix}-file-zip-o:before, +.@{fa-css-prefix}-file-archive-o:before { content: @fa-var-file-archive-o; } +.@{fa-css-prefix}-file-sound-o:before, +.@{fa-css-prefix}-file-audio-o:before { content: @fa-var-file-audio-o; } +.@{fa-css-prefix}-file-movie-o:before, +.@{fa-css-prefix}-file-video-o:before { content: @fa-var-file-video-o; } +.@{fa-css-prefix}-file-code-o:before { content: @fa-var-file-code-o; } +.@{fa-css-prefix}-vine:before { content: @fa-var-vine; } +.@{fa-css-prefix}-codepen:before { content: @fa-var-codepen; } +.@{fa-css-prefix}-jsfiddle:before { content: @fa-var-jsfiddle; } +.@{fa-css-prefix}-life-bouy:before, +.@{fa-css-prefix}-life-buoy:before, +.@{fa-css-prefix}-life-saver:before, +.@{fa-css-prefix}-support:before, +.@{fa-css-prefix}-life-ring:before { content: @fa-var-life-ring; } +.@{fa-css-prefix}-circle-o-notch:before { content: @fa-var-circle-o-notch; } +.@{fa-css-prefix}-ra:before, +.@{fa-css-prefix}-resistance:before, +.@{fa-css-prefix}-rebel:before { content: @fa-var-rebel; } +.@{fa-css-prefix}-ge:before, +.@{fa-css-prefix}-empire:before { content: @fa-var-empire; } +.@{fa-css-prefix}-git-square:before { content: @fa-var-git-square; } +.@{fa-css-prefix}-git:before { content: @fa-var-git; } +.@{fa-css-prefix}-y-combinator-square:before, +.@{fa-css-prefix}-yc-square:before, +.@{fa-css-prefix}-hacker-news:before { content: @fa-var-hacker-news; } +.@{fa-css-prefix}-tencent-weibo:before { content: @fa-var-tencent-weibo; } +.@{fa-css-prefix}-qq:before { content: @fa-var-qq; } +.@{fa-css-prefix}-wechat:before, +.@{fa-css-prefix}-weixin:before { content: @fa-var-weixin; } +.@{fa-css-prefix}-send:before, +.@{fa-css-prefix}-paper-plane:before { content: @fa-var-paper-plane; } +.@{fa-css-prefix}-send-o:before, +.@{fa-css-prefix}-paper-plane-o:before { content: @fa-var-paper-plane-o; } +.@{fa-css-prefix}-history:before { content: @fa-var-history; } +.@{fa-css-prefix}-circle-thin:before { content: @fa-var-circle-thin; } +.@{fa-css-prefix}-header:before { content: @fa-var-header; } +.@{fa-css-prefix}-paragraph:before { content: @fa-var-paragraph; } +.@{fa-css-prefix}-sliders:before { content: @fa-var-sliders; } +.@{fa-css-prefix}-share-alt:before { content: @fa-var-share-alt; } +.@{fa-css-prefix}-share-alt-square:before { content: @fa-var-share-alt-square; } +.@{fa-css-prefix}-bomb:before { content: @fa-var-bomb; } +.@{fa-css-prefix}-soccer-ball-o:before, +.@{fa-css-prefix}-futbol-o:before { content: @fa-var-futbol-o; } +.@{fa-css-prefix}-tty:before { content: @fa-var-tty; } +.@{fa-css-prefix}-binoculars:before { content: @fa-var-binoculars; } +.@{fa-css-prefix}-plug:before { content: @fa-var-plug; } +.@{fa-css-prefix}-slideshare:before { content: @fa-var-slideshare; } +.@{fa-css-prefix}-twitch:before { content: @fa-var-twitch; } +.@{fa-css-prefix}-yelp:before { content: @fa-var-yelp; } +.@{fa-css-prefix}-newspaper-o:before { content: @fa-var-newspaper-o; } +.@{fa-css-prefix}-wifi:before { content: @fa-var-wifi; } +.@{fa-css-prefix}-calculator:before { content: @fa-var-calculator; } +.@{fa-css-prefix}-paypal:before { content: @fa-var-paypal; } +.@{fa-css-prefix}-google-wallet:before { content: @fa-var-google-wallet; } +.@{fa-css-prefix}-cc-visa:before { content: @fa-var-cc-visa; } +.@{fa-css-prefix}-cc-mastercard:before { content: @fa-var-cc-mastercard; } +.@{fa-css-prefix}-cc-discover:before { content: @fa-var-cc-discover; } +.@{fa-css-prefix}-cc-amex:before { content: @fa-var-cc-amex; } +.@{fa-css-prefix}-cc-paypal:before { content: @fa-var-cc-paypal; } +.@{fa-css-prefix}-cc-stripe:before { content: @fa-var-cc-stripe; } +.@{fa-css-prefix}-bell-slash:before { content: @fa-var-bell-slash; } +.@{fa-css-prefix}-bell-slash-o:before { content: @fa-var-bell-slash-o; } +.@{fa-css-prefix}-trash:before { content: @fa-var-trash; } +.@{fa-css-prefix}-copyright:before { content: @fa-var-copyright; } +.@{fa-css-prefix}-at:before { content: @fa-var-at; } +.@{fa-css-prefix}-eyedropper:before { content: @fa-var-eyedropper; } +.@{fa-css-prefix}-paint-brush:before { content: @fa-var-paint-brush; } +.@{fa-css-prefix}-birthday-cake:before { content: @fa-var-birthday-cake; } +.@{fa-css-prefix}-area-chart:before { content: @fa-var-area-chart; } +.@{fa-css-prefix}-pie-chart:before { content: @fa-var-pie-chart; } +.@{fa-css-prefix}-line-chart:before { content: @fa-var-line-chart; } +.@{fa-css-prefix}-lastfm:before { content: @fa-var-lastfm; } +.@{fa-css-prefix}-lastfm-square:before { content: @fa-var-lastfm-square; } +.@{fa-css-prefix}-toggle-off:before { content: @fa-var-toggle-off; } +.@{fa-css-prefix}-toggle-on:before { content: @fa-var-toggle-on; } +.@{fa-css-prefix}-bicycle:before { content: @fa-var-bicycle; } +.@{fa-css-prefix}-bus:before { content: @fa-var-bus; } +.@{fa-css-prefix}-ioxhost:before { content: @fa-var-ioxhost; } +.@{fa-css-prefix}-angellist:before { content: @fa-var-angellist; } +.@{fa-css-prefix}-cc:before { content: @fa-var-cc; } +.@{fa-css-prefix}-shekel:before, +.@{fa-css-prefix}-sheqel:before, +.@{fa-css-prefix}-ils:before { content: @fa-var-ils; } +.@{fa-css-prefix}-meanpath:before { content: @fa-var-meanpath; } +.@{fa-css-prefix}-buysellads:before { content: @fa-var-buysellads; } +.@{fa-css-prefix}-connectdevelop:before { content: @fa-var-connectdevelop; } +.@{fa-css-prefix}-dashcube:before { content: @fa-var-dashcube; } +.@{fa-css-prefix}-forumbee:before { content: @fa-var-forumbee; } +.@{fa-css-prefix}-leanpub:before { content: @fa-var-leanpub; } +.@{fa-css-prefix}-sellsy:before { content: @fa-var-sellsy; } +.@{fa-css-prefix}-shirtsinbulk:before { content: @fa-var-shirtsinbulk; } +.@{fa-css-prefix}-simplybuilt:before { content: @fa-var-simplybuilt; } +.@{fa-css-prefix}-skyatlas:before { content: @fa-var-skyatlas; } +.@{fa-css-prefix}-cart-plus:before { content: @fa-var-cart-plus; } +.@{fa-css-prefix}-cart-arrow-down:before { content: @fa-var-cart-arrow-down; } +.@{fa-css-prefix}-diamond:before { content: @fa-var-diamond; } +.@{fa-css-prefix}-ship:before { content: @fa-var-ship; } +.@{fa-css-prefix}-user-secret:before { content: @fa-var-user-secret; } +.@{fa-css-prefix}-motorcycle:before { content: @fa-var-motorcycle; } +.@{fa-css-prefix}-street-view:before { content: @fa-var-street-view; } +.@{fa-css-prefix}-heartbeat:before { content: @fa-var-heartbeat; } +.@{fa-css-prefix}-venus:before { content: @fa-var-venus; } +.@{fa-css-prefix}-mars:before { content: @fa-var-mars; } +.@{fa-css-prefix}-mercury:before { content: @fa-var-mercury; } +.@{fa-css-prefix}-intersex:before, +.@{fa-css-prefix}-transgender:before { content: @fa-var-transgender; } +.@{fa-css-prefix}-transgender-alt:before { content: @fa-var-transgender-alt; } +.@{fa-css-prefix}-venus-double:before { content: @fa-var-venus-double; } +.@{fa-css-prefix}-mars-double:before { content: @fa-var-mars-double; } +.@{fa-css-prefix}-venus-mars:before { content: @fa-var-venus-mars; } +.@{fa-css-prefix}-mars-stroke:before { content: @fa-var-mars-stroke; } +.@{fa-css-prefix}-mars-stroke-v:before { content: @fa-var-mars-stroke-v; } +.@{fa-css-prefix}-mars-stroke-h:before { content: @fa-var-mars-stroke-h; } +.@{fa-css-prefix}-neuter:before { content: @fa-var-neuter; } +.@{fa-css-prefix}-genderless:before { content: @fa-var-genderless; } +.@{fa-css-prefix}-facebook-official:before { content: @fa-var-facebook-official; } +.@{fa-css-prefix}-pinterest-p:before { content: @fa-var-pinterest-p; } +.@{fa-css-prefix}-whatsapp:before { content: @fa-var-whatsapp; } +.@{fa-css-prefix}-server:before { content: @fa-var-server; } +.@{fa-css-prefix}-user-plus:before { content: @fa-var-user-plus; } +.@{fa-css-prefix}-user-times:before { content: @fa-var-user-times; } +.@{fa-css-prefix}-hotel:before, +.@{fa-css-prefix}-bed:before { content: @fa-var-bed; } +.@{fa-css-prefix}-viacoin:before { content: @fa-var-viacoin; } +.@{fa-css-prefix}-train:before { content: @fa-var-train; } +.@{fa-css-prefix}-subway:before { content: @fa-var-subway; } +.@{fa-css-prefix}-medium:before { content: @fa-var-medium; } +.@{fa-css-prefix}-yc:before, +.@{fa-css-prefix}-y-combinator:before { content: @fa-var-y-combinator; } +.@{fa-css-prefix}-optin-monster:before { content: @fa-var-optin-monster; } +.@{fa-css-prefix}-opencart:before { content: @fa-var-opencart; } +.@{fa-css-prefix}-expeditedssl:before { content: @fa-var-expeditedssl; } +.@{fa-css-prefix}-battery-4:before, +.@{fa-css-prefix}-battery:before, +.@{fa-css-prefix}-battery-full:before { content: @fa-var-battery-full; } +.@{fa-css-prefix}-battery-3:before, +.@{fa-css-prefix}-battery-three-quarters:before { content: @fa-var-battery-three-quarters; } +.@{fa-css-prefix}-battery-2:before, +.@{fa-css-prefix}-battery-half:before { content: @fa-var-battery-half; } +.@{fa-css-prefix}-battery-1:before, +.@{fa-css-prefix}-battery-quarter:before { content: @fa-var-battery-quarter; } +.@{fa-css-prefix}-battery-0:before, +.@{fa-css-prefix}-battery-empty:before { content: @fa-var-battery-empty; } +.@{fa-css-prefix}-mouse-pointer:before { content: @fa-var-mouse-pointer; } +.@{fa-css-prefix}-i-cursor:before { content: @fa-var-i-cursor; } +.@{fa-css-prefix}-object-group:before { content: @fa-var-object-group; } +.@{fa-css-prefix}-object-ungroup:before { content: @fa-var-object-ungroup; } +.@{fa-css-prefix}-sticky-note:before { content: @fa-var-sticky-note; } +.@{fa-css-prefix}-sticky-note-o:before { content: @fa-var-sticky-note-o; } +.@{fa-css-prefix}-cc-jcb:before { content: @fa-var-cc-jcb; } +.@{fa-css-prefix}-cc-diners-club:before { content: @fa-var-cc-diners-club; } +.@{fa-css-prefix}-clone:before { content: @fa-var-clone; } +.@{fa-css-prefix}-balance-scale:before { content: @fa-var-balance-scale; } +.@{fa-css-prefix}-hourglass-o:before { content: @fa-var-hourglass-o; } +.@{fa-css-prefix}-hourglass-1:before, +.@{fa-css-prefix}-hourglass-start:before { content: @fa-var-hourglass-start; } +.@{fa-css-prefix}-hourglass-2:before, +.@{fa-css-prefix}-hourglass-half:before { content: @fa-var-hourglass-half; } +.@{fa-css-prefix}-hourglass-3:before, +.@{fa-css-prefix}-hourglass-end:before { content: @fa-var-hourglass-end; } +.@{fa-css-prefix}-hourglass:before { content: @fa-var-hourglass; } +.@{fa-css-prefix}-hand-grab-o:before, +.@{fa-css-prefix}-hand-rock-o:before { content: @fa-var-hand-rock-o; } +.@{fa-css-prefix}-hand-stop-o:before, +.@{fa-css-prefix}-hand-paper-o:before { content: @fa-var-hand-paper-o; } +.@{fa-css-prefix}-hand-scissors-o:before { content: @fa-var-hand-scissors-o; } +.@{fa-css-prefix}-hand-lizard-o:before { content: @fa-var-hand-lizard-o; } +.@{fa-css-prefix}-hand-spock-o:before { content: @fa-var-hand-spock-o; } +.@{fa-css-prefix}-hand-pointer-o:before { content: @fa-var-hand-pointer-o; } +.@{fa-css-prefix}-hand-peace-o:before { content: @fa-var-hand-peace-o; } +.@{fa-css-prefix}-trademark:before { content: @fa-var-trademark; } +.@{fa-css-prefix}-registered:before { content: @fa-var-registered; } +.@{fa-css-prefix}-creative-commons:before { content: @fa-var-creative-commons; } +.@{fa-css-prefix}-gg:before { content: @fa-var-gg; } +.@{fa-css-prefix}-gg-circle:before { content: @fa-var-gg-circle; } +.@{fa-css-prefix}-tripadvisor:before { content: @fa-var-tripadvisor; } +.@{fa-css-prefix}-odnoklassniki:before { content: @fa-var-odnoklassniki; } +.@{fa-css-prefix}-odnoklassniki-square:before { content: @fa-var-odnoklassniki-square; } +.@{fa-css-prefix}-get-pocket:before { content: @fa-var-get-pocket; } +.@{fa-css-prefix}-wikipedia-w:before { content: @fa-var-wikipedia-w; } +.@{fa-css-prefix}-safari:before { content: @fa-var-safari; } +.@{fa-css-prefix}-chrome:before { content: @fa-var-chrome; } +.@{fa-css-prefix}-firefox:before { content: @fa-var-firefox; } +.@{fa-css-prefix}-opera:before { content: @fa-var-opera; } +.@{fa-css-prefix}-internet-explorer:before { content: @fa-var-internet-explorer; } +.@{fa-css-prefix}-tv:before, +.@{fa-css-prefix}-television:before { content: @fa-var-television; } +.@{fa-css-prefix}-contao:before { content: @fa-var-contao; } +.@{fa-css-prefix}-500px:before { content: @fa-var-500px; } +.@{fa-css-prefix}-amazon:before { content: @fa-var-amazon; } +.@{fa-css-prefix}-calendar-plus-o:before { content: @fa-var-calendar-plus-o; } +.@{fa-css-prefix}-calendar-minus-o:before { content: @fa-var-calendar-minus-o; } +.@{fa-css-prefix}-calendar-times-o:before { content: @fa-var-calendar-times-o; } +.@{fa-css-prefix}-calendar-check-o:before { content: @fa-var-calendar-check-o; } +.@{fa-css-prefix}-industry:before { content: @fa-var-industry; } +.@{fa-css-prefix}-map-pin:before { content: @fa-var-map-pin; } +.@{fa-css-prefix}-map-signs:before { content: @fa-var-map-signs; } +.@{fa-css-prefix}-map-o:before { content: @fa-var-map-o; } +.@{fa-css-prefix}-map:before { content: @fa-var-map; } +.@{fa-css-prefix}-commenting:before { content: @fa-var-commenting; } +.@{fa-css-prefix}-commenting-o:before { content: @fa-var-commenting-o; } +.@{fa-css-prefix}-houzz:before { content: @fa-var-houzz; } +.@{fa-css-prefix}-vimeo:before { content: @fa-var-vimeo; } +.@{fa-css-prefix}-black-tie:before { content: @fa-var-black-tie; } +.@{fa-css-prefix}-fonticons:before { content: @fa-var-fonticons; } +.@{fa-css-prefix}-reddit-alien:before { content: @fa-var-reddit-alien; } +.@{fa-css-prefix}-edge:before { content: @fa-var-edge; } +.@{fa-css-prefix}-credit-card-alt:before { content: @fa-var-credit-card-alt; } +.@{fa-css-prefix}-codiepie:before { content: @fa-var-codiepie; } +.@{fa-css-prefix}-modx:before { content: @fa-var-modx; } +.@{fa-css-prefix}-fort-awesome:before { content: @fa-var-fort-awesome; } +.@{fa-css-prefix}-usb:before { content: @fa-var-usb; } +.@{fa-css-prefix}-product-hunt:before { content: @fa-var-product-hunt; } +.@{fa-css-prefix}-mixcloud:before { content: @fa-var-mixcloud; } +.@{fa-css-prefix}-scribd:before { content: @fa-var-scribd; } +.@{fa-css-prefix}-pause-circle:before { content: @fa-var-pause-circle; } +.@{fa-css-prefix}-pause-circle-o:before { content: @fa-var-pause-circle-o; } +.@{fa-css-prefix}-stop-circle:before { content: @fa-var-stop-circle; } +.@{fa-css-prefix}-stop-circle-o:before { content: @fa-var-stop-circle-o; } +.@{fa-css-prefix}-shopping-bag:before { content: @fa-var-shopping-bag; } +.@{fa-css-prefix}-shopping-basket:before { content: @fa-var-shopping-basket; } +.@{fa-css-prefix}-hashtag:before { content: @fa-var-hashtag; } +.@{fa-css-prefix}-bluetooth:before { content: @fa-var-bluetooth; } +.@{fa-css-prefix}-bluetooth-b:before { content: @fa-var-bluetooth-b; } +.@{fa-css-prefix}-percent:before { content: @fa-var-percent; } +.@{fa-css-prefix}-gitlab:before { content: @fa-var-gitlab; } +.@{fa-css-prefix}-wpbeginner:before { content: @fa-var-wpbeginner; } +.@{fa-css-prefix}-wpforms:before { content: @fa-var-wpforms; } +.@{fa-css-prefix}-envira:before { content: @fa-var-envira; } +.@{fa-css-prefix}-universal-access:before { content: @fa-var-universal-access; } +.@{fa-css-prefix}-wheelchair-alt:before { content: @fa-var-wheelchair-alt; } +.@{fa-css-prefix}-question-circle-o:before { content: @fa-var-question-circle-o; } +.@{fa-css-prefix}-blind:before { content: @fa-var-blind; } +.@{fa-css-prefix}-audio-description:before { content: @fa-var-audio-description; } +.@{fa-css-prefix}-volume-control-phone:before { content: @fa-var-volume-control-phone; } +.@{fa-css-prefix}-braille:before { content: @fa-var-braille; } +.@{fa-css-prefix}-assistive-listening-systems:before { content: @fa-var-assistive-listening-systems; } +.@{fa-css-prefix}-asl-interpreting:before, +.@{fa-css-prefix}-american-sign-language-interpreting:before { content: @fa-var-american-sign-language-interpreting; } +.@{fa-css-prefix}-deafness:before, +.@{fa-css-prefix}-hard-of-hearing:before, +.@{fa-css-prefix}-deaf:before { content: @fa-var-deaf; } +.@{fa-css-prefix}-glide:before { content: @fa-var-glide; } +.@{fa-css-prefix}-glide-g:before { content: @fa-var-glide-g; } +.@{fa-css-prefix}-signing:before, +.@{fa-css-prefix}-sign-language:before { content: @fa-var-sign-language; } +.@{fa-css-prefix}-low-vision:before { content: @fa-var-low-vision; } +.@{fa-css-prefix}-viadeo:before { content: @fa-var-viadeo; } +.@{fa-css-prefix}-viadeo-square:before { content: @fa-var-viadeo-square; } +.@{fa-css-prefix}-snapchat:before { content: @fa-var-snapchat; } +.@{fa-css-prefix}-snapchat-ghost:before { content: @fa-var-snapchat-ghost; } +.@{fa-css-prefix}-snapchat-square:before { content: @fa-var-snapchat-square; } +.@{fa-css-prefix}-pied-piper:before { content: @fa-var-pied-piper; } +.@{fa-css-prefix}-first-order:before { content: @fa-var-first-order; } +.@{fa-css-prefix}-yoast:before { content: @fa-var-yoast; } +.@{fa-css-prefix}-themeisle:before { content: @fa-var-themeisle; } +.@{fa-css-prefix}-google-plus-circle:before, +.@{fa-css-prefix}-google-plus-official:before { content: @fa-var-google-plus-official; } +.@{fa-css-prefix}-fa:before, +.@{fa-css-prefix}-font-awesome:before { content: @fa-var-font-awesome; } +.@{fa-css-prefix}-handshake-o:before { content: @fa-var-handshake-o; } +.@{fa-css-prefix}-envelope-open:before { content: @fa-var-envelope-open; } +.@{fa-css-prefix}-envelope-open-o:before { content: @fa-var-envelope-open-o; } +.@{fa-css-prefix}-linode:before { content: @fa-var-linode; } +.@{fa-css-prefix}-address-book:before { content: @fa-var-address-book; } +.@{fa-css-prefix}-address-book-o:before { content: @fa-var-address-book-o; } +.@{fa-css-prefix}-vcard:before, +.@{fa-css-prefix}-address-card:before { content: @fa-var-address-card; } +.@{fa-css-prefix}-vcard-o:before, +.@{fa-css-prefix}-address-card-o:before { content: @fa-var-address-card-o; } +.@{fa-css-prefix}-user-circle:before { content: @fa-var-user-circle; } +.@{fa-css-prefix}-user-circle-o:before { content: @fa-var-user-circle-o; } +.@{fa-css-prefix}-user-o:before { content: @fa-var-user-o; } +.@{fa-css-prefix}-id-badge:before { content: @fa-var-id-badge; } +.@{fa-css-prefix}-drivers-license:before, +.@{fa-css-prefix}-id-card:before { content: @fa-var-id-card; } +.@{fa-css-prefix}-drivers-license-o:before, +.@{fa-css-prefix}-id-card-o:before { content: @fa-var-id-card-o; } +.@{fa-css-prefix}-quora:before { content: @fa-var-quora; } +.@{fa-css-prefix}-free-code-camp:before { content: @fa-var-free-code-camp; } +.@{fa-css-prefix}-telegram:before { content: @fa-var-telegram; } +.@{fa-css-prefix}-thermometer-4:before, +.@{fa-css-prefix}-thermometer:before, +.@{fa-css-prefix}-thermometer-full:before { content: @fa-var-thermometer-full; } +.@{fa-css-prefix}-thermometer-3:before, +.@{fa-css-prefix}-thermometer-three-quarters:before { content: @fa-var-thermometer-three-quarters; } +.@{fa-css-prefix}-thermometer-2:before, +.@{fa-css-prefix}-thermometer-half:before { content: @fa-var-thermometer-half; } +.@{fa-css-prefix}-thermometer-1:before, +.@{fa-css-prefix}-thermometer-quarter:before { content: @fa-var-thermometer-quarter; } +.@{fa-css-prefix}-thermometer-0:before, +.@{fa-css-prefix}-thermometer-empty:before { content: @fa-var-thermometer-empty; } +.@{fa-css-prefix}-shower:before { content: @fa-var-shower; } +.@{fa-css-prefix}-bathtub:before, +.@{fa-css-prefix}-s15:before, +.@{fa-css-prefix}-bath:before { content: @fa-var-bath; } +.@{fa-css-prefix}-podcast:before { content: @fa-var-podcast; } +.@{fa-css-prefix}-window-maximize:before { content: @fa-var-window-maximize; } +.@{fa-css-prefix}-window-minimize:before { content: @fa-var-window-minimize; } +.@{fa-css-prefix}-window-restore:before { content: @fa-var-window-restore; } +.@{fa-css-prefix}-times-rectangle:before, +.@{fa-css-prefix}-window-close:before { content: @fa-var-window-close; } +.@{fa-css-prefix}-times-rectangle-o:before, +.@{fa-css-prefix}-window-close-o:before { content: @fa-var-window-close-o; } +.@{fa-css-prefix}-bandcamp:before { content: @fa-var-bandcamp; } +.@{fa-css-prefix}-grav:before { content: @fa-var-grav; } +.@{fa-css-prefix}-etsy:before { content: @fa-var-etsy; } +.@{fa-css-prefix}-imdb:before { content: @fa-var-imdb; } +.@{fa-css-prefix}-ravelry:before { content: @fa-var-ravelry; } +.@{fa-css-prefix}-eercast:before { content: @fa-var-eercast; } +.@{fa-css-prefix}-microchip:before { content: @fa-var-microchip; } +.@{fa-css-prefix}-snowflake-o:before { content: @fa-var-snowflake-o; } +.@{fa-css-prefix}-superpowers:before { content: @fa-var-superpowers; } +.@{fa-css-prefix}-wpexplorer:before { content: @fa-var-wpexplorer; } +.@{fa-css-prefix}-meetup:before { content: @fa-var-meetup; } diff --git a/web/css/font-awesome-4.7.0/less/larger.less b/web/css/font-awesome-4.7.0/less/larger.less new file mode 100644 index 000000000..c9d646770 --- /dev/null +++ b/web/css/font-awesome-4.7.0/less/larger.less @@ -0,0 +1,13 @@ +// Icon Sizes +// ------------------------- + +/* makes the font 33% larger relative to the icon container */ +.@{fa-css-prefix}-lg { + font-size: (4em / 3); + line-height: (3em / 4); + vertical-align: -15%; +} +.@{fa-css-prefix}-2x { font-size: 2em; } +.@{fa-css-prefix}-3x { font-size: 3em; } +.@{fa-css-prefix}-4x { font-size: 4em; } +.@{fa-css-prefix}-5x { font-size: 5em; } diff --git a/web/css/font-awesome-4.7.0/less/list.less b/web/css/font-awesome-4.7.0/less/list.less new file mode 100644 index 000000000..0b440382f --- /dev/null +++ b/web/css/font-awesome-4.7.0/less/list.less @@ -0,0 +1,19 @@ +// List Icons +// ------------------------- + +.@{fa-css-prefix}-ul { + padding-left: 0; + margin-left: @fa-li-width; + list-style-type: none; + > li { position: relative; } +} +.@{fa-css-prefix}-li { + position: absolute; + left: -@fa-li-width; + width: @fa-li-width; + top: (2em / 14); + text-align: center; + &.@{fa-css-prefix}-lg { + left: (-@fa-li-width + (4em / 14)); + } +} diff --git a/web/css/font-awesome-4.7.0/less/mixins.less b/web/css/font-awesome-4.7.0/less/mixins.less new file mode 100644 index 000000000..beef231d0 --- /dev/null +++ b/web/css/font-awesome-4.7.0/less/mixins.less @@ -0,0 +1,60 @@ +// Mixins +// -------------------------- + +.fa-icon() { + display: inline-block; + font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration + font-size: inherit; // can't have font-size inherit on line above, so need to override + text-rendering: auto; // optimizelegibility throws things off #1094 + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + +} + +.fa-icon-rotate(@degrees, @rotation) { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation})"; + -webkit-transform: rotate(@degrees); + -ms-transform: rotate(@degrees); + transform: rotate(@degrees); +} + +.fa-icon-flip(@horiz, @vert, @rotation) { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation}, mirror=1)"; + -webkit-transform: scale(@horiz, @vert); + -ms-transform: scale(@horiz, @vert); + transform: scale(@horiz, @vert); +} + + +// Only display content to screen readers. A la Bootstrap 4. +// +// See: http://a11yproject.com/posts/how-to-hide-content/ + +.sr-only() { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0,0,0,0); + border: 0; +} + +// Use in conjunction with .sr-only to only display content when it's focused. +// +// Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1 +// +// Credit: HTML5 Boilerplate + +.sr-only-focusable() { + &:active, + &:focus { + position: static; + width: auto; + height: auto; + margin: 0; + overflow: visible; + clip: auto; + } +} diff --git a/web/css/font-awesome-4.7.0/less/path.less b/web/css/font-awesome-4.7.0/less/path.less new file mode 100644 index 000000000..835be41f8 --- /dev/null +++ b/web/css/font-awesome-4.7.0/less/path.less @@ -0,0 +1,15 @@ +/* FONT PATH + * -------------------------- */ + +@font-face { + font-family: 'FontAwesome'; + src: url('@{fa-font-path}/fontawesome-webfont.eot?v=@{fa-version}'); + src: url('@{fa-font-path}/fontawesome-webfont.eot?#iefix&v=@{fa-version}') format('embedded-opentype'), + url('@{fa-font-path}/fontawesome-webfont.woff2?v=@{fa-version}') format('woff2'), + url('@{fa-font-path}/fontawesome-webfont.woff?v=@{fa-version}') format('woff'), + url('@{fa-font-path}/fontawesome-webfont.ttf?v=@{fa-version}') format('truetype'), + url('@{fa-font-path}/fontawesome-webfont.svg?v=@{fa-version}#fontawesomeregular') format('svg'); + // src: url('@{fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts + font-weight: normal; + font-style: normal; +} diff --git a/web/css/font-awesome-4.7.0/less/rotated-flipped.less b/web/css/font-awesome-4.7.0/less/rotated-flipped.less new file mode 100644 index 000000000..f6ba81475 --- /dev/null +++ b/web/css/font-awesome-4.7.0/less/rotated-flipped.less @@ -0,0 +1,20 @@ +// Rotated & Flipped Icons +// ------------------------- + +.@{fa-css-prefix}-rotate-90 { .fa-icon-rotate(90deg, 1); } +.@{fa-css-prefix}-rotate-180 { .fa-icon-rotate(180deg, 2); } +.@{fa-css-prefix}-rotate-270 { .fa-icon-rotate(270deg, 3); } + +.@{fa-css-prefix}-flip-horizontal { .fa-icon-flip(-1, 1, 0); } +.@{fa-css-prefix}-flip-vertical { .fa-icon-flip(1, -1, 2); } + +// Hook for IE8-9 +// ------------------------- + +:root .@{fa-css-prefix}-rotate-90, +:root .@{fa-css-prefix}-rotate-180, +:root .@{fa-css-prefix}-rotate-270, +:root .@{fa-css-prefix}-flip-horizontal, +:root .@{fa-css-prefix}-flip-vertical { + filter: none; +} diff --git a/web/css/font-awesome-4.7.0/less/screen-reader.less b/web/css/font-awesome-4.7.0/less/screen-reader.less new file mode 100644 index 000000000..11c188196 --- /dev/null +++ b/web/css/font-awesome-4.7.0/less/screen-reader.less @@ -0,0 +1,5 @@ +// Screen Readers +// ------------------------- + +.sr-only { .sr-only(); } +.sr-only-focusable { .sr-only-focusable(); } diff --git a/web/css/font-awesome-4.7.0/less/stacked.less b/web/css/font-awesome-4.7.0/less/stacked.less new file mode 100644 index 000000000..fc53fb0e7 --- /dev/null +++ b/web/css/font-awesome-4.7.0/less/stacked.less @@ -0,0 +1,20 @@ +// Stacked Icons +// ------------------------- + +.@{fa-css-prefix}-stack { + position: relative; + display: inline-block; + width: 2em; + height: 2em; + line-height: 2em; + vertical-align: middle; +} +.@{fa-css-prefix}-stack-1x, .@{fa-css-prefix}-stack-2x { + position: absolute; + left: 0; + width: 100%; + text-align: center; +} +.@{fa-css-prefix}-stack-1x { line-height: inherit; } +.@{fa-css-prefix}-stack-2x { font-size: 2em; } +.@{fa-css-prefix}-inverse { color: @fa-inverse; } diff --git a/web/css/font-awesome-4.7.0/less/variables.less b/web/css/font-awesome-4.7.0/less/variables.less new file mode 100644 index 000000000..7ddbbc011 --- /dev/null +++ b/web/css/font-awesome-4.7.0/less/variables.less @@ -0,0 +1,800 @@ +// Variables +// -------------------------- + +@fa-font-path: "../fonts"; +@fa-font-size-base: 14px; +@fa-line-height-base: 1; +//@fa-font-path: "//netdna.bootstrapcdn.com/font-awesome/4.7.0/fonts"; // for referencing Bootstrap CDN font files directly +@fa-css-prefix: fa; +@fa-version: "4.7.0"; +@fa-border-color: #eee; +@fa-inverse: #fff; +@fa-li-width: (30em / 14); + +@fa-var-500px: "\f26e"; +@fa-var-address-book: "\f2b9"; +@fa-var-address-book-o: "\f2ba"; +@fa-var-address-card: "\f2bb"; +@fa-var-address-card-o: "\f2bc"; +@fa-var-adjust: "\f042"; +@fa-var-adn: "\f170"; +@fa-var-align-center: "\f037"; +@fa-var-align-justify: "\f039"; +@fa-var-align-left: "\f036"; +@fa-var-align-right: "\f038"; +@fa-var-amazon: "\f270"; +@fa-var-ambulance: "\f0f9"; +@fa-var-american-sign-language-interpreting: "\f2a3"; +@fa-var-anchor: "\f13d"; +@fa-var-android: "\f17b"; +@fa-var-angellist: "\f209"; +@fa-var-angle-double-down: "\f103"; +@fa-var-angle-double-left: "\f100"; +@fa-var-angle-double-right: "\f101"; +@fa-var-angle-double-up: "\f102"; +@fa-var-angle-down: "\f107"; +@fa-var-angle-left: "\f104"; +@fa-var-angle-right: "\f105"; +@fa-var-angle-up: "\f106"; +@fa-var-apple: "\f179"; +@fa-var-archive: "\f187"; +@fa-var-area-chart: "\f1fe"; +@fa-var-arrow-circle-down: "\f0ab"; +@fa-var-arrow-circle-left: "\f0a8"; +@fa-var-arrow-circle-o-down: "\f01a"; +@fa-var-arrow-circle-o-left: "\f190"; +@fa-var-arrow-circle-o-right: "\f18e"; +@fa-var-arrow-circle-o-up: "\f01b"; +@fa-var-arrow-circle-right: "\f0a9"; +@fa-var-arrow-circle-up: "\f0aa"; +@fa-var-arrow-down: "\f063"; +@fa-var-arrow-left: "\f060"; +@fa-var-arrow-right: "\f061"; +@fa-var-arrow-up: "\f062"; +@fa-var-arrows: "\f047"; +@fa-var-arrows-alt: "\f0b2"; +@fa-var-arrows-h: "\f07e"; +@fa-var-arrows-v: "\f07d"; +@fa-var-asl-interpreting: "\f2a3"; +@fa-var-assistive-listening-systems: "\f2a2"; +@fa-var-asterisk: "\f069"; +@fa-var-at: "\f1fa"; +@fa-var-audio-description: "\f29e"; +@fa-var-automobile: "\f1b9"; +@fa-var-backward: "\f04a"; +@fa-var-balance-scale: "\f24e"; +@fa-var-ban: "\f05e"; +@fa-var-bandcamp: "\f2d5"; +@fa-var-bank: "\f19c"; +@fa-var-bar-chart: "\f080"; +@fa-var-bar-chart-o: "\f080"; +@fa-var-barcode: "\f02a"; +@fa-var-bars: "\f0c9"; +@fa-var-bath: "\f2cd"; +@fa-var-bathtub: "\f2cd"; +@fa-var-battery: "\f240"; +@fa-var-battery-0: "\f244"; +@fa-var-battery-1: "\f243"; +@fa-var-battery-2: "\f242"; +@fa-var-battery-3: "\f241"; +@fa-var-battery-4: "\f240"; +@fa-var-battery-empty: "\f244"; +@fa-var-battery-full: "\f240"; +@fa-var-battery-half: "\f242"; +@fa-var-battery-quarter: "\f243"; +@fa-var-battery-three-quarters: "\f241"; +@fa-var-bed: "\f236"; +@fa-var-beer: "\f0fc"; +@fa-var-behance: "\f1b4"; +@fa-var-behance-square: "\f1b5"; +@fa-var-bell: "\f0f3"; +@fa-var-bell-o: "\f0a2"; +@fa-var-bell-slash: "\f1f6"; +@fa-var-bell-slash-o: "\f1f7"; +@fa-var-bicycle: "\f206"; +@fa-var-binoculars: "\f1e5"; +@fa-var-birthday-cake: "\f1fd"; +@fa-var-bitbucket: "\f171"; +@fa-var-bitbucket-square: "\f172"; +@fa-var-bitcoin: "\f15a"; +@fa-var-black-tie: "\f27e"; +@fa-var-blind: "\f29d"; +@fa-var-bluetooth: "\f293"; +@fa-var-bluetooth-b: "\f294"; +@fa-var-bold: "\f032"; +@fa-var-bolt: "\f0e7"; +@fa-var-bomb: "\f1e2"; +@fa-var-book: "\f02d"; +@fa-var-bookmark: "\f02e"; +@fa-var-bookmark-o: "\f097"; +@fa-var-braille: "\f2a1"; +@fa-var-briefcase: "\f0b1"; +@fa-var-btc: "\f15a"; +@fa-var-bug: "\f188"; +@fa-var-building: "\f1ad"; +@fa-var-building-o: "\f0f7"; +@fa-var-bullhorn: "\f0a1"; +@fa-var-bullseye: "\f140"; +@fa-var-bus: "\f207"; +@fa-var-buysellads: "\f20d"; +@fa-var-cab: "\f1ba"; +@fa-var-calculator: "\f1ec"; +@fa-var-calendar: "\f073"; +@fa-var-calendar-check-o: "\f274"; +@fa-var-calendar-minus-o: "\f272"; +@fa-var-calendar-o: "\f133"; +@fa-var-calendar-plus-o: "\f271"; +@fa-var-calendar-times-o: "\f273"; +@fa-var-camera: "\f030"; +@fa-var-camera-retro: "\f083"; +@fa-var-car: "\f1b9"; +@fa-var-caret-down: "\f0d7"; +@fa-var-caret-left: "\f0d9"; +@fa-var-caret-right: "\f0da"; +@fa-var-caret-square-o-down: "\f150"; +@fa-var-caret-square-o-left: "\f191"; +@fa-var-caret-square-o-right: "\f152"; +@fa-var-caret-square-o-up: "\f151"; +@fa-var-caret-up: "\f0d8"; +@fa-var-cart-arrow-down: "\f218"; +@fa-var-cart-plus: "\f217"; +@fa-var-cc: "\f20a"; +@fa-var-cc-amex: "\f1f3"; +@fa-var-cc-diners-club: "\f24c"; +@fa-var-cc-discover: "\f1f2"; +@fa-var-cc-jcb: "\f24b"; +@fa-var-cc-mastercard: "\f1f1"; +@fa-var-cc-paypal: "\f1f4"; +@fa-var-cc-stripe: "\f1f5"; +@fa-var-cc-visa: "\f1f0"; +@fa-var-certificate: "\f0a3"; +@fa-var-chain: "\f0c1"; +@fa-var-chain-broken: "\f127"; +@fa-var-check: "\f00c"; +@fa-var-check-circle: "\f058"; +@fa-var-check-circle-o: "\f05d"; +@fa-var-check-square: "\f14a"; +@fa-var-check-square-o: "\f046"; +@fa-var-chevron-circle-down: "\f13a"; +@fa-var-chevron-circle-left: "\f137"; +@fa-var-chevron-circle-right: "\f138"; +@fa-var-chevron-circle-up: "\f139"; +@fa-var-chevron-down: "\f078"; +@fa-var-chevron-left: "\f053"; +@fa-var-chevron-right: "\f054"; +@fa-var-chevron-up: "\f077"; +@fa-var-child: "\f1ae"; +@fa-var-chrome: "\f268"; +@fa-var-circle: "\f111"; +@fa-var-circle-o: "\f10c"; +@fa-var-circle-o-notch: "\f1ce"; +@fa-var-circle-thin: "\f1db"; +@fa-var-clipboard: "\f0ea"; +@fa-var-clock-o: "\f017"; +@fa-var-clone: "\f24d"; +@fa-var-close: "\f00d"; +@fa-var-cloud: "\f0c2"; +@fa-var-cloud-download: "\f0ed"; +@fa-var-cloud-upload: "\f0ee"; +@fa-var-cny: "\f157"; +@fa-var-code: "\f121"; +@fa-var-code-fork: "\f126"; +@fa-var-codepen: "\f1cb"; +@fa-var-codiepie: "\f284"; +@fa-var-coffee: "\f0f4"; +@fa-var-cog: "\f013"; +@fa-var-cogs: "\f085"; +@fa-var-columns: "\f0db"; +@fa-var-comment: "\f075"; +@fa-var-comment-o: "\f0e5"; +@fa-var-commenting: "\f27a"; +@fa-var-commenting-o: "\f27b"; +@fa-var-comments: "\f086"; +@fa-var-comments-o: "\f0e6"; +@fa-var-compass: "\f14e"; +@fa-var-compress: "\f066"; +@fa-var-connectdevelop: "\f20e"; +@fa-var-contao: "\f26d"; +@fa-var-copy: "\f0c5"; +@fa-var-copyright: "\f1f9"; +@fa-var-creative-commons: "\f25e"; +@fa-var-credit-card: "\f09d"; +@fa-var-credit-card-alt: "\f283"; +@fa-var-crop: "\f125"; +@fa-var-crosshairs: "\f05b"; +@fa-var-css3: "\f13c"; +@fa-var-cube: "\f1b2"; +@fa-var-cubes: "\f1b3"; +@fa-var-cut: "\f0c4"; +@fa-var-cutlery: "\f0f5"; +@fa-var-dashboard: "\f0e4"; +@fa-var-dashcube: "\f210"; +@fa-var-database: "\f1c0"; +@fa-var-deaf: "\f2a4"; +@fa-var-deafness: "\f2a4"; +@fa-var-dedent: "\f03b"; +@fa-var-delicious: "\f1a5"; +@fa-var-desktop: "\f108"; +@fa-var-deviantart: "\f1bd"; +@fa-var-diamond: "\f219"; +@fa-var-digg: "\f1a6"; +@fa-var-dollar: "\f155"; +@fa-var-dot-circle-o: "\f192"; +@fa-var-download: "\f019"; +@fa-var-dribbble: "\f17d"; +@fa-var-drivers-license: "\f2c2"; +@fa-var-drivers-license-o: "\f2c3"; +@fa-var-dropbox: "\f16b"; +@fa-var-drupal: "\f1a9"; +@fa-var-edge: "\f282"; +@fa-var-edit: "\f044"; +@fa-var-eercast: "\f2da"; +@fa-var-eject: "\f052"; +@fa-var-ellipsis-h: "\f141"; +@fa-var-ellipsis-v: "\f142"; +@fa-var-empire: "\f1d1"; +@fa-var-envelope: "\f0e0"; +@fa-var-envelope-o: "\f003"; +@fa-var-envelope-open: "\f2b6"; +@fa-var-envelope-open-o: "\f2b7"; +@fa-var-envelope-square: "\f199"; +@fa-var-envira: "\f299"; +@fa-var-eraser: "\f12d"; +@fa-var-etsy: "\f2d7"; +@fa-var-eur: "\f153"; +@fa-var-euro: "\f153"; +@fa-var-exchange: "\f0ec"; +@fa-var-exclamation: "\f12a"; +@fa-var-exclamation-circle: "\f06a"; +@fa-var-exclamation-triangle: "\f071"; +@fa-var-expand: "\f065"; +@fa-var-expeditedssl: "\f23e"; +@fa-var-external-link: "\f08e"; +@fa-var-external-link-square: "\f14c"; +@fa-var-eye: "\f06e"; +@fa-var-eye-slash: "\f070"; +@fa-var-eyedropper: "\f1fb"; +@fa-var-fa: "\f2b4"; +@fa-var-facebook: "\f09a"; +@fa-var-facebook-f: "\f09a"; +@fa-var-facebook-official: "\f230"; +@fa-var-facebook-square: "\f082"; +@fa-var-fast-backward: "\f049"; +@fa-var-fast-forward: "\f050"; +@fa-var-fax: "\f1ac"; +@fa-var-feed: "\f09e"; +@fa-var-female: "\f182"; +@fa-var-fighter-jet: "\f0fb"; +@fa-var-file: "\f15b"; +@fa-var-file-archive-o: "\f1c6"; +@fa-var-file-audio-o: "\f1c7"; +@fa-var-file-code-o: "\f1c9"; +@fa-var-file-excel-o: "\f1c3"; +@fa-var-file-image-o: "\f1c5"; +@fa-var-file-movie-o: "\f1c8"; +@fa-var-file-o: "\f016"; +@fa-var-file-pdf-o: "\f1c1"; +@fa-var-file-photo-o: "\f1c5"; +@fa-var-file-picture-o: "\f1c5"; +@fa-var-file-powerpoint-o: "\f1c4"; +@fa-var-file-sound-o: "\f1c7"; +@fa-var-file-text: "\f15c"; +@fa-var-file-text-o: "\f0f6"; +@fa-var-file-video-o: "\f1c8"; +@fa-var-file-word-o: "\f1c2"; +@fa-var-file-zip-o: "\f1c6"; +@fa-var-files-o: "\f0c5"; +@fa-var-film: "\f008"; +@fa-var-filter: "\f0b0"; +@fa-var-fire: "\f06d"; +@fa-var-fire-extinguisher: "\f134"; +@fa-var-firefox: "\f269"; +@fa-var-first-order: "\f2b0"; +@fa-var-flag: "\f024"; +@fa-var-flag-checkered: "\f11e"; +@fa-var-flag-o: "\f11d"; +@fa-var-flash: "\f0e7"; +@fa-var-flask: "\f0c3"; +@fa-var-flickr: "\f16e"; +@fa-var-floppy-o: "\f0c7"; +@fa-var-folder: "\f07b"; +@fa-var-folder-o: "\f114"; +@fa-var-folder-open: "\f07c"; +@fa-var-folder-open-o: "\f115"; +@fa-var-font: "\f031"; +@fa-var-font-awesome: "\f2b4"; +@fa-var-fonticons: "\f280"; +@fa-var-fort-awesome: "\f286"; +@fa-var-forumbee: "\f211"; +@fa-var-forward: "\f04e"; +@fa-var-foursquare: "\f180"; +@fa-var-free-code-camp: "\f2c5"; +@fa-var-frown-o: "\f119"; +@fa-var-futbol-o: "\f1e3"; +@fa-var-gamepad: "\f11b"; +@fa-var-gavel: "\f0e3"; +@fa-var-gbp: "\f154"; +@fa-var-ge: "\f1d1"; +@fa-var-gear: "\f013"; +@fa-var-gears: "\f085"; +@fa-var-genderless: "\f22d"; +@fa-var-get-pocket: "\f265"; +@fa-var-gg: "\f260"; +@fa-var-gg-circle: "\f261"; +@fa-var-gift: "\f06b"; +@fa-var-git: "\f1d3"; +@fa-var-git-square: "\f1d2"; +@fa-var-github: "\f09b"; +@fa-var-github-alt: "\f113"; +@fa-var-github-square: "\f092"; +@fa-var-gitlab: "\f296"; +@fa-var-gittip: "\f184"; +@fa-var-glass: "\f000"; +@fa-var-glide: "\f2a5"; +@fa-var-glide-g: "\f2a6"; +@fa-var-globe: "\f0ac"; +@fa-var-google: "\f1a0"; +@fa-var-google-plus: "\f0d5"; +@fa-var-google-plus-circle: "\f2b3"; +@fa-var-google-plus-official: "\f2b3"; +@fa-var-google-plus-square: "\f0d4"; +@fa-var-google-wallet: "\f1ee"; +@fa-var-graduation-cap: "\f19d"; +@fa-var-gratipay: "\f184"; +@fa-var-grav: "\f2d6"; +@fa-var-group: "\f0c0"; +@fa-var-h-square: "\f0fd"; +@fa-var-hacker-news: "\f1d4"; +@fa-var-hand-grab-o: "\f255"; +@fa-var-hand-lizard-o: "\f258"; +@fa-var-hand-o-down: "\f0a7"; +@fa-var-hand-o-left: "\f0a5"; +@fa-var-hand-o-right: "\f0a4"; +@fa-var-hand-o-up: "\f0a6"; +@fa-var-hand-paper-o: "\f256"; +@fa-var-hand-peace-o: "\f25b"; +@fa-var-hand-pointer-o: "\f25a"; +@fa-var-hand-rock-o: "\f255"; +@fa-var-hand-scissors-o: "\f257"; +@fa-var-hand-spock-o: "\f259"; +@fa-var-hand-stop-o: "\f256"; +@fa-var-handshake-o: "\f2b5"; +@fa-var-hard-of-hearing: "\f2a4"; +@fa-var-hashtag: "\f292"; +@fa-var-hdd-o: "\f0a0"; +@fa-var-header: "\f1dc"; +@fa-var-headphones: "\f025"; +@fa-var-heart: "\f004"; +@fa-var-heart-o: "\f08a"; +@fa-var-heartbeat: "\f21e"; +@fa-var-history: "\f1da"; +@fa-var-home: "\f015"; +@fa-var-hospital-o: "\f0f8"; +@fa-var-hotel: "\f236"; +@fa-var-hourglass: "\f254"; +@fa-var-hourglass-1: "\f251"; +@fa-var-hourglass-2: "\f252"; +@fa-var-hourglass-3: "\f253"; +@fa-var-hourglass-end: "\f253"; +@fa-var-hourglass-half: "\f252"; +@fa-var-hourglass-o: "\f250"; +@fa-var-hourglass-start: "\f251"; +@fa-var-houzz: "\f27c"; +@fa-var-html5: "\f13b"; +@fa-var-i-cursor: "\f246"; +@fa-var-id-badge: "\f2c1"; +@fa-var-id-card: "\f2c2"; +@fa-var-id-card-o: "\f2c3"; +@fa-var-ils: "\f20b"; +@fa-var-image: "\f03e"; +@fa-var-imdb: "\f2d8"; +@fa-var-inbox: "\f01c"; +@fa-var-indent: "\f03c"; +@fa-var-industry: "\f275"; +@fa-var-info: "\f129"; +@fa-var-info-circle: "\f05a"; +@fa-var-inr: "\f156"; +@fa-var-instagram: "\f16d"; +@fa-var-institution: "\f19c"; +@fa-var-internet-explorer: "\f26b"; +@fa-var-intersex: "\f224"; +@fa-var-ioxhost: "\f208"; +@fa-var-italic: "\f033"; +@fa-var-joomla: "\f1aa"; +@fa-var-jpy: "\f157"; +@fa-var-jsfiddle: "\f1cc"; +@fa-var-key: "\f084"; +@fa-var-keyboard-o: "\f11c"; +@fa-var-krw: "\f159"; +@fa-var-language: "\f1ab"; +@fa-var-laptop: "\f109"; +@fa-var-lastfm: "\f202"; +@fa-var-lastfm-square: "\f203"; +@fa-var-leaf: "\f06c"; +@fa-var-leanpub: "\f212"; +@fa-var-legal: "\f0e3"; +@fa-var-lemon-o: "\f094"; +@fa-var-level-down: "\f149"; +@fa-var-level-up: "\f148"; +@fa-var-life-bouy: "\f1cd"; +@fa-var-life-buoy: "\f1cd"; +@fa-var-life-ring: "\f1cd"; +@fa-var-life-saver: "\f1cd"; +@fa-var-lightbulb-o: "\f0eb"; +@fa-var-line-chart: "\f201"; +@fa-var-link: "\f0c1"; +@fa-var-linkedin: "\f0e1"; +@fa-var-linkedin-square: "\f08c"; +@fa-var-linode: "\f2b8"; +@fa-var-linux: "\f17c"; +@fa-var-list: "\f03a"; +@fa-var-list-alt: "\f022"; +@fa-var-list-ol: "\f0cb"; +@fa-var-list-ul: "\f0ca"; +@fa-var-location-arrow: "\f124"; +@fa-var-lock: "\f023"; +@fa-var-long-arrow-down: "\f175"; +@fa-var-long-arrow-left: "\f177"; +@fa-var-long-arrow-right: "\f178"; +@fa-var-long-arrow-up: "\f176"; +@fa-var-low-vision: "\f2a8"; +@fa-var-magic: "\f0d0"; +@fa-var-magnet: "\f076"; +@fa-var-mail-forward: "\f064"; +@fa-var-mail-reply: "\f112"; +@fa-var-mail-reply-all: "\f122"; +@fa-var-male: "\f183"; +@fa-var-map: "\f279"; +@fa-var-map-marker: "\f041"; +@fa-var-map-o: "\f278"; +@fa-var-map-pin: "\f276"; +@fa-var-map-signs: "\f277"; +@fa-var-mars: "\f222"; +@fa-var-mars-double: "\f227"; +@fa-var-mars-stroke: "\f229"; +@fa-var-mars-stroke-h: "\f22b"; +@fa-var-mars-stroke-v: "\f22a"; +@fa-var-maxcdn: "\f136"; +@fa-var-meanpath: "\f20c"; +@fa-var-medium: "\f23a"; +@fa-var-medkit: "\f0fa"; +@fa-var-meetup: "\f2e0"; +@fa-var-meh-o: "\f11a"; +@fa-var-mercury: "\f223"; +@fa-var-microchip: "\f2db"; +@fa-var-microphone: "\f130"; +@fa-var-microphone-slash: "\f131"; +@fa-var-minus: "\f068"; +@fa-var-minus-circle: "\f056"; +@fa-var-minus-square: "\f146"; +@fa-var-minus-square-o: "\f147"; +@fa-var-mixcloud: "\f289"; +@fa-var-mobile: "\f10b"; +@fa-var-mobile-phone: "\f10b"; +@fa-var-modx: "\f285"; +@fa-var-money: "\f0d6"; +@fa-var-moon-o: "\f186"; +@fa-var-mortar-board: "\f19d"; +@fa-var-motorcycle: "\f21c"; +@fa-var-mouse-pointer: "\f245"; +@fa-var-music: "\f001"; +@fa-var-navicon: "\f0c9"; +@fa-var-neuter: "\f22c"; +@fa-var-newspaper-o: "\f1ea"; +@fa-var-object-group: "\f247"; +@fa-var-object-ungroup: "\f248"; +@fa-var-odnoklassniki: "\f263"; +@fa-var-odnoklassniki-square: "\f264"; +@fa-var-opencart: "\f23d"; +@fa-var-openid: "\f19b"; +@fa-var-opera: "\f26a"; +@fa-var-optin-monster: "\f23c"; +@fa-var-outdent: "\f03b"; +@fa-var-pagelines: "\f18c"; +@fa-var-paint-brush: "\f1fc"; +@fa-var-paper-plane: "\f1d8"; +@fa-var-paper-plane-o: "\f1d9"; +@fa-var-paperclip: "\f0c6"; +@fa-var-paragraph: "\f1dd"; +@fa-var-paste: "\f0ea"; +@fa-var-pause: "\f04c"; +@fa-var-pause-circle: "\f28b"; +@fa-var-pause-circle-o: "\f28c"; +@fa-var-paw: "\f1b0"; +@fa-var-paypal: "\f1ed"; +@fa-var-pencil: "\f040"; +@fa-var-pencil-square: "\f14b"; +@fa-var-pencil-square-o: "\f044"; +@fa-var-percent: "\f295"; +@fa-var-phone: "\f095"; +@fa-var-phone-square: "\f098"; +@fa-var-photo: "\f03e"; +@fa-var-picture-o: "\f03e"; +@fa-var-pie-chart: "\f200"; +@fa-var-pied-piper: "\f2ae"; +@fa-var-pied-piper-alt: "\f1a8"; +@fa-var-pied-piper-pp: "\f1a7"; +@fa-var-pinterest: "\f0d2"; +@fa-var-pinterest-p: "\f231"; +@fa-var-pinterest-square: "\f0d3"; +@fa-var-plane: "\f072"; +@fa-var-play: "\f04b"; +@fa-var-play-circle: "\f144"; +@fa-var-play-circle-o: "\f01d"; +@fa-var-plug: "\f1e6"; +@fa-var-plus: "\f067"; +@fa-var-plus-circle: "\f055"; +@fa-var-plus-square: "\f0fe"; +@fa-var-plus-square-o: "\f196"; +@fa-var-podcast: "\f2ce"; +@fa-var-power-off: "\f011"; +@fa-var-print: "\f02f"; +@fa-var-product-hunt: "\f288"; +@fa-var-puzzle-piece: "\f12e"; +@fa-var-qq: "\f1d6"; +@fa-var-qrcode: "\f029"; +@fa-var-question: "\f128"; +@fa-var-question-circle: "\f059"; +@fa-var-question-circle-o: "\f29c"; +@fa-var-quora: "\f2c4"; +@fa-var-quote-left: "\f10d"; +@fa-var-quote-right: "\f10e"; +@fa-var-ra: "\f1d0"; +@fa-var-random: "\f074"; +@fa-var-ravelry: "\f2d9"; +@fa-var-rebel: "\f1d0"; +@fa-var-recycle: "\f1b8"; +@fa-var-reddit: "\f1a1"; +@fa-var-reddit-alien: "\f281"; +@fa-var-reddit-square: "\f1a2"; +@fa-var-refresh: "\f021"; +@fa-var-registered: "\f25d"; +@fa-var-remove: "\f00d"; +@fa-var-renren: "\f18b"; +@fa-var-reorder: "\f0c9"; +@fa-var-repeat: "\f01e"; +@fa-var-reply: "\f112"; +@fa-var-reply-all: "\f122"; +@fa-var-resistance: "\f1d0"; +@fa-var-retweet: "\f079"; +@fa-var-rmb: "\f157"; +@fa-var-road: "\f018"; +@fa-var-rocket: "\f135"; +@fa-var-rotate-left: "\f0e2"; +@fa-var-rotate-right: "\f01e"; +@fa-var-rouble: "\f158"; +@fa-var-rss: "\f09e"; +@fa-var-rss-square: "\f143"; +@fa-var-rub: "\f158"; +@fa-var-ruble: "\f158"; +@fa-var-rupee: "\f156"; +@fa-var-s15: "\f2cd"; +@fa-var-safari: "\f267"; +@fa-var-save: "\f0c7"; +@fa-var-scissors: "\f0c4"; +@fa-var-scribd: "\f28a"; +@fa-var-search: "\f002"; +@fa-var-search-minus: "\f010"; +@fa-var-search-plus: "\f00e"; +@fa-var-sellsy: "\f213"; +@fa-var-send: "\f1d8"; +@fa-var-send-o: "\f1d9"; +@fa-var-server: "\f233"; +@fa-var-share: "\f064"; +@fa-var-share-alt: "\f1e0"; +@fa-var-share-alt-square: "\f1e1"; +@fa-var-share-square: "\f14d"; +@fa-var-share-square-o: "\f045"; +@fa-var-shekel: "\f20b"; +@fa-var-sheqel: "\f20b"; +@fa-var-shield: "\f132"; +@fa-var-ship: "\f21a"; +@fa-var-shirtsinbulk: "\f214"; +@fa-var-shopping-bag: "\f290"; +@fa-var-shopping-basket: "\f291"; +@fa-var-shopping-cart: "\f07a"; +@fa-var-shower: "\f2cc"; +@fa-var-sign-in: "\f090"; +@fa-var-sign-language: "\f2a7"; +@fa-var-sign-out: "\f08b"; +@fa-var-signal: "\f012"; +@fa-var-signing: "\f2a7"; +@fa-var-simplybuilt: "\f215"; +@fa-var-sitemap: "\f0e8"; +@fa-var-skyatlas: "\f216"; +@fa-var-skype: "\f17e"; +@fa-var-slack: "\f198"; +@fa-var-sliders: "\f1de"; +@fa-var-slideshare: "\f1e7"; +@fa-var-smile-o: "\f118"; +@fa-var-snapchat: "\f2ab"; +@fa-var-snapchat-ghost: "\f2ac"; +@fa-var-snapchat-square: "\f2ad"; +@fa-var-snowflake-o: "\f2dc"; +@fa-var-soccer-ball-o: "\f1e3"; +@fa-var-sort: "\f0dc"; +@fa-var-sort-alpha-asc: "\f15d"; +@fa-var-sort-alpha-desc: "\f15e"; +@fa-var-sort-amount-asc: "\f160"; +@fa-var-sort-amount-desc: "\f161"; +@fa-var-sort-asc: "\f0de"; +@fa-var-sort-desc: "\f0dd"; +@fa-var-sort-down: "\f0dd"; +@fa-var-sort-numeric-asc: "\f162"; +@fa-var-sort-numeric-desc: "\f163"; +@fa-var-sort-up: "\f0de"; +@fa-var-soundcloud: "\f1be"; +@fa-var-space-shuttle: "\f197"; +@fa-var-spinner: "\f110"; +@fa-var-spoon: "\f1b1"; +@fa-var-spotify: "\f1bc"; +@fa-var-square: "\f0c8"; +@fa-var-square-o: "\f096"; +@fa-var-stack-exchange: "\f18d"; +@fa-var-stack-overflow: "\f16c"; +@fa-var-star: "\f005"; +@fa-var-star-half: "\f089"; +@fa-var-star-half-empty: "\f123"; +@fa-var-star-half-full: "\f123"; +@fa-var-star-half-o: "\f123"; +@fa-var-star-o: "\f006"; +@fa-var-steam: "\f1b6"; +@fa-var-steam-square: "\f1b7"; +@fa-var-step-backward: "\f048"; +@fa-var-step-forward: "\f051"; +@fa-var-stethoscope: "\f0f1"; +@fa-var-sticky-note: "\f249"; +@fa-var-sticky-note-o: "\f24a"; +@fa-var-stop: "\f04d"; +@fa-var-stop-circle: "\f28d"; +@fa-var-stop-circle-o: "\f28e"; +@fa-var-street-view: "\f21d"; +@fa-var-strikethrough: "\f0cc"; +@fa-var-stumbleupon: "\f1a4"; +@fa-var-stumbleupon-circle: "\f1a3"; +@fa-var-subscript: "\f12c"; +@fa-var-subway: "\f239"; +@fa-var-suitcase: "\f0f2"; +@fa-var-sun-o: "\f185"; +@fa-var-superpowers: "\f2dd"; +@fa-var-superscript: "\f12b"; +@fa-var-support: "\f1cd"; +@fa-var-table: "\f0ce"; +@fa-var-tablet: "\f10a"; +@fa-var-tachometer: "\f0e4"; +@fa-var-tag: "\f02b"; +@fa-var-tags: "\f02c"; +@fa-var-tasks: "\f0ae"; +@fa-var-taxi: "\f1ba"; +@fa-var-telegram: "\f2c6"; +@fa-var-television: "\f26c"; +@fa-var-tencent-weibo: "\f1d5"; +@fa-var-terminal: "\f120"; +@fa-var-text-height: "\f034"; +@fa-var-text-width: "\f035"; +@fa-var-th: "\f00a"; +@fa-var-th-large: "\f009"; +@fa-var-th-list: "\f00b"; +@fa-var-themeisle: "\f2b2"; +@fa-var-thermometer: "\f2c7"; +@fa-var-thermometer-0: "\f2cb"; +@fa-var-thermometer-1: "\f2ca"; +@fa-var-thermometer-2: "\f2c9"; +@fa-var-thermometer-3: "\f2c8"; +@fa-var-thermometer-4: "\f2c7"; +@fa-var-thermometer-empty: "\f2cb"; +@fa-var-thermometer-full: "\f2c7"; +@fa-var-thermometer-half: "\f2c9"; +@fa-var-thermometer-quarter: "\f2ca"; +@fa-var-thermometer-three-quarters: "\f2c8"; +@fa-var-thumb-tack: "\f08d"; +@fa-var-thumbs-down: "\f165"; +@fa-var-thumbs-o-down: "\f088"; +@fa-var-thumbs-o-up: "\f087"; +@fa-var-thumbs-up: "\f164"; +@fa-var-ticket: "\f145"; +@fa-var-times: "\f00d"; +@fa-var-times-circle: "\f057"; +@fa-var-times-circle-o: "\f05c"; +@fa-var-times-rectangle: "\f2d3"; +@fa-var-times-rectangle-o: "\f2d4"; +@fa-var-tint: "\f043"; +@fa-var-toggle-down: "\f150"; +@fa-var-toggle-left: "\f191"; +@fa-var-toggle-off: "\f204"; +@fa-var-toggle-on: "\f205"; +@fa-var-toggle-right: "\f152"; +@fa-var-toggle-up: "\f151"; +@fa-var-trademark: "\f25c"; +@fa-var-train: "\f238"; +@fa-var-transgender: "\f224"; +@fa-var-transgender-alt: "\f225"; +@fa-var-trash: "\f1f8"; +@fa-var-trash-o: "\f014"; +@fa-var-tree: "\f1bb"; +@fa-var-trello: "\f181"; +@fa-var-tripadvisor: "\f262"; +@fa-var-trophy: "\f091"; +@fa-var-truck: "\f0d1"; +@fa-var-try: "\f195"; +@fa-var-tty: "\f1e4"; +@fa-var-tumblr: "\f173"; +@fa-var-tumblr-square: "\f174"; +@fa-var-turkish-lira: "\f195"; +@fa-var-tv: "\f26c"; +@fa-var-twitch: "\f1e8"; +@fa-var-twitter: "\f099"; +@fa-var-twitter-square: "\f081"; +@fa-var-umbrella: "\f0e9"; +@fa-var-underline: "\f0cd"; +@fa-var-undo: "\f0e2"; +@fa-var-universal-access: "\f29a"; +@fa-var-university: "\f19c"; +@fa-var-unlink: "\f127"; +@fa-var-unlock: "\f09c"; +@fa-var-unlock-alt: "\f13e"; +@fa-var-unsorted: "\f0dc"; +@fa-var-upload: "\f093"; +@fa-var-usb: "\f287"; +@fa-var-usd: "\f155"; +@fa-var-user: "\f007"; +@fa-var-user-circle: "\f2bd"; +@fa-var-user-circle-o: "\f2be"; +@fa-var-user-md: "\f0f0"; +@fa-var-user-o: "\f2c0"; +@fa-var-user-plus: "\f234"; +@fa-var-user-secret: "\f21b"; +@fa-var-user-times: "\f235"; +@fa-var-users: "\f0c0"; +@fa-var-vcard: "\f2bb"; +@fa-var-vcard-o: "\f2bc"; +@fa-var-venus: "\f221"; +@fa-var-venus-double: "\f226"; +@fa-var-venus-mars: "\f228"; +@fa-var-viacoin: "\f237"; +@fa-var-viadeo: "\f2a9"; +@fa-var-viadeo-square: "\f2aa"; +@fa-var-video-camera: "\f03d"; +@fa-var-vimeo: "\f27d"; +@fa-var-vimeo-square: "\f194"; +@fa-var-vine: "\f1ca"; +@fa-var-vk: "\f189"; +@fa-var-volume-control-phone: "\f2a0"; +@fa-var-volume-down: "\f027"; +@fa-var-volume-off: "\f026"; +@fa-var-volume-up: "\f028"; +@fa-var-warning: "\f071"; +@fa-var-wechat: "\f1d7"; +@fa-var-weibo: "\f18a"; +@fa-var-weixin: "\f1d7"; +@fa-var-whatsapp: "\f232"; +@fa-var-wheelchair: "\f193"; +@fa-var-wheelchair-alt: "\f29b"; +@fa-var-wifi: "\f1eb"; +@fa-var-wikipedia-w: "\f266"; +@fa-var-window-close: "\f2d3"; +@fa-var-window-close-o: "\f2d4"; +@fa-var-window-maximize: "\f2d0"; +@fa-var-window-minimize: "\f2d1"; +@fa-var-window-restore: "\f2d2"; +@fa-var-windows: "\f17a"; +@fa-var-won: "\f159"; +@fa-var-wordpress: "\f19a"; +@fa-var-wpbeginner: "\f297"; +@fa-var-wpexplorer: "\f2de"; +@fa-var-wpforms: "\f298"; +@fa-var-wrench: "\f0ad"; +@fa-var-xing: "\f168"; +@fa-var-xing-square: "\f169"; +@fa-var-y-combinator: "\f23b"; +@fa-var-y-combinator-square: "\f1d4"; +@fa-var-yahoo: "\f19e"; +@fa-var-yc: "\f23b"; +@fa-var-yc-square: "\f1d4"; +@fa-var-yelp: "\f1e9"; +@fa-var-yen: "\f157"; +@fa-var-yoast: "\f2b1"; +@fa-var-youtube: "\f167"; +@fa-var-youtube-play: "\f16a"; +@fa-var-youtube-square: "\f166"; + diff --git a/web/css/font-awesome-4.7.0/scss/_animated.scss b/web/css/font-awesome-4.7.0/scss/_animated.scss new file mode 100644 index 000000000..8a020dbff --- /dev/null +++ b/web/css/font-awesome-4.7.0/scss/_animated.scss @@ -0,0 +1,34 @@ +// Spinning Icons +// -------------------------- + +.#{$fa-css-prefix}-spin { + -webkit-animation: fa-spin 2s infinite linear; + animation: fa-spin 2s infinite linear; +} + +.#{$fa-css-prefix}-pulse { + -webkit-animation: fa-spin 1s infinite steps(8); + animation: fa-spin 1s infinite steps(8); +} + +@-webkit-keyframes fa-spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} + +@keyframes fa-spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} diff --git a/web/css/font-awesome-4.7.0/scss/_bordered-pulled.scss b/web/css/font-awesome-4.7.0/scss/_bordered-pulled.scss new file mode 100644 index 000000000..d4b85a02f --- /dev/null +++ b/web/css/font-awesome-4.7.0/scss/_bordered-pulled.scss @@ -0,0 +1,25 @@ +// Bordered & Pulled +// ------------------------- + +.#{$fa-css-prefix}-border { + padding: .2em .25em .15em; + border: solid .08em $fa-border-color; + border-radius: .1em; +} + +.#{$fa-css-prefix}-pull-left { float: left; } +.#{$fa-css-prefix}-pull-right { float: right; } + +.#{$fa-css-prefix} { + &.#{$fa-css-prefix}-pull-left { margin-right: .3em; } + &.#{$fa-css-prefix}-pull-right { margin-left: .3em; } +} + +/* Deprecated as of 4.4.0 */ +.pull-right { float: right; } +.pull-left { float: left; } + +.#{$fa-css-prefix} { + &.pull-left { margin-right: .3em; } + &.pull-right { margin-left: .3em; } +} diff --git a/web/css/font-awesome-4.7.0/scss/_core.scss b/web/css/font-awesome-4.7.0/scss/_core.scss new file mode 100644 index 000000000..7425ef85f --- /dev/null +++ b/web/css/font-awesome-4.7.0/scss/_core.scss @@ -0,0 +1,12 @@ +// Base Class Definition +// ------------------------- + +.#{$fa-css-prefix} { + display: inline-block; + font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration + font-size: inherit; // can't have font-size inherit on line above, so need to override + text-rendering: auto; // optimizelegibility throws things off #1094 + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + +} diff --git a/web/css/font-awesome-4.7.0/scss/_fixed-width.scss b/web/css/font-awesome-4.7.0/scss/_fixed-width.scss new file mode 100644 index 000000000..b221c9813 --- /dev/null +++ b/web/css/font-awesome-4.7.0/scss/_fixed-width.scss @@ -0,0 +1,6 @@ +// Fixed Width Icons +// ------------------------- +.#{$fa-css-prefix}-fw { + width: (18em / 14); + text-align: center; +} diff --git a/web/css/font-awesome-4.7.0/scss/_icons.scss b/web/css/font-awesome-4.7.0/scss/_icons.scss new file mode 100644 index 000000000..e63e702c4 --- /dev/null +++ b/web/css/font-awesome-4.7.0/scss/_icons.scss @@ -0,0 +1,789 @@ +/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen + readers do not read off random characters that represent icons */ + +.#{$fa-css-prefix}-glass:before { content: $fa-var-glass; } +.#{$fa-css-prefix}-music:before { content: $fa-var-music; } +.#{$fa-css-prefix}-search:before { content: $fa-var-search; } +.#{$fa-css-prefix}-envelope-o:before { content: $fa-var-envelope-o; } +.#{$fa-css-prefix}-heart:before { content: $fa-var-heart; } +.#{$fa-css-prefix}-star:before { content: $fa-var-star; } +.#{$fa-css-prefix}-star-o:before { content: $fa-var-star-o; } +.#{$fa-css-prefix}-user:before { content: $fa-var-user; } +.#{$fa-css-prefix}-film:before { content: $fa-var-film; } +.#{$fa-css-prefix}-th-large:before { content: $fa-var-th-large; } +.#{$fa-css-prefix}-th:before { content: $fa-var-th; } +.#{$fa-css-prefix}-th-list:before { content: $fa-var-th-list; } +.#{$fa-css-prefix}-check:before { content: $fa-var-check; } +.#{$fa-css-prefix}-remove:before, +.#{$fa-css-prefix}-close:before, +.#{$fa-css-prefix}-times:before { content: $fa-var-times; } +.#{$fa-css-prefix}-search-plus:before { content: $fa-var-search-plus; } +.#{$fa-css-prefix}-search-minus:before { content: $fa-var-search-minus; } +.#{$fa-css-prefix}-power-off:before { content: $fa-var-power-off; } +.#{$fa-css-prefix}-signal:before { content: $fa-var-signal; } +.#{$fa-css-prefix}-gear:before, +.#{$fa-css-prefix}-cog:before { content: $fa-var-cog; } +.#{$fa-css-prefix}-trash-o:before { content: $fa-var-trash-o; } +.#{$fa-css-prefix}-home:before { content: $fa-var-home; } +.#{$fa-css-prefix}-file-o:before { content: $fa-var-file-o; } +.#{$fa-css-prefix}-clock-o:before { content: $fa-var-clock-o; } +.#{$fa-css-prefix}-road:before { content: $fa-var-road; } +.#{$fa-css-prefix}-download:before { content: $fa-var-download; } +.#{$fa-css-prefix}-arrow-circle-o-down:before { content: $fa-var-arrow-circle-o-down; } +.#{$fa-css-prefix}-arrow-circle-o-up:before { content: $fa-var-arrow-circle-o-up; } +.#{$fa-css-prefix}-inbox:before { content: $fa-var-inbox; } +.#{$fa-css-prefix}-play-circle-o:before { content: $fa-var-play-circle-o; } +.#{$fa-css-prefix}-rotate-right:before, +.#{$fa-css-prefix}-repeat:before { content: $fa-var-repeat; } +.#{$fa-css-prefix}-refresh:before { content: $fa-var-refresh; } +.#{$fa-css-prefix}-list-alt:before { content: $fa-var-list-alt; } +.#{$fa-css-prefix}-lock:before { content: $fa-var-lock; } +.#{$fa-css-prefix}-flag:before { content: $fa-var-flag; } +.#{$fa-css-prefix}-headphones:before { content: $fa-var-headphones; } +.#{$fa-css-prefix}-volume-off:before { content: $fa-var-volume-off; } +.#{$fa-css-prefix}-volume-down:before { content: $fa-var-volume-down; } +.#{$fa-css-prefix}-volume-up:before { content: $fa-var-volume-up; } +.#{$fa-css-prefix}-qrcode:before { content: $fa-var-qrcode; } +.#{$fa-css-prefix}-barcode:before { content: $fa-var-barcode; } +.#{$fa-css-prefix}-tag:before { content: $fa-var-tag; } +.#{$fa-css-prefix}-tags:before { content: $fa-var-tags; } +.#{$fa-css-prefix}-book:before { content: $fa-var-book; } +.#{$fa-css-prefix}-bookmark:before { content: $fa-var-bookmark; } +.#{$fa-css-prefix}-print:before { content: $fa-var-print; } +.#{$fa-css-prefix}-camera:before { content: $fa-var-camera; } +.#{$fa-css-prefix}-font:before { content: $fa-var-font; } +.#{$fa-css-prefix}-bold:before { content: $fa-var-bold; } +.#{$fa-css-prefix}-italic:before { content: $fa-var-italic; } +.#{$fa-css-prefix}-text-height:before { content: $fa-var-text-height; } +.#{$fa-css-prefix}-text-width:before { content: $fa-var-text-width; } +.#{$fa-css-prefix}-align-left:before { content: $fa-var-align-left; } +.#{$fa-css-prefix}-align-center:before { content: $fa-var-align-center; } +.#{$fa-css-prefix}-align-right:before { content: $fa-var-align-right; } +.#{$fa-css-prefix}-align-justify:before { content: $fa-var-align-justify; } +.#{$fa-css-prefix}-list:before { content: $fa-var-list; } +.#{$fa-css-prefix}-dedent:before, +.#{$fa-css-prefix}-outdent:before { content: $fa-var-outdent; } +.#{$fa-css-prefix}-indent:before { content: $fa-var-indent; } +.#{$fa-css-prefix}-video-camera:before { content: $fa-var-video-camera; } +.#{$fa-css-prefix}-photo:before, +.#{$fa-css-prefix}-image:before, +.#{$fa-css-prefix}-picture-o:before { content: $fa-var-picture-o; } +.#{$fa-css-prefix}-pencil:before { content: $fa-var-pencil; } +.#{$fa-css-prefix}-map-marker:before { content: $fa-var-map-marker; } +.#{$fa-css-prefix}-adjust:before { content: $fa-var-adjust; } +.#{$fa-css-prefix}-tint:before { content: $fa-var-tint; } +.#{$fa-css-prefix}-edit:before, +.#{$fa-css-prefix}-pencil-square-o:before { content: $fa-var-pencil-square-o; } +.#{$fa-css-prefix}-share-square-o:before { content: $fa-var-share-square-o; } +.#{$fa-css-prefix}-check-square-o:before { content: $fa-var-check-square-o; } +.#{$fa-css-prefix}-arrows:before { content: $fa-var-arrows; } +.#{$fa-css-prefix}-step-backward:before { content: $fa-var-step-backward; } +.#{$fa-css-prefix}-fast-backward:before { content: $fa-var-fast-backward; } +.#{$fa-css-prefix}-backward:before { content: $fa-var-backward; } +.#{$fa-css-prefix}-play:before { content: $fa-var-play; } +.#{$fa-css-prefix}-pause:before { content: $fa-var-pause; } +.#{$fa-css-prefix}-stop:before { content: $fa-var-stop; } +.#{$fa-css-prefix}-forward:before { content: $fa-var-forward; } +.#{$fa-css-prefix}-fast-forward:before { content: $fa-var-fast-forward; } +.#{$fa-css-prefix}-step-forward:before { content: $fa-var-step-forward; } +.#{$fa-css-prefix}-eject:before { content: $fa-var-eject; } +.#{$fa-css-prefix}-chevron-left:before { content: $fa-var-chevron-left; } +.#{$fa-css-prefix}-chevron-right:before { content: $fa-var-chevron-right; } +.#{$fa-css-prefix}-plus-circle:before { content: $fa-var-plus-circle; } +.#{$fa-css-prefix}-minus-circle:before { content: $fa-var-minus-circle; } +.#{$fa-css-prefix}-times-circle:before { content: $fa-var-times-circle; } +.#{$fa-css-prefix}-check-circle:before { content: $fa-var-check-circle; } +.#{$fa-css-prefix}-question-circle:before { content: $fa-var-question-circle; } +.#{$fa-css-prefix}-info-circle:before { content: $fa-var-info-circle; } +.#{$fa-css-prefix}-crosshairs:before { content: $fa-var-crosshairs; } +.#{$fa-css-prefix}-times-circle-o:before { content: $fa-var-times-circle-o; } +.#{$fa-css-prefix}-check-circle-o:before { content: $fa-var-check-circle-o; } +.#{$fa-css-prefix}-ban:before { content: $fa-var-ban; } +.#{$fa-css-prefix}-arrow-left:before { content: $fa-var-arrow-left; } +.#{$fa-css-prefix}-arrow-right:before { content: $fa-var-arrow-right; } +.#{$fa-css-prefix}-arrow-up:before { content: $fa-var-arrow-up; } +.#{$fa-css-prefix}-arrow-down:before { content: $fa-var-arrow-down; } +.#{$fa-css-prefix}-mail-forward:before, +.#{$fa-css-prefix}-share:before { content: $fa-var-share; } +.#{$fa-css-prefix}-expand:before { content: $fa-var-expand; } +.#{$fa-css-prefix}-compress:before { content: $fa-var-compress; } +.#{$fa-css-prefix}-plus:before { content: $fa-var-plus; } +.#{$fa-css-prefix}-minus:before { content: $fa-var-minus; } +.#{$fa-css-prefix}-asterisk:before { content: $fa-var-asterisk; } +.#{$fa-css-prefix}-exclamation-circle:before { content: $fa-var-exclamation-circle; } +.#{$fa-css-prefix}-gift:before { content: $fa-var-gift; } +.#{$fa-css-prefix}-leaf:before { content: $fa-var-leaf; } +.#{$fa-css-prefix}-fire:before { content: $fa-var-fire; } +.#{$fa-css-prefix}-eye:before { content: $fa-var-eye; } +.#{$fa-css-prefix}-eye-slash:before { content: $fa-var-eye-slash; } +.#{$fa-css-prefix}-warning:before, +.#{$fa-css-prefix}-exclamation-triangle:before { content: $fa-var-exclamation-triangle; } +.#{$fa-css-prefix}-plane:before { content: $fa-var-plane; } +.#{$fa-css-prefix}-calendar:before { content: $fa-var-calendar; } +.#{$fa-css-prefix}-random:before { content: $fa-var-random; } +.#{$fa-css-prefix}-comment:before { content: $fa-var-comment; } +.#{$fa-css-prefix}-magnet:before { content: $fa-var-magnet; } +.#{$fa-css-prefix}-chevron-up:before { content: $fa-var-chevron-up; } +.#{$fa-css-prefix}-chevron-down:before { content: $fa-var-chevron-down; } +.#{$fa-css-prefix}-retweet:before { content: $fa-var-retweet; } +.#{$fa-css-prefix}-shopping-cart:before { content: $fa-var-shopping-cart; } +.#{$fa-css-prefix}-folder:before { content: $fa-var-folder; } +.#{$fa-css-prefix}-folder-open:before { content: $fa-var-folder-open; } +.#{$fa-css-prefix}-arrows-v:before { content: $fa-var-arrows-v; } +.#{$fa-css-prefix}-arrows-h:before { content: $fa-var-arrows-h; } +.#{$fa-css-prefix}-bar-chart-o:before, +.#{$fa-css-prefix}-bar-chart:before { content: $fa-var-bar-chart; } +.#{$fa-css-prefix}-twitter-square:before { content: $fa-var-twitter-square; } +.#{$fa-css-prefix}-facebook-square:before { content: $fa-var-facebook-square; } +.#{$fa-css-prefix}-camera-retro:before { content: $fa-var-camera-retro; } +.#{$fa-css-prefix}-key:before { content: $fa-var-key; } +.#{$fa-css-prefix}-gears:before, +.#{$fa-css-prefix}-cogs:before { content: $fa-var-cogs; } +.#{$fa-css-prefix}-comments:before { content: $fa-var-comments; } +.#{$fa-css-prefix}-thumbs-o-up:before { content: $fa-var-thumbs-o-up; } +.#{$fa-css-prefix}-thumbs-o-down:before { content: $fa-var-thumbs-o-down; } +.#{$fa-css-prefix}-star-half:before { content: $fa-var-star-half; } +.#{$fa-css-prefix}-heart-o:before { content: $fa-var-heart-o; } +.#{$fa-css-prefix}-sign-out:before { content: $fa-var-sign-out; } +.#{$fa-css-prefix}-linkedin-square:before { content: $fa-var-linkedin-square; } +.#{$fa-css-prefix}-thumb-tack:before { content: $fa-var-thumb-tack; } +.#{$fa-css-prefix}-external-link:before { content: $fa-var-external-link; } +.#{$fa-css-prefix}-sign-in:before { content: $fa-var-sign-in; } +.#{$fa-css-prefix}-trophy:before { content: $fa-var-trophy; } +.#{$fa-css-prefix}-github-square:before { content: $fa-var-github-square; } +.#{$fa-css-prefix}-upload:before { content: $fa-var-upload; } +.#{$fa-css-prefix}-lemon-o:before { content: $fa-var-lemon-o; } +.#{$fa-css-prefix}-phone:before { content: $fa-var-phone; } +.#{$fa-css-prefix}-square-o:before { content: $fa-var-square-o; } +.#{$fa-css-prefix}-bookmark-o:before { content: $fa-var-bookmark-o; } +.#{$fa-css-prefix}-phone-square:before { content: $fa-var-phone-square; } +.#{$fa-css-prefix}-twitter:before { content: $fa-var-twitter; } +.#{$fa-css-prefix}-facebook-f:before, +.#{$fa-css-prefix}-facebook:before { content: $fa-var-facebook; } +.#{$fa-css-prefix}-github:before { content: $fa-var-github; } +.#{$fa-css-prefix}-unlock:before { content: $fa-var-unlock; } +.#{$fa-css-prefix}-credit-card:before { content: $fa-var-credit-card; } +.#{$fa-css-prefix}-feed:before, +.#{$fa-css-prefix}-rss:before { content: $fa-var-rss; } +.#{$fa-css-prefix}-hdd-o:before { content: $fa-var-hdd-o; } +.#{$fa-css-prefix}-bullhorn:before { content: $fa-var-bullhorn; } +.#{$fa-css-prefix}-bell:before { content: $fa-var-bell; } +.#{$fa-css-prefix}-certificate:before { content: $fa-var-certificate; } +.#{$fa-css-prefix}-hand-o-right:before { content: $fa-var-hand-o-right; } +.#{$fa-css-prefix}-hand-o-left:before { content: $fa-var-hand-o-left; } +.#{$fa-css-prefix}-hand-o-up:before { content: $fa-var-hand-o-up; } +.#{$fa-css-prefix}-hand-o-down:before { content: $fa-var-hand-o-down; } +.#{$fa-css-prefix}-arrow-circle-left:before { content: $fa-var-arrow-circle-left; } +.#{$fa-css-prefix}-arrow-circle-right:before { content: $fa-var-arrow-circle-right; } +.#{$fa-css-prefix}-arrow-circle-up:before { content: $fa-var-arrow-circle-up; } +.#{$fa-css-prefix}-arrow-circle-down:before { content: $fa-var-arrow-circle-down; } +.#{$fa-css-prefix}-globe:before { content: $fa-var-globe; } +.#{$fa-css-prefix}-wrench:before { content: $fa-var-wrench; } +.#{$fa-css-prefix}-tasks:before { content: $fa-var-tasks; } +.#{$fa-css-prefix}-filter:before { content: $fa-var-filter; } +.#{$fa-css-prefix}-briefcase:before { content: $fa-var-briefcase; } +.#{$fa-css-prefix}-arrows-alt:before { content: $fa-var-arrows-alt; } +.#{$fa-css-prefix}-group:before, +.#{$fa-css-prefix}-users:before { content: $fa-var-users; } +.#{$fa-css-prefix}-chain:before, +.#{$fa-css-prefix}-link:before { content: $fa-var-link; } +.#{$fa-css-prefix}-cloud:before { content: $fa-var-cloud; } +.#{$fa-css-prefix}-flask:before { content: $fa-var-flask; } +.#{$fa-css-prefix}-cut:before, +.#{$fa-css-prefix}-scissors:before { content: $fa-var-scissors; } +.#{$fa-css-prefix}-copy:before, +.#{$fa-css-prefix}-files-o:before { content: $fa-var-files-o; } +.#{$fa-css-prefix}-paperclip:before { content: $fa-var-paperclip; } +.#{$fa-css-prefix}-save:before, +.#{$fa-css-prefix}-floppy-o:before { content: $fa-var-floppy-o; } +.#{$fa-css-prefix}-square:before { content: $fa-var-square; } +.#{$fa-css-prefix}-navicon:before, +.#{$fa-css-prefix}-reorder:before, +.#{$fa-css-prefix}-bars:before { content: $fa-var-bars; } +.#{$fa-css-prefix}-list-ul:before { content: $fa-var-list-ul; } +.#{$fa-css-prefix}-list-ol:before { content: $fa-var-list-ol; } +.#{$fa-css-prefix}-strikethrough:before { content: $fa-var-strikethrough; } +.#{$fa-css-prefix}-underline:before { content: $fa-var-underline; } +.#{$fa-css-prefix}-table:before { content: $fa-var-table; } +.#{$fa-css-prefix}-magic:before { content: $fa-var-magic; } +.#{$fa-css-prefix}-truck:before { content: $fa-var-truck; } +.#{$fa-css-prefix}-pinterest:before { content: $fa-var-pinterest; } +.#{$fa-css-prefix}-pinterest-square:before { content: $fa-var-pinterest-square; } +.#{$fa-css-prefix}-google-plus-square:before { content: $fa-var-google-plus-square; } +.#{$fa-css-prefix}-google-plus:before { content: $fa-var-google-plus; } +.#{$fa-css-prefix}-money:before { content: $fa-var-money; } +.#{$fa-css-prefix}-caret-down:before { content: $fa-var-caret-down; } +.#{$fa-css-prefix}-caret-up:before { content: $fa-var-caret-up; } +.#{$fa-css-prefix}-caret-left:before { content: $fa-var-caret-left; } +.#{$fa-css-prefix}-caret-right:before { content: $fa-var-caret-right; } +.#{$fa-css-prefix}-columns:before { content: $fa-var-columns; } +.#{$fa-css-prefix}-unsorted:before, +.#{$fa-css-prefix}-sort:before { content: $fa-var-sort; } +.#{$fa-css-prefix}-sort-down:before, +.#{$fa-css-prefix}-sort-desc:before { content: $fa-var-sort-desc; } +.#{$fa-css-prefix}-sort-up:before, +.#{$fa-css-prefix}-sort-asc:before { content: $fa-var-sort-asc; } +.#{$fa-css-prefix}-envelope:before { content: $fa-var-envelope; } +.#{$fa-css-prefix}-linkedin:before { content: $fa-var-linkedin; } +.#{$fa-css-prefix}-rotate-left:before, +.#{$fa-css-prefix}-undo:before { content: $fa-var-undo; } +.#{$fa-css-prefix}-legal:before, +.#{$fa-css-prefix}-gavel:before { content: $fa-var-gavel; } +.#{$fa-css-prefix}-dashboard:before, +.#{$fa-css-prefix}-tachometer:before { content: $fa-var-tachometer; } +.#{$fa-css-prefix}-comment-o:before { content: $fa-var-comment-o; } +.#{$fa-css-prefix}-comments-o:before { content: $fa-var-comments-o; } +.#{$fa-css-prefix}-flash:before, +.#{$fa-css-prefix}-bolt:before { content: $fa-var-bolt; } +.#{$fa-css-prefix}-sitemap:before { content: $fa-var-sitemap; } +.#{$fa-css-prefix}-umbrella:before { content: $fa-var-umbrella; } +.#{$fa-css-prefix}-paste:before, +.#{$fa-css-prefix}-clipboard:before { content: $fa-var-clipboard; } +.#{$fa-css-prefix}-lightbulb-o:before { content: $fa-var-lightbulb-o; } +.#{$fa-css-prefix}-exchange:before { content: $fa-var-exchange; } +.#{$fa-css-prefix}-cloud-download:before { content: $fa-var-cloud-download; } +.#{$fa-css-prefix}-cloud-upload:before { content: $fa-var-cloud-upload; } +.#{$fa-css-prefix}-user-md:before { content: $fa-var-user-md; } +.#{$fa-css-prefix}-stethoscope:before { content: $fa-var-stethoscope; } +.#{$fa-css-prefix}-suitcase:before { content: $fa-var-suitcase; } +.#{$fa-css-prefix}-bell-o:before { content: $fa-var-bell-o; } +.#{$fa-css-prefix}-coffee:before { content: $fa-var-coffee; } +.#{$fa-css-prefix}-cutlery:before { content: $fa-var-cutlery; } +.#{$fa-css-prefix}-file-text-o:before { content: $fa-var-file-text-o; } +.#{$fa-css-prefix}-building-o:before { content: $fa-var-building-o; } +.#{$fa-css-prefix}-hospital-o:before { content: $fa-var-hospital-o; } +.#{$fa-css-prefix}-ambulance:before { content: $fa-var-ambulance; } +.#{$fa-css-prefix}-medkit:before { content: $fa-var-medkit; } +.#{$fa-css-prefix}-fighter-jet:before { content: $fa-var-fighter-jet; } +.#{$fa-css-prefix}-beer:before { content: $fa-var-beer; } +.#{$fa-css-prefix}-h-square:before { content: $fa-var-h-square; } +.#{$fa-css-prefix}-plus-square:before { content: $fa-var-plus-square; } +.#{$fa-css-prefix}-angle-double-left:before { content: $fa-var-angle-double-left; } +.#{$fa-css-prefix}-angle-double-right:before { content: $fa-var-angle-double-right; } +.#{$fa-css-prefix}-angle-double-up:before { content: $fa-var-angle-double-up; } +.#{$fa-css-prefix}-angle-double-down:before { content: $fa-var-angle-double-down; } +.#{$fa-css-prefix}-angle-left:before { content: $fa-var-angle-left; } +.#{$fa-css-prefix}-angle-right:before { content: $fa-var-angle-right; } +.#{$fa-css-prefix}-angle-up:before { content: $fa-var-angle-up; } +.#{$fa-css-prefix}-angle-down:before { content: $fa-var-angle-down; } +.#{$fa-css-prefix}-desktop:before { content: $fa-var-desktop; } +.#{$fa-css-prefix}-laptop:before { content: $fa-var-laptop; } +.#{$fa-css-prefix}-tablet:before { content: $fa-var-tablet; } +.#{$fa-css-prefix}-mobile-phone:before, +.#{$fa-css-prefix}-mobile:before { content: $fa-var-mobile; } +.#{$fa-css-prefix}-circle-o:before { content: $fa-var-circle-o; } +.#{$fa-css-prefix}-quote-left:before { content: $fa-var-quote-left; } +.#{$fa-css-prefix}-quote-right:before { content: $fa-var-quote-right; } +.#{$fa-css-prefix}-spinner:before { content: $fa-var-spinner; } +.#{$fa-css-prefix}-circle:before { content: $fa-var-circle; } +.#{$fa-css-prefix}-mail-reply:before, +.#{$fa-css-prefix}-reply:before { content: $fa-var-reply; } +.#{$fa-css-prefix}-github-alt:before { content: $fa-var-github-alt; } +.#{$fa-css-prefix}-folder-o:before { content: $fa-var-folder-o; } +.#{$fa-css-prefix}-folder-open-o:before { content: $fa-var-folder-open-o; } +.#{$fa-css-prefix}-smile-o:before { content: $fa-var-smile-o; } +.#{$fa-css-prefix}-frown-o:before { content: $fa-var-frown-o; } +.#{$fa-css-prefix}-meh-o:before { content: $fa-var-meh-o; } +.#{$fa-css-prefix}-gamepad:before { content: $fa-var-gamepad; } +.#{$fa-css-prefix}-keyboard-o:before { content: $fa-var-keyboard-o; } +.#{$fa-css-prefix}-flag-o:before { content: $fa-var-flag-o; } +.#{$fa-css-prefix}-flag-checkered:before { content: $fa-var-flag-checkered; } +.#{$fa-css-prefix}-terminal:before { content: $fa-var-terminal; } +.#{$fa-css-prefix}-code:before { content: $fa-var-code; } +.#{$fa-css-prefix}-mail-reply-all:before, +.#{$fa-css-prefix}-reply-all:before { content: $fa-var-reply-all; } +.#{$fa-css-prefix}-star-half-empty:before, +.#{$fa-css-prefix}-star-half-full:before, +.#{$fa-css-prefix}-star-half-o:before { content: $fa-var-star-half-o; } +.#{$fa-css-prefix}-location-arrow:before { content: $fa-var-location-arrow; } +.#{$fa-css-prefix}-crop:before { content: $fa-var-crop; } +.#{$fa-css-prefix}-code-fork:before { content: $fa-var-code-fork; } +.#{$fa-css-prefix}-unlink:before, +.#{$fa-css-prefix}-chain-broken:before { content: $fa-var-chain-broken; } +.#{$fa-css-prefix}-question:before { content: $fa-var-question; } +.#{$fa-css-prefix}-info:before { content: $fa-var-info; } +.#{$fa-css-prefix}-exclamation:before { content: $fa-var-exclamation; } +.#{$fa-css-prefix}-superscript:before { content: $fa-var-superscript; } +.#{$fa-css-prefix}-subscript:before { content: $fa-var-subscript; } +.#{$fa-css-prefix}-eraser:before { content: $fa-var-eraser; } +.#{$fa-css-prefix}-puzzle-piece:before { content: $fa-var-puzzle-piece; } +.#{$fa-css-prefix}-microphone:before { content: $fa-var-microphone; } +.#{$fa-css-prefix}-microphone-slash:before { content: $fa-var-microphone-slash; } +.#{$fa-css-prefix}-shield:before { content: $fa-var-shield; } +.#{$fa-css-prefix}-calendar-o:before { content: $fa-var-calendar-o; } +.#{$fa-css-prefix}-fire-extinguisher:before { content: $fa-var-fire-extinguisher; } +.#{$fa-css-prefix}-rocket:before { content: $fa-var-rocket; } +.#{$fa-css-prefix}-maxcdn:before { content: $fa-var-maxcdn; } +.#{$fa-css-prefix}-chevron-circle-left:before { content: $fa-var-chevron-circle-left; } +.#{$fa-css-prefix}-chevron-circle-right:before { content: $fa-var-chevron-circle-right; } +.#{$fa-css-prefix}-chevron-circle-up:before { content: $fa-var-chevron-circle-up; } +.#{$fa-css-prefix}-chevron-circle-down:before { content: $fa-var-chevron-circle-down; } +.#{$fa-css-prefix}-html5:before { content: $fa-var-html5; } +.#{$fa-css-prefix}-css3:before { content: $fa-var-css3; } +.#{$fa-css-prefix}-anchor:before { content: $fa-var-anchor; } +.#{$fa-css-prefix}-unlock-alt:before { content: $fa-var-unlock-alt; } +.#{$fa-css-prefix}-bullseye:before { content: $fa-var-bullseye; } +.#{$fa-css-prefix}-ellipsis-h:before { content: $fa-var-ellipsis-h; } +.#{$fa-css-prefix}-ellipsis-v:before { content: $fa-var-ellipsis-v; } +.#{$fa-css-prefix}-rss-square:before { content: $fa-var-rss-square; } +.#{$fa-css-prefix}-play-circle:before { content: $fa-var-play-circle; } +.#{$fa-css-prefix}-ticket:before { content: $fa-var-ticket; } +.#{$fa-css-prefix}-minus-square:before { content: $fa-var-minus-square; } +.#{$fa-css-prefix}-minus-square-o:before { content: $fa-var-minus-square-o; } +.#{$fa-css-prefix}-level-up:before { content: $fa-var-level-up; } +.#{$fa-css-prefix}-level-down:before { content: $fa-var-level-down; } +.#{$fa-css-prefix}-check-square:before { content: $fa-var-check-square; } +.#{$fa-css-prefix}-pencil-square:before { content: $fa-var-pencil-square; } +.#{$fa-css-prefix}-external-link-square:before { content: $fa-var-external-link-square; } +.#{$fa-css-prefix}-share-square:before { content: $fa-var-share-square; } +.#{$fa-css-prefix}-compass:before { content: $fa-var-compass; } +.#{$fa-css-prefix}-toggle-down:before, +.#{$fa-css-prefix}-caret-square-o-down:before { content: $fa-var-caret-square-o-down; } +.#{$fa-css-prefix}-toggle-up:before, +.#{$fa-css-prefix}-caret-square-o-up:before { content: $fa-var-caret-square-o-up; } +.#{$fa-css-prefix}-toggle-right:before, +.#{$fa-css-prefix}-caret-square-o-right:before { content: $fa-var-caret-square-o-right; } +.#{$fa-css-prefix}-euro:before, +.#{$fa-css-prefix}-eur:before { content: $fa-var-eur; } +.#{$fa-css-prefix}-gbp:before { content: $fa-var-gbp; } +.#{$fa-css-prefix}-dollar:before, +.#{$fa-css-prefix}-usd:before { content: $fa-var-usd; } +.#{$fa-css-prefix}-rupee:before, +.#{$fa-css-prefix}-inr:before { content: $fa-var-inr; } +.#{$fa-css-prefix}-cny:before, +.#{$fa-css-prefix}-rmb:before, +.#{$fa-css-prefix}-yen:before, +.#{$fa-css-prefix}-jpy:before { content: $fa-var-jpy; } +.#{$fa-css-prefix}-ruble:before, +.#{$fa-css-prefix}-rouble:before, +.#{$fa-css-prefix}-rub:before { content: $fa-var-rub; } +.#{$fa-css-prefix}-won:before, +.#{$fa-css-prefix}-krw:before { content: $fa-var-krw; } +.#{$fa-css-prefix}-bitcoin:before, +.#{$fa-css-prefix}-btc:before { content: $fa-var-btc; } +.#{$fa-css-prefix}-file:before { content: $fa-var-file; } +.#{$fa-css-prefix}-file-text:before { content: $fa-var-file-text; } +.#{$fa-css-prefix}-sort-alpha-asc:before { content: $fa-var-sort-alpha-asc; } +.#{$fa-css-prefix}-sort-alpha-desc:before { content: $fa-var-sort-alpha-desc; } +.#{$fa-css-prefix}-sort-amount-asc:before { content: $fa-var-sort-amount-asc; } +.#{$fa-css-prefix}-sort-amount-desc:before { content: $fa-var-sort-amount-desc; } +.#{$fa-css-prefix}-sort-numeric-asc:before { content: $fa-var-sort-numeric-asc; } +.#{$fa-css-prefix}-sort-numeric-desc:before { content: $fa-var-sort-numeric-desc; } +.#{$fa-css-prefix}-thumbs-up:before { content: $fa-var-thumbs-up; } +.#{$fa-css-prefix}-thumbs-down:before { content: $fa-var-thumbs-down; } +.#{$fa-css-prefix}-youtube-square:before { content: $fa-var-youtube-square; } +.#{$fa-css-prefix}-youtube:before { content: $fa-var-youtube; } +.#{$fa-css-prefix}-xing:before { content: $fa-var-xing; } +.#{$fa-css-prefix}-xing-square:before { content: $fa-var-xing-square; } +.#{$fa-css-prefix}-youtube-play:before { content: $fa-var-youtube-play; } +.#{$fa-css-prefix}-dropbox:before { content: $fa-var-dropbox; } +.#{$fa-css-prefix}-stack-overflow:before { content: $fa-var-stack-overflow; } +.#{$fa-css-prefix}-instagram:before { content: $fa-var-instagram; } +.#{$fa-css-prefix}-flickr:before { content: $fa-var-flickr; } +.#{$fa-css-prefix}-adn:before { content: $fa-var-adn; } +.#{$fa-css-prefix}-bitbucket:before { content: $fa-var-bitbucket; } +.#{$fa-css-prefix}-bitbucket-square:before { content: $fa-var-bitbucket-square; } +.#{$fa-css-prefix}-tumblr:before { content: $fa-var-tumblr; } +.#{$fa-css-prefix}-tumblr-square:before { content: $fa-var-tumblr-square; } +.#{$fa-css-prefix}-long-arrow-down:before { content: $fa-var-long-arrow-down; } +.#{$fa-css-prefix}-long-arrow-up:before { content: $fa-var-long-arrow-up; } +.#{$fa-css-prefix}-long-arrow-left:before { content: $fa-var-long-arrow-left; } +.#{$fa-css-prefix}-long-arrow-right:before { content: $fa-var-long-arrow-right; } +.#{$fa-css-prefix}-apple:before { content: $fa-var-apple; } +.#{$fa-css-prefix}-windows:before { content: $fa-var-windows; } +.#{$fa-css-prefix}-android:before { content: $fa-var-android; } +.#{$fa-css-prefix}-linux:before { content: $fa-var-linux; } +.#{$fa-css-prefix}-dribbble:before { content: $fa-var-dribbble; } +.#{$fa-css-prefix}-skype:before { content: $fa-var-skype; } +.#{$fa-css-prefix}-foursquare:before { content: $fa-var-foursquare; } +.#{$fa-css-prefix}-trello:before { content: $fa-var-trello; } +.#{$fa-css-prefix}-female:before { content: $fa-var-female; } +.#{$fa-css-prefix}-male:before { content: $fa-var-male; } +.#{$fa-css-prefix}-gittip:before, +.#{$fa-css-prefix}-gratipay:before { content: $fa-var-gratipay; } +.#{$fa-css-prefix}-sun-o:before { content: $fa-var-sun-o; } +.#{$fa-css-prefix}-moon-o:before { content: $fa-var-moon-o; } +.#{$fa-css-prefix}-archive:before { content: $fa-var-archive; } +.#{$fa-css-prefix}-bug:before { content: $fa-var-bug; } +.#{$fa-css-prefix}-vk:before { content: $fa-var-vk; } +.#{$fa-css-prefix}-weibo:before { content: $fa-var-weibo; } +.#{$fa-css-prefix}-renren:before { content: $fa-var-renren; } +.#{$fa-css-prefix}-pagelines:before { content: $fa-var-pagelines; } +.#{$fa-css-prefix}-stack-exchange:before { content: $fa-var-stack-exchange; } +.#{$fa-css-prefix}-arrow-circle-o-right:before { content: $fa-var-arrow-circle-o-right; } +.#{$fa-css-prefix}-arrow-circle-o-left:before { content: $fa-var-arrow-circle-o-left; } +.#{$fa-css-prefix}-toggle-left:before, +.#{$fa-css-prefix}-caret-square-o-left:before { content: $fa-var-caret-square-o-left; } +.#{$fa-css-prefix}-dot-circle-o:before { content: $fa-var-dot-circle-o; } +.#{$fa-css-prefix}-wheelchair:before { content: $fa-var-wheelchair; } +.#{$fa-css-prefix}-vimeo-square:before { content: $fa-var-vimeo-square; } +.#{$fa-css-prefix}-turkish-lira:before, +.#{$fa-css-prefix}-try:before { content: $fa-var-try; } +.#{$fa-css-prefix}-plus-square-o:before { content: $fa-var-plus-square-o; } +.#{$fa-css-prefix}-space-shuttle:before { content: $fa-var-space-shuttle; } +.#{$fa-css-prefix}-slack:before { content: $fa-var-slack; } +.#{$fa-css-prefix}-envelope-square:before { content: $fa-var-envelope-square; } +.#{$fa-css-prefix}-wordpress:before { content: $fa-var-wordpress; } +.#{$fa-css-prefix}-openid:before { content: $fa-var-openid; } +.#{$fa-css-prefix}-institution:before, +.#{$fa-css-prefix}-bank:before, +.#{$fa-css-prefix}-university:before { content: $fa-var-university; } +.#{$fa-css-prefix}-mortar-board:before, +.#{$fa-css-prefix}-graduation-cap:before { content: $fa-var-graduation-cap; } +.#{$fa-css-prefix}-yahoo:before { content: $fa-var-yahoo; } +.#{$fa-css-prefix}-google:before { content: $fa-var-google; } +.#{$fa-css-prefix}-reddit:before { content: $fa-var-reddit; } +.#{$fa-css-prefix}-reddit-square:before { content: $fa-var-reddit-square; } +.#{$fa-css-prefix}-stumbleupon-circle:before { content: $fa-var-stumbleupon-circle; } +.#{$fa-css-prefix}-stumbleupon:before { content: $fa-var-stumbleupon; } +.#{$fa-css-prefix}-delicious:before { content: $fa-var-delicious; } +.#{$fa-css-prefix}-digg:before { content: $fa-var-digg; } +.#{$fa-css-prefix}-pied-piper-pp:before { content: $fa-var-pied-piper-pp; } +.#{$fa-css-prefix}-pied-piper-alt:before { content: $fa-var-pied-piper-alt; } +.#{$fa-css-prefix}-drupal:before { content: $fa-var-drupal; } +.#{$fa-css-prefix}-joomla:before { content: $fa-var-joomla; } +.#{$fa-css-prefix}-language:before { content: $fa-var-language; } +.#{$fa-css-prefix}-fax:before { content: $fa-var-fax; } +.#{$fa-css-prefix}-building:before { content: $fa-var-building; } +.#{$fa-css-prefix}-child:before { content: $fa-var-child; } +.#{$fa-css-prefix}-paw:before { content: $fa-var-paw; } +.#{$fa-css-prefix}-spoon:before { content: $fa-var-spoon; } +.#{$fa-css-prefix}-cube:before { content: $fa-var-cube; } +.#{$fa-css-prefix}-cubes:before { content: $fa-var-cubes; } +.#{$fa-css-prefix}-behance:before { content: $fa-var-behance; } +.#{$fa-css-prefix}-behance-square:before { content: $fa-var-behance-square; } +.#{$fa-css-prefix}-steam:before { content: $fa-var-steam; } +.#{$fa-css-prefix}-steam-square:before { content: $fa-var-steam-square; } +.#{$fa-css-prefix}-recycle:before { content: $fa-var-recycle; } +.#{$fa-css-prefix}-automobile:before, +.#{$fa-css-prefix}-car:before { content: $fa-var-car; } +.#{$fa-css-prefix}-cab:before, +.#{$fa-css-prefix}-taxi:before { content: $fa-var-taxi; } +.#{$fa-css-prefix}-tree:before { content: $fa-var-tree; } +.#{$fa-css-prefix}-spotify:before { content: $fa-var-spotify; } +.#{$fa-css-prefix}-deviantart:before { content: $fa-var-deviantart; } +.#{$fa-css-prefix}-soundcloud:before { content: $fa-var-soundcloud; } +.#{$fa-css-prefix}-database:before { content: $fa-var-database; } +.#{$fa-css-prefix}-file-pdf-o:before { content: $fa-var-file-pdf-o; } +.#{$fa-css-prefix}-file-word-o:before { content: $fa-var-file-word-o; } +.#{$fa-css-prefix}-file-excel-o:before { content: $fa-var-file-excel-o; } +.#{$fa-css-prefix}-file-powerpoint-o:before { content: $fa-var-file-powerpoint-o; } +.#{$fa-css-prefix}-file-photo-o:before, +.#{$fa-css-prefix}-file-picture-o:before, +.#{$fa-css-prefix}-file-image-o:before { content: $fa-var-file-image-o; } +.#{$fa-css-prefix}-file-zip-o:before, +.#{$fa-css-prefix}-file-archive-o:before { content: $fa-var-file-archive-o; } +.#{$fa-css-prefix}-file-sound-o:before, +.#{$fa-css-prefix}-file-audio-o:before { content: $fa-var-file-audio-o; } +.#{$fa-css-prefix}-file-movie-o:before, +.#{$fa-css-prefix}-file-video-o:before { content: $fa-var-file-video-o; } +.#{$fa-css-prefix}-file-code-o:before { content: $fa-var-file-code-o; } +.#{$fa-css-prefix}-vine:before { content: $fa-var-vine; } +.#{$fa-css-prefix}-codepen:before { content: $fa-var-codepen; } +.#{$fa-css-prefix}-jsfiddle:before { content: $fa-var-jsfiddle; } +.#{$fa-css-prefix}-life-bouy:before, +.#{$fa-css-prefix}-life-buoy:before, +.#{$fa-css-prefix}-life-saver:before, +.#{$fa-css-prefix}-support:before, +.#{$fa-css-prefix}-life-ring:before { content: $fa-var-life-ring; } +.#{$fa-css-prefix}-circle-o-notch:before { content: $fa-var-circle-o-notch; } +.#{$fa-css-prefix}-ra:before, +.#{$fa-css-prefix}-resistance:before, +.#{$fa-css-prefix}-rebel:before { content: $fa-var-rebel; } +.#{$fa-css-prefix}-ge:before, +.#{$fa-css-prefix}-empire:before { content: $fa-var-empire; } +.#{$fa-css-prefix}-git-square:before { content: $fa-var-git-square; } +.#{$fa-css-prefix}-git:before { content: $fa-var-git; } +.#{$fa-css-prefix}-y-combinator-square:before, +.#{$fa-css-prefix}-yc-square:before, +.#{$fa-css-prefix}-hacker-news:before { content: $fa-var-hacker-news; } +.#{$fa-css-prefix}-tencent-weibo:before { content: $fa-var-tencent-weibo; } +.#{$fa-css-prefix}-qq:before { content: $fa-var-qq; } +.#{$fa-css-prefix}-wechat:before, +.#{$fa-css-prefix}-weixin:before { content: $fa-var-weixin; } +.#{$fa-css-prefix}-send:before, +.#{$fa-css-prefix}-paper-plane:before { content: $fa-var-paper-plane; } +.#{$fa-css-prefix}-send-o:before, +.#{$fa-css-prefix}-paper-plane-o:before { content: $fa-var-paper-plane-o; } +.#{$fa-css-prefix}-history:before { content: $fa-var-history; } +.#{$fa-css-prefix}-circle-thin:before { content: $fa-var-circle-thin; } +.#{$fa-css-prefix}-header:before { content: $fa-var-header; } +.#{$fa-css-prefix}-paragraph:before { content: $fa-var-paragraph; } +.#{$fa-css-prefix}-sliders:before { content: $fa-var-sliders; } +.#{$fa-css-prefix}-share-alt:before { content: $fa-var-share-alt; } +.#{$fa-css-prefix}-share-alt-square:before { content: $fa-var-share-alt-square; } +.#{$fa-css-prefix}-bomb:before { content: $fa-var-bomb; } +.#{$fa-css-prefix}-soccer-ball-o:before, +.#{$fa-css-prefix}-futbol-o:before { content: $fa-var-futbol-o; } +.#{$fa-css-prefix}-tty:before { content: $fa-var-tty; } +.#{$fa-css-prefix}-binoculars:before { content: $fa-var-binoculars; } +.#{$fa-css-prefix}-plug:before { content: $fa-var-plug; } +.#{$fa-css-prefix}-slideshare:before { content: $fa-var-slideshare; } +.#{$fa-css-prefix}-twitch:before { content: $fa-var-twitch; } +.#{$fa-css-prefix}-yelp:before { content: $fa-var-yelp; } +.#{$fa-css-prefix}-newspaper-o:before { content: $fa-var-newspaper-o; } +.#{$fa-css-prefix}-wifi:before { content: $fa-var-wifi; } +.#{$fa-css-prefix}-calculator:before { content: $fa-var-calculator; } +.#{$fa-css-prefix}-paypal:before { content: $fa-var-paypal; } +.#{$fa-css-prefix}-google-wallet:before { content: $fa-var-google-wallet; } +.#{$fa-css-prefix}-cc-visa:before { content: $fa-var-cc-visa; } +.#{$fa-css-prefix}-cc-mastercard:before { content: $fa-var-cc-mastercard; } +.#{$fa-css-prefix}-cc-discover:before { content: $fa-var-cc-discover; } +.#{$fa-css-prefix}-cc-amex:before { content: $fa-var-cc-amex; } +.#{$fa-css-prefix}-cc-paypal:before { content: $fa-var-cc-paypal; } +.#{$fa-css-prefix}-cc-stripe:before { content: $fa-var-cc-stripe; } +.#{$fa-css-prefix}-bell-slash:before { content: $fa-var-bell-slash; } +.#{$fa-css-prefix}-bell-slash-o:before { content: $fa-var-bell-slash-o; } +.#{$fa-css-prefix}-trash:before { content: $fa-var-trash; } +.#{$fa-css-prefix}-copyright:before { content: $fa-var-copyright; } +.#{$fa-css-prefix}-at:before { content: $fa-var-at; } +.#{$fa-css-prefix}-eyedropper:before { content: $fa-var-eyedropper; } +.#{$fa-css-prefix}-paint-brush:before { content: $fa-var-paint-brush; } +.#{$fa-css-prefix}-birthday-cake:before { content: $fa-var-birthday-cake; } +.#{$fa-css-prefix}-area-chart:before { content: $fa-var-area-chart; } +.#{$fa-css-prefix}-pie-chart:before { content: $fa-var-pie-chart; } +.#{$fa-css-prefix}-line-chart:before { content: $fa-var-line-chart; } +.#{$fa-css-prefix}-lastfm:before { content: $fa-var-lastfm; } +.#{$fa-css-prefix}-lastfm-square:before { content: $fa-var-lastfm-square; } +.#{$fa-css-prefix}-toggle-off:before { content: $fa-var-toggle-off; } +.#{$fa-css-prefix}-toggle-on:before { content: $fa-var-toggle-on; } +.#{$fa-css-prefix}-bicycle:before { content: $fa-var-bicycle; } +.#{$fa-css-prefix}-bus:before { content: $fa-var-bus; } +.#{$fa-css-prefix}-ioxhost:before { content: $fa-var-ioxhost; } +.#{$fa-css-prefix}-angellist:before { content: $fa-var-angellist; } +.#{$fa-css-prefix}-cc:before { content: $fa-var-cc; } +.#{$fa-css-prefix}-shekel:before, +.#{$fa-css-prefix}-sheqel:before, +.#{$fa-css-prefix}-ils:before { content: $fa-var-ils; } +.#{$fa-css-prefix}-meanpath:before { content: $fa-var-meanpath; } +.#{$fa-css-prefix}-buysellads:before { content: $fa-var-buysellads; } +.#{$fa-css-prefix}-connectdevelop:before { content: $fa-var-connectdevelop; } +.#{$fa-css-prefix}-dashcube:before { content: $fa-var-dashcube; } +.#{$fa-css-prefix}-forumbee:before { content: $fa-var-forumbee; } +.#{$fa-css-prefix}-leanpub:before { content: $fa-var-leanpub; } +.#{$fa-css-prefix}-sellsy:before { content: $fa-var-sellsy; } +.#{$fa-css-prefix}-shirtsinbulk:before { content: $fa-var-shirtsinbulk; } +.#{$fa-css-prefix}-simplybuilt:before { content: $fa-var-simplybuilt; } +.#{$fa-css-prefix}-skyatlas:before { content: $fa-var-skyatlas; } +.#{$fa-css-prefix}-cart-plus:before { content: $fa-var-cart-plus; } +.#{$fa-css-prefix}-cart-arrow-down:before { content: $fa-var-cart-arrow-down; } +.#{$fa-css-prefix}-diamond:before { content: $fa-var-diamond; } +.#{$fa-css-prefix}-ship:before { content: $fa-var-ship; } +.#{$fa-css-prefix}-user-secret:before { content: $fa-var-user-secret; } +.#{$fa-css-prefix}-motorcycle:before { content: $fa-var-motorcycle; } +.#{$fa-css-prefix}-street-view:before { content: $fa-var-street-view; } +.#{$fa-css-prefix}-heartbeat:before { content: $fa-var-heartbeat; } +.#{$fa-css-prefix}-venus:before { content: $fa-var-venus; } +.#{$fa-css-prefix}-mars:before { content: $fa-var-mars; } +.#{$fa-css-prefix}-mercury:before { content: $fa-var-mercury; } +.#{$fa-css-prefix}-intersex:before, +.#{$fa-css-prefix}-transgender:before { content: $fa-var-transgender; } +.#{$fa-css-prefix}-transgender-alt:before { content: $fa-var-transgender-alt; } +.#{$fa-css-prefix}-venus-double:before { content: $fa-var-venus-double; } +.#{$fa-css-prefix}-mars-double:before { content: $fa-var-mars-double; } +.#{$fa-css-prefix}-venus-mars:before { content: $fa-var-venus-mars; } +.#{$fa-css-prefix}-mars-stroke:before { content: $fa-var-mars-stroke; } +.#{$fa-css-prefix}-mars-stroke-v:before { content: $fa-var-mars-stroke-v; } +.#{$fa-css-prefix}-mars-stroke-h:before { content: $fa-var-mars-stroke-h; } +.#{$fa-css-prefix}-neuter:before { content: $fa-var-neuter; } +.#{$fa-css-prefix}-genderless:before { content: $fa-var-genderless; } +.#{$fa-css-prefix}-facebook-official:before { content: $fa-var-facebook-official; } +.#{$fa-css-prefix}-pinterest-p:before { content: $fa-var-pinterest-p; } +.#{$fa-css-prefix}-whatsapp:before { content: $fa-var-whatsapp; } +.#{$fa-css-prefix}-server:before { content: $fa-var-server; } +.#{$fa-css-prefix}-user-plus:before { content: $fa-var-user-plus; } +.#{$fa-css-prefix}-user-times:before { content: $fa-var-user-times; } +.#{$fa-css-prefix}-hotel:before, +.#{$fa-css-prefix}-bed:before { content: $fa-var-bed; } +.#{$fa-css-prefix}-viacoin:before { content: $fa-var-viacoin; } +.#{$fa-css-prefix}-train:before { content: $fa-var-train; } +.#{$fa-css-prefix}-subway:before { content: $fa-var-subway; } +.#{$fa-css-prefix}-medium:before { content: $fa-var-medium; } +.#{$fa-css-prefix}-yc:before, +.#{$fa-css-prefix}-y-combinator:before { content: $fa-var-y-combinator; } +.#{$fa-css-prefix}-optin-monster:before { content: $fa-var-optin-monster; } +.#{$fa-css-prefix}-opencart:before { content: $fa-var-opencart; } +.#{$fa-css-prefix}-expeditedssl:before { content: $fa-var-expeditedssl; } +.#{$fa-css-prefix}-battery-4:before, +.#{$fa-css-prefix}-battery:before, +.#{$fa-css-prefix}-battery-full:before { content: $fa-var-battery-full; } +.#{$fa-css-prefix}-battery-3:before, +.#{$fa-css-prefix}-battery-three-quarters:before { content: $fa-var-battery-three-quarters; } +.#{$fa-css-prefix}-battery-2:before, +.#{$fa-css-prefix}-battery-half:before { content: $fa-var-battery-half; } +.#{$fa-css-prefix}-battery-1:before, +.#{$fa-css-prefix}-battery-quarter:before { content: $fa-var-battery-quarter; } +.#{$fa-css-prefix}-battery-0:before, +.#{$fa-css-prefix}-battery-empty:before { content: $fa-var-battery-empty; } +.#{$fa-css-prefix}-mouse-pointer:before { content: $fa-var-mouse-pointer; } +.#{$fa-css-prefix}-i-cursor:before { content: $fa-var-i-cursor; } +.#{$fa-css-prefix}-object-group:before { content: $fa-var-object-group; } +.#{$fa-css-prefix}-object-ungroup:before { content: $fa-var-object-ungroup; } +.#{$fa-css-prefix}-sticky-note:before { content: $fa-var-sticky-note; } +.#{$fa-css-prefix}-sticky-note-o:before { content: $fa-var-sticky-note-o; } +.#{$fa-css-prefix}-cc-jcb:before { content: $fa-var-cc-jcb; } +.#{$fa-css-prefix}-cc-diners-club:before { content: $fa-var-cc-diners-club; } +.#{$fa-css-prefix}-clone:before { content: $fa-var-clone; } +.#{$fa-css-prefix}-balance-scale:before { content: $fa-var-balance-scale; } +.#{$fa-css-prefix}-hourglass-o:before { content: $fa-var-hourglass-o; } +.#{$fa-css-prefix}-hourglass-1:before, +.#{$fa-css-prefix}-hourglass-start:before { content: $fa-var-hourglass-start; } +.#{$fa-css-prefix}-hourglass-2:before, +.#{$fa-css-prefix}-hourglass-half:before { content: $fa-var-hourglass-half; } +.#{$fa-css-prefix}-hourglass-3:before, +.#{$fa-css-prefix}-hourglass-end:before { content: $fa-var-hourglass-end; } +.#{$fa-css-prefix}-hourglass:before { content: $fa-var-hourglass; } +.#{$fa-css-prefix}-hand-grab-o:before, +.#{$fa-css-prefix}-hand-rock-o:before { content: $fa-var-hand-rock-o; } +.#{$fa-css-prefix}-hand-stop-o:before, +.#{$fa-css-prefix}-hand-paper-o:before { content: $fa-var-hand-paper-o; } +.#{$fa-css-prefix}-hand-scissors-o:before { content: $fa-var-hand-scissors-o; } +.#{$fa-css-prefix}-hand-lizard-o:before { content: $fa-var-hand-lizard-o; } +.#{$fa-css-prefix}-hand-spock-o:before { content: $fa-var-hand-spock-o; } +.#{$fa-css-prefix}-hand-pointer-o:before { content: $fa-var-hand-pointer-o; } +.#{$fa-css-prefix}-hand-peace-o:before { content: $fa-var-hand-peace-o; } +.#{$fa-css-prefix}-trademark:before { content: $fa-var-trademark; } +.#{$fa-css-prefix}-registered:before { content: $fa-var-registered; } +.#{$fa-css-prefix}-creative-commons:before { content: $fa-var-creative-commons; } +.#{$fa-css-prefix}-gg:before { content: $fa-var-gg; } +.#{$fa-css-prefix}-gg-circle:before { content: $fa-var-gg-circle; } +.#{$fa-css-prefix}-tripadvisor:before { content: $fa-var-tripadvisor; } +.#{$fa-css-prefix}-odnoklassniki:before { content: $fa-var-odnoklassniki; } +.#{$fa-css-prefix}-odnoklassniki-square:before { content: $fa-var-odnoklassniki-square; } +.#{$fa-css-prefix}-get-pocket:before { content: $fa-var-get-pocket; } +.#{$fa-css-prefix}-wikipedia-w:before { content: $fa-var-wikipedia-w; } +.#{$fa-css-prefix}-safari:before { content: $fa-var-safari; } +.#{$fa-css-prefix}-chrome:before { content: $fa-var-chrome; } +.#{$fa-css-prefix}-firefox:before { content: $fa-var-firefox; } +.#{$fa-css-prefix}-opera:before { content: $fa-var-opera; } +.#{$fa-css-prefix}-internet-explorer:before { content: $fa-var-internet-explorer; } +.#{$fa-css-prefix}-tv:before, +.#{$fa-css-prefix}-television:before { content: $fa-var-television; } +.#{$fa-css-prefix}-contao:before { content: $fa-var-contao; } +.#{$fa-css-prefix}-500px:before { content: $fa-var-500px; } +.#{$fa-css-prefix}-amazon:before { content: $fa-var-amazon; } +.#{$fa-css-prefix}-calendar-plus-o:before { content: $fa-var-calendar-plus-o; } +.#{$fa-css-prefix}-calendar-minus-o:before { content: $fa-var-calendar-minus-o; } +.#{$fa-css-prefix}-calendar-times-o:before { content: $fa-var-calendar-times-o; } +.#{$fa-css-prefix}-calendar-check-o:before { content: $fa-var-calendar-check-o; } +.#{$fa-css-prefix}-industry:before { content: $fa-var-industry; } +.#{$fa-css-prefix}-map-pin:before { content: $fa-var-map-pin; } +.#{$fa-css-prefix}-map-signs:before { content: $fa-var-map-signs; } +.#{$fa-css-prefix}-map-o:before { content: $fa-var-map-o; } +.#{$fa-css-prefix}-map:before { content: $fa-var-map; } +.#{$fa-css-prefix}-commenting:before { content: $fa-var-commenting; } +.#{$fa-css-prefix}-commenting-o:before { content: $fa-var-commenting-o; } +.#{$fa-css-prefix}-houzz:before { content: $fa-var-houzz; } +.#{$fa-css-prefix}-vimeo:before { content: $fa-var-vimeo; } +.#{$fa-css-prefix}-black-tie:before { content: $fa-var-black-tie; } +.#{$fa-css-prefix}-fonticons:before { content: $fa-var-fonticons; } +.#{$fa-css-prefix}-reddit-alien:before { content: $fa-var-reddit-alien; } +.#{$fa-css-prefix}-edge:before { content: $fa-var-edge; } +.#{$fa-css-prefix}-credit-card-alt:before { content: $fa-var-credit-card-alt; } +.#{$fa-css-prefix}-codiepie:before { content: $fa-var-codiepie; } +.#{$fa-css-prefix}-modx:before { content: $fa-var-modx; } +.#{$fa-css-prefix}-fort-awesome:before { content: $fa-var-fort-awesome; } +.#{$fa-css-prefix}-usb:before { content: $fa-var-usb; } +.#{$fa-css-prefix}-product-hunt:before { content: $fa-var-product-hunt; } +.#{$fa-css-prefix}-mixcloud:before { content: $fa-var-mixcloud; } +.#{$fa-css-prefix}-scribd:before { content: $fa-var-scribd; } +.#{$fa-css-prefix}-pause-circle:before { content: $fa-var-pause-circle; } +.#{$fa-css-prefix}-pause-circle-o:before { content: $fa-var-pause-circle-o; } +.#{$fa-css-prefix}-stop-circle:before { content: $fa-var-stop-circle; } +.#{$fa-css-prefix}-stop-circle-o:before { content: $fa-var-stop-circle-o; } +.#{$fa-css-prefix}-shopping-bag:before { content: $fa-var-shopping-bag; } +.#{$fa-css-prefix}-shopping-basket:before { content: $fa-var-shopping-basket; } +.#{$fa-css-prefix}-hashtag:before { content: $fa-var-hashtag; } +.#{$fa-css-prefix}-bluetooth:before { content: $fa-var-bluetooth; } +.#{$fa-css-prefix}-bluetooth-b:before { content: $fa-var-bluetooth-b; } +.#{$fa-css-prefix}-percent:before { content: $fa-var-percent; } +.#{$fa-css-prefix}-gitlab:before { content: $fa-var-gitlab; } +.#{$fa-css-prefix}-wpbeginner:before { content: $fa-var-wpbeginner; } +.#{$fa-css-prefix}-wpforms:before { content: $fa-var-wpforms; } +.#{$fa-css-prefix}-envira:before { content: $fa-var-envira; } +.#{$fa-css-prefix}-universal-access:before { content: $fa-var-universal-access; } +.#{$fa-css-prefix}-wheelchair-alt:before { content: $fa-var-wheelchair-alt; } +.#{$fa-css-prefix}-question-circle-o:before { content: $fa-var-question-circle-o; } +.#{$fa-css-prefix}-blind:before { content: $fa-var-blind; } +.#{$fa-css-prefix}-audio-description:before { content: $fa-var-audio-description; } +.#{$fa-css-prefix}-volume-control-phone:before { content: $fa-var-volume-control-phone; } +.#{$fa-css-prefix}-braille:before { content: $fa-var-braille; } +.#{$fa-css-prefix}-assistive-listening-systems:before { content: $fa-var-assistive-listening-systems; } +.#{$fa-css-prefix}-asl-interpreting:before, +.#{$fa-css-prefix}-american-sign-language-interpreting:before { content: $fa-var-american-sign-language-interpreting; } +.#{$fa-css-prefix}-deafness:before, +.#{$fa-css-prefix}-hard-of-hearing:before, +.#{$fa-css-prefix}-deaf:before { content: $fa-var-deaf; } +.#{$fa-css-prefix}-glide:before { content: $fa-var-glide; } +.#{$fa-css-prefix}-glide-g:before { content: $fa-var-glide-g; } +.#{$fa-css-prefix}-signing:before, +.#{$fa-css-prefix}-sign-language:before { content: $fa-var-sign-language; } +.#{$fa-css-prefix}-low-vision:before { content: $fa-var-low-vision; } +.#{$fa-css-prefix}-viadeo:before { content: $fa-var-viadeo; } +.#{$fa-css-prefix}-viadeo-square:before { content: $fa-var-viadeo-square; } +.#{$fa-css-prefix}-snapchat:before { content: $fa-var-snapchat; } +.#{$fa-css-prefix}-snapchat-ghost:before { content: $fa-var-snapchat-ghost; } +.#{$fa-css-prefix}-snapchat-square:before { content: $fa-var-snapchat-square; } +.#{$fa-css-prefix}-pied-piper:before { content: $fa-var-pied-piper; } +.#{$fa-css-prefix}-first-order:before { content: $fa-var-first-order; } +.#{$fa-css-prefix}-yoast:before { content: $fa-var-yoast; } +.#{$fa-css-prefix}-themeisle:before { content: $fa-var-themeisle; } +.#{$fa-css-prefix}-google-plus-circle:before, +.#{$fa-css-prefix}-google-plus-official:before { content: $fa-var-google-plus-official; } +.#{$fa-css-prefix}-fa:before, +.#{$fa-css-prefix}-font-awesome:before { content: $fa-var-font-awesome; } +.#{$fa-css-prefix}-handshake-o:before { content: $fa-var-handshake-o; } +.#{$fa-css-prefix}-envelope-open:before { content: $fa-var-envelope-open; } +.#{$fa-css-prefix}-envelope-open-o:before { content: $fa-var-envelope-open-o; } +.#{$fa-css-prefix}-linode:before { content: $fa-var-linode; } +.#{$fa-css-prefix}-address-book:before { content: $fa-var-address-book; } +.#{$fa-css-prefix}-address-book-o:before { content: $fa-var-address-book-o; } +.#{$fa-css-prefix}-vcard:before, +.#{$fa-css-prefix}-address-card:before { content: $fa-var-address-card; } +.#{$fa-css-prefix}-vcard-o:before, +.#{$fa-css-prefix}-address-card-o:before { content: $fa-var-address-card-o; } +.#{$fa-css-prefix}-user-circle:before { content: $fa-var-user-circle; } +.#{$fa-css-prefix}-user-circle-o:before { content: $fa-var-user-circle-o; } +.#{$fa-css-prefix}-user-o:before { content: $fa-var-user-o; } +.#{$fa-css-prefix}-id-badge:before { content: $fa-var-id-badge; } +.#{$fa-css-prefix}-drivers-license:before, +.#{$fa-css-prefix}-id-card:before { content: $fa-var-id-card; } +.#{$fa-css-prefix}-drivers-license-o:before, +.#{$fa-css-prefix}-id-card-o:before { content: $fa-var-id-card-o; } +.#{$fa-css-prefix}-quora:before { content: $fa-var-quora; } +.#{$fa-css-prefix}-free-code-camp:before { content: $fa-var-free-code-camp; } +.#{$fa-css-prefix}-telegram:before { content: $fa-var-telegram; } +.#{$fa-css-prefix}-thermometer-4:before, +.#{$fa-css-prefix}-thermometer:before, +.#{$fa-css-prefix}-thermometer-full:before { content: $fa-var-thermometer-full; } +.#{$fa-css-prefix}-thermometer-3:before, +.#{$fa-css-prefix}-thermometer-three-quarters:before { content: $fa-var-thermometer-three-quarters; } +.#{$fa-css-prefix}-thermometer-2:before, +.#{$fa-css-prefix}-thermometer-half:before { content: $fa-var-thermometer-half; } +.#{$fa-css-prefix}-thermometer-1:before, +.#{$fa-css-prefix}-thermometer-quarter:before { content: $fa-var-thermometer-quarter; } +.#{$fa-css-prefix}-thermometer-0:before, +.#{$fa-css-prefix}-thermometer-empty:before { content: $fa-var-thermometer-empty; } +.#{$fa-css-prefix}-shower:before { content: $fa-var-shower; } +.#{$fa-css-prefix}-bathtub:before, +.#{$fa-css-prefix}-s15:before, +.#{$fa-css-prefix}-bath:before { content: $fa-var-bath; } +.#{$fa-css-prefix}-podcast:before { content: $fa-var-podcast; } +.#{$fa-css-prefix}-window-maximize:before { content: $fa-var-window-maximize; } +.#{$fa-css-prefix}-window-minimize:before { content: $fa-var-window-minimize; } +.#{$fa-css-prefix}-window-restore:before { content: $fa-var-window-restore; } +.#{$fa-css-prefix}-times-rectangle:before, +.#{$fa-css-prefix}-window-close:before { content: $fa-var-window-close; } +.#{$fa-css-prefix}-times-rectangle-o:before, +.#{$fa-css-prefix}-window-close-o:before { content: $fa-var-window-close-o; } +.#{$fa-css-prefix}-bandcamp:before { content: $fa-var-bandcamp; } +.#{$fa-css-prefix}-grav:before { content: $fa-var-grav; } +.#{$fa-css-prefix}-etsy:before { content: $fa-var-etsy; } +.#{$fa-css-prefix}-imdb:before { content: $fa-var-imdb; } +.#{$fa-css-prefix}-ravelry:before { content: $fa-var-ravelry; } +.#{$fa-css-prefix}-eercast:before { content: $fa-var-eercast; } +.#{$fa-css-prefix}-microchip:before { content: $fa-var-microchip; } +.#{$fa-css-prefix}-snowflake-o:before { content: $fa-var-snowflake-o; } +.#{$fa-css-prefix}-superpowers:before { content: $fa-var-superpowers; } +.#{$fa-css-prefix}-wpexplorer:before { content: $fa-var-wpexplorer; } +.#{$fa-css-prefix}-meetup:before { content: $fa-var-meetup; } diff --git a/web/css/font-awesome-4.7.0/scss/_larger.scss b/web/css/font-awesome-4.7.0/scss/_larger.scss new file mode 100644 index 000000000..41e9a8184 --- /dev/null +++ b/web/css/font-awesome-4.7.0/scss/_larger.scss @@ -0,0 +1,13 @@ +// Icon Sizes +// ------------------------- + +/* makes the font 33% larger relative to the icon container */ +.#{$fa-css-prefix}-lg { + font-size: (4em / 3); + line-height: (3em / 4); + vertical-align: -15%; +} +.#{$fa-css-prefix}-2x { font-size: 2em; } +.#{$fa-css-prefix}-3x { font-size: 3em; } +.#{$fa-css-prefix}-4x { font-size: 4em; } +.#{$fa-css-prefix}-5x { font-size: 5em; } diff --git a/web/css/font-awesome-4.7.0/scss/_list.scss b/web/css/font-awesome-4.7.0/scss/_list.scss new file mode 100644 index 000000000..7d1e4d54d --- /dev/null +++ b/web/css/font-awesome-4.7.0/scss/_list.scss @@ -0,0 +1,19 @@ +// List Icons +// ------------------------- + +.#{$fa-css-prefix}-ul { + padding-left: 0; + margin-left: $fa-li-width; + list-style-type: none; + > li { position: relative; } +} +.#{$fa-css-prefix}-li { + position: absolute; + left: -$fa-li-width; + width: $fa-li-width; + top: (2em / 14); + text-align: center; + &.#{$fa-css-prefix}-lg { + left: -$fa-li-width + (4em / 14); + } +} diff --git a/web/css/font-awesome-4.7.0/scss/_mixins.scss b/web/css/font-awesome-4.7.0/scss/_mixins.scss new file mode 100644 index 000000000..c3bbd5745 --- /dev/null +++ b/web/css/font-awesome-4.7.0/scss/_mixins.scss @@ -0,0 +1,60 @@ +// Mixins +// -------------------------- + +@mixin fa-icon() { + display: inline-block; + font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration + font-size: inherit; // can't have font-size inherit on line above, so need to override + text-rendering: auto; // optimizelegibility throws things off #1094 + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + +} + +@mixin fa-icon-rotate($degrees, $rotation) { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation})"; + -webkit-transform: rotate($degrees); + -ms-transform: rotate($degrees); + transform: rotate($degrees); +} + +@mixin fa-icon-flip($horiz, $vert, $rotation) { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation}, mirror=1)"; + -webkit-transform: scale($horiz, $vert); + -ms-transform: scale($horiz, $vert); + transform: scale($horiz, $vert); +} + + +// Only display content to screen readers. A la Bootstrap 4. +// +// See: http://a11yproject.com/posts/how-to-hide-content/ + +@mixin sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0,0,0,0); + border: 0; +} + +// Use in conjunction with .sr-only to only display content when it's focused. +// +// Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1 +// +// Credit: HTML5 Boilerplate + +@mixin sr-only-focusable { + &:active, + &:focus { + position: static; + width: auto; + height: auto; + margin: 0; + overflow: visible; + clip: auto; + } +} diff --git a/web/css/font-awesome-4.7.0/scss/_path.scss b/web/css/font-awesome-4.7.0/scss/_path.scss new file mode 100644 index 000000000..bb457c23a --- /dev/null +++ b/web/css/font-awesome-4.7.0/scss/_path.scss @@ -0,0 +1,15 @@ +/* FONT PATH + * -------------------------- */ + +@font-face { + font-family: 'FontAwesome'; + src: url('#{$fa-font-path}/fontawesome-webfont.eot?v=#{$fa-version}'); + src: url('#{$fa-font-path}/fontawesome-webfont.eot?#iefix&v=#{$fa-version}') format('embedded-opentype'), + url('#{$fa-font-path}/fontawesome-webfont.woff2?v=#{$fa-version}') format('woff2'), + url('#{$fa-font-path}/fontawesome-webfont.woff?v=#{$fa-version}') format('woff'), + url('#{$fa-font-path}/fontawesome-webfont.ttf?v=#{$fa-version}') format('truetype'), + url('#{$fa-font-path}/fontawesome-webfont.svg?v=#{$fa-version}#fontawesomeregular') format('svg'); +// src: url('#{$fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts + font-weight: normal; + font-style: normal; +} diff --git a/web/css/font-awesome-4.7.0/scss/_rotated-flipped.scss b/web/css/font-awesome-4.7.0/scss/_rotated-flipped.scss new file mode 100644 index 000000000..a3558fd09 --- /dev/null +++ b/web/css/font-awesome-4.7.0/scss/_rotated-flipped.scss @@ -0,0 +1,20 @@ +// Rotated & Flipped Icons +// ------------------------- + +.#{$fa-css-prefix}-rotate-90 { @include fa-icon-rotate(90deg, 1); } +.#{$fa-css-prefix}-rotate-180 { @include fa-icon-rotate(180deg, 2); } +.#{$fa-css-prefix}-rotate-270 { @include fa-icon-rotate(270deg, 3); } + +.#{$fa-css-prefix}-flip-horizontal { @include fa-icon-flip(-1, 1, 0); } +.#{$fa-css-prefix}-flip-vertical { @include fa-icon-flip(1, -1, 2); } + +// Hook for IE8-9 +// ------------------------- + +:root .#{$fa-css-prefix}-rotate-90, +:root .#{$fa-css-prefix}-rotate-180, +:root .#{$fa-css-prefix}-rotate-270, +:root .#{$fa-css-prefix}-flip-horizontal, +:root .#{$fa-css-prefix}-flip-vertical { + filter: none; +} diff --git a/web/css/font-awesome-4.7.0/scss/_screen-reader.scss b/web/css/font-awesome-4.7.0/scss/_screen-reader.scss new file mode 100644 index 000000000..637426f0d --- /dev/null +++ b/web/css/font-awesome-4.7.0/scss/_screen-reader.scss @@ -0,0 +1,5 @@ +// Screen Readers +// ------------------------- + +.sr-only { @include sr-only(); } +.sr-only-focusable { @include sr-only-focusable(); } diff --git a/web/css/font-awesome-4.7.0/scss/_stacked.scss b/web/css/font-awesome-4.7.0/scss/_stacked.scss new file mode 100644 index 000000000..aef740366 --- /dev/null +++ b/web/css/font-awesome-4.7.0/scss/_stacked.scss @@ -0,0 +1,20 @@ +// Stacked Icons +// ------------------------- + +.#{$fa-css-prefix}-stack { + position: relative; + display: inline-block; + width: 2em; + height: 2em; + line-height: 2em; + vertical-align: middle; +} +.#{$fa-css-prefix}-stack-1x, .#{$fa-css-prefix}-stack-2x { + position: absolute; + left: 0; + width: 100%; + text-align: center; +} +.#{$fa-css-prefix}-stack-1x { line-height: inherit; } +.#{$fa-css-prefix}-stack-2x { font-size: 2em; } +.#{$fa-css-prefix}-inverse { color: $fa-inverse; } diff --git a/web/css/font-awesome-4.7.0/scss/_variables.scss b/web/css/font-awesome-4.7.0/scss/_variables.scss new file mode 100644 index 000000000..498fc4a08 --- /dev/null +++ b/web/css/font-awesome-4.7.0/scss/_variables.scss @@ -0,0 +1,800 @@ +// Variables +// -------------------------- + +$fa-font-path: "../fonts" !default; +$fa-font-size-base: 14px !default; +$fa-line-height-base: 1 !default; +//$fa-font-path: "//netdna.bootstrapcdn.com/font-awesome/4.7.0/fonts" !default; // for referencing Bootstrap CDN font files directly +$fa-css-prefix: fa !default; +$fa-version: "4.7.0" !default; +$fa-border-color: #eee !default; +$fa-inverse: #fff !default; +$fa-li-width: (30em / 14) !default; + +$fa-var-500px: "\f26e"; +$fa-var-address-book: "\f2b9"; +$fa-var-address-book-o: "\f2ba"; +$fa-var-address-card: "\f2bb"; +$fa-var-address-card-o: "\f2bc"; +$fa-var-adjust: "\f042"; +$fa-var-adn: "\f170"; +$fa-var-align-center: "\f037"; +$fa-var-align-justify: "\f039"; +$fa-var-align-left: "\f036"; +$fa-var-align-right: "\f038"; +$fa-var-amazon: "\f270"; +$fa-var-ambulance: "\f0f9"; +$fa-var-american-sign-language-interpreting: "\f2a3"; +$fa-var-anchor: "\f13d"; +$fa-var-android: "\f17b"; +$fa-var-angellist: "\f209"; +$fa-var-angle-double-down: "\f103"; +$fa-var-angle-double-left: "\f100"; +$fa-var-angle-double-right: "\f101"; +$fa-var-angle-double-up: "\f102"; +$fa-var-angle-down: "\f107"; +$fa-var-angle-left: "\f104"; +$fa-var-angle-right: "\f105"; +$fa-var-angle-up: "\f106"; +$fa-var-apple: "\f179"; +$fa-var-archive: "\f187"; +$fa-var-area-chart: "\f1fe"; +$fa-var-arrow-circle-down: "\f0ab"; +$fa-var-arrow-circle-left: "\f0a8"; +$fa-var-arrow-circle-o-down: "\f01a"; +$fa-var-arrow-circle-o-left: "\f190"; +$fa-var-arrow-circle-o-right: "\f18e"; +$fa-var-arrow-circle-o-up: "\f01b"; +$fa-var-arrow-circle-right: "\f0a9"; +$fa-var-arrow-circle-up: "\f0aa"; +$fa-var-arrow-down: "\f063"; +$fa-var-arrow-left: "\f060"; +$fa-var-arrow-right: "\f061"; +$fa-var-arrow-up: "\f062"; +$fa-var-arrows: "\f047"; +$fa-var-arrows-alt: "\f0b2"; +$fa-var-arrows-h: "\f07e"; +$fa-var-arrows-v: "\f07d"; +$fa-var-asl-interpreting: "\f2a3"; +$fa-var-assistive-listening-systems: "\f2a2"; +$fa-var-asterisk: "\f069"; +$fa-var-at: "\f1fa"; +$fa-var-audio-description: "\f29e"; +$fa-var-automobile: "\f1b9"; +$fa-var-backward: "\f04a"; +$fa-var-balance-scale: "\f24e"; +$fa-var-ban: "\f05e"; +$fa-var-bandcamp: "\f2d5"; +$fa-var-bank: "\f19c"; +$fa-var-bar-chart: "\f080"; +$fa-var-bar-chart-o: "\f080"; +$fa-var-barcode: "\f02a"; +$fa-var-bars: "\f0c9"; +$fa-var-bath: "\f2cd"; +$fa-var-bathtub: "\f2cd"; +$fa-var-battery: "\f240"; +$fa-var-battery-0: "\f244"; +$fa-var-battery-1: "\f243"; +$fa-var-battery-2: "\f242"; +$fa-var-battery-3: "\f241"; +$fa-var-battery-4: "\f240"; +$fa-var-battery-empty: "\f244"; +$fa-var-battery-full: "\f240"; +$fa-var-battery-half: "\f242"; +$fa-var-battery-quarter: "\f243"; +$fa-var-battery-three-quarters: "\f241"; +$fa-var-bed: "\f236"; +$fa-var-beer: "\f0fc"; +$fa-var-behance: "\f1b4"; +$fa-var-behance-square: "\f1b5"; +$fa-var-bell: "\f0f3"; +$fa-var-bell-o: "\f0a2"; +$fa-var-bell-slash: "\f1f6"; +$fa-var-bell-slash-o: "\f1f7"; +$fa-var-bicycle: "\f206"; +$fa-var-binoculars: "\f1e5"; +$fa-var-birthday-cake: "\f1fd"; +$fa-var-bitbucket: "\f171"; +$fa-var-bitbucket-square: "\f172"; +$fa-var-bitcoin: "\f15a"; +$fa-var-black-tie: "\f27e"; +$fa-var-blind: "\f29d"; +$fa-var-bluetooth: "\f293"; +$fa-var-bluetooth-b: "\f294"; +$fa-var-bold: "\f032"; +$fa-var-bolt: "\f0e7"; +$fa-var-bomb: "\f1e2"; +$fa-var-book: "\f02d"; +$fa-var-bookmark: "\f02e"; +$fa-var-bookmark-o: "\f097"; +$fa-var-braille: "\f2a1"; +$fa-var-briefcase: "\f0b1"; +$fa-var-btc: "\f15a"; +$fa-var-bug: "\f188"; +$fa-var-building: "\f1ad"; +$fa-var-building-o: "\f0f7"; +$fa-var-bullhorn: "\f0a1"; +$fa-var-bullseye: "\f140"; +$fa-var-bus: "\f207"; +$fa-var-buysellads: "\f20d"; +$fa-var-cab: "\f1ba"; +$fa-var-calculator: "\f1ec"; +$fa-var-calendar: "\f073"; +$fa-var-calendar-check-o: "\f274"; +$fa-var-calendar-minus-o: "\f272"; +$fa-var-calendar-o: "\f133"; +$fa-var-calendar-plus-o: "\f271"; +$fa-var-calendar-times-o: "\f273"; +$fa-var-camera: "\f030"; +$fa-var-camera-retro: "\f083"; +$fa-var-car: "\f1b9"; +$fa-var-caret-down: "\f0d7"; +$fa-var-caret-left: "\f0d9"; +$fa-var-caret-right: "\f0da"; +$fa-var-caret-square-o-down: "\f150"; +$fa-var-caret-square-o-left: "\f191"; +$fa-var-caret-square-o-right: "\f152"; +$fa-var-caret-square-o-up: "\f151"; +$fa-var-caret-up: "\f0d8"; +$fa-var-cart-arrow-down: "\f218"; +$fa-var-cart-plus: "\f217"; +$fa-var-cc: "\f20a"; +$fa-var-cc-amex: "\f1f3"; +$fa-var-cc-diners-club: "\f24c"; +$fa-var-cc-discover: "\f1f2"; +$fa-var-cc-jcb: "\f24b"; +$fa-var-cc-mastercard: "\f1f1"; +$fa-var-cc-paypal: "\f1f4"; +$fa-var-cc-stripe: "\f1f5"; +$fa-var-cc-visa: "\f1f0"; +$fa-var-certificate: "\f0a3"; +$fa-var-chain: "\f0c1"; +$fa-var-chain-broken: "\f127"; +$fa-var-check: "\f00c"; +$fa-var-check-circle: "\f058"; +$fa-var-check-circle-o: "\f05d"; +$fa-var-check-square: "\f14a"; +$fa-var-check-square-o: "\f046"; +$fa-var-chevron-circle-down: "\f13a"; +$fa-var-chevron-circle-left: "\f137"; +$fa-var-chevron-circle-right: "\f138"; +$fa-var-chevron-circle-up: "\f139"; +$fa-var-chevron-down: "\f078"; +$fa-var-chevron-left: "\f053"; +$fa-var-chevron-right: "\f054"; +$fa-var-chevron-up: "\f077"; +$fa-var-child: "\f1ae"; +$fa-var-chrome: "\f268"; +$fa-var-circle: "\f111"; +$fa-var-circle-o: "\f10c"; +$fa-var-circle-o-notch: "\f1ce"; +$fa-var-circle-thin: "\f1db"; +$fa-var-clipboard: "\f0ea"; +$fa-var-clock-o: "\f017"; +$fa-var-clone: "\f24d"; +$fa-var-close: "\f00d"; +$fa-var-cloud: "\f0c2"; +$fa-var-cloud-download: "\f0ed"; +$fa-var-cloud-upload: "\f0ee"; +$fa-var-cny: "\f157"; +$fa-var-code: "\f121"; +$fa-var-code-fork: "\f126"; +$fa-var-codepen: "\f1cb"; +$fa-var-codiepie: "\f284"; +$fa-var-coffee: "\f0f4"; +$fa-var-cog: "\f013"; +$fa-var-cogs: "\f085"; +$fa-var-columns: "\f0db"; +$fa-var-comment: "\f075"; +$fa-var-comment-o: "\f0e5"; +$fa-var-commenting: "\f27a"; +$fa-var-commenting-o: "\f27b"; +$fa-var-comments: "\f086"; +$fa-var-comments-o: "\f0e6"; +$fa-var-compass: "\f14e"; +$fa-var-compress: "\f066"; +$fa-var-connectdevelop: "\f20e"; +$fa-var-contao: "\f26d"; +$fa-var-copy: "\f0c5"; +$fa-var-copyright: "\f1f9"; +$fa-var-creative-commons: "\f25e"; +$fa-var-credit-card: "\f09d"; +$fa-var-credit-card-alt: "\f283"; +$fa-var-crop: "\f125"; +$fa-var-crosshairs: "\f05b"; +$fa-var-css3: "\f13c"; +$fa-var-cube: "\f1b2"; +$fa-var-cubes: "\f1b3"; +$fa-var-cut: "\f0c4"; +$fa-var-cutlery: "\f0f5"; +$fa-var-dashboard: "\f0e4"; +$fa-var-dashcube: "\f210"; +$fa-var-database: "\f1c0"; +$fa-var-deaf: "\f2a4"; +$fa-var-deafness: "\f2a4"; +$fa-var-dedent: "\f03b"; +$fa-var-delicious: "\f1a5"; +$fa-var-desktop: "\f108"; +$fa-var-deviantart: "\f1bd"; +$fa-var-diamond: "\f219"; +$fa-var-digg: "\f1a6"; +$fa-var-dollar: "\f155"; +$fa-var-dot-circle-o: "\f192"; +$fa-var-download: "\f019"; +$fa-var-dribbble: "\f17d"; +$fa-var-drivers-license: "\f2c2"; +$fa-var-drivers-license-o: "\f2c3"; +$fa-var-dropbox: "\f16b"; +$fa-var-drupal: "\f1a9"; +$fa-var-edge: "\f282"; +$fa-var-edit: "\f044"; +$fa-var-eercast: "\f2da"; +$fa-var-eject: "\f052"; +$fa-var-ellipsis-h: "\f141"; +$fa-var-ellipsis-v: "\f142"; +$fa-var-empire: "\f1d1"; +$fa-var-envelope: "\f0e0"; +$fa-var-envelope-o: "\f003"; +$fa-var-envelope-open: "\f2b6"; +$fa-var-envelope-open-o: "\f2b7"; +$fa-var-envelope-square: "\f199"; +$fa-var-envira: "\f299"; +$fa-var-eraser: "\f12d"; +$fa-var-etsy: "\f2d7"; +$fa-var-eur: "\f153"; +$fa-var-euro: "\f153"; +$fa-var-exchange: "\f0ec"; +$fa-var-exclamation: "\f12a"; +$fa-var-exclamation-circle: "\f06a"; +$fa-var-exclamation-triangle: "\f071"; +$fa-var-expand: "\f065"; +$fa-var-expeditedssl: "\f23e"; +$fa-var-external-link: "\f08e"; +$fa-var-external-link-square: "\f14c"; +$fa-var-eye: "\f06e"; +$fa-var-eye-slash: "\f070"; +$fa-var-eyedropper: "\f1fb"; +$fa-var-fa: "\f2b4"; +$fa-var-facebook: "\f09a"; +$fa-var-facebook-f: "\f09a"; +$fa-var-facebook-official: "\f230"; +$fa-var-facebook-square: "\f082"; +$fa-var-fast-backward: "\f049"; +$fa-var-fast-forward: "\f050"; +$fa-var-fax: "\f1ac"; +$fa-var-feed: "\f09e"; +$fa-var-female: "\f182"; +$fa-var-fighter-jet: "\f0fb"; +$fa-var-file: "\f15b"; +$fa-var-file-archive-o: "\f1c6"; +$fa-var-file-audio-o: "\f1c7"; +$fa-var-file-code-o: "\f1c9"; +$fa-var-file-excel-o: "\f1c3"; +$fa-var-file-image-o: "\f1c5"; +$fa-var-file-movie-o: "\f1c8"; +$fa-var-file-o: "\f016"; +$fa-var-file-pdf-o: "\f1c1"; +$fa-var-file-photo-o: "\f1c5"; +$fa-var-file-picture-o: "\f1c5"; +$fa-var-file-powerpoint-o: "\f1c4"; +$fa-var-file-sound-o: "\f1c7"; +$fa-var-file-text: "\f15c"; +$fa-var-file-text-o: "\f0f6"; +$fa-var-file-video-o: "\f1c8"; +$fa-var-file-word-o: "\f1c2"; +$fa-var-file-zip-o: "\f1c6"; +$fa-var-files-o: "\f0c5"; +$fa-var-film: "\f008"; +$fa-var-filter: "\f0b0"; +$fa-var-fire: "\f06d"; +$fa-var-fire-extinguisher: "\f134"; +$fa-var-firefox: "\f269"; +$fa-var-first-order: "\f2b0"; +$fa-var-flag: "\f024"; +$fa-var-flag-checkered: "\f11e"; +$fa-var-flag-o: "\f11d"; +$fa-var-flash: "\f0e7"; +$fa-var-flask: "\f0c3"; +$fa-var-flickr: "\f16e"; +$fa-var-floppy-o: "\f0c7"; +$fa-var-folder: "\f07b"; +$fa-var-folder-o: "\f114"; +$fa-var-folder-open: "\f07c"; +$fa-var-folder-open-o: "\f115"; +$fa-var-font: "\f031"; +$fa-var-font-awesome: "\f2b4"; +$fa-var-fonticons: "\f280"; +$fa-var-fort-awesome: "\f286"; +$fa-var-forumbee: "\f211"; +$fa-var-forward: "\f04e"; +$fa-var-foursquare: "\f180"; +$fa-var-free-code-camp: "\f2c5"; +$fa-var-frown-o: "\f119"; +$fa-var-futbol-o: "\f1e3"; +$fa-var-gamepad: "\f11b"; +$fa-var-gavel: "\f0e3"; +$fa-var-gbp: "\f154"; +$fa-var-ge: "\f1d1"; +$fa-var-gear: "\f013"; +$fa-var-gears: "\f085"; +$fa-var-genderless: "\f22d"; +$fa-var-get-pocket: "\f265"; +$fa-var-gg: "\f260"; +$fa-var-gg-circle: "\f261"; +$fa-var-gift: "\f06b"; +$fa-var-git: "\f1d3"; +$fa-var-git-square: "\f1d2"; +$fa-var-github: "\f09b"; +$fa-var-github-alt: "\f113"; +$fa-var-github-square: "\f092"; +$fa-var-gitlab: "\f296"; +$fa-var-gittip: "\f184"; +$fa-var-glass: "\f000"; +$fa-var-glide: "\f2a5"; +$fa-var-glide-g: "\f2a6"; +$fa-var-globe: "\f0ac"; +$fa-var-google: "\f1a0"; +$fa-var-google-plus: "\f0d5"; +$fa-var-google-plus-circle: "\f2b3"; +$fa-var-google-plus-official: "\f2b3"; +$fa-var-google-plus-square: "\f0d4"; +$fa-var-google-wallet: "\f1ee"; +$fa-var-graduation-cap: "\f19d"; +$fa-var-gratipay: "\f184"; +$fa-var-grav: "\f2d6"; +$fa-var-group: "\f0c0"; +$fa-var-h-square: "\f0fd"; +$fa-var-hacker-news: "\f1d4"; +$fa-var-hand-grab-o: "\f255"; +$fa-var-hand-lizard-o: "\f258"; +$fa-var-hand-o-down: "\f0a7"; +$fa-var-hand-o-left: "\f0a5"; +$fa-var-hand-o-right: "\f0a4"; +$fa-var-hand-o-up: "\f0a6"; +$fa-var-hand-paper-o: "\f256"; +$fa-var-hand-peace-o: "\f25b"; +$fa-var-hand-pointer-o: "\f25a"; +$fa-var-hand-rock-o: "\f255"; +$fa-var-hand-scissors-o: "\f257"; +$fa-var-hand-spock-o: "\f259"; +$fa-var-hand-stop-o: "\f256"; +$fa-var-handshake-o: "\f2b5"; +$fa-var-hard-of-hearing: "\f2a4"; +$fa-var-hashtag: "\f292"; +$fa-var-hdd-o: "\f0a0"; +$fa-var-header: "\f1dc"; +$fa-var-headphones: "\f025"; +$fa-var-heart: "\f004"; +$fa-var-heart-o: "\f08a"; +$fa-var-heartbeat: "\f21e"; +$fa-var-history: "\f1da"; +$fa-var-home: "\f015"; +$fa-var-hospital-o: "\f0f8"; +$fa-var-hotel: "\f236"; +$fa-var-hourglass: "\f254"; +$fa-var-hourglass-1: "\f251"; +$fa-var-hourglass-2: "\f252"; +$fa-var-hourglass-3: "\f253"; +$fa-var-hourglass-end: "\f253"; +$fa-var-hourglass-half: "\f252"; +$fa-var-hourglass-o: "\f250"; +$fa-var-hourglass-start: "\f251"; +$fa-var-houzz: "\f27c"; +$fa-var-html5: "\f13b"; +$fa-var-i-cursor: "\f246"; +$fa-var-id-badge: "\f2c1"; +$fa-var-id-card: "\f2c2"; +$fa-var-id-card-o: "\f2c3"; +$fa-var-ils: "\f20b"; +$fa-var-image: "\f03e"; +$fa-var-imdb: "\f2d8"; +$fa-var-inbox: "\f01c"; +$fa-var-indent: "\f03c"; +$fa-var-industry: "\f275"; +$fa-var-info: "\f129"; +$fa-var-info-circle: "\f05a"; +$fa-var-inr: "\f156"; +$fa-var-instagram: "\f16d"; +$fa-var-institution: "\f19c"; +$fa-var-internet-explorer: "\f26b"; +$fa-var-intersex: "\f224"; +$fa-var-ioxhost: "\f208"; +$fa-var-italic: "\f033"; +$fa-var-joomla: "\f1aa"; +$fa-var-jpy: "\f157"; +$fa-var-jsfiddle: "\f1cc"; +$fa-var-key: "\f084"; +$fa-var-keyboard-o: "\f11c"; +$fa-var-krw: "\f159"; +$fa-var-language: "\f1ab"; +$fa-var-laptop: "\f109"; +$fa-var-lastfm: "\f202"; +$fa-var-lastfm-square: "\f203"; +$fa-var-leaf: "\f06c"; +$fa-var-leanpub: "\f212"; +$fa-var-legal: "\f0e3"; +$fa-var-lemon-o: "\f094"; +$fa-var-level-down: "\f149"; +$fa-var-level-up: "\f148"; +$fa-var-life-bouy: "\f1cd"; +$fa-var-life-buoy: "\f1cd"; +$fa-var-life-ring: "\f1cd"; +$fa-var-life-saver: "\f1cd"; +$fa-var-lightbulb-o: "\f0eb"; +$fa-var-line-chart: "\f201"; +$fa-var-link: "\f0c1"; +$fa-var-linkedin: "\f0e1"; +$fa-var-linkedin-square: "\f08c"; +$fa-var-linode: "\f2b8"; +$fa-var-linux: "\f17c"; +$fa-var-list: "\f03a"; +$fa-var-list-alt: "\f022"; +$fa-var-list-ol: "\f0cb"; +$fa-var-list-ul: "\f0ca"; +$fa-var-location-arrow: "\f124"; +$fa-var-lock: "\f023"; +$fa-var-long-arrow-down: "\f175"; +$fa-var-long-arrow-left: "\f177"; +$fa-var-long-arrow-right: "\f178"; +$fa-var-long-arrow-up: "\f176"; +$fa-var-low-vision: "\f2a8"; +$fa-var-magic: "\f0d0"; +$fa-var-magnet: "\f076"; +$fa-var-mail-forward: "\f064"; +$fa-var-mail-reply: "\f112"; +$fa-var-mail-reply-all: "\f122"; +$fa-var-male: "\f183"; +$fa-var-map: "\f279"; +$fa-var-map-marker: "\f041"; +$fa-var-map-o: "\f278"; +$fa-var-map-pin: "\f276"; +$fa-var-map-signs: "\f277"; +$fa-var-mars: "\f222"; +$fa-var-mars-double: "\f227"; +$fa-var-mars-stroke: "\f229"; +$fa-var-mars-stroke-h: "\f22b"; +$fa-var-mars-stroke-v: "\f22a"; +$fa-var-maxcdn: "\f136"; +$fa-var-meanpath: "\f20c"; +$fa-var-medium: "\f23a"; +$fa-var-medkit: "\f0fa"; +$fa-var-meetup: "\f2e0"; +$fa-var-meh-o: "\f11a"; +$fa-var-mercury: "\f223"; +$fa-var-microchip: "\f2db"; +$fa-var-microphone: "\f130"; +$fa-var-microphone-slash: "\f131"; +$fa-var-minus: "\f068"; +$fa-var-minus-circle: "\f056"; +$fa-var-minus-square: "\f146"; +$fa-var-minus-square-o: "\f147"; +$fa-var-mixcloud: "\f289"; +$fa-var-mobile: "\f10b"; +$fa-var-mobile-phone: "\f10b"; +$fa-var-modx: "\f285"; +$fa-var-money: "\f0d6"; +$fa-var-moon-o: "\f186"; +$fa-var-mortar-board: "\f19d"; +$fa-var-motorcycle: "\f21c"; +$fa-var-mouse-pointer: "\f245"; +$fa-var-music: "\f001"; +$fa-var-navicon: "\f0c9"; +$fa-var-neuter: "\f22c"; +$fa-var-newspaper-o: "\f1ea"; +$fa-var-object-group: "\f247"; +$fa-var-object-ungroup: "\f248"; +$fa-var-odnoklassniki: "\f263"; +$fa-var-odnoklassniki-square: "\f264"; +$fa-var-opencart: "\f23d"; +$fa-var-openid: "\f19b"; +$fa-var-opera: "\f26a"; +$fa-var-optin-monster: "\f23c"; +$fa-var-outdent: "\f03b"; +$fa-var-pagelines: "\f18c"; +$fa-var-paint-brush: "\f1fc"; +$fa-var-paper-plane: "\f1d8"; +$fa-var-paper-plane-o: "\f1d9"; +$fa-var-paperclip: "\f0c6"; +$fa-var-paragraph: "\f1dd"; +$fa-var-paste: "\f0ea"; +$fa-var-pause: "\f04c"; +$fa-var-pause-circle: "\f28b"; +$fa-var-pause-circle-o: "\f28c"; +$fa-var-paw: "\f1b0"; +$fa-var-paypal: "\f1ed"; +$fa-var-pencil: "\f040"; +$fa-var-pencil-square: "\f14b"; +$fa-var-pencil-square-o: "\f044"; +$fa-var-percent: "\f295"; +$fa-var-phone: "\f095"; +$fa-var-phone-square: "\f098"; +$fa-var-photo: "\f03e"; +$fa-var-picture-o: "\f03e"; +$fa-var-pie-chart: "\f200"; +$fa-var-pied-piper: "\f2ae"; +$fa-var-pied-piper-alt: "\f1a8"; +$fa-var-pied-piper-pp: "\f1a7"; +$fa-var-pinterest: "\f0d2"; +$fa-var-pinterest-p: "\f231"; +$fa-var-pinterest-square: "\f0d3"; +$fa-var-plane: "\f072"; +$fa-var-play: "\f04b"; +$fa-var-play-circle: "\f144"; +$fa-var-play-circle-o: "\f01d"; +$fa-var-plug: "\f1e6"; +$fa-var-plus: "\f067"; +$fa-var-plus-circle: "\f055"; +$fa-var-plus-square: "\f0fe"; +$fa-var-plus-square-o: "\f196"; +$fa-var-podcast: "\f2ce"; +$fa-var-power-off: "\f011"; +$fa-var-print: "\f02f"; +$fa-var-product-hunt: "\f288"; +$fa-var-puzzle-piece: "\f12e"; +$fa-var-qq: "\f1d6"; +$fa-var-qrcode: "\f029"; +$fa-var-question: "\f128"; +$fa-var-question-circle: "\f059"; +$fa-var-question-circle-o: "\f29c"; +$fa-var-quora: "\f2c4"; +$fa-var-quote-left: "\f10d"; +$fa-var-quote-right: "\f10e"; +$fa-var-ra: "\f1d0"; +$fa-var-random: "\f074"; +$fa-var-ravelry: "\f2d9"; +$fa-var-rebel: "\f1d0"; +$fa-var-recycle: "\f1b8"; +$fa-var-reddit: "\f1a1"; +$fa-var-reddit-alien: "\f281"; +$fa-var-reddit-square: "\f1a2"; +$fa-var-refresh: "\f021"; +$fa-var-registered: "\f25d"; +$fa-var-remove: "\f00d"; +$fa-var-renren: "\f18b"; +$fa-var-reorder: "\f0c9"; +$fa-var-repeat: "\f01e"; +$fa-var-reply: "\f112"; +$fa-var-reply-all: "\f122"; +$fa-var-resistance: "\f1d0"; +$fa-var-retweet: "\f079"; +$fa-var-rmb: "\f157"; +$fa-var-road: "\f018"; +$fa-var-rocket: "\f135"; +$fa-var-rotate-left: "\f0e2"; +$fa-var-rotate-right: "\f01e"; +$fa-var-rouble: "\f158"; +$fa-var-rss: "\f09e"; +$fa-var-rss-square: "\f143"; +$fa-var-rub: "\f158"; +$fa-var-ruble: "\f158"; +$fa-var-rupee: "\f156"; +$fa-var-s15: "\f2cd"; +$fa-var-safari: "\f267"; +$fa-var-save: "\f0c7"; +$fa-var-scissors: "\f0c4"; +$fa-var-scribd: "\f28a"; +$fa-var-search: "\f002"; +$fa-var-search-minus: "\f010"; +$fa-var-search-plus: "\f00e"; +$fa-var-sellsy: "\f213"; +$fa-var-send: "\f1d8"; +$fa-var-send-o: "\f1d9"; +$fa-var-server: "\f233"; +$fa-var-share: "\f064"; +$fa-var-share-alt: "\f1e0"; +$fa-var-share-alt-square: "\f1e1"; +$fa-var-share-square: "\f14d"; +$fa-var-share-square-o: "\f045"; +$fa-var-shekel: "\f20b"; +$fa-var-sheqel: "\f20b"; +$fa-var-shield: "\f132"; +$fa-var-ship: "\f21a"; +$fa-var-shirtsinbulk: "\f214"; +$fa-var-shopping-bag: "\f290"; +$fa-var-shopping-basket: "\f291"; +$fa-var-shopping-cart: "\f07a"; +$fa-var-shower: "\f2cc"; +$fa-var-sign-in: "\f090"; +$fa-var-sign-language: "\f2a7"; +$fa-var-sign-out: "\f08b"; +$fa-var-signal: "\f012"; +$fa-var-signing: "\f2a7"; +$fa-var-simplybuilt: "\f215"; +$fa-var-sitemap: "\f0e8"; +$fa-var-skyatlas: "\f216"; +$fa-var-skype: "\f17e"; +$fa-var-slack: "\f198"; +$fa-var-sliders: "\f1de"; +$fa-var-slideshare: "\f1e7"; +$fa-var-smile-o: "\f118"; +$fa-var-snapchat: "\f2ab"; +$fa-var-snapchat-ghost: "\f2ac"; +$fa-var-snapchat-square: "\f2ad"; +$fa-var-snowflake-o: "\f2dc"; +$fa-var-soccer-ball-o: "\f1e3"; +$fa-var-sort: "\f0dc"; +$fa-var-sort-alpha-asc: "\f15d"; +$fa-var-sort-alpha-desc: "\f15e"; +$fa-var-sort-amount-asc: "\f160"; +$fa-var-sort-amount-desc: "\f161"; +$fa-var-sort-asc: "\f0de"; +$fa-var-sort-desc: "\f0dd"; +$fa-var-sort-down: "\f0dd"; +$fa-var-sort-numeric-asc: "\f162"; +$fa-var-sort-numeric-desc: "\f163"; +$fa-var-sort-up: "\f0de"; +$fa-var-soundcloud: "\f1be"; +$fa-var-space-shuttle: "\f197"; +$fa-var-spinner: "\f110"; +$fa-var-spoon: "\f1b1"; +$fa-var-spotify: "\f1bc"; +$fa-var-square: "\f0c8"; +$fa-var-square-o: "\f096"; +$fa-var-stack-exchange: "\f18d"; +$fa-var-stack-overflow: "\f16c"; +$fa-var-star: "\f005"; +$fa-var-star-half: "\f089"; +$fa-var-star-half-empty: "\f123"; +$fa-var-star-half-full: "\f123"; +$fa-var-star-half-o: "\f123"; +$fa-var-star-o: "\f006"; +$fa-var-steam: "\f1b6"; +$fa-var-steam-square: "\f1b7"; +$fa-var-step-backward: "\f048"; +$fa-var-step-forward: "\f051"; +$fa-var-stethoscope: "\f0f1"; +$fa-var-sticky-note: "\f249"; +$fa-var-sticky-note-o: "\f24a"; +$fa-var-stop: "\f04d"; +$fa-var-stop-circle: "\f28d"; +$fa-var-stop-circle-o: "\f28e"; +$fa-var-street-view: "\f21d"; +$fa-var-strikethrough: "\f0cc"; +$fa-var-stumbleupon: "\f1a4"; +$fa-var-stumbleupon-circle: "\f1a3"; +$fa-var-subscript: "\f12c"; +$fa-var-subway: "\f239"; +$fa-var-suitcase: "\f0f2"; +$fa-var-sun-o: "\f185"; +$fa-var-superpowers: "\f2dd"; +$fa-var-superscript: "\f12b"; +$fa-var-support: "\f1cd"; +$fa-var-table: "\f0ce"; +$fa-var-tablet: "\f10a"; +$fa-var-tachometer: "\f0e4"; +$fa-var-tag: "\f02b"; +$fa-var-tags: "\f02c"; +$fa-var-tasks: "\f0ae"; +$fa-var-taxi: "\f1ba"; +$fa-var-telegram: "\f2c6"; +$fa-var-television: "\f26c"; +$fa-var-tencent-weibo: "\f1d5"; +$fa-var-terminal: "\f120"; +$fa-var-text-height: "\f034"; +$fa-var-text-width: "\f035"; +$fa-var-th: "\f00a"; +$fa-var-th-large: "\f009"; +$fa-var-th-list: "\f00b"; +$fa-var-themeisle: "\f2b2"; +$fa-var-thermometer: "\f2c7"; +$fa-var-thermometer-0: "\f2cb"; +$fa-var-thermometer-1: "\f2ca"; +$fa-var-thermometer-2: "\f2c9"; +$fa-var-thermometer-3: "\f2c8"; +$fa-var-thermometer-4: "\f2c7"; +$fa-var-thermometer-empty: "\f2cb"; +$fa-var-thermometer-full: "\f2c7"; +$fa-var-thermometer-half: "\f2c9"; +$fa-var-thermometer-quarter: "\f2ca"; +$fa-var-thermometer-three-quarters: "\f2c8"; +$fa-var-thumb-tack: "\f08d"; +$fa-var-thumbs-down: "\f165"; +$fa-var-thumbs-o-down: "\f088"; +$fa-var-thumbs-o-up: "\f087"; +$fa-var-thumbs-up: "\f164"; +$fa-var-ticket: "\f145"; +$fa-var-times: "\f00d"; +$fa-var-times-circle: "\f057"; +$fa-var-times-circle-o: "\f05c"; +$fa-var-times-rectangle: "\f2d3"; +$fa-var-times-rectangle-o: "\f2d4"; +$fa-var-tint: "\f043"; +$fa-var-toggle-down: "\f150"; +$fa-var-toggle-left: "\f191"; +$fa-var-toggle-off: "\f204"; +$fa-var-toggle-on: "\f205"; +$fa-var-toggle-right: "\f152"; +$fa-var-toggle-up: "\f151"; +$fa-var-trademark: "\f25c"; +$fa-var-train: "\f238"; +$fa-var-transgender: "\f224"; +$fa-var-transgender-alt: "\f225"; +$fa-var-trash: "\f1f8"; +$fa-var-trash-o: "\f014"; +$fa-var-tree: "\f1bb"; +$fa-var-trello: "\f181"; +$fa-var-tripadvisor: "\f262"; +$fa-var-trophy: "\f091"; +$fa-var-truck: "\f0d1"; +$fa-var-try: "\f195"; +$fa-var-tty: "\f1e4"; +$fa-var-tumblr: "\f173"; +$fa-var-tumblr-square: "\f174"; +$fa-var-turkish-lira: "\f195"; +$fa-var-tv: "\f26c"; +$fa-var-twitch: "\f1e8"; +$fa-var-twitter: "\f099"; +$fa-var-twitter-square: "\f081"; +$fa-var-umbrella: "\f0e9"; +$fa-var-underline: "\f0cd"; +$fa-var-undo: "\f0e2"; +$fa-var-universal-access: "\f29a"; +$fa-var-university: "\f19c"; +$fa-var-unlink: "\f127"; +$fa-var-unlock: "\f09c"; +$fa-var-unlock-alt: "\f13e"; +$fa-var-unsorted: "\f0dc"; +$fa-var-upload: "\f093"; +$fa-var-usb: "\f287"; +$fa-var-usd: "\f155"; +$fa-var-user: "\f007"; +$fa-var-user-circle: "\f2bd"; +$fa-var-user-circle-o: "\f2be"; +$fa-var-user-md: "\f0f0"; +$fa-var-user-o: "\f2c0"; +$fa-var-user-plus: "\f234"; +$fa-var-user-secret: "\f21b"; +$fa-var-user-times: "\f235"; +$fa-var-users: "\f0c0"; +$fa-var-vcard: "\f2bb"; +$fa-var-vcard-o: "\f2bc"; +$fa-var-venus: "\f221"; +$fa-var-venus-double: "\f226"; +$fa-var-venus-mars: "\f228"; +$fa-var-viacoin: "\f237"; +$fa-var-viadeo: "\f2a9"; +$fa-var-viadeo-square: "\f2aa"; +$fa-var-video-camera: "\f03d"; +$fa-var-vimeo: "\f27d"; +$fa-var-vimeo-square: "\f194"; +$fa-var-vine: "\f1ca"; +$fa-var-vk: "\f189"; +$fa-var-volume-control-phone: "\f2a0"; +$fa-var-volume-down: "\f027"; +$fa-var-volume-off: "\f026"; +$fa-var-volume-up: "\f028"; +$fa-var-warning: "\f071"; +$fa-var-wechat: "\f1d7"; +$fa-var-weibo: "\f18a"; +$fa-var-weixin: "\f1d7"; +$fa-var-whatsapp: "\f232"; +$fa-var-wheelchair: "\f193"; +$fa-var-wheelchair-alt: "\f29b"; +$fa-var-wifi: "\f1eb"; +$fa-var-wikipedia-w: "\f266"; +$fa-var-window-close: "\f2d3"; +$fa-var-window-close-o: "\f2d4"; +$fa-var-window-maximize: "\f2d0"; +$fa-var-window-minimize: "\f2d1"; +$fa-var-window-restore: "\f2d2"; +$fa-var-windows: "\f17a"; +$fa-var-won: "\f159"; +$fa-var-wordpress: "\f19a"; +$fa-var-wpbeginner: "\f297"; +$fa-var-wpexplorer: "\f2de"; +$fa-var-wpforms: "\f298"; +$fa-var-wrench: "\f0ad"; +$fa-var-xing: "\f168"; +$fa-var-xing-square: "\f169"; +$fa-var-y-combinator: "\f23b"; +$fa-var-y-combinator-square: "\f1d4"; +$fa-var-yahoo: "\f19e"; +$fa-var-yc: "\f23b"; +$fa-var-yc-square: "\f1d4"; +$fa-var-yelp: "\f1e9"; +$fa-var-yen: "\f157"; +$fa-var-yoast: "\f2b1"; +$fa-var-youtube: "\f167"; +$fa-var-youtube-play: "\f16a"; +$fa-var-youtube-square: "\f166"; + diff --git a/web/css/font-awesome-4.7.0/scss/font-awesome.scss b/web/css/font-awesome-4.7.0/scss/font-awesome.scss new file mode 100644 index 000000000..f1c83aaa5 --- /dev/null +++ b/web/css/font-awesome-4.7.0/scss/font-awesome.scss @@ -0,0 +1,18 @@ +/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */ + +@import "variables"; +@import "mixins"; +@import "path"; +@import "core"; +@import "larger"; +@import "fixed-width"; +@import "list"; +@import "bordered-pulled"; +@import "animated"; +@import "rotated-flipped"; +@import "stacked"; +@import "icons"; +@import "screen-reader"; diff --git a/web/css/jquery.qtip.css b/web/css/jquery.qtip.css new file mode 100644 index 000000000..4f9a78841 --- /dev/null +++ b/web/css/jquery.qtip.css @@ -0,0 +1,625 @@ +/* + * qTip2 - Pretty powerful tooltips - v2.2.0 + * http://qtip2.com + * + * Copyright (c) 2013 Craig Michael Thompson + * Released under the MIT, GPL licenses + * http://jquery.org/license + * + * Date: Thu Nov 21 2013 08:34 GMT+0000 + * Plugins: tips modal viewport svg imagemap ie6 + * Styles: basic css3 + */ +.qtip{ + position: absolute; + left: -28000px; + top: -28000px; + display: none; + + max-width: 280px; + min-width: 50px; + + font-size: 10.5px; + line-height: 12px; + + direction: ltr; + + box-shadow: none; + padding: 0; +} + + .qtip-content{ + position: relative; + padding: 5px 9px; + overflow: hidden; + + text-align: left; + word-wrap: break-word; + } + + .qtip-titlebar{ + position: relative; + padding: 5px 35px 5px 10px; + overflow: hidden; + + border-width: 0 0 1px; + font-weight: bold; + } + + .qtip-titlebar + .qtip-content{ border-top-width: 0 !important; } + + /* Default close button class */ + .qtip-close{ + position: absolute; + right: -9px; top: -9px; + + cursor: pointer; + outline: medium none; + + border-width: 1px; + border-style: solid; + border-color: transparent; + } + + .qtip-titlebar .qtip-close{ + right: 4px; top: 50%; + margin-top: -9px; + } + + * html .qtip-titlebar .qtip-close{ top: 16px; } /* IE fix */ + + .qtip-titlebar .ui-icon, + .qtip-icon .ui-icon{ + display: block; + text-indent: -1000em; + direction: ltr; + } + + .qtip-icon, .qtip-icon .ui-icon{ + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + border-radius: 3px; + text-decoration: none; + } + + .qtip-icon .ui-icon{ + width: 18px; + height: 14px; + + line-height: 14px; + text-align: center; + text-indent: 0; + font: normal bold 10px/13px Tahoma,sans-serif; + + color: inherit; + background: transparent none no-repeat -100em -100em; + } + +/* Applied to 'focused' tooltips e.g. most recently displayed/interacted with */ +.qtip-focus{} + +/* Applied on hover of tooltips i.e. added/removed on mouseenter/mouseleave respectively */ +.qtip-hover{} + +/* Default tooltip style */ +.qtip-default{ + border-width: 1px; + border-style: solid; + border-color: #F1D031; + + background-color: #FFFFA3; + color: #555; +} + + .qtip-default .qtip-titlebar{ + background-color: #FFEF93; + } + + .qtip-default .qtip-icon{ + border-color: #CCC; + background: #F1F1F1; + color: #777; + } + + .qtip-default .qtip-titlebar .qtip-close{ + border-color: #AAA; + color: #111; + } + + + +/*! Light tooltip style */ +.qtip-light{ + background-color: white; + border-color: #E2E2E2; + color: #454545; +} + + .qtip-light .qtip-titlebar{ + background-color: #f1f1f1; + } + + +/*! Dark tooltip style */ +.qtip-dark{ + background-color: #505050; + border-color: #303030; + color: #f3f3f3; +} + + .qtip-dark .qtip-titlebar{ + background-color: #404040; + } + + .qtip-dark .qtip-icon{ + border-color: #444; + } + + .qtip-dark .qtip-titlebar .ui-state-hover{ + border-color: #303030; + } + + +/*! Cream tooltip style */ +.qtip-cream{ + background-color: #FBF7AA; + border-color: #F9E98E; + color: #A27D35; +} + + .qtip-cream .qtip-titlebar{ + background-color: #F0DE7D; + } + + .qtip-cream .qtip-close .qtip-icon{ + background-position: -82px 0; + } + + +/*! Red tooltip style */ +.qtip-red{ + background-color: #F78B83; + border-color: #D95252; + color: #912323; +} + + .qtip-red .qtip-titlebar{ + background-color: #F06D65; + } + + .qtip-red .qtip-close .qtip-icon{ + background-position: -102px 0; + } + + .qtip-red .qtip-icon{ + border-color: #D95252; + } + + .qtip-red .qtip-titlebar .ui-state-hover{ + border-color: #D95252; + } + + +/*! Green tooltip style */ +.qtip-green{ + background-color: #CAED9E; + border-color: #90D93F; + color: #3F6219; +} + + .qtip-green .qtip-titlebar{ + background-color: #B0DE78; + } + + .qtip-green .qtip-close .qtip-icon{ + background-position: -42px 0; + } + + +/*! Blue tooltip style */ +.qtip-blue{ + background-color: #E5F6FE; + border-color: #ADD9ED; + color: #5E99BD; +} + + .qtip-blue .qtip-titlebar{ + background-color: #D0E9F5; + } + + .qtip-blue .qtip-close .qtip-icon{ + background-position: -2px 0; + } + + + +.qtip-shadow{ + -webkit-box-shadow: 1px 1px 3px 1px rgba(0, 0, 0, 0.15); + -moz-box-shadow: 1px 1px 3px 1px rgba(0, 0, 0, 0.15); + box-shadow: 1px 1px 3px 1px rgba(0, 0, 0, 0.15); +} + +/* Add rounded corners to your tooltips in: FF3+, Chrome 2+, Opera 10.6+, IE9+, Safari 2+ */ +.qtip-rounded, +.qtip-tipsy, +.qtip-bootstrap{ + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + border-radius: 5px; +} + +.qtip-rounded .qtip-titlebar{ + -moz-border-radius: 4px 4px 0 0; + -webkit-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} + +/* Youtube tooltip style */ +.qtip-youtube{ + -moz-border-radius: 2px; + -webkit-border-radius: 2px; + border-radius: 2px; + + -webkit-box-shadow: 0 0 3px #333; + -moz-box-shadow: 0 0 3px #333; + box-shadow: 0 0 3px #333; + + color: white; + border-width: 0; + + background: #4A4A4A; + background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0,#4A4A4A),color-stop(100%,black)); + background-image: -webkit-linear-gradient(top,#4A4A4A 0,black 100%); + background-image: -moz-linear-gradient(top,#4A4A4A 0,black 100%); + background-image: -ms-linear-gradient(top,#4A4A4A 0,black 100%); + background-image: -o-linear-gradient(top,#4A4A4A 0,black 100%); +} + + .qtip-youtube .qtip-titlebar{ + background-color: #4A4A4A; + background-color: rgba(0,0,0,0); + } + + .qtip-youtube .qtip-content{ + padding: .75em; + font: 12px arial,sans-serif; + + filter: progid:DXImageTransform.Microsoft.Gradient(GradientType=0,StartColorStr=#4a4a4a,EndColorStr=#000000); + -ms-filter: "progid:DXImageTransform.Microsoft.Gradient(GradientType=0,StartColorStr=#4a4a4a,EndColorStr=#000000);"; + } + + .qtip-youtube .qtip-icon{ + border-color: #222; + } + + .qtip-youtube .qtip-titlebar .ui-state-hover{ + border-color: #303030; + } + + +/* jQuery TOOLS Tooltip style */ +.qtip-jtools{ + background: #232323; + background: rgba(0, 0, 0, 0.7); + background-image: -webkit-gradient(linear, left top, left bottom, from(#717171), to(#232323)); + background-image: -moz-linear-gradient(top, #717171, #232323); + background-image: -webkit-linear-gradient(top, #717171, #232323); + background-image: -ms-linear-gradient(top, #717171, #232323); + background-image: -o-linear-gradient(top, #717171, #232323); + + border: 2px solid #ddd; + border: 2px solid rgba(241,241,241,1); + + -moz-border-radius: 2px; + -webkit-border-radius: 2px; + border-radius: 2px; + + -webkit-box-shadow: 0 0 12px #333; + -moz-box-shadow: 0 0 12px #333; + box-shadow: 0 0 12px #333; +} + + /* IE Specific */ + .qtip-jtools .qtip-titlebar{ + background-color: transparent; + filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#717171,endColorstr=#4A4A4A); + -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#717171,endColorstr=#4A4A4A)"; + } + .qtip-jtools .qtip-content{ + filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#4A4A4A,endColorstr=#232323); + -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#4A4A4A,endColorstr=#232323)"; + } + + .qtip-jtools .qtip-titlebar, + .qtip-jtools .qtip-content{ + background: transparent; + color: white; + border: 0 dashed transparent; + } + + .qtip-jtools .qtip-icon{ + border-color: #555; + } + + .qtip-jtools .qtip-titlebar .ui-state-hover{ + border-color: #333; + } + + +/* Cluetip style */ +.qtip-cluetip{ + -webkit-box-shadow: 4px 4px 5px rgba(0, 0, 0, 0.4); + -moz-box-shadow: 4px 4px 5px rgba(0, 0, 0, 0.4); + box-shadow: 4px 4px 5px rgba(0, 0, 0, 0.4); + + background-color: #D9D9C2; + color: #111; + border: 0 dashed transparent; +} + + .qtip-cluetip .qtip-titlebar{ + background-color: #87876A; + color: white; + border: 0 dashed transparent; + } + + .qtip-cluetip .qtip-icon{ + border-color: #808064; + } + + .qtip-cluetip .qtip-titlebar .ui-state-hover{ + border-color: #696952; + color: #696952; + } + + +/* Tipsy style */ +.qtip-tipsy{ + background: black; + background: rgba(0, 0, 0, .87); + + color: white; + border: 0 solid transparent; + + font-size: 11px; + font-family: 'Lucida Grande', sans-serif; + font-weight: bold; + line-height: 16px; + text-shadow: 0 1px black; +} + + .qtip-tipsy .qtip-titlebar{ + padding: 6px 35px 0 10px; + background-color: transparent; + } + + .qtip-tipsy .qtip-content{ + padding: 6px 10px; + } + + .qtip-tipsy .qtip-icon{ + border-color: #222; + text-shadow: none; + } + + .qtip-tipsy .qtip-titlebar .ui-state-hover{ + border-color: #303030; + } + + +/* Tipped style */ +.qtip-tipped{ + border: 3px solid #959FA9; + + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + border-radius: 3px; + + background-color: #F9F9F9; + color: #454545; + + font-weight: normal; + font-family: serif; +} + + .qtip-tipped .qtip-titlebar{ + border-bottom-width: 0; + + color: white; + background: #3A79B8; + background-image: -webkit-gradient(linear, left top, left bottom, from(#3A79B8), to(#2E629D)); + background-image: -webkit-linear-gradient(top, #3A79B8, #2E629D); + background-image: -moz-linear-gradient(top, #3A79B8, #2E629D); + background-image: -ms-linear-gradient(top, #3A79B8, #2E629D); + background-image: -o-linear-gradient(top, #3A79B8, #2E629D); + filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#3A79B8,endColorstr=#2E629D); + -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#3A79B8,endColorstr=#2E629D)"; + } + + .qtip-tipped .qtip-icon{ + border: 2px solid #285589; + background: #285589; + } + + .qtip-tipped .qtip-icon .ui-icon{ + background-color: #FBFBFB; + color: #555; + } + + +/** + * Twitter Bootstrap style. + * + * Tested with IE 8, IE 9, Chrome 18, Firefox 9, Opera 11. + * Does not work with IE 7. + */ +.qtip-bootstrap{ + /** Taken from Bootstrap body */ + font-size: 14px; + line-height: 20px; + color: #333333; + + /** Taken from Bootstrap .popover */ + padding: 1px; + background-color: #f0f0f0; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.2); + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; +} + + .qtip-bootstrap .qtip-titlebar{ + /** Taken from Bootstrap .popover-title */ + padding: 8px 14px; + margin: 0; + font-size: 14px; + font-weight: normal; + line-height: 18px; + background-color: #f7f7f7; + border-bottom: 1px solid #ebebeb; + -webkit-border-radius: 5px 5px 0 0; + -moz-border-radius: 5px 5px 0 0; + border-radius: 5px 5px 0 0; + } + + .qtip-bootstrap .qtip-titlebar .qtip-close{ + /** + * Overrides qTip2: + * .qtip-titlebar .qtip-close{ + * [...] + * right: 4px; + * top: 50%; + * [...] + * border-style: solid; + * } + */ + right: 11px; + top: 45%; + border-style: none; + } + + .qtip-bootstrap .qtip-content{ + /** Taken from Bootstrap .popover-content */ + padding: 1px 1px; + font-family:monospace,monospace; + font-size:0.9em; + } + + .qtip-bootstrap .qtip-icon{ + /** + * Overrides qTip2: + * .qtip-default .qtip-icon { + * border-color: #CCC; + * background: #F1F1F1; + * color: #777; + * } + */ + background: transparent; + } + + .qtip-bootstrap .qtip-icon .ui-icon{ + /** + * Overrides qTip2: + * .qtip-icon .ui-icon{ + * width: 18px; + * height: 14px; + * } + */ + width: auto; + height: auto; + + /* Taken from Bootstrap .close */ + float: right; + font-size: 20px; + font-weight: bold; + line-height: 18px; + color: #000000; + text-shadow: 0 1px 0 #ffffff; + opacity: 0.2; + filter: alpha(opacity=20); + } + + .qtip-bootstrap .qtip-icon .ui-icon:hover{ + /* Taken from Bootstrap .close:hover */ + color: #000000; + text-decoration: none; + cursor: pointer; + opacity: 0.4; + filter: alpha(opacity=40); + } + + +/* IE9 fix - removes all filters */ +.qtip:not(.ie9haxors) div.qtip-content, +.qtip:not(.ie9haxors) div.qtip-titlebar{ + filter: none; + -ms-filter: none; +} + + + +.qtip .qtip-tip{ + margin: 0 auto; + overflow: hidden; + z-index: 10; + +} + + /* Opera bug #357 - Incorrect tip position + https://github.com/Craga89/qTip2/issues/367 */ + x:-o-prefocus, .qtip .qtip-tip{ + visibility: hidden; + } + + .qtip .qtip-tip, + .qtip .qtip-tip .qtip-vml, + .qtip .qtip-tip canvas{ + position: absolute; + + color: #123456; + background: transparent; + border: 0 dashed transparent; + } + + .qtip .qtip-tip canvas{ top: 0; left: 0; } + + .qtip .qtip-tip .qtip-vml{ + behavior: url(#default#VML); + display: inline-block; + visibility: visible; + } + +#qtip-overlay{ + position: fixed; + left: 0; top: 0; + width: 100%; height: 100%; +} + + /* Applied to modals with show.modal.blur set to true */ + #qtip-overlay.blurs{ cursor: pointer; } + + /* Change opacity of overlay here */ + #qtip-overlay div{ + position: absolute; + left: 0; top: 0; + width: 100%; height: 100%; + + background-color: black; + + opacity: 0.7; + filter:alpha(opacity=70); + -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=70)"; + } + + + +.qtipmodal-ie6fix{ + position: absolute !important; +} \ No newline at end of file diff --git a/web/css/nprogress.css b/web/css/nprogress.css new file mode 100644 index 000000000..6752d7f4b --- /dev/null +++ b/web/css/nprogress.css @@ -0,0 +1,74 @@ +/* Make clicks pass-through */ +#nprogress { + pointer-events: none; +} + +#nprogress .bar { + background: #29d; + + position: fixed; + z-index: 1031; + top: 0; + left: 0; + + width: 100%; + height: 2px; +} + +/* Fancy blur effect */ +#nprogress .peg { + display: block; + position: absolute; + right: 0px; + width: 100px; + height: 100%; + box-shadow: 0 0 10px #29d, 0 0 5px #29d; + opacity: 1.0; + + -webkit-transform: rotate(3deg) translate(0px, -4px); + -ms-transform: rotate(3deg) translate(0px, -4px); + transform: rotate(3deg) translate(0px, -4px); +} + +/* Remove these to get rid of the spinner */ +#nprogress .spinner { + display: block; + position: fixed; + z-index: 1031; + top: 15px; + right: 15px; +} + +#nprogress .spinner-icon { + width: 18px; + height: 18px; + box-sizing: border-box; + + border: solid 2px transparent; + border-top-color: #29d; + border-left-color: #29d; + border-radius: 50%; + + -webkit-animation: nprogress-spinner 400ms linear infinite; + animation: nprogress-spinner 400ms linear infinite; +} + +.nprogress-custom-parent { + overflow: hidden; + position: relative; +} + +.nprogress-custom-parent #nprogress .spinner, +.nprogress-custom-parent #nprogress .bar { + position: absolute; +} + +@-webkit-keyframes nprogress-spinner { + 0% { -webkit-transform: rotate(0deg); } + 100% { -webkit-transform: rotate(360deg); } +} +@keyframes nprogress-spinner { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + diff --git a/web/favicon.ico b/web/favicon.ico new file mode 100644 index 000000000..7eb9398b4 Binary files /dev/null and b/web/favicon.ico differ diff --git a/web/icons/aws/Analytics/Analytics_AWSDataPipeline.svg b/web/icons/aws/Analytics/Analytics_AWSDataPipeline.svg new file mode 100644 index 000000000..7f3148e88 --- /dev/null +++ b/web/icons/aws/Analytics/Analytics_AWSDataPipeline.svg @@ -0,0 +1,13 @@ + + Analytics + + + + + + + + + + + diff --git a/web/icons/aws/Analytics/Analytics_AmazonAthena.svg b/web/icons/aws/Analytics/Analytics_AmazonAthena.svg new file mode 100644 index 000000000..2b2f435d6 --- /dev/null +++ b/web/icons/aws/Analytics/Analytics_AmazonAthena.svg @@ -0,0 +1,23 @@ + + Analytics + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Analytics/Analytics_AmazonCloudSearch.svg b/web/icons/aws/Analytics/Analytics_AmazonCloudSearch.svg new file mode 100644 index 000000000..65bc17260 --- /dev/null +++ b/web/icons/aws/Analytics/Analytics_AmazonCloudSearch.svg @@ -0,0 +1,19 @@ + + Analytics + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Analytics/Analytics_AmazonCloudSearch_searchdocuments.svg b/web/icons/aws/Analytics/Analytics_AmazonCloudSearch_searchdocuments.svg new file mode 100644 index 000000000..7d8fbfbb3 --- /dev/null +++ b/web/icons/aws/Analytics/Analytics_AmazonCloudSearch_searchdocuments.svg @@ -0,0 +1,19 @@ + + Analytics + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Analytics/Analytics_AmazonEMR-HDFScluster.svg b/web/icons/aws/Analytics/Analytics_AmazonEMR-HDFScluster.svg new file mode 100644 index 000000000..087b46c4a --- /dev/null +++ b/web/icons/aws/Analytics/Analytics_AmazonEMR-HDFScluster.svg @@ -0,0 +1,13 @@ + + Analytics + + + + + + + + + + + diff --git a/web/icons/aws/Analytics/Analytics_AmazonEMR.svg b/web/icons/aws/Analytics/Analytics_AmazonEMR.svg new file mode 100644 index 000000000..d034a2809 --- /dev/null +++ b/web/icons/aws/Analytics/Analytics_AmazonEMR.svg @@ -0,0 +1,16 @@ + + Analytics + + + + + + + + + + + + + + diff --git a/web/icons/aws/Analytics/Analytics_AmazonEMR_EMRengine.svg b/web/icons/aws/Analytics/Analytics_AmazonEMR_EMRengine.svg new file mode 100644 index 000000000..e3a46f241 --- /dev/null +++ b/web/icons/aws/Analytics/Analytics_AmazonEMR_EMRengine.svg @@ -0,0 +1,7 @@ + + Analytics + + + + + diff --git a/web/icons/aws/Analytics/Analytics_AmazonEMR_EMRengineMapRM3.svg b/web/icons/aws/Analytics/Analytics_AmazonEMR_EMRengineMapRM3.svg new file mode 100644 index 000000000..650c5ec84 --- /dev/null +++ b/web/icons/aws/Analytics/Analytics_AmazonEMR_EMRengineMapRM3.svg @@ -0,0 +1,17 @@ + + Analytics + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Analytics/Analytics_AmazonEMR_EMRengineMapRM5.svg b/web/icons/aws/Analytics/Analytics_AmazonEMR_EMRengineMapRM5.svg new file mode 100644 index 000000000..0ea0a89f0 --- /dev/null +++ b/web/icons/aws/Analytics/Analytics_AmazonEMR_EMRengineMapRM5.svg @@ -0,0 +1,15 @@ + + Analytics + + + + + + + + + + + + + diff --git a/web/icons/aws/Analytics/Analytics_AmazonEMR_EMRengineMapRM7.svg b/web/icons/aws/Analytics/Analytics_AmazonEMR_EMRengineMapRM7.svg new file mode 100644 index 000000000..241fe44ff --- /dev/null +++ b/web/icons/aws/Analytics/Analytics_AmazonEMR_EMRengineMapRM7.svg @@ -0,0 +1,15 @@ + + Analytics + + + + + + + + + + + + + diff --git a/web/icons/aws/Analytics/Analytics_AmazonEMR_cluster.svg b/web/icons/aws/Analytics/Analytics_AmazonEMR_cluster.svg new file mode 100644 index 000000000..7737bbb20 --- /dev/null +++ b/web/icons/aws/Analytics/Analytics_AmazonEMR_cluster.svg @@ -0,0 +1,7 @@ + + Analytics + + + + + diff --git a/web/icons/aws/Analytics/Analytics_AmazonES.svg b/web/icons/aws/Analytics/Analytics_AmazonES.svg new file mode 100644 index 000000000..594703fe3 --- /dev/null +++ b/web/icons/aws/Analytics/Analytics_AmazonES.svg @@ -0,0 +1,14 @@ + + Analytics + + + + + + + + + + + + diff --git a/web/icons/aws/Analytics/Analytics_AmazonKinesis.svg b/web/icons/aws/Analytics/Analytics_AmazonKinesis.svg new file mode 100644 index 000000000..3ad5f427e --- /dev/null +++ b/web/icons/aws/Analytics/Analytics_AmazonKinesis.svg @@ -0,0 +1,19 @@ + + Analytics + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Analytics/Analytics_AmazonKinesis_AmazonKinesis-enabledapp.svg b/web/icons/aws/Analytics/Analytics_AmazonKinesis_AmazonKinesis-enabledapp.svg new file mode 100644 index 000000000..38f25d421 --- /dev/null +++ b/web/icons/aws/Analytics/Analytics_AmazonKinesis_AmazonKinesis-enabledapp.svg @@ -0,0 +1,12 @@ + + Analytics + + + + + + + + + + diff --git a/web/icons/aws/Analytics/Analytics_AmazonKinesis_AmazonKinesisAnalytics.svg b/web/icons/aws/Analytics/Analytics_AmazonKinesis_AmazonKinesisAnalytics.svg new file mode 100644 index 000000000..9c97046bc --- /dev/null +++ b/web/icons/aws/Analytics/Analytics_AmazonKinesis_AmazonKinesisAnalytics.svg @@ -0,0 +1,17 @@ + + Analytics + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Analytics/Analytics_AmazonKinesis_AmazonKinesisFirehose.svg b/web/icons/aws/Analytics/Analytics_AmazonKinesis_AmazonKinesisFirehose.svg new file mode 100644 index 000000000..003f067ab --- /dev/null +++ b/web/icons/aws/Analytics/Analytics_AmazonKinesis_AmazonKinesisFirehose.svg @@ -0,0 +1,15 @@ + + Analytics + + + + + + + + + + + + + diff --git a/web/icons/aws/Analytics/Analytics_AmazonKinesis_AmazonKinesisStreams.svg b/web/icons/aws/Analytics/Analytics_AmazonKinesis_AmazonKinesisStreams.svg new file mode 100644 index 000000000..f499ab3fd --- /dev/null +++ b/web/icons/aws/Analytics/Analytics_AmazonKinesis_AmazonKinesisStreams.svg @@ -0,0 +1,11 @@ + + Analytics + + + + + + + + + diff --git a/web/icons/aws/Analytics/Analytics_AmazonQuickSight.svg b/web/icons/aws/Analytics/Analytics_AmazonQuickSight.svg new file mode 100644 index 000000000..97d6345fa --- /dev/null +++ b/web/icons/aws/Analytics/Analytics_AmazonQuickSight.svg @@ -0,0 +1,6 @@ + + Analytics + + + + diff --git a/web/icons/aws/Analytics/Analytics_AmazonRedshift.svg b/web/icons/aws/Analytics/Analytics_AmazonRedshift.svg new file mode 100644 index 000000000..0b40e38c6 --- /dev/null +++ b/web/icons/aws/Analytics/Analytics_AmazonRedshift.svg @@ -0,0 +1,12 @@ + + Analytics + + + + + + + + + + diff --git a/web/icons/aws/Analytics/Analytics_AmazonRedshift_densecomputenode.svg b/web/icons/aws/Analytics/Analytics_AmazonRedshift_densecomputenode.svg new file mode 100644 index 000000000..255bcd722 --- /dev/null +++ b/web/icons/aws/Analytics/Analytics_AmazonRedshift_densecomputenode.svg @@ -0,0 +1,15 @@ + + Database + + + + + + + + + + + + + diff --git a/web/icons/aws/Analytics/Analytics_AmazonRedshift_densestoragenode.svg b/web/icons/aws/Analytics/Analytics_AmazonRedshift_densestoragenode.svg new file mode 100644 index 000000000..99a2b5e3c --- /dev/null +++ b/web/icons/aws/Analytics/Analytics_AmazonRedshift_densestoragenode.svg @@ -0,0 +1,15 @@ + + Database + + + + + + + + + + + + + diff --git a/web/icons/aws/Application Services/ApplicationServices_AWSStepFunctions.svg b/web/icons/aws/Application Services/ApplicationServices_AWSStepFunctions.svg new file mode 100644 index 000000000..77573c5b6 --- /dev/null +++ b/web/icons/aws/Application Services/ApplicationServices_AWSStepFunctions.svg @@ -0,0 +1,34 @@ + + ApplicationServices + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Application Services/ApplicationServices_AmazonAPIGateway.svg b/web/icons/aws/Application Services/ApplicationServices_AmazonAPIGateway.svg new file mode 100644 index 000000000..d292cfa3a --- /dev/null +++ b/web/icons/aws/Application Services/ApplicationServices_AmazonAPIGateway.svg @@ -0,0 +1,27 @@ + + ApplicationServices + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Application Services/ApplicationServices_AmazonAppStream.svg b/web/icons/aws/Application Services/ApplicationServices_AmazonAppStream.svg new file mode 100644 index 000000000..3125cf3bc --- /dev/null +++ b/web/icons/aws/Application Services/ApplicationServices_AmazonAppStream.svg @@ -0,0 +1,18 @@ + + ApplicationServices + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Application Services/ApplicationServices_AmazonElasticTranscoder.svg b/web/icons/aws/Application Services/ApplicationServices_AmazonElasticTranscoder.svg new file mode 100644 index 000000000..7212c1435 --- /dev/null +++ b/web/icons/aws/Application Services/ApplicationServices_AmazonElasticTranscoder.svg @@ -0,0 +1,37 @@ + + ApplicationServices + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Application Services/ApplicationServices_AmazonSWF.svg b/web/icons/aws/Application Services/ApplicationServices_AmazonSWF.svg new file mode 100644 index 000000000..3b022ee9b --- /dev/null +++ b/web/icons/aws/Application Services/ApplicationServices_AmazonSWF.svg @@ -0,0 +1,14 @@ + + Messaging + + + + + + + + + + + + diff --git a/web/icons/aws/Application Services/ApplicationServices_AmazonSWF_decider.svg b/web/icons/aws/Application Services/ApplicationServices_AmazonSWF_decider.svg new file mode 100644 index 000000000..70cb2f526 --- /dev/null +++ b/web/icons/aws/Application Services/ApplicationServices_AmazonSWF_decider.svg @@ -0,0 +1,18 @@ + + Messaging + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Application Services/ApplicationServices_AmazonSWF_worker.svg b/web/icons/aws/Application Services/ApplicationServices_AmazonSWF_worker.svg new file mode 100644 index 000000000..9b56fd0dc --- /dev/null +++ b/web/icons/aws/Application Services/ApplicationServices_AmazonSWF_worker.svg @@ -0,0 +1,11 @@ + + Messaging + + + + + + + + + diff --git a/web/icons/aws/Artificial Intelligence/AI_AmazonLex.svg b/web/icons/aws/Artificial Intelligence/AI_AmazonLex.svg new file mode 100644 index 000000000..f995bec11 --- /dev/null +++ b/web/icons/aws/Artificial Intelligence/AI_AmazonLex.svg @@ -0,0 +1,17 @@ + + AI + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Artificial Intelligence/AI_AmazonMachineLearning.svg b/web/icons/aws/Artificial Intelligence/AI_AmazonMachineLearning.svg new file mode 100644 index 000000000..db4663567 --- /dev/null +++ b/web/icons/aws/Artificial Intelligence/AI_AmazonMachineLearning.svg @@ -0,0 +1,29 @@ + + AI + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Artificial Intelligence/AI_AmazonPolly.svg b/web/icons/aws/Artificial Intelligence/AI_AmazonPolly.svg new file mode 100644 index 000000000..221e5da60 --- /dev/null +++ b/web/icons/aws/Artificial Intelligence/AI_AmazonPolly.svg @@ -0,0 +1,24 @@ + + AI + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Artificial Intelligence/AI_AmazonRekognition.svg b/web/icons/aws/Artificial Intelligence/AI_AmazonRekognition.svg new file mode 100644 index 000000000..19273accc --- /dev/null +++ b/web/icons/aws/Artificial Intelligence/AI_AmazonRekognition.svg @@ -0,0 +1,19 @@ + + AI + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Business Productivity/BusinessProductivity_AmazonWorkDocs.svg b/web/icons/aws/Business Productivity/BusinessProductivity_AmazonWorkDocs.svg new file mode 100644 index 000000000..569a33c3f --- /dev/null +++ b/web/icons/aws/Business Productivity/BusinessProductivity_AmazonWorkDocs.svg @@ -0,0 +1,21 @@ + + + + + + + + BusinessProductivity + + + + + + + + + + + + + diff --git a/web/icons/aws/Business Productivity/BusinessProductivity_AmazonWorkMail.svg b/web/icons/aws/Business Productivity/BusinessProductivity_AmazonWorkMail.svg new file mode 100644 index 000000000..297cb0626 --- /dev/null +++ b/web/icons/aws/Business Productivity/BusinessProductivity_AmazonWorkMail.svg @@ -0,0 +1,13 @@ + + + + + + + + BusinessProductivity + + + + + diff --git a/web/icons/aws/Compute/Compute_AWSBatch.svg b/web/icons/aws/Compute/Compute_AWSBatch.svg new file mode 100644 index 000000000..e60fc97fb --- /dev/null +++ b/web/icons/aws/Compute/Compute_AWSBatch.svg @@ -0,0 +1,25 @@ + + Compute + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Compute/Compute_AWSElasticBeanstalk.svg b/web/icons/aws/Compute/Compute_AWSElasticBeanstalk.svg new file mode 100644 index 000000000..cc69fb8a3 --- /dev/null +++ b/web/icons/aws/Compute/Compute_AWSElasticBeanstalk.svg @@ -0,0 +1,13 @@ + + Compute + + + + + + + + + + + diff --git a/web/icons/aws/Compute/Compute_AWSElasticBeanstalk_application.svg b/web/icons/aws/Compute/Compute_AWSElasticBeanstalk_application.svg new file mode 100644 index 000000000..be9236365 --- /dev/null +++ b/web/icons/aws/Compute/Compute_AWSElasticBeanstalk_application.svg @@ -0,0 +1,7 @@ + + Compute + + + + + diff --git a/web/icons/aws/Compute/Compute_AWSElasticBeanstalk_deployment.svg b/web/icons/aws/Compute/Compute_AWSElasticBeanstalk_deployment.svg new file mode 100644 index 000000000..9904e87ee --- /dev/null +++ b/web/icons/aws/Compute/Compute_AWSElasticBeanstalk_deployment.svg @@ -0,0 +1,10 @@ + + Compute + + + + + + + + diff --git a/web/icons/aws/Compute/Compute_AWSLambda.svg b/web/icons/aws/Compute/Compute_AWSLambda.svg new file mode 100644 index 000000000..6e67ff218 --- /dev/null +++ b/web/icons/aws/Compute/Compute_AWSLambda.svg @@ -0,0 +1,16 @@ + + Compute + + + + + + + + + + + + + + diff --git a/web/icons/aws/Compute/Compute_AWSLambda_LambdaFunction.svg b/web/icons/aws/Compute/Compute_AWSLambda_LambdaFunction.svg new file mode 100644 index 000000000..c14ba1501 --- /dev/null +++ b/web/icons/aws/Compute/Compute_AWSLambda_LambdaFunction.svg @@ -0,0 +1,9 @@ + + Compute + + + + + + + diff --git a/web/icons/aws/Compute/Compute_AmazonEC2.svg b/web/icons/aws/Compute/Compute_AmazonEC2.svg new file mode 100644 index 000000000..de372045b --- /dev/null +++ b/web/icons/aws/Compute/Compute_AmazonEC2.svg @@ -0,0 +1,13 @@ + + Compute + + + + + + + + + + + diff --git a/web/icons/aws/Compute/Compute_AmazonEC2_AMI.svg b/web/icons/aws/Compute/Compute_AmazonEC2_AMI.svg new file mode 100644 index 000000000..5fb38ccf8 --- /dev/null +++ b/web/icons/aws/Compute/Compute_AmazonEC2_AMI.svg @@ -0,0 +1,15 @@ + + Compute + + + + + + + + + + + + + diff --git a/web/icons/aws/Compute/Compute_AmazonEC2_AutoScaling.svg b/web/icons/aws/Compute/Compute_AmazonEC2_AutoScaling.svg new file mode 100644 index 000000000..7b915e191 --- /dev/null +++ b/web/icons/aws/Compute/Compute_AmazonEC2_AutoScaling.svg @@ -0,0 +1,11 @@ + + Compute + + + + + + + + + diff --git a/web/icons/aws/Compute/Compute_AmazonEC2_DBoninstance.svg b/web/icons/aws/Compute/Compute_AmazonEC2_DBoninstance.svg new file mode 100644 index 000000000..4c565c252 --- /dev/null +++ b/web/icons/aws/Compute/Compute_AmazonEC2_DBoninstance.svg @@ -0,0 +1,12 @@ + + Compute + + + + + + + + + + diff --git a/web/icons/aws/Compute/Compute_AmazonEC2_ElasticIPaddress.svg b/web/icons/aws/Compute/Compute_AmazonEC2_ElasticIPaddress.svg new file mode 100644 index 000000000..7fe4a2389 --- /dev/null +++ b/web/icons/aws/Compute/Compute_AmazonEC2_ElasticIPaddress.svg @@ -0,0 +1,7 @@ + + Compute + + + + + diff --git a/web/icons/aws/Compute/Compute_AmazonEC2_SpotFleet.svg b/web/icons/aws/Compute/Compute_AmazonEC2_SpotFleet.svg new file mode 100644 index 000000000..a8f81e510 --- /dev/null +++ b/web/icons/aws/Compute/Compute_AmazonEC2_SpotFleet.svg @@ -0,0 +1,40 @@ + + + + + + + + + + Compute + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Compute/Compute_AmazonEC2_Spotinstance.svg b/web/icons/aws/Compute/Compute_AmazonEC2_Spotinstance.svg new file mode 100644 index 000000000..ea12a7ea9 --- /dev/null +++ b/web/icons/aws/Compute/Compute_AmazonEC2_Spotinstance.svg @@ -0,0 +1,10 @@ + + Compute + + + + + + + + diff --git a/web/icons/aws/Compute/Compute_AmazonEC2_X1instance.svg b/web/icons/aws/Compute/Compute_AmazonEC2_X1instance.svg new file mode 100644 index 000000000..f6bec7b43 --- /dev/null +++ b/web/icons/aws/Compute/Compute_AmazonEC2_X1instance.svg @@ -0,0 +1,14 @@ + + Compute + + + + + + + + + + + + diff --git a/web/icons/aws/Compute/Compute_AmazonEC2_instance.svg b/web/icons/aws/Compute/Compute_AmazonEC2_instance.svg new file mode 100644 index 000000000..7c0b02889 --- /dev/null +++ b/web/icons/aws/Compute/Compute_AmazonEC2_instance.svg @@ -0,0 +1,7 @@ + + Compute + + + + + diff --git a/web/icons/aws/Compute/Compute_AmazonEC2_instances.svg b/web/icons/aws/Compute/Compute_AmazonEC2_instances.svg new file mode 100644 index 000000000..af0b0dd64 --- /dev/null +++ b/web/icons/aws/Compute/Compute_AmazonEC2_instances.svg @@ -0,0 +1,11 @@ + + Compute + + + + + + + + + diff --git a/web/icons/aws/Compute/Compute_AmazonEC2_instancewithCloudWatch.svg b/web/icons/aws/Compute/Compute_AmazonEC2_instancewithCloudWatch.svg new file mode 100644 index 000000000..4e8ad2bb0 --- /dev/null +++ b/web/icons/aws/Compute/Compute_AmazonEC2_instancewithCloudWatch.svg @@ -0,0 +1,13 @@ + + Compute + + + + + + + + + + + diff --git a/web/icons/aws/Compute/Compute_AmazonEC2_optimizedinstance.svg b/web/icons/aws/Compute/Compute_AmazonEC2_optimizedinstance.svg new file mode 100644 index 000000000..ebee15615 --- /dev/null +++ b/web/icons/aws/Compute/Compute_AmazonEC2_optimizedinstance.svg @@ -0,0 +1,13 @@ + + Compute + + + + + + + + + + + diff --git a/web/icons/aws/Compute/Compute_AmazonECR.svg b/web/icons/aws/Compute/Compute_AmazonECR.svg new file mode 100644 index 000000000..aa225c5fb --- /dev/null +++ b/web/icons/aws/Compute/Compute_AmazonECR.svg @@ -0,0 +1,25 @@ + + Compute + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Compute/Compute_AmazonECR_ECRRegistry.svg b/web/icons/aws/Compute/Compute_AmazonECR_ECRRegistry.svg new file mode 100644 index 000000000..47ef43cc7 --- /dev/null +++ b/web/icons/aws/Compute/Compute_AmazonECR_ECRRegistry.svg @@ -0,0 +1,67 @@ + + Compute + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Compute/Compute_AmazonECS.svg b/web/icons/aws/Compute/Compute_AmazonECS.svg new file mode 100644 index 000000000..b8875c3aa --- /dev/null +++ b/web/icons/aws/Compute/Compute_AmazonECS.svg @@ -0,0 +1,27 @@ + + Compute + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Compute/Compute_AmazonECS_EC2ComputeContainer-Alt1.svg b/web/icons/aws/Compute/Compute_AmazonECS_EC2ComputeContainer-Alt1.svg new file mode 100644 index 000000000..3c9ddd80b --- /dev/null +++ b/web/icons/aws/Compute/Compute_AmazonECS_EC2ComputeContainer-Alt1.svg @@ -0,0 +1,43 @@ + + Compute + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Compute/Compute_AmazonECS_EC2ComputeContainer-Alt2.svg b/web/icons/aws/Compute/Compute_AmazonECS_EC2ComputeContainer-Alt2.svg new file mode 100644 index 000000000..81e575ead --- /dev/null +++ b/web/icons/aws/Compute/Compute_AmazonECS_EC2ComputeContainer-Alt2.svg @@ -0,0 +1,21 @@ + + Compute + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Compute/Compute_AmazonECS_EC2ComputeContainer.svg b/web/icons/aws/Compute/Compute_AmazonECS_EC2ComputeContainer.svg new file mode 100644 index 000000000..7a59519d3 --- /dev/null +++ b/web/icons/aws/Compute/Compute_AmazonECS_EC2ComputeContainer.svg @@ -0,0 +1,29 @@ + + Compute + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Compute/Compute_AmazonLightsail.svg b/web/icons/aws/Compute/Compute_AmazonLightsail.svg new file mode 100644 index 000000000..4ca4a7e17 --- /dev/null +++ b/web/icons/aws/Compute/Compute_AmazonLightsail.svg @@ -0,0 +1,30 @@ + + Compute + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Compute/Compute_AmazonVPC.svg b/web/icons/aws/Compute/Compute_AmazonVPC.svg new file mode 100644 index 000000000..c198f0580 --- /dev/null +++ b/web/icons/aws/Compute/Compute_AmazonVPC.svg @@ -0,0 +1,17 @@ + + Compute + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Compute/Compute_AmazonVPC_Internetgateway.svg b/web/icons/aws/Compute/Compute_AmazonVPC_Internetgateway.svg new file mode 100644 index 000000000..399460381 --- /dev/null +++ b/web/icons/aws/Compute/Compute_AmazonVPC_Internetgateway.svg @@ -0,0 +1,10 @@ + + Compute + + + + + + + + diff --git a/web/icons/aws/Compute/Compute_AmazonVPC_VPCNATgateway.svg b/web/icons/aws/Compute/Compute_AmazonVPC_VPCNATgateway.svg new file mode 100644 index 000000000..8427dca57 --- /dev/null +++ b/web/icons/aws/Compute/Compute_AmazonVPC_VPCNATgateway.svg @@ -0,0 +1,15 @@ + + Compute + + + + + + + + + + + + + diff --git a/web/icons/aws/Compute/Compute_AmazonVPC_VPCpeering.svg b/web/icons/aws/Compute/Compute_AmazonVPC_VPCpeering.svg new file mode 100644 index 000000000..ce23f9f26 --- /dev/null +++ b/web/icons/aws/Compute/Compute_AmazonVPC_VPCpeering.svg @@ -0,0 +1,12 @@ + + Compute + + + + + + + + + + diff --git a/web/icons/aws/Compute/Compute_AmazonVPC_VPNconnection.svg b/web/icons/aws/Compute/Compute_AmazonVPC_VPNconnection.svg new file mode 100644 index 000000000..93775f177 --- /dev/null +++ b/web/icons/aws/Compute/Compute_AmazonVPC_VPNconnection.svg @@ -0,0 +1,7 @@ + + Compute + + + + + diff --git a/web/icons/aws/Compute/Compute_AmazonVPC_VPNgateway.svg b/web/icons/aws/Compute/Compute_AmazonVPC_VPNgateway.svg new file mode 100644 index 000000000..89c6d7541 --- /dev/null +++ b/web/icons/aws/Compute/Compute_AmazonVPC_VPNgateway.svg @@ -0,0 +1,8 @@ + + Compute + + + + + + diff --git a/web/icons/aws/Compute/Compute_AmazonVPC_customergateway.svg b/web/icons/aws/Compute/Compute_AmazonVPC_customergateway.svg new file mode 100644 index 000000000..72c35dca5 --- /dev/null +++ b/web/icons/aws/Compute/Compute_AmazonVPC_customergateway.svg @@ -0,0 +1,13 @@ + + Compute + + + + + + + + + + + diff --git a/web/icons/aws/Compute/Compute_AmazonVPC_elasticnetworkadapter.svg b/web/icons/aws/Compute/Compute_AmazonVPC_elasticnetworkadapter.svg new file mode 100644 index 000000000..38fdc8485 --- /dev/null +++ b/web/icons/aws/Compute/Compute_AmazonVPC_elasticnetworkadapter.svg @@ -0,0 +1,12 @@ + + Compute + + + + + + + + + + diff --git a/web/icons/aws/Compute/Compute_AmazonVPC_elasticnetworkinterface.svg b/web/icons/aws/Compute/Compute_AmazonVPC_elasticnetworkinterface.svg new file mode 100644 index 000000000..eeec31cc5 --- /dev/null +++ b/web/icons/aws/Compute/Compute_AmazonVPC_elasticnetworkinterface.svg @@ -0,0 +1,13 @@ + + Compute + + + + + + + + + + + diff --git a/web/icons/aws/Compute/Compute_AmazonVPC_endpoints.svg b/web/icons/aws/Compute/Compute_AmazonVPC_endpoints.svg new file mode 100644 index 000000000..62fae8bc7 --- /dev/null +++ b/web/icons/aws/Compute/Compute_AmazonVPC_endpoints.svg @@ -0,0 +1,11 @@ + + Compute + + + + + + + + + diff --git a/web/icons/aws/Compute/Compute_AmazonVPC_flowlogs.svg b/web/icons/aws/Compute/Compute_AmazonVPC_flowlogs.svg new file mode 100644 index 000000000..e988d480c --- /dev/null +++ b/web/icons/aws/Compute/Compute_AmazonVPC_flowlogs.svg @@ -0,0 +1,19 @@ + + Compute + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Compute/Compute_AmazonVPC_router.svg b/web/icons/aws/Compute/Compute_AmazonVPC_router.svg new file mode 100644 index 000000000..f0d33af25 --- /dev/null +++ b/web/icons/aws/Compute/Compute_AmazonVPC_router.svg @@ -0,0 +1,20 @@ + + Compute + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Compute/Compute_ElasticLoadBalancing.svg b/web/icons/aws/Compute/Compute_ElasticLoadBalancing.svg new file mode 100644 index 000000000..2a2336987 --- /dev/null +++ b/web/icons/aws/Compute/Compute_ElasticLoadBalancing.svg @@ -0,0 +1,23 @@ + + Compute + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Compute/Compute_ElasticLoadBalancing_ApplicationLoadBalancer.svg b/web/icons/aws/Compute/Compute_ElasticLoadBalancing_ApplicationLoadBalancer.svg new file mode 100644 index 000000000..a795b46e8 --- /dev/null +++ b/web/icons/aws/Compute/Compute_ElasticLoadBalancing_ApplicationLoadBalancer.svg @@ -0,0 +1,24 @@ + + Compute + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Compute/Compute_ElasticLoadBalancing_ELLoadBalancer.svg b/web/icons/aws/Compute/Compute_ElasticLoadBalancing_ELLoadBalancer.svg new file mode 100644 index 000000000..d41fa4037 --- /dev/null +++ b/web/icons/aws/Compute/Compute_ElasticLoadBalancing_ELLoadBalancer.svg @@ -0,0 +1,12 @@ + + Compute + + + + + + + + + + diff --git a/web/icons/aws/Database/Database_AWSDMS.svg b/web/icons/aws/Database/Database_AWSDMS.svg new file mode 100644 index 000000000..b7c662862 --- /dev/null +++ b/web/icons/aws/Database/Database_AWSDMS.svg @@ -0,0 +1,20 @@ + + Database + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Database/Database_AWSDMS_databasemigrationworkflowjob.svg b/web/icons/aws/Database/Database_AWSDMS_databasemigrationworkflowjob.svg new file mode 100644 index 000000000..6270a9a2a --- /dev/null +++ b/web/icons/aws/Database/Database_AWSDMS_databasemigrationworkflowjob.svg @@ -0,0 +1,21 @@ + + Database + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Database/Database_AmazonDynamoDB.svg b/web/icons/aws/Database/Database_AmazonDynamoDB.svg new file mode 100644 index 000000000..2cba67104 --- /dev/null +++ b/web/icons/aws/Database/Database_AmazonDynamoDB.svg @@ -0,0 +1,10 @@ + + Database + + + + + + + + diff --git a/web/icons/aws/Database/Database_AmazonDynamoDB_attribute.svg b/web/icons/aws/Database/Database_AmazonDynamoDB_attribute.svg new file mode 100644 index 000000000..171fc852f --- /dev/null +++ b/web/icons/aws/Database/Database_AmazonDynamoDB_attribute.svg @@ -0,0 +1,14 @@ + + Database + + + + + + + + + + + + diff --git a/web/icons/aws/Database/Database_AmazonDynamoDB_attributes.svg b/web/icons/aws/Database/Database_AmazonDynamoDB_attributes.svg new file mode 100644 index 000000000..fdd3db876 --- /dev/null +++ b/web/icons/aws/Database/Database_AmazonDynamoDB_attributes.svg @@ -0,0 +1,20 @@ + + Database + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Database/Database_AmazonDynamoDB_globalsecondaryindex.svg b/web/icons/aws/Database/Database_AmazonDynamoDB_globalsecondaryindex.svg new file mode 100644 index 000000000..9d7e32fc3 --- /dev/null +++ b/web/icons/aws/Database/Database_AmazonDynamoDB_globalsecondaryindex.svg @@ -0,0 +1,29 @@ + + Database + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Database/Database_AmazonDynamoDB_item.svg b/web/icons/aws/Database/Database_AmazonDynamoDB_item.svg new file mode 100644 index 000000000..7a5c2707a --- /dev/null +++ b/web/icons/aws/Database/Database_AmazonDynamoDB_item.svg @@ -0,0 +1,14 @@ + + Database + + + + + + + + + + + + diff --git a/web/icons/aws/Database/Database_AmazonDynamoDB_items.svg b/web/icons/aws/Database/Database_AmazonDynamoDB_items.svg new file mode 100644 index 000000000..ce9bbde83 --- /dev/null +++ b/web/icons/aws/Database/Database_AmazonDynamoDB_items.svg @@ -0,0 +1,20 @@ + + Database + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Database/Database_AmazonDynamoDB_table.svg b/web/icons/aws/Database/Database_AmazonDynamoDB_table.svg new file mode 100644 index 000000000..091e268d3 --- /dev/null +++ b/web/icons/aws/Database/Database_AmazonDynamoDB_table.svg @@ -0,0 +1,21 @@ + + Database + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Database/Database_AmazonElasticCache.svg b/web/icons/aws/Database/Database_AmazonElasticCache.svg new file mode 100644 index 000000000..9999b6c1a --- /dev/null +++ b/web/icons/aws/Database/Database_AmazonElasticCache.svg @@ -0,0 +1,13 @@ + + Database + + + + + + + + + + + diff --git a/web/icons/aws/Database/Database_AmazonElasticCache_Memcached.svg b/web/icons/aws/Database/Database_AmazonElasticCache_Memcached.svg new file mode 100644 index 000000000..58ab00426 --- /dev/null +++ b/web/icons/aws/Database/Database_AmazonElasticCache_Memcached.svg @@ -0,0 +1,11 @@ + + Database + + + + + + + + + diff --git a/web/icons/aws/Database/Database_AmazonElasticCache_Redis.svg b/web/icons/aws/Database/Database_AmazonElasticCache_Redis.svg new file mode 100644 index 000000000..76c6b279b --- /dev/null +++ b/web/icons/aws/Database/Database_AmazonElasticCache_Redis.svg @@ -0,0 +1,9 @@ + + Database + + + + + + + diff --git a/web/icons/aws/Database/Database_AmazonElasticCache_cachenode.svg b/web/icons/aws/Database/Database_AmazonElasticCache_cachenode.svg new file mode 100644 index 000000000..0fba57fc8 --- /dev/null +++ b/web/icons/aws/Database/Database_AmazonElasticCache_cachenode.svg @@ -0,0 +1,14 @@ + + Database + + + + + + + + + + + + diff --git a/web/icons/aws/Database/Database_AmazonRDS.svg b/web/icons/aws/Database/Database_AmazonRDS.svg new file mode 100644 index 000000000..3f184686b --- /dev/null +++ b/web/icons/aws/Database/Database_AmazonRDS.svg @@ -0,0 +1,10 @@ + + Database + + + + + + + + diff --git a/web/icons/aws/Database/Database_AmazonRDS_DBinstance.svg b/web/icons/aws/Database/Database_AmazonRDS_DBinstance.svg new file mode 100644 index 000000000..a30cb4e87 --- /dev/null +++ b/web/icons/aws/Database/Database_AmazonRDS_DBinstance.svg @@ -0,0 +1,10 @@ + + Database + + + + + + + + diff --git a/web/icons/aws/Database/Database_AmazonRDS_MSSQLinstance.svg b/web/icons/aws/Database/Database_AmazonRDS_MSSQLinstance.svg new file mode 100644 index 000000000..87f9ed046 --- /dev/null +++ b/web/icons/aws/Database/Database_AmazonRDS_MSSQLinstance.svg @@ -0,0 +1,20 @@ + + Database + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Database/Database_AmazonRDS_MSSQLinstancealternate.svg b/web/icons/aws/Database/Database_AmazonRDS_MSSQLinstancealternate.svg new file mode 100644 index 000000000..4401e68bc --- /dev/null +++ b/web/icons/aws/Database/Database_AmazonRDS_MSSQLinstancealternate.svg @@ -0,0 +1,14 @@ + + Database + + + + + + + + + + + + diff --git a/web/icons/aws/Database/Database_AmazonRDS_MySQLDBinstance.svg b/web/icons/aws/Database/Database_AmazonRDS_MySQLDBinstance.svg new file mode 100644 index 000000000..c40afe693 --- /dev/null +++ b/web/icons/aws/Database/Database_AmazonRDS_MySQLDBinstance.svg @@ -0,0 +1,20 @@ + + Database + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Database/Database_AmazonRDS_MySQLinstancealternate.svg b/web/icons/aws/Database/Database_AmazonRDS_MySQLinstancealternate.svg new file mode 100644 index 000000000..182d289af --- /dev/null +++ b/web/icons/aws/Database/Database_AmazonRDS_MySQLinstancealternate.svg @@ -0,0 +1,14 @@ + + Database + + + + + + + + + + + + diff --git a/web/icons/aws/Database/Database_AmazonRDS_OracleDBinstancealternate.svg b/web/icons/aws/Database/Database_AmazonRDS_OracleDBinstancealternate.svg new file mode 100644 index 000000000..444df86f7 --- /dev/null +++ b/web/icons/aws/Database/Database_AmazonRDS_OracleDBinstancealternate.svg @@ -0,0 +1,15 @@ + + Database + + + + + + + + + + + + + diff --git a/web/icons/aws/Database/Database_AmazonRDS_PIOP.svg b/web/icons/aws/Database/Database_AmazonRDS_PIOP.svg new file mode 100644 index 000000000..e78b16317 --- /dev/null +++ b/web/icons/aws/Database/Database_AmazonRDS_PIOP.svg @@ -0,0 +1,17 @@ + + Database + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Database/Database_AmazonRDS_PostgreSQLinstance.svg b/web/icons/aws/Database/Database_AmazonRDS_PostgreSQLinstance.svg new file mode 100644 index 000000000..fd5678ac1 --- /dev/null +++ b/web/icons/aws/Database/Database_AmazonRDS_PostgreSQLinstance.svg @@ -0,0 +1,19 @@ + + Database + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Database/Database_AmazonRDS_SQLmaster.svg b/web/icons/aws/Database/Database_AmazonRDS_SQLmaster.svg new file mode 100644 index 000000000..5401d7427 --- /dev/null +++ b/web/icons/aws/Database/Database_AmazonRDS_SQLmaster.svg @@ -0,0 +1,13 @@ + + Database + + + + + + + + + + + diff --git a/web/icons/aws/Database/Database_AmazonRDS_SQLslave.svg b/web/icons/aws/Database/Database_AmazonRDS_SQLslave.svg new file mode 100644 index 000000000..490db1fd1 --- /dev/null +++ b/web/icons/aws/Database/Database_AmazonRDS_SQLslave.svg @@ -0,0 +1,13 @@ + + Database + + + + + + + + + + + diff --git a/web/icons/aws/Database/Database_AmazonRDS_instancereadreplica.svg b/web/icons/aws/Database/Database_AmazonRDS_instancereadreplica.svg new file mode 100644 index 000000000..5b5fb4657 --- /dev/null +++ b/web/icons/aws/Database/Database_AmazonRDS_instancereadreplica.svg @@ -0,0 +1,10 @@ + + Database + + + + + + + + diff --git a/web/icons/aws/Database/Database_AmazonRDS_instancestandby.svg b/web/icons/aws/Database/Database_AmazonRDS_instancestandby.svg new file mode 100644 index 000000000..c820a3f12 --- /dev/null +++ b/web/icons/aws/Database/Database_AmazonRDS_instancestandby.svg @@ -0,0 +1,10 @@ + + Database + + + + + + + + diff --git a/web/icons/aws/Database/Database_AmazonRDS_oracleDBinstance.svg b/web/icons/aws/Database/Database_AmazonRDS_oracleDBinstance.svg new file mode 100644 index 000000000..5fa00281e --- /dev/null +++ b/web/icons/aws/Database/Database_AmazonRDS_oracleDBinstance.svg @@ -0,0 +1,21 @@ + + Database + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Database/Database_AmazonRedshift.svg b/web/icons/aws/Database/Database_AmazonRedshift.svg new file mode 100644 index 000000000..b8e72b987 --- /dev/null +++ b/web/icons/aws/Database/Database_AmazonRedshift.svg @@ -0,0 +1,12 @@ + + Database + + + + + + + + + + diff --git a/web/icons/aws/Database/Database_AmazonRedshift_densecomputenode.svg b/web/icons/aws/Database/Database_AmazonRedshift_densecomputenode.svg new file mode 100644 index 000000000..255bcd722 --- /dev/null +++ b/web/icons/aws/Database/Database_AmazonRedshift_densecomputenode.svg @@ -0,0 +1,15 @@ + + Database + + + + + + + + + + + + + diff --git a/web/icons/aws/Database/Database_AmazonRedshift_densestoragenode.svg b/web/icons/aws/Database/Database_AmazonRedshift_densestoragenode.svg new file mode 100644 index 000000000..99a2b5e3c --- /dev/null +++ b/web/icons/aws/Database/Database_AmazonRedshift_densestoragenode.svg @@ -0,0 +1,15 @@ + + Database + + + + + + + + + + + + + diff --git a/web/icons/aws/Desktop App Streaming/DesktopAppStream_AmazonAppStream2.0.svg b/web/icons/aws/Desktop App Streaming/DesktopAppStream_AmazonAppStream2.0.svg new file mode 100644 index 000000000..e5bc3edea --- /dev/null +++ b/web/icons/aws/Desktop App Streaming/DesktopAppStream_AmazonAppStream2.0.svg @@ -0,0 +1,18 @@ + + DesktopAppStreaming + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Desktop App Streaming/DesktopAppStreaming_AmazonAppStream2.0.svg b/web/icons/aws/Desktop App Streaming/DesktopAppStreaming_AmazonAppStream2.0.svg new file mode 100644 index 000000000..e5bc3edea --- /dev/null +++ b/web/icons/aws/Desktop App Streaming/DesktopAppStreaming_AmazonAppStream2.0.svg @@ -0,0 +1,18 @@ + + DesktopAppStreaming + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Desktop App Streaming/DesktopAppStreaming_AmazonWorkSpaces.svg b/web/icons/aws/Desktop App Streaming/DesktopAppStreaming_AmazonWorkSpaces.svg new file mode 100644 index 000000000..e2eaa1ea1 --- /dev/null +++ b/web/icons/aws/Desktop App Streaming/DesktopAppStreaming_AmazonWorkSpaces.svg @@ -0,0 +1,11 @@ + + + + + + + + DesktopAppStreaming + + + diff --git a/web/icons/aws/Developer Tools/DeveloperTools_AWSCodeBuild.svg b/web/icons/aws/Developer Tools/DeveloperTools_AWSCodeBuild.svg new file mode 100644 index 000000000..1ca20d0bc --- /dev/null +++ b/web/icons/aws/Developer Tools/DeveloperTools_AWSCodeBuild.svg @@ -0,0 +1,35 @@ + + DeveloperTools + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Developer Tools/DeveloperTools_AWSCodeCommit.svg b/web/icons/aws/Developer Tools/DeveloperTools_AWSCodeCommit.svg new file mode 100644 index 000000000..7a7d2f503 --- /dev/null +++ b/web/icons/aws/Developer Tools/DeveloperTools_AWSCodeCommit.svg @@ -0,0 +1,21 @@ + + DeveloperTools + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Developer Tools/DeveloperTools_AWSCodeDeploy.svg b/web/icons/aws/Developer Tools/DeveloperTools_AWSCodeDeploy.svg new file mode 100644 index 000000000..a7f124a35 --- /dev/null +++ b/web/icons/aws/Developer Tools/DeveloperTools_AWSCodeDeploy.svg @@ -0,0 +1,15 @@ + + DeveloperTools + + + + + + + + + + + + + diff --git a/web/icons/aws/Developer Tools/DeveloperTools_AWSCodePipeline.svg b/web/icons/aws/Developer Tools/DeveloperTools_AWSCodePipeline.svg new file mode 100644 index 000000000..4bf982b4b --- /dev/null +++ b/web/icons/aws/Developer Tools/DeveloperTools_AWSCodePipeline.svg @@ -0,0 +1,19 @@ + + DeveloperTools + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Developer Tools/DeveloperTools_AWSX-Ray.svg b/web/icons/aws/Developer Tools/DeveloperTools_AWSX-Ray.svg new file mode 100644 index 000000000..d03392fca --- /dev/null +++ b/web/icons/aws/Developer Tools/DeveloperTools_AWSX-Ray.svg @@ -0,0 +1,19 @@ + + DeveloperTools + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Analytics/Analytics_GRAYSCALE_AWSDataPipeline.svg b/web/icons/aws/GRAYSCALE/Analytics/Analytics_GRAYSCALE_AWSDataPipeline.svg new file mode 100644 index 000000000..c478e1773 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Analytics/Analytics_GRAYSCALE_AWSDataPipeline.svg @@ -0,0 +1,13 @@ + + Analytics_GRAYSCALE + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Analytics/Analytics_GRAYSCALE_AmazonAthena.svg b/web/icons/aws/GRAYSCALE/Analytics/Analytics_GRAYSCALE_AmazonAthena.svg new file mode 100644 index 000000000..49ce1f605 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Analytics/Analytics_GRAYSCALE_AmazonAthena.svg @@ -0,0 +1,23 @@ + + Analytics_GRAYSCALE + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Analytics/Analytics_GRAYSCALE_AmazonCloudSearch.svg b/web/icons/aws/GRAYSCALE/Analytics/Analytics_GRAYSCALE_AmazonCloudSearch.svg new file mode 100644 index 000000000..b5e303ba5 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Analytics/Analytics_GRAYSCALE_AmazonCloudSearch.svg @@ -0,0 +1,19 @@ + + Analytics_GRAYSCALE + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Analytics/Analytics_GRAYSCALE_AmazonEMR.svg b/web/icons/aws/GRAYSCALE/Analytics/Analytics_GRAYSCALE_AmazonEMR.svg new file mode 100644 index 000000000..68b9abacd --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Analytics/Analytics_GRAYSCALE_AmazonEMR.svg @@ -0,0 +1,16 @@ + + Analytics_GRAYSCALE + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Analytics/Analytics_GRAYSCALE_AmazonES.svg b/web/icons/aws/GRAYSCALE/Analytics/Analytics_GRAYSCALE_AmazonES.svg new file mode 100644 index 000000000..dd5112792 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Analytics/Analytics_GRAYSCALE_AmazonES.svg @@ -0,0 +1,14 @@ + + Analytics_GRAYSCALE + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Analytics/Analytics_GRAYSCALE_AmazonKinesis.svg b/web/icons/aws/GRAYSCALE/Analytics/Analytics_GRAYSCALE_AmazonKinesis.svg new file mode 100644 index 000000000..29993193a --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Analytics/Analytics_GRAYSCALE_AmazonKinesis.svg @@ -0,0 +1,19 @@ + + Analytics_GRAYSCALE + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Analytics/Analytics_GRAYSCALE_AmazonQuickSight.svg b/web/icons/aws/GRAYSCALE/Analytics/Analytics_GRAYSCALE_AmazonQuickSight.svg new file mode 100644 index 000000000..86bc1cb42 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Analytics/Analytics_GRAYSCALE_AmazonQuickSight.svg @@ -0,0 +1,6 @@ + + Analytics_GRAYSCALE + + + + diff --git a/web/icons/aws/GRAYSCALE/Analytics/Analytics_GRAYSCALE_AmazonRedshift.svg b/web/icons/aws/GRAYSCALE/Analytics/Analytics_GRAYSCALE_AmazonRedshift.svg new file mode 100644 index 000000000..b31ee672f --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Analytics/Analytics_GRAYSCALE_AmazonRedshift.svg @@ -0,0 +1,12 @@ + + Analytics_GRAYSCALE + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Application Services/ApplicationServices_GRAYSCALE_AWSStepFunction.svg b/web/icons/aws/GRAYSCALE/Application Services/ApplicationServices_GRAYSCALE_AWSStepFunction.svg new file mode 100644 index 000000000..909a9c2ee --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Application Services/ApplicationServices_GRAYSCALE_AWSStepFunction.svg @@ -0,0 +1,34 @@ + + ApplicationServices_GRAYSCALE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Application Services/ApplicationServices_GRAYSCALE_AmazonAPIGateway.svg b/web/icons/aws/GRAYSCALE/Application Services/ApplicationServices_GRAYSCALE_AmazonAPIGateway.svg new file mode 100644 index 000000000..70f53b090 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Application Services/ApplicationServices_GRAYSCALE_AmazonAPIGateway.svg @@ -0,0 +1,27 @@ + + ApplicationServices_GRAYSCALE + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Application Services/ApplicationServices_GRAYSCALE_AmazonAppStream.svg b/web/icons/aws/GRAYSCALE/Application Services/ApplicationServices_GRAYSCALE_AmazonAppStream.svg new file mode 100644 index 000000000..4a94ad63a --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Application Services/ApplicationServices_GRAYSCALE_AmazonAppStream.svg @@ -0,0 +1,18 @@ + + ApplicationServices_GRAYSCALE + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Application Services/ApplicationServices_GRAYSCALE_AmazonElasticTranscoder.svg b/web/icons/aws/GRAYSCALE/Application Services/ApplicationServices_GRAYSCALE_AmazonElasticTranscoder.svg new file mode 100644 index 000000000..051955b97 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Application Services/ApplicationServices_GRAYSCALE_AmazonElasticTranscoder.svg @@ -0,0 +1,37 @@ + + ApplicationServices_GRAYSCALE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Application Services/ApplicationServices_GRAYSCALE_AmazonSWF.svg b/web/icons/aws/GRAYSCALE/Application Services/ApplicationServices_GRAYSCALE_AmazonSWF.svg new file mode 100644 index 000000000..7b575c11b --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Application Services/ApplicationServices_GRAYSCALE_AmazonSWF.svg @@ -0,0 +1,14 @@ + + Messaging_GRAYSCALE + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Artificial Intelligence/AI_GRAYSCALE_AmazonLex.svg b/web/icons/aws/GRAYSCALE/Artificial Intelligence/AI_GRAYSCALE_AmazonLex.svg new file mode 100644 index 000000000..7f1d560a2 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Artificial Intelligence/AI_GRAYSCALE_AmazonLex.svg @@ -0,0 +1,17 @@ + + AI_GRAYSCALE + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Artificial Intelligence/AI_GRAYSCALE_AmazonMachineLearning.svg b/web/icons/aws/GRAYSCALE/Artificial Intelligence/AI_GRAYSCALE_AmazonMachineLearning.svg new file mode 100644 index 000000000..ab8995d31 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Artificial Intelligence/AI_GRAYSCALE_AmazonMachineLearning.svg @@ -0,0 +1,29 @@ + + AI_GRAYSCALE + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Artificial Intelligence/AI_GRAYSCALE_AmazonPolly.svg b/web/icons/aws/GRAYSCALE/Artificial Intelligence/AI_GRAYSCALE_AmazonPolly.svg new file mode 100644 index 000000000..e8d6f207a --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Artificial Intelligence/AI_GRAYSCALE_AmazonPolly.svg @@ -0,0 +1,24 @@ + + AI_GRAYSCALE + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Artificial Intelligence/AI_GRAYSCALE_AmazonRekognition.svg b/web/icons/aws/GRAYSCALE/Artificial Intelligence/AI_GRAYSCALE_AmazonRekognition.svg new file mode 100644 index 000000000..41afae33f --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Artificial Intelligence/AI_GRAYSCALE_AmazonRekognition.svg @@ -0,0 +1,19 @@ + + AI_GRAYSCALE + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Business Productivity/BusinessProductivity_GRAYSCALE_AmazonWorkDocs.svg b/web/icons/aws/GRAYSCALE/Business Productivity/BusinessProductivity_GRAYSCALE_AmazonWorkDocs.svg new file mode 100644 index 000000000..0fd12baec --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Business Productivity/BusinessProductivity_GRAYSCALE_AmazonWorkDocs.svg @@ -0,0 +1,21 @@ + + + + + + + + BusinessProductivity_GRAYSCALE + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Business Productivity/BusinessProductivity_GRAYSCALE_AmazonWorkMail.svg b/web/icons/aws/GRAYSCALE/Business Productivity/BusinessProductivity_GRAYSCALE_AmazonWorkMail.svg new file mode 100644 index 000000000..bd96f245d --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Business Productivity/BusinessProductivity_GRAYSCALE_AmazonWorkMail.svg @@ -0,0 +1,13 @@ + + + + + + + + BusinessProductivity_GRAYSCALE + + + + + diff --git a/web/icons/aws/GRAYSCALE/Compute/Compute_GRAYSCALE_AWSBatch.svg b/web/icons/aws/GRAYSCALE/Compute/Compute_GRAYSCALE_AWSBatch.svg new file mode 100644 index 000000000..3e327eb1d --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Compute/Compute_GRAYSCALE_AWSBatch.svg @@ -0,0 +1,25 @@ + + Compute_GRAYSCALE + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Compute/Compute_GRAYSCALE_AWSElasticBeanstalk.svg b/web/icons/aws/GRAYSCALE/Compute/Compute_GRAYSCALE_AWSElasticBeanstalk.svg new file mode 100644 index 000000000..96e5da75f --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Compute/Compute_GRAYSCALE_AWSElasticBeanstalk.svg @@ -0,0 +1,13 @@ + + Compute_GRAYSCALE + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Compute/Compute_GRAYSCALE_AWSLambda.svg b/web/icons/aws/GRAYSCALE/Compute/Compute_GRAYSCALE_AWSLambda.svg new file mode 100644 index 000000000..fba32137e --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Compute/Compute_GRAYSCALE_AWSLambda.svg @@ -0,0 +1,16 @@ + + Compute_GRAYSCALE + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Compute/Compute_GRAYSCALE_AmazonEC2.svg b/web/icons/aws/GRAYSCALE/Compute/Compute_GRAYSCALE_AmazonEC2.svg new file mode 100644 index 000000000..9c7cb2e1f --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Compute/Compute_GRAYSCALE_AmazonEC2.svg @@ -0,0 +1,13 @@ + + Compute_GRAYSCALE + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Compute/Compute_GRAYSCALE_AmazonECR.svg b/web/icons/aws/GRAYSCALE/Compute/Compute_GRAYSCALE_AmazonECR.svg new file mode 100644 index 000000000..09c4985e9 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Compute/Compute_GRAYSCALE_AmazonECR.svg @@ -0,0 +1,25 @@ + + Compute_GRAYSCALE + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Compute/Compute_GRAYSCALE_AmazonECS.svg b/web/icons/aws/GRAYSCALE/Compute/Compute_GRAYSCALE_AmazonECS.svg new file mode 100644 index 000000000..d85d9ab64 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Compute/Compute_GRAYSCALE_AmazonECS.svg @@ -0,0 +1,27 @@ + + Compute_GRAYSCALE + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Compute/Compute_GRAYSCALE_AmazonLightsail.svg b/web/icons/aws/GRAYSCALE/Compute/Compute_GRAYSCALE_AmazonLightsail.svg new file mode 100644 index 000000000..54b9b8a36 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Compute/Compute_GRAYSCALE_AmazonLightsail.svg @@ -0,0 +1,30 @@ + + Compute_GRAYSCALE + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Compute/Compute_GRAYSCALE_AmazonVPC.svg b/web/icons/aws/GRAYSCALE/Compute/Compute_GRAYSCALE_AmazonVPC.svg new file mode 100644 index 000000000..05321a370 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Compute/Compute_GRAYSCALE_AmazonVPC.svg @@ -0,0 +1,17 @@ + + Compute_GRAYSCALE + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Compute/Compute_GRAYSCALE_ElasticLoadBalancing.svg b/web/icons/aws/GRAYSCALE/Compute/Compute_GRAYSCALE_ElasticLoadBalancing.svg new file mode 100644 index 000000000..a5665ca4a --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Compute/Compute_GRAYSCALE_ElasticLoadBalancing.svg @@ -0,0 +1,23 @@ + + Compute_GRAYSCALE + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Database/Database_GRAYSCALE_AWSDMS.svg b/web/icons/aws/GRAYSCALE/Database/Database_GRAYSCALE_AWSDMS.svg new file mode 100644 index 000000000..cf799531a --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Database/Database_GRAYSCALE_AWSDMS.svg @@ -0,0 +1,20 @@ + + Database_GRAYSCALE + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Database/Database_GRAYSCALE_AmazonDynamoDB.svg b/web/icons/aws/GRAYSCALE/Database/Database_GRAYSCALE_AmazonDynamoDB.svg new file mode 100644 index 000000000..91515c667 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Database/Database_GRAYSCALE_AmazonDynamoDB.svg @@ -0,0 +1,10 @@ + + Database_GRAYSCALE + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Database/Database_GRAYSCALE_AmazonElasticCache.svg b/web/icons/aws/GRAYSCALE/Database/Database_GRAYSCALE_AmazonElasticCache.svg new file mode 100644 index 000000000..23bd6e03c --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Database/Database_GRAYSCALE_AmazonElasticCache.svg @@ -0,0 +1,13 @@ + + Database_GRAYSCALE + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Database/Database_GRAYSCALE_AmazonRDS.svg b/web/icons/aws/GRAYSCALE/Database/Database_GRAYSCALE_AmazonRDS.svg new file mode 100644 index 000000000..4b5017632 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Database/Database_GRAYSCALE_AmazonRDS.svg @@ -0,0 +1,10 @@ + + Database_GRAYSCALE + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Database/Database_GRAYSCALE_AmazonRedshift.svg b/web/icons/aws/GRAYSCALE/Database/Database_GRAYSCALE_AmazonRedshift.svg new file mode 100644 index 000000000..54757c1b3 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Database/Database_GRAYSCALE_AmazonRedshift.svg @@ -0,0 +1,12 @@ + + Database_GRAYSCALE + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Desktop App Streaming/DesktopAppStreaming_GRAYSCALE_AmazonAppStream2.0.svg b/web/icons/aws/GRAYSCALE/Desktop App Streaming/DesktopAppStreaming_GRAYSCALE_AmazonAppStream2.0.svg new file mode 100644 index 000000000..654f1aac8 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Desktop App Streaming/DesktopAppStreaming_GRAYSCALE_AmazonAppStream2.0.svg @@ -0,0 +1,18 @@ + + DesktopAppStreaming_GRAYSCALE + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Desktop App Streaming/DesktopAppStreaming_GRAYSCALE_AmazonWorkSpaces.svg b/web/icons/aws/GRAYSCALE/Desktop App Streaming/DesktopAppStreaming_GRAYSCALE_AmazonWorkSpaces.svg new file mode 100644 index 000000000..2c2c0549c --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Desktop App Streaming/DesktopAppStreaming_GRAYSCALE_AmazonWorkSpaces.svg @@ -0,0 +1,11 @@ + + + + + + + + DesktopAppStreaming_GRAYSCALE + + + diff --git a/web/icons/aws/GRAYSCALE/Developer Tools/DeveloperTools_GRAYSCALE_AWSCodeBuild.svg b/web/icons/aws/GRAYSCALE/Developer Tools/DeveloperTools_GRAYSCALE_AWSCodeBuild.svg new file mode 100644 index 000000000..0fe48d2aa --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Developer Tools/DeveloperTools_GRAYSCALE_AWSCodeBuild.svg @@ -0,0 +1,35 @@ + + DeveloperTools_GRAYSCALE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Developer Tools/DeveloperTools_GRAYSCALE_AWSCodeCommit.svg b/web/icons/aws/GRAYSCALE/Developer Tools/DeveloperTools_GRAYSCALE_AWSCodeCommit.svg new file mode 100644 index 000000000..a0c71b468 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Developer Tools/DeveloperTools_GRAYSCALE_AWSCodeCommit.svg @@ -0,0 +1,21 @@ + + DeveloperTools_GRAYSCALE + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Developer Tools/DeveloperTools_GRAYSCALE_AWSCodeDeploy.svg b/web/icons/aws/GRAYSCALE/Developer Tools/DeveloperTools_GRAYSCALE_AWSCodeDeploy.svg new file mode 100644 index 000000000..81f41c9c3 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Developer Tools/DeveloperTools_GRAYSCALE_AWSCodeDeploy.svg @@ -0,0 +1,15 @@ + + DeveloperTools_GRAYSCALE + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Developer Tools/DeveloperTools_GRAYSCALE_AWSCodePipeline.svg b/web/icons/aws/GRAYSCALE/Developer Tools/DeveloperTools_GRAYSCALE_AWSCodePipeline.svg new file mode 100644 index 000000000..d6892c5b4 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Developer Tools/DeveloperTools_GRAYSCALE_AWSCodePipeline.svg @@ -0,0 +1,19 @@ + + DeveloperTools_GRAYSCALE + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Developer Tools/DeveloperTools_GRAYSCALE_AWSX-Ray.svg b/web/icons/aws/GRAYSCALE/Developer Tools/DeveloperTools_GRAYSCALE_AWSX-Ray.svg new file mode 100644 index 000000000..f87a0fd6e --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Developer Tools/DeveloperTools_GRAYSCALE_AWSX-Ray.svg @@ -0,0 +1,19 @@ + + DeveloperTools_GRAYSCALE + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Game Development/GameDevelopment_GRAYSCALE_AmazonGameLift.svg b/web/icons/aws/GRAYSCALE/Game Development/GameDevelopment_GRAYSCALE_AmazonGameLift.svg new file mode 100644 index 000000000..d731a2bd1 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Game Development/GameDevelopment_GRAYSCALE_AmazonGameLift.svg @@ -0,0 +1,19 @@ + + GameDevelopment_GRAYSCALE + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Internet of Things/InternetOfThings_GRAYSCALE_AWSGreengrass.svg b/web/icons/aws/GRAYSCALE/Internet of Things/InternetOfThings_GRAYSCALE_AWSGreengrass.svg new file mode 100644 index 000000000..607119734 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Internet of Things/InternetOfThings_GRAYSCALE_AWSGreengrass.svg @@ -0,0 +1,19 @@ + + InternetOfThings_GRAYSCALE + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Internet of Things/InternetOfThings_GRAYSCALE_AWSIoT.svg b/web/icons/aws/GRAYSCALE/Internet of Things/InternetOfThings_GRAYSCALE_AWSIoT.svg new file mode 100644 index 000000000..e7fdbc303 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Internet of Things/InternetOfThings_GRAYSCALE_AWSIoT.svg @@ -0,0 +1,28 @@ + + InternetOfThings_GRAYSCALE + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Management Tools/ManagementTools_GRAYSCALE_AWSCloudFormation.svg b/web/icons/aws/GRAYSCALE/Management Tools/ManagementTools_GRAYSCALE_AWSCloudFormation.svg new file mode 100644 index 000000000..92dfce05e --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Management Tools/ManagementTools_GRAYSCALE_AWSCloudFormation.svg @@ -0,0 +1,13 @@ + + ManagementTools_GRAYSCALE + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Management Tools/ManagementTools_GRAYSCALE_AWSCloudTrail.svg b/web/icons/aws/GRAYSCALE/Management Tools/ManagementTools_GRAYSCALE_AWSCloudTrail.svg new file mode 100644 index 000000000..5df8bf5e3 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Management Tools/ManagementTools_GRAYSCALE_AWSCloudTrail.svg @@ -0,0 +1,19 @@ + + ManagementTools_GRAYSCALE + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Management Tools/ManagementTools_GRAYSCALE_AWSConfig.svg b/web/icons/aws/GRAYSCALE/Management Tools/ManagementTools_GRAYSCALE_AWSConfig.svg new file mode 100644 index 000000000..202434a60 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Management Tools/ManagementTools_GRAYSCALE_AWSConfig.svg @@ -0,0 +1,19 @@ + + ManagementTools_GRAYSCALE + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Management Tools/ManagementTools_GRAYSCALE_AWSManagedServices.svg b/web/icons/aws/GRAYSCALE/Management Tools/ManagementTools_GRAYSCALE_AWSManagedServices.svg new file mode 100644 index 000000000..22715f68e --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Management Tools/ManagementTools_GRAYSCALE_AWSManagedServices.svg @@ -0,0 +1,23 @@ + + ManagementTools_GRAYSCALE + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Management Tools/ManagementTools_GRAYSCALE_AWSOpsWorks.svg b/web/icons/aws/GRAYSCALE/Management Tools/ManagementTools_GRAYSCALE_AWSOpsWorks.svg new file mode 100644 index 000000000..5128d904c --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Management Tools/ManagementTools_GRAYSCALE_AWSOpsWorks.svg @@ -0,0 +1,15 @@ + + ManagementTools_GRAYSCALE + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Management Tools/ManagementTools_GRAYSCALE_AWSServiceCatalog.svg b/web/icons/aws/GRAYSCALE/Management Tools/ManagementTools_GRAYSCALE_AWSServiceCatalog.svg new file mode 100644 index 000000000..394c6b6f9 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Management Tools/ManagementTools_GRAYSCALE_AWSServiceCatalog.svg @@ -0,0 +1,27 @@ + + ManagementTools_GRAYSCALE + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Management Tools/ManagementTools_GRAYSCALE_AWSTrustedAdvisor.svg b/web/icons/aws/GRAYSCALE/Management Tools/ManagementTools_GRAYSCALE_AWSTrustedAdvisor.svg new file mode 100644 index 000000000..18118d053 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Management Tools/ManagementTools_GRAYSCALE_AWSTrustedAdvisor.svg @@ -0,0 +1,14 @@ + + ManagementTools_GRAYSCALE + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Management Tools/ManagementTools_GRAYSCALE_AmazonCloudWatch.svg b/web/icons/aws/GRAYSCALE/Management Tools/ManagementTools_GRAYSCALE_AmazonCloudWatch.svg new file mode 100644 index 000000000..99a883af0 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Management Tools/ManagementTools_GRAYSCALE_AmazonCloudWatch.svg @@ -0,0 +1,15 @@ + + ManagementTools_GRAYSCALE + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Messaging/Messaging_GRAYSCALE_AmazonPinpoint.svg b/web/icons/aws/GRAYSCALE/Messaging/Messaging_GRAYSCALE_AmazonPinpoint.svg new file mode 100644 index 000000000..23a953f6a --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Messaging/Messaging_GRAYSCALE_AmazonPinpoint.svg @@ -0,0 +1,75 @@ + + Messaging_GRAYSCALE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Messaging/Messaging_GRAYSCALE_AmazonSES.svg b/web/icons/aws/GRAYSCALE/Messaging/Messaging_GRAYSCALE_AmazonSES.svg new file mode 100644 index 000000000..6d13b8c8b --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Messaging/Messaging_GRAYSCALE_AmazonSES.svg @@ -0,0 +1,12 @@ + + Messaging_GRAYSCALE + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Messaging/Messaging_GRAYSCALE_AmazonSNS.svg b/web/icons/aws/GRAYSCALE/Messaging/Messaging_GRAYSCALE_AmazonSNS.svg new file mode 100644 index 000000000..ef96456be --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Messaging/Messaging_GRAYSCALE_AmazonSNS.svg @@ -0,0 +1,17 @@ + + Messaging_GRAYSCALE + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Messaging/Messaging_GRAYSCALE_AmazonSQS.svg b/web/icons/aws/GRAYSCALE/Messaging/Messaging_GRAYSCALE_AmazonSQS.svg new file mode 100644 index 000000000..d800de8d9 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Messaging/Messaging_GRAYSCALE_AmazonSQS.svg @@ -0,0 +1,16 @@ + + Messaging_GRAYSCALE + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Migration/Migration_GRAYSCALE_AWSApplicationDiscoveryService.svg b/web/icons/aws/GRAYSCALE/Migration/Migration_GRAYSCALE_AWSApplicationDiscoveryService.svg new file mode 100644 index 000000000..53e48bba7 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Migration/Migration_GRAYSCALE_AWSApplicationDiscoveryService.svg @@ -0,0 +1,18 @@ + + ManagementTools_GRAYSCALE + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Migration/Migration_GRAYSCALE_AWSDMS.svg b/web/icons/aws/GRAYSCALE/Migration/Migration_GRAYSCALE_AWSDMS.svg new file mode 100644 index 000000000..d6d58db88 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Migration/Migration_GRAYSCALE_AWSDMS.svg @@ -0,0 +1,20 @@ + + Migration_GRAYSCALE + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Migration/Migration_GRAYSCALE_AWSSMS.svg b/web/icons/aws/GRAYSCALE/Migration/Migration_GRAYSCALE_AWSSMS.svg new file mode 100644 index 000000000..463767558 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Migration/Migration_GRAYSCALE_AWSSMS.svg @@ -0,0 +1,40 @@ + + Migration_GRAYSCALE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Migration/Migration_GRAYSCALE_AWSSnowball.svg b/web/icons/aws/GRAYSCALE/Migration/Migration_GRAYSCALE_AWSSnowball.svg new file mode 100644 index 000000000..502a09d47 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Migration/Migration_GRAYSCALE_AWSSnowball.svg @@ -0,0 +1,25 @@ + + Migration_GRAYSCALE + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Mobile Services/MobileServices_GRAYSCALE_AWSDeviceFarm.svg b/web/icons/aws/GRAYSCALE/Mobile Services/MobileServices_GRAYSCALE_AWSDeviceFarm.svg new file mode 100644 index 000000000..8733c3369 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Mobile Services/MobileServices_GRAYSCALE_AWSDeviceFarm.svg @@ -0,0 +1,20 @@ + + MobileServices_GRAYSCALE + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Mobile Services/MobileServices_GRAYSCALE_AWSMobileHub.svg b/web/icons/aws/GRAYSCALE/Mobile Services/MobileServices_GRAYSCALE_AWSMobileHub.svg new file mode 100644 index 000000000..ab9dfe679 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Mobile Services/MobileServices_GRAYSCALE_AWSMobileHub.svg @@ -0,0 +1,17 @@ + + + + + + + + + MobileServices_GRAYSCALE + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Mobile Services/MobileServices_GRAYSCALE_AmazonAPIGateway.svg b/web/icons/aws/GRAYSCALE/Mobile Services/MobileServices_GRAYSCALE_AmazonAPIGateway.svg new file mode 100644 index 000000000..0bca556d1 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Mobile Services/MobileServices_GRAYSCALE_AmazonAPIGateway.svg @@ -0,0 +1,27 @@ + + MobileServices_GRAYSCALE + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Mobile Services/MobileServices_GRAYSCALE_AmazonCognito.svg b/web/icons/aws/GRAYSCALE/Mobile Services/MobileServices_GRAYSCALE_AmazonCognito.svg new file mode 100644 index 000000000..3c995ccab --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Mobile Services/MobileServices_GRAYSCALE_AmazonCognito.svg @@ -0,0 +1,19 @@ + + MobileServices_GRAYSCALE + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Mobile Services/MobileServices_GRAYSCALE_AmazonMobileAnalytics.svg b/web/icons/aws/GRAYSCALE/Mobile Services/MobileServices_GRAYSCALE_AmazonMobileAnalytics.svg new file mode 100644 index 000000000..17fccd368 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Mobile Services/MobileServices_GRAYSCALE_AmazonMobileAnalytics.svg @@ -0,0 +1,21 @@ + + MobileServices_GRAYSCALE + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Mobile Services/MobileServices_GRAYSCALE_AmazonPinpoint.svg b/web/icons/aws/GRAYSCALE/Mobile Services/MobileServices_GRAYSCALE_AmazonPinpoint.svg new file mode 100644 index 000000000..734cf9904 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Mobile Services/MobileServices_GRAYSCALE_AmazonPinpoint.svg @@ -0,0 +1,75 @@ + + MobileServices_GRAYSCALE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Networking & Content Delivery/NetworkingContentDelivery_GRAYSCALE_AWSDirectConnect.svg b/web/icons/aws/GRAYSCALE/Networking & Content Delivery/NetworkingContentDelivery_GRAYSCALE_AWSDirectConnect.svg new file mode 100644 index 000000000..24204697f --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Networking & Content Delivery/NetworkingContentDelivery_GRAYSCALE_AWSDirectConnect.svg @@ -0,0 +1,15 @@ + + NetworkingContentDelivery_GRAYSCALE + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Networking & Content Delivery/NetworkingContentDelivery_GRAYSCALE_AmazonCloudFront.svg b/web/icons/aws/GRAYSCALE/Networking & Content Delivery/NetworkingContentDelivery_GRAYSCALE_AmazonCloudFront.svg new file mode 100644 index 000000000..70f819bbf --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Networking & Content Delivery/NetworkingContentDelivery_GRAYSCALE_AmazonCloudFront.svg @@ -0,0 +1,23 @@ + + NetworkingContentDelivery_GRAYSCALE + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Networking & Content Delivery/NetworkingContentDelivery_GRAYSCALE_AmazonRoute53.svg b/web/icons/aws/GRAYSCALE/Networking & Content Delivery/NetworkingContentDelivery_GRAYSCALE_AmazonRoute53.svg new file mode 100644 index 000000000..9504b5cbe --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Networking & Content Delivery/NetworkingContentDelivery_GRAYSCALE_AmazonRoute53.svg @@ -0,0 +1,12 @@ + + NetworkingContentDelivery_GRAYSCALE + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Networking & Content Delivery/NetworkingContentDelivery_GRAYSCALE_AmazonVPC.svg b/web/icons/aws/GRAYSCALE/Networking & Content Delivery/NetworkingContentDelivery_GRAYSCALE_AmazonVPC.svg new file mode 100644 index 000000000..92b407212 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Networking & Content Delivery/NetworkingContentDelivery_GRAYSCALE_AmazonVPC.svg @@ -0,0 +1,17 @@ + + NetworkingContentDelivery_GRAYSCALE + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Networking & Content Delivery/NetworkingContentDelivery_GRAYSCALE_ElasticLoadBalancing.svg b/web/icons/aws/GRAYSCALE/Networking & Content Delivery/NetworkingContentDelivery_GRAYSCALE_ElasticLoadBalancing.svg new file mode 100644 index 000000000..6fc0827e6 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Networking & Content Delivery/NetworkingContentDelivery_GRAYSCALE_ElasticLoadBalancing.svg @@ -0,0 +1,23 @@ + + NetworkingContentDelivery_GRAYSCALE + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Security Identity & Compliance/SecurityIdentityCompliance_GRAYSCALE_AWSArtifact.svg b/web/icons/aws/GRAYSCALE/Security Identity & Compliance/SecurityIdentityCompliance_GRAYSCALE_AWSArtifact.svg new file mode 100644 index 000000000..a4909ffd6 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Security Identity & Compliance/SecurityIdentityCompliance_GRAYSCALE_AWSArtifact.svg @@ -0,0 +1,19 @@ + + SecurityIdentityCompliance_GRAYSCALE + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Security Identity & Compliance/SecurityIdentityCompliance_GRAYSCALE_AWSCertificateManager.svg b/web/icons/aws/GRAYSCALE/Security Identity & Compliance/SecurityIdentityCompliance_GRAYSCALE_AWSCertificateManager.svg new file mode 100644 index 000000000..758b9aa2d --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Security Identity & Compliance/SecurityIdentityCompliance_GRAYSCALE_AWSCertificateManager.svg @@ -0,0 +1,11 @@ + + SecurityIdentityCompliance_GRAYSCALE + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Security Identity & Compliance/SecurityIdentityCompliance_GRAYSCALE_AWSCloudHSM.svg b/web/icons/aws/GRAYSCALE/Security Identity & Compliance/SecurityIdentityCompliance_GRAYSCALE_AWSCloudHSM.svg new file mode 100644 index 000000000..7401dfbb1 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Security Identity & Compliance/SecurityIdentityCompliance_GRAYSCALE_AWSCloudHSM.svg @@ -0,0 +1,14 @@ + + SecurityIdentityCompliance_GRAYSCALE + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Security Identity & Compliance/SecurityIdentityCompliance_GRAYSCALE_AWSDirectoryService.svg b/web/icons/aws/GRAYSCALE/Security Identity & Compliance/SecurityIdentityCompliance_GRAYSCALE_AWSDirectoryService.svg new file mode 100644 index 000000000..a1bb58cea --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Security Identity & Compliance/SecurityIdentityCompliance_GRAYSCALE_AWSDirectoryService.svg @@ -0,0 +1,19 @@ + + SecurityIdentityCompliance_GRAYSCALE + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Security Identity & Compliance/SecurityIdentityCompliance_GRAYSCALE_AWSKMS.svg b/web/icons/aws/GRAYSCALE/Security Identity & Compliance/SecurityIdentityCompliance_GRAYSCALE_AWSKMS.svg new file mode 100644 index 000000000..0c3cc9622 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Security Identity & Compliance/SecurityIdentityCompliance_GRAYSCALE_AWSKMS.svg @@ -0,0 +1,11 @@ + + SecurityIdentityCompliance_GRAYSCALE + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Security Identity & Compliance/SecurityIdentityCompliance_GRAYSCALE_AWSOrganizations.svg b/web/icons/aws/GRAYSCALE/Security Identity & Compliance/SecurityIdentityCompliance_GRAYSCALE_AWSOrganizations.svg new file mode 100644 index 000000000..ff433e3a9 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Security Identity & Compliance/SecurityIdentityCompliance_GRAYSCALE_AWSOrganizations.svg @@ -0,0 +1,23 @@ + + ManagementTools_GRAYSCALE + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Security Identity & Compliance/SecurityIdentityCompliance_GRAYSCALE_AWSShield.svg b/web/icons/aws/GRAYSCALE/Security Identity & Compliance/SecurityIdentityCompliance_GRAYSCALE_AWSShield.svg new file mode 100644 index 000000000..5bb7114b1 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Security Identity & Compliance/SecurityIdentityCompliance_GRAYSCALE_AWSShield.svg @@ -0,0 +1,13 @@ + + SecurityIdentityCompliance_GRAYSCALE + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Security Identity & Compliance/SecurityIdentityCompliance_GRAYSCALE_AWSWAF.svg b/web/icons/aws/GRAYSCALE/Security Identity & Compliance/SecurityIdentityCompliance_GRAYSCALE_AWSWAF.svg new file mode 100644 index 000000000..5b0c78118 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Security Identity & Compliance/SecurityIdentityCompliance_GRAYSCALE_AWSWAF.svg @@ -0,0 +1,20 @@ + + SecurityIdentityCompliance_GRAYSCALE + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Security Identity & Compliance/SecurityIdentityCompliance_GRAYSCALE_AmazonInspector.svg b/web/icons/aws/GRAYSCALE/Security Identity & Compliance/SecurityIdentityCompliance_GRAYSCALE_AmazonInspector.svg new file mode 100644 index 000000000..4429e7d70 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Security Identity & Compliance/SecurityIdentityCompliance_GRAYSCALE_AmazonInspector.svg @@ -0,0 +1,13 @@ + + SecurityIdentityCompliance_GRAYSCALE + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Security Identity & Compliance/SecurityIdentityCompliance_GRAYSCALE_IAM.svg b/web/icons/aws/GRAYSCALE/Security Identity & Compliance/SecurityIdentityCompliance_GRAYSCALE_IAM.svg new file mode 100644 index 000000000..931eb74cf --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Security Identity & Compliance/SecurityIdentityCompliance_GRAYSCALE_IAM.svg @@ -0,0 +1,15 @@ + + SecurityIdentityCompliance_GRAYSCALE + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Storage/Storage_GRAYSCALE_AWSSnowball.svg b/web/icons/aws/GRAYSCALE/Storage/Storage_GRAYSCALE_AWSSnowball.svg new file mode 100644 index 000000000..131d00348 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Storage/Storage_GRAYSCALE_AWSSnowball.svg @@ -0,0 +1,25 @@ + + Storage_GRAYSCALE + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Storage/Storage_GRAYSCALE_AWSStorageGateway.svg b/web/icons/aws/GRAYSCALE/Storage/Storage_GRAYSCALE_AWSStorageGateway.svg new file mode 100644 index 000000000..6337769dc --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Storage/Storage_GRAYSCALE_AWSStorageGateway.svg @@ -0,0 +1,11 @@ + + Storage_GRAYSCALE + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Storage/Storage_GRAYSCALE_AmazonEFS.svg b/web/icons/aws/GRAYSCALE/Storage/Storage_GRAYSCALE_AmazonEFS.svg new file mode 100644 index 000000000..7a9308058 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Storage/Storage_GRAYSCALE_AmazonEFS.svg @@ -0,0 +1,23 @@ + + Storage_GRAYSCALE + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Storage/Storage_GRAYSCALE_AmazonGlacier.svg b/web/icons/aws/GRAYSCALE/Storage/Storage_GRAYSCALE_AmazonGlacier.svg new file mode 100644 index 000000000..cae0aa075 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Storage/Storage_GRAYSCALE_AmazonGlacier.svg @@ -0,0 +1,11 @@ + + Storage_GRAYSCALE + + + + + + + + + diff --git a/web/icons/aws/GRAYSCALE/Storage/Storage_GRAYSCALE_AmazonS3.svg b/web/icons/aws/GRAYSCALE/Storage/Storage_GRAYSCALE_AmazonS3.svg new file mode 100644 index 000000000..16aa13f91 --- /dev/null +++ b/web/icons/aws/GRAYSCALE/Storage/Storage_GRAYSCALE_AmazonS3.svg @@ -0,0 +1,17 @@ + + Storage_GRAYSCALE + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Game Development/GameDevelopment_AmazonGameLift.svg b/web/icons/aws/Game Development/GameDevelopment_AmazonGameLift.svg new file mode 100644 index 000000000..82f014b88 --- /dev/null +++ b/web/icons/aws/Game Development/GameDevelopment_AmazonGameLift.svg @@ -0,0 +1,19 @@ + + GameDevelopment + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/General/General_AWSManagementConsole.svg b/web/icons/aws/General/General_AWSManagementConsole.svg new file mode 100644 index 000000000..ccaf66c41 --- /dev/null +++ b/web/icons/aws/General/General_AWSManagementConsole.svg @@ -0,0 +1,9 @@ + + General + + + + + + + diff --git a/web/icons/aws/General/General_AWScloud.svg b/web/icons/aws/General/General_AWScloud.svg new file mode 100644 index 000000000..5c42ce4a2 --- /dev/null +++ b/web/icons/aws/General/General_AWScloud.svg @@ -0,0 +1,8 @@ + + General + + + + + + diff --git a/web/icons/aws/General/General_Internet.svg b/web/icons/aws/General/General_Internet.svg new file mode 100644 index 000000000..4f8763451 --- /dev/null +++ b/web/icons/aws/General/General_Internet.svg @@ -0,0 +1,10 @@ + + General + + + + + + + + diff --git a/web/icons/aws/General/General_Internetalternate1.svg b/web/icons/aws/General/General_Internetalternate1.svg new file mode 100644 index 000000000..8f51bd430 --- /dev/null +++ b/web/icons/aws/General/General_Internetalternate1.svg @@ -0,0 +1,9 @@ + + General + + + + + + + diff --git a/web/icons/aws/General/General_Internetalternate2.svg b/web/icons/aws/General/General_Internetalternate2.svg new file mode 100644 index 000000000..413571f1e --- /dev/null +++ b/web/icons/aws/General/General_Internetalternate2.svg @@ -0,0 +1,8 @@ + + General + + + + + + diff --git a/web/icons/aws/General/General_SAMLtoken.svg b/web/icons/aws/General/General_SAMLtoken.svg new file mode 100644 index 000000000..141c85256 --- /dev/null +++ b/web/icons/aws/General/General_SAMLtoken.svg @@ -0,0 +1,7 @@ + + General + + + + + diff --git a/web/icons/aws/General/General_SSLpadlock.svg b/web/icons/aws/General/General_SSLpadlock.svg new file mode 100644 index 000000000..417f3ece4 --- /dev/null +++ b/web/icons/aws/General/General_SSLpadlock.svg @@ -0,0 +1,7 @@ + + General + + + + + diff --git a/web/icons/aws/General/General_client.svg b/web/icons/aws/General/General_client.svg new file mode 100644 index 000000000..ee1d641da --- /dev/null +++ b/web/icons/aws/General/General_client.svg @@ -0,0 +1,9 @@ + + General + + + + + + + diff --git a/web/icons/aws/General/General_corporatedatacenter.svg b/web/icons/aws/General/General_corporatedatacenter.svg new file mode 100644 index 000000000..a855c0d63 --- /dev/null +++ b/web/icons/aws/General/General_corporatedatacenter.svg @@ -0,0 +1,6 @@ + + General + + + + diff --git a/web/icons/aws/General/General_disk.svg b/web/icons/aws/General/General_disk.svg new file mode 100644 index 000000000..18012870c --- /dev/null +++ b/web/icons/aws/General/General_disk.svg @@ -0,0 +1,20 @@ + + + + + + + General + + + + + + + + + + + + + diff --git a/web/icons/aws/General/General_forums.svg b/web/icons/aws/General/General_forums.svg new file mode 100644 index 000000000..5e3a5befa --- /dev/null +++ b/web/icons/aws/General/General_forums.svg @@ -0,0 +1,15 @@ + + General + + + + + + + + + + + + + diff --git a/web/icons/aws/General/General_genericdatabase.svg b/web/icons/aws/General/General_genericdatabase.svg new file mode 100644 index 000000000..2d3971616 --- /dev/null +++ b/web/icons/aws/General/General_genericdatabase.svg @@ -0,0 +1,20 @@ + + + + + + + General + + + + + + + + + + + + + diff --git a/web/icons/aws/General/General_mobileclient.svg b/web/icons/aws/General/General_mobileclient.svg new file mode 100644 index 000000000..1c371f3bc --- /dev/null +++ b/web/icons/aws/General/General_mobileclient.svg @@ -0,0 +1,6 @@ + + General + + + + diff --git a/web/icons/aws/General/General_multimedia.svg b/web/icons/aws/General/General_multimedia.svg new file mode 100644 index 000000000..2baa4e0b0 --- /dev/null +++ b/web/icons/aws/General/General_multimedia.svg @@ -0,0 +1,6 @@ + + General + + + + diff --git a/web/icons/aws/General/General_officebuilding.svg b/web/icons/aws/General/General_officebuilding.svg new file mode 100644 index 000000000..16548c307 --- /dev/null +++ b/web/icons/aws/General/General_officebuilding.svg @@ -0,0 +1,51 @@ + + General + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/General/General_tapestorage.svg b/web/icons/aws/General/General_tapestorage.svg new file mode 100644 index 000000000..af65294da --- /dev/null +++ b/web/icons/aws/General/General_tapestorage.svg @@ -0,0 +1,15 @@ + + General + + + + + + + + + + + + + diff --git a/web/icons/aws/General/General_traditionalserver.svg b/web/icons/aws/General/General_traditionalserver.svg new file mode 100644 index 000000000..ae5e6e3d5 --- /dev/null +++ b/web/icons/aws/General/General_traditionalserver.svg @@ -0,0 +1,6 @@ + + General + + + + diff --git a/web/icons/aws/General/General_user.svg b/web/icons/aws/General/General_user.svg new file mode 100644 index 000000000..f62383ef9 --- /dev/null +++ b/web/icons/aws/General/General_user.svg @@ -0,0 +1,7 @@ + + General + + + + + diff --git a/web/icons/aws/General/General_users.svg b/web/icons/aws/General/General_users.svg new file mode 100644 index 000000000..c086d9015 --- /dev/null +++ b/web/icons/aws/General/General_users.svg @@ -0,0 +1,15 @@ + + General + + + + + + + + + + + + + diff --git a/web/icons/aws/General/General_virtualprivatecloud.svg b/web/icons/aws/General/General_virtualprivatecloud.svg new file mode 100644 index 000000000..5d2abf449 --- /dev/null +++ b/web/icons/aws/General/General_virtualprivatecloud.svg @@ -0,0 +1,8 @@ + + General + + + + + + diff --git a/web/icons/aws/Internet of Things/InternetOfThings_AVSenableddevice.svg b/web/icons/aws/Internet of Things/InternetOfThings_AVSenableddevice.svg new file mode 100644 index 000000000..29737fc5d --- /dev/null +++ b/web/icons/aws/Internet of Things/InternetOfThings_AVSenableddevice.svg @@ -0,0 +1,26 @@ + + InternetOfThings + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Internet of Things/InternetOfThings_AWSGreengrass.svg b/web/icons/aws/Internet of Things/InternetOfThings_AWSGreengrass.svg new file mode 100644 index 000000000..567c1b1e8 --- /dev/null +++ b/web/icons/aws/Internet of Things/InternetOfThings_AWSGreengrass.svg @@ -0,0 +1,19 @@ + + InternetOfThings + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT.svg b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT.svg new file mode 100644 index 000000000..d4d235116 --- /dev/null +++ b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT.svg @@ -0,0 +1,28 @@ + + InternetOfThings + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_HTTP2protocol.svg b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_HTTP2protocol.svg new file mode 100644 index 000000000..da2653b79 --- /dev/null +++ b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_HTTP2protocol.svg @@ -0,0 +1,18 @@ + + InternetOfThings + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_HTTPprotocol.svg b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_HTTPprotocol.svg new file mode 100644 index 000000000..7ca270a94 --- /dev/null +++ b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_HTTPprotocol.svg @@ -0,0 +1,16 @@ + + InternetOfThings + + + + + + + + + + + + + + diff --git a/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_MQTTprotocol.svg b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_MQTTprotocol.svg new file mode 100644 index 000000000..875a74b64 --- /dev/null +++ b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_MQTTprotocol.svg @@ -0,0 +1,16 @@ + + InternetOfThings + + + + + + + + + + + + + + diff --git a/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_action.svg b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_action.svg new file mode 100644 index 000000000..709f6c44d --- /dev/null +++ b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_action.svg @@ -0,0 +1,8 @@ + + InternetOfThings + + + + + + diff --git a/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_actuator.svg b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_actuator.svg new file mode 100644 index 000000000..2a0a8948a --- /dev/null +++ b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_actuator.svg @@ -0,0 +1,16 @@ + + InternetOfThings + + + + + + + + + + + + + + diff --git a/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_certificate.svg b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_certificate.svg new file mode 100644 index 000000000..4378dc25b --- /dev/null +++ b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_certificate.svg @@ -0,0 +1,15 @@ + + InternetOfThings + + + + + + + + + + + + + diff --git a/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_desiredstate.svg b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_desiredstate.svg new file mode 100644 index 000000000..f7694fc5d --- /dev/null +++ b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_desiredstate.svg @@ -0,0 +1,14 @@ + + InternetOfThings + + + + + + + + + + + + diff --git a/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_hardwareboard.svg b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_hardwareboard.svg new file mode 100644 index 000000000..ee1be5761 --- /dev/null +++ b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_hardwareboard.svg @@ -0,0 +1,31 @@ + + InternetOfThings + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_policy.svg b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_policy.svg new file mode 100644 index 000000000..2f102fd4d --- /dev/null +++ b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_policy.svg @@ -0,0 +1,20 @@ + + InternetOfThings + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_reportedstate.svg b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_reportedstate.svg new file mode 100644 index 000000000..c322ecbff --- /dev/null +++ b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_reportedstate.svg @@ -0,0 +1,13 @@ + + InternetOfThings + + + + + + + + + + + diff --git a/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_rule.svg b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_rule.svg new file mode 100644 index 000000000..668ac4425 --- /dev/null +++ b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_rule.svg @@ -0,0 +1,16 @@ + + InternetOfThings + + + + + + + + + + + + + + diff --git a/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_sensor.svg b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_sensor.svg new file mode 100644 index 000000000..1558e75cc --- /dev/null +++ b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_sensor.svg @@ -0,0 +1,15 @@ + + InternetOfThings + + + + + + + + + + + + + diff --git a/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_servo.svg b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_servo.svg new file mode 100644 index 000000000..b79f2236e --- /dev/null +++ b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_servo.svg @@ -0,0 +1,12 @@ + + InternetOfThings + + + + + + + + + + diff --git a/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_shadow.svg b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_shadow.svg new file mode 100644 index 000000000..4e1d4881b --- /dev/null +++ b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_shadow.svg @@ -0,0 +1,16 @@ + + InternetOfThings + + + + + + + + + + + + + + diff --git a/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_simulator.svg b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_simulator.svg new file mode 100644 index 000000000..f7c26b539 --- /dev/null +++ b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_simulator.svg @@ -0,0 +1,24 @@ + + InternetOfThings + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thingbank.svg b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thingbank.svg new file mode 100644 index 000000000..ef619b2ed --- /dev/null +++ b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thingbank.svg @@ -0,0 +1,32 @@ + + InternetOfThings + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thingbicycle.svg b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thingbicycle.svg new file mode 100644 index 000000000..f97aa1a61 --- /dev/null +++ b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thingbicycle.svg @@ -0,0 +1,45 @@ + + InternetOfThings + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thingcamera.svg b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thingcamera.svg new file mode 100644 index 000000000..8f0de985c --- /dev/null +++ b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thingcamera.svg @@ -0,0 +1,32 @@ + + InternetOfThings + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thingcar.svg b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thingcar.svg new file mode 100644 index 000000000..f77e09517 --- /dev/null +++ b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thingcar.svg @@ -0,0 +1,46 @@ + + InternetOfThings + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thingcart.svg b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thingcart.svg new file mode 100644 index 000000000..88f0ef9ef --- /dev/null +++ b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thingcart.svg @@ -0,0 +1,40 @@ + + InternetOfThings + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thingcoffeepot.svg b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thingcoffeepot.svg new file mode 100644 index 000000000..c5aec103f --- /dev/null +++ b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thingcoffeepot.svg @@ -0,0 +1,37 @@ + + InternetOfThings + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thingdoorlock.svg b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thingdoorlock.svg new file mode 100644 index 000000000..71f26298a --- /dev/null +++ b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thingdoorlock.svg @@ -0,0 +1,36 @@ + + InternetOfThings + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thingfactory.svg b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thingfactory.svg new file mode 100644 index 000000000..3b4175139 --- /dev/null +++ b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thingfactory.svg @@ -0,0 +1,34 @@ + + InternetOfThings + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thinggeneric.svg b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thinggeneric.svg new file mode 100644 index 000000000..97b57ab4a --- /dev/null +++ b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thinggeneric.svg @@ -0,0 +1,32 @@ + + InternetOfThings + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thinghouse.svg b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thinghouse.svg new file mode 100644 index 000000000..b8be3a7a9 --- /dev/null +++ b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thinghouse.svg @@ -0,0 +1,32 @@ + + InternetOfThings + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thinglightbulb.svg b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thinglightbulb.svg new file mode 100644 index 000000000..aaa1d5558 --- /dev/null +++ b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thinglightbulb.svg @@ -0,0 +1,34 @@ + + InternetOfThings + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thingmedicalemergency.svg b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thingmedicalemergency.svg new file mode 100644 index 000000000..57199ddaa --- /dev/null +++ b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thingmedicalemergency.svg @@ -0,0 +1,29 @@ + + InternetOfThings + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thingpoliceemergency.svg b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thingpoliceemergency.svg new file mode 100644 index 000000000..62fb32f63 --- /dev/null +++ b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thingpoliceemergency.svg @@ -0,0 +1,28 @@ + + InternetOfThings + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thingthermostat.svg b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thingthermostat.svg new file mode 100644 index 000000000..a2ec6e9c7 --- /dev/null +++ b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thingthermostat.svg @@ -0,0 +1,41 @@ + + InternetOfThings + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thingtravel.svg b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thingtravel.svg new file mode 100644 index 000000000..a505a955c --- /dev/null +++ b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thingtravel.svg @@ -0,0 +1,40 @@ + + InternetOfThings + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thingutility.svg b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thingutility.svg new file mode 100644 index 000000000..611a164cd --- /dev/null +++ b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thingutility.svg @@ -0,0 +1,51 @@ + + InternetOfThings + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thingwindfarm.svg b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thingwindfarm.svg new file mode 100644 index 000000000..19f4f8a50 --- /dev/null +++ b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_thingwindfarm.svg @@ -0,0 +1,31 @@ + + InternetOfThings + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_topic.svg b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_topic.svg new file mode 100644 index 000000000..e5aa06d13 --- /dev/null +++ b/web/icons/aws/Internet of Things/InternetOfThings_AWSIoT_topic.svg @@ -0,0 +1,12 @@ + + InternetOfThings + + + + + + + + + + diff --git a/web/icons/aws/Internet of Things/InternetOfThings_alexaskill.svg b/web/icons/aws/Internet of Things/InternetOfThings_alexaskill.svg new file mode 100644 index 000000000..1ee007a96 --- /dev/null +++ b/web/icons/aws/Internet of Things/InternetOfThings_alexaskill.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + InternetOfThings + + + + + + + + + diff --git a/web/icons/aws/Internet of Things/InternetOfThings_alexasmarthomeskill.svg b/web/icons/aws/Internet of Things/InternetOfThings_alexasmarthomeskill.svg new file mode 100644 index 000000000..7a675b44b --- /dev/null +++ b/web/icons/aws/Internet of Things/InternetOfThings_alexasmarthomeskill.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + InternetOfThings + + + + + + + + + + + diff --git a/web/icons/aws/Internet of Things/InternetOfThings_alexavoiceservice.svg b/web/icons/aws/Internet of Things/InternetOfThings_alexavoiceservice.svg new file mode 100644 index 000000000..717e2b7e6 --- /dev/null +++ b/web/icons/aws/Internet of Things/InternetOfThings_alexavoiceservice.svg @@ -0,0 +1,8 @@ + + InternetOfThings + + + + + + diff --git a/web/icons/aws/Internet of Things/InternetOfThings_echo.svg b/web/icons/aws/Internet of Things/InternetOfThings_echo.svg new file mode 100644 index 000000000..7bdfba738 --- /dev/null +++ b/web/icons/aws/Internet of Things/InternetOfThings_echo.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + InternetOfThings + + + + + + + + + diff --git a/web/icons/aws/Internet of Things/InternetOfThings_fireTV.svg b/web/icons/aws/Internet of Things/InternetOfThings_fireTV.svg new file mode 100644 index 000000000..46d00acac --- /dev/null +++ b/web/icons/aws/Internet of Things/InternetOfThings_fireTV.svg @@ -0,0 +1,12 @@ + + InternetOfThings + + + + + + + + + + diff --git a/web/icons/aws/Internet of Things/InternetOfThings_fireTVstick.svg b/web/icons/aws/Internet of Things/InternetOfThings_fireTVstick.svg new file mode 100644 index 000000000..3a99721ba --- /dev/null +++ b/web/icons/aws/Internet of Things/InternetOfThings_fireTVstick.svg @@ -0,0 +1,14 @@ + + InternetOfThings + + + + + + + + + + + + diff --git a/web/icons/aws/Internet of Things/InternetOfThings_lambdafunction.svg b/web/icons/aws/Internet of Things/InternetOfThings_lambdafunction.svg new file mode 100644 index 000000000..221e608aa --- /dev/null +++ b/web/icons/aws/Internet of Things/InternetOfThings_lambdafunction.svg @@ -0,0 +1,8 @@ + + InternetOfThings + + + + + + diff --git a/web/icons/aws/Management Tools/ManagementTools_AWSCloudFormation.svg b/web/icons/aws/Management Tools/ManagementTools_AWSCloudFormation.svg new file mode 100644 index 000000000..e078199e4 --- /dev/null +++ b/web/icons/aws/Management Tools/ManagementTools_AWSCloudFormation.svg @@ -0,0 +1,13 @@ + + ManagementTools + + + + + + + + + + + diff --git a/web/icons/aws/Management Tools/ManagementTools_AWSCloudFormation_changeset.svg b/web/icons/aws/Management Tools/ManagementTools_AWSCloudFormation_changeset.svg new file mode 100644 index 000000000..f6f92090b --- /dev/null +++ b/web/icons/aws/Management Tools/ManagementTools_AWSCloudFormation_changeset.svg @@ -0,0 +1,24 @@ + + ManagementTools + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Management Tools/ManagementTools_AWSCloudFormation_stack.svg b/web/icons/aws/Management Tools/ManagementTools_AWSCloudFormation_stack.svg new file mode 100644 index 000000000..c0afd6446 --- /dev/null +++ b/web/icons/aws/Management Tools/ManagementTools_AWSCloudFormation_stack.svg @@ -0,0 +1,17 @@ + + ManagementTools + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Management Tools/ManagementTools_AWSCloudFormation_template.svg b/web/icons/aws/Management Tools/ManagementTools_AWSCloudFormation_template.svg new file mode 100644 index 000000000..24141de1f --- /dev/null +++ b/web/icons/aws/Management Tools/ManagementTools_AWSCloudFormation_template.svg @@ -0,0 +1,15 @@ + + ManagementTools + + + + + + + + + + + + + diff --git a/web/icons/aws/Management Tools/ManagementTools_AWSCloudTrail.svg b/web/icons/aws/Management Tools/ManagementTools_AWSCloudTrail.svg new file mode 100644 index 000000000..983b71a2e --- /dev/null +++ b/web/icons/aws/Management Tools/ManagementTools_AWSCloudTrail.svg @@ -0,0 +1,19 @@ + + ManagementTools + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Management Tools/ManagementTools_AWSConfig.svg b/web/icons/aws/Management Tools/ManagementTools_AWSConfig.svg new file mode 100644 index 000000000..a71acdc0b --- /dev/null +++ b/web/icons/aws/Management Tools/ManagementTools_AWSConfig.svg @@ -0,0 +1,19 @@ + + ManagementTools + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Management Tools/ManagementTools_AWSManagedServices.svg b/web/icons/aws/Management Tools/ManagementTools_AWSManagedServices.svg new file mode 100644 index 000000000..73cc6a0a6 --- /dev/null +++ b/web/icons/aws/Management Tools/ManagementTools_AWSManagedServices.svg @@ -0,0 +1,23 @@ + + ManagementTools + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Management Tools/ManagementTools_AWSOpsWorks.svg b/web/icons/aws/Management Tools/ManagementTools_AWSOpsWorks.svg new file mode 100644 index 000000000..a6edc99f3 --- /dev/null +++ b/web/icons/aws/Management Tools/ManagementTools_AWSOpsWorks.svg @@ -0,0 +1,15 @@ + + ManagementTools + + + + + + + + + + + + + diff --git a/web/icons/aws/Management Tools/ManagementTools_AWSOpsWorks_apps.svg b/web/icons/aws/Management Tools/ManagementTools_AWSOpsWorks_apps.svg new file mode 100644 index 000000000..ab5ecccc6 --- /dev/null +++ b/web/icons/aws/Management Tools/ManagementTools_AWSOpsWorks_apps.svg @@ -0,0 +1,7 @@ + + ManagementTools + + + + + diff --git a/web/icons/aws/Management Tools/ManagementTools_AWSOpsWorks_deployments.svg b/web/icons/aws/Management Tools/ManagementTools_AWSOpsWorks_deployments.svg new file mode 100644 index 000000000..e416bf7dd --- /dev/null +++ b/web/icons/aws/Management Tools/ManagementTools_AWSOpsWorks_deployments.svg @@ -0,0 +1,13 @@ + + ManagementTools + + + + + + + + + + + diff --git a/web/icons/aws/Management Tools/ManagementTools_AWSOpsWorks_instances.svg b/web/icons/aws/Management Tools/ManagementTools_AWSOpsWorks_instances.svg new file mode 100644 index 000000000..e9b968510 --- /dev/null +++ b/web/icons/aws/Management Tools/ManagementTools_AWSOpsWorks_instances.svg @@ -0,0 +1,23 @@ + + ManagementTools + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Management Tools/ManagementTools_AWSOpsWorks_layers.svg b/web/icons/aws/Management Tools/ManagementTools_AWSOpsWorks_layers.svg new file mode 100644 index 000000000..16cf880cf --- /dev/null +++ b/web/icons/aws/Management Tools/ManagementTools_AWSOpsWorks_layers.svg @@ -0,0 +1,9 @@ + + ManagementTools + + + + + + + diff --git a/web/icons/aws/Management Tools/ManagementTools_AWSOpsWorks_monitoring.svg b/web/icons/aws/Management Tools/ManagementTools_AWSOpsWorks_monitoring.svg new file mode 100644 index 000000000..b6453afbf --- /dev/null +++ b/web/icons/aws/Management Tools/ManagementTools_AWSOpsWorks_monitoring.svg @@ -0,0 +1,7 @@ + + ManagementTools + + + + + diff --git a/web/icons/aws/Management Tools/ManagementTools_AWSOpsWorks_permissions.svg b/web/icons/aws/Management Tools/ManagementTools_AWSOpsWorks_permissions.svg new file mode 100644 index 000000000..479361808 --- /dev/null +++ b/web/icons/aws/Management Tools/ManagementTools_AWSOpsWorks_permissions.svg @@ -0,0 +1,7 @@ + + ManagementTools + + + + + diff --git a/web/icons/aws/Management Tools/ManagementTools_AWSOpsWorks_resources.svg b/web/icons/aws/Management Tools/ManagementTools_AWSOpsWorks_resources.svg new file mode 100644 index 000000000..9592fbe0a --- /dev/null +++ b/web/icons/aws/Management Tools/ManagementTools_AWSOpsWorks_resources.svg @@ -0,0 +1,10 @@ + + ManagementTools + + + + + + + + diff --git a/web/icons/aws/Management Tools/ManagementTools_AWSOpsWorks_stack.svg b/web/icons/aws/Management Tools/ManagementTools_AWSOpsWorks_stack.svg new file mode 100644 index 000000000..13d20e04a --- /dev/null +++ b/web/icons/aws/Management Tools/ManagementTools_AWSOpsWorks_stack.svg @@ -0,0 +1,7 @@ + + ManagementTools + + + + + diff --git a/web/icons/aws/Management Tools/ManagementTools_AWSServiceCatalog.svg b/web/icons/aws/Management Tools/ManagementTools_AWSServiceCatalog.svg new file mode 100644 index 000000000..f0e6ed75e --- /dev/null +++ b/web/icons/aws/Management Tools/ManagementTools_AWSServiceCatalog.svg @@ -0,0 +1,27 @@ + + ManagementTools + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Management Tools/ManagementTools_AWSTrustedAdvisor.svg b/web/icons/aws/Management Tools/ManagementTools_AWSTrustedAdvisor.svg new file mode 100644 index 000000000..ffdf683ff --- /dev/null +++ b/web/icons/aws/Management Tools/ManagementTools_AWSTrustedAdvisor.svg @@ -0,0 +1,14 @@ + + ManagementTools + + + + + + + + + + + + diff --git a/web/icons/aws/Management Tools/ManagementTools_AWSTrustedAdvisor_checklist.svg b/web/icons/aws/Management Tools/ManagementTools_AWSTrustedAdvisor_checklist.svg new file mode 100644 index 000000000..0abfc95fb --- /dev/null +++ b/web/icons/aws/Management Tools/ManagementTools_AWSTrustedAdvisor_checklist.svg @@ -0,0 +1,18 @@ + + ManagementTools + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Management Tools/ManagementTools_AWSTrustedAdvisor_checklistcost.svg b/web/icons/aws/Management Tools/ManagementTools_AWSTrustedAdvisor_checklistcost.svg new file mode 100644 index 000000000..eefbb123f --- /dev/null +++ b/web/icons/aws/Management Tools/ManagementTools_AWSTrustedAdvisor_checklistcost.svg @@ -0,0 +1,18 @@ + + ManagementTools + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Management Tools/ManagementTools_AWSTrustedAdvisor_checklistfaulttolerance.svg b/web/icons/aws/Management Tools/ManagementTools_AWSTrustedAdvisor_checklistfaulttolerance.svg new file mode 100644 index 000000000..7447d2b3f --- /dev/null +++ b/web/icons/aws/Management Tools/ManagementTools_AWSTrustedAdvisor_checklistfaulttolerance.svg @@ -0,0 +1,20 @@ + + ManagementTools + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Management Tools/ManagementTools_AWSTrustedAdvisor_checklistperformance.svg b/web/icons/aws/Management Tools/ManagementTools_AWSTrustedAdvisor_checklistperformance.svg new file mode 100644 index 000000000..c43495c60 --- /dev/null +++ b/web/icons/aws/Management Tools/ManagementTools_AWSTrustedAdvisor_checklistperformance.svg @@ -0,0 +1,32 @@ + + ManagementTools + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Management Tools/ManagementTools_AWSTrustedAdvisor_checklistsecurity.svg b/web/icons/aws/Management Tools/ManagementTools_AWSTrustedAdvisor_checklistsecurity.svg new file mode 100644 index 000000000..4a27d74f8 --- /dev/null +++ b/web/icons/aws/Management Tools/ManagementTools_AWSTrustedAdvisor_checklistsecurity.svg @@ -0,0 +1,18 @@ + + ManagementTools + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Management Tools/ManagementTools_AmazonCloudWatch.svg b/web/icons/aws/Management Tools/ManagementTools_AmazonCloudWatch.svg new file mode 100644 index 000000000..ab380f615 --- /dev/null +++ b/web/icons/aws/Management Tools/ManagementTools_AmazonCloudWatch.svg @@ -0,0 +1,15 @@ + + ManagementTools + + + + + + + + + + + + + diff --git a/web/icons/aws/Management Tools/ManagementTools_AmazonCloudWatch_alarm.svg b/web/icons/aws/Management Tools/ManagementTools_AmazonCloudWatch_alarm.svg new file mode 100644 index 000000000..a89c2fecf --- /dev/null +++ b/web/icons/aws/Management Tools/ManagementTools_AmazonCloudWatch_alarm.svg @@ -0,0 +1,15 @@ + + ManagementTools + + + + + + + + + + + + + diff --git a/web/icons/aws/Management Tools/ManagementTools_AmazonCloudWatch_configrule.svg b/web/icons/aws/Management Tools/ManagementTools_AmazonCloudWatch_configrule.svg new file mode 100644 index 000000000..f8e7989ce --- /dev/null +++ b/web/icons/aws/Management Tools/ManagementTools_AmazonCloudWatch_configrule.svg @@ -0,0 +1,17 @@ + + ManagementTools + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Management Tools/ManagementTools_AmazonCloudWatch_eventeventbased.svg b/web/icons/aws/Management Tools/ManagementTools_AmazonCloudWatch_eventeventbased.svg new file mode 100644 index 000000000..6a78958c7 --- /dev/null +++ b/web/icons/aws/Management Tools/ManagementTools_AmazonCloudWatch_eventeventbased.svg @@ -0,0 +1,15 @@ + + ManagementTools + + + + + + + + + + + + + diff --git a/web/icons/aws/Management Tools/ManagementTools_AmazonCloudWatch_eventtimebased.svg b/web/icons/aws/Management Tools/ManagementTools_AmazonCloudWatch_eventtimebased.svg new file mode 100644 index 000000000..31409b06b --- /dev/null +++ b/web/icons/aws/Management Tools/ManagementTools_AmazonCloudWatch_eventtimebased.svg @@ -0,0 +1,23 @@ + + ManagementTools + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Messaging/Messaging_AmazonPinpoint.svg b/web/icons/aws/Messaging/Messaging_AmazonPinpoint.svg new file mode 100644 index 000000000..3eb8333b1 --- /dev/null +++ b/web/icons/aws/Messaging/Messaging_AmazonPinpoint.svg @@ -0,0 +1,75 @@ + + Messaging + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Messaging/Messaging_AmazonSES.svg b/web/icons/aws/Messaging/Messaging_AmazonSES.svg new file mode 100644 index 000000000..13effbf4e --- /dev/null +++ b/web/icons/aws/Messaging/Messaging_AmazonSES.svg @@ -0,0 +1,12 @@ + + Messaging + + + + + + + + + + diff --git a/web/icons/aws/Messaging/Messaging_AmazonSES_email.svg b/web/icons/aws/Messaging/Messaging_AmazonSES_email.svg new file mode 100644 index 000000000..96cca71ce --- /dev/null +++ b/web/icons/aws/Messaging/Messaging_AmazonSES_email.svg @@ -0,0 +1,35 @@ + + + + + + + + + + Messaging + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Messaging/Messaging_AmazonSNS.svg b/web/icons/aws/Messaging/Messaging_AmazonSNS.svg new file mode 100644 index 000000000..5ae892b2f --- /dev/null +++ b/web/icons/aws/Messaging/Messaging_AmazonSNS.svg @@ -0,0 +1,17 @@ + + Messaging + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Messaging/Messaging_AmazonSNS_HTTPnotification.svg b/web/icons/aws/Messaging/Messaging_AmazonSNS_HTTPnotification.svg new file mode 100644 index 000000000..aafbb0851 --- /dev/null +++ b/web/icons/aws/Messaging/Messaging_AmazonSNS_HTTPnotification.svg @@ -0,0 +1,32 @@ + + + + + + + Messaging + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Messaging/Messaging_AmazonSNS_emailnotification.svg b/web/icons/aws/Messaging/Messaging_AmazonSNS_emailnotification.svg new file mode 100644 index 000000000..cde2fcecf --- /dev/null +++ b/web/icons/aws/Messaging/Messaging_AmazonSNS_emailnotification.svg @@ -0,0 +1,33 @@ + + + + + + + Messaging + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Messaging/Messaging_AmazonSNS_topic.svg b/web/icons/aws/Messaging/Messaging_AmazonSNS_topic.svg new file mode 100644 index 000000000..2c8334e17 --- /dev/null +++ b/web/icons/aws/Messaging/Messaging_AmazonSNS_topic.svg @@ -0,0 +1,13 @@ + + Messaging + + + + + + + + + + + diff --git a/web/icons/aws/Messaging/Messaging_AmazonSQS.svg b/web/icons/aws/Messaging/Messaging_AmazonSQS.svg new file mode 100644 index 000000000..777e72b89 --- /dev/null +++ b/web/icons/aws/Messaging/Messaging_AmazonSQS.svg @@ -0,0 +1,16 @@ + + Messaging + + + + + + + + + + + + + + diff --git a/web/icons/aws/Messaging/Messaging_AmazonSQS_message.svg b/web/icons/aws/Messaging/Messaging_AmazonSQS_message.svg new file mode 100644 index 000000000..e9114033e --- /dev/null +++ b/web/icons/aws/Messaging/Messaging_AmazonSQS_message.svg @@ -0,0 +1,16 @@ + + Messaging + + + + + + + + + + + + + + diff --git a/web/icons/aws/Messaging/Messaging_AmazonSQS_queue.svg b/web/icons/aws/Messaging/Messaging_AmazonSQS_queue.svg new file mode 100644 index 000000000..6f996245c --- /dev/null +++ b/web/icons/aws/Messaging/Messaging_AmazonSQS_queue.svg @@ -0,0 +1,12 @@ + + Messaging + + + + + + + + + + diff --git a/web/icons/aws/Migration/Migration_AWSApplicationDiscoveryService.svg b/web/icons/aws/Migration/Migration_AWSApplicationDiscoveryService.svg new file mode 100644 index 000000000..04974c80d --- /dev/null +++ b/web/icons/aws/Migration/Migration_AWSApplicationDiscoveryService.svg @@ -0,0 +1,18 @@ + + Migration + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Migration/Migration_AWSDMS.svg b/web/icons/aws/Migration/Migration_AWSDMS.svg new file mode 100644 index 000000000..b11afc08d --- /dev/null +++ b/web/icons/aws/Migration/Migration_AWSDMS.svg @@ -0,0 +1,20 @@ + + Migration + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Migration/Migration_AWSDMS_databasemigrationworkflow-job.svg b/web/icons/aws/Migration/Migration_AWSDMS_databasemigrationworkflow-job.svg new file mode 100644 index 000000000..ddaba331f --- /dev/null +++ b/web/icons/aws/Migration/Migration_AWSDMS_databasemigrationworkflow-job.svg @@ -0,0 +1,21 @@ + + Migration + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Migration/Migration_AWSSMS.svg b/web/icons/aws/Migration/Migration_AWSSMS.svg new file mode 100644 index 000000000..8ac3ab2fb --- /dev/null +++ b/web/icons/aws/Migration/Migration_AWSSMS.svg @@ -0,0 +1,40 @@ + + Migration + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Migration/Migration_AWSSnowball.svg b/web/icons/aws/Migration/Migration_AWSSnowball.svg new file mode 100644 index 000000000..5e374d4e6 --- /dev/null +++ b/web/icons/aws/Migration/Migration_AWSSnowball.svg @@ -0,0 +1,25 @@ + + Migration + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Migration/Migration_AWSSnowball_importexport.svg b/web/icons/aws/Migration/Migration_AWSSnowball_importexport.svg new file mode 100644 index 000000000..5de7d0132 --- /dev/null +++ b/web/icons/aws/Migration/Migration_AWSSnowball_importexport.svg @@ -0,0 +1,15 @@ + + Migration + + + + + + + + + + + + + diff --git a/web/icons/aws/Mobile Services/MobileServices_AWSDeviceFarm.svg b/web/icons/aws/Mobile Services/MobileServices_AWSDeviceFarm.svg new file mode 100644 index 000000000..72adf6a98 --- /dev/null +++ b/web/icons/aws/Mobile Services/MobileServices_AWSDeviceFarm.svg @@ -0,0 +1,20 @@ + + MobileServices + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Mobile Services/MobileServices_AWSMobileHub.svg b/web/icons/aws/Mobile Services/MobileServices_AWSMobileHub.svg new file mode 100644 index 000000000..dcf7ec928 --- /dev/null +++ b/web/icons/aws/Mobile Services/MobileServices_AWSMobileHub.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + MobileServices + + + + + + + + diff --git a/web/icons/aws/Mobile Services/MobileServices_AmazonAPIGateway.svg b/web/icons/aws/Mobile Services/MobileServices_AmazonAPIGateway.svg new file mode 100644 index 000000000..31791dcbf --- /dev/null +++ b/web/icons/aws/Mobile Services/MobileServices_AmazonAPIGateway.svg @@ -0,0 +1,27 @@ + + MobileServices + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Mobile Services/MobileServices_AmazonCognito.svg b/web/icons/aws/Mobile Services/MobileServices_AmazonCognito.svg new file mode 100644 index 000000000..d1a53e4e7 --- /dev/null +++ b/web/icons/aws/Mobile Services/MobileServices_AmazonCognito.svg @@ -0,0 +1,19 @@ + + MobileServices + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Mobile Services/MobileServices_AmazonMobileAnalytics.svg b/web/icons/aws/Mobile Services/MobileServices_AmazonMobileAnalytics.svg new file mode 100644 index 000000000..b9787072c --- /dev/null +++ b/web/icons/aws/Mobile Services/MobileServices_AmazonMobileAnalytics.svg @@ -0,0 +1,21 @@ + + MobileServices + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Mobile Services/MobileServices_AmazonPinpoint.svg b/web/icons/aws/Mobile Services/MobileServices_AmazonPinpoint.svg new file mode 100644 index 000000000..d9bac694e --- /dev/null +++ b/web/icons/aws/Mobile Services/MobileServices_AmazonPinpoint.svg @@ -0,0 +1,75 @@ + + MobileServices + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AWSDirectConnect.svg b/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AWSDirectConnect.svg new file mode 100644 index 000000000..44ef8830c --- /dev/null +++ b/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AWSDirectConnect.svg @@ -0,0 +1,15 @@ + + NetworkingContentDelivery + + + + + + + + + + + + + diff --git a/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonCloudFront.svg b/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonCloudFront.svg new file mode 100644 index 000000000..9e8b8b095 --- /dev/null +++ b/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonCloudFront.svg @@ -0,0 +1,23 @@ + + NetworkingContentDelivery + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonCloudFront_downloaddistribution.svg b/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonCloudFront_downloaddistribution.svg new file mode 100644 index 000000000..178dff259 --- /dev/null +++ b/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonCloudFront_downloaddistribution.svg @@ -0,0 +1,8 @@ + + NetworkingContentDelivery + + + + + + diff --git a/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonCloudFront_edgelocation.svg b/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonCloudFront_edgelocation.svg new file mode 100644 index 000000000..3ccf55d86 --- /dev/null +++ b/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonCloudFront_edgelocation.svg @@ -0,0 +1,33 @@ + + + + + + + + + + NetworkingContentDelivery + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonCloudFront_streamingdistribution.svg b/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonCloudFront_streamingdistribution.svg new file mode 100644 index 000000000..623b186b4 --- /dev/null +++ b/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonCloudFront_streamingdistribution.svg @@ -0,0 +1,8 @@ + + NetworkingContentDelivery + + + + + + diff --git a/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonRoute53.svg b/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonRoute53.svg new file mode 100644 index 000000000..9453aca6f --- /dev/null +++ b/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonRoute53.svg @@ -0,0 +1,12 @@ + + NetworkingContentDelivery + + + + + + + + + + diff --git a/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonRoute53_hostedzone.svg b/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonRoute53_hostedzone.svg new file mode 100644 index 000000000..253733947 --- /dev/null +++ b/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonRoute53_hostedzone.svg @@ -0,0 +1,7 @@ + + NetworkingContentDelivery + + + + + diff --git a/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonRoute53_routetable.svg b/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonRoute53_routetable.svg new file mode 100644 index 000000000..92eb186ff --- /dev/null +++ b/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonRoute53_routetable.svg @@ -0,0 +1,21 @@ + + NetworkingContentDelivery + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonVPC.svg b/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonVPC.svg new file mode 100644 index 000000000..aacb834da --- /dev/null +++ b/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonVPC.svg @@ -0,0 +1,17 @@ + + NetworkingContentDelivery + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonVPC_VPCNATgateway.svg b/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonVPC_VPCNATgateway.svg new file mode 100644 index 000000000..8ad4388ad --- /dev/null +++ b/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonVPC_VPCNATgateway.svg @@ -0,0 +1,15 @@ + + NetworkingContentDelivery + + + + + + + + + + + + + diff --git a/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonVPC_VPCpeering.svg b/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonVPC_VPCpeering.svg new file mode 100644 index 000000000..a304409d9 --- /dev/null +++ b/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonVPC_VPCpeering.svg @@ -0,0 +1,12 @@ + + NetworkingContentDelivery + + + + + + + + + + diff --git a/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonVPC_VPNconnection.svg b/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonVPC_VPNconnection.svg new file mode 100644 index 000000000..467b817fe --- /dev/null +++ b/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonVPC_VPNconnection.svg @@ -0,0 +1,7 @@ + + NetworkingContentDelivery + + + + + diff --git a/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonVPC_VPNgateway.svg b/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonVPC_VPNgateway.svg new file mode 100644 index 000000000..ecd13ddb3 --- /dev/null +++ b/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonVPC_VPNgateway.svg @@ -0,0 +1,8 @@ + + NetworkingContentDelivery + + + + + + diff --git a/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonVPC_customergateway.svg b/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonVPC_customergateway.svg new file mode 100644 index 000000000..33f4ab710 --- /dev/null +++ b/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonVPC_customergateway.svg @@ -0,0 +1,13 @@ + + NetworkingContentDelivery + + + + + + + + + + + diff --git a/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonVPC_elasticnetworkadapter.svg b/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonVPC_elasticnetworkadapter.svg new file mode 100644 index 000000000..0db123c40 --- /dev/null +++ b/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonVPC_elasticnetworkadapter.svg @@ -0,0 +1,12 @@ + + NetworkingContentDelivery + + + + + + + + + + diff --git a/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonVPC_elasticnetworkinterface.svg b/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonVPC_elasticnetworkinterface.svg new file mode 100644 index 000000000..9eef92b40 --- /dev/null +++ b/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonVPC_elasticnetworkinterface.svg @@ -0,0 +1,13 @@ + + NetworkingContentDelivery + + + + + + + + + + + diff --git a/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonVPC_endpoints.svg b/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonVPC_endpoints.svg new file mode 100644 index 000000000..ae88db110 --- /dev/null +++ b/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonVPC_endpoints.svg @@ -0,0 +1,11 @@ + + NetworkingContentDelivery + + + + + + + + + diff --git a/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonVPC_flowlogs.svg b/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonVPC_flowlogs.svg new file mode 100644 index 000000000..08f27bfaf --- /dev/null +++ b/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonVPC_flowlogs.svg @@ -0,0 +1,19 @@ + + NetworkingContentDelivery + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonVPC_internetgateway.svg b/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonVPC_internetgateway.svg new file mode 100644 index 000000000..ad60a1bd1 --- /dev/null +++ b/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonVPC_internetgateway.svg @@ -0,0 +1,10 @@ + + NetworkingContentDelivery + + + + + + + + diff --git a/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonVPC_router.svg b/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonVPC_router.svg new file mode 100644 index 000000000..0d958212a --- /dev/null +++ b/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_AmazonVPC_router.svg @@ -0,0 +1,20 @@ + + NetworkingContentDelivery + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_ElasticLoadBalancing.svg b/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_ElasticLoadBalancing.svg new file mode 100644 index 000000000..0629317f7 --- /dev/null +++ b/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_ElasticLoadBalancing.svg @@ -0,0 +1,23 @@ + + NetworkingContentDelivery + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_ElasticLoadBalancing_ApplicationLoadBalancer.svg b/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_ElasticLoadBalancing_ApplicationLoadBalancer.svg new file mode 100644 index 000000000..f260675e6 --- /dev/null +++ b/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_ElasticLoadBalancing_ApplicationLoadBalancer.svg @@ -0,0 +1,24 @@ + + NetworkingContentDelivery + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_ElasticLoadBalancing_ClassicLoadBalancer.svg b/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_ElasticLoadBalancing_ClassicLoadBalancer.svg new file mode 100644 index 000000000..4acfbe729 --- /dev/null +++ b/web/icons/aws/Networking & Content Delivery/NetworkingContentDelivery_ElasticLoadBalancing_ClassicLoadBalancer.svg @@ -0,0 +1,12 @@ + + NetworkingContentDelivery + + + + + + + + + + diff --git a/web/icons/aws/On Demand Workforce/OnDemandWorkforce_AmazonMechanicalTurk.svg b/web/icons/aws/On Demand Workforce/OnDemandWorkforce_AmazonMechanicalTurk.svg new file mode 100644 index 000000000..4af707e21 --- /dev/null +++ b/web/icons/aws/On Demand Workforce/OnDemandWorkforce_AmazonMechanicalTurk.svg @@ -0,0 +1 @@ +OnDemandWorkforce \ No newline at end of file diff --git a/web/icons/aws/On Demand Workforce/OnDemandWorkforce_AmazonMechanicalTurk_assignmenttask.svg b/web/icons/aws/On Demand Workforce/OnDemandWorkforce_AmazonMechanicalTurk_assignmenttask.svg new file mode 100644 index 000000000..912f75755 --- /dev/null +++ b/web/icons/aws/On Demand Workforce/OnDemandWorkforce_AmazonMechanicalTurk_assignmenttask.svg @@ -0,0 +1 @@ +OnDemandWorkforce \ No newline at end of file diff --git a/web/icons/aws/On Demand Workforce/OnDemandWorkforce_AmazonMechanicalTurk_humanintelligencetasks.svg b/web/icons/aws/On Demand Workforce/OnDemandWorkforce_AmazonMechanicalTurk_humanintelligencetasks.svg new file mode 100644 index 000000000..37e7665a7 --- /dev/null +++ b/web/icons/aws/On Demand Workforce/OnDemandWorkforce_AmazonMechanicalTurk_humanintelligencetasks.svg @@ -0,0 +1 @@ +OnDemandWorkforce \ No newline at end of file diff --git a/web/icons/aws/On Demand Workforce/OnDemandWorkforce_AmazonMechanicalTurk_requester.svg b/web/icons/aws/On Demand Workforce/OnDemandWorkforce_AmazonMechanicalTurk_requester.svg new file mode 100644 index 000000000..8e36ba3f7 --- /dev/null +++ b/web/icons/aws/On Demand Workforce/OnDemandWorkforce_AmazonMechanicalTurk_requester.svg @@ -0,0 +1 @@ +OnDemandWorkforce \ No newline at end of file diff --git a/web/icons/aws/On Demand Workforce/OnDemandWorkforce_AmazonMechanicalTurk_workers.svg b/web/icons/aws/On Demand Workforce/OnDemandWorkforce_AmazonMechanicalTurk_workers.svg new file mode 100644 index 000000000..5ae214288 --- /dev/null +++ b/web/icons/aws/On Demand Workforce/OnDemandWorkforce_AmazonMechanicalTurk_workers.svg @@ -0,0 +1 @@ +OnDemandWorkforce \ No newline at end of file diff --git a/web/icons/aws/SDKs/SDKs_AWSCLI.svg b/web/icons/aws/SDKs/SDKs_AWSCLI.svg new file mode 100644 index 000000000..ffa2f0c14 --- /dev/null +++ b/web/icons/aws/SDKs/SDKs_AWSCLI.svg @@ -0,0 +1,59 @@ + + SDKs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/SDKs/SDKs_AWSToolkitForEclipse.svg b/web/icons/aws/SDKs/SDKs_AWSToolkitForEclipse.svg new file mode 100644 index 000000000..f70ea84e5 --- /dev/null +++ b/web/icons/aws/SDKs/SDKs_AWSToolkitForEclipse.svg @@ -0,0 +1,32 @@ + + SDKs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/SDKs/SDKs_AWSToolkitForVisualStudio.svg b/web/icons/aws/SDKs/SDKs_AWSToolkitForVisualStudio.svg new file mode 100644 index 000000000..231891bc4 --- /dev/null +++ b/web/icons/aws/SDKs/SDKs_AWSToolkitForVisualStudio.svg @@ -0,0 +1,32 @@ + + SDKs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/SDKs/SDKs_AWSToolsForWindowsPowerShell.svg b/web/icons/aws/SDKs/SDKs_AWSToolsForWindowsPowerShell.svg new file mode 100644 index 000000000..9646f3dd6 --- /dev/null +++ b/web/icons/aws/SDKs/SDKs_AWSToolsForWindowsPowerShell.svg @@ -0,0 +1,32 @@ + + SDKs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/SDKs/SDKs_Android.svg b/web/icons/aws/SDKs/SDKs_Android.svg new file mode 100644 index 000000000..61996718b --- /dev/null +++ b/web/icons/aws/SDKs/SDKs_Android.svg @@ -0,0 +1,19 @@ + + SDKs + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/SDKs/SDKs_Java.svg b/web/icons/aws/SDKs/SDKs_Java.svg new file mode 100644 index 000000000..0bbe9bbe4 --- /dev/null +++ b/web/icons/aws/SDKs/SDKs_Java.svg @@ -0,0 +1,19 @@ + + SDKs + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/SDKs/SDKs_JavaScript.svg b/web/icons/aws/SDKs/SDKs_JavaScript.svg new file mode 100644 index 000000000..68ccfc49d --- /dev/null +++ b/web/icons/aws/SDKs/SDKs_JavaScript.svg @@ -0,0 +1,19 @@ + + SDKs + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/SDKs/SDKs_Net.svg b/web/icons/aws/SDKs/SDKs_Net.svg new file mode 100644 index 000000000..fd7047adf --- /dev/null +++ b/web/icons/aws/SDKs/SDKs_Net.svg @@ -0,0 +1,19 @@ + + SDKs + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/SDKs/SDKs_Nodejs.svg b/web/icons/aws/SDKs/SDKs_Nodejs.svg new file mode 100644 index 000000000..4f4233454 --- /dev/null +++ b/web/icons/aws/SDKs/SDKs_Nodejs.svg @@ -0,0 +1,19 @@ + + SDKs + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/SDKs/SDKs_PHP.svg b/web/icons/aws/SDKs/SDKs_PHP.svg new file mode 100644 index 000000000..2b0b7ba82 --- /dev/null +++ b/web/icons/aws/SDKs/SDKs_PHP.svg @@ -0,0 +1,19 @@ + + SDKs + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/SDKs/SDKs_Python.svg b/web/icons/aws/SDKs/SDKs_Python.svg new file mode 100644 index 000000000..e1b034d36 --- /dev/null +++ b/web/icons/aws/SDKs/SDKs_Python.svg @@ -0,0 +1,19 @@ + + SDKs + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/SDKs/SDKs_Ruby.svg b/web/icons/aws/SDKs/SDKs_Ruby.svg new file mode 100644 index 000000000..63f415ddc --- /dev/null +++ b/web/icons/aws/SDKs/SDKs_Ruby.svg @@ -0,0 +1,19 @@ + + SDKs + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/SDKs/SDKs_Xamarin.svg b/web/icons/aws/SDKs/SDKs_Xamarin.svg new file mode 100644 index 000000000..d2a5d0c26 --- /dev/null +++ b/web/icons/aws/SDKs/SDKs_Xamarin.svg @@ -0,0 +1,33 @@ + + SDKs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/SDKs/SDKs_iOS.svg b/web/icons/aws/SDKs/SDKs_iOS.svg new file mode 100644 index 000000000..b527ea457 --- /dev/null +++ b/web/icons/aws/SDKs/SDKs_iOS.svg @@ -0,0 +1,19 @@ + + SDKs + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_AWSArtifact.svg b/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_AWSArtifact.svg new file mode 100644 index 000000000..1a3375d4a --- /dev/null +++ b/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_AWSArtifact.svg @@ -0,0 +1,19 @@ + + SecurityIdentityCompliance + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_AWSCertificateManager.svg b/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_AWSCertificateManager.svg new file mode 100644 index 000000000..9b29490ec --- /dev/null +++ b/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_AWSCertificateManager.svg @@ -0,0 +1,11 @@ + + SecurityIdentityCompliance + + + + + + + + + diff --git a/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_AWSCertificateManager_certificatemanager.svg b/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_AWSCertificateManager_certificatemanager.svg new file mode 100644 index 000000000..bc4a422ae --- /dev/null +++ b/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_AWSCertificateManager_certificatemanager.svg @@ -0,0 +1,13 @@ + + SecurityIdentityCompliance + + + + + + + + + + + diff --git a/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_AWSCloudHSM.svg b/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_AWSCloudHSM.svg new file mode 100644 index 000000000..ad853385a --- /dev/null +++ b/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_AWSCloudHSM.svg @@ -0,0 +1,14 @@ + + SecurityIdentityCompliance + + + + + + + + + + + + diff --git a/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_AWSKMS.svg b/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_AWSKMS.svg new file mode 100644 index 000000000..12b70bdd5 --- /dev/null +++ b/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_AWSKMS.svg @@ -0,0 +1,11 @@ + + SecurityIdentityCompliance + + + + + + + + + diff --git a/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_AWSOrganizations.svg b/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_AWSOrganizations.svg new file mode 100644 index 000000000..b50293ebd --- /dev/null +++ b/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_AWSOrganizations.svg @@ -0,0 +1,23 @@ + + ManagementTools + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_AWSShield.svg b/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_AWSShield.svg new file mode 100644 index 000000000..007136e9a --- /dev/null +++ b/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_AWSShield.svg @@ -0,0 +1,13 @@ + + SecurityIdentityCompliance + + + + + + + + + + + diff --git a/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_AWSWAF.svg b/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_AWSWAF.svg new file mode 100644 index 000000000..0c1c815dd --- /dev/null +++ b/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_AWSWAF.svg @@ -0,0 +1,20 @@ + + SecurityIdentityCompliance + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_AWSWAF_filteringrule.svg b/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_AWSWAF_filteringrule.svg new file mode 100644 index 000000000..749737fe2 --- /dev/null +++ b/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_AWSWAF_filteringrule.svg @@ -0,0 +1,8 @@ + + SecurityIdentityCompliance + + + + + + diff --git a/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_AmazonInspector.svg b/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_AmazonInspector.svg new file mode 100644 index 000000000..944abc8bc --- /dev/null +++ b/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_AmazonInspector.svg @@ -0,0 +1,13 @@ + + SecurityIdentityCompliance + + + + + + + + + + + diff --git a/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_AmazonInspector_agent.svg b/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_AmazonInspector_agent.svg new file mode 100644 index 000000000..979899263 --- /dev/null +++ b/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_AmazonInspector_agent.svg @@ -0,0 +1,46 @@ + + SecurityIdentityCompliance + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_IAM.svg b/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_IAM.svg new file mode 100644 index 000000000..c8e0b6890 --- /dev/null +++ b/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_IAM.svg @@ -0,0 +1,15 @@ + + SecurityIdentityCompliance + + + + + + + + + + + + + diff --git a/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_IAM_AWSSTS-2.svg b/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_IAM_AWSSTS-2.svg new file mode 100644 index 000000000..fd26527da --- /dev/null +++ b/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_IAM_AWSSTS-2.svg @@ -0,0 +1,17 @@ + + SecurityIdentityCompliance + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_IAM_AWSSTS.svg b/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_IAM_AWSSTS.svg new file mode 100644 index 000000000..0e38fdcc0 --- /dev/null +++ b/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_IAM_AWSSTS.svg @@ -0,0 +1,10 @@ + + SecurityIdentityCompliance + + + + + + + + diff --git a/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_IAM_MFAtoken.svg b/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_IAM_MFAtoken.svg new file mode 100644 index 000000000..99b11092e --- /dev/null +++ b/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_IAM_MFAtoken.svg @@ -0,0 +1,18 @@ + + SecurityIdentityCompliance + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_IAM_addon.svg b/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_IAM_addon.svg new file mode 100644 index 000000000..29e1e073e --- /dev/null +++ b/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_IAM_addon.svg @@ -0,0 +1,11 @@ + + SecurityIdentityCompliance + + + + + + + + + diff --git a/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_IAM_dataencryptionkey.svg b/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_IAM_dataencryptionkey.svg new file mode 100644 index 000000000..d1f72b7ad --- /dev/null +++ b/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_IAM_dataencryptionkey.svg @@ -0,0 +1,9 @@ + + SecurityIdentityCompliance + + + + + + + diff --git a/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_IAM_encrypteddata.svg b/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_IAM_encrypteddata.svg new file mode 100644 index 000000000..68cc9852b --- /dev/null +++ b/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_IAM_encrypteddata.svg @@ -0,0 +1,7 @@ + + SecurityIdentityCompliance + + + + + diff --git a/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_IAM_long-termsecuritycredential.svg b/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_IAM_long-termsecuritycredential.svg new file mode 100644 index 000000000..aec818889 --- /dev/null +++ b/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_IAM_long-termsecuritycredential.svg @@ -0,0 +1,13 @@ + + SecurityIdentityCompliance + + + + + + + + + + + diff --git a/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_IAM_permissions.svg b/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_IAM_permissions.svg new file mode 100644 index 000000000..8489e7d3a --- /dev/null +++ b/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_IAM_permissions.svg @@ -0,0 +1,12 @@ + + SecurityIdentityCompliance + + + + + + + + + + diff --git a/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_IAM_role.svg b/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_IAM_role.svg new file mode 100644 index 000000000..0409a2bf8 --- /dev/null +++ b/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_IAM_role.svg @@ -0,0 +1,11 @@ + + SecurityIdentityCompliance + + + + + + + + + diff --git a/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_IAM_temporarysecuritycredential.svg b/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_IAM_temporarysecuritycredential.svg new file mode 100644 index 000000000..5acb33bc0 --- /dev/null +++ b/web/icons/aws/Security Identity & Compliance/SecurityIdentityCompliance_IAM_temporarysecuritycredential.svg @@ -0,0 +1,19 @@ + + SecurityIdentityCompliance + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Storage/Storage_AWSSnowball.svg b/web/icons/aws/Storage/Storage_AWSSnowball.svg new file mode 100644 index 000000000..e4bbdfe8e --- /dev/null +++ b/web/icons/aws/Storage/Storage_AWSSnowball.svg @@ -0,0 +1,25 @@ + + Storage + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Storage/Storage_AWSSnowball_importexport.svg b/web/icons/aws/Storage/Storage_AWSSnowball_importexport.svg new file mode 100644 index 000000000..f1cd633dd --- /dev/null +++ b/web/icons/aws/Storage/Storage_AWSSnowball_importexport.svg @@ -0,0 +1,15 @@ + + Storage + + + + + + + + + + + + + diff --git a/web/icons/aws/Storage/Storage_AWSStorageGateway.svg b/web/icons/aws/Storage/Storage_AWSStorageGateway.svg new file mode 100644 index 000000000..372252a5e --- /dev/null +++ b/web/icons/aws/Storage/Storage_AWSStorageGateway.svg @@ -0,0 +1,11 @@ + + Storage + + + + + + + + + diff --git a/web/icons/aws/Storage/Storage_AWSStorageGateway_cachedvolume.svg b/web/icons/aws/Storage/Storage_AWSStorageGateway_cachedvolume.svg new file mode 100644 index 000000000..b09089235 --- /dev/null +++ b/web/icons/aws/Storage/Storage_AWSStorageGateway_cachedvolume.svg @@ -0,0 +1,14 @@ + + Storage + + + + + + + + + + + + diff --git a/web/icons/aws/Storage/Storage_AWSStorageGateway_non-cachedvolume.svg b/web/icons/aws/Storage/Storage_AWSStorageGateway_non-cachedvolume.svg new file mode 100644 index 000000000..a954080b2 --- /dev/null +++ b/web/icons/aws/Storage/Storage_AWSStorageGateway_non-cachedvolume.svg @@ -0,0 +1,7 @@ + + Storage + + + + + diff --git a/web/icons/aws/Storage/Storage_AWSStorageGateway_virtualtapelibrary.svg b/web/icons/aws/Storage/Storage_AWSStorageGateway_virtualtapelibrary.svg new file mode 100644 index 000000000..3f2c4ba31 --- /dev/null +++ b/web/icons/aws/Storage/Storage_AWSStorageGateway_virtualtapelibrary.svg @@ -0,0 +1,18 @@ + + Storage + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Storage/Storage_AmazonEBS.svg b/web/icons/aws/Storage/Storage_AmazonEBS.svg new file mode 100644 index 000000000..14621747c --- /dev/null +++ b/web/icons/aws/Storage/Storage_AmazonEBS.svg @@ -0,0 +1,9 @@ + + Storage + + + + + + + diff --git a/web/icons/aws/Storage/Storage_AmazonEFS.svg b/web/icons/aws/Storage/Storage_AmazonEFS.svg new file mode 100644 index 000000000..ef9f7e9bb --- /dev/null +++ b/web/icons/aws/Storage/Storage_AmazonEFS.svg @@ -0,0 +1,23 @@ + + Storage + + + + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Storage/Storage_AmazonEFS_EFSShare.svg b/web/icons/aws/Storage/Storage_AmazonEFS_EFSShare.svg new file mode 100644 index 000000000..51b9a46a5 --- /dev/null +++ b/web/icons/aws/Storage/Storage_AmazonEFS_EFSShare.svg @@ -0,0 +1,19 @@ + + Storage + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Storage/Storage_AmazonGlacier.svg b/web/icons/aws/Storage/Storage_AmazonGlacier.svg new file mode 100644 index 000000000..824ac97d2 --- /dev/null +++ b/web/icons/aws/Storage/Storage_AmazonGlacier.svg @@ -0,0 +1,11 @@ + + Storage + + + + + + + + + diff --git a/web/icons/aws/Storage/Storage_AmazonGlacier_archive.svg b/web/icons/aws/Storage/Storage_AmazonGlacier_archive.svg new file mode 100644 index 000000000..c57082a3b --- /dev/null +++ b/web/icons/aws/Storage/Storage_AmazonGlacier_archive.svg @@ -0,0 +1,13 @@ + + Storage + + + + + + + + + + + diff --git a/web/icons/aws/Storage/Storage_AmazonGlacier_vault.svg b/web/icons/aws/Storage/Storage_AmazonGlacier_vault.svg new file mode 100644 index 000000000..d1b57a53b --- /dev/null +++ b/web/icons/aws/Storage/Storage_AmazonGlacier_vault.svg @@ -0,0 +1,20 @@ + + Storage + + + + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Storage/Storage_AmazonS3.svg b/web/icons/aws/Storage/Storage_AmazonS3.svg new file mode 100644 index 000000000..316804ac4 --- /dev/null +++ b/web/icons/aws/Storage/Storage_AmazonS3.svg @@ -0,0 +1,17 @@ + + Storage + + + + + + + + + + + + + + + diff --git a/web/icons/aws/Storage/Storage_AmazonS3_bucket.svg b/web/icons/aws/Storage/Storage_AmazonS3_bucket.svg new file mode 100644 index 000000000..67e5531ce --- /dev/null +++ b/web/icons/aws/Storage/Storage_AmazonS3_bucket.svg @@ -0,0 +1,9 @@ + + Storage + + + + + + + diff --git a/web/icons/aws/Storage/Storage_AmazonS3_bucketwithobjects.svg b/web/icons/aws/Storage/Storage_AmazonS3_bucketwithobjects.svg new file mode 100644 index 000000000..5dd051bb3 --- /dev/null +++ b/web/icons/aws/Storage/Storage_AmazonS3_bucketwithobjects.svg @@ -0,0 +1,12 @@ + + Storage + + + + + + + + + + diff --git a/web/icons/aws/Storage/Storage_AmazonS3_object.svg b/web/icons/aws/Storage/Storage_AmazonS3_object.svg new file mode 100644 index 000000000..ccdba9af4 --- /dev/null +++ b/web/icons/aws/Storage/Storage_AmazonS3_object.svg @@ -0,0 +1,8 @@ + + Storage + + + + + + diff --git a/web/icons/aws/Storage/Storage_snapshot.svg b/web/icons/aws/Storage/Storage_snapshot.svg new file mode 100644 index 000000000..f69e232dd --- /dev/null +++ b/web/icons/aws/Storage/Storage_snapshot.svg @@ -0,0 +1,13 @@ + + Storage + + + + + + + + + + + diff --git a/web/icons/aws/Storage/Storage_volume.svg b/web/icons/aws/Storage/Storage_volume.svg new file mode 100644 index 000000000..14621747c --- /dev/null +++ b/web/icons/aws/Storage/Storage_volume.svg @@ -0,0 +1,9 @@ + + Storage + + + + + + + diff --git a/web/icons/cube.svg b/web/icons/cube.svg new file mode 100644 index 000000000..ec693b6ca --- /dev/null +++ b/web/icons/cube.svg @@ -0,0 +1 @@ +Layer 1 \ No newline at end of file diff --git a/web/index.html b/web/index.html new file mode 100644 index 000000000..056238fda --- /dev/null +++ b/web/index.html @@ -0,0 +1,90 @@ + + + + Duo CloudMapper + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web/js/FileSaver.min.js b/web/js/FileSaver.min.js new file mode 100644 index 000000000..9a1e397f2 --- /dev/null +++ b/web/js/FileSaver.min.js @@ -0,0 +1,2 @@ +/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */ +var saveAs=saveAs||function(e){"use strict";if(typeof e==="undefined"||typeof navigator!=="undefined"&&/MSIE [1-9]\./.test(navigator.userAgent)){return}var t=e.document,n=function(){return e.URL||e.webkitURL||e},r=t.createElementNS("http://www.w3.org/1999/xhtml","a"),o="download"in r,a=function(e){var t=new MouseEvent("click");e.dispatchEvent(t)},i=/constructor/i.test(e.HTMLElement)||e.safari,f=/CriOS\/[\d]+/.test(navigator.userAgent),u=function(t){(e.setImmediate||e.setTimeout)(function(){throw t},0)},s="application/octet-stream",d=1e3*40,c=function(e){var t=function(){if(typeof e==="string"){n().revokeObjectURL(e)}else{e.remove()}};setTimeout(t,d)},l=function(e,t,n){t=[].concat(t);var r=t.length;while(r--){var o=e["on"+t[r]];if(typeof o==="function"){try{o.call(e,n||e)}catch(a){u(a)}}}},p=function(e){if(/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(e.type)){return new Blob([String.fromCharCode(65279),e],{type:e.type})}return e},v=function(t,u,d){if(!d){t=p(t)}var v=this,w=t.type,m=w===s,y,h=function(){l(v,"writestart progress write writeend".split(" "))},S=function(){if((f||m&&i)&&e.FileReader){var r=new FileReader;r.onloadend=function(){var t=f?r.result:r.result.replace(/^data:[^;]*;/,"data:attachment/file;");var n=e.open(t,"_blank");if(!n)e.location.href=t;t=undefined;v.readyState=v.DONE;h()};r.readAsDataURL(t);v.readyState=v.INIT;return}if(!y){y=n().createObjectURL(t)}if(m){e.location.href=y}else{var o=e.open(y,"_blank");if(!o){e.location.href=y}}v.readyState=v.DONE;h();c(y)};v.readyState=v.INIT;if(o){y=n().createObjectURL(t);setTimeout(function(){r.href=y;r.download=u;a(r);h();c(y);v.readyState=v.DONE});return}S()},w=v.prototype,m=function(e,t,n){return new v(e,t||e.name||"download",n)};if(typeof navigator!=="undefined"&&navigator.msSaveOrOpenBlob){return function(e,t,n){t=t||e.name||"download";if(!n){e=p(e)}return navigator.msSaveOrOpenBlob(e,t)}}w.abort=function(){};w.readyState=w.INIT=0;w.WRITING=1;w.DONE=2;w.error=w.onwritestart=w.onprogress=w.onwrite=w.onabort=w.onerror=w.onwriteend=null;return m}(typeof self!=="undefined"&&self||typeof window!=="undefined"&&window||this.content);if(typeof module!=="undefined"&&module.exports){module.exports.saveAs=saveAs}else if(typeof define!=="undefined"&&define!==null&&define.amd!==null){define("FileSaver.js",function(){return saveAs})} diff --git a/web/js/akkordion.min.js b/web/js/akkordion.min.js new file mode 100644 index 000000000..5df50b597 --- /dev/null +++ b/web/js/akkordion.min.js @@ -0,0 +1,368 @@ +/*! + * akkordion 0.2.5 + * Accordion UI Element + * https://github.com/TrySound/akkordion + * + * Released under the MIT license + * Copyright (c) 2015, Bogdan Chadkin + */ + +;(function (module) { + + window.akkordion = module(window, document) + +} (function (window, document, undefined) { + + + var defaults = { + single: true, + speed: 350, + hover: false + }, callbacks = { + 'init': [], + 'beforeopen': [], + 'open': [], + 'afteropen': [], + 'beforeclose': [], + 'close': [], + 'afterclose': [] + }, PLUGIN_NAME = 'akkordion'; + + + var transition = false, + transitionEnd = false, + dataActive = 'active', + dataAnim = 'animating', + dataIndex = 'index', + dataInit = 'initialized'; + + + (function () { + var el = document.createElement("div"); + + if(el.style.transition !== undefined) { + transition = 'transition'; + transitionEnd = 'transitionend'; + } + } ()); + + + + function bind(el, options) { + var self = this; + self.root = el; + self.options = extend({}, options, getDataAttrs(el)); + self.cache(); + self.bindEvents(); + trigger('init', self); + }; + + bind.prototype = { + cache: function () { + var self = this, + root = self.root, + children = root.children, + empty = document.createElement('div'), + titleSet = [], + contentSet = [], + outerSet = [], + classList, i, title, content, outer; + + self.titleSet = titleSet; + self.outerSet = outerSet; + self.contentSet = contentSet; + + empty.className = PLUGIN_NAME + '-outer'; + for(i = children.length - 1; i > -1; i--) { + title = children[i]; + + if(title.className.split(' ').indexOf(PLUGIN_NAME + '-title') > -1) { + classList = (content = title.nextElementSibling).className.split(' '); + if(classList.indexOf(PLUGIN_NAME + '-content') > -1) { + titleSet.unshift(title); + contentSet.unshift(content); + outerSet.unshift(outer = empty.cloneNode()); + + outer.appendChild(root.replaceChild(outer, content)); + // Default state + content.style.height = 'auto'; + if(classList.indexOf(PLUGIN_NAME + '-active') > -1) { + setActive(self, 0, true); + outer.style.height = 'auto'; + } + } + } + } + }, + + bindEvents: function () { + var self = this, + root = self.root, + hover = self.options.hover, + mouseInst; + + if(hover !== false) { + on(root, 'mouseover', function (e) { + mouseInst = setTimeout(function () { + push(e); + }, hover); + }); + + on(root, 'mouseout', function (e) { + clearTimeout(mouseInst); + }); + } + + on(root, 'click', push); + + function push (e) { + var titleSet = self.titleSet, + el = e.target, + title = el, + index; + + while(root !== title) { + if((index = titleSet.indexOf(title)) > -1 || title === null) { + break; + } + title = title.parentNode; + } + + if(index > -1) { + if(attr(title, dataActive)) { + self.close(index); + } else { + self.open(index); + } + + e.preventDefault(); + } + } + + on(root, transitionEnd, function (e) { + var el = e.target, + index; + + if(e.propertyName === 'height' && (index = self.outerSet.indexOf(el)) > -1) { + attr(el, dataAnim, null); + if(attr(el, dataActive)) { + el.style.cssText = 'height:auto;'; + trigger('afteropen', self, index); + } else { + el.style.cssText = ''; + trigger('afterclose', self, index); + } + + } + }); + }, + + open: function (index, noAnim) { + var self = this, + outerSet = self.outerSet, + options = self.options, + speed = options.speed, + height, i, outer; + + index = index === -1 ? outerSet.length - 1 : index; + outer = outerSet[index]; + + if(options.single) { + for(i = outerSet.length - 1; i > -1; i--) if(i !== index) { + self.close(i, noAnim); + } + } + + if(outer && ! attr(outer, dataAnim) && ! attr(outer, dataActive) && trigger('beforeopen', self, index)) { + setActive(self, index, true); + trigger('open', self, index); + + if( ! transition || noAnim || speed === 0) { + outer.style.cssText = 'height:auto;'; + trigger('afteropen', self, index); + } else { + outer.style.height = 'auto'; + height = outer.offsetHeight; + if(height !== 0) { + attr(outer, dataAnim, true); + outer.style.height = 0; + outer.offsetWidth; + outer.style.cssText = 'height:' + height + 'px;' + transition + '-duration:' + speed + 'ms;'; + } + + } + + return true; + } + }, + + close: function (index, noAnim) { + var self = this, + outerSet = self.outerSet, + speed = self.options.speed; + + index = index === -1 ? outerSet.length - 1 : index; + outer = outerSet[index]; + + if(outer && ! attr(outer, dataAnim) && attr(outer, dataActive) && trigger('beforeclose', self, index)) { + setActive(self, index, false); + trigger('close', self, index); + + if( ! transition || noAnim || speed === 0) { + outer.style.cssText = ''; + trigger('afterclose', self, index); + } else { + attr(outer, dataAnim, true); + outer.style.height = outer.offsetHeight + 'px'; + outer.offsetWidth; + outer.style.cssText = transition + '-duration:' + speed + 'ms;'; + } + + return true; + } + } + } + + + + var registry = []; + + /* Initialize */ + function akkordion(elements, options) { + var options = extend({}, defaults, options), + el; + + if(typeof elements === 'string') { + elements = document.querySelectorAll(elements); + } + + + for(i = 0, max = elements.length; i < max; i++) { + el = elements[i]; + if( ! attr(el, dataInit)) { + attr(el, dataInit, true); + registry.push(new bind(el, options)); + } + } + } + + + akkordion.on = function (event, cb) { + var collection = callbacks[(event = event.toLowerCase())]; + + if(collection && typeof cb === 'function') { + collection.push(cb); + } + + return akkordion; + }; + + akkordion.open = function (root, index, noanim) { + action(root, index, noanim, 'open'); + }; + + akkordion.close = function (root, index, noanim) { + action(root, index, noanim, 'close'); + }; + + function action(root, index, noanim, method) { + var inst, next; + + if(root) { + for(i = registry.length - 1; i > -1; i--) if(registry[i].root === root) { + inst = registry[i]; + + if( ! Number.isInteger(index)) { + if(next = inst.titleSet.indexOf(index) > -1) { + index = next; + } else if(next = inst.contentSet.indexOf(index) > -1) { + index = next; + } + } + + return !! inst[method](Number(index), noanim); + } + } + } + + + on(document, 'DOMContentLoaded', function () { + akkordion('.' + PLUGIN_NAME); + }); + + + + return akkordion; + + + function trigger(event, inst, index) { + var collection = callbacks[event], + root = inst.root, + title = inst.titleSet[index], + content = inst.contentSet[index], + result = true, + i, max; + + for(i = 0, max = collection.length; i < max; i++) { + result = collection[i].call(root, title, content) === false ? false : result; + } + + return result; + } + + function setActive(inst, index, state) { + state = state ? true : null; + attr(inst.titleSet[index], dataActive, state); + attr(inst.outerSet[index], dataActive, state); + attr(inst.contentSet[index], dataActive, state); + } + + + function attr(el, name, val) { + name = 'data-' + PLUGIN_NAME + '-' + name; + return val === undefined ? el.hasAttribute(name) : + val === null ? el.removeAttribute(name) : el.setAttribute(name, val); + } + + function on(el, event, cb) { + el.addEventListener(event, cb, false); + } + + function extend() { + var result = arguments[0] || {}; + var i, max, options, key; + + for (i = 1, max = arguments.length; i < max; i++) { + options = arguments[i]; + if (options != null) { + for (key in options) if(options.hasOwnProperty(key) && options[key] !== undefined) { + result[key] = options[key]; + } + } + } + + return result; + } + + function getDataAttrs(el) { + var attrs = el.attributes, + prefix = 'data-' + PLUGIN_NAME + '-', + i, name, val, + result = {}; + + for(i = attrs.length; i--; ) { + name = attrs[i].name; + val = attrs[i].value; + if(name.indexOf(prefix) === 0) { + result[name.substring(prefix.length)] = + val === 'true' ? true : + val === 'false' ? false : + isNaN(val) ? val : Number(val); + } + } + + return result; + } + + +})); diff --git a/web/js/circular-json.js b/web/js/circular-json.js new file mode 100644 index 000000000..f675c012e --- /dev/null +++ b/web/js/circular-json.js @@ -0,0 +1,2 @@ +/*! (C) WebReflection Mit Style License */ +var CircularJSON=function(JSON,RegExp){var specialChar="~",safeSpecialChar="\\x"+("0"+specialChar.charCodeAt(0).toString(16)).slice(-2),escapedSafeSpecialChar="\\"+safeSpecialChar,specialCharRG=new RegExp(safeSpecialChar,"g"),safeSpecialCharRG=new RegExp(escapedSafeSpecialChar,"g"),safeStartWithSpecialCharRG=new RegExp("(?:^|([^\\\\]))"+escapedSafeSpecialChar),indexOf=[].indexOf||function(v){for(var i=this.length;i--&&this[i]!==v;);return i},$String=String;function generateReplacer(value,replacer,resolve){var inspect=!!replacer,path=[],all=[value],seen=[value],mapp=[resolve?specialChar:"[Circular]"],last=value,lvl=1,i,fn;if(inspect){fn=typeof replacer==="object"?function(key,value){return key!==""&&replacer.indexOf(key)<0?void 0:value}:replacer}return function(key,value){if(inspect)value=fn.call(this,key,value);if(key!==""){if(last!==this){i=lvl-indexOf.call(all,this)-1;lvl-=i;all.splice(lvl,all.length);path.splice(lvl-1,path.length);last=this}if(typeof value==="object"&&value){if(indexOf.call(all,value)<0){all.push(last=value)}lvl=all.length;i=indexOf.call(seen,value);if(i<0){i=seen.push(value)-1;if(resolve){path.push((""+key).replace(specialCharRG,safeSpecialChar));mapp[i]=specialChar+path.join(specialChar)}else{mapp[i]=mapp[0]}}else{value=mapp[i]}}else{if(typeof value==="string"&&resolve){value=value.replace(safeSpecialChar,escapedSafeSpecialChar).replace(specialChar,safeSpecialChar)}}}return value}}function retrieveFromPath(current,keys){for(var i=0,length=keys.length;i -1) { + e.preventDefault(); + } +}, false); + +$(window).on('load', function(){ + NProgress.set(0.1); + akkordion(".akkordion", {}); + + $.when( + $.getJSON("./data.json"), + $.getJSON("./style.json") + ).done(function(datafile, stylefile) { + loadCytoscape({ + wheelSensitivity: 0.1, + container: document.getElementById('cy'), + elements: datafile[0], + layout: { + name: 'cose-bilkent', + nodeDimensionsIncludeLabels: true, + tilingPaddingVertical: 10, + tilingPaddingHorizontal: 100 + }, + style: stylefile[0] + }); + }); +}); // Page loaded + + +function loadCytoscape(options) { + NProgress.set(0.2); + // Perform the layout + var cy = window.cy = cytoscape(options); + NProgress.set(0.9); + + // Snap to grid + cy.gridGuide({ + drawGrid: false, + gridSpacing: 20, + }); + + // Add ability to undo moves + var ur = cy.undoRedo(); + + // Add ability to expand and collapse nodes + cy.expandCollapse({ + layoutBy: { + name: "cose-bilkent", + animate: "end", + randomize: true, + fit: true, + animationDuration: 1000, + }, + fisheye: true, + animate: true + }); + + // Add pan and zoom UI control + cy.panzoom({ + panSpeed: 5, + zoomDelay: 30, + }); + + // Bird's eye navigator + cy.navigator({}); + + // Pan when dragging off-screen + cy.autopanOnDrag({}); + + // Add ability to hide nodes and see neighbors + var api = cy.viewUtilities({ + neighbor: function(node){ + return node.closedNeighborhood(); + }, + neighborSelectTime: 1000, + edge: { + highlighted: { // Styles for when edges are unhighlighted. + "width": 5, + "color": "#000", + "opacity": 1 + }, + unhighlighted: { // Styles for when edges are unhighlighted. + 'opacity': 0.1 + } + }, + node: { + unhighlighted: { // Styles for when nodes are unhighlighted. + 'opacity': 0.3 + } + } + }); + + // Increase border width to show nodes with hidden neighbors + function thickenBorder(eles){ + eles.forEach(function( ele ){ + ele.toggleClass("hiddenNeighbors", true); + }); + eles.data("thickBorder", true); + return eles; + } + // Decrease border width when hidden neighbors of the nodes become visible + function thinBorder(eles){ + eles.forEach(function( ele ){ + ele.toggleClass("hiddenNeighbors", false); + }); + eles.removeData("thickBorder"); + return eles; + } + + ur.action("thickenBorder", thickenBorder, thinBorder); + ur.action("thinBorder", thinBorder, thickenBorder); + + // Collapse selected nodes + document.getElementById("collapseRecursively").addEventListener("click", function () { + ur.do("collapseRecursively", { + nodes: cy.$(":selected") + }); + }); + + // Expand selected nodes + document.getElementById("expandRecursively").addEventListener("click", function () { + ur.do("expandRecursively", { + nodes: cy.$(":selected") + }); + }); + + // Collapse all + document.getElementById("collapseAll").addEventListener("click", function () { + ur.do("collapseAll"); + }); + + // Expand all + document.getElementById("expandAll").addEventListener("click", function () { + ur.do("expandAll"); + }); + + + // Save image + document.getElementById("saveImage").addEventListener("click", function () { + var png = cy.png( { + output: 'blob', + full: true + }); + saveAs(png, "CloudMapper.png"); + }); + + // Export layout + document.getElementById("exportLayout").addEventListener("click", function () { + blob = new Blob([CircularJSON.stringify(cy.json())], {type: "text/plain;charset=utf-8"}); + saveAs(blob, "layout.json"); + }); + + // Import layout + document.getElementById("importLayout").addEventListener("click", function () { + //cy.json( cyJson ); + }); + + // Randomize layout + function randomizeLayout() { + var layout = cy.layout({ + name: 'cose-bilkent', + animate: 'end', + animationEasing: 'ease-out', + animationDuration: 2000, + randomize: true + }); + layout.run(); + } + document.getElementById("randomizeLayout").addEventListener("click", function(){ + randomizeLayout(); + }); + + //In below functions, finding the nodes to hide/show are sample specific. + //If the sample graph changes, those calculations may also need a change. + + $("#hide").click(function (){ + hideSelectedNodes(); + }); + + $("#showAll").click(function () { + var actions = []; + var nodesWithHiddenNeighbor = cy.nodes("[thickBorder]"); + actions.push({name: "thinBorder", param: nodesWithHiddenNeighbor}); + actions.push({name: "show", param: cy.elements()}); + ur.do("batch", actions); + }); + + + $("#showHiddenNeighbors").click(function () { + // Not used, as you can double-click on a node to see this. + var hiddenEles = cy.$(":selected").neighborhood().filter(':hidden'); + var actions = []; + var nodesWithHiddenNeighbor = (hiddenEles.neighborhood(":visible").nodes("[thickBorder]")) + .difference(cy.edges(":hidden").difference(hiddenEles.edges().union(hiddenEles.nodes().connectedEdges())).connectedNodes()); + actions.push({name: "thinBorder", param: nodesWithHiddenNeighbor}); + actions.push({name: "show", param: hiddenEles.union(hiddenEles.parent())}); + nodesWithHiddenNeighbor = hiddenEles.nodes().edgesWith(cy.nodes(":hidden").difference(hiddenEles.nodes())) + .connectedNodes().intersection(hiddenEles.nodes()); + actions.push({name: "thickenBorder", param: nodesWithHiddenNeighbor}); + cy.undoRedo().do("batch", actions); + }); + + + // Double-tapping a node makes it's hidden neighbors reappear + var tappedBefore; + cy.on('tap', 'node', function (event) { + var node = this; + + var tappedNow = node; + setTimeout(function () { + tappedBefore = null; + }, 300); + if (tappedBefore && tappedBefore.id() === tappedNow.id()) { + tappedNow.trigger('doubleTap'); + tappedBefore = null; + } else { + tappedBefore = tappedNow; + } + }); + cy.on('doubleTap', 'node', function (event) { + var hiddenEles = cy.$(":selected").neighborhood().filter(':hidden'); + var actions = []; + var nodesWithHiddenNeighbor = (hiddenEles.neighborhood(":visible").nodes("[thickBorder]")) + .difference(cy.edges(":hidden").difference(hiddenEles.edges().union(hiddenEles.nodes().connectedEdges())).connectedNodes()); + actions.push({name: "thinBorder", param: nodesWithHiddenNeighbor}); + actions.push({name: "show", param: hiddenEles.union(hiddenEles.parent())}); + nodesWithHiddenNeighbor = hiddenEles.nodes().edgesWith(cy.nodes(":hidden").difference(hiddenEles.nodes())) + .connectedNodes().intersection(hiddenEles.nodes()); + actions.push({name: "thickenBorder", param: nodesWithHiddenNeighbor}); + cy.undoRedo().do("batch", actions); + }); + + var highlight = false; + $("#highlightNeighbors").click(function () { + highlight = true; + if(cy.$(":selected").length > 0) + ur.do("highlightNeighbors", cy.$(":selected")); + }); + + $("#removeHighlights").click(function () { + highlight = false; + ur.do("removeHighlights"); + }); + + $("#search").click(function () { + var text = $("#toSearch").val(); + cy.elements().search(text).highlightNeighbors(); + }); + + // Undo redo + document.addEventListener("keydown", function (e) { + if (e.ctrlKey){ + if (e.which === 90) + ur.undo(); + else if (e.which === 89) + ur.redo(); + } + }); + + // Provide viewing area for when a node is clicked on + var ni = cy.ni = cy.nodeInfo(); + + // Do something when a node is clicked on + cy.nodes().on('tap', function( e ){ + // This function is just to get us to directtap + var eventIsDirect = e.target.same( this ); // don't use 2.x cyTarget + + if( eventIsDirect ){ + this.emit('directtap'); + } + }).on('directtap', function( e ){ + // A node has been click on + ni.describe(this); + + e.stopPropagation(); + }); + + // Do something when an edge is clicked on + cy.edges().on('tap', function( e ){ + // This function is just to get us to directtap + var eventIsDirect = e.target.same( this ); // don't use 2.x cyTarget + + if( eventIsDirect ){ + this.emit('directtap'); + } + }).on('directtap', function( e ){ + // An edge has been click on + ni.describe(this); + + e.stopPropagation(); + }); + + // + // Handle hotkeys + // + + // Pan + Mousetrap.bind('left', function(e) { cy.panBy({x: 10, y:0}); return false; }); + Mousetrap.bind('right', function(e) { cy.panBy({x: -10, y:0}); return false; }); + Mousetrap.bind('up', function(e) { cy.panBy({x: 0, y:10}); return false; }); + Mousetrap.bind('down', function(e) { cy.panBy({x: 0, y:-10}); return false; }); + + // Zoom + Mousetrap.bind(['-', '_'], function() { + cy.zoom( { + level: cy.zoom()*0.9, + renderedPosition: { x: cy.width()/2, y: cy.height()/2 } + }); + }); + Mousetrap.bind(['=', '+'], function() { + cy.zoom( { + level: cy.zoom()*1.2, + renderedPosition: { x: cy.width()/2, y: cy.height()/2 } + }); + }); + + // Collapse selected nodes + Mousetrap.bind('c', function() { + ur.do("collapseRecursively", { + nodes: cy.$(":selected") + }); + }); + + // Expand selected nodes + Mousetrap.bind('e', function() { + ur.do("expandRecursively", { + nodes: cy.$(":selected") + }); + }); + + // Randomize layout + Mousetrap.bind('r', function() { + randomizeLayout(); + }); + + // Highlight neighbors + Mousetrap.bind('h', function() { + if (!highlight) { + highlight = true; + if(cy.$(":selected").length > 0) + ur.do("highlightNeighbors", cy.$(":selected")); + } else { + highlight = false; + ur.do("removeHighlights"); + } + }); + + // Delete + Mousetrap.bind('d', function() { + hideSelectedNodes(); + }); + + // App has finished loading + NProgress.done(); +} + +function hideSelectedNodes() { + var actions = []; + var nodesToHide = cy.$(":selected").add(cy.$(":selected").nodes().descendants()); + var nodesWithHiddenNeighbor = cy.edges(":hidden").connectedNodes().intersection(nodesToHide); + actions.push({name: "thinBorder", param: nodesWithHiddenNeighbor}); + actions.push({name: "hide", param: nodesToHide}); + nodesWithHiddenNeighbor = nodesToHide.neighborhood(":visible") + .nodes().difference(nodesToHide).difference(cy.nodes("[thickBorder]")); + actions.push({name: "thickenBorder", param: nodesWithHiddenNeighbor}); + cy.undoRedo().do("batch", actions); +} + + + +function importLayout() { + var f = document.getElementById("fileUpload").files[0]; + var reader = new FileReader(); + reader.readAsText(f, "UTF-8"); + reader.onload = function(evt) { + var fileString = evt.target.result; + //console.log(fileString); + options = JSON.parse(fileString); + options.container = document.getElementById('cy'); + options.layout = {name: 'preset'}; + loadCytoscape(options); + }; +} \ No newline at end of file diff --git a/web/js/cytoscape-autopan-on-drag.js b/web/js/cytoscape-autopan-on-drag.js new file mode 100644 index 000000000..be336d120 --- /dev/null +++ b/web/js/cytoscape-autopan-on-drag.js @@ -0,0 +1,170 @@ +;(function(){ 'use strict'; + + // registers the extension on a cytoscape lib ref + var register = function( cytoscape ){ + + if( !cytoscape ){ return; } // can't register if cytoscape unspecified + + var cy; + var currentNode; + var tapstartFcn, tapdragFcn, tapendFcn; + + // Default options + var defaults = { + enabled: true, // Whether the extension is enabled on register + selector: 'node', // Which elements will be affected by this extension + speed: 1 // Speed of panning when elements exceed canvas bounds + }; + + var options; + + // Merge default options with the ones coming from parameter + function extend(defaults, options) { + var obj = {}; + + for (var i in defaults) { + obj[i] = defaults[i]; + } + + for (var i in options) { + obj[i] = options[i]; + } + + return obj; + }; + + function bindCyEvents() { + + cy.on('tapstart', options.selector, tapstartFcn = function() { + var node = this; + + var renderedPosition = node.renderedPosition(); + var renderedWidth = node.renderedWidth(); + var renderedHeight = node.renderedHeight(); + + var maxRenderedX = $(cy.container()).width(); + var maxRenderedY = $(cy.container()).height(); + + var topLeftRenderedPosition = { + x: renderedPosition.x - renderedWidth / 2, + y: renderedPosition.y - renderedHeight / 2 + }; + + var bottomRightRenderedPosition = { + x: renderedPosition.x + renderedWidth / 2, + y: renderedPosition.y + renderedHeight / 2 + }; + + var exceed = false; + + if( ( bottomRightRenderedPosition.x >= maxRenderedX ) || ( topLeftRenderedPosition.x <= 0 ) + || ( bottomRightRenderedPosition.y >= maxRenderedY ) || ( topLeftRenderedPosition.y <= 0 ) ){ + exceed = true; + } + + if( !exceed ) { + currentNode = node; + } + + }); + + cy.on('tapdrag', tapdragFcn = function() { + if(currentNode === undefined) { + return; + } + + var newRenderedPosition = currentNode.renderedPosition(); + var renderedWidth = currentNode.renderedWidth(); + var renderedHeight = currentNode.renderedHeight(); + + var maxRenderedX = $(cy.container()).width(); + var maxRenderedY = $(cy.container()).height(); + + var topLeftRenderedPosition = { + x: newRenderedPosition.x - renderedWidth / 2, + y: newRenderedPosition.y - renderedHeight / 2 + }; + + var bottomRightRenderedPosition = { + x: newRenderedPosition.x + renderedWidth / 2, + y: newRenderedPosition.y + renderedHeight / 2 + }; + + var exceedX; + var exceedY; + + if(bottomRightRenderedPosition.x >= maxRenderedX) { + exceedX = -bottomRightRenderedPosition.x + maxRenderedX; + } + + if(topLeftRenderedPosition.x <= 0) { + exceedX = -topLeftRenderedPosition.x; + } + + if(bottomRightRenderedPosition.y >= maxRenderedY ) { + exceedY = -bottomRightRenderedPosition.y + maxRenderedY; + } + + if(topLeftRenderedPosition.y <= 0) { + exceedY = -topLeftRenderedPosition.y; + } + + if(exceedX) { + cy.panBy({x: exceedX * options.speed}); + } + + if(exceedY) { + cy.panBy({y: exceedY * options.speed}); + } + }); + + cy.on('tapend', tapendFcn = function() { + currentNode = undefined; + }); + } + + function unbindCyEvents() { + cy.off('tapstart', options.selector, tapstartFcn); + cy.off('tapdrag', tapdragFcn); + cy.off('tapend', tapendFcn); + } + + cytoscape( 'core', 'autopanOnDrag', function(opts){ + cy = this; + + if(opts !== 'get') { + // merge the options with default ones + options = extend(defaults, opts); + + if(options.enabled) { + bindCyEvents(); + } + } + + return { + enable: function() { + bindCyEvents(); + }, + disable: function() { + unbindCyEvents(); + } + }; + } ); + + }; + + if( typeof module !== 'undefined' && module.exports ){ // expose as a commonjs module + module.exports = register; + } + + if( typeof define !== 'undefined' && define.amd ){ // expose as an amd/requirejs module + define('cytoscape-context-menus', function(){ + return register; + }); + } + + if( typeof cytoscape !== 'undefined' ){ // expose to global cytoscape (i.e. window.cytoscape) + register( cytoscape ); + } + +})(); \ No newline at end of file diff --git a/web/js/cytoscape-cose-bilkent.js b/web/js/cytoscape-cose-bilkent.js new file mode 100644 index 000000000..64871fc54 --- /dev/null +++ b/web/js/cytoscape-cose-bilkent.js @@ -0,0 +1,5413 @@ +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.cytoscapeCoseBilkent = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 0) { + this.positionNodesRadially(forest); + } + // The graph associated with this layout is not flat or a forest + else { + // Reduce the trees when incremental mode is not enabled and graph is not a forest + this.reduceTrees(); + // Update nodes that gravity will be applied + this.graphManager.resetAllNodesToApplyGravitation(); + var allNodes = new Set(this.getAllNodes()); + var intersection = this.nodesWithGravity.filter(function (x) { + return allNodes.has(x); + }); + this.graphManager.setAllNodesToApplyGravitation(intersection); + + this.positionNodesRandomly(); + } + } + + this.initSpringEmbedder(); + this.runSpringEmbedder(); + + return true; +}; + +CoSELayout.prototype.tick = function () { + this.totalIterations++; + + if (this.totalIterations === this.maxIterations && !this.isTreeGrowing && !this.isGrowthFinished) { + if (this.prunedNodesAll.length > 0) { + this.isTreeGrowing = true; + } else { + return true; + } + } + + if (this.totalIterations % FDLayoutConstants.CONVERGENCE_CHECK_PERIOD == 0 && !this.isTreeGrowing && !this.isGrowthFinished) { + if (this.isConverged()) { + if (this.prunedNodesAll.length > 0) { + this.isTreeGrowing = true; + } else { + return true; + } + } + + this.coolingFactor = this.initialCoolingFactor * ((this.maxIterations - this.totalIterations) / this.maxIterations); + this.animationPeriod = Math.ceil(this.initialAnimationPeriod * Math.sqrt(this.coolingFactor)); + } + // Operations while tree is growing again + if (this.isTreeGrowing) { + if (this.growTreeIterations % 10 == 0) { + if (this.prunedNodesAll.length > 0) { + this.graphManager.updateBounds(); + this.updateGrid(); + this.growTree(this.prunedNodesAll); + // Update nodes that gravity will be applied + this.graphManager.resetAllNodesToApplyGravitation(); + var allNodes = new Set(this.getAllNodes()); + var intersection = this.nodesWithGravity.filter(function (x) { + return allNodes.has(x); + }); + this.graphManager.setAllNodesToApplyGravitation(intersection); + + this.graphManager.updateBounds(); + this.updateGrid(); + this.coolingFactor = FDLayoutConstants.DEFAULT_COOLING_FACTOR_INCREMENTAL; + } else { + this.isTreeGrowing = false; + this.isGrowthFinished = true; + } + } + this.growTreeIterations++; + } + // Operations after growth is finished + if (this.isGrowthFinished) { + if (this.isConverged()) { + return true; + } + if (this.afterGrowthIterations % 10 == 0) { + this.graphManager.updateBounds(); + this.updateGrid(); + } + this.coolingFactor = FDLayoutConstants.DEFAULT_COOLING_FACTOR_INCREMENTAL * ((100 - this.afterGrowthIterations) / 100); + this.afterGrowthIterations++; + } + + this.totalDisplacement = 0; + this.graphManager.updateBounds(); + this.calcSpringForces(); + this.calcRepulsionForces(); + this.calcGravitationalForces(); + this.moveNodes(); + this.animate(); + + return false; // Layout is not ended yet return false +}; + +CoSELayout.prototype.getPositionsData = function () { + var allNodes = this.graphManager.getAllNodes(); + var pData = {}; + for (var i = 0; i < allNodes.length; i++) { + var rect = allNodes[i].rect; + var id = allNodes[i].id; + pData[id] = { + id: id, + x: rect.getCenterX(), + y: rect.getCenterY(), + w: rect.width, + h: rect.height + }; + } + + return pData; +}; + +CoSELayout.prototype.runSpringEmbedder = function () { + this.initialAnimationPeriod = 25; + this.animationPeriod = this.initialAnimationPeriod; + var layoutEnded = false; + + // If aminate option is 'during' signal that layout is supposed to start iterating + if (FDLayoutConstants.ANIMATE === 'during') { + this.emit('layoutstarted'); + } else { + // If aminate option is 'during' tick() function will be called on index.js + while (!layoutEnded) { + layoutEnded = this.tick(); + } + + this.graphManager.updateBounds(); + } +}; + +CoSELayout.prototype.calculateNodesToApplyGravitationTo = function () { + var nodeList = []; + var graph; + + var graphs = this.graphManager.getGraphs(); + var size = graphs.length; + var i; + for (i = 0; i < size; i++) { + graph = graphs[i]; + + graph.updateConnected(); + + if (!graph.isConnected) { + nodeList = nodeList.concat(graph.getNodes()); + } + } + + return nodeList; +}; + +CoSELayout.prototype.calcNoOfChildrenForAllNodes = function () { + var node; + var allNodes = this.graphManager.getAllNodes(); + + for (var i = 0; i < allNodes.length; i++) { + node = allNodes[i]; + node.noOfChildren = node.getNoOfChildren(); + } +}; + +CoSELayout.prototype.createBendpoints = function () { + var edges = []; + edges = edges.concat(this.graphManager.getAllEdges()); + var visited = new HashSet(); + var i; + for (i = 0; i < edges.length; i++) { + var edge = edges[i]; + + if (!visited.contains(edge)) { + var source = edge.getSource(); + var target = edge.getTarget(); + + if (source == target) { + edge.getBendpoints().push(new PointD()); + edge.getBendpoints().push(new PointD()); + this.createDummyNodesForBendpoints(edge); + visited.add(edge); + } else { + var edgeList = []; + + edgeList = edgeList.concat(source.getEdgeListToNode(target)); + edgeList = edgeList.concat(target.getEdgeListToNode(source)); + + if (!visited.contains(edgeList[0])) { + if (edgeList.length > 1) { + var k; + for (k = 0; k < edgeList.length; k++) { + var multiEdge = edgeList[k]; + multiEdge.getBendpoints().push(new PointD()); + this.createDummyNodesForBendpoints(multiEdge); + } + } + visited.addAll(list); + } + } + } + + if (visited.size() == edges.length) { + break; + } + } +}; + +CoSELayout.prototype.positionNodesRadially = function (forest) { + // We tile the trees to a grid row by row; first tree starts at (0,0) + var currentStartingPoint = new Point(0, 0); + var numberOfColumns = Math.ceil(Math.sqrt(forest.length)); + var height = 0; + var currentY = 0; + var currentX = 0; + var point = new PointD(0, 0); + + for (var i = 0; i < forest.length; i++) { + if (i % numberOfColumns == 0) { + // Start of a new row, make the x coordinate 0, increment the + // y coordinate with the max height of the previous row + currentX = 0; + currentY = height; + + if (i != 0) { + currentY += CoSEConstants.DEFAULT_COMPONENT_SEPERATION; + } + + height = 0; + } + + var tree = forest[i]; + + // Find the center of the tree + var centerNode = Layout.findCenterOfTree(tree); + + // Set the staring point of the next tree + currentStartingPoint.x = currentX; + currentStartingPoint.y = currentY; + + // Do a radial layout starting with the center + point = CoSELayout.radialLayout(tree, centerNode, currentStartingPoint); + + if (point.y > height) { + height = Math.floor(point.y); + } + + currentX = Math.floor(point.x + CoSEConstants.DEFAULT_COMPONENT_SEPERATION); + } + + this.transform(new PointD(LayoutConstants.WORLD_CENTER_X - point.x / 2, LayoutConstants.WORLD_CENTER_Y - point.y / 2)); +}; + +CoSELayout.radialLayout = function (tree, centerNode, startingPoint) { + var radialSep = Math.max(this.maxDiagonalInTree(tree), CoSEConstants.DEFAULT_RADIAL_SEPARATION); + CoSELayout.branchRadialLayout(centerNode, null, 0, 359, 0, radialSep); + var bounds = LGraph.calculateBounds(tree); + + var transform = new Transform(); + transform.setDeviceOrgX(bounds.getMinX()); + transform.setDeviceOrgY(bounds.getMinY()); + transform.setWorldOrgX(startingPoint.x); + transform.setWorldOrgY(startingPoint.y); + + for (var i = 0; i < tree.length; i++) { + var node = tree[i]; + node.transform(transform); + } + + var bottomRight = new PointD(bounds.getMaxX(), bounds.getMaxY()); + + return transform.inverseTransformPoint(bottomRight); +}; + +CoSELayout.branchRadialLayout = function (node, parentOfNode, startAngle, endAngle, distance, radialSeparation) { + // First, position this node by finding its angle. + var halfInterval = (endAngle - startAngle + 1) / 2; + + if (halfInterval < 0) { + halfInterval += 180; + } + + var nodeAngle = (halfInterval + startAngle) % 360; + var teta = nodeAngle * IGeometry.TWO_PI / 360; + + // Make polar to java cordinate conversion. + var cos_teta = Math.cos(teta); + var x_ = distance * Math.cos(teta); + var y_ = distance * Math.sin(teta); + + node.setCenter(x_, y_); + + // Traverse all neighbors of this node and recursively call this + // function. + var neighborEdges = []; + neighborEdges = neighborEdges.concat(node.getEdges()); + var childCount = neighborEdges.length; + + if (parentOfNode != null) { + childCount--; + } + + var branchCount = 0; + + var incEdgesCount = neighborEdges.length; + var startIndex; + + var edges = node.getEdgesBetween(parentOfNode); + + // If there are multiple edges, prune them until there remains only one + // edge. + while (edges.length > 1) { + //neighborEdges.remove(edges.remove(0)); + var temp = edges[0]; + edges.splice(0, 1); + var index = neighborEdges.indexOf(temp); + if (index >= 0) { + neighborEdges.splice(index, 1); + } + incEdgesCount--; + childCount--; + } + + if (parentOfNode != null) { + //assert edges.length == 1; + startIndex = (neighborEdges.indexOf(edges[0]) + 1) % incEdgesCount; + } else { + startIndex = 0; + } + + var stepAngle = Math.abs(endAngle - startAngle) / childCount; + + for (var i = startIndex; branchCount != childCount; i = ++i % incEdgesCount) { + var currentNeighbor = neighborEdges[i].getOtherEnd(node); + + // Don't back traverse to root node in current tree. + if (currentNeighbor == parentOfNode) { + continue; + } + + var childStartAngle = (startAngle + branchCount * stepAngle) % 360; + var childEndAngle = (childStartAngle + stepAngle) % 360; + + CoSELayout.branchRadialLayout(currentNeighbor, node, childStartAngle, childEndAngle, distance + radialSeparation, radialSeparation); + + branchCount++; + } +}; + +CoSELayout.maxDiagonalInTree = function (tree) { + var maxDiagonal = Integer.MIN_VALUE; + + for (var i = 0; i < tree.length; i++) { + var node = tree[i]; + var diagonal = node.getDiagonal(); + + if (diagonal > maxDiagonal) { + maxDiagonal = diagonal; + } + } + + return maxDiagonal; +}; + +CoSELayout.prototype.calcRepulsionRange = function () { + // formula is 2 x (level + 1) x idealEdgeLength + return 2 * (this.level + 1) * this.idealEdgeLength; +}; + +// Tiling methods + +// Group zero degree members whose parents are not to be tiled, create dummy parents where needed and fill memberGroups by their dummp parent id's +CoSELayout.prototype.groupZeroDegreeMembers = function () { + var self = this; + // array of [parent_id x oneDegreeNode_id] + var tempMemberGroups = {}; // A temporary map of parent node and its zero degree members + this.memberGroups = {}; // A map of dummy parent node and its zero degree members whose parents are not to be tiled + this.idToDummyNode = {}; // A map of id to dummy node + + var zeroDegree = []; // List of zero degree nodes whose parents are not to be tiled + var allNodes = this.graphManager.getAllNodes(); + + // Fill zero degree list + for (var i = 0; i < allNodes.length; i++) { + var node = allNodes[i]; + var parent = node.getParent(); + // If a node has zero degree and its parent is not to be tiled if exists add that node to zeroDegres list + if (this.getNodeDegreeWithChildren(node) === 0 && (parent.id == undefined || !this.getToBeTiled(parent))) { + zeroDegree.push(node); + } + } + + // Create a map of parent node and its zero degree members + for (var i = 0; i < zeroDegree.length; i++) { + var node = zeroDegree[i]; // Zero degree node itself + var p_id = node.getParent().id; // Parent id + + if (typeof tempMemberGroups[p_id] === "undefined") tempMemberGroups[p_id] = []; + + tempMemberGroups[p_id] = tempMemberGroups[p_id].concat(node); // Push node to the list belongs to its parent in tempMemberGroups + } + + // If there are at least two nodes at a level, create a dummy compound for them + Object.keys(tempMemberGroups).forEach(function (p_id) { + if (tempMemberGroups[p_id].length > 1) { + var dummyCompoundId = "DummyCompound_" + p_id; // The id of dummy compound which will be created soon + self.memberGroups[dummyCompoundId] = tempMemberGroups[p_id]; // Add dummy compound to memberGroups + + var parent = tempMemberGroups[p_id][0].getParent(); // The parent of zero degree nodes will be the parent of new dummy compound + + // Create a dummy compound with calculated id + var dummyCompound = new CoSENode(self.graphManager); + dummyCompound.id = dummyCompoundId; + dummyCompound.paddingLeft = parent.paddingLeft || 0; + dummyCompound.paddingRight = parent.paddingRight || 0; + dummyCompound.paddingBottom = parent.paddingBottom || 0; + dummyCompound.paddingTop = parent.paddingTop || 0; + + self.idToDummyNode[dummyCompoundId] = dummyCompound; + + var dummyParentGraph = self.getGraphManager().add(self.newGraph(), dummyCompound); + var parentGraph = parent.getChild(); + + // Add dummy compound to parent the graph + parentGraph.add(dummyCompound); + + // For each zero degree node in this level remove it from its parent graph and add it to the graph of dummy parent + for (var i = 0; i < tempMemberGroups[p_id].length; i++) { + var node = tempMemberGroups[p_id][i]; + + parentGraph.remove(node); + dummyParentGraph.add(node); + } + } + }); +}; + +CoSELayout.prototype.clearCompounds = function () { + var childGraphMap = {}; + var idToNode = {}; + + // Get compound ordering by finding the inner one first + this.performDFSOnCompounds(); + + for (var i = 0; i < this.compoundOrder.length; i++) { + + idToNode[this.compoundOrder[i].id] = this.compoundOrder[i]; + childGraphMap[this.compoundOrder[i].id] = [].concat(this.compoundOrder[i].getChild().getNodes()); + + // Remove children of compounds + this.graphManager.remove(this.compoundOrder[i].getChild()); + this.compoundOrder[i].child = null; + } + + this.graphManager.resetAllNodes(); + + // Tile the removed children + this.tileCompoundMembers(childGraphMap, idToNode); +}; + +CoSELayout.prototype.clearZeroDegreeMembers = function () { + var self = this; + var tiledZeroDegreePack = this.tiledZeroDegreePack = []; + + Object.keys(this.memberGroups).forEach(function (id) { + var compoundNode = self.idToDummyNode[id]; // Get the dummy compound + + tiledZeroDegreePack[id] = self.tileNodes(self.memberGroups[id], compoundNode.paddingLeft + compoundNode.paddingRight); + + // Set the width and height of the dummy compound as calculated + compoundNode.rect.width = tiledZeroDegreePack[id].width; + compoundNode.rect.height = tiledZeroDegreePack[id].height; + }); +}; + +CoSELayout.prototype.repopulateCompounds = function () { + for (var i = this.compoundOrder.length - 1; i >= 0; i--) { + var lCompoundNode = this.compoundOrder[i]; + var id = lCompoundNode.id; + var horizontalMargin = lCompoundNode.paddingLeft; + var verticalMargin = lCompoundNode.paddingTop; + + this.adjustLocations(this.tiledMemberPack[id], lCompoundNode.rect.x, lCompoundNode.rect.y, horizontalMargin, verticalMargin); + } +}; + +CoSELayout.prototype.repopulateZeroDegreeMembers = function () { + var self = this; + var tiledPack = this.tiledZeroDegreePack; + + Object.keys(tiledPack).forEach(function (id) { + var compoundNode = self.idToDummyNode[id]; // Get the dummy compound by its id + var horizontalMargin = compoundNode.paddingLeft; + var verticalMargin = compoundNode.paddingTop; + + // Adjust the positions of nodes wrt its compound + self.adjustLocations(tiledPack[id], compoundNode.rect.x, compoundNode.rect.y, horizontalMargin, verticalMargin); + }); +}; + +CoSELayout.prototype.getToBeTiled = function (node) { + var id = node.id; + //firstly check the previous results + if (this.toBeTiled[id] != null) { + return this.toBeTiled[id]; + } + + //only compound nodes are to be tiled + var childGraph = node.getChild(); + if (childGraph == null) { + this.toBeTiled[id] = false; + return false; + } + + var children = childGraph.getNodes(); // Get the children nodes + + //a compound node is not to be tiled if all of its compound children are not to be tiled + for (var i = 0; i < children.length; i++) { + var theChild = children[i]; + + if (this.getNodeDegree(theChild) > 0) { + this.toBeTiled[id] = false; + return false; + } + + //pass the children not having the compound structure + if (theChild.getChild() == null) { + this.toBeTiled[theChild.id] = false; + continue; + } + + if (!this.getToBeTiled(theChild)) { + this.toBeTiled[id] = false; + return false; + } + } + this.toBeTiled[id] = true; + return true; +}; + +// Get degree of a node depending of its edges and independent of its children +CoSELayout.prototype.getNodeDegree = function (node) { + var id = node.id; + var edges = node.getEdges(); + var degree = 0; + + // For the edges connected + for (var i = 0; i < edges.length; i++) { + var edge = edges[i]; + if (edge.getSource().id !== edge.getTarget().id) { + degree = degree + 1; + } + } + return degree; +}; + +// Get degree of a node with its children +CoSELayout.prototype.getNodeDegreeWithChildren = function (node) { + var degree = this.getNodeDegree(node); + if (node.getChild() == null) { + return degree; + } + var children = node.getChild().getNodes(); + for (var i = 0; i < children.length; i++) { + var child = children[i]; + degree += this.getNodeDegreeWithChildren(child); + } + return degree; +}; + +CoSELayout.prototype.performDFSOnCompounds = function () { + this.compoundOrder = []; + this.fillCompexOrderByDFS(this.graphManager.getRoot().getNodes()); +}; + +CoSELayout.prototype.fillCompexOrderByDFS = function (children) { + for (var i = 0; i < children.length; i++) { + var child = children[i]; + if (child.getChild() != null) { + this.fillCompexOrderByDFS(child.getChild().getNodes()); + } + if (this.getToBeTiled(child)) { + this.compoundOrder.push(child); + } + } +}; + +/** +* This method places each zero degree member wrt given (x,y) coordinates (top left). +*/ +CoSELayout.prototype.adjustLocations = function (organization, x, y, compoundHorizontalMargin, compoundVerticalMargin) { + x += compoundHorizontalMargin; + y += compoundVerticalMargin; + + var left = x; + + for (var i = 0; i < organization.rows.length; i++) { + var row = organization.rows[i]; + x = left; + var maxHeight = 0; + + for (var j = 0; j < row.length; j++) { + var lnode = row[j]; + + lnode.rect.x = x; // + lnode.rect.width / 2; + lnode.rect.y = y; // + lnode.rect.height / 2; + + x += lnode.rect.width + organization.horizontalPadding; + + if (lnode.rect.height > maxHeight) maxHeight = lnode.rect.height; + } + + y += maxHeight + organization.verticalPadding; + } +}; + +CoSELayout.prototype.tileCompoundMembers = function (childGraphMap, idToNode) { + var self = this; + this.tiledMemberPack = []; + + Object.keys(childGraphMap).forEach(function (id) { + // Get the compound node + var compoundNode = idToNode[id]; + + self.tiledMemberPack[id] = self.tileNodes(childGraphMap[id], compoundNode.paddingLeft + compoundNode.paddingRight); + + compoundNode.rect.width = self.tiledMemberPack[id].width + 20; + compoundNode.rect.height = self.tiledMemberPack[id].height + 20; + }); +}; + +CoSELayout.prototype.tileNodes = function (nodes, minWidth) { + var verticalPadding = CoSEConstants.TILING_PADDING_VERTICAL; + var horizontalPadding = CoSEConstants.TILING_PADDING_HORIZONTAL; + var organization = { + rows: [], + rowWidth: [], + rowHeight: [], + width: 20, + height: 20, + verticalPadding: verticalPadding, + horizontalPadding: horizontalPadding + }; + + // Sort the nodes in ascending order of their areas + nodes.sort(function (n1, n2) { + if (n1.rect.width * n1.rect.height > n2.rect.width * n2.rect.height) return -1; + if (n1.rect.width * n1.rect.height < n2.rect.width * n2.rect.height) return 1; + return 0; + }); + + // Create the organization -> tile members + for (var i = 0; i < nodes.length; i++) { + var lNode = nodes[i]; + + if (organization.rows.length == 0) { + this.insertNodeToRow(organization, lNode, 0, minWidth); + } else if (this.canAddHorizontal(organization, lNode.rect.width, lNode.rect.height)) { + this.insertNodeToRow(organization, lNode, this.getShortestRowIndex(organization), minWidth); + } else { + this.insertNodeToRow(organization, lNode, organization.rows.length, minWidth); + } + + this.shiftToLastRow(organization); + } + + return organization; +}; + +CoSELayout.prototype.insertNodeToRow = function (organization, node, rowIndex, minWidth) { + var minCompoundSize = minWidth; + + // Add new row if needed + if (rowIndex == organization.rows.length) { + var secondDimension = []; + + organization.rows.push(secondDimension); + organization.rowWidth.push(minCompoundSize); + organization.rowHeight.push(0); + } + + // Update row width + var w = organization.rowWidth[rowIndex] + node.rect.width; + + if (organization.rows[rowIndex].length > 0) { + w += organization.horizontalPadding; + } + + organization.rowWidth[rowIndex] = w; + // Update compound width + if (organization.width < w) { + organization.width = w; + } + + // Update height + var h = node.rect.height; + if (rowIndex > 0) h += organization.verticalPadding; + + var extraHeight = 0; + if (h > organization.rowHeight[rowIndex]) { + extraHeight = organization.rowHeight[rowIndex]; + organization.rowHeight[rowIndex] = h; + extraHeight = organization.rowHeight[rowIndex] - extraHeight; + } + + organization.height += extraHeight; + + // Insert node + organization.rows[rowIndex].push(node); +}; + +//Scans the rows of an organization and returns the one with the min width +CoSELayout.prototype.getShortestRowIndex = function (organization) { + var r = -1; + var min = Number.MAX_VALUE; + + for (var i = 0; i < organization.rows.length; i++) { + if (organization.rowWidth[i] < min) { + r = i; + min = organization.rowWidth[i]; + } + } + return r; +}; + +//Scans the rows of an organization and returns the one with the max width +CoSELayout.prototype.getLongestRowIndex = function (organization) { + var r = -1; + var max = Number.MIN_VALUE; + + for (var i = 0; i < organization.rows.length; i++) { + + if (organization.rowWidth[i] > max) { + r = i; + max = organization.rowWidth[i]; + } + } + + return r; +}; + +/** +* This method checks whether adding extra width to the organization violates +* the aspect ratio(1) or not. +*/ +CoSELayout.prototype.canAddHorizontal = function (organization, extraWidth, extraHeight) { + + var sri = this.getShortestRowIndex(organization); + + if (sri < 0) { + return true; + } + + var min = organization.rowWidth[sri]; + + if (min + organization.horizontalPadding + extraWidth <= organization.width) return true; + + var hDiff = 0; + + // Adding to an existing row + if (organization.rowHeight[sri] < extraHeight) { + if (sri > 0) hDiff = extraHeight + organization.verticalPadding - organization.rowHeight[sri]; + } + + var add_to_row_ratio; + if (organization.width - min >= extraWidth + organization.horizontalPadding) { + add_to_row_ratio = (organization.height + hDiff) / (min + extraWidth + organization.horizontalPadding); + } else { + add_to_row_ratio = (organization.height + hDiff) / organization.width; + } + + // Adding a new row for this node + hDiff = extraHeight + organization.verticalPadding; + var add_new_row_ratio; + if (organization.width < extraWidth) { + add_new_row_ratio = (organization.height + hDiff) / extraWidth; + } else { + add_new_row_ratio = (organization.height + hDiff) / organization.width; + } + + if (add_new_row_ratio < 1) add_new_row_ratio = 1 / add_new_row_ratio; + + if (add_to_row_ratio < 1) add_to_row_ratio = 1 / add_to_row_ratio; + + return add_to_row_ratio < add_new_row_ratio; +}; + +//If moving the last node from the longest row and adding it to the last +//row makes the bounding box smaller, do it. +CoSELayout.prototype.shiftToLastRow = function (organization) { + var longest = this.getLongestRowIndex(organization); + var last = organization.rowWidth.length - 1; + var row = organization.rows[longest]; + var node = row[row.length - 1]; + + var diff = node.width + organization.horizontalPadding; + + // Check if there is enough space on the last row + if (organization.width - organization.rowWidth[last] > diff && longest != last) { + // Remove the last element of the longest row + row.splice(-1, 1); + + // Push it to the last row + organization.rows[last].push(node); + + organization.rowWidth[longest] = organization.rowWidth[longest] - diff; + organization.rowWidth[last] = organization.rowWidth[last] + diff; + organization.width = organization.rowWidth[instance.getLongestRowIndex(organization)]; + + // Update heights of the organization + var maxHeight = Number.MIN_VALUE; + for (var i = 0; i < row.length; i++) { + if (row[i].height > maxHeight) maxHeight = row[i].height; + } + if (longest > 0) maxHeight += organization.verticalPadding; + + var prevTotal = organization.rowHeight[longest] + organization.rowHeight[last]; + + organization.rowHeight[longest] = maxHeight; + if (organization.rowHeight[last] < node.height + organization.verticalPadding) organization.rowHeight[last] = node.height + organization.verticalPadding; + + var finalTotal = organization.rowHeight[longest] + organization.rowHeight[last]; + organization.height += finalTotal - prevTotal; + + this.shiftToLastRow(organization); + } +}; + +CoSELayout.prototype.tilingPreLayout = function () { + if (CoSEConstants.TILE) { + // Find zero degree nodes and create a compound for each level + this.groupZeroDegreeMembers(); + // Tile and clear children of each compound + this.clearCompounds(); + // Separately tile and clear zero degree nodes for each level + this.clearZeroDegreeMembers(); + } +}; + +CoSELayout.prototype.tilingPostLayout = function () { + if (CoSEConstants.TILE) { + this.repopulateZeroDegreeMembers(); + this.repopulateCompounds(); + } +}; + +module.exports = CoSELayout; + +},{"./CoSEConstants":4,"./CoSEEdge":5,"./CoSEGraph":6,"./CoSEGraphManager":7,"./CoSENode":9,"./FDLayout":12,"./FDLayoutConstants":13,"./IGeometry":18,"./Integer":20,"./LGraph":22,"./Layout":26,"./LayoutConstants":27,"./Point":28,"./PointD":29,"./Transform":32}],9:[function(_dereq_,module,exports){ +'use strict'; + +var FDLayoutNode = _dereq_('./FDLayoutNode'); +var IMath = _dereq_('./IMath'); + +function CoSENode(gm, loc, size, vNode) { + FDLayoutNode.call(this, gm, loc, size, vNode); +} + +CoSENode.prototype = Object.create(FDLayoutNode.prototype); +for (var prop in FDLayoutNode) { + CoSENode[prop] = FDLayoutNode[prop]; +} + +CoSENode.prototype.move = function () { + var layout = this.graphManager.getLayout(); + this.displacementX = layout.coolingFactor * (this.springForceX + this.repulsionForceX + this.gravitationForceX) / this.noOfChildren; + this.displacementY = layout.coolingFactor * (this.springForceY + this.repulsionForceY + this.gravitationForceY) / this.noOfChildren; + + if (Math.abs(this.displacementX) > layout.coolingFactor * layout.maxNodeDisplacement) { + this.displacementX = layout.coolingFactor * layout.maxNodeDisplacement * IMath.sign(this.displacementX); + } + + if (Math.abs(this.displacementY) > layout.coolingFactor * layout.maxNodeDisplacement) { + this.displacementY = layout.coolingFactor * layout.maxNodeDisplacement * IMath.sign(this.displacementY); + } + + // a simple node, just move it + if (this.child == null) { + this.moveBy(this.displacementX, this.displacementY); + } + // an empty compound node, again just move it + else if (this.child.getNodes().length == 0) { + this.moveBy(this.displacementX, this.displacementY); + } + // non-empty compound node, propogate movement to children as well + else { + this.propogateDisplacementToChildren(this.displacementX, this.displacementY); + } + + layout.totalDisplacement += Math.abs(this.displacementX) + Math.abs(this.displacementY); + + this.springForceX = 0; + this.springForceY = 0; + this.repulsionForceX = 0; + this.repulsionForceY = 0; + this.gravitationForceX = 0; + this.gravitationForceY = 0; + this.displacementX = 0; + this.displacementY = 0; +}; + +CoSENode.prototype.propogateDisplacementToChildren = function (dX, dY) { + var nodes = this.getChild().getNodes(); + var node; + for (var i = 0; i < nodes.length; i++) { + node = nodes[i]; + if (node.getChild() == null) { + node.moveBy(dX, dY); + node.displacementX += dX; + node.displacementY += dY; + } else { + node.propogateDisplacementToChildren(dX, dY); + } + } +}; + +CoSENode.prototype.setPred1 = function (pred1) { + this.pred1 = pred1; +}; + +CoSENode.prototype.getPred1 = function () { + return pred1; +}; + +CoSENode.prototype.getPred2 = function () { + return pred2; +}; + +CoSENode.prototype.setNext = function (next) { + this.next = next; +}; + +CoSENode.prototype.getNext = function () { + return next; +}; + +CoSENode.prototype.setProcessed = function (processed) { + this.processed = processed; +}; + +CoSENode.prototype.isProcessed = function () { + return processed; +}; + +module.exports = CoSENode; + +},{"./FDLayoutNode":15,"./IMath":19}],10:[function(_dereq_,module,exports){ +"use strict"; + +function DimensionD(width, height) { + this.width = 0; + this.height = 0; + if (width !== null && height !== null) { + this.height = height; + this.width = width; + } +} + +DimensionD.prototype.getWidth = function () { + return this.width; +}; + +DimensionD.prototype.setWidth = function (width) { + this.width = width; +}; + +DimensionD.prototype.getHeight = function () { + return this.height; +}; + +DimensionD.prototype.setHeight = function (height) { + this.height = height; +}; + +module.exports = DimensionD; + +},{}],11:[function(_dereq_,module,exports){ +"use strict"; + +function Emitter() { + this.listeners = []; +} + +var p = Emitter.prototype; + +p.addListener = function (event, callback) { + this.listeners.push({ + event: event, + callback: callback + }); +}; + +p.removeListener = function (event, callback) { + for (var i = this.listeners.length; i >= 0; i--) { + var l = this.listeners[i]; + + if (l.event === event && l.callback === callback) { + this.listeners.splice(i, 1); + } + } +}; + +p.emit = function (event, data) { + for (var i = 0; i < this.listeners.length; i++) { + var l = this.listeners[i]; + + if (event === l.event) { + l.callback(data); + } + } +}; + +module.exports = Emitter; + +},{}],12:[function(_dereq_,module,exports){ +'use strict'; + +function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } + +var Layout = _dereq_('./Layout'); +var FDLayoutConstants = _dereq_('./FDLayoutConstants'); +var LayoutConstants = _dereq_('./LayoutConstants'); +var IGeometry = _dereq_('./IGeometry'); +var IMath = _dereq_('./IMath'); +var Integer = _dereq_('./Integer'); + +function FDLayout() { + Layout.call(this); + + this.useSmartIdealEdgeLengthCalculation = FDLayoutConstants.DEFAULT_USE_SMART_IDEAL_EDGE_LENGTH_CALCULATION; + this.idealEdgeLength = FDLayoutConstants.DEFAULT_EDGE_LENGTH; + this.springConstant = FDLayoutConstants.DEFAULT_SPRING_STRENGTH; + this.repulsionConstant = FDLayoutConstants.DEFAULT_REPULSION_STRENGTH; + this.gravityConstant = FDLayoutConstants.DEFAULT_GRAVITY_STRENGTH; + this.compoundGravityConstant = FDLayoutConstants.DEFAULT_COMPOUND_GRAVITY_STRENGTH; + this.gravityRangeFactor = FDLayoutConstants.DEFAULT_GRAVITY_RANGE_FACTOR; + this.compoundGravityRangeFactor = FDLayoutConstants.DEFAULT_COMPOUND_GRAVITY_RANGE_FACTOR; + this.displacementThresholdPerNode = 3.0 * FDLayoutConstants.DEFAULT_EDGE_LENGTH / 100; + this.coolingFactor = FDLayoutConstants.DEFAULT_COOLING_FACTOR_INCREMENTAL; + this.initialCoolingFactor = FDLayoutConstants.DEFAULT_COOLING_FACTOR_INCREMENTAL; + this.totalDisplacement = 0.0; + this.oldTotalDisplacement = 0.0; + this.maxIterations = FDLayoutConstants.MAX_ITERATIONS; +} + +FDLayout.prototype = Object.create(Layout.prototype); + +for (var prop in Layout) { + FDLayout[prop] = Layout[prop]; +} + +FDLayout.prototype.initParameters = function () { + Layout.prototype.initParameters.call(this, arguments); + + if (this.layoutQuality == LayoutConstants.DRAFT_QUALITY) { + this.displacementThresholdPerNode += 0.30; + this.maxIterations *= 0.8; + } else if (this.layoutQuality == LayoutConstants.PROOF_QUALITY) { + this.displacementThresholdPerNode -= 0.30; + this.maxIterations *= 1.2; + } + + this.totalIterations = 0; + this.notAnimatedIterations = 0; + + this.useFRGridVariant = FDLayoutConstants.DEFAULT_USE_SMART_REPULSION_RANGE_CALCULATION; + + this.grid = []; + // variables for tree reduction support + this.prunedNodesAll = []; + this.growTreeIterations = 0; + this.afterGrowthIterations = 0; + this.isTreeGrowing = false; + this.isGrowthFinished = false; +}; + +FDLayout.prototype.calcIdealEdgeLengths = function () { + var edge; + var lcaDepth; + var source; + var target; + var sizeOfSourceInLca; + var sizeOfTargetInLca; + + var allEdges = this.getGraphManager().getAllEdges(); + for (var i = 0; i < allEdges.length; i++) { + edge = allEdges[i]; + + edge.idealLength = this.idealEdgeLength; + + if (edge.isInterGraph) { + source = edge.getSource(); + target = edge.getTarget(); + + sizeOfSourceInLca = edge.getSourceInLca().getEstimatedSize(); + sizeOfTargetInLca = edge.getTargetInLca().getEstimatedSize(); + + if (this.useSmartIdealEdgeLengthCalculation) { + edge.idealLength += sizeOfSourceInLca + sizeOfTargetInLca - 2 * LayoutConstants.SIMPLE_NODE_SIZE; + } + + lcaDepth = edge.getLca().getInclusionTreeDepth(); + + edge.idealLength += FDLayoutConstants.DEFAULT_EDGE_LENGTH * FDLayoutConstants.PER_LEVEL_IDEAL_EDGE_LENGTH_FACTOR * (source.getInclusionTreeDepth() + target.getInclusionTreeDepth() - 2 * lcaDepth); + } + } +}; + +FDLayout.prototype.initSpringEmbedder = function () { + + if (this.incremental) { + this.maxNodeDisplacement = FDLayoutConstants.MAX_NODE_DISPLACEMENT_INCREMENTAL; + } else { + this.coolingFactor = 1.0; + this.initialCoolingFactor = 1.0; + this.maxNodeDisplacement = FDLayoutConstants.MAX_NODE_DISPLACEMENT; + } + + this.maxIterations = Math.max(this.getAllNodes().length * 5, this.maxIterations); + + this.totalDisplacementThreshold = this.displacementThresholdPerNode * this.getAllNodes().length; + + this.repulsionRange = this.calcRepulsionRange(); +}; + +FDLayout.prototype.calcSpringForces = function () { + var lEdges = this.getAllEdges(); + var edge; + + for (var i = 0; i < lEdges.length; i++) { + edge = lEdges[i]; + + this.calcSpringForce(edge, edge.idealLength); + } +}; + +FDLayout.prototype.calcRepulsionForces = function () { + var i, j; + var nodeA, nodeB; + var lNodes = this.getAllNodes(); + var processedNodeSet; + + if (this.useFRGridVariant) { + if (this.totalIterations % FDLayoutConstants.GRID_CALCULATION_CHECK_PERIOD == 1 && !this.isTreeGrowing && !this.isGrowthFinished) { + this.updateGrid(); + } + + processedNodeSet = new Set(); + + // calculate repulsion forces between each nodes and its surrounding + for (i = 0; i < lNodes.length; i++) { + nodeA = lNodes[i]; + this.calculateRepulsionForceOfANode(nodeA, processedNodeSet); + processedNodeSet.add(nodeA); + } + } else { + for (i = 0; i < lNodes.length; i++) { + nodeA = lNodes[i]; + + for (j = i + 1; j < lNodes.length; j++) { + nodeB = lNodes[j]; + + // If both nodes are not members of the same graph, skip. + if (nodeA.getOwner() != nodeB.getOwner()) { + continue; + } + + this.calcRepulsionForce(nodeA, nodeB); + } + } + } +}; + +FDLayout.prototype.calcGravitationalForces = function () { + var node; + var lNodes = this.getAllNodesToApplyGravitation(); + + for (var i = 0; i < lNodes.length; i++) { + node = lNodes[i]; + this.calcGravitationalForce(node); + } +}; + +FDLayout.prototype.moveNodes = function () { + var lNodes = this.getAllNodes(); + var node; + + for (var i = 0; i < lNodes.length; i++) { + node = lNodes[i]; + node.move(); + } +}; + +FDLayout.prototype.calcSpringForce = function (edge, idealLength) { + var sourceNode = edge.getSource(); + var targetNode = edge.getTarget(); + + var length; + var springForce; + var springForceX; + var springForceY; + + // Update edge length + if (this.uniformLeafNodeSizes && sourceNode.getChild() == null && targetNode.getChild() == null) { + edge.updateLengthSimple(); + } else { + edge.updateLength(); + + if (edge.isOverlapingSourceAndTarget) { + return; + } + } + + length = edge.getLength(); + + // Calculate spring forces + springForce = this.springConstant * (length - idealLength); + + // Project force onto x and y axes + springForceX = springForce * (edge.lengthX / length); + springForceY = springForce * (edge.lengthY / length); + + // Apply forces on the end nodes + sourceNode.springForceX += springForceX; + sourceNode.springForceY += springForceY; + targetNode.springForceX -= springForceX; + targetNode.springForceY -= springForceY; +}; + +FDLayout.prototype.calcRepulsionForce = function (nodeA, nodeB) { + var rectA = nodeA.getRect(); + var rectB = nodeB.getRect(); + var overlapAmount = new Array(2); + var clipPoints = new Array(4); + var distanceX; + var distanceY; + var distanceSquared; + var distance; + var repulsionForce; + var repulsionForceX; + var repulsionForceY; + + if (rectA.intersects(rectB)) // two nodes overlap + { + // calculate separation amount in x and y directions + IGeometry.calcSeparationAmount(rectA, rectB, overlapAmount, FDLayoutConstants.DEFAULT_EDGE_LENGTH / 2.0); + + repulsionForceX = 2 * overlapAmount[0]; + repulsionForceY = 2 * overlapAmount[1]; + + var childrenConstant = nodeA.noOfChildren * nodeB.noOfChildren / (nodeA.noOfChildren + nodeB.noOfChildren); + + // Apply forces on the two nodes + nodeA.repulsionForceX -= childrenConstant * repulsionForceX; + nodeA.repulsionForceY -= childrenConstant * repulsionForceY; + nodeB.repulsionForceX += childrenConstant * repulsionForceX; + nodeB.repulsionForceY += childrenConstant * repulsionForceY; + } else // no overlap + { + // calculate distance + + if (this.uniformLeafNodeSizes && nodeA.getChild() == null && nodeB.getChild() == null) // simply base repulsion on distance of node centers + { + distanceX = rectB.getCenterX() - rectA.getCenterX(); + distanceY = rectB.getCenterY() - rectA.getCenterY(); + } else // use clipping points + { + IGeometry.getIntersection(rectA, rectB, clipPoints); + + distanceX = clipPoints[2] - clipPoints[0]; + distanceY = clipPoints[3] - clipPoints[1]; + } + + // No repulsion range. FR grid variant should take care of this. + if (Math.abs(distanceX) < FDLayoutConstants.MIN_REPULSION_DIST) { + distanceX = IMath.sign(distanceX) * FDLayoutConstants.MIN_REPULSION_DIST; + } + + if (Math.abs(distanceY) < FDLayoutConstants.MIN_REPULSION_DIST) { + distanceY = IMath.sign(distanceY) * FDLayoutConstants.MIN_REPULSION_DIST; + } + + distanceSquared = distanceX * distanceX + distanceY * distanceY; + distance = Math.sqrt(distanceSquared); + + repulsionForce = this.repulsionConstant * nodeA.noOfChildren * nodeB.noOfChildren / distanceSquared; + + // Project force onto x and y axes + repulsionForceX = repulsionForce * distanceX / distance; + repulsionForceY = repulsionForce * distanceY / distance; + + // Apply forces on the two nodes + nodeA.repulsionForceX -= repulsionForceX; + nodeA.repulsionForceY -= repulsionForceY; + nodeB.repulsionForceX += repulsionForceX; + nodeB.repulsionForceY += repulsionForceY; + } +}; + +FDLayout.prototype.calcGravitationalForce = function (node) { + var ownerGraph; + var ownerCenterX; + var ownerCenterY; + var distanceX; + var distanceY; + var absDistanceX; + var absDistanceY; + var estimatedSize; + ownerGraph = node.getOwner(); + + ownerCenterX = (ownerGraph.getRight() + ownerGraph.getLeft()) / 2; + ownerCenterY = (ownerGraph.getTop() + ownerGraph.getBottom()) / 2; + distanceX = node.getCenterX() - ownerCenterX; + distanceY = node.getCenterY() - ownerCenterY; + absDistanceX = Math.abs(distanceX) + node.getWidth() / 2; + absDistanceY = Math.abs(distanceY) + node.getHeight() / 2; + + if (node.getOwner() == this.graphManager.getRoot()) // in the root graph + { + estimatedSize = ownerGraph.getEstimatedSize() * this.gravityRangeFactor; + + if (absDistanceX > estimatedSize || absDistanceY > estimatedSize) { + node.gravitationForceX = -this.gravityConstant * distanceX; + node.gravitationForceY = -this.gravityConstant * distanceY; + } + } else // inside a compound + { + estimatedSize = ownerGraph.getEstimatedSize() * this.compoundGravityRangeFactor; + + if (absDistanceX > estimatedSize || absDistanceY > estimatedSize) { + node.gravitationForceX = -this.gravityConstant * distanceX * this.compoundGravityConstant; + node.gravitationForceY = -this.gravityConstant * distanceY * this.compoundGravityConstant; + } + } +}; + +FDLayout.prototype.isConverged = function () { + var converged; + var oscilating = false; + + if (this.totalIterations > this.maxIterations / 3) { + oscilating = Math.abs(this.totalDisplacement - this.oldTotalDisplacement) < 2; + } + + converged = this.totalDisplacement < this.totalDisplacementThreshold; + + this.oldTotalDisplacement = this.totalDisplacement; + + return converged || oscilating; +}; + +FDLayout.prototype.animate = function () { + if (this.animationDuringLayout && !this.isSubLayout) { + if (this.notAnimatedIterations == this.animationPeriod) { + this.update(); + this.notAnimatedIterations = 0; + } else { + this.notAnimatedIterations++; + } + } +}; + +// ----------------------------------------------------------------------------- +// Section: FR-Grid Variant Repulsion Force Calculation +// ----------------------------------------------------------------------------- + +FDLayout.prototype.calcGrid = function (graph) { + + var sizeX = 0; + var sizeY = 0; + + sizeX = parseInt(Math.ceil((graph.getRight() - graph.getLeft()) / this.repulsionRange)); + sizeY = parseInt(Math.ceil((graph.getBottom() - graph.getTop()) / this.repulsionRange)); + + var grid = new Array(sizeX); + + for (var i = 0; i < sizeX; i++) { + grid[i] = new Array(sizeY); + } + + for (var i = 0; i < sizeX; i++) { + for (var j = 0; j < sizeY; j++) { + grid[i][j] = new Array(); + } + } + + return grid; +}; + +FDLayout.prototype.addNodeToGrid = function (v, left, top) { + + var startX = 0; + var finishX = 0; + var startY = 0; + var finishY = 0; + + startX = parseInt(Math.floor((v.getRect().x - left) / this.repulsionRange)); + finishX = parseInt(Math.floor((v.getRect().width + v.getRect().x - left) / this.repulsionRange)); + startY = parseInt(Math.floor((v.getRect().y - top) / this.repulsionRange)); + finishY = parseInt(Math.floor((v.getRect().height + v.getRect().y - top) / this.repulsionRange)); + + for (var i = startX; i <= finishX; i++) { + for (var j = startY; j <= finishY; j++) { + this.grid[i][j].push(v); + v.setGridCoordinates(startX, finishX, startY, finishY); + } + } +}; + +FDLayout.prototype.updateGrid = function () { + var i; + var nodeA; + var lNodes = this.getAllNodes(); + + this.grid = this.calcGrid(this.graphManager.getRoot()); + + // put all nodes to proper grid cells + for (i = 0; i < lNodes.length; i++) { + nodeA = lNodes[i]; + this.addNodeToGrid(nodeA, this.graphManager.getRoot().getLeft(), this.graphManager.getRoot().getTop()); + } +}; + +FDLayout.prototype.calculateRepulsionForceOfANode = function (nodeA, processedNodeSet) { + + if (this.totalIterations % FDLayoutConstants.GRID_CALCULATION_CHECK_PERIOD == 1 && !this.isTreeGrowing && !this.isGrowthFinished || this.growTreeIterations % 10 == 1 && this.isTreeGrowing || this.afterGrowthIterations % 10 == 1 && this.isGrowthFinished) { + var surrounding = new Set(); + nodeA.surrounding = new Array(); + var nodeB; + var grid = this.grid; + + for (var i = nodeA.startX - 1; i < nodeA.finishX + 2; i++) { + for (var j = nodeA.startY - 1; j < nodeA.finishY + 2; j++) { + if (!(i < 0 || j < 0 || i >= grid.length || j >= grid[0].length)) { + for (var k = 0; k < grid[i][j].length; k++) { + nodeB = grid[i][j][k]; + + // If both nodes are not members of the same graph, + // or both nodes are the same, skip. + if (nodeA.getOwner() != nodeB.getOwner() || nodeA == nodeB) { + continue; + } + + // check if the repulsion force between + // nodeA and nodeB has already been calculated + if (!processedNodeSet.has(nodeB) && !surrounding.has(nodeB)) { + var distanceX = Math.abs(nodeA.getCenterX() - nodeB.getCenterX()) - (nodeA.getWidth() / 2 + nodeB.getWidth() / 2); + var distanceY = Math.abs(nodeA.getCenterY() - nodeB.getCenterY()) - (nodeA.getHeight() / 2 + nodeB.getHeight() / 2); + + // if the distance between nodeA and nodeB + // is less then calculation range + if (distanceX <= this.repulsionRange && distanceY <= this.repulsionRange) { + //then add nodeB to surrounding of nodeA + surrounding.add(nodeB); + } + } + } + } + } + } + + nodeA.surrounding = [].concat(_toConsumableArray(surrounding)); + } + for (i = 0; i < nodeA.surrounding.length; i++) { + this.calcRepulsionForce(nodeA, nodeA.surrounding[i]); + } +}; + +FDLayout.prototype.calcRepulsionRange = function () { + return 0.0; +}; + +// ----------------------------------------------------------------------------- +// Section: Tree Reduction methods +// ----------------------------------------------------------------------------- +// Reduce trees +FDLayout.prototype.reduceTrees = function () { + var prunedNodesAll = []; + var containsLeaf = true; + var node; + + while (containsLeaf) { + var allNodes = this.graphManager.getAllNodes(); + var prunedNodesInStepTemp = []; + containsLeaf = false; + + for (var i = 0; i < allNodes.length; i++) { + node = allNodes[i]; + if (node.getEdges().length == 1 && !node.getEdges()[0].isInterGraph && node.getChild() == null) { + prunedNodesInStepTemp.push([node, node.getEdges()[0], node.getOwner()]); + containsLeaf = true; + } + } + if (containsLeaf == true) { + var prunedNodesInStep = []; + for (var j = 0; j < prunedNodesInStepTemp.length; j++) { + if (prunedNodesInStepTemp[j][0].getEdges().length == 1) { + prunedNodesInStep.push(prunedNodesInStepTemp[j]); + prunedNodesInStepTemp[j][0].getOwner().remove(prunedNodesInStepTemp[j][0]); + } + } + prunedNodesAll.push(prunedNodesInStep); + this.graphManager.resetAllNodes(); + this.graphManager.resetAllEdges(); + } + } + this.prunedNodesAll = prunedNodesAll; +}; + +// Grow tree one step +FDLayout.prototype.growTree = function (prunedNodesAll) { + var lengthOfPrunedNodesInStep = prunedNodesAll.length; + var prunedNodesInStep = prunedNodesAll[lengthOfPrunedNodesInStep - 1]; + + var nodeData; + for (var i = 0; i < prunedNodesInStep.length; i++) { + nodeData = prunedNodesInStep[i]; + + this.findPlaceforPrunedNode(nodeData); + + nodeData[2].add(nodeData[0]); + nodeData[2].add(nodeData[1], nodeData[1].source, nodeData[1].target); + } + + prunedNodesAll.splice(prunedNodesAll.length - 1, 1); + this.graphManager.resetAllNodes(); + this.graphManager.resetAllEdges(); +}; + +// Find an appropriate position to replace pruned node, this method can be improved +FDLayout.prototype.findPlaceforPrunedNode = function (nodeData) { + + var gridForPrunedNode; + var nodeToConnect; + var prunedNode = nodeData[0]; + if (prunedNode == nodeData[1].source) { + nodeToConnect = nodeData[1].target; + } else { + nodeToConnect = nodeData[1].source; + } + var startGridX = nodeToConnect.startX; + var finishGridX = nodeToConnect.finishX; + var startGridY = nodeToConnect.startY; + var finishGridY = nodeToConnect.finishY; + + var upNodeCount = 0; + var downNodeCount = 0; + var rightNodeCount = 0; + var leftNodeCount = 0; + var controlRegions = [upNodeCount, rightNodeCount, downNodeCount, leftNodeCount]; + + if (startGridY > 0) { + for (var i = startGridX; i <= finishGridX; i++) { + controlRegions[0] += this.grid[i][startGridY - 1].length + this.grid[i][startGridY].length - 1; + } + } + if (finishGridX < this.grid.length - 1) { + for (var i = startGridY; i <= finishGridY; i++) { + controlRegions[1] += this.grid[finishGridX + 1][i].length + this.grid[finishGridX][i].length - 1; + } + } + if (finishGridY < this.grid[0].length - 1) { + for (var i = startGridX; i <= finishGridX; i++) { + controlRegions[2] += this.grid[i][finishGridY + 1].length + this.grid[i][finishGridY].length - 1; + } + } + if (startGridX > 0) { + for (var i = startGridY; i <= finishGridY; i++) { + controlRegions[3] += this.grid[startGridX - 1][i].length + this.grid[startGridX][i].length - 1; + } + } + var min = Integer.MAX_VALUE; + var minCount; + var minIndex; + for (var j = 0; j < controlRegions.length; j++) { + if (controlRegions[j] < min) { + min = controlRegions[j]; + minCount = 1; + minIndex = j; + } else if (controlRegions[j] == min) { + minCount++; + } + } + + if (minCount == 3 && min == 0) { + if (controlRegions[0] == 0 && controlRegions[1] == 0 && controlRegions[2] == 0) { + gridForPrunedNode = 1; + } else if (controlRegions[0] == 0 && controlRegions[1] == 0 && controlRegions[3] == 0) { + gridForPrunedNode = 0; + } else if (controlRegions[0] == 0 && controlRegions[2] == 0 && controlRegions[3] == 0) { + gridForPrunedNode = 3; + } else if (controlRegions[1] == 0 && controlRegions[2] == 0 && controlRegions[3] == 0) { + gridForPrunedNode = 2; + } + } else if (minCount == 2 && min == 0) { + var random = Math.floor(Math.random() * 2); + if (controlRegions[0] == 0 && controlRegions[1] == 0) { + ; + if (random == 0) { + gridForPrunedNode = 0; + } else { + gridForPrunedNode = 1; + } + } else if (controlRegions[0] == 0 && controlRegions[2] == 0) { + if (random == 0) { + gridForPrunedNode = 0; + } else { + gridForPrunedNode = 2; + } + } else if (controlRegions[0] == 0 && controlRegions[3] == 0) { + if (random == 0) { + gridForPrunedNode = 0; + } else { + gridForPrunedNode = 3; + } + } else if (controlRegions[1] == 0 && controlRegions[2] == 0) { + if (random == 0) { + gridForPrunedNode = 1; + } else { + gridForPrunedNode = 2; + } + } else if (controlRegions[1] == 0 && controlRegions[3] == 0) { + if (random == 0) { + gridForPrunedNode = 1; + } else { + gridForPrunedNode = 3; + } + } else { + if (random == 0) { + gridForPrunedNode = 2; + } else { + gridForPrunedNode = 3; + } + } + } else if (minCount == 4 && min == 0) { + var random = Math.floor(Math.random() * 4); + gridForPrunedNode = random; + } else { + gridForPrunedNode = minIndex; + } + + if (gridForPrunedNode == 0) { + prunedNode.setCenter(nodeToConnect.getCenterX(), nodeToConnect.getCenterY() - nodeToConnect.getHeight() / 2 - FDLayoutConstants.DEFAULT_EDGE_LENGTH - prunedNode.getHeight() / 2); + } else if (gridForPrunedNode == 1) { + prunedNode.setCenter(nodeToConnect.getCenterX() + nodeToConnect.getWidth() / 2 + FDLayoutConstants.DEFAULT_EDGE_LENGTH + prunedNode.getWidth() / 2, nodeToConnect.getCenterY()); + } else if (gridForPrunedNode == 2) { + prunedNode.setCenter(nodeToConnect.getCenterX(), nodeToConnect.getCenterY() + nodeToConnect.getHeight() / 2 + FDLayoutConstants.DEFAULT_EDGE_LENGTH + prunedNode.getHeight() / 2); + } else { + prunedNode.setCenter(nodeToConnect.getCenterX() - nodeToConnect.getWidth() / 2 - FDLayoutConstants.DEFAULT_EDGE_LENGTH - prunedNode.getWidth() / 2, nodeToConnect.getCenterY()); + } +}; + +module.exports = FDLayout; + +},{"./FDLayoutConstants":13,"./IGeometry":18,"./IMath":19,"./Integer":20,"./Layout":26,"./LayoutConstants":27}],13:[function(_dereq_,module,exports){ +'use strict'; + +var LayoutConstants = _dereq_('./LayoutConstants'); + +function FDLayoutConstants() {} + +//FDLayoutConstants inherits static props in LayoutConstants +for (var prop in LayoutConstants) { + FDLayoutConstants[prop] = LayoutConstants[prop]; +} + +FDLayoutConstants.MAX_ITERATIONS = 2500; + +FDLayoutConstants.DEFAULT_EDGE_LENGTH = 50; +FDLayoutConstants.DEFAULT_SPRING_STRENGTH = 0.45; +FDLayoutConstants.DEFAULT_REPULSION_STRENGTH = 4500.0; +FDLayoutConstants.DEFAULT_GRAVITY_STRENGTH = 0.4; +FDLayoutConstants.DEFAULT_COMPOUND_GRAVITY_STRENGTH = 1.0; +FDLayoutConstants.DEFAULT_GRAVITY_RANGE_FACTOR = 3.8; +FDLayoutConstants.DEFAULT_COMPOUND_GRAVITY_RANGE_FACTOR = 1.5; +FDLayoutConstants.DEFAULT_USE_SMART_IDEAL_EDGE_LENGTH_CALCULATION = true; +FDLayoutConstants.DEFAULT_USE_SMART_REPULSION_RANGE_CALCULATION = true; +FDLayoutConstants.DEFAULT_COOLING_FACTOR_INCREMENTAL = 0.5; +FDLayoutConstants.MAX_NODE_DISPLACEMENT_INCREMENTAL = 100.0; +FDLayoutConstants.MAX_NODE_DISPLACEMENT = FDLayoutConstants.MAX_NODE_DISPLACEMENT_INCREMENTAL * 3; +FDLayoutConstants.MIN_REPULSION_DIST = FDLayoutConstants.DEFAULT_EDGE_LENGTH / 10.0; +FDLayoutConstants.CONVERGENCE_CHECK_PERIOD = 100; +FDLayoutConstants.PER_LEVEL_IDEAL_EDGE_LENGTH_FACTOR = 0.1; +FDLayoutConstants.MIN_EDGE_LENGTH = 1; +FDLayoutConstants.GRID_CALCULATION_CHECK_PERIOD = 10; + +module.exports = FDLayoutConstants; + +},{"./LayoutConstants":27}],14:[function(_dereq_,module,exports){ +'use strict'; + +var LEdge = _dereq_('./LEdge'); +var FDLayoutConstants = _dereq_('./FDLayoutConstants'); + +function FDLayoutEdge(source, target, vEdge) { + LEdge.call(this, source, target, vEdge); + this.idealLength = FDLayoutConstants.DEFAULT_EDGE_LENGTH; +} + +FDLayoutEdge.prototype = Object.create(LEdge.prototype); + +for (var prop in LEdge) { + FDLayoutEdge[prop] = LEdge[prop]; +} + +module.exports = FDLayoutEdge; + +},{"./FDLayoutConstants":13,"./LEdge":21}],15:[function(_dereq_,module,exports){ +'use strict'; + +var LNode = _dereq_('./LNode'); + +function FDLayoutNode(gm, loc, size, vNode) { + // alternative constructor is handled inside LNode + LNode.call(this, gm, loc, size, vNode); + //Spring, repulsion and gravitational forces acting on this node + this.springForceX = 0; + this.springForceY = 0; + this.repulsionForceX = 0; + this.repulsionForceY = 0; + this.gravitationForceX = 0; + this.gravitationForceY = 0; + //Amount by which this node is to be moved in this iteration + this.displacementX = 0; + this.displacementY = 0; + + //Start and finish grid coordinates that this node is fallen into + this.startX = 0; + this.finishX = 0; + this.startY = 0; + this.finishY = 0; + + //Geometric neighbors of this node + this.surrounding = []; +} + +FDLayoutNode.prototype = Object.create(LNode.prototype); + +for (var prop in LNode) { + FDLayoutNode[prop] = LNode[prop]; +} + +FDLayoutNode.prototype.setGridCoordinates = function (_startX, _finishX, _startY, _finishY) { + this.startX = _startX; + this.finishX = _finishX; + this.startY = _startY; + this.finishY = _finishY; +}; + +module.exports = FDLayoutNode; + +},{"./LNode":25}],16:[function(_dereq_,module,exports){ +'use strict'; + +var UniqueIDGeneretor = _dereq_('./UniqueIDGeneretor'); + +function HashMap() { + this.map = {}; + this.keys = []; +} + +HashMap.prototype.put = function (key, value) { + var theId = UniqueIDGeneretor.createID(key); + if (!this.contains(theId)) { + this.map[theId] = value; + this.keys.push(key); + } +}; + +HashMap.prototype.contains = function (key) { + var theId = UniqueIDGeneretor.createID(key); + return this.map[key] != null; +}; + +HashMap.prototype.get = function (key) { + var theId = UniqueIDGeneretor.createID(key); + return this.map[theId]; +}; + +HashMap.prototype.keySet = function () { + return this.keys; +}; + +module.exports = HashMap; + +},{"./UniqueIDGeneretor":33}],17:[function(_dereq_,module,exports){ +'use strict'; + +var UniqueIDGeneretor = _dereq_('./UniqueIDGeneretor'); + +function HashSet() { + this.set = {}; +} +; + +HashSet.prototype.add = function (obj) { + var theId = UniqueIDGeneretor.createID(obj); + if (!this.contains(theId)) this.set[theId] = obj; +}; + +HashSet.prototype.remove = function (obj) { + delete this.set[UniqueIDGeneretor.createID(obj)]; +}; + +HashSet.prototype.clear = function () { + this.set = {}; +}; + +HashSet.prototype.contains = function (obj) { + return this.set[UniqueIDGeneretor.createID(obj)] == obj; +}; + +HashSet.prototype.isEmpty = function () { + return this.size() === 0; +}; + +HashSet.prototype.size = function () { + return Object.keys(this.set).length; +}; + +//concats this.set to the given list +HashSet.prototype.addAllTo = function (list) { + var keys = Object.keys(this.set); + var length = keys.length; + for (var i = 0; i < length; i++) { + list.push(this.set[keys[i]]); + } +}; + +HashSet.prototype.size = function () { + return Object.keys(this.set).length; +}; + +HashSet.prototype.addAll = function (list) { + var s = list.length; + for (var i = 0; i < s; i++) { + var v = list[i]; + this.add(v); + } +}; + +module.exports = HashSet; + +},{"./UniqueIDGeneretor":33}],18:[function(_dereq_,module,exports){ +"use strict"; + +function IGeometry() {} + +IGeometry.calcSeparationAmount = function (rectA, rectB, overlapAmount, separationBuffer) { + if (!rectA.intersects(rectB)) { + throw "assert failed"; + } + var directions = new Array(2); + IGeometry.decideDirectionsForOverlappingNodes(rectA, rectB, directions); + overlapAmount[0] = Math.min(rectA.getRight(), rectB.getRight()) - Math.max(rectA.x, rectB.x); + overlapAmount[1] = Math.min(rectA.getBottom(), rectB.getBottom()) - Math.max(rectA.y, rectB.y); + // update the overlapping amounts for the following cases: + if (rectA.getX() <= rectB.getX() && rectA.getRight() >= rectB.getRight()) { + overlapAmount[0] += Math.min(rectB.getX() - rectA.getX(), rectA.getRight() - rectB.getRight()); + } else if (rectB.getX() <= rectA.getX() && rectB.getRight() >= rectA.getRight()) { + overlapAmount[0] += Math.min(rectA.getX() - rectB.getX(), rectB.getRight() - rectA.getRight()); + } + if (rectA.getY() <= rectB.getY() && rectA.getBottom() >= rectB.getBottom()) { + overlapAmount[1] += Math.min(rectB.getY() - rectA.getY(), rectA.getBottom() - rectB.getBottom()); + } else if (rectB.getY() <= rectA.getY() && rectB.getBottom() >= rectA.getBottom()) { + overlapAmount[1] += Math.min(rectA.getY() - rectB.getY(), rectB.getBottom() - rectA.getBottom()); + } + + // find slope of the line passes two centers + var slope = Math.abs((rectB.getCenterY() - rectA.getCenterY()) / (rectB.getCenterX() - rectA.getCenterX())); + // if centers are overlapped + if (rectB.getCenterY() == rectA.getCenterY() && rectB.getCenterX() == rectA.getCenterX()) { + // assume the slope is 1 (45 degree) + slope = 1.0; + } + + var moveByY = slope * overlapAmount[0]; + var moveByX = overlapAmount[1] / slope; + if (overlapAmount[0] < moveByX) { + moveByX = overlapAmount[0]; + } else { + moveByY = overlapAmount[1]; + } + // return half the amount so that if each rectangle is moved by these + // amounts in opposite directions, overlap will be resolved + overlapAmount[0] = -1 * directions[0] * (moveByX / 2 + separationBuffer); + overlapAmount[1] = -1 * directions[1] * (moveByY / 2 + separationBuffer); +}; + +IGeometry.decideDirectionsForOverlappingNodes = function (rectA, rectB, directions) { + if (rectA.getCenterX() < rectB.getCenterX()) { + directions[0] = -1; + } else { + directions[0] = 1; + } + + if (rectA.getCenterY() < rectB.getCenterY()) { + directions[1] = -1; + } else { + directions[1] = 1; + } +}; + +IGeometry.getIntersection2 = function (rectA, rectB, result) { + //result[0-1] will contain clipPoint of rectA, result[2-3] will contain clipPoint of rectB + var p1x = rectA.getCenterX(); + var p1y = rectA.getCenterY(); + var p2x = rectB.getCenterX(); + var p2y = rectB.getCenterY(); + + //if two rectangles intersect, then clipping points are centers + if (rectA.intersects(rectB)) { + result[0] = p1x; + result[1] = p1y; + result[2] = p2x; + result[3] = p2y; + return true; + } + //variables for rectA + var topLeftAx = rectA.getX(); + var topLeftAy = rectA.getY(); + var topRightAx = rectA.getRight(); + var bottomLeftAx = rectA.getX(); + var bottomLeftAy = rectA.getBottom(); + var bottomRightAx = rectA.getRight(); + var halfWidthA = rectA.getWidthHalf(); + var halfHeightA = rectA.getHeightHalf(); + //variables for rectB + var topLeftBx = rectB.getX(); + var topLeftBy = rectB.getY(); + var topRightBx = rectB.getRight(); + var bottomLeftBx = rectB.getX(); + var bottomLeftBy = rectB.getBottom(); + var bottomRightBx = rectB.getRight(); + var halfWidthB = rectB.getWidthHalf(); + var halfHeightB = rectB.getHeightHalf(); + //flag whether clipping points are found + var clipPointAFound = false; + var clipPointBFound = false; + + // line is vertical + if (p1x == p2x) { + if (p1y > p2y) { + result[0] = p1x; + result[1] = topLeftAy; + result[2] = p2x; + result[3] = bottomLeftBy; + return false; + } else if (p1y < p2y) { + result[0] = p1x; + result[1] = bottomLeftAy; + result[2] = p2x; + result[3] = topLeftBy; + return false; + } else { + //not line, return null; + } + } + // line is horizontal + else if (p1y == p2y) { + if (p1x > p2x) { + result[0] = topLeftAx; + result[1] = p1y; + result[2] = topRightBx; + result[3] = p2y; + return false; + } else if (p1x < p2x) { + result[0] = topRightAx; + result[1] = p1y; + result[2] = topLeftBx; + result[3] = p2y; + return false; + } else { + //not valid line, return null; + } + } else { + //slopes of rectA's and rectB's diagonals + var slopeA = rectA.height / rectA.width; + var slopeB = rectB.height / rectB.width; + + //slope of line between center of rectA and center of rectB + var slopePrime = (p2y - p1y) / (p2x - p1x); + var cardinalDirectionA; + var cardinalDirectionB; + var tempPointAx; + var tempPointAy; + var tempPointBx; + var tempPointBy; + + //determine whether clipping point is the corner of nodeA + if (-slopeA == slopePrime) { + if (p1x > p2x) { + result[0] = bottomLeftAx; + result[1] = bottomLeftAy; + clipPointAFound = true; + } else { + result[0] = topRightAx; + result[1] = topLeftAy; + clipPointAFound = true; + } + } else if (slopeA == slopePrime) { + if (p1x > p2x) { + result[0] = topLeftAx; + result[1] = topLeftAy; + clipPointAFound = true; + } else { + result[0] = bottomRightAx; + result[1] = bottomLeftAy; + clipPointAFound = true; + } + } + + //determine whether clipping point is the corner of nodeB + if (-slopeB == slopePrime) { + if (p2x > p1x) { + result[2] = bottomLeftBx; + result[3] = bottomLeftBy; + clipPointBFound = true; + } else { + result[2] = topRightBx; + result[3] = topLeftBy; + clipPointBFound = true; + } + } else if (slopeB == slopePrime) { + if (p2x > p1x) { + result[2] = topLeftBx; + result[3] = topLeftBy; + clipPointBFound = true; + } else { + result[2] = bottomRightBx; + result[3] = bottomLeftBy; + clipPointBFound = true; + } + } + + //if both clipping points are corners + if (clipPointAFound && clipPointBFound) { + return false; + } + + //determine Cardinal Direction of rectangles + if (p1x > p2x) { + if (p1y > p2y) { + cardinalDirectionA = IGeometry.getCardinalDirection(slopeA, slopePrime, 4); + cardinalDirectionB = IGeometry.getCardinalDirection(slopeB, slopePrime, 2); + } else { + cardinalDirectionA = IGeometry.getCardinalDirection(-slopeA, slopePrime, 3); + cardinalDirectionB = IGeometry.getCardinalDirection(-slopeB, slopePrime, 1); + } + } else { + if (p1y > p2y) { + cardinalDirectionA = IGeometry.getCardinalDirection(-slopeA, slopePrime, 1); + cardinalDirectionB = IGeometry.getCardinalDirection(-slopeB, slopePrime, 3); + } else { + cardinalDirectionA = IGeometry.getCardinalDirection(slopeA, slopePrime, 2); + cardinalDirectionB = IGeometry.getCardinalDirection(slopeB, slopePrime, 4); + } + } + //calculate clipping Point if it is not found before + if (!clipPointAFound) { + switch (cardinalDirectionA) { + case 1: + tempPointAy = topLeftAy; + tempPointAx = p1x + -halfHeightA / slopePrime; + result[0] = tempPointAx; + result[1] = tempPointAy; + break; + case 2: + tempPointAx = bottomRightAx; + tempPointAy = p1y + halfWidthA * slopePrime; + result[0] = tempPointAx; + result[1] = tempPointAy; + break; + case 3: + tempPointAy = bottomLeftAy; + tempPointAx = p1x + halfHeightA / slopePrime; + result[0] = tempPointAx; + result[1] = tempPointAy; + break; + case 4: + tempPointAx = bottomLeftAx; + tempPointAy = p1y + -halfWidthA * slopePrime; + result[0] = tempPointAx; + result[1] = tempPointAy; + break; + } + } + if (!clipPointBFound) { + switch (cardinalDirectionB) { + case 1: + tempPointBy = topLeftBy; + tempPointBx = p2x + -halfHeightB / slopePrime; + result[2] = tempPointBx; + result[3] = tempPointBy; + break; + case 2: + tempPointBx = bottomRightBx; + tempPointBy = p2y + halfWidthB * slopePrime; + result[2] = tempPointBx; + result[3] = tempPointBy; + break; + case 3: + tempPointBy = bottomLeftBy; + tempPointBx = p2x + halfHeightB / slopePrime; + result[2] = tempPointBx; + result[3] = tempPointBy; + break; + case 4: + tempPointBx = bottomLeftBx; + tempPointBy = p2y + -halfWidthB * slopePrime; + result[2] = tempPointBx; + result[3] = tempPointBy; + break; + } + } + } + return false; +}; + +IGeometry.getCardinalDirection = function (slope, slopePrime, line) { + if (slope > slopePrime) { + return line; + } else { + return 1 + line % 4; + } +}; + +IGeometry.getIntersection = function (s1, s2, f1, f2) { + if (f2 == null) { + return IGeometry.getIntersection2(s1, s2, f1); + } + var x1 = s1.x; + var y1 = s1.y; + var x2 = s2.x; + var y2 = s2.y; + var x3 = f1.x; + var y3 = f1.y; + var x4 = f2.x; + var y4 = f2.y; + var x, y; // intersection point + var a1, a2, b1, b2, c1, c2; // coefficients of line eqns. + var denom; + + a1 = y2 - y1; + b1 = x1 - x2; + c1 = x2 * y1 - x1 * y2; // { a1*x + b1*y + c1 = 0 is line 1 } + + a2 = y4 - y3; + b2 = x3 - x4; + c2 = x4 * y3 - x3 * y4; // { a2*x + b2*y + c2 = 0 is line 2 } + + denom = a1 * b2 - a2 * b1; + + if (denom == 0) { + return null; + } + + x = (b1 * c2 - b2 * c1) / denom; + y = (a2 * c1 - a1 * c2) / denom; + + return new Point(x, y); +}; + +// ----------------------------------------------------------------------------- +// Section: Class Constants +// ----------------------------------------------------------------------------- +/** + * Some useful pre-calculated constants + */ +IGeometry.HALF_PI = 0.5 * Math.PI; +IGeometry.ONE_AND_HALF_PI = 1.5 * Math.PI; +IGeometry.TWO_PI = 2.0 * Math.PI; +IGeometry.THREE_PI = 3.0 * Math.PI; + +module.exports = IGeometry; + +},{}],19:[function(_dereq_,module,exports){ +"use strict"; + +function IMath() {} + +/** + * This method returns the sign of the input value. + */ +IMath.sign = function (value) { + if (value > 0) { + return 1; + } else if (value < 0) { + return -1; + } else { + return 0; + } +}; + +IMath.floor = function (value) { + return value < 0 ? Math.ceil(value) : Math.floor(value); +}; + +IMath.ceil = function (value) { + return value < 0 ? Math.floor(value) : Math.ceil(value); +}; + +module.exports = IMath; + +},{}],20:[function(_dereq_,module,exports){ +"use strict"; + +function Integer() {} + +Integer.MAX_VALUE = 2147483647; +Integer.MIN_VALUE = -2147483648; + +module.exports = Integer; + +},{}],21:[function(_dereq_,module,exports){ +'use strict'; + +var LGraphObject = _dereq_('./LGraphObject'); +var IGeometry = _dereq_('./IGeometry'); +var IMath = _dereq_('./IMath'); + +function LEdge(source, target, vEdge) { + LGraphObject.call(this, vEdge); + + this.isOverlapingSourceAndTarget = false; + this.vGraphObject = vEdge; + this.bendpoints = []; + this.source = source; + this.target = target; +} + +LEdge.prototype = Object.create(LGraphObject.prototype); + +for (var prop in LGraphObject) { + LEdge[prop] = LGraphObject[prop]; +} + +LEdge.prototype.getSource = function () { + return this.source; +}; + +LEdge.prototype.getTarget = function () { + return this.target; +}; + +LEdge.prototype.isInterGraph = function () { + return this.isInterGraph; +}; + +LEdge.prototype.getLength = function () { + return this.length; +}; + +LEdge.prototype.isOverlapingSourceAndTarget = function () { + return this.isOverlapingSourceAndTarget; +}; + +LEdge.prototype.getBendpoints = function () { + return this.bendpoints; +}; + +LEdge.prototype.getLca = function () { + return this.lca; +}; + +LEdge.prototype.getSourceInLca = function () { + return this.sourceInLca; +}; + +LEdge.prototype.getTargetInLca = function () { + return this.targetInLca; +}; + +LEdge.prototype.getOtherEnd = function (node) { + if (this.source === node) { + return this.target; + } else if (this.target === node) { + return this.source; + } else { + throw "Node is not incident with this edge"; + } +}; + +LEdge.prototype.getOtherEndInGraph = function (node, graph) { + var otherEnd = this.getOtherEnd(node); + var root = graph.getGraphManager().getRoot(); + + while (true) { + if (otherEnd.getOwner() == graph) { + return otherEnd; + } + + if (otherEnd.getOwner() == root) { + break; + } + + otherEnd = otherEnd.getOwner().getParent(); + } + + return null; +}; + +LEdge.prototype.updateLength = function () { + var clipPointCoordinates = new Array(4); + + this.isOverlapingSourceAndTarget = IGeometry.getIntersection(this.target.getRect(), this.source.getRect(), clipPointCoordinates); + + if (!this.isOverlapingSourceAndTarget) { + this.lengthX = clipPointCoordinates[0] - clipPointCoordinates[2]; + this.lengthY = clipPointCoordinates[1] - clipPointCoordinates[3]; + + if (Math.abs(this.lengthX) < 1.0) { + this.lengthX = IMath.sign(this.lengthX); + } + + if (Math.abs(this.lengthY) < 1.0) { + this.lengthY = IMath.sign(this.lengthY); + } + + this.length = Math.sqrt(this.lengthX * this.lengthX + this.lengthY * this.lengthY); + } +}; + +LEdge.prototype.updateLengthSimple = function () { + this.lengthX = this.target.getCenterX() - this.source.getCenterX(); + this.lengthY = this.target.getCenterY() - this.source.getCenterY(); + + if (Math.abs(this.lengthX) < 1.0) { + this.lengthX = IMath.sign(this.lengthX); + } + + if (Math.abs(this.lengthY) < 1.0) { + this.lengthY = IMath.sign(this.lengthY); + } + + this.length = Math.sqrt(this.lengthX * this.lengthX + this.lengthY * this.lengthY); +}; + +module.exports = LEdge; + +},{"./IGeometry":18,"./IMath":19,"./LGraphObject":24}],22:[function(_dereq_,module,exports){ +'use strict'; + +var LGraphObject = _dereq_('./LGraphObject'); +var Integer = _dereq_('./Integer'); +var LayoutConstants = _dereq_('./LayoutConstants'); +var LGraphManager = _dereq_('./LGraphManager'); +var LNode = _dereq_('./LNode'); +var LEdge = _dereq_('./LEdge'); +var HashSet = _dereq_('./HashSet'); +var RectangleD = _dereq_('./RectangleD'); +var Point = _dereq_('./Point'); +var List = _dereq_('linkedlist-js').List; + +function LGraph(parent, obj2, vGraph) { + LGraphObject.call(this, vGraph); + this.estimatedSize = Integer.MIN_VALUE; + this.margin = LayoutConstants.DEFAULT_GRAPH_MARGIN; + this.edges = []; + this.nodes = []; + this.isConnected = false; + this.parent = parent; + + if (obj2 != null && obj2 instanceof LGraphManager) { + this.graphManager = obj2; + } else if (obj2 != null && obj2 instanceof Layout) { + this.graphManager = obj2.graphManager; + } +} + +LGraph.prototype = Object.create(LGraphObject.prototype); +for (var prop in LGraphObject) { + LGraph[prop] = LGraphObject[prop]; +} + +LGraph.prototype.getNodes = function () { + return this.nodes; +}; + +LGraph.prototype.getEdges = function () { + return this.edges; +}; + +LGraph.prototype.getGraphManager = function () { + return this.graphManager; +}; + +LGraph.prototype.getParent = function () { + return this.parent; +}; + +LGraph.prototype.getLeft = function () { + return this.left; +}; + +LGraph.prototype.getRight = function () { + return this.right; +}; + +LGraph.prototype.getTop = function () { + return this.top; +}; + +LGraph.prototype.getBottom = function () { + return this.bottom; +}; + +LGraph.prototype.isConnected = function () { + return this.isConnected; +}; + +LGraph.prototype.add = function (obj1, sourceNode, targetNode) { + if (sourceNode == null && targetNode == null) { + var newNode = obj1; + if (this.graphManager == null) { + throw "Graph has no graph mgr!"; + } + if (this.getNodes().indexOf(newNode) > -1) { + throw "Node already in graph!"; + } + newNode.owner = this; + this.getNodes().push(newNode); + + return newNode; + } else { + var newEdge = obj1; + if (!(this.getNodes().indexOf(sourceNode) > -1 && this.getNodes().indexOf(targetNode) > -1)) { + throw "Source or target not in graph!"; + } + + if (!(sourceNode.owner == targetNode.owner && sourceNode.owner == this)) { + throw "Both owners must be this graph!"; + } + + if (sourceNode.owner != targetNode.owner) { + return null; + } + + // set source and target + newEdge.source = sourceNode; + newEdge.target = targetNode; + + // set as intra-graph edge + newEdge.isInterGraph = false; + + // add to graph edge list + this.getEdges().push(newEdge); + + // add to incidency lists + sourceNode.edges.push(newEdge); + + if (targetNode != sourceNode) { + targetNode.edges.push(newEdge); + } + + return newEdge; + } +}; + +LGraph.prototype.remove = function (obj) { + var node = obj; + if (obj instanceof LNode) { + if (node == null) { + throw "Node is null!"; + } + if (!(node.owner != null && node.owner == this)) { + throw "Owner graph is invalid!"; + } + if (this.graphManager == null) { + throw "Owner graph manager is invalid!"; + } + // remove incident edges first (make a copy to do it safely) + var edgesToBeRemoved = node.edges.slice(); + var edge; + var s = edgesToBeRemoved.length; + for (var i = 0; i < s; i++) { + edge = edgesToBeRemoved[i]; + + if (edge.isInterGraph) { + this.graphManager.remove(edge); + } else { + edge.source.owner.remove(edge); + } + } + + // now the node itself + var index = this.nodes.indexOf(node); + if (index == -1) { + throw "Node not in owner node list!"; + } + + this.nodes.splice(index, 1); + } else if (obj instanceof LEdge) { + var edge = obj; + if (edge == null) { + throw "Edge is null!"; + } + if (!(edge.source != null && edge.target != null)) { + throw "Source and/or target is null!"; + } + if (!(edge.source.owner != null && edge.target.owner != null && edge.source.owner == this && edge.target.owner == this)) { + throw "Source and/or target owner is invalid!"; + } + + var sourceIndex = edge.source.edges.indexOf(edge); + var targetIndex = edge.target.edges.indexOf(edge); + if (!(sourceIndex > -1 && targetIndex > -1)) { + throw "Source and/or target doesn't know this edge!"; + } + + edge.source.edges.splice(sourceIndex, 1); + + if (edge.target != edge.source) { + edge.target.edges.splice(targetIndex, 1); + } + + var index = edge.source.owner.getEdges().indexOf(edge); + if (index == -1) { + throw "Not in owner's edge list!"; + } + + edge.source.owner.getEdges().splice(index, 1); + } +}; + +LGraph.prototype.updateLeftTop = function () { + var top = Integer.MAX_VALUE; + var left = Integer.MAX_VALUE; + var nodeTop; + var nodeLeft; + var margin; + + var nodes = this.getNodes(); + var s = nodes.length; + + for (var i = 0; i < s; i++) { + var lNode = nodes[i]; + nodeTop = lNode.getTop(); + nodeLeft = lNode.getLeft(); + + if (top > nodeTop) { + top = nodeTop; + } + + if (left > nodeLeft) { + left = nodeLeft; + } + } + + // Do we have any nodes in this graph? + if (top == Integer.MAX_VALUE) { + return null; + } + + if (nodes[0].getParent().paddingLeft != undefined) { + margin = nodes[0].getParent().paddingLeft; + } else { + margin = this.margin; + } + + this.left = left - margin; + this.top = top - margin; + + // Apply the margins and return the result + return new Point(this.left, this.top); +}; + +LGraph.prototype.updateBounds = function (recursive) { + // calculate bounds + var left = Integer.MAX_VALUE; + var right = -Integer.MAX_VALUE; + var top = Integer.MAX_VALUE; + var bottom = -Integer.MAX_VALUE; + var nodeLeft; + var nodeRight; + var nodeTop; + var nodeBottom; + var margin; + + var nodes = this.nodes; + var s = nodes.length; + for (var i = 0; i < s; i++) { + var lNode = nodes[i]; + + if (recursive && lNode.child != null) { + lNode.updateBounds(); + } + nodeLeft = lNode.getLeft(); + nodeRight = lNode.getRight(); + nodeTop = lNode.getTop(); + nodeBottom = lNode.getBottom(); + + if (left > nodeLeft) { + left = nodeLeft; + } + + if (right < nodeRight) { + right = nodeRight; + } + + if (top > nodeTop) { + top = nodeTop; + } + + if (bottom < nodeBottom) { + bottom = nodeBottom; + } + } + + var boundingRect = new RectangleD(left, top, right - left, bottom - top); + if (left == Integer.MAX_VALUE) { + this.left = this.parent.getLeft(); + this.right = this.parent.getRight(); + this.top = this.parent.getTop(); + this.bottom = this.parent.getBottom(); + } + + if (nodes[0].getParent().paddingLeft != undefined) { + margin = nodes[0].getParent().paddingLeft; + } else { + margin = this.margin; + } + + this.left = boundingRect.x - margin; + this.right = boundingRect.x + boundingRect.width + margin; + this.top = boundingRect.y - margin; + this.bottom = boundingRect.y + boundingRect.height + margin; +}; + +LGraph.calculateBounds = function (nodes) { + var left = Integer.MAX_VALUE; + var right = -Integer.MAX_VALUE; + var top = Integer.MAX_VALUE; + var bottom = -Integer.MAX_VALUE; + var nodeLeft; + var nodeRight; + var nodeTop; + var nodeBottom; + + var s = nodes.length; + + for (var i = 0; i < s; i++) { + var lNode = nodes[i]; + nodeLeft = lNode.getLeft(); + nodeRight = lNode.getRight(); + nodeTop = lNode.getTop(); + nodeBottom = lNode.getBottom(); + + if (left > nodeLeft) { + left = nodeLeft; + } + + if (right < nodeRight) { + right = nodeRight; + } + + if (top > nodeTop) { + top = nodeTop; + } + + if (bottom < nodeBottom) { + bottom = nodeBottom; + } + } + + var boundingRect = new RectangleD(left, top, right - left, bottom - top); + + return boundingRect; +}; + +LGraph.prototype.getInclusionTreeDepth = function () { + if (this == this.graphManager.getRoot()) { + return 1; + } else { + return this.parent.getInclusionTreeDepth(); + } +}; + +LGraph.prototype.getEstimatedSize = function () { + if (this.estimatedSize == Integer.MIN_VALUE) { + throw "assert failed"; + } + return this.estimatedSize; +}; + +LGraph.prototype.calcEstimatedSize = function () { + var size = 0; + var nodes = this.nodes; + var s = nodes.length; + + for (var i = 0; i < s; i++) { + var lNode = nodes[i]; + size += lNode.calcEstimatedSize(); + } + + if (size == 0) { + this.estimatedSize = LayoutConstants.EMPTY_COMPOUND_NODE_SIZE; + } else { + this.estimatedSize = size / Math.sqrt(this.nodes.length); + } + + return this.estimatedSize; +}; + +LGraph.prototype.updateConnected = function () { + var self = this; + if (this.nodes.length == 0) { + this.isConnected = true; + return; + } + + var toBeVisited = new List(); + var visited = new HashSet(); + var currentNode = this.nodes[0]; + var neighborEdges; + var currentNeighbor; + var childrenOfNode = currentNode.withChildren(); + childrenOfNode.forEach(function (node) { + toBeVisited.push(node); + }); + + while (!toBeVisited.isEmpty()) { + currentNode = toBeVisited.shift().value(); + visited.add(currentNode); + + // Traverse all neighbors of this node + neighborEdges = currentNode.getEdges(); + var s = neighborEdges.length; + for (var i = 0; i < s; i++) { + var neighborEdge = neighborEdges[i]; + currentNeighbor = neighborEdge.getOtherEndInGraph(currentNode, this); + + // Add unvisited neighbors to the list to visit + if (currentNeighbor != null && !visited.contains(currentNeighbor)) { + var childrenOfNeighbor = currentNeighbor.withChildren(); + + childrenOfNeighbor.forEach(function (node) { + toBeVisited.push(node); + }); + } + } + } + + this.isConnected = false; + + if (visited.size() >= this.nodes.length) { + var noOfVisitedInThisGraph = 0; + + var s = visited.size(); + Object.keys(visited.set).forEach(function (visitedId) { + var visitedNode = visited.set[visitedId]; + if (visitedNode.owner == self) { + noOfVisitedInThisGraph++; + } + }); + + if (noOfVisitedInThisGraph == this.nodes.length) { + this.isConnected = true; + } + } +}; + +module.exports = LGraph; + +},{"./HashSet":17,"./Integer":20,"./LEdge":21,"./LGraphManager":23,"./LGraphObject":24,"./LNode":25,"./LayoutConstants":27,"./Point":28,"./RectangleD":31,"linkedlist-js":1}],23:[function(_dereq_,module,exports){ +'use strict'; + +var LGraph; +var LEdge = _dereq_('./LEdge'); + +function LGraphManager(layout) { + LGraph = _dereq_('./LGraph'); // It may be better to initilize this out of this function but it gives an error (Right-hand side of 'instanceof' is not callable) now. + this.layout = layout; + + this.graphs = []; + this.edges = []; +} + +LGraphManager.prototype.addRoot = function () { + var ngraph = this.layout.newGraph(); + var nnode = this.layout.newNode(null); + var root = this.add(ngraph, nnode); + this.setRootGraph(root); + return this.rootGraph; +}; + +LGraphManager.prototype.add = function (newGraph, parentNode, newEdge, sourceNode, targetNode) { + //there are just 2 parameters are passed then it adds an LGraph else it adds an LEdge + if (newEdge == null && sourceNode == null && targetNode == null) { + if (newGraph == null) { + throw "Graph is null!"; + } + if (parentNode == null) { + throw "Parent node is null!"; + } + if (this.graphs.indexOf(newGraph) > -1) { + throw "Graph already in this graph mgr!"; + } + + this.graphs.push(newGraph); + + if (newGraph.parent != null) { + throw "Already has a parent!"; + } + if (parentNode.child != null) { + throw "Already has a child!"; + } + + newGraph.parent = parentNode; + parentNode.child = newGraph; + + return newGraph; + } else { + //change the order of the parameters + targetNode = newEdge; + sourceNode = parentNode; + newEdge = newGraph; + var sourceGraph = sourceNode.getOwner(); + var targetGraph = targetNode.getOwner(); + + if (!(sourceGraph != null && sourceGraph.getGraphManager() == this)) { + throw "Source not in this graph mgr!"; + } + if (!(targetGraph != null && targetGraph.getGraphManager() == this)) { + throw "Target not in this graph mgr!"; + } + + if (sourceGraph == targetGraph) { + newEdge.isInterGraph = false; + return sourceGraph.add(newEdge, sourceNode, targetNode); + } else { + newEdge.isInterGraph = true; + + // set source and target + newEdge.source = sourceNode; + newEdge.target = targetNode; + + // add edge to inter-graph edge list + if (this.edges.indexOf(newEdge) > -1) { + throw "Edge already in inter-graph edge list!"; + } + + this.edges.push(newEdge); + + // add edge to source and target incidency lists + if (!(newEdge.source != null && newEdge.target != null)) { + throw "Edge source and/or target is null!"; + } + + if (!(newEdge.source.edges.indexOf(newEdge) == -1 && newEdge.target.edges.indexOf(newEdge) == -1)) { + throw "Edge already in source and/or target incidency list!"; + } + + newEdge.source.edges.push(newEdge); + newEdge.target.edges.push(newEdge); + + return newEdge; + } + } +}; + +LGraphManager.prototype.remove = function (lObj) { + if (lObj instanceof LGraph) { + var graph = lObj; + if (graph.getGraphManager() != this) { + throw "Graph not in this graph mgr"; + } + if (!(graph == this.rootGraph || graph.parent != null && graph.parent.graphManager == this)) { + throw "Invalid parent node!"; + } + + // first the edges (make a copy to do it safely) + var edgesToBeRemoved = []; + + edgesToBeRemoved = edgesToBeRemoved.concat(graph.getEdges()); + + var edge; + var s = edgesToBeRemoved.length; + for (var i = 0; i < s; i++) { + edge = edgesToBeRemoved[i]; + graph.remove(edge); + } + + // then the nodes (make a copy to do it safely) + var nodesToBeRemoved = []; + + nodesToBeRemoved = nodesToBeRemoved.concat(graph.getNodes()); + + var node; + s = nodesToBeRemoved.length; + for (var i = 0; i < s; i++) { + node = nodesToBeRemoved[i]; + graph.remove(node); + } + + // check if graph is the root + if (graph == this.rootGraph) { + this.setRootGraph(null); + } + + // now remove the graph itself + var index = this.graphs.indexOf(graph); + this.graphs.splice(index, 1); + + // also reset the parent of the graph + graph.parent = null; + } else if (lObj instanceof LEdge) { + edge = lObj; + if (edge == null) { + throw "Edge is null!"; + } + if (!edge.isInterGraph) { + throw "Not an inter-graph edge!"; + } + if (!(edge.source != null && edge.target != null)) { + throw "Source and/or target is null!"; + } + + // remove edge from source and target nodes' incidency lists + + if (!(edge.source.edges.indexOf(edge) != -1 && edge.target.edges.indexOf(edge) != -1)) { + throw "Source and/or target doesn't know this edge!"; + } + + var index = edge.source.edges.indexOf(edge); + edge.source.edges.splice(index, 1); + index = edge.target.edges.indexOf(edge); + edge.target.edges.splice(index, 1); + + // remove edge from owner graph manager's inter-graph edge list + + if (!(edge.source.owner != null && edge.source.owner.getGraphManager() != null)) { + throw "Edge owner graph or owner graph manager is null!"; + } + if (edge.source.owner.getGraphManager().edges.indexOf(edge) == -1) { + throw "Not in owner graph manager's edge list!"; + } + + var index = edge.source.owner.getGraphManager().edges.indexOf(edge); + edge.source.owner.getGraphManager().edges.splice(index, 1); + } +}; + +LGraphManager.prototype.updateBounds = function () { + this.rootGraph.updateBounds(true); +}; + +LGraphManager.prototype.getGraphs = function () { + return this.graphs; +}; + +LGraphManager.prototype.getAllNodes = function () { + if (this.allNodes == null) { + var nodeList = []; + var graphs = this.getGraphs(); + var s = graphs.length; + for (var i = 0; i < s; i++) { + nodeList = nodeList.concat(graphs[i].getNodes()); + } + this.allNodes = nodeList; + } + return this.allNodes; +}; + +LGraphManager.prototype.resetAllNodes = function () { + this.allNodes = null; +}; + +LGraphManager.prototype.resetAllEdges = function () { + this.allEdges = null; +}; + +LGraphManager.prototype.resetAllNodesToApplyGravitation = function () { + this.allNodesToApplyGravitation = null; +}; + +LGraphManager.prototype.getAllEdges = function () { + if (this.allEdges == null) { + var edgeList = []; + var graphs = this.getGraphs(); + var s = graphs.length; + for (var i = 0; i < graphs.length; i++) { + edgeList = edgeList.concat(graphs[i].getEdges()); + } + + edgeList = edgeList.concat(this.edges); + + this.allEdges = edgeList; + } + return this.allEdges; +}; + +LGraphManager.prototype.getAllNodesToApplyGravitation = function () { + return this.allNodesToApplyGravitation; +}; + +LGraphManager.prototype.setAllNodesToApplyGravitation = function (nodeList) { + if (this.allNodesToApplyGravitation != null) { + throw "assert failed"; + } + + this.allNodesToApplyGravitation = nodeList; +}; + +LGraphManager.prototype.getRoot = function () { + return this.rootGraph; +}; + +LGraphManager.prototype.setRootGraph = function (graph) { + if (graph.getGraphManager() != this) { + throw "Root not in this graph mgr!"; + } + + this.rootGraph = graph; + // root graph must have a root node associated with it for convenience + if (graph.parent == null) { + graph.parent = this.layout.newNode("Root node"); + } +}; + +LGraphManager.prototype.getLayout = function () { + return this.layout; +}; + +LGraphManager.prototype.isOneAncestorOfOther = function (firstNode, secondNode) { + if (!(firstNode != null && secondNode != null)) { + throw "assert failed"; + } + + if (firstNode == secondNode) { + return true; + } + // Is second node an ancestor of the first one? + var ownerGraph = firstNode.getOwner(); + var parentNode; + + do { + parentNode = ownerGraph.getParent(); + + if (parentNode == null) { + break; + } + + if (parentNode == secondNode) { + return true; + } + + ownerGraph = parentNode.getOwner(); + if (ownerGraph == null) { + break; + } + } while (true); + // Is first node an ancestor of the second one? + ownerGraph = secondNode.getOwner(); + + do { + parentNode = ownerGraph.getParent(); + + if (parentNode == null) { + break; + } + + if (parentNode == firstNode) { + return true; + } + + ownerGraph = parentNode.getOwner(); + if (ownerGraph == null) { + break; + } + } while (true); + + return false; +}; + +LGraphManager.prototype.calcLowestCommonAncestors = function () { + var edge; + var sourceNode; + var targetNode; + var sourceAncestorGraph; + var targetAncestorGraph; + + var edges = this.getAllEdges(); + var s = edges.length; + for (var i = 0; i < s; i++) { + edge = edges[i]; + + sourceNode = edge.source; + targetNode = edge.target; + edge.lca = null; + edge.sourceInLca = sourceNode; + edge.targetInLca = targetNode; + + if (sourceNode == targetNode) { + edge.lca = sourceNode.getOwner(); + continue; + } + + sourceAncestorGraph = sourceNode.getOwner(); + + while (edge.lca == null) { + edge.targetInLca = targetNode; + targetAncestorGraph = targetNode.getOwner(); + + while (edge.lca == null) { + if (targetAncestorGraph == sourceAncestorGraph) { + edge.lca = targetAncestorGraph; + break; + } + + if (targetAncestorGraph == this.rootGraph) { + break; + } + + if (edge.lca != null) { + throw "assert failed"; + } + edge.targetInLca = targetAncestorGraph.getParent(); + targetAncestorGraph = edge.targetInLca.getOwner(); + } + + if (sourceAncestorGraph == this.rootGraph) { + break; + } + + if (edge.lca == null) { + edge.sourceInLca = sourceAncestorGraph.getParent(); + sourceAncestorGraph = edge.sourceInLca.getOwner(); + } + } + + if (edge.lca == null) { + throw "assert failed"; + } + } +}; + +LGraphManager.prototype.calcLowestCommonAncestor = function (firstNode, secondNode) { + if (firstNode == secondNode) { + return firstNode.getOwner(); + } + var firstOwnerGraph = firstNode.getOwner(); + + do { + if (firstOwnerGraph == null) { + break; + } + var secondOwnerGraph = secondNode.getOwner(); + + do { + if (secondOwnerGraph == null) { + break; + } + + if (secondOwnerGraph == firstOwnerGraph) { + return secondOwnerGraph; + } + secondOwnerGraph = secondOwnerGraph.getParent().getOwner(); + } while (true); + + firstOwnerGraph = firstOwnerGraph.getParent().getOwner(); + } while (true); + + return firstOwnerGraph; +}; + +LGraphManager.prototype.calcInclusionTreeDepths = function (graph, depth) { + if (graph == null && depth == null) { + graph = this.rootGraph; + depth = 1; + } + var node; + + var nodes = graph.getNodes(); + var s = nodes.length; + for (var i = 0; i < s; i++) { + node = nodes[i]; + node.inclusionTreeDepth = depth; + + if (node.child != null) { + this.calcInclusionTreeDepths(node.child, depth + 1); + } + } +}; + +LGraphManager.prototype.includesInvalidEdge = function () { + var edge; + + var s = this.edges.length; + for (var i = 0; i < s; i++) { + edge = this.edges[i]; + + if (this.isOneAncestorOfOther(edge.source, edge.target)) { + return true; + } + } + return false; +}; + +module.exports = LGraphManager; + +},{"./LEdge":21,"./LGraph":22}],24:[function(_dereq_,module,exports){ +"use strict"; + +function LGraphObject(vGraphObject) { + this.vGraphObject = vGraphObject; +} + +module.exports = LGraphObject; + +},{}],25:[function(_dereq_,module,exports){ +'use strict'; + +var LGraphObject = _dereq_('./LGraphObject'); +var Integer = _dereq_('./Integer'); +var RectangleD = _dereq_('./RectangleD'); +var LayoutConstants = _dereq_('./LayoutConstants'); +var RandomSeed = _dereq_('./RandomSeed'); +var PointD = _dereq_('./PointD'); +var HashSet = _dereq_('./HashSet'); + +function LNode(gm, loc, size, vNode) { + //Alternative constructor 1 : LNode(LGraphManager gm, Point loc, Dimension size, Object vNode) + if (size == null && vNode == null) { + vNode = loc; + } + + LGraphObject.call(this, vNode); + + //Alternative constructor 2 : LNode(Layout layout, Object vNode) + if (gm.graphManager != null) gm = gm.graphManager; + + this.estimatedSize = Integer.MIN_VALUE; + this.inclusionTreeDepth = Integer.MAX_VALUE; + this.vGraphObject = vNode; + this.edges = []; + this.graphManager = gm; + + if (size != null && loc != null) this.rect = new RectangleD(loc.x, loc.y, size.width, size.height);else this.rect = new RectangleD(); +} + +LNode.prototype = Object.create(LGraphObject.prototype); +for (var prop in LGraphObject) { + LNode[prop] = LGraphObject[prop]; +} + +LNode.prototype.getEdges = function () { + return this.edges; +}; + +LNode.prototype.getChild = function () { + return this.child; +}; + +LNode.prototype.getOwner = function () { + // if (this.owner != null) { + // if (!(this.owner == null || this.owner.getNodes().indexOf(this) > -1)) { + // throw "assert failed"; + // } + // } + + return this.owner; +}; + +LNode.prototype.getWidth = function () { + return this.rect.width; +}; + +LNode.prototype.setWidth = function (width) { + this.rect.width = width; +}; + +LNode.prototype.getHeight = function () { + return this.rect.height; +}; + +LNode.prototype.setHeight = function (height) { + this.rect.height = height; +}; + +LNode.prototype.getCenterX = function () { + return this.rect.x + this.rect.width / 2; +}; + +LNode.prototype.getCenterY = function () { + return this.rect.y + this.rect.height / 2; +}; + +LNode.prototype.getCenter = function () { + return new PointD(this.rect.x + this.rect.width / 2, this.rect.y + this.rect.height / 2); +}; + +LNode.prototype.getLocation = function () { + return new PointD(this.rect.x, this.rect.y); +}; + +LNode.prototype.getRect = function () { + return this.rect; +}; + +LNode.prototype.getDiagonal = function () { + return Math.sqrt(this.rect.width * this.rect.width + this.rect.height * this.rect.height); +}; + +LNode.prototype.setRect = function (upperLeft, dimension) { + this.rect.x = upperLeft.x; + this.rect.y = upperLeft.y; + this.rect.width = dimension.width; + this.rect.height = dimension.height; +}; + +LNode.prototype.setCenter = function (cx, cy) { + this.rect.x = cx - this.rect.width / 2; + this.rect.y = cy - this.rect.height / 2; +}; + +LNode.prototype.setLocation = function (x, y) { + this.rect.x = x; + this.rect.y = y; +}; + +LNode.prototype.moveBy = function (dx, dy) { + this.rect.x += dx; + this.rect.y += dy; +}; + +LNode.prototype.getEdgeListToNode = function (to) { + var edgeList = []; + var edge; + var self = this; + + self.edges.forEach(function (edge) { + + if (edge.target == to) { + if (edge.source != self) throw "Incorrect edge source!"; + + edgeList.push(edge); + } + }); + + return edgeList; +}; + +LNode.prototype.getEdgesBetween = function (other) { + var edgeList = []; + var edge; + + var self = this; + self.edges.forEach(function (edge) { + + if (!(edge.source == self || edge.target == self)) throw "Incorrect edge source and/or target"; + + if (edge.target == other || edge.source == other) { + edgeList.push(edge); + } + }); + + return edgeList; +}; + +LNode.prototype.getNeighborsList = function () { + var neighbors = new HashSet(); + var edge; + + var self = this; + self.edges.forEach(function (edge) { + + if (edge.source == self) { + neighbors.add(edge.target); + } else { + if (edge.target != self) { + throw "Incorrect incidency!"; + } + + neighbors.add(edge.source); + } + }); + + return neighbors; +}; + +LNode.prototype.withChildren = function () { + var withNeighborsList = new Set(); + var childNode; + var children; + + withNeighborsList.add(this); + + if (this.child != null) { + var nodes = this.child.getNodes(); + for (var i = 0; i < nodes.length; i++) { + childNode = nodes[i]; + children = childNode.withChildren(); + children.forEach(function (node) { + withNeighborsList.add(node); + }); + } + } + + return withNeighborsList; +}; + +LNode.prototype.getNoOfChildren = function () { + var noOfChildren = 0; + var childNode; + + if (this.child == null) { + noOfChildren = 1; + } else { + var nodes = this.child.getNodes(); + for (var i = 0; i < nodes.length; i++) { + childNode = nodes[i]; + + noOfChildren += childNode.getNoOfChildren(); + } + } + + if (noOfChildren == 0) { + noOfChildren = 1; + } + return noOfChildren; +}; + +LNode.prototype.getEstimatedSize = function () { + if (this.estimatedSize == Integer.MIN_VALUE) { + throw "assert failed"; + } + return this.estimatedSize; +}; + +LNode.prototype.calcEstimatedSize = function () { + if (this.child == null) { + return this.estimatedSize = (this.rect.width + this.rect.height) / 2; + } else { + this.estimatedSize = this.child.calcEstimatedSize(); + this.rect.width = this.estimatedSize; + this.rect.height = this.estimatedSize; + + return this.estimatedSize; + } +}; + +LNode.prototype.scatter = function () { + var randomCenterX; + var randomCenterY; + + var minX = -LayoutConstants.INITIAL_WORLD_BOUNDARY; + var maxX = LayoutConstants.INITIAL_WORLD_BOUNDARY; + randomCenterX = LayoutConstants.WORLD_CENTER_X + RandomSeed.nextDouble() * (maxX - minX) + minX; + + var minY = -LayoutConstants.INITIAL_WORLD_BOUNDARY; + var maxY = LayoutConstants.INITIAL_WORLD_BOUNDARY; + randomCenterY = LayoutConstants.WORLD_CENTER_Y + RandomSeed.nextDouble() * (maxY - minY) + minY; + + this.rect.x = randomCenterX; + this.rect.y = randomCenterY; +}; + +LNode.prototype.updateBounds = function () { + if (this.getChild() == null) { + throw "assert failed"; + } + if (this.getChild().getNodes().length != 0) { + // wrap the children nodes by re-arranging the boundaries + var childGraph = this.getChild(); + childGraph.updateBounds(true); + + this.rect.x = childGraph.getLeft(); + this.rect.y = childGraph.getTop(); + + this.setWidth(childGraph.getRight() - childGraph.getLeft()); + this.setHeight(childGraph.getBottom() - childGraph.getTop()); + + // Update compound bounds considering its label properties + if (LayoutConstants.NODE_DIMENSIONS_INCLUDE_LABELS) { + + var width = childGraph.getRight() - childGraph.getLeft(); + var height = childGraph.getBottom() - childGraph.getTop(); + + if (this.labelWidth > width) { + this.rect.x -= (this.labelWidth - width) / 2; + this.setWidth(this.labelWidth); + } + + if (this.labelHeight > height) { + if (this.labelPos == "center") { + this.rect.y -= (this.labelHeight - height) / 2; + } else if (this.labelPos == "top") { + this.rect.y -= this.labelHeight - height; + } + this.setHeight(this.labelHeight); + } + } + } +}; + +LNode.prototype.getInclusionTreeDepth = function () { + if (this.inclusionTreeDepth == Integer.MAX_VALUE) { + throw "assert failed"; + } + return this.inclusionTreeDepth; +}; + +LNode.prototype.transform = function (trans) { + var left = this.rect.x; + + if (left > LayoutConstants.WORLD_BOUNDARY) { + left = LayoutConstants.WORLD_BOUNDARY; + } else if (left < -LayoutConstants.WORLD_BOUNDARY) { + left = -LayoutConstants.WORLD_BOUNDARY; + } + + var top = this.rect.y; + + if (top > LayoutConstants.WORLD_BOUNDARY) { + top = LayoutConstants.WORLD_BOUNDARY; + } else if (top < -LayoutConstants.WORLD_BOUNDARY) { + top = -LayoutConstants.WORLD_BOUNDARY; + } + + var leftTop = new PointD(left, top); + var vLeftTop = trans.inverseTransformPoint(leftTop); + + this.setLocation(vLeftTop.x, vLeftTop.y); +}; + +LNode.prototype.getLeft = function () { + return this.rect.x; +}; + +LNode.prototype.getRight = function () { + return this.rect.x + this.rect.width; +}; + +LNode.prototype.getTop = function () { + return this.rect.y; +}; + +LNode.prototype.getBottom = function () { + return this.rect.y + this.rect.height; +}; + +LNode.prototype.getParent = function () { + if (this.owner == null) { + return null; + } + + return this.owner.getParent(); +}; + +module.exports = LNode; + +},{"./HashSet":17,"./Integer":20,"./LGraphObject":24,"./LayoutConstants":27,"./PointD":29,"./RandomSeed":30,"./RectangleD":31}],26:[function(_dereq_,module,exports){ +'use strict'; + +var LayoutConstants = _dereq_('./LayoutConstants'); +var HashMap = _dereq_('./HashMap'); +var LGraphManager = _dereq_('./LGraphManager'); +var LNode = _dereq_('./LNode'); +var LEdge = _dereq_('./LEdge'); +var LGraph = _dereq_('./LGraph'); +var PointD = _dereq_('./PointD'); +var Transform = _dereq_('./Transform'); +var Emitter = _dereq_('./Emitter'); +var HashSet = _dereq_('./HashSet'); + +function Layout(isRemoteUse) { + Emitter.call(this); + + //Layout Quality: 0:proof, 1:default, 2:draft + this.layoutQuality = LayoutConstants.DEFAULT_QUALITY; + //Whether layout should create bendpoints as needed or not + this.createBendsAsNeeded = LayoutConstants.DEFAULT_CREATE_BENDS_AS_NEEDED; + //Whether layout should be incremental or not + this.incremental = LayoutConstants.DEFAULT_INCREMENTAL; + //Whether we animate from before to after layout node positions + this.animationOnLayout = LayoutConstants.DEFAULT_ANIMATION_ON_LAYOUT; + //Whether we animate the layout process or not + this.animationDuringLayout = LayoutConstants.DEFAULT_ANIMATION_DURING_LAYOUT; + //Number iterations that should be done between two successive animations + this.animationPeriod = LayoutConstants.DEFAULT_ANIMATION_PERIOD; + /** + * Whether or not leaf nodes (non-compound nodes) are of uniform sizes. When + * they are, both spring and repulsion forces between two leaf nodes can be + * calculated without the expensive clipping point calculations, resulting + * in major speed-up. + */ + this.uniformLeafNodeSizes = LayoutConstants.DEFAULT_UNIFORM_LEAF_NODE_SIZES; + /** + * This is used for creation of bendpoints by using dummy nodes and edges. + * Maps an LEdge to its dummy bendpoint path. + */ + this.edgeToDummyNodes = new HashMap(); + this.graphManager = new LGraphManager(this); + this.isLayoutFinished = false; + this.isSubLayout = false; + this.isRemoteUse = false; + + if (isRemoteUse != null) { + this.isRemoteUse = isRemoteUse; + } +} + +Layout.RANDOM_SEED = 1; + +Layout.prototype = Object.create(Emitter.prototype); + +Layout.prototype.getGraphManager = function () { + return this.graphManager; +}; + +Layout.prototype.getAllNodes = function () { + return this.graphManager.getAllNodes(); +}; + +Layout.prototype.getAllEdges = function () { + return this.graphManager.getAllEdges(); +}; + +Layout.prototype.getAllNodesToApplyGravitation = function () { + return this.graphManager.getAllNodesToApplyGravitation(); +}; + +Layout.prototype.newGraphManager = function () { + var gm = new LGraphManager(this); + this.graphManager = gm; + return gm; +}; + +Layout.prototype.newGraph = function (vGraph) { + return new LGraph(null, this.graphManager, vGraph); +}; + +Layout.prototype.newNode = function (vNode) { + return new LNode(this.graphManager, vNode); +}; + +Layout.prototype.newEdge = function (vEdge) { + return new LEdge(null, null, vEdge); +}; + +Layout.prototype.checkLayoutSuccess = function () { + return this.graphManager.getRoot() == null || this.graphManager.getRoot().getNodes().length == 0 || this.graphManager.includesInvalidEdge(); +}; + +Layout.prototype.runLayout = function () { + this.isLayoutFinished = false; + + if (this.tilingPreLayout) { + this.tilingPreLayout(); + } + + this.initParameters(); + var isLayoutSuccessfull; + + if (this.checkLayoutSuccess()) { + isLayoutSuccessfull = false; + } else { + isLayoutSuccessfull = this.layout(); + } + + if (LayoutConstants.ANIMATE === 'during') { + // If this is a 'during' layout animation. Layout is not finished yet. + // We need to perform these in index.js when layout is really finished. + return false; + } + + if (isLayoutSuccessfull) { + if (!this.isSubLayout) { + this.doPostLayout(); + } + } + + if (this.tilingPostLayout) { + this.tilingPostLayout(); + } + + this.isLayoutFinished = true; + + return isLayoutSuccessfull; +}; + +/** + * This method performs the operations required after layout. + */ +Layout.prototype.doPostLayout = function () { + //assert !isSubLayout : "Should not be called on sub-layout!"; + // Propagate geometric changes to v-level objects + if (!this.incremental) { + this.transform(); + } + this.update(); +}; + +/** + * This method updates the geometry of the target graph according to + * calculated layout. + */ +Layout.prototype.update2 = function () { + // update bend points + if (this.createBendsAsNeeded) { + this.createBendpointsFromDummyNodes(); + + // reset all edges, since the topology has changed + this.graphManager.resetAllEdges(); + } + + // perform edge, node and root updates if layout is not called + // remotely + if (!this.isRemoteUse) { + // update all edges + var edge; + var allEdges = this.graphManager.getAllEdges(); + for (var i = 0; i < allEdges.length; i++) { + edge = allEdges[i]; + // this.update(edge); + } + + // recursively update nodes + var node; + var nodes = this.graphManager.getRoot().getNodes(); + for (var i = 0; i < nodes.length; i++) { + node = nodes[i]; + // this.update(node); + } + + // update root graph + this.update(this.graphManager.getRoot()); + } +}; + +Layout.prototype.update = function (obj) { + if (obj == null) { + this.update2(); + } else if (obj instanceof LNode) { + var node = obj; + if (node.getChild() != null) { + // since node is compound, recursively update child nodes + var nodes = node.getChild().getNodes(); + for (var i = 0; i < nodes.length; i++) { + update(nodes[i]); + } + } + + // if the l-level node is associated with a v-level graph object, + // then it is assumed that the v-level node implements the + // interface Updatable. + if (node.vGraphObject != null) { + // cast to Updatable without any type check + var vNode = node.vGraphObject; + + // call the update method of the interface + vNode.update(node); + } + } else if (obj instanceof LEdge) { + var edge = obj; + // if the l-level edge is associated with a v-level graph object, + // then it is assumed that the v-level edge implements the + // interface Updatable. + + if (edge.vGraphObject != null) { + // cast to Updatable without any type check + var vEdge = edge.vGraphObject; + + // call the update method of the interface + vEdge.update(edge); + } + } else if (obj instanceof LGraph) { + var graph = obj; + // if the l-level graph is associated with a v-level graph object, + // then it is assumed that the v-level object implements the + // interface Updatable. + + if (graph.vGraphObject != null) { + // cast to Updatable without any type check + var vGraph = graph.vGraphObject; + + // call the update method of the interface + vGraph.update(graph); + } + } +}; + +/** + * This method is used to set all layout parameters to default values + * determined at compile time. + */ +Layout.prototype.initParameters = function () { + if (!this.isSubLayout) { + this.layoutQuality = LayoutConstants.DEFAULT_QUALITY; + this.animationDuringLayout = LayoutConstants.DEFAULT_ANIMATION_DURING_LAYOUT; + this.animationPeriod = LayoutConstants.DEFAULT_ANIMATION_PERIOD; + this.animationOnLayout = LayoutConstants.DEFAULT_ANIMATION_ON_LAYOUT; + this.incremental = LayoutConstants.DEFAULT_INCREMENTAL; + this.createBendsAsNeeded = LayoutConstants.DEFAULT_CREATE_BENDS_AS_NEEDED; + this.uniformLeafNodeSizes = LayoutConstants.DEFAULT_UNIFORM_LEAF_NODE_SIZES; + } + + if (this.animationDuringLayout) { + this.animationOnLayout = false; + } +}; + +Layout.prototype.transform = function (newLeftTop) { + if (newLeftTop == undefined) { + this.transform(new PointD(0, 0)); + } else { + // create a transformation object (from Eclipse to layout). When an + // inverse transform is applied, we get upper-left coordinate of the + // drawing or the root graph at given input coordinate (some margins + // already included in calculation of left-top). + + var trans = new Transform(); + var leftTop = this.graphManager.getRoot().updateLeftTop(); + + if (leftTop != null) { + trans.setWorldOrgX(newLeftTop.x); + trans.setWorldOrgY(newLeftTop.y); + + trans.setDeviceOrgX(leftTop.x); + trans.setDeviceOrgY(leftTop.y); + + var nodes = this.getAllNodes(); + var node; + + for (var i = 0; i < nodes.length; i++) { + node = nodes[i]; + node.transform(trans); + } + } + } +}; + +Layout.prototype.positionNodesRandomly = function (graph) { + + if (graph == undefined) { + //assert !this.incremental; + this.positionNodesRandomly(this.getGraphManager().getRoot()); + this.getGraphManager().getRoot().updateBounds(true); + } else { + var lNode; + var childGraph; + + var nodes = graph.getNodes(); + for (var i = 0; i < nodes.length; i++) { + lNode = nodes[i]; + childGraph = lNode.getChild(); + + if (childGraph == null) { + lNode.scatter(); + } else if (childGraph.getNodes().length == 0) { + lNode.scatter(); + } else { + this.positionNodesRandomly(childGraph); + lNode.updateBounds(); + } + } + } +}; + +/** + * This method returns a list of trees where each tree is represented as a + * list of l-nodes. The method returns a list of size 0 when: + * - The graph is not flat or + * - One of the component(s) of the graph is not a tree. + */ +Layout.prototype.getFlatForest = function () { + var flatForest = []; + var isForest = true; + + // Quick reference for all nodes in the graph manager associated with + // this layout. The list should not be changed. + var allNodes = this.graphManager.getRoot().getNodes(); + + // First be sure that the graph is flat + var isFlat = true; + + for (var i = 0; i < allNodes.length; i++) { + if (allNodes[i].getChild() != null) { + isFlat = false; + } + } + + // Return empty forest if the graph is not flat. + if (!isFlat) { + return flatForest; + } + + // Run BFS for each component of the graph. + + var visited = new HashSet(); + var toBeVisited = []; + var parents = new HashMap(); + var unProcessedNodes = []; + + unProcessedNodes = unProcessedNodes.concat(allNodes); + + // Each iteration of this loop finds a component of the graph and + // decides whether it is a tree or not. If it is a tree, adds it to the + // forest and continued with the next component. + + while (unProcessedNodes.length > 0 && isForest) { + toBeVisited.push(unProcessedNodes[0]); + + // Start the BFS. Each iteration of this loop visits a node in a + // BFS manner. + while (toBeVisited.length > 0 && isForest) { + //pool operation + var currentNode = toBeVisited[0]; + toBeVisited.splice(0, 1); + visited.add(currentNode); + + // Traverse all neighbors of this node + var neighborEdges = currentNode.getEdges(); + + for (var i = 0; i < neighborEdges.length; i++) { + var currentNeighbor = neighborEdges[i].getOtherEnd(currentNode); + + // If BFS is not growing from this neighbor. + if (parents.get(currentNode) != currentNeighbor) { + // We haven't previously visited this neighbor. + if (!visited.contains(currentNeighbor)) { + toBeVisited.push(currentNeighbor); + parents.put(currentNeighbor, currentNode); + } + // Since we have previously visited this neighbor and + // this neighbor is not parent of currentNode, given + // graph contains a component that is not tree, hence + // it is not a forest. + else { + isForest = false; + break; + } + } + } + } + + // The graph contains a component that is not a tree. Empty + // previously found trees. The method will end. + if (!isForest) { + flatForest = []; + } + // Save currently visited nodes as a tree in our forest. Reset + // visited and parents lists. Continue with the next component of + // the graph, if any. + else { + var temp = []; + visited.addAllTo(temp); + flatForest.push(temp); + //flatForest = flatForest.concat(temp); + //unProcessedNodes.removeAll(visited); + for (var i = 0; i < temp.length; i++) { + var value = temp[i]; + var index = unProcessedNodes.indexOf(value); + if (index > -1) { + unProcessedNodes.splice(index, 1); + } + } + visited = new HashSet(); + parents = new HashMap(); + } + } + + return flatForest; +}; + +/** + * This method creates dummy nodes (an l-level node with minimal dimensions) + * for the given edge (one per bendpoint). The existing l-level structure + * is updated accordingly. + */ +Layout.prototype.createDummyNodesForBendpoints = function (edge) { + var dummyNodes = []; + var prev = edge.source; + + var graph = this.graphManager.calcLowestCommonAncestor(edge.source, edge.target); + + for (var i = 0; i < edge.bendpoints.length; i++) { + // create new dummy node + var dummyNode = this.newNode(null); + dummyNode.setRect(new Point(0, 0), new Dimension(1, 1)); + + graph.add(dummyNode); + + // create new dummy edge between prev and dummy node + var dummyEdge = this.newEdge(null); + this.graphManager.add(dummyEdge, prev, dummyNode); + + dummyNodes.add(dummyNode); + prev = dummyNode; + } + + var dummyEdge = this.newEdge(null); + this.graphManager.add(dummyEdge, prev, edge.target); + + this.edgeToDummyNodes.put(edge, dummyNodes); + + // remove real edge from graph manager if it is inter-graph + if (edge.isInterGraph()) { + this.graphManager.remove(edge); + } + // else, remove the edge from the current graph + else { + graph.remove(edge); + } + + return dummyNodes; +}; + +/** + * This method creates bendpoints for edges from the dummy nodes + * at l-level. + */ +Layout.prototype.createBendpointsFromDummyNodes = function () { + var edges = []; + edges = edges.concat(this.graphManager.getAllEdges()); + edges = this.edgeToDummyNodes.keySet().concat(edges); + + for (var k = 0; k < edges.length; k++) { + var lEdge = edges[k]; + + if (lEdge.bendpoints.length > 0) { + var path = this.edgeToDummyNodes.get(lEdge); + + for (var i = 0; i < path.length; i++) { + var dummyNode = path[i]; + var p = new PointD(dummyNode.getCenterX(), dummyNode.getCenterY()); + + // update bendpoint's location according to dummy node + var ebp = lEdge.bendpoints.get(i); + ebp.x = p.x; + ebp.y = p.y; + + // remove the dummy node, dummy edges incident with this + // dummy node is also removed (within the remove method) + dummyNode.getOwner().remove(dummyNode); + } + + // add the real edge to graph + this.graphManager.add(lEdge, lEdge.source, lEdge.target); + } + } +}; + +Layout.transform = function (sliderValue, defaultValue, minDiv, maxMul) { + if (minDiv != undefined && maxMul != undefined) { + var value = defaultValue; + + if (sliderValue <= 50) { + var minValue = defaultValue / minDiv; + value -= (defaultValue - minValue) / 50 * (50 - sliderValue); + } else { + var maxValue = defaultValue * maxMul; + value += (maxValue - defaultValue) / 50 * (sliderValue - 50); + } + + return value; + } else { + var a, b; + + if (sliderValue <= 50) { + a = 9.0 * defaultValue / 500.0; + b = defaultValue / 10.0; + } else { + a = 9.0 * defaultValue / 50.0; + b = -8 * defaultValue; + } + + return a * sliderValue + b; + } +}; + +/** + * This method finds and returns the center of the given nodes, assuming + * that the given nodes form a tree in themselves. + */ +Layout.findCenterOfTree = function (nodes) { + var list = []; + list = list.concat(nodes); + + var removedNodes = []; + var remainingDegrees = new HashMap(); + var foundCenter = false; + var centerNode = null; + + if (list.length == 1 || list.length == 2) { + foundCenter = true; + centerNode = list[0]; + } + + for (var i = 0; i < list.length; i++) { + var node = list[i]; + var degree = node.getNeighborsList().size(); + remainingDegrees.put(node, node.getNeighborsList().size()); + + if (degree == 1) { + removedNodes.push(node); + } + } + + var tempList = []; + tempList = tempList.concat(removedNodes); + + while (!foundCenter) { + var tempList2 = []; + tempList2 = tempList2.concat(tempList); + tempList = []; + + for (var i = 0; i < list.length; i++) { + var node = list[i]; + + var index = list.indexOf(node); + if (index >= 0) { + list.splice(index, 1); + } + + var neighbours = node.getNeighborsList(); + + Object.keys(neighbours.set).forEach(function (j) { + var neighbour = neighbours.set[j]; + if (removedNodes.indexOf(neighbour) < 0) { + var otherDegree = remainingDegrees.get(neighbour); + var newDegree = otherDegree - 1; + + if (newDegree == 1) { + tempList.push(neighbour); + } + + remainingDegrees.put(neighbour, newDegree); + } + }); + } + + removedNodes = removedNodes.concat(tempList); + + if (list.length == 1 || list.length == 2) { + foundCenter = true; + centerNode = list[0]; + } + } + + return centerNode; +}; + +/** + * During the coarsening process, this layout may be referenced by two graph managers + * this setter function grants access to change the currently being used graph manager + */ +Layout.prototype.setGraphManager = function (gm) { + this.graphManager = gm; +}; + +module.exports = Layout; + +},{"./Emitter":11,"./HashMap":16,"./HashSet":17,"./LEdge":21,"./LGraph":22,"./LGraphManager":23,"./LNode":25,"./LayoutConstants":27,"./PointD":29,"./Transform":32}],27:[function(_dereq_,module,exports){ +"use strict"; + +function LayoutConstants() {} + +/** + * Layout Quality + */ +LayoutConstants.PROOF_QUALITY = 0; +LayoutConstants.DEFAULT_QUALITY = 1; +LayoutConstants.DRAFT_QUALITY = 2; + +/** + * Default parameters + */ +LayoutConstants.DEFAULT_CREATE_BENDS_AS_NEEDED = false; +//LayoutConstants.DEFAULT_INCREMENTAL = true; +LayoutConstants.DEFAULT_INCREMENTAL = false; +LayoutConstants.DEFAULT_ANIMATION_ON_LAYOUT = true; +LayoutConstants.DEFAULT_ANIMATION_DURING_LAYOUT = false; +LayoutConstants.DEFAULT_ANIMATION_PERIOD = 50; +LayoutConstants.DEFAULT_UNIFORM_LEAF_NODE_SIZES = false; + +// ----------------------------------------------------------------------------- +// Section: General other constants +// ----------------------------------------------------------------------------- +/* + * Margins of a graph to be applied on bouding rectangle of its contents. We + * assume margins on all four sides to be uniform. + */ +LayoutConstants.DEFAULT_GRAPH_MARGIN = 15; + +/* + * Whether to consider labels in node dimensions or not + */ +LayoutConstants.NODE_DIMENSIONS_INCLUDE_LABELS = false; + +/* + * Default dimension of a non-compound node. + */ +LayoutConstants.SIMPLE_NODE_SIZE = 40; + +/* + * Default dimension of a non-compound node. + */ +LayoutConstants.SIMPLE_NODE_HALF_SIZE = LayoutConstants.SIMPLE_NODE_SIZE / 2; + +/* + * Empty compound node size. When a compound node is empty, its both + * dimensions should be of this value. + */ +LayoutConstants.EMPTY_COMPOUND_NODE_SIZE = 40; + +/* + * Minimum length that an edge should take during layout + */ +LayoutConstants.MIN_EDGE_LENGTH = 1; + +/* + * World boundaries that layout operates on + */ +LayoutConstants.WORLD_BOUNDARY = 1000000; + +/* + * World boundaries that random positioning can be performed with + */ +LayoutConstants.INITIAL_WORLD_BOUNDARY = LayoutConstants.WORLD_BOUNDARY / 1000; + +/* + * Coordinates of the world center + */ +LayoutConstants.WORLD_CENTER_X = 1200; +LayoutConstants.WORLD_CENTER_Y = 900; + +module.exports = LayoutConstants; + +},{}],28:[function(_dereq_,module,exports){ +'use strict'; + +/* + *This class is the javascript implementation of the Point.java class in jdk + */ +function Point(x, y, p) { + this.x = null; + this.y = null; + if (x == null && y == null && p == null) { + this.x = 0; + this.y = 0; + } else if (typeof x == 'number' && typeof y == 'number' && p == null) { + this.x = x; + this.y = y; + } else if (x.constructor.name == 'Point' && y == null && p == null) { + p = x; + this.x = p.x; + this.y = p.y; + } +} + +Point.prototype.getX = function () { + return this.x; +}; + +Point.prototype.getY = function () { + return this.y; +}; + +Point.prototype.getLocation = function () { + return new Point(this.x, this.y); +}; + +Point.prototype.setLocation = function (x, y, p) { + if (x.constructor.name == 'Point' && y == null && p == null) { + p = x; + this.setLocation(p.x, p.y); + } else if (typeof x == 'number' && typeof y == 'number' && p == null) { + //if both parameters are integer just move (x,y) location + if (parseInt(x) == x && parseInt(y) == y) { + this.move(x, y); + } else { + this.x = Math.floor(x + 0.5); + this.y = Math.floor(y + 0.5); + } + } +}; + +Point.prototype.move = function (x, y) { + this.x = x; + this.y = y; +}; + +Point.prototype.translate = function (dx, dy) { + this.x += dx; + this.y += dy; +}; + +Point.prototype.equals = function (obj) { + if (obj.constructor.name == "Point") { + var pt = obj; + return this.x == pt.x && this.y == pt.y; + } + return this == obj; +}; + +Point.prototype.toString = function () { + return new Point().constructor.name + "[x=" + this.x + ",y=" + this.y + "]"; +}; + +module.exports = Point; + +},{}],29:[function(_dereq_,module,exports){ +"use strict"; + +function PointD(x, y) { + if (x == null && y == null) { + this.x = 0; + this.y = 0; + } else { + this.x = x; + this.y = y; + } +} + +PointD.prototype.getX = function () { + return this.x; +}; + +PointD.prototype.getY = function () { + return this.y; +}; + +PointD.prototype.setX = function (x) { + this.x = x; +}; + +PointD.prototype.setY = function (y) { + this.y = y; +}; + +PointD.prototype.getDifference = function (pt) { + return new DimensionD(this.x - pt.x, this.y - pt.y); +}; + +PointD.prototype.getCopy = function () { + return new PointD(this.x, this.y); +}; + +PointD.prototype.translate = function (dim) { + this.x += dim.width; + this.y += dim.height; + return this; +}; + +module.exports = PointD; + +},{}],30:[function(_dereq_,module,exports){ +"use strict"; + +function RandomSeed() {} +RandomSeed.seed = 1; +RandomSeed.x = 0; + +RandomSeed.nextDouble = function () { + RandomSeed.x = Math.sin(RandomSeed.seed++) * 10000; + return RandomSeed.x - Math.floor(RandomSeed.x); +}; + +module.exports = RandomSeed; + +},{}],31:[function(_dereq_,module,exports){ +"use strict"; + +function RectangleD(x, y, width, height) { + this.x = 0; + this.y = 0; + this.width = 0; + this.height = 0; + + if (x != null && y != null && width != null && height != null) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } +} + +RectangleD.prototype.getX = function () { + return this.x; +}; + +RectangleD.prototype.setX = function (x) { + this.x = x; +}; + +RectangleD.prototype.getY = function () { + return this.y; +}; + +RectangleD.prototype.setY = function (y) { + this.y = y; +}; + +RectangleD.prototype.getWidth = function () { + return this.width; +}; + +RectangleD.prototype.setWidth = function (width) { + this.width = width; +}; + +RectangleD.prototype.getHeight = function () { + return this.height; +}; + +RectangleD.prototype.setHeight = function (height) { + this.height = height; +}; + +RectangleD.prototype.getRight = function () { + return this.x + this.width; +}; + +RectangleD.prototype.getBottom = function () { + return this.y + this.height; +}; + +RectangleD.prototype.intersects = function (a) { + if (this.getRight() < a.x) { + return false; + } + + if (this.getBottom() < a.y) { + return false; + } + + if (a.getRight() < this.x) { + return false; + } + + if (a.getBottom() < this.y) { + return false; + } + + return true; +}; + +RectangleD.prototype.getCenterX = function () { + return this.x + this.width / 2; +}; + +RectangleD.prototype.getMinX = function () { + return this.getX(); +}; + +RectangleD.prototype.getMaxX = function () { + return this.getX() + this.width; +}; + +RectangleD.prototype.getCenterY = function () { + return this.y + this.height / 2; +}; + +RectangleD.prototype.getMinY = function () { + return this.getY(); +}; + +RectangleD.prototype.getMaxY = function () { + return this.getY() + this.height; +}; + +RectangleD.prototype.getWidthHalf = function () { + return this.width / 2; +}; + +RectangleD.prototype.getHeightHalf = function () { + return this.height / 2; +}; + +module.exports = RectangleD; + +},{}],32:[function(_dereq_,module,exports){ +'use strict'; + +var PointD = _dereq_('./PointD'); + +function Transform(x, y) { + this.lworldOrgX = 0.0; + this.lworldOrgY = 0.0; + this.ldeviceOrgX = 0.0; + this.ldeviceOrgY = 0.0; + this.lworldExtX = 1.0; + this.lworldExtY = 1.0; + this.ldeviceExtX = 1.0; + this.ldeviceExtY = 1.0; +} + +Transform.prototype.getWorldOrgX = function () { + return this.lworldOrgX; +}; + +Transform.prototype.setWorldOrgX = function (wox) { + this.lworldOrgX = wox; +}; + +Transform.prototype.getWorldOrgY = function () { + return this.lworldOrgY; +}; + +Transform.prototype.setWorldOrgY = function (woy) { + this.lworldOrgY = woy; +}; + +Transform.prototype.getWorldExtX = function () { + return this.lworldExtX; +}; + +Transform.prototype.setWorldExtX = function (wex) { + this.lworldExtX = wex; +}; + +Transform.prototype.getWorldExtY = function () { + return this.lworldExtY; +}; + +Transform.prototype.setWorldExtY = function (wey) { + this.lworldExtY = wey; +}; + +/* Device related */ + +Transform.prototype.getDeviceOrgX = function () { + return this.ldeviceOrgX; +}; + +Transform.prototype.setDeviceOrgX = function (dox) { + this.ldeviceOrgX = dox; +}; + +Transform.prototype.getDeviceOrgY = function () { + return this.ldeviceOrgY; +}; + +Transform.prototype.setDeviceOrgY = function (doy) { + this.ldeviceOrgY = doy; +}; + +Transform.prototype.getDeviceExtX = function () { + return this.ldeviceExtX; +}; + +Transform.prototype.setDeviceExtX = function (dex) { + this.ldeviceExtX = dex; +}; + +Transform.prototype.getDeviceExtY = function () { + return this.ldeviceExtY; +}; + +Transform.prototype.setDeviceExtY = function (dey) { + this.ldeviceExtY = dey; +}; + +Transform.prototype.transformX = function (x) { + var xDevice = 0.0; + var worldExtX = this.lworldExtX; + if (worldExtX != 0.0) { + xDevice = this.ldeviceOrgX + (x - this.lworldOrgX) * this.ldeviceExtX / worldExtX; + } + + return xDevice; +}; + +Transform.prototype.transformY = function (y) { + var yDevice = 0.0; + var worldExtY = this.lworldExtY; + if (worldExtY != 0.0) { + yDevice = this.ldeviceOrgY + (y - this.lworldOrgY) * this.ldeviceExtY / worldExtY; + } + + return yDevice; +}; + +Transform.prototype.inverseTransformX = function (x) { + var xWorld = 0.0; + var deviceExtX = this.ldeviceExtX; + if (deviceExtX != 0.0) { + xWorld = this.lworldOrgX + (x - this.ldeviceOrgX) * this.lworldExtX / deviceExtX; + } + + return xWorld; +}; + +Transform.prototype.inverseTransformY = function (y) { + var yWorld = 0.0; + var deviceExtY = this.ldeviceExtY; + if (deviceExtY != 0.0) { + yWorld = this.lworldOrgY + (y - this.ldeviceOrgY) * this.lworldExtY / deviceExtY; + } + return yWorld; +}; + +Transform.prototype.inverseTransformPoint = function (inPoint) { + var outPoint = new PointD(this.inverseTransformX(inPoint.x), this.inverseTransformY(inPoint.y)); + return outPoint; +}; + +module.exports = Transform; + +},{"./PointD":29}],33:[function(_dereq_,module,exports){ +"use strict"; + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +function UniqueIDGeneretor() {} + +UniqueIDGeneretor.lastID = 0; + +UniqueIDGeneretor.createID = function (obj) { + if (UniqueIDGeneretor.isPrimitive(obj)) { + return obj; + } + if (obj.uniqueID != null) { + return obj.uniqueID; + } + obj.uniqueID = UniqueIDGeneretor.getString(); + UniqueIDGeneretor.lastID++; + return obj.uniqueID; +}; + +UniqueIDGeneretor.getString = function (id) { + if (id == null) id = UniqueIDGeneretor.lastID; + return "Object#" + id + ""; +}; + +UniqueIDGeneretor.isPrimitive = function (arg) { + var type = typeof arg === "undefined" ? "undefined" : _typeof(arg); + return arg == null || type != "object" && type != "function"; +}; + +module.exports = UniqueIDGeneretor; + +},{}],34:[function(_dereq_,module,exports){ +'use strict'; + +var DimensionD = _dereq_('./DimensionD'); +var HashMap = _dereq_('./HashMap'); +var HashSet = _dereq_('./HashSet'); +var IGeometry = _dereq_('./IGeometry'); +var IMath = _dereq_('./IMath'); +var Integer = _dereq_('./Integer'); +var Point = _dereq_('./Point'); +var PointD = _dereq_('./PointD'); +var RandomSeed = _dereq_('./RandomSeed'); +var RectangleD = _dereq_('./RectangleD'); +var Transform = _dereq_('./Transform'); +var UniqueIDGeneretor = _dereq_('./UniqueIDGeneretor'); +var LGraphObject = _dereq_('./LGraphObject'); +var LGraph = _dereq_('./LGraph'); +var LEdge = _dereq_('./LEdge'); +var LGraphManager = _dereq_('./LGraphManager'); +var LNode = _dereq_('./LNode'); +var Layout = _dereq_('./Layout'); +var LayoutConstants = _dereq_('./LayoutConstants'); +var FDLayout = _dereq_('./FDLayout'); +var FDLayoutConstants = _dereq_('./FDLayoutConstants'); +var FDLayoutEdge = _dereq_('./FDLayoutEdge'); +var FDLayoutNode = _dereq_('./FDLayoutNode'); +var CoSEConstants = _dereq_('./CoSEConstants'); +var CoSEEdge = _dereq_('./CoSEEdge'); +var CoSEGraph = _dereq_('./CoSEGraph'); +var CoSEGraphManager = _dereq_('./CoSEGraphManager'); +var CoSELayout = _dereq_('./CoSELayout'); +var CoSENode = _dereq_('./CoSENode'); + +var defaults = { + // Called on `layoutready` + ready: function ready() {}, + // Called on `layoutstop` + stop: function stop() {}, + // include labels in node dimensions + nodeDimensionsIncludeLabels: false, + // number of ticks per frame; higher is faster but more jerky + refresh: 30, + // Whether to fit the network view after when done + fit: true, + // Padding on fit + padding: 10, + // Whether to enable incremental mode + randomize: true, + // Node repulsion (non overlapping) multiplier + nodeRepulsion: 4500, + // Ideal edge (non nested) length + idealEdgeLength: 50, + // Divisor to compute edge forces + edgeElasticity: 0.45, + // Nesting factor (multiplier) to compute ideal edge length for nested edges + nestingFactor: 0.1, + // Gravity force (constant) + gravity: 0.25, + // Maximum number of iterations to perform + numIter: 2500, + // For enabling tiling + tile: true, + // Type of layout animation. The option set is {'during', 'end', false} + animate: 'end', + // Duration for animate:end + animationDuration: 500, + // Represents the amount of the vertical space to put between the zero degree members during the tiling operation(can also be a function) + tilingPaddingVertical: 10, + // Represents the amount of the horizontal space to put between the zero degree members during the tiling operation(can also be a function) + tilingPaddingHorizontal: 10, + // Gravity range (constant) for compounds + gravityRangeCompound: 1.5, + // Gravity force (constant) for compounds + gravityCompound: 1.0, + // Gravity range (constant) + gravityRange: 3.8, + // Initial cooling factor for incremental layout + initialEnergyOnIncremental: 0.5 +}; + +function extend(defaults, options) { + var obj = {}; + + for (var i in defaults) { + obj[i] = defaults[i]; + } + + for (var i in options) { + obj[i] = options[i]; + } + + return obj; +}; + +function _CoSELayout(_options) { + this.options = extend(defaults, _options); + getUserOptions(this.options); +} + +var getUserOptions = function getUserOptions(options) { + if (options.nodeRepulsion != null) CoSEConstants.DEFAULT_REPULSION_STRENGTH = FDLayoutConstants.DEFAULT_REPULSION_STRENGTH = options.nodeRepulsion; + if (options.idealEdgeLength != null) CoSEConstants.DEFAULT_EDGE_LENGTH = FDLayoutConstants.DEFAULT_EDGE_LENGTH = options.idealEdgeLength; + if (options.edgeElasticity != null) CoSEConstants.DEFAULT_SPRING_STRENGTH = FDLayoutConstants.DEFAULT_SPRING_STRENGTH = options.edgeElasticity; + if (options.nestingFactor != null) CoSEConstants.PER_LEVEL_IDEAL_EDGE_LENGTH_FACTOR = FDLayoutConstants.PER_LEVEL_IDEAL_EDGE_LENGTH_FACTOR = options.nestingFactor; + if (options.gravity != null) CoSEConstants.DEFAULT_GRAVITY_STRENGTH = FDLayoutConstants.DEFAULT_GRAVITY_STRENGTH = options.gravity; + if (options.numIter != null) CoSEConstants.MAX_ITERATIONS = FDLayoutConstants.MAX_ITERATIONS = options.numIter; + if (options.gravityRange != null) CoSEConstants.DEFAULT_GRAVITY_RANGE_FACTOR = FDLayoutConstants.DEFAULT_GRAVITY_RANGE_FACTOR = options.gravityRange; + if (options.gravityCompound != null) CoSEConstants.DEFAULT_COMPOUND_GRAVITY_STRENGTH = FDLayoutConstants.DEFAULT_COMPOUND_GRAVITY_STRENGTH = options.gravityCompound; + if (options.gravityRangeCompound != null) CoSEConstants.DEFAULT_COMPOUND_GRAVITY_RANGE_FACTOR = FDLayoutConstants.DEFAULT_COMPOUND_GRAVITY_RANGE_FACTOR = options.gravityRangeCompound; + if (options.initialEnergyOnIncremental != null) CoSEConstants.DEFAULT_COOLING_FACTOR_INCREMENTAL = FDLayoutConstants.DEFAULT_COOLING_FACTOR_INCREMENTAL = options.initialEnergyOnIncremental; + + CoSEConstants.NODE_DIMENSIONS_INCLUDE_LABELS = FDLayoutConstants.NODE_DIMENSIONS_INCLUDE_LABELS = LayoutConstants.NODE_DIMENSIONS_INCLUDE_LABELS = options.nodeDimensionsIncludeLabels; + CoSEConstants.DEFAULT_INCREMENTAL = FDLayoutConstants.DEFAULT_INCREMENTAL = LayoutConstants.DEFAULT_INCREMENTAL = !options.randomize; + CoSEConstants.ANIMATE = FDLayoutConstants.ANIMATE = LayoutConstants.ANIMATE = options.animate; + CoSEConstants.TILE = options.tile; + CoSEConstants.TILING_PADDING_VERTICAL = typeof options.tilingPaddingVertical === 'function' ? options.tilingPaddingVertical.call() : options.tilingPaddingVertical; + CoSEConstants.TILING_PADDING_HORIZONTAL = typeof options.tilingPaddingHorizontal === 'function' ? options.tilingPaddingHorizontal.call() : options.tilingPaddingHorizontal; +}; + +_CoSELayout.prototype.run = function () { + var ready; + var frameId; + var options = this.options; + var idToLNode = this.idToLNode = {}; + var layout = this.layout = new CoSELayout(); + var self = this; + + self.stopped = false; + + this.cy = this.options.cy; + + this.cy.trigger({ type: 'layoutstart', layout: this }); + + var gm = layout.newGraphManager(); + this.gm = gm; + + var nodes = this.options.eles.nodes(); + var edges = this.options.eles.edges(); + + this.root = gm.addRoot(); + this.processChildrenList(this.root, this.getTopMostNodes(nodes), layout); + + for (var i = 0; i < edges.length; i++) { + var edge = edges[i]; + var sourceNode = this.idToLNode[edge.data("source")]; + var targetNode = this.idToLNode[edge.data("target")]; + if (sourceNode.getEdgesBetween(targetNode).length == 0) { + var e1 = gm.add(layout.newEdge(), sourceNode, targetNode); + e1.id = edge.id(); + } + } + + var getPositions = function getPositions(ele, i) { + if (typeof ele === "number") { + ele = i; + } + var theId = ele.data('id'); + var lNode = self.idToLNode[theId]; + + return { + x: lNode.getRect().getCenterX(), + y: lNode.getRect().getCenterY() + }; + }; + + /* + * Reposition nodes in iterations animatedly + */ + var iterateAnimated = function iterateAnimated() { + // Thigs to perform after nodes are repositioned on screen + var afterReposition = function afterReposition() { + if (options.fit) { + options.cy.fit(options.eles.nodes(), options.padding); + } + + if (!ready) { + ready = true; + self.cy.one('layoutready', options.ready); + self.cy.trigger({ type: 'layoutready', layout: self }); + } + }; + + var ticksPerFrame = self.options.refresh; + var isDone; + + for (var i = 0; i < ticksPerFrame && !isDone; i++) { + isDone = self.stopped || self.layout.tick(); + } + + // If layout is done + if (isDone) { + // If the layout is not a sublayout and it is successful perform post layout. + if (layout.checkLayoutSuccess() && !layout.isSubLayout) { + layout.doPostLayout(); + } + + // If layout has a tilingPostLayout function property call it. + if (layout.tilingPostLayout) { + layout.tilingPostLayout(); + } + + layout.isLayoutFinished = true; + + self.options.eles.nodes().positions(getPositions); + + afterReposition(); + + // trigger layoutstop when the layout stops (e.g. finishes) + self.cy.one('layoutstop', self.options.stop); + self.cy.trigger({ type: 'layoutstop', layout: self }); + + if (frameId) { + cancelAnimationFrame(frameId); + } + + ready = false; + return; + } + + var animationData = self.layout.getPositionsData(); // Get positions of layout nodes note that all nodes may not be layout nodes because of tiling + + // Position nodes, for the nodes whose id does not included in data (because they are removed from their parents and included in dummy compounds) + // use position of their ancestors or dummy ancestors + options.eles.nodes().positions(function (ele, i) { + if (typeof ele === "number") { + ele = i; + } + var theId = ele.id(); + var pNode = animationData[theId]; + var temp = ele; + // If pNode is undefined search until finding position data of its first ancestor (It may be dummy as well) + while (pNode == null) { + pNode = animationData[temp.data('parent')] || animationData['DummyCompound_' + temp.data('parent')]; + animationData[theId] = pNode; + temp = temp.parent()[0]; + if (temp == undefined) { + break; + } + } + if (pNode != null) { + return { + x: pNode.x, + y: pNode.y + }; + } else { + return { + x: ele.x, + y: ele.y + }; + } + }); + + afterReposition(); + + frameId = requestAnimationFrame(iterateAnimated); + }; + + /* + * Listen 'layoutstarted' event and start animated iteration if animate option is 'during' + */ + layout.addListener('layoutstarted', function () { + if (self.options.animate === 'during') { + frameId = requestAnimationFrame(iterateAnimated); + } + }); + + layout.runLayout(); // Run cose layout + + /* + * If animate option is not 'during' ('end' or false) perform these here (If it is 'during' similar things are already performed) + */ + if (this.options.animate !== "during") { + self.options.eles.nodes().not(":parent").layoutPositions(self, self.options, getPositions); // Use layout positions to reposition the nodes it considers the options parameter + ready = false; + } + + return this; // chaining +}; + +//Get the top most ones of a list of nodes +_CoSELayout.prototype.getTopMostNodes = function (nodes) { + var nodesMap = {}; + for (var i = 0; i < nodes.length; i++) { + nodesMap[nodes[i].id()] = true; + } + var roots = nodes.filter(function (ele, i) { + if (typeof ele === "number") { + ele = i; + } + var parent = ele.parent()[0]; + while (parent != null) { + if (nodesMap[parent.id()]) { + return false; + } + parent = parent.parent()[0]; + } + return true; + }); + + return roots; +}; + +_CoSELayout.prototype.processChildrenList = function (parent, children, layout) { + var size = children.length; + for (var i = 0; i < size; i++) { + var theChild = children[i]; + var children_of_children = theChild.children(); + var theNode; + + var dimensions = theChild.layoutDimensions({ + nodeDimensionsIncludeLabels: this.options.nodeDimensionsIncludeLabels + }); + + if (theChild.outerWidth() != null && theChild.outerHeight() != null) { + theNode = parent.add(new CoSENode(layout.graphManager, new PointD(theChild.position('x') - dimensions.w / 2, theChild.position('y') - dimensions.h / 2), new DimensionD(parseFloat(dimensions.w), parseFloat(dimensions.h)))); + } else { + theNode = parent.add(new CoSENode(this.graphManager)); + } + // Attach id to the layout node + theNode.id = theChild.data("id"); + // Attach the paddings of cy node to layout node + theNode.paddingLeft = parseInt(theChild.css('padding')); + theNode.paddingTop = parseInt(theChild.css('padding')); + theNode.paddingRight = parseInt(theChild.css('padding')); + theNode.paddingBottom = parseInt(theChild.css('padding')); + + //Attach the label properties to compound if labels will be included in node dimensions + if (this.options.nodeDimensionsIncludeLabels) { + if (theChild.isParent()) { + var labelWidth = theChild.boundingBox({ includeLabels: true, includeNodes: false }).w; + var labelHeight = theChild.boundingBox({ includeLabels: true, includeNodes: false }).h; + var labelPos = theChild.css("text-halign"); + theNode.labelWidth = labelWidth; + theNode.labelHeight = labelHeight; + theNode.labelPos = labelPos; + } + } + + // Map the layout node + this.idToLNode[theChild.data("id")] = theNode; + + if (isNaN(theNode.rect.x)) { + theNode.rect.x = 0; + } + + if (isNaN(theNode.rect.y)) { + theNode.rect.y = 0; + } + + if (children_of_children != null && children_of_children.length > 0) { + var theNewGraph; + theNewGraph = layout.getGraphManager().add(layout.newGraph(), theNode); + this.processChildrenList(theNewGraph, children_of_children, layout); + } + } +}; + +/** + * @brief : called on continuous layouts to stop them before they finish + */ +_CoSELayout.prototype.stop = function () { + this.stopped = true; + + return this; // chaining +}; + +module.exports = function get(cytoscape) { + return _CoSELayout; +}; + +},{"./CoSEConstants":4,"./CoSEEdge":5,"./CoSEGraph":6,"./CoSEGraphManager":7,"./CoSELayout":8,"./CoSENode":9,"./DimensionD":10,"./FDLayout":12,"./FDLayoutConstants":13,"./FDLayoutEdge":14,"./FDLayoutNode":15,"./HashMap":16,"./HashSet":17,"./IGeometry":18,"./IMath":19,"./Integer":20,"./LEdge":21,"./LGraph":22,"./LGraphManager":23,"./LGraphObject":24,"./LNode":25,"./Layout":26,"./LayoutConstants":27,"./Point":28,"./PointD":29,"./RandomSeed":30,"./RectangleD":31,"./Transform":32,"./UniqueIDGeneretor":33}],35:[function(_dereq_,module,exports){ +'use strict'; + +// registers the extension on a cytoscape lib ref + +var getLayout = _dereq_('./Layout'); + +var register = function register(cytoscape) { + var Layout = getLayout(cytoscape); + + cytoscape('layout', 'cose-bilkent', Layout); +}; + +// auto reg for globals +if (typeof cytoscape !== 'undefined') { + register(cytoscape); +} + +module.exports = register; + +},{"./Layout":34}]},{},[35])(35) +}); +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJub2RlX21vZHVsZXMvbGlua2VkbGlzdC1qcy9pbmRleC5qcyIsIm5vZGVfbW9kdWxlcy9saW5rZWRsaXN0LWpzL3NyYy9MaXN0LmpzIiwibm9kZV9tb2R1bGVzL2xpbmtlZGxpc3QtanMvc3JjL05vZGUuanMiLCJzcmMvTGF5b3V0L0NvU0VDb25zdGFudHMuanMiLCJzcmMvTGF5b3V0L0NvU0VFZGdlLmpzIiwic3JjL0xheW91dC9Db1NFR3JhcGguanMiLCJzcmMvTGF5b3V0L0NvU0VHcmFwaE1hbmFnZXIuanMiLCJzcmMvTGF5b3V0L0NvU0VMYXlvdXQuanMiLCJzcmMvTGF5b3V0L0NvU0VOb2RlLmpzIiwic3JjL0xheW91dC9EaW1lbnNpb25ELmpzIiwic3JjL0xheW91dC9FbWl0dGVyLmpzIiwic3JjL0xheW91dC9GRExheW91dC5qcyIsInNyYy9MYXlvdXQvRkRMYXlvdXRDb25zdGFudHMuanMiLCJzcmMvTGF5b3V0L0ZETGF5b3V0RWRnZS5qcyIsInNyYy9MYXlvdXQvRkRMYXlvdXROb2RlLmpzIiwic3JjL0xheW91dC9IYXNoTWFwLmpzIiwic3JjL0xheW91dC9IYXNoU2V0LmpzIiwic3JjL0xheW91dC9JR2VvbWV0cnkuanMiLCJzcmMvTGF5b3V0L0lNYXRoLmpzIiwic3JjL0xheW91dC9JbnRlZ2VyLmpzIiwic3JjL0xheW91dC9MRWRnZS5qcyIsInNyYy9MYXlvdXQvTEdyYXBoLmpzIiwic3JjL0xheW91dC9MR3JhcGhNYW5hZ2VyLmpzIiwic3JjL0xheW91dC9MR3JhcGhPYmplY3QuanMiLCJzcmMvTGF5b3V0L0xOb2RlLmpzIiwic3JjL0xheW91dC9MYXlvdXQuanMiLCJzcmMvTGF5b3V0L0xheW91dENvbnN0YW50cy5qcyIsInNyYy9MYXlvdXQvUG9pbnQuanMiLCJzcmMvTGF5b3V0L1BvaW50RC5qcyIsInNyYy9MYXlvdXQvUmFuZG9tU2VlZC5qcyIsInNyYy9MYXlvdXQvUmVjdGFuZ2xlRC5qcyIsInNyYy9MYXlvdXQvVHJhbnNmb3JtLmpzIiwic3JjL0xheW91dC9VbmlxdWVJREdlbmVyZXRvci5qcyIsInNyYy9MYXlvdXQvaW5kZXguanMiLCJpbmRleC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtBQ0FBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDYkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNB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QUFiLEVBQXdCO0FBQ3ZDLFNBQU8sV0FBUDtBQUNELENBRkQ7OztBQ2xZQTs7QUFFQTs7QUFDQSxJQUFJLFlBQVksUUFBUSxVQUFSLENBQWhCOztBQUVBLElBQUksV0FBVyxTQUFYLFFBQVcsQ0FBVSxTQUFWLEVBQXFCO0FBQ2xDLE1BQUksU0FBUyxVQUFXLFNBQVgsQ0FBYjs7QUFFQSxZQUFVLFFBQVYsRUFBb0IsY0FBcEIsRUFBb0MsTUFBcEM7QUFDRCxDQUpEOztBQU1BO0FBQ0EsSUFBSSxPQUFPLFNBQVAsS0FBcUIsV0FBekIsRUFBc0M7QUFDcEMsV0FBVSxTQUFWO0FBQ0Q7O0FBRUQsT0FBTyxPQUFQLEdBQWlCLFFBQWpCIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIoZnVuY3Rpb24gZSh0LG4scil7ZnVuY3Rpb24gcyhvLHUpe2lmKCFuW29dKXtpZighdFtvXSl7dmFyIGE9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtpZighdSYmYSlyZXR1cm4gYShvLCEwKTtpZihpKXJldHVybiBpKG8sITApO3ZhciBmPW5ldyBFcnJvcihcIkNhbm5vdCBmaW5kIG1vZHVsZSAnXCIrbytcIidcIik7dGhyb3cgZi5jb2RlPVwiTU9EVUxFX05PVF9GT1VORFwiLGZ9dmFyIGw9bltvXT17ZXhwb3J0czp7fX07dFtvXVswXS5jYWxsKGwuZXhwb3J0cyxmdW5jdGlvbihlKXt2YXIgbj10W29dWzFdW2VdO3JldHVybiBzKG4/bjplKX0sbCxsLmV4cG9ydHMsZSx0LG4scil9cmV0dXJuIG5bb10uZXhwb3J0c312YXIgaT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2Zvcih2YXIgbz0wO288ci5sZW5ndGg7bysrKXMocltvXSk7cmV0dXJuIHN9KSIsInZhciBucyA9IHtcblx0TGlzdDogcmVxdWlyZSgnLi9zcmMvTGlzdCcpLFxuXHROb2RlOiByZXF1aXJlKCcuL3NyYy9Ob2RlJyksXG59O1xuXG5pZiAodHlwZW9mIG1vZHVsZSAhPT0gJ3VuZGVmaW5lZCcpIHtcblx0bW9kdWxlLmV4cG9ydHMgPSBucztcbn0gZWxzZSBpZiAodHlwZW9mIGRlZmluZSAhPT0gJ3VuZGVmaW5lZCcpIHtcblx0ZGVmaW5lKCdMaW5rZWRMaXN0SlMnLCBmdW5jdGlvbiAoKSB7XG5cdFx0cmV0dXJuIG5zO1xuXHR9KTtcbn0gZWxzZSBpZiAodHlwZW9mIHdpbmRvdyAhPT0gJ3VuZGVmaW5lZCcpIHtcblx0d2luZG93LkxpbmtlZExpc3RKUyA9IG5zO1xufSIsInZhciBOb2RlID0gcmVxdWlyZSgnLi9Ob2RlJyk7XG5cbnZhciBMaXN0ID0gZnVuY3Rpb24gKCkge1xuXHR0aGlzLl9jb3VudCA9IDA7XG5cdHRoaXMuX2hlYWQgPSBudWxsO1xuXHR0aGlzLl90YWlsID0gbnVsbDtcbn07XG5cbkxpc3QucHJvdG90eXBlLmhlYWQgPSBmdW5jdGlvbiAoKSB7XG5cdHJldHVybiB0aGlzLl9oZWFkO1xufTtcblxuTGlzdC5wcm90b3R5cGUudGFpbCA9IGZ1bmN0aW9uICgpIHtcblx0cmV0dXJuIHRoaXMuX3RhaWw7XG59O1xuXG5MaXN0LnByb3RvdHlwZS5jb3VudCA9IGZ1bmN0aW9uICgpIHtcblx0cmV0dXJuIHRoaXMuX2NvdW50O1xufTtcblxuTGlzdC5wcm90b3R5cGUuZ2V0ID0gZnVuY3Rpb24gKGluZGV4KSB7XG5cdHZhciBub2RlID0gdGhpcy5faGVhZDtcblxuXHRmb3IgKHZhciBpID0gMDsgaSA8IGluZGV4OyBpKyspIHtcblx0XHRub2RlID0gbm9kZS5uZXh0KCk7XG5cdH1cblxuXHRyZXR1cm4gbm9kZTtcbn07XG5cbkxpc3QucHJvdG90eXBlLnNldCA9IGZ1bmN0aW9uIChpbmRleCwgdmFsdWUpIHtcblx0dmFyIG5vZGUgPSB0aGlzLmdldChpbmRleCk7XG5cdG5vZGUuc2V0KHZhbHVlKTtcbn07XG5cbkxpc3QucHJvdG90eXBlLnB1c2ggPSBmdW5jdGlvbiAodmFsdWUpIHtcblx0dmFyIG5vZGUgPSBuZXcgTm9kZSh2YWx1ZSwgdGhpcy5fdGFpbCwgbnVsbCk7XG5cblx0aWYgKHRoaXMuX3RhaWwgIT09IG51bGwpIHtcblx0XHR0aGlzLl90YWlsLnNldE5leHQobm9kZSk7XG5cdH1cblxuXHRpZiAodGhpcy5faGVhZCA9PT0gbnVsbCkge1xuXHRcdHRoaXMuX2hlYWQgPSBub2RlO1xuXHR9XG5cblx0dGhpcy5fdGFpbCA9IG5vZGU7XG5cdHRoaXMuX2NvdW50Kys7XG5cblx0cmV0dXJuIG5vZGU7XG59O1xuXG5MaXN0LnByb3RvdHlwZS5wb3AgPSBmdW5jdGlvbiAoKSB7XG5cdHZhciBub2RlID0gdGhpcy5fdGFpbDtcblxuXHR2YXIgbmV3X3RhaWwgPSBudWxsO1xuXHRpZiAodGhpcy5fdGFpbC5wcmV2aW91cygpICE9PSBudWxsKSB7XG5cdFx0bmV3X3RhaWwgPSB0aGlzLl90YWlsLnByZXZpb3VzKCk7XG5cdFx0bmV3X3RhaWwuc2V0TmV4dChudWxsKTtcblx0fVxuXHRcblx0dGhpcy5fdGFpbCA9IG5ld190YWlsO1xuXG5cdHRoaXMuX2NvdW50LS07XG5cblx0aWYgKHRoaXMuX2NvdW50ID09PSAwKSB7XG5cdFx0dGhpcy5faGVhZCA9IG51bGw7XG5cdH1cblxuXHRyZXR1cm4gbm9kZTtcbn07XG5cbkxpc3QucHJvdG90eXBlLnVuc2hpZnQgPSBmdW5jdGlvbiAodmFsdWUpIHtcblx0dmFyIG5vZGUgPSBuZXcgTm9kZSh2YWx1ZSwgbnVsbCwgdGhpcy5faGVhZCk7XG5cblx0aWYgKHRoaXMuX2hlYWQgIT09IG51bGwpIHtcblx0XHR0aGlzLl9oZWFkLnNldFByZXZpb3VzKG5vZGUpO1xuXHR9XG5cblx0aWYgKHRoaXMuX3RhaWwgPT09IG51bGwpIHtcblx0XHR0aGlzLl90YWlsID0gbm9kZTtcblx0fVxuXHRcblx0dGhpcy5faGVhZCA9IG5vZGU7XG5cblx0dGhpcy5fY291bnQrKztcblxuXHRyZXR1cm4gbm9kZTtcbn07XG5cbkxpc3QucHJvdG90eXBlLnNoaWZ0ID0gZnVuY3Rpb24gKCkge1xuXHR2YXIgbm9kZSA9IHRoaXMuX2hlYWQ7XG5cblx0dmFyIG5ld19oZWFkID0gbnVsbDtcblx0aWYgKHRoaXMuX2hlYWQubmV4dCgpICE9PSBudWxsKSB7XG5cdFx0bmV3X2hlYWQgPSB0aGlzLl9oZWFkLm5leHQoKTtcblx0XHRuZXdfaGVhZC5zZXRQcmV2aW91cyhudWxsKTtcblx0fVxuXG5cdHRoaXMuX2hlYWQgPSBuZXdfaGVhZDtcblxuXHR0aGlzLl9jb3VudC0tO1xuXG5cdGlmICh0aGlzLl9jb3VudCA9PT0gMCkge1xuXHRcdHRoaXMuX3RhaWwgPSBudWxsO1xuXHR9XG5cblx0cmV0dXJuIG5vZGU7XG59O1xuXG5MaXN0LnByb3RvdHlwZS5hc0FycmF5ID0gZnVuY3Rpb24gKCkge1xuXHR2YXIgYXJyID0gW107XG5cdHZhciBub2RlID0gdGhpcy5faGVhZDtcblxuXHR3aGlsZSAobm9kZSkge1xuXHRcdGFyci5wdXNoKG5vZGUudmFsdWUoKSk7XG5cdFx0bm9kZSA9IG5vZGUubmV4dCgpO1xuXHR9XG5cblx0cmV0dXJuIGFycjtcbn07XG5cbkxpc3QucHJvdG90eXBlLnRydW5jYXRlVG8gPSBmdW5jdGlvbiAobGVuZ3RoKSB7XG5cdHRoaXMuX2NvdW50ID0gbGVuZ3RoO1xuXG5cdGlmIChsZW5ndGggPT09IDApIHtcblx0XHR0aGlzLl9oZWFkID0gbnVsbDtcblx0XHR0aGlzLl90YWlsID0gbnVsbDtcblxuXHRcdHJldHVybjtcblx0fVxuXG5cdHZhciBub2RlID0gdGhpcy5nZXQobGVuZ3RoLTEpO1xuXHRub2RlLnNldE5leHQobnVsbCk7XG5cdHRoaXMuX3RhaWwgPSBub2RlO1xufTtcblxuTGlzdC5wcm90b3R5cGUuZW1wdHkgPSBmdW5jdGlvbiAoKSB7XG5cdHRoaXMudHJ1bmNhdGVUbygwKTtcbn07XG5cbkxpc3QucHJvdG90eXBlLmlzRW1wdHkgPSBmdW5jdGlvbiAoKSB7XG5cdHJldHVybiB0aGlzLl9oZWFkID09PSBudWxsO1xufTtcblxuTGlzdC5wcm90b3R5cGUuZmluZCA9IGZ1bmN0aW9uICh2YWx1ZSkge1xuXHR2YXIgbm9kZSA9IHRoaXMuX2hlYWQ7XG5cblx0d2hpbGUgKG5vZGUgIT09IG51bGwpIHtcblx0XHRpZiAobm9kZS52YWx1ZSgpID09PSB2YWx1ZSkge1xuXHRcdFx0cmV0dXJuIG5vZGU7XG5cdFx0fVxuXG5cdFx0bm9kZSA9IG5vZGUubmV4dCgpO1xuXHR9XG5cblx0cmV0dXJuIG51bGw7XG59O1xuXG5MaXN0LnByb3RvdHlwZS5lYWNoID0gZnVuY3Rpb24gKGNhbGxiYWNrKSB7XG5cdHZhciBub2RlID0gdGhpcy5faGVhZDtcblx0dmFyIGkgPSAwO1xuXHR3aGlsZSAobm9kZSAhPT0gbnVsbCkge1xuXHRcdGNhbGxiYWNrKGksIG5vZGUpO1xuXHRcdG5vZGUgPSBub2RlLm5leHQoKTtcblx0XHRpKys7XG5cdH1cbn1cblxubW9kdWxlLmV4cG9ydHMgPSBMaXN0OyIsInZhciBOb2RlID0gZnVuY3Rpb24gKHZhbHVlLCBwcmV2aW91cywgbmV4dCkge1xuXHR0aGlzLl92YWx1ZSA9IHZhbHVlID09PSB1bmRlZmluZWQgPyBudWxsIDogdmFsdWU7XG5cdFxuXHR0aGlzLl9wcmV2aW91cyA9IHByZXZpb3VzID09PSB1bmRlZmluZWQgPyBudWxsIDogcHJldmlvdXM7XG5cdHRoaXMuX25leHQgPSBuZXh0ID09PSB1bmRlZmluZWQgPyBudWxsIDogbmV4dDtcbn07XG5cbk5vZGUucHJvdG90eXBlLnZhbHVlID0gZnVuY3Rpb24gKCkge1xuXHRyZXR1cm4gdGhpcy5fdmFsdWU7XG59O1xuXG5Ob2RlLnByb3RvdHlwZS5wcmV2aW91cyA9IGZ1bmN0aW9uICgpIHtcblx0cmV0dXJuIHRoaXMuX3ByZXZpb3VzO1xufTtcblxuTm9kZS5wcm90b3R5cGUubmV4dCA9IGZ1bmN0aW9uICgpIHtcblx0cmV0dXJuIHRoaXMuX25leHQ7XG59O1xuXG5Ob2RlLnByb3RvdHlwZS5zZXQgPSBmdW5jdGlvbiAodmFsdWUpIHtcblx0dGhpcy5fdmFsdWUgPSB2YWx1ZTtcbn07XG5cbk5vZGUucHJvdG90eXBlLnNldFByZXZpb3VzID0gZnVuY3Rpb24gKG5vZGUpIHtcblx0dGhpcy5fcHJldmlvdXMgPSBub2RlO1xufTtcblxuTm9kZS5wcm90b3R5cGUuc2V0TmV4dCA9IGZ1bmN0aW9uIChub2RlKSB7XG5cdHRoaXMuX25leHQgPSBub2RlO1xufTtcblxuTm9kZS5wcm90b3R5cGUuaXNIZWFkID0gZnVuY3Rpb24gKCkge1xuXHRyZXR1cm4gdGhpcy5fcHJldmlvdXMgPT09IG51bGw7XG59O1xuXG5Ob2RlLnByb3RvdHlwZS5pc1RhaWwgPSBmdW5jdGlvbiAoKSB7XG5cdHJldHVybiB0aGlzLl9uZXh0ID09PSBudWxsO1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSBOb2RlOyIsInZhciBGRExheW91dENvbnN0YW50cyA9IHJlcXVpcmUoJy4vRkRMYXlvdXRDb25zdGFudHMnKTtcblxuZnVuY3Rpb24gQ29TRUNvbnN0YW50cygpIHtcbn1cblxuLy9Db1NFQ29uc3RhbnRzIGluaGVyaXRzIHN0YXRpYyBwcm9wcyBpbiBGRExheW91dENvbnN0YW50c1xuZm9yICh2YXIgcHJvcCBpbiBGRExheW91dENvbnN0YW50cykge1xuICBDb1NFQ29uc3RhbnRzW3Byb3BdID0gRkRMYXlvdXRDb25zdGFudHNbcHJvcF07XG59XG5cbkNvU0VDb25zdGFudHMuREVGQVVMVF9VU0VfTVVMVElfTEVWRUxfU0NBTElORyA9IGZhbHNlO1xuQ29TRUNvbnN0YW50cy5ERUZBVUxUX1JBRElBTF9TRVBBUkFUSU9OID0gRkRMYXlvdXRDb25zdGFudHMuREVGQVVMVF9FREdFX0xFTkdUSDtcbkNvU0VDb25zdGFudHMuREVGQVVMVF9DT01QT05FTlRfU0VQRVJBVElPTiA9IDYwO1xuQ29TRUNvbnN0YW50cy5USUxFID0gdHJ1ZTtcbkNvU0VDb25zdGFudHMuVElMSU5HX1BBRERJTkdfVkVSVElDQUwgPSAxMDtcbkNvU0VDb25zdGFudHMuVElMSU5HX1BBRERJTkdfSE9SSVpPTlRBTCA9IDEwO1xuXG5tb2R1bGUuZXhwb3J0cyA9IENvU0VDb25zdGFudHM7XG4iLCJ2YXIgRkRMYXlvdXRFZGdlID0gcmVxdWlyZSgnLi9GRExheW91dEVkZ2UnKTtcblxuZnVuY3Rpb24gQ29TRUVkZ2Uoc291cmNlLCB0YXJnZXQsIHZFZGdlKSB7XG4gIEZETGF5b3V0RWRnZS5jYWxsKHRoaXMsIHNvdXJjZSwgdGFyZ2V0LCB2RWRnZSk7XG59XG5cbkNvU0VFZGdlLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoRkRMYXlvdXRFZGdlLnByb3RvdHlwZSk7XG5mb3IgKHZhciBwcm9wIGluIEZETGF5b3V0RWRnZSkge1xuICBDb1NFRWRnZVtwcm9wXSA9IEZETGF5b3V0RWRnZVtwcm9wXTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBDb1NFRWRnZVxuIiwidmFyIExHcmFwaCA9IHJlcXVpcmUoJy4vTEdyYXBoJyk7XG5cbmZ1bmN0aW9uIENvU0VHcmFwaChwYXJlbnQsIGdyYXBoTWdyLCB2R3JhcGgpIHtcbiAgTEdyYXBoLmNhbGwodGhpcywgcGFyZW50LCBncmFwaE1nciwgdkdyYXBoKTtcbn1cblxuQ29TRUdyYXBoLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoTEdyYXBoLnByb3RvdHlwZSk7XG5mb3IgKHZhciBwcm9wIGluIExHcmFwaCkge1xuICBDb1NFR3JhcGhbcHJvcF0gPSBMR3JhcGhbcHJvcF07XG59XG5cbm1vZHVsZS5leHBvcnRzID0gQ29TRUdyYXBoO1xuIiwidmFyIExHcmFwaE1hbmFnZXIgPSByZXF1aXJlKCcuL0xHcmFwaE1hbmFnZXInKTtcblxuZnVuY3Rpb24gQ29TRUdyYXBoTWFuYWdlcihsYXlvdXQpIHtcbiAgTEdyYXBoTWFuYWdlci5jYWxsKHRoaXMsIGxheW91dCk7XG59XG5cbkNvU0VHcmFwaE1hbmFnZXIucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShMR3JhcGhNYW5hZ2VyLnByb3RvdHlwZSk7XG5mb3IgKHZhciBwcm9wIGluIExHcmFwaE1hbmFnZXIpIHtcbiAgQ29TRUdyYXBoTWFuYWdlcltwcm9wXSA9IExHcmFwaE1hbmFnZXJbcHJvcF07XG59XG5cbm1vZHVsZS5leHBvcnRzID0gQ29TRUdyYXBoTWFuYWdlcjtcbiIsInZhciBGRExheW91dCA9IHJlcXVpcmUoJy4vRkRMYXlvdXQnKTtcbnZhciBDb1NFR3JhcGhNYW5hZ2VyID0gcmVxdWlyZSgnLi9Db1NFR3JhcGhNYW5hZ2VyJyk7XG52YXIgQ29TRUdyYXBoID0gcmVxdWlyZSgnLi9Db1NFR3JhcGgnKTtcbnZhciBDb1NFTm9kZSA9IHJlcXVpcmUoJy4vQ29TRU5vZGUnKTtcbnZhciBDb1NFRWRnZSA9IHJlcXVpcmUoJy4vQ29TRUVkZ2UnKTtcbnZhciBDb1NFQ29uc3RhbnRzID0gcmVxdWlyZSgnLi9Db1NFQ29uc3RhbnRzJyk7XG52YXIgRkRMYXlvdXRDb25zdGFudHMgPSByZXF1aXJlKCcuL0ZETGF5b3V0Q29uc3RhbnRzJyk7XG52YXIgTGF5b3V0Q29uc3RhbnRzID0gcmVxdWlyZSgnLi9MYXlvdXRDb25zdGFudHMnKTtcbnZhciBQb2ludCA9IHJlcXVpcmUoJy4vUG9pbnQnKTtcbnZhciBQb2ludEQgPSByZXF1aXJlKCcuL1BvaW50RCcpO1xudmFyIExheW91dCA9IHJlcXVpcmUoJy4vTGF5b3V0Jyk7XG52YXIgSW50ZWdlciA9IHJlcXVpcmUoJy4vSW50ZWdlcicpO1xudmFyIElHZW9tZXRyeSA9IHJlcXVpcmUoJy4vSUdlb21ldHJ5Jyk7XG52YXIgTEdyYXBoID0gcmVxdWlyZSgnLi9MR3JhcGgnKTtcbnZhciBUcmFuc2Zvcm0gPSByZXF1aXJlKCcuL1RyYW5zZm9ybScpO1xuXG5mdW5jdGlvbiBDb1NFTGF5b3V0KCkge1xuICBGRExheW91dC5jYWxsKHRoaXMpO1xuICBcbiAgdGhpcy50b0JlVGlsZWQgPSB7fTsgLy8gTWVtb3JpemUgaWYgYSBub2RlIGlzIHRvIGJlIHRpbGVkIG9yIGlzIHRpbGVkXG59XG5cbkNvU0VMYXlvdXQucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShGRExheW91dC5wcm90b3R5cGUpO1xuXG5mb3IgKHZhciBwcm9wIGluIEZETGF5b3V0KSB7XG4gIENvU0VMYXlvdXRbcHJvcF0gPSBGRExheW91dFtwcm9wXTtcbn1cblxuQ29TRUxheW91dC5wcm90b3R5cGUubmV3R3JhcGhNYW5hZ2VyID0gZnVuY3Rpb24gKCkge1xuICB2YXIgZ20gPSBuZXcgQ29TRUdyYXBoTWFuYWdlcih0aGlzKTtcbiAgdGhpcy5ncmFwaE1hbmFnZXIgPSBnbTtcbiAgcmV0dXJuIGdtO1xufTtcblxuQ29TRUxheW91dC5wcm90b3R5cGUubmV3R3JhcGggPSBmdW5jdGlvbiAodkdyYXBoKSB7XG4gIHJldHVybiBuZXcgQ29TRUdyYXBoKG51bGwsIHRoaXMuZ3JhcGhNYW5hZ2VyLCB2R3JhcGgpO1xufTtcblxuQ29TRUxheW91dC5wcm90b3R5cGUubmV3Tm9kZSA9IGZ1bmN0aW9uICh2Tm9kZSkge1xuICByZXR1cm4gbmV3IENvU0VOb2RlKHRoaXMuZ3JhcGhNYW5hZ2VyLCB2Tm9kZSk7XG59O1xuXG5Db1NFTGF5b3V0LnByb3RvdHlwZS5uZXdFZGdlID0gZnVuY3Rpb24gKHZFZGdlKSB7XG4gIHJldHVybiBuZXcgQ29TRUVkZ2UobnVsbCwgbnVsbCwgdkVkZ2UpO1xufTtcblxuQ29TRUxheW91dC5wcm90b3R5cGUuaW5pdFBhcmFtZXRlcnMgPSBmdW5jdGlvbiAoKSB7XG4gIEZETGF5b3V0LnByb3RvdHlwZS5pbml0UGFyYW1ldGVycy5jYWxsKHRoaXMsIGFyZ3VtZW50cyk7XG4gIGlmICghdGhpcy5pc1N1YkxheW91dCkge1xuICAgIGlmIChDb1NFQ29uc3RhbnRzLkRFRkFVTFRfRURHRV9MRU5HVEggPCAxMClcbiAgICB7XG4gICAgICB0aGlzLmlkZWFsRWRnZUxlbmd0aCA9IDEwO1xuICAgIH1cbiAgICBlbHNlXG4gICAge1xuICAgICAgdGhpcy5pZGVhbEVkZ2VMZW5ndGggPSBDb1NFQ29uc3RhbnRzLkRFRkFVTFRfRURHRV9MRU5HVEg7XG4gICAgfVxuXG4gICAgdGhpcy51c2VTbWFydElkZWFsRWRnZUxlbmd0aENhbGN1bGF0aW9uID1cbiAgICAgICAgICAgIENvU0VDb25zdGFudHMuREVGQVVMVF9VU0VfU01BUlRfSURFQUxfRURHRV9MRU5HVEhfQ0FMQ1VMQVRJT047XG4gICAgdGhpcy5zcHJpbmdDb25zdGFudCA9XG4gICAgICAgICAgICBGRExheW91dENvbnN0YW50cy5ERUZBVUxUX1NQUklOR19TVFJFTkdUSDtcbiAgICB0aGlzLnJlcHVsc2lvbkNvbnN0YW50ID1cbiAgICAgICAgICAgIEZETGF5b3V0Q29uc3RhbnRzLkRFRkFVTFRfUkVQVUxTSU9OX1NUUkVOR1RIO1xuICAgIHRoaXMuZ3Jhdml0eUNvbnN0YW50ID1cbiAgICAgICAgICAgIEZETGF5b3V0Q29uc3RhbnRzLkRFRkFVTFRfR1JBVklUWV9TVFJFTkdUSDtcbiAgICB0aGlzLmNvbXBvdW5kR3Jhdml0eUNvbnN0YW50ID1cbiAgICAgICAgICAgIEZETGF5b3V0Q29uc3RhbnRzLkRFRkFVTFRfQ09NUE9VTkRfR1JBVklUWV9TVFJFTkdUSDtcbiAgICB0aGlzLmdyYXZpdHlSYW5nZUZhY3RvciA9XG4gICAgICAgICAgICBGRExheW91dENvbnN0YW50cy5ERUZBVUxUX0dSQVZJVFlfUkFOR0VfRkFDVE9SO1xuICAgIHRoaXMuY29tcG91bmRHcmF2aXR5UmFuZ2VGYWN0b3IgPVxuICAgICAgICAgICAgRkRMYXlvdXRDb25zdGFudHMuREVGQVVMVF9DT01QT1VORF9HUkFWSVRZX1JBTkdFX0ZBQ1RPUjtcbiAgfVxufTtcblxuQ29TRUxheW91dC5wcm90b3R5cGUubGF5b3V0ID0gZnVuY3Rpb24gKCkge1xuICB2YXIgY3JlYXRlQmVuZHNBc05lZWRlZCA9IExheW91dENvbnN0YW50cy5ERUZBVUxUX0NSRUFURV9CRU5EU19BU19ORUVERUQ7XG4gIGlmIChjcmVhdGVCZW5kc0FzTmVlZGVkKVxuICB7XG4gICAgdGhpcy5jcmVhdGVCZW5kcG9pbnRzKCk7XG4gICAgdGhpcy5ncmFwaE1hbmFnZXIucmVzZXRBbGxFZGdlcygpO1xuICB9XG5cbiAgdGhpcy5sZXZlbCA9IDA7XG4gIHJldHVybiB0aGlzLmNsYXNzaWNMYXlvdXQoKTtcbn07XG5cbkNvU0VMYXlvdXQucHJvdG90eXBlLmNsYXNzaWNMYXlvdXQgPSBmdW5jdGlvbiAoKSB7XG4gIHRoaXMubm9kZXNXaXRoR3Jhdml0eSA9IHRoaXMuY2FsY3VsYXRlTm9kZXNUb0FwcGx5R3Jhdml0YXRpb25UbygpO1xuICB0aGlzLmdyYXBoTWFuYWdlci5zZXRBbGxOb2Rlc1RvQXBwbHlHcmF2aXRhdGlvbih0aGlzLm5vZGVzV2l0aEdyYXZpdHkpO1xuICB0aGlzLmNhbGNOb09mQ2hpbGRyZW5Gb3JBbGxOb2RlcygpO1xuICB0aGlzLmdyYXBoTWFuYWdlci5jYWxjTG93ZXN0Q29tbW9uQW5jZXN0b3JzKCk7XG4gIHRoaXMuZ3JhcGhNYW5hZ2VyLmNhbGNJbmNsdXNpb25UcmVlRGVwdGhzKCk7XG4gIHRoaXMuZ3JhcGhNYW5hZ2VyLmdldFJvb3QoKS5jYWxjRXN0aW1hdGVkU2l6ZSgpO1xuICB0aGlzLmNhbGNJZGVhbEVkZ2VMZW5ndGhzKCk7XG4gIFxuICBpZiAoIXRoaXMuaW5jcmVtZW50YWwpXG4gIHtcbiAgICB2YXIgZm9yZXN0ID0gdGhpcy5nZXRGbGF0Rm9yZXN0KCk7XG5cbiAgICAvLyBUaGUgZ3JhcGggYXNzb2NpYXRlZCB3aXRoIHRoaXMgbGF5b3V0IGlzIGZsYXQgYW5kIGEgZm9yZXN0XG4gICAgaWYgKGZvcmVzdC5sZW5ndGggPiAwKVxuICAgIHtcbiAgICAgIHRoaXMucG9zaXRpb25Ob2Rlc1JhZGlhbGx5KGZvcmVzdCk7XG4gICAgfVxuICAgIC8vIFRoZSBncmFwaCBhc3NvY2lhdGVkIHdpdGggdGhpcyBsYXlvdXQgaXMgbm90IGZsYXQgb3IgYSBmb3Jlc3RcbiAgICBlbHNlXG4gICAge1xuICAgICAgLy8gUmVkdWNlIHRoZSB0cmVlcyB3aGVuIGluY3JlbWVudGFsIG1vZGUgaXMgbm90IGVuYWJsZWQgYW5kIGdyYXBoIGlzIG5vdCBhIGZvcmVzdCBcbiAgICAgIHRoaXMucmVkdWNlVHJlZXMoKTtcbiAgICAgIC8vIFVwZGF0ZSBub2RlcyB0aGF0IGdyYXZpdHkgd2lsbCBiZSBhcHBsaWVkXG4gICAgICB0aGlzLmdyYXBoTWFuYWdlci5yZXNldEFsbE5vZGVzVG9BcHBseUdyYXZpdGF0aW9uKCk7XG4gICAgICB2YXIgYWxsTm9kZXMgPSBuZXcgU2V0KHRoaXMuZ2V0QWxsTm9kZXMoKSk7XG4gICAgICB2YXIgaW50ZXJzZWN0aW9uID0gdGhpcy5ub2Rlc1dpdGhHcmF2aXR5LmZpbHRlcih4ID0+IGFsbE5vZGVzLmhhcyh4KSk7XG4gICAgICB0aGlzLmdyYXBoTWFuYWdlci5zZXRBbGxOb2Rlc1RvQXBwbHlHcmF2aXRhdGlvbihpbnRlcnNlY3Rpb24pO1xuICAgICAgXG4gICAgICB0aGlzLnBvc2l0aW9uTm9kZXNSYW5kb21seSgpO1xuICAgIH1cbiAgfVxuXG4gIHRoaXMuaW5pdFNwcmluZ0VtYmVkZGVyKCk7XG4gIHRoaXMucnVuU3ByaW5nRW1iZWRkZXIoKTtcblxuICByZXR1cm4gdHJ1ZTtcbn07XG5cbkNvU0VMYXlvdXQucHJvdG90eXBlLnRpY2sgPSBmdW5jdGlvbigpIHtcbiAgdGhpcy50b3RhbEl0ZXJhdGlvbnMrKztcbiAgXG4gIGlmICh0aGlzLnRvdGFsSXRlcmF0aW9ucyA9PT0gdGhpcy5tYXhJdGVyYXRpb25zICYmICF0aGlzLmlzVHJlZUdyb3dpbmcgJiYgIXRoaXMuaXNHcm93dGhGaW5pc2hlZCkge1xuICAgIGlmKHRoaXMucHJ1bmVkTm9kZXNBbGwubGVuZ3RoID4gMCl7XG4gICAgICB0aGlzLmlzVHJlZUdyb3dpbmcgPSB0cnVlO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgIHJldHVybiB0cnVlOyAgXG4gICAgfVxuICB9XG4gIFxuICBpZiAodGhpcy50b3RhbEl0ZXJhdGlvbnMgJSBGRExheW91dENvbnN0YW50cy5DT05WRVJHRU5DRV9DSEVDS19QRVJJT0QgPT0gMCAgJiYgIXRoaXMuaXNUcmVlR3Jvd2luZyAmJiAhdGhpcy5pc0dyb3d0aEZpbmlzaGVkKVxuICB7XG4gICAgaWYgKHRoaXMuaXNDb252ZXJnZWQoKSlcbiAgICB7XG4gICAgICBpZih0aGlzLnBydW5lZE5vZGVzQWxsLmxlbmd0aCA+IDApe1xuICAgICAgICB0aGlzLmlzVHJlZUdyb3dpbmcgPSB0cnVlO1xuICAgICAgfVxuICAgICAgZWxzZSB7XG4gICAgICAgIHJldHVybiB0cnVlOyAgXG4gICAgICB9IFxuICAgIH1cblxuICAgIHRoaXMuY29vbGluZ0ZhY3RvciA9IHRoaXMuaW5pdGlhbENvb2xpbmdGYWN0b3IgKlxuICAgICAgICAgICAgKCh0aGlzLm1heEl0ZXJhdGlvbnMgLSB0aGlzLnRvdGFsSXRlcmF0aW9ucykgLyB0aGlzLm1heEl0ZXJhdGlvbnMpO1xuICAgIHRoaXMuYW5pbWF0aW9uUGVyaW9kID0gTWF0aC5jZWlsKHRoaXMuaW5pdGlhbEFuaW1hdGlvblBlcmlvZCAqIE1hdGguc3FydCh0aGlzLmNvb2xpbmdGYWN0b3IpKTtcbiAgfVxuICAvLyBPcGVyYXRpb25zIHdoaWxlIHRyZWUgaXMgZ3Jvd2luZyBhZ2FpbiBcbiAgaWYodGhpcy5pc1RyZWVHcm93aW5nKXtcbiAgICBpZih0aGlzLmdyb3dUcmVlSXRlcmF0aW9ucyAlIDEwID09IDApe1xuICAgICAgaWYodGhpcy5wcnVuZWROb2Rlc0FsbC5sZW5ndGggPiAwKSB7XG4gICAgICAgIHRoaXMuZ3JhcGhNYW5hZ2VyLnVwZGF0ZUJvdW5kcygpO1xuICAgICAgICB0aGlzLnVwZGF0ZUdyaWQoKTtcbiAgICAgICAgdGhpcy5ncm93VHJlZSh0aGlzLnBydW5lZE5vZGVzQWxsKTtcbiAgICAgICAgLy8gVXBkYXRlIG5vZGVzIHRoYXQgZ3Jhdml0eSB3aWxsIGJlIGFwcGxpZWRcbiAgICAgICAgdGhpcy5ncmFwaE1hbmFnZXIucmVzZXRBbGxOb2Rlc1RvQXBwbHlHcmF2aXRhdGlvbigpO1xuICAgICAgICB2YXIgYWxsTm9kZXMgPSBuZXcgU2V0KHRoaXMuZ2V0QWxsTm9kZXMoKSk7XG4gICAgICAgIHZhciBpbnRlcnNlY3Rpb24gPSB0aGlzLm5vZGVzV2l0aEdyYXZpdHkuZmlsdGVyKHggPT4gYWxsTm9kZXMuaGFzKHgpKTtcbiAgICAgICAgdGhpcy5ncmFwaE1hbmFnZXIuc2V0QWxsTm9kZXNUb0FwcGx5R3Jhdml0YXRpb24oaW50ZXJzZWN0aW9uKTtcbiAgICAgICAgXG4gICAgICAgIHRoaXMuZ3JhcGhNYW5hZ2VyLnVwZGF0ZUJvdW5kcygpO1xuICAgICAgICB0aGlzLnVwZGF0ZUdyaWQoKTsgXG4gICAgICAgIHRoaXMuY29vbGluZ0ZhY3RvciA9IEZETGF5b3V0Q29uc3RhbnRzLkRFRkFVTFRfQ09PTElOR19GQUNUT1JfSU5DUkVNRU5UQUw7IFxuICAgICAgfVxuICAgICAgZWxzZSB7XG4gICAgICAgIHRoaXMuaXNUcmVlR3Jvd2luZyA9IGZhbHNlOyAgXG4gICAgICAgIHRoaXMuaXNHcm93dGhGaW5pc2hlZCA9IHRydWU7IFxuICAgICAgfVxuICAgIH1cbiAgICB0aGlzLmdyb3dUcmVlSXRlcmF0aW9ucysrO1xuICB9XG4gIC8vIE9wZXJhdGlvbnMgYWZ0ZXIgZ3Jvd3RoIGlzIGZpbmlzaGVkXG4gIGlmKHRoaXMuaXNHcm93dGhGaW5pc2hlZCl7XG4gICAgaWYgKHRoaXMuaXNDb252ZXJnZWQoKSlcbiAgICB7XG4gICAgICByZXR1cm4gdHJ1ZTsgIFxuICAgIH1cbiAgICBpZih0aGlzLmFmdGVyR3Jvd3RoSXRlcmF0aW9ucyAlIDEwID09IDApe1xuICAgICAgdGhpcy5ncmFwaE1hbmFnZXIudXBkYXRlQm91bmRzKCk7XG4gICAgICB0aGlzLnVwZGF0ZUdyaWQoKTsgXG4gICAgfVxuICAgIHRoaXMuY29vbGluZ0ZhY3RvciA9IEZETGF5b3V0Q29uc3RhbnRzLkRFRkFVTFRfQ09PTElOR19GQUNUT1JfSU5DUkVNRU5UQUwgKiAoKDEwMCAtIHRoaXMuYWZ0ZXJHcm93dGhJdGVyYXRpb25zKSAvIDEwMCk7XG4gICAgdGhpcy5hZnRlckdyb3d0aEl0ZXJhdGlvbnMrKztcbiAgfVxuICBcbiAgdGhpcy50b3RhbERpc3BsYWNlbWVudCA9IDA7XG4gIHRoaXMuZ3JhcGhNYW5hZ2VyLnVwZGF0ZUJvdW5kcygpO1xuICB0aGlzLmNhbGNTcHJpbmdGb3JjZXMoKTtcbiAgdGhpcy5jYWxjUmVwdWxzaW9uRm9yY2VzKCk7XG4gIHRoaXMuY2FsY0dyYXZpdGF0aW9uYWxGb3JjZXMoKTtcbiAgdGhpcy5tb3ZlTm9kZXMoKTtcbiAgdGhpcy5hbmltYXRlKCk7XG4gIFxuICByZXR1cm4gZmFsc2U7IC8vIExheW91dCBpcyBub3QgZW5kZWQgeWV0IHJldHVybiBmYWxzZVxufTtcblxuQ29TRUxheW91dC5wcm90b3R5cGUuZ2V0UG9zaXRpb25zRGF0YSA9IGZ1bmN0aW9uKCkge1xuICB2YXIgYWxsTm9kZXMgPSB0aGlzLmdyYXBoTWFuYWdlci5nZXRBbGxOb2RlcygpO1xuICB2YXIgcERhdGEgPSB7fTtcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBhbGxOb2Rlcy5sZW5ndGg7IGkrKykge1xuICAgIHZhciByZWN0ID0gYWxsTm9kZXNbaV0ucmVjdDtcbiAgICB2YXIgaWQgPSBhbGxOb2Rlc1tpXS5pZDtcbiAgICBwRGF0YVtpZF0gPSB7XG4gICAgICBpZDogaWQsXG4gICAgICB4OiByZWN0LmdldENlbnRlclgoKSxcbiAgICAgIHk6IHJlY3QuZ2V0Q2VudGVyWSgpLFxuICAgICAgdzogcmVjdC53aWR0aCxcbiAgICAgIGg6IHJlY3QuaGVpZ2h0XG4gICAgfTtcbiAgfVxuICBcbiAgcmV0dXJuIHBEYXRhO1xufTtcblxuQ29TRUxheW91dC5wcm90b3R5cGUucnVuU3ByaW5nRW1iZWRkZXIgPSBmdW5jdGlvbiAoKSB7XG4gIHRoaXMuaW5pdGlhbEFuaW1hdGlvblBlcmlvZCA9IDI1O1xuICB0aGlzLmFuaW1hdGlvblBlcmlvZCA9IHRoaXMuaW5pdGlhbEFuaW1hdGlvblBlcmlvZDtcbiAgdmFyIGxheW91dEVuZGVkID0gZmFsc2U7XG4gIFxuICAvLyBJZiBhbWluYXRlIG9wdGlvbiBpcyAnZHVyaW5nJyBzaWduYWwgdGhhdCBsYXlvdXQgaXMgc3VwcG9zZWQgdG8gc3RhcnQgaXRlcmF0aW5nXG4gIGlmICggRkRMYXlvdXRDb25zdGFudHMuQU5JTUFURSA9PT0gJ2R1cmluZycgKSB7XG4gICAgdGhpcy5lbWl0KCdsYXlvdXRzdGFydGVkJyk7XG4gIH1cbiAgZWxzZSB7XG4gICAgLy8gSWYgYW1pbmF0ZSBvcHRpb24gaXMgJ2R1cmluZycgdGljaygpIGZ1bmN0aW9uIHdpbGwgYmUgY2FsbGVkIG9uIGluZGV4LmpzXG4gICAgd2hpbGUgKCFsYXlvdXRFbmRlZCkge1xuICAgICAgbGF5b3V0RW5kZWQgPSB0aGlzLnRpY2soKTtcbiAgICB9XG5cbiAgICB0aGlzLmdyYXBoTWFuYWdlci51cGRhdGVCb3VuZHMoKTtcbiAgfVxufTtcblxuQ29TRUxheW91dC5wcm90b3R5cGUuY2FsY3VsYXRlTm9kZXNUb0FwcGx5R3Jhdml0YXRpb25UbyA9IGZ1bmN0aW9uICgpIHtcbiAgdmFyIG5vZGVMaXN0ID0gW107XG4gIHZhciBncmFwaDtcblxuICB2YXIgZ3JhcGhzID0gdGhpcy5ncmFwaE1hbmFnZXIuZ2V0R3JhcGhzKCk7XG4gIHZhciBzaXplID0gZ3JhcGhzLmxlbmd0aDtcbiAgdmFyIGk7XG4gIGZvciAoaSA9IDA7IGkgPCBzaXplOyBpKyspXG4gIHtcbiAgICBncmFwaCA9IGdyYXBoc1tpXTtcblxuICAgIGdyYXBoLnVwZGF0ZUNvbm5lY3RlZCgpO1xuXG4gICAgaWYgKCFncmFwaC5pc0Nvbm5lY3RlZClcbiAgICB7XG4gICAgICBub2RlTGlzdCA9IG5vZGVMaXN0LmNvbmNhdChncmFwaC5nZXROb2RlcygpKTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gbm9kZUxpc3Q7XG59O1xuXG5Db1NFTGF5b3V0LnByb3RvdHlwZS5jYWxjTm9PZkNoaWxkcmVuRm9yQWxsTm9kZXMgPSBmdW5jdGlvbiAoKVxue1xuICB2YXIgbm9kZTtcbiAgdmFyIGFsbE5vZGVzID0gdGhpcy5ncmFwaE1hbmFnZXIuZ2V0QWxsTm9kZXMoKTtcbiAgXG4gIGZvcih2YXIgaSA9IDA7IGkgPCBhbGxOb2Rlcy5sZW5ndGg7IGkrKylcbiAge1xuICAgICAgbm9kZSA9IGFsbE5vZGVzW2ldO1xuICAgICAgbm9kZS5ub09mQ2hpbGRyZW4gPSBub2RlLmdldE5vT2ZDaGlsZHJlbigpO1xuICB9XG59O1xuXG5Db1NFTGF5b3V0LnByb3RvdHlwZS5jcmVhdGVCZW5kcG9pbnRzID0gZnVuY3Rpb24gKCkge1xuICB2YXIgZWRnZXMgPSBbXTtcbiAgZWRnZXMgPSBlZGdlcy5jb25jYXQodGhpcy5ncmFwaE1hbmFnZXIuZ2V0QWxsRWRnZXMoKSk7XG4gIHZhciB2aXNpdGVkID0gbmV3IEhhc2hTZXQoKTtcbiAgdmFyIGk7XG4gIGZvciAoaSA9IDA7IGkgPCBlZGdlcy5sZW5ndGg7IGkrKylcbiAge1xuICAgIHZhciBlZGdlID0gZWRnZXNbaV07XG5cbiAgICBpZiAoIXZpc2l0ZWQuY29udGFpbnMoZWRnZSkpXG4gICAge1xuICAgICAgdmFyIHNvdXJjZSA9IGVkZ2UuZ2V0U291cmNlKCk7XG4gICAgICB2YXIgdGFyZ2V0ID0gZWRnZS5nZXRUYXJnZXQoKTtcblxuICAgICAgaWYgKHNvdXJjZSA9PSB0YXJnZXQpXG4gICAgICB7XG4gICAgICAgIGVkZ2UuZ2V0QmVuZHBvaW50cygpLnB1c2gobmV3IFBvaW50RCgpKTtcbiAgICAgICAgZWRnZS5nZXRCZW5kcG9pbnRzKCkucHVzaChuZXcgUG9pbnREKCkpO1xuICAgICAgICB0aGlzLmNyZWF0ZUR1bW15Tm9kZXNGb3JCZW5kcG9pbnRzKGVkZ2UpO1xuICAgICAgICB2aXNpdGVkLmFkZChlZGdlKTtcbiAgICAgIH1cbiAgICAgIGVsc2VcbiAgICAgIHtcbiAgICAgICAgdmFyIGVkZ2VMaXN0ID0gW107XG5cbiAgICAgICAgZWRnZUxpc3QgPSBlZGdlTGlzdC5jb25jYXQoc291cmNlLmdldEVkZ2VMaXN0VG9Ob2RlKHRhcmdldCkpO1xuICAgICAgICBlZGdlTGlzdCA9IGVkZ2VMaXN0LmNvbmNhdCh0YXJnZXQuZ2V0RWRnZUxpc3RUb05vZGUoc291cmNlKSk7XG5cbiAgICAgICAgaWYgKCF2aXNpdGVkLmNvbnRhaW5zKGVkZ2VMaXN0WzBdKSlcbiAgICAgICAge1xuICAgICAgICAgIGlmIChlZGdlTGlzdC5sZW5ndGggPiAxKVxuICAgICAgICAgIHtcbiAgICAgICAgICAgIHZhciBrO1xuICAgICAgICAgICAgZm9yIChrID0gMDsgayA8IGVkZ2VMaXN0Lmxlbmd0aDsgaysrKVxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICB2YXIgbXVsdGlFZGdlID0gZWRnZUxpc3Rba107XG4gICAgICAgICAgICAgIG11bHRpRWRnZS5nZXRCZW5kcG9pbnRzKCkucHVzaChuZXcgUG9pbnREKCkpO1xuICAgICAgICAgICAgICB0aGlzLmNyZWF0ZUR1bW15Tm9kZXNGb3JCZW5kcG9pbnRzKG11bHRpRWRnZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICAgIHZpc2l0ZWQuYWRkQWxsKGxpc3QpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKHZpc2l0ZWQuc2l6ZSgpID09IGVkZ2VzLmxlbmd0aClcbiAgICB7XG4gICAgICBicmVhaztcbiAgICB9XG4gIH1cbn07XG5cbkNvU0VMYXlvdXQucHJvdG90eXBlLnBvc2l0aW9uTm9kZXNSYWRpYWxseSA9IGZ1bmN0aW9uIChmb3Jlc3QpIHtcbiAgLy8gV2UgdGlsZSB0aGUgdHJlZXMgdG8gYSBncmlkIHJvdyBieSByb3c7IGZpcnN0IHRyZWUgc3RhcnRzIGF0ICgwLDApXG4gIHZhciBjdXJyZW50U3RhcnRpbmdQb2ludCA9IG5ldyBQb2ludCgwLCAwKTtcbiAgdmFyIG51bWJlck9mQ29sdW1ucyA9IE1hdGguY2VpbChNYXRoLnNxcnQoZm9yZXN0Lmxlbmd0aCkpO1xuICB2YXIgaGVpZ2h0ID0gMDtcbiAgdmFyIGN1cnJlbnRZID0gMDtcbiAgdmFyIGN1cnJlbnRYID0gMDtcbiAgdmFyIHBvaW50ID0gbmV3IFBvaW50RCgwLCAwKTtcblxuICBmb3IgKHZhciBpID0gMDsgaSA8IGZvcmVzdC5sZW5ndGg7IGkrKylcbiAge1xuICAgIGlmIChpICUgbnVtYmVyT2ZDb2x1bW5zID09IDApXG4gICAge1xuICAgICAgLy8gU3RhcnQgb2YgYSBuZXcgcm93LCBtYWtlIHRoZSB4IGNvb3JkaW5hdGUgMCwgaW5jcmVtZW50IHRoZVxuICAgICAgLy8geSBjb29yZGluYXRlIHdpdGggdGhlIG1heCBoZWlnaHQgb2YgdGhlIHByZXZpb3VzIHJvd1xuICAgICAgY3VycmVudFggPSAwO1xuICAgICAgY3VycmVudFkgPSBoZWlnaHQ7XG5cbiAgICAgIGlmIChpICE9IDApXG4gICAgICB7XG4gICAgICAgIGN1cnJlbnRZICs9IENvU0VDb25zdGFudHMuREVGQVVMVF9DT01QT05FTlRfU0VQRVJBVElPTjtcbiAgICAgIH1cblxuICAgICAgaGVpZ2h0ID0gMDtcbiAgICB9XG5cbiAgICB2YXIgdHJlZSA9IGZvcmVzdFtpXTtcblxuICAgIC8vIEZpbmQgdGhlIGNlbnRlciBvZiB0aGUgdHJlZVxuICAgIHZhciBjZW50ZXJOb2RlID0gTGF5b3V0LmZpbmRDZW50ZXJPZlRyZWUodHJlZSk7XG5cbiAgICAvLyBTZXQgdGhlIHN0YXJpbmcgcG9pbnQgb2YgdGhlIG5leHQgdHJlZVxuICAgIGN1cnJlbnRTdGFydGluZ1BvaW50LnggPSBjdXJyZW50WDtcbiAgICBjdXJyZW50U3RhcnRpbmdQb2ludC55ID0gY3VycmVudFk7XG5cbiAgICAvLyBEbyBhIHJhZGlhbCBsYXlvdXQgc3RhcnRpbmcgd2l0aCB0aGUgY2VudGVyXG4gICAgcG9pbnQgPVxuICAgICAgICAgICAgQ29TRUxheW91dC5yYWRpYWxMYXlvdXQodHJlZSwgY2VudGVyTm9kZSwgY3VycmVudFN0YXJ0aW5nUG9pbnQpO1xuXG4gICAgaWYgKHBvaW50LnkgPiBoZWlnaHQpXG4gICAge1xuICAgICAgaGVpZ2h0ID0gTWF0aC5mbG9vcihwb2ludC55KTtcbiAgICB9XG5cbiAgICBjdXJyZW50WCA9IE1hdGguZmxvb3IocG9pbnQueCArIENvU0VDb25zdGFudHMuREVGQVVMVF9DT01QT05FTlRfU0VQRVJBVElPTik7XG4gIH1cblxuICB0aGlzLnRyYW5zZm9ybShcbiAgICAgICAgICBuZXcgUG9pbnREKExheW91dENvbnN0YW50cy5XT1JMRF9DRU5URVJfWCAtIHBvaW50LnggLyAyLFxuICAgICAgICAgICAgICAgICAgTGF5b3V0Q29uc3RhbnRzLldPUkxEX0NFTlRFUl9ZIC0gcG9pbnQueSAvIDIpKTtcbn07XG5cbkNvU0VMYXlvdXQucmFkaWFsTGF5b3V0ID0gZnVuY3Rpb24gKHRyZWUsIGNlbnRlck5vZGUsIHN0YXJ0aW5nUG9pbnQpIHtcbiAgdmFyIHJhZGlhbFNlcCA9IE1hdGgubWF4KHRoaXMubWF4RGlhZ29uYWxJblRyZWUodHJlZSksXG4gICAgICAgICAgQ29TRUNvbnN0YW50cy5ERUZBVUxUX1JBRElBTF9TRVBBUkFUSU9OKTtcbiAgQ29TRUxheW91dC5icmFuY2hSYWRpYWxMYXlvdXQoY2VudGVyTm9kZSwgbnVsbCwgMCwgMzU5LCAwLCByYWRpYWxTZXApO1xuICB2YXIgYm91bmRzID0gTEdyYXBoLmNhbGN1bGF0ZUJvdW5kcyh0cmVlKTtcblxuICB2YXIgdHJhbnNmb3JtID0gbmV3IFRyYW5zZm9ybSgpO1xuICB0cmFuc2Zvcm0uc2V0RGV2aWNlT3JnWChib3VuZHMuZ2V0TWluWCgpKTtcbiAgdHJhbnNmb3JtLnNldERldmljZU9yZ1koYm91bmRzLmdldE1pblkoKSk7XG4gIHRyYW5zZm9ybS5zZXRXb3JsZE9yZ1goc3RhcnRpbmdQb2ludC54KTtcbiAgdHJhbnNmb3JtLnNldFdvcmxkT3JnWShzdGFydGluZ1BvaW50LnkpO1xuXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgdHJlZS5sZW5ndGg7IGkrKylcbiAge1xuICAgIHZhciBub2RlID0gdHJlZVtpXTtcbiAgICBub2RlLnRyYW5zZm9ybSh0cmFuc2Zvcm0pO1xuICB9XG5cbiAgdmFyIGJvdHRvbVJpZ2h0ID1cbiAgICAgICAgICBuZXcgUG9pbnREKGJvdW5kcy5nZXRNYXhYKCksIGJvdW5kcy5nZXRNYXhZKCkpO1xuXG4gIHJldHVybiB0cmFuc2Zvcm0uaW52ZXJzZVRyYW5zZm9ybVBvaW50KGJvdHRvbVJpZ2h0KTtcbn07XG5cbkNvU0VMYXlvdXQuYnJhbmNoUmFkaWFsTGF5b3V0ID0gZnVuY3Rpb24gKG5vZGUsIHBhcmVudE9mTm9kZSwgc3RhcnRBbmdsZSwgZW5kQW5nbGUsIGRpc3RhbmNlLCByYWRpYWxTZXBhcmF0aW9uKSB7XG4gIC8vIEZpcnN0LCBwb3NpdGlvbiB0aGlzIG5vZGUgYnkgZmluZGluZyBpdHMgYW5nbGUuXG4gIHZhciBoYWxmSW50ZXJ2YWwgPSAoKGVuZEFuZ2xlIC0gc3RhcnRBbmdsZSkgKyAxKSAvIDI7XG5cbiAgaWYgKGhhbGZJbnRlcnZhbCA8IDApXG4gIHtcbiAgICBoYWxmSW50ZXJ2YWwgKz0gMTgwO1xuICB9XG5cbiAgdmFyIG5vZGVBbmdsZSA9IChoYWxmSW50ZXJ2YWwgKyBzdGFydEFuZ2xlKSAlIDM2MDtcbiAgdmFyIHRldGEgPSAobm9kZUFuZ2xlICogSUdlb21ldHJ5LlRXT19QSSkgLyAzNjA7XG5cbiAgLy8gTWFrZSBwb2xhciB0byBqYXZhIGNvcmRpbmF0ZSBjb252ZXJzaW9uLlxuICB2YXIgY29zX3RldGEgPSBNYXRoLmNvcyh0ZXRhKTtcbiAgdmFyIHhfID0gZGlzdGFuY2UgKiBNYXRoLmNvcyh0ZXRhKTtcbiAgdmFyIHlfID0gZGlzdGFuY2UgKiBNYXRoLnNpbih0ZXRhKTtcblxuICBub2RlLnNldENlbnRlcih4XywgeV8pO1xuXG4gIC8vIFRyYXZlcnNlIGFsbCBuZWlnaGJvcnMgb2YgdGhpcyBub2RlIGFuZCByZWN1cnNpdmVseSBjYWxsIHRoaXNcbiAgLy8gZnVuY3Rpb24uXG4gIHZhciBuZWlnaGJvckVkZ2VzID0gW107XG4gIG5laWdoYm9yRWRnZXMgPSBuZWlnaGJvckVkZ2VzLmNvbmNhdChub2RlLmdldEVkZ2VzKCkpO1xuICB2YXIgY2hpbGRDb3VudCA9IG5laWdoYm9yRWRnZXMubGVuZ3RoO1xuXG4gIGlmIChwYXJlbnRPZk5vZGUgIT0gbnVsbClcbiAge1xuICAgIGNoaWxkQ291bnQtLTtcbiAgfVxuXG4gIHZhciBicmFuY2hDb3VudCA9IDA7XG5cbiAgdmFyIGluY0VkZ2VzQ291bnQgPSBuZWlnaGJvckVkZ2VzLmxlbmd0aDtcbiAgdmFyIHN0YXJ0SW5kZXg7XG5cbiAgdmFyIGVkZ2VzID0gbm9kZS5nZXRFZGdlc0JldHdlZW4ocGFyZW50T2ZOb2RlKTtcblxuICAvLyBJZiB0aGVyZSBhcmUgbXVsdGlwbGUgZWRnZXMsIHBydW5lIHRoZW0gdW50aWwgdGhlcmUgcmVtYWlucyBvbmx5IG9uZVxuICAvLyBlZGdlLlxuICB3aGlsZSAoZWRnZXMubGVuZ3RoID4gMSlcbiAge1xuICAgIC8vbmVpZ2hib3JFZGdlcy5yZW1vdmUoZWRnZXMucmVtb3ZlKDApKTtcbiAgICB2YXIgdGVtcCA9IGVkZ2VzWzBdO1xuICAgIGVkZ2VzLnNwbGljZSgwLCAxKTtcbiAgICB2YXIgaW5kZXggPSBuZWlnaGJvckVkZ2VzLmluZGV4T2YodGVtcCk7XG4gICAgaWYgKGluZGV4ID49IDApIHtcbiAgICAgIG5laWdoYm9yRWRnZXMuc3BsaWNlKGluZGV4LCAxKTtcbiAgICB9XG4gICAgaW5jRWRnZXNDb3VudC0tO1xuICAgIGNoaWxkQ291bnQtLTtcbiAgfVxuXG4gIGlmIChwYXJlbnRPZk5vZGUgIT0gbnVsbClcbiAge1xuICAgIC8vYXNzZXJ0IGVkZ2VzLmxlbmd0aCA9PSAxO1xuICAgIHN0YXJ0SW5kZXggPSAobmVpZ2hib3JFZGdlcy5pbmRleE9mKGVkZ2VzWzBdKSArIDEpICUgaW5jRWRnZXNDb3VudDtcbiAgfVxuICBlbHNlXG4gIHtcbiAgICBzdGFydEluZGV4ID0gMDtcbiAgfVxuXG4gIHZhciBzdGVwQW5nbGUgPSBNYXRoLmFicyhlbmRBbmdsZSAtIHN0YXJ0QW5nbGUpIC8gY2hpbGRDb3VudDtcblxuICBmb3IgKHZhciBpID0gc3RhcnRJbmRleDtcbiAgICAgICAgICBicmFuY2hDb3VudCAhPSBjaGlsZENvdW50O1xuICAgICAgICAgIGkgPSAoKytpKSAlIGluY0VkZ2VzQ291bnQpXG4gIHtcbiAgICB2YXIgY3VycmVudE5laWdoYm9yID1cbiAgICAgICAgICAgIG5laWdoYm9yRWRnZXNbaV0uZ2V0T3RoZXJFbmQobm9kZSk7XG5cbiAgICAvLyBEb24ndCBiYWNrIHRyYXZlcnNlIHRvIHJvb3Qgbm9kZSBpbiBjdXJyZW50IHRyZWUuXG4gICAgaWYgKGN1cnJlbnROZWlnaGJvciA9PSBwYXJlbnRPZk5vZGUpXG4gICAge1xuICAgICAgY29udGludWU7XG4gICAgfVxuXG4gICAgdmFyIGNoaWxkU3RhcnRBbmdsZSA9XG4gICAgICAgICAgICAoc3RhcnRBbmdsZSArIGJyYW5jaENvdW50ICogc3RlcEFuZ2xlKSAlIDM2MDtcbiAgICB2YXIgY2hpbGRFbmRBbmdsZSA9IChjaGlsZFN0YXJ0QW5nbGUgKyBzdGVwQW5nbGUpICUgMzYwO1xuXG4gICAgQ29TRUxheW91dC5icmFuY2hSYWRpYWxMYXlvdXQoY3VycmVudE5laWdoYm9yLFxuICAgICAgICAgICAgbm9kZSxcbiAgICAgICAgICAgIGNoaWxkU3RhcnRBbmdsZSwgY2hpbGRFbmRBbmdsZSxcbiAgICAgICAgICAgIGRpc3RhbmNlICsgcmFkaWFsU2VwYXJhdGlvbiwgcmFkaWFsU2VwYXJhdGlvbik7XG5cbiAgICBicmFuY2hDb3VudCsrO1xuICB9XG59O1xuXG5Db1NFTGF5b3V0Lm1heERpYWdvbmFsSW5UcmVlID0gZnVuY3Rpb24gKHRyZWUpIHtcbiAgdmFyIG1heERpYWdvbmFsID0gSW50ZWdlci5NSU5fVkFMVUU7XG5cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCB0cmVlLmxlbmd0aDsgaSsrKVxuICB7XG4gICAgdmFyIG5vZGUgPSB0cmVlW2ldO1xuICAgIHZhciBkaWFnb25hbCA9IG5vZGUuZ2V0RGlhZ29uYWwoKTtcblxuICAgIGlmIChkaWFnb25hbCA+IG1heERpYWdvbmFsKVxuICAgIHtcbiAgICAgIG1heERpYWdvbmFsID0gZGlhZ29uYWw7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIG1heERpYWdvbmFsO1xufTtcblxuQ29TRUxheW91dC5wcm90b3R5cGUuY2FsY1JlcHVsc2lvblJhbmdlID0gZnVuY3Rpb24gKCkge1xuICAvLyBmb3JtdWxhIGlzIDIgeCAobGV2ZWwgKyAxKSB4IGlkZWFsRWRnZUxlbmd0aFxuICByZXR1cm4gKDIgKiAodGhpcy5sZXZlbCArIDEpICogdGhpcy5pZGVhbEVkZ2VMZW5ndGgpO1xufTtcblxuLy8gVGlsaW5nIG1ldGhvZHNcblxuLy8gR3JvdXAgemVybyBkZWdyZWUgbWVtYmVycyB3aG9zZSBwYXJlbnRzIGFyZSBub3QgdG8gYmUgdGlsZWQsIGNyZWF0ZSBkdW1teSBwYXJlbnRzIHdoZXJlIG5lZWRlZCBhbmQgZmlsbCBtZW1iZXJHcm91cHMgYnkgdGhlaXIgZHVtbXAgcGFyZW50IGlkJ3NcbkNvU0VMYXlvdXQucHJvdG90eXBlLmdyb3VwWmVyb0RlZ3JlZU1lbWJlcnMgPSBmdW5jdGlvbiAoKSB7XG4gIHZhciBzZWxmID0gdGhpcztcbiAgLy8gYXJyYXkgb2YgW3BhcmVudF9pZCB4IG9uZURlZ3JlZU5vZGVfaWRdXG4gIHZhciB0ZW1wTWVtYmVyR3JvdXBzID0ge307IC8vIEEgdGVtcG9yYXJ5IG1hcCBvZiBwYXJlbnQgbm9kZSBhbmQgaXRzIHplcm8gZGVncmVlIG1lbWJlcnNcbiAgdGhpcy5tZW1iZXJHcm91cHMgPSB7fTsgLy8gQSBtYXAgb2YgZHVtbXkgcGFyZW50IG5vZGUgYW5kIGl0cyB6ZXJvIGRlZ3JlZSBtZW1iZXJzIHdob3NlIHBhcmVudHMgYXJlIG5vdCB0byBiZSB0aWxlZFxuICB0aGlzLmlkVG9EdW1teU5vZGUgPSB7fTsgLy8gQSBtYXAgb2YgaWQgdG8gZHVtbXkgbm9kZSBcbiAgXG4gIHZhciB6ZXJvRGVncmVlID0gW107IC8vIExpc3Qgb2YgemVybyBkZWdyZWUgbm9kZXMgd2hvc2UgcGFyZW50cyBhcmUgbm90IHRvIGJlIHRpbGVkXG4gIHZhciBhbGxOb2RlcyA9IHRoaXMuZ3JhcGhNYW5hZ2VyLmdldEFsbE5vZGVzKCk7XG5cbiAgLy8gRmlsbCB6ZXJvIGRlZ3JlZSBsaXN0XG4gIGZvciAodmFyIGkgPSAwOyBpIDwgYWxsTm9kZXMubGVuZ3RoOyBpKyspIHtcbiAgICB2YXIgbm9kZSA9IGFsbE5vZGVzW2ldO1xuICAgIHZhciBwYXJlbnQgPSBub2RlLmdldFBhcmVudCgpO1xuICAgIC8vIElmIGEgbm9kZSBoYXMgemVybyBkZWdyZWUgYW5kIGl0cyBwYXJlbnQgaXMgbm90IHRvIGJlIHRpbGVkIGlmIGV4aXN0cyBhZGQgdGhhdCBub2RlIHRvIHplcm9EZWdyZXMgbGlzdFxuICAgIGlmICh0aGlzLmdldE5vZGVEZWdyZWVXaXRoQ2hpbGRyZW4obm9kZSkgPT09IDAgJiYgKCBwYXJlbnQuaWQgPT0gdW5kZWZpbmVkIHx8ICF0aGlzLmdldFRvQmVUaWxlZChwYXJlbnQpICkgKSB7XG4gICAgICB6ZXJvRGVncmVlLnB1c2gobm9kZSk7XG4gICAgfVxuICB9XG5cbiAgLy8gQ3JlYXRlIGEgbWFwIG9mIHBhcmVudCBub2RlIGFuZCBpdHMgemVybyBkZWdyZWUgbWVtYmVyc1xuICBmb3IgKHZhciBpID0gMDsgaSA8IHplcm9EZWdyZWUubGVuZ3RoOyBpKyspXG4gIHtcbiAgICB2YXIgbm9kZSA9IHplcm9EZWdyZWVbaV07IC8vIFplcm8gZGVncmVlIG5vZGUgaXRzZWxmXG4gICAgdmFyIHBfaWQgPSBub2RlLmdldFBhcmVudCgpLmlkOyAvLyBQYXJlbnQgaWRcblxuICAgIGlmICh0eXBlb2YgdGVtcE1lbWJlckdyb3Vwc1twX2lkXSA9PT0gXCJ1bmRlZmluZWRcIilcbiAgICAgIHRlbXBNZW1iZXJHcm91cHNbcF9pZF0gPSBbXTtcblxuICAgIHRlbXBNZW1iZXJHcm91cHNbcF9pZF0gPSB0ZW1wTWVtYmVyR3JvdXBzW3BfaWRdLmNvbmNhdChub2RlKTsgLy8gUHVzaCBub2RlIHRvIHRoZSBsaXN0IGJlbG9uZ3MgdG8gaXRzIHBhcmVudCBpbiB0ZW1wTWVtYmVyR3JvdXBzXG4gIH1cblxuICAvLyBJZiB0aGVyZSBhcmUgYXQgbGVhc3QgdHdvIG5vZGVzIGF0IGEgbGV2ZWwsIGNyZWF0ZSBhIGR1bW15IGNvbXBvdW5kIGZvciB0aGVtXG4gIE9iamVjdC5rZXlzKHRlbXBNZW1iZXJHcm91cHMpLmZvckVhY2goZnVuY3Rpb24ocF9pZCkge1xuICAgIGlmICh0ZW1wTWVtYmVyR3JvdXBzW3BfaWRdLmxlbmd0aCA+IDEpIHtcbiAgICAgIHZhciBkdW1teUNvbXBvdW5kSWQgPSBcIkR1bW15Q29tcG91bmRfXCIgKyBwX2lkOyAvLyBUaGUgaWQgb2YgZHVtbXkgY29tcG91bmQgd2hpY2ggd2lsbCBiZSBjcmVhdGVkIHNvb25cbiAgICAgIHNlbGYubWVtYmVyR3JvdXBzW2R1bW15Q29tcG91bmRJZF0gPSB0ZW1wTWVtYmVyR3JvdXBzW3BfaWRdOyAvLyBBZGQgZHVtbXkgY29tcG91bmQgdG8gbWVtYmVyR3JvdXBzXG5cbiAgICAgIHZhciBwYXJlbnQgPSB0ZW1wTWVtYmVyR3JvdXBzW3BfaWRdWzBdLmdldFBhcmVudCgpOyAvLyBUaGUgcGFyZW50IG9mIHplcm8gZGVncmVlIG5vZGVzIHdpbGwgYmUgdGhlIHBhcmVudCBvZiBuZXcgZHVtbXkgY29tcG91bmRcblxuICAgICAgLy8gQ3JlYXRlIGEgZHVtbXkgY29tcG91bmQgd2l0aCBjYWxjdWxhdGVkIGlkXG4gICAgICB2YXIgZHVtbXlDb21wb3VuZCA9IG5ldyBDb1NFTm9kZShzZWxmLmdyYXBoTWFuYWdlcik7XG4gICAgICBkdW1teUNvbXBvdW5kLmlkID0gZHVtbXlDb21wb3VuZElkO1xuICAgICAgZHVtbXlDb21wb3VuZC5wYWRkaW5nTGVmdCA9IHBhcmVudC5wYWRkaW5nTGVmdCB8fCAwO1xuICAgICAgZHVtbXlDb21wb3VuZC5wYWRkaW5nUmlnaHQgPSBwYXJlbnQucGFkZGluZ1JpZ2h0IHx8IDA7XG4gICAgICBkdW1teUNvbXBvdW5kLnBhZGRpbmdCb3R0b20gPSBwYXJlbnQucGFkZGluZ0JvdHRvbSB8fCAwO1xuICAgICAgZHVtbXlDb21wb3VuZC5wYWRkaW5nVG9wID0gcGFyZW50LnBhZGRpbmdUb3AgfHwgMDtcbiAgICAgIFxuICAgICAgc2VsZi5pZFRvRHVtbXlOb2RlW2R1bW15Q29tcG91bmRJZF0gPSBkdW1teUNvbXBvdW5kO1xuICAgICAgXG4gICAgICB2YXIgZHVtbXlQYXJlbnRHcmFwaCA9IHNlbGYuZ2V0R3JhcGhNYW5hZ2VyKCkuYWRkKHNlbGYubmV3R3JhcGgoKSwgZHVtbXlDb21wb3VuZCk7XG4gICAgICB2YXIgcGFyZW50R3JhcGggPSBwYXJlbnQuZ2V0Q2hpbGQoKTtcblxuICAgICAgLy8gQWRkIGR1bW15IGNvbXBvdW5kIHRvIHBhcmVudCB0aGUgZ3JhcGhcbiAgICAgIHBhcmVudEdyYXBoLmFkZChkdW1teUNvbXBvdW5kKTtcblxuICAgICAgLy8gRm9yIGVhY2ggemVybyBkZWdyZWUgbm9kZSBpbiB0aGlzIGxldmVsIHJlbW92ZSBpdCBmcm9tIGl0cyBwYXJlbnQgZ3JhcGggYW5kIGFkZCBpdCB0byB0aGUgZ3JhcGggb2YgZHVtbXkgcGFyZW50XG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRlbXBNZW1iZXJHcm91cHNbcF9pZF0ubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdmFyIG5vZGUgPSB0ZW1wTWVtYmVyR3JvdXBzW3BfaWRdW2ldO1xuICAgICAgICBcbiAgICAgICAgcGFyZW50R3JhcGgucmVtb3ZlKG5vZGUpO1xuICAgICAgICBkdW1teVBhcmVudEdyYXBoLmFkZChub2RlKTtcbiAgICAgIH1cbiAgICB9XG4gIH0pO1xufTtcblxuQ29TRUxheW91dC5wcm90b3R5cGUuY2xlYXJDb21wb3VuZHMgPSBmdW5jdGlvbiAoKSB7XG4gIHZhciBjaGlsZEdyYXBoTWFwID0ge307XG4gIHZhciBpZFRvTm9kZSA9IHt9O1xuXG4gIC8vIEdldCBjb21wb3VuZCBvcmRlcmluZyBieSBmaW5kaW5nIHRoZSBpbm5lciBvbmUgZmlyc3RcbiAgdGhpcy5wZXJmb3JtREZTT25Db21wb3VuZHMoKTtcblxuICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMuY29tcG91bmRPcmRlci5sZW5ndGg7IGkrKykge1xuICAgIFxuICAgIGlkVG9Ob2RlW3RoaXMuY29tcG91bmRPcmRlcltpXS5pZF0gPSB0aGlzLmNvbXBvdW5kT3JkZXJbaV07XG4gICAgY2hpbGRHcmFwaE1hcFt0aGlzLmNvbXBvdW5kT3JkZXJbaV0uaWRdID0gW10uY29uY2F0KHRoaXMuY29tcG91bmRPcmRlcltpXS5nZXRDaGlsZCgpLmdldE5vZGVzKCkpO1xuXG4gICAgLy8gUmVtb3ZlIGNoaWxkcmVuIG9mIGNvbXBvdW5kc1xuICAgIHRoaXMuZ3JhcGhNYW5hZ2VyLnJlbW92ZSh0aGlzLmNvbXBvdW5kT3JkZXJbaV0uZ2V0Q2hpbGQoKSk7XG4gICAgdGhpcy5jb21wb3VuZE9yZGVyW2ldLmNoaWxkID0gbnVsbDtcbiAgfVxuICBcbiAgdGhpcy5ncmFwaE1hbmFnZXIucmVzZXRBbGxOb2RlcygpO1xuICBcbiAgLy8gVGlsZSB0aGUgcmVtb3ZlZCBjaGlsZHJlblxuICB0aGlzLnRpbGVDb21wb3VuZE1lbWJlcnMoY2hpbGRHcmFwaE1hcCwgaWRUb05vZGUpO1xufTtcblxuQ29TRUxheW91dC5wcm90b3R5cGUuY2xlYXJaZXJvRGVncmVlTWVtYmVycyA9IGZ1bmN0aW9uICgpIHtcbiAgdmFyIHNlbGYgPSB0aGlzO1xuICB2YXIgdGlsZWRaZXJvRGVncmVlUGFjayA9IHRoaXMudGlsZWRaZXJvRGVncmVlUGFjayA9IFtdO1xuXG4gIE9iamVjdC5rZXlzKHRoaXMubWVtYmVyR3JvdXBzKS5mb3JFYWNoKGZ1bmN0aW9uKGlkKSB7XG4gICAgdmFyIGNvbXBvdW5kTm9kZSA9IHNlbGYuaWRUb0R1bW15Tm9kZVtpZF07IC8vIEdldCB0aGUgZHVtbXkgY29tcG91bmRcblxuICAgIHRpbGVkWmVyb0RlZ3JlZVBhY2tbaWRdID0gc2VsZi50aWxlTm9kZXMoc2VsZi5tZW1iZXJHcm91cHNbaWRdLCBjb21wb3VuZE5vZGUucGFkZGluZ0xlZnQgKyBjb21wb3VuZE5vZGUucGFkZGluZ1JpZ2h0KTtcblxuICAgIC8vIFNldCB0aGUgd2lkdGggYW5kIGhlaWdodCBvZiB0aGUgZHVtbXkgY29tcG91bmQgYXMgY2FsY3VsYXRlZFxuICAgIGNvbXBvdW5kTm9kZS5yZWN0LndpZHRoID0gdGlsZWRaZXJvRGVncmVlUGFja1tpZF0ud2lkdGg7XG4gICAgY29tcG91bmROb2RlLnJlY3QuaGVpZ2h0ID0gdGlsZWRaZXJvRGVncmVlUGFja1tpZF0uaGVpZ2h0O1xuICB9KTtcbn07XG5cbkNvU0VMYXlvdXQucHJvdG90eXBlLnJlcG9wdWxhdGVDb21wb3VuZHMgPSBmdW5jdGlvbiAoKSB7XG4gIGZvciAodmFyIGkgPSB0aGlzLmNvbXBvdW5kT3JkZXIubGVuZ3RoIC0gMTsgaSA+PSAwOyBpLS0pIHtcbiAgICB2YXIgbENvbXBvdW5kTm9kZSA9IHRoaXMuY29tcG91bmRPcmRlcltpXTtcbiAgICB2YXIgaWQgPSBsQ29tcG91bmROb2RlLmlkO1xuICAgIHZhciBob3Jpem9udGFsTWFyZ2luID0gbENvbXBvdW5kTm9kZS5wYWRkaW5nTGVmdDtcbiAgICB2YXIgdmVydGljYWxNYXJnaW4gPSBsQ29tcG91bmROb2RlLnBhZGRpbmdUb3A7XG5cbiAgICB0aGlzLmFkanVzdExvY2F0aW9ucyh0aGlzLnRpbGVkTWVtYmVyUGFja1tpZF0sIGxDb21wb3VuZE5vZGUucmVjdC54LCBsQ29tcG91bmROb2RlLnJlY3QueSwgaG9yaXpvbnRhbE1hcmdpbiwgdmVydGljYWxNYXJnaW4pO1xuICB9XG59O1xuXG5Db1NFTGF5b3V0LnByb3RvdHlwZS5yZXBvcHVsYXRlWmVyb0RlZ3JlZU1lbWJlcnMgPSBmdW5jdGlvbiAoKSB7XG4gIHZhciBzZWxmID0gdGhpcztcbiAgdmFyIHRpbGVkUGFjayA9IHRoaXMudGlsZWRaZXJvRGVncmVlUGFjaztcbiAgXG4gIE9iamVjdC5rZXlzKHRpbGVkUGFjaykuZm9yRWFjaChmdW5jdGlvbihpZCkge1xuICAgIHZhciBjb21wb3VuZE5vZGUgPSBzZWxmLmlkVG9EdW1teU5vZGVbaWRdOyAvLyBHZXQgdGhlIGR1bW15IGNvbXBvdW5kIGJ5IGl0cyBpZFxuICAgIHZhciBob3Jpem9udGFsTWFyZ2luID0gY29tcG91bmROb2RlLnBhZGRpbmdMZWZ0O1xuICAgIHZhciB2ZXJ0aWNhbE1hcmdpbiA9IGNvbXBvdW5kTm9kZS5wYWRkaW5nVG9wO1xuXG4gICAgLy8gQWRqdXN0IHRoZSBwb3NpdGlvbnMgb2Ygbm9kZXMgd3J0IGl0cyBjb21wb3VuZFxuICAgIHNlbGYuYWRqdXN0TG9jYXRpb25zKHRpbGVkUGFja1tpZF0sIGNvbXBvdW5kTm9kZS5yZWN0LngsIGNvbXBvdW5kTm9kZS5yZWN0LnksIGhvcml6b250YWxNYXJnaW4sIHZlcnRpY2FsTWFyZ2luKTtcbiAgfSk7XG59O1xuXG5Db1NFTGF5b3V0LnByb3RvdHlwZS5nZXRUb0JlVGlsZWQgPSBmdW5jdGlvbiAobm9kZSkge1xuICB2YXIgaWQgPSBub2RlLmlkO1xuICAvL2ZpcnN0bHkgY2hlY2sgdGhlIHByZXZpb3VzIHJlc3VsdHNcbiAgaWYgKHRoaXMudG9CZVRpbGVkW2lkXSAhPSBudWxsKSB7XG4gICAgcmV0dXJuIHRoaXMudG9CZVRpbGVkW2lkXTtcbiAgfVxuXG4gIC8vb25seSBjb21wb3VuZCBub2RlcyBhcmUgdG8gYmUgdGlsZWRcbiAgdmFyIGNoaWxkR3JhcGggPSBub2RlLmdldENoaWxkKCk7XG4gIGlmIChjaGlsZEdyYXBoID09IG51bGwpIHtcbiAgICB0aGlzLnRvQmVUaWxlZFtpZF0gPSBmYWxzZTtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICB2YXIgY2hpbGRyZW4gPSBjaGlsZEdyYXBoLmdldE5vZGVzKCk7IC8vIEdldCB0aGUgY2hpbGRyZW4gbm9kZXNcblxuICAvL2EgY29tcG91bmQgbm9kZSBpcyBub3QgdG8gYmUgdGlsZWQgaWYgYWxsIG9mIGl0cyBjb21wb3VuZCBjaGlsZHJlbiBhcmUgbm90IHRvIGJlIHRpbGVkXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgY2hpbGRyZW4ubGVuZ3RoOyBpKyspIHtcbiAgICB2YXIgdGhlQ2hpbGQgPSBjaGlsZHJlbltpXTtcblxuICAgIGlmICh0aGlzLmdldE5vZGVEZWdyZWUodGhlQ2hpbGQpID4gMCkge1xuICAgICAgdGhpcy50b0JlVGlsZWRbaWRdID0gZmFsc2U7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgLy9wYXNzIHRoZSBjaGlsZHJlbiBub3QgaGF2aW5nIHRoZSBjb21wb3VuZCBzdHJ1Y3R1cmVcbiAgICBpZiAodGhlQ2hpbGQuZ2V0Q2hpbGQoKSA9PSBudWxsKSB7XG4gICAgICB0aGlzLnRvQmVUaWxlZFt0aGVDaGlsZC5pZF0gPSBmYWxzZTtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cblxuICAgIGlmICghdGhpcy5nZXRUb0JlVGlsZWQodGhlQ2hpbGQpKSB7XG4gICAgICB0aGlzLnRvQmVUaWxlZFtpZF0gPSBmYWxzZTtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cbiAgdGhpcy50b0JlVGlsZWRbaWRdID0gdHJ1ZTtcbiAgcmV0dXJuIHRydWU7XG59O1xuXG4vLyBHZXQgZGVncmVlIG9mIGEgbm9kZSBkZXBlbmRpbmcgb2YgaXRzIGVkZ2VzIGFuZCBpbmRlcGVuZGVudCBvZiBpdHMgY2hpbGRyZW5cbkNvU0VMYXlvdXQucHJvdG90eXBlLmdldE5vZGVEZWdyZWUgPSBmdW5jdGlvbiAobm9kZSkge1xuICB2YXIgaWQgPSBub2RlLmlkO1xuICB2YXIgZWRnZXMgPSBub2RlLmdldEVkZ2VzKCk7XG4gIHZhciBkZWdyZWUgPSAwO1xuICBcbiAgLy8gRm9yIHRoZSBlZGdlcyBjb25uZWN0ZWRcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBlZGdlcy5sZW5ndGg7IGkrKykge1xuICAgIHZhciBlZGdlID0gZWRnZXNbaV07XG4gICAgaWYgKGVkZ2UuZ2V0U291cmNlKCkuaWQgIT09IGVkZ2UuZ2V0VGFyZ2V0KCkuaWQpIHtcbiAgICAgIGRlZ3JlZSA9IGRlZ3JlZSArIDE7XG4gICAgfVxuICB9XG4gIHJldHVybiBkZWdyZWU7XG59O1xuXG4vLyBHZXQgZGVncmVlIG9mIGEgbm9kZSB3aXRoIGl0cyBjaGlsZHJlblxuQ29TRUxheW91dC5wcm90b3R5cGUuZ2V0Tm9kZURlZ3JlZVdpdGhDaGlsZHJlbiA9IGZ1bmN0aW9uIChub2RlKSB7XG4gIHZhciBkZWdyZWUgPSB0aGlzLmdldE5vZGVEZWdyZWUobm9kZSk7XG4gIGlmIChub2RlLmdldENoaWxkKCkgPT0gbnVsbCkge1xuICAgIHJldHVybiBkZWdyZWU7XG4gIH1cbiAgdmFyIGNoaWxkcmVuID0gbm9kZS5nZXRDaGlsZCgpLmdldE5vZGVzKCk7XG4gIGZvciAodmFyIGkgPSAwOyBpIDwgY2hpbGRyZW4ubGVuZ3RoOyBpKyspIHtcbiAgICB2YXIgY2hpbGQgPSBjaGlsZHJlbltpXTtcbiAgICBkZWdyZWUgKz0gdGhpcy5nZXROb2RlRGVncmVlV2l0aENoaWxkcmVuKGNoaWxkKTtcbiAgfVxuICByZXR1cm4gZGVncmVlO1xufTtcblxuQ29TRUxheW91dC5wcm90b3R5cGUucGVyZm9ybURGU09uQ29tcG91bmRzID0gZnVuY3Rpb24gKCkge1xuICB0aGlzLmNvbXBvdW5kT3JkZXIgPSBbXTtcbiAgdGhpcy5maWxsQ29tcGV4T3JkZXJCeURGUyh0aGlzLmdyYXBoTWFuYWdlci5nZXRSb290KCkuZ2V0Tm9kZXMoKSk7XG59O1xuXG5Db1NFTGF5b3V0LnByb3RvdHlwZS5maWxsQ29tcGV4T3JkZXJCeURGUyA9IGZ1bmN0aW9uIChjaGlsZHJlbikge1xuICBmb3IgKHZhciBpID0gMDsgaSA8IGNoaWxkcmVuLmxlbmd0aDsgaSsrKSB7XG4gICAgdmFyIGNoaWxkID0gY2hpbGRyZW5baV07XG4gICAgaWYgKGNoaWxkLmdldENoaWxkKCkgIT0gbnVsbCkge1xuICAgICAgdGhpcy5maWxsQ29tcGV4T3JkZXJCeURGUyhjaGlsZC5nZXRDaGlsZCgpLmdldE5vZGVzKCkpO1xuICAgIH1cbiAgICBpZiAodGhpcy5nZXRUb0JlVGlsZWQoY2hpbGQpKSB7XG4gICAgICB0aGlzLmNvbXBvdW5kT3JkZXIucHVzaChjaGlsZCk7XG4gICAgfVxuICB9XG59O1xuXG4vKipcbiogVGhpcyBtZXRob2QgcGxhY2VzIGVhY2ggemVybyBkZWdyZWUgbWVtYmVyIHdydCBnaXZlbiAoeCx5KSBjb29yZGluYXRlcyAodG9wIGxlZnQpLlxuKi9cbkNvU0VMYXlvdXQucHJvdG90eXBlLmFkanVzdExvY2F0aW9ucyA9IGZ1bmN0aW9uIChvcmdhbml6YXRpb24sIHgsIHksIGNvbXBvdW5kSG9yaXpvbnRhbE1hcmdpbiwgY29tcG91bmRWZXJ0aWNhbE1hcmdpbikge1xuICB4ICs9IGNvbXBvdW5kSG9yaXpvbnRhbE1hcmdpbjtcbiAgeSArPSBjb21wb3VuZFZlcnRpY2FsTWFyZ2luO1xuXG4gIHZhciBsZWZ0ID0geDtcblxuICBmb3IgKHZhciBpID0gMDsgaSA8IG9yZ2FuaXphdGlvbi5yb3dzLmxlbmd0aDsgaSsrKSB7XG4gICAgdmFyIHJvdyA9IG9yZ2FuaXphdGlvbi5yb3dzW2ldO1xuICAgIHggPSBsZWZ0O1xuICAgIHZhciBtYXhIZWlnaHQgPSAwO1xuXG4gICAgZm9yICh2YXIgaiA9IDA7IGogPCByb3cubGVuZ3RoOyBqKyspIHtcbiAgICAgIHZhciBsbm9kZSA9IHJvd1tqXTtcblxuICAgICAgbG5vZGUucmVjdC54ID0geDsvLyArIGxub2RlLnJlY3Qud2lkdGggLyAyO1xuICAgICAgbG5vZGUucmVjdC55ID0geTsvLyArIGxub2RlLnJlY3QuaGVpZ2h0IC8gMjtcblxuICAgICAgeCArPSBsbm9kZS5yZWN0LndpZHRoICsgb3JnYW5pemF0aW9uLmhvcml6b250YWxQYWRkaW5nO1xuXG4gICAgICBpZiAobG5vZGUucmVjdC5oZWlnaHQgPiBtYXhIZWlnaHQpXG4gICAgICAgIG1heEhlaWdodCA9IGxub2RlLnJlY3QuaGVpZ2h0O1xuICAgIH1cblxuICAgIHkgKz0gbWF4SGVpZ2h0ICsgb3JnYW5pemF0aW9uLnZlcnRpY2FsUGFkZGluZztcbiAgfVxufTtcblxuQ29TRUxheW91dC5wcm90b3R5cGUudGlsZUNvbXBvdW5kTWVtYmVycyA9IGZ1bmN0aW9uIChjaGlsZEdyYXBoTWFwLCBpZFRvTm9kZSkge1xuICB2YXIgc2VsZiA9IHRoaXM7XG4gIHRoaXMudGlsZWRNZW1iZXJQYWNrID0gW107XG5cbiAgT2JqZWN0LmtleXMoY2hpbGRHcmFwaE1hcCkuZm9yRWFjaChmdW5jdGlvbihpZCkge1xuICAgIC8vIEdldCB0aGUgY29tcG91bmQgbm9kZVxuICAgIHZhciBjb21wb3VuZE5vZGUgPSBpZFRvTm9kZVtpZF07XG5cbiAgICBzZWxmLnRpbGVkTWVtYmVyUGFja1tpZF0gPSBzZWxmLnRpbGVOb2RlcyhjaGlsZEdyYXBoTWFwW2lkXSwgY29tcG91bmROb2RlLnBhZGRpbmdMZWZ0ICsgY29tcG91bmROb2RlLnBhZGRpbmdSaWdodCk7XG5cbiAgICBjb21wb3VuZE5vZGUucmVjdC53aWR0aCA9IHNlbGYudGlsZWRNZW1iZXJQYWNrW2lkXS53aWR0aCArIDIwO1xuICAgIGNvbXBvdW5kTm9kZS5yZWN0LmhlaWdodCA9IHNlbGYudGlsZWRNZW1iZXJQYWNrW2lkXS5oZWlnaHQgKyAyMDtcbiAgfSk7XG59O1xuXG5Db1NFTGF5b3V0LnByb3RvdHlwZS50aWxlTm9kZXMgPSBmdW5jdGlvbiAobm9kZXMsIG1pbldpZHRoKSB7XG4gIHZhciB2ZXJ0aWNhbFBhZGRpbmcgPSBDb1NFQ29uc3RhbnRzLlRJTElOR19QQURESU5HX1ZFUlRJQ0FMO1xuICB2YXIgaG9yaXpvbnRhbFBhZGRpbmcgPSBDb1NFQ29uc3RhbnRzLlRJTElOR19QQURESU5HX0hPUklaT05UQUw7XG4gIHZhciBvcmdhbml6YXRpb24gPSB7XG4gICAgcm93czogW10sXG4gICAgcm93V2lkdGg6IFtdLFxuICAgIHJvd0hlaWdodDogW10sXG4gICAgd2lkdGg6IDIwLFxuICAgIGhlaWdodDogMjAsXG4gICAgdmVydGljYWxQYWRkaW5nOiB2ZXJ0aWNhbFBhZGRpbmcsXG4gICAgaG9yaXpvbnRhbFBhZGRpbmc6IGhvcml6b250YWxQYWRkaW5nXG4gIH07XG5cbiAgLy8gU29ydCB0aGUgbm9kZXMgaW4gYXNjZW5kaW5nIG9yZGVyIG9mIHRoZWlyIGFyZWFzXG4gIG5vZGVzLnNvcnQoZnVuY3Rpb24gKG4xLCBuMikge1xuICAgIGlmIChuMS5yZWN0LndpZHRoICogbjEucmVjdC5oZWlnaHQgPiBuMi5yZWN0LndpZHRoICogbjIucmVjdC5oZWlnaHQpXG4gICAgICByZXR1cm4gLTE7XG4gICAgaWYgKG4xLnJlY3Qud2lkdGggKiBuMS5yZWN0LmhlaWdodCA8IG4yLnJlY3Qud2lkdGggKiBuMi5yZWN0LmhlaWdodClcbiAgICAgIHJldHVybiAxO1xuICAgIHJldHVybiAwO1xuICB9KTtcblxuICAvLyBDcmVhdGUgdGhlIG9yZ2FuaXphdGlvbiAtPiB0aWxlIG1lbWJlcnNcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBub2Rlcy5sZW5ndGg7IGkrKykge1xuICAgIHZhciBsTm9kZSA9IG5vZGVzW2ldO1xuICAgIFxuICAgIGlmIChvcmdhbml6YXRpb24ucm93cy5sZW5ndGggPT0gMCkge1xuICAgICAgdGhpcy5pbnNlcnROb2RlVG9Sb3cob3JnYW5pemF0aW9uLCBsTm9kZSwgMCwgbWluV2lkdGgpO1xuICAgIH1cbiAgICBlbHNlIGlmICh0aGlzLmNhbkFkZEhvcml6b250YWwob3JnYW5pemF0aW9uLCBsTm9kZS5yZWN0LndpZHRoLCBsTm9kZS5yZWN0LmhlaWdodCkpIHtcbiAgICAgIHRoaXMuaW5zZXJ0Tm9kZVRvUm93KG9yZ2FuaXphdGlvbiwgbE5vZGUsIHRoaXMuZ2V0U2hvcnRlc3RSb3dJbmRleChvcmdhbml6YXRpb24pLCBtaW5XaWR0aCk7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgdGhpcy5pbnNlcnROb2RlVG9Sb3cob3JnYW5pemF0aW9uLCBsTm9kZSwgb3JnYW5pemF0aW9uLnJvd3MubGVuZ3RoLCBtaW5XaWR0aCk7XG4gICAgfVxuXG4gICAgdGhpcy5zaGlmdFRvTGFzdFJvdyhvcmdhbml6YXRpb24pO1xuICB9XG5cbiAgcmV0dXJuIG9yZ2FuaXphdGlvbjtcbn07XG5cbkNvU0VMYXlvdXQucHJvdG90eXBlLmluc2VydE5vZGVUb1JvdyA9IGZ1bmN0aW9uIChvcmdhbml6YXRpb24sIG5vZGUsIHJvd0luZGV4LCBtaW5XaWR0aCkge1xuICB2YXIgbWluQ29tcG91bmRTaXplID0gbWluV2lkdGg7XG5cbiAgLy8gQWRkIG5ldyByb3cgaWYgbmVlZGVkXG4gIGlmIChyb3dJbmRleCA9PSBvcmdhbml6YXRpb24ucm93cy5sZW5ndGgpIHtcbiAgICB2YXIgc2Vjb25kRGltZW5zaW9uID0gW107XG5cbiAgICBvcmdhbml6YXRpb24ucm93cy5wdXNoKHNlY29uZERpbWVuc2lvbik7XG4gICAgb3JnYW5pemF0aW9uLnJvd1dpZHRoLnB1c2gobWluQ29tcG91bmRTaXplKTtcbiAgICBvcmdhbml6YXRpb24ucm93SGVpZ2h0LnB1c2goMCk7XG4gIH1cblxuICAvLyBVcGRhdGUgcm93IHdpZHRoXG4gIHZhciB3ID0gb3JnYW5pemF0aW9uLnJvd1dpZHRoW3Jvd0luZGV4XSArIG5vZGUucmVjdC53aWR0aDtcblxuICBpZiAob3JnYW5pemF0aW9uLnJvd3Nbcm93SW5kZXhdLmxlbmd0aCA+IDApIHtcbiAgICB3ICs9IG9yZ2FuaXphdGlvbi5ob3Jpem9udGFsUGFkZGluZztcbiAgfVxuXG4gIG9yZ2FuaXphdGlvbi5yb3dXaWR0aFtyb3dJbmRleF0gPSB3O1xuICAvLyBVcGRhdGUgY29tcG91bmQgd2lkdGhcbiAgaWYgKG9yZ2FuaXphdGlvbi53aWR0aCA8IHcpIHtcbiAgICBvcmdhbml6YXRpb24ud2lkdGggPSB3O1xuICB9XG5cbiAgLy8gVXBkYXRlIGhlaWdodFxuICB2YXIgaCA9IG5vZGUucmVjdC5oZWlnaHQ7XG4gIGlmIChyb3dJbmRleCA+IDApXG4gICAgaCArPSBvcmdhbml6YXRpb24udmVydGljYWxQYWRkaW5nO1xuXG4gIHZhciBleHRyYUhlaWdodCA9IDA7XG4gIGlmIChoID4gb3JnYW5pemF0aW9uLnJvd0hlaWdodFtyb3dJbmRleF0pIHtcbiAgICBleHRyYUhlaWdodCA9IG9yZ2FuaXphdGlvbi5yb3dIZWlnaHRbcm93SW5kZXhdO1xuICAgIG9yZ2FuaXphdGlvbi5yb3dIZWlnaHRbcm93SW5kZXhdID0gaDtcbiAgICBleHRyYUhlaWdodCA9IG9yZ2FuaXphdGlvbi5yb3dIZWlnaHRbcm93SW5kZXhdIC0gZXh0cmFIZWlnaHQ7XG4gIH1cblxuICBvcmdhbml6YXRpb24uaGVpZ2h0ICs9IGV4dHJhSGVpZ2h0O1xuXG4gIC8vIEluc2VydCBub2RlXG4gIG9yZ2FuaXphdGlvbi5yb3dzW3Jvd0luZGV4XS5wdXNoKG5vZGUpO1xufTtcblxuLy9TY2FucyB0aGUgcm93cyBvZiBhbiBvcmdhbml6YXRpb24gYW5kIHJldHVybnMgdGhlIG9uZSB3aXRoIHRoZSBtaW4gd2lkdGhcbkNvU0VMYXlvdXQucHJvdG90eXBlLmdldFNob3J0ZXN0Um93SW5kZXggPSBmdW5jdGlvbiAob3JnYW5pemF0aW9uKSB7XG4gIHZhciByID0gLTE7XG4gIHZhciBtaW4gPSBOdW1iZXIuTUFYX1ZBTFVFO1xuXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgb3JnYW5pemF0aW9uLnJvd3MubGVuZ3RoOyBpKyspIHtcbiAgICBpZiAob3JnYW5pemF0aW9uLnJvd1dpZHRoW2ldIDwgbWluKSB7XG4gICAgICByID0gaTtcbiAgICAgIG1pbiA9IG9yZ2FuaXphdGlvbi5yb3dXaWR0aFtpXTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHI7XG59O1xuXG4vL1NjYW5zIHRoZSByb3dzIG9mIGFuIG9yZ2FuaXphdGlvbiBhbmQgcmV0dXJucyB0aGUgb25lIHdpdGggdGhlIG1heCB3aWR0aFxuQ29TRUxheW91dC5wcm90b3R5cGUuZ2V0TG9uZ2VzdFJvd0luZGV4ID0gZnVuY3Rpb24gKG9yZ2FuaXphdGlvbikge1xuICB2YXIgciA9IC0xO1xuICB2YXIgbWF4ID0gTnVtYmVyLk1JTl9WQUxVRTtcblxuICBmb3IgKHZhciBpID0gMDsgaSA8IG9yZ2FuaXphdGlvbi5yb3dzLmxlbmd0aDsgaSsrKSB7XG5cbiAgICBpZiAob3JnYW5pemF0aW9uLnJvd1dpZHRoW2ldID4gbWF4KSB7XG4gICAgICByID0gaTtcbiAgICAgIG1heCA9IG9yZ2FuaXphdGlvbi5yb3dXaWR0aFtpXTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gcjtcbn07XG5cbi8qKlxuKiBUaGlzIG1ldGhvZCBjaGVja3Mgd2hldGhlciBhZGRpbmcgZXh0cmEgd2lkdGggdG8gdGhlIG9yZ2FuaXphdGlvbiB2aW9sYXRlc1xuKiB0aGUgYXNwZWN0IHJhdGlvKDEpIG9yIG5vdC5cbiovXG5Db1NFTGF5b3V0LnByb3RvdHlwZS5jYW5BZGRIb3Jpem9udGFsID0gZnVuY3Rpb24gKG9yZ2FuaXphdGlvbiwgZXh0cmFXaWR0aCwgZXh0cmFIZWlnaHQpIHtcblxuICB2YXIgc3JpID0gdGhpcy5nZXRTaG9ydGVzdFJvd0luZGV4KG9yZ2FuaXphdGlvbik7XG5cbiAgaWYgKHNyaSA8IDApIHtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIHZhciBtaW4gPSBvcmdhbml6YXRpb24ucm93V2lkdGhbc3JpXTtcblxuICBpZiAobWluICsgb3JnYW5pemF0aW9uLmhvcml6b250YWxQYWRkaW5nICsgZXh0cmFXaWR0aCA8PSBvcmdhbml6YXRpb24ud2lkdGgpXG4gICAgcmV0dXJuIHRydWU7XG5cbiAgdmFyIGhEaWZmID0gMDtcblxuICAvLyBBZGRpbmcgdG8gYW4gZXhpc3Rpbmcgcm93XG4gIGlmIChvcmdhbml6YXRpb24ucm93SGVpZ2h0W3NyaV0gPCBleHRyYUhlaWdodCkge1xuICAgIGlmIChzcmkgPiAwKVxuICAgICAgaERpZmYgPSBleHRyYUhlaWdodCArIG9yZ2FuaXphdGlvbi52ZXJ0aWNhbFBhZGRpbmcgLSBvcmdhbml6YXRpb24ucm93SGVpZ2h0W3NyaV07XG4gIH1cblxuICB2YXIgYWRkX3RvX3Jvd19yYXRpbztcbiAgaWYgKG9yZ2FuaXphdGlvbi53aWR0aCAtIG1pbiA+PSBleHRyYVdpZHRoICsgb3JnYW5pemF0aW9uLmhvcml6b250YWxQYWRkaW5nKSB7XG4gICAgYWRkX3RvX3Jvd19yYXRpbyA9IChvcmdhbml6YXRpb24uaGVpZ2h0ICsgaERpZmYpIC8gKG1pbiArIGV4dHJhV2lkdGggKyBvcmdhbml6YXRpb24uaG9yaXpvbnRhbFBhZGRpbmcpO1xuICB9IGVsc2Uge1xuICAgIGFkZF90b19yb3dfcmF0aW8gPSAob3JnYW5pemF0aW9uLmhlaWdodCArIGhEaWZmKSAvIG9yZ2FuaXphdGlvbi53aWR0aDtcbiAgfVxuXG4gIC8vIEFkZGluZyBhIG5ldyByb3cgZm9yIHRoaXMgbm9kZVxuICBoRGlmZiA9IGV4dHJhSGVpZ2h0ICsgb3JnYW5pemF0aW9uLnZlcnRpY2FsUGFkZGluZztcbiAgdmFyIGFkZF9uZXdfcm93X3JhdGlvO1xuICBpZiAob3JnYW5pemF0aW9uLndpZHRoIDwgZXh0cmFXaWR0aCkge1xuICAgIGFkZF9uZXdfcm93X3JhdGlvID0gKG9yZ2FuaXphdGlvbi5oZWlnaHQgKyBoRGlmZikgLyBleHRyYVdpZHRoO1xuICB9IGVsc2Uge1xuICAgIGFkZF9uZXdfcm93X3JhdGlvID0gKG9yZ2FuaXphdGlvbi5oZWlnaHQgKyBoRGlmZikgLyBvcmdhbml6YXRpb24ud2lkdGg7XG4gIH1cblxuICBpZiAoYWRkX25ld19yb3dfcmF0aW8gPCAxKVxuICAgIGFkZF9uZXdfcm93X3JhdGlvID0gMSAvIGFkZF9uZXdfcm93X3JhdGlvO1xuXG4gIGlmIChhZGRfdG9fcm93X3JhdGlvIDwgMSlcbiAgICBhZGRfdG9fcm93X3JhdGlvID0gMSAvIGFkZF90b19yb3dfcmF0aW87XG5cbiAgcmV0dXJuIGFkZF90b19yb3dfcmF0aW8gPCBhZGRfbmV3X3Jvd19yYXRpbztcbn07XG5cbi8vSWYgbW92aW5nIHRoZSBsYXN0IG5vZGUgZnJvbSB0aGUgbG9uZ2VzdCByb3cgYW5kIGFkZGluZyBpdCB0byB0aGUgbGFzdFxuLy9yb3cgbWFrZXMgdGhlIGJvdW5kaW5nIGJveCBzbWFsbGVyLCBkbyBpdC5cbkNvU0VMYXlvdXQucHJvdG90eXBlLnNoaWZ0VG9MYXN0Um93ID0gZnVuY3Rpb24gKG9yZ2FuaXphdGlvbikge1xuICB2YXIgbG9uZ2VzdCA9IHRoaXMuZ2V0TG9uZ2VzdFJvd0luZGV4KG9yZ2FuaXphdGlvbik7XG4gIHZhciBsYXN0ID0gb3JnYW5pemF0aW9uLnJvd1dpZHRoLmxlbmd0aCAtIDE7XG4gIHZhciByb3cgPSBvcmdhbml6YXRpb24ucm93c1tsb25nZXN0XTtcbiAgdmFyIG5vZGUgPSByb3dbcm93Lmxlbmd0aCAtIDFdO1xuXG4gIHZhciBkaWZmID0gbm9kZS53aWR0aCArIG9yZ2FuaXphdGlvbi5ob3Jpem9udGFsUGFkZGluZztcblxuICAvLyBDaGVjayBpZiB0aGVyZSBpcyBlbm91Z2ggc3BhY2Ugb24gdGhlIGxhc3Qgcm93XG4gIGlmIChvcmdhbml6YXRpb24ud2lkdGggLSBvcmdhbml6YXRpb24ucm93V2lkdGhbbGFzdF0gPiBkaWZmICYmIGxvbmdlc3QgIT0gbGFzdCkge1xuICAgIC8vIFJlbW92ZSB0aGUgbGFzdCBlbGVtZW50IG9mIHRoZSBsb25nZXN0IHJvd1xuICAgIHJvdy5zcGxpY2UoLTEsIDEpO1xuXG4gICAgLy8gUHVzaCBpdCB0byB0aGUgbGFzdCByb3dcbiAgICBvcmdhbml6YXRpb24ucm93c1tsYXN0XS5wdXNoKG5vZGUpO1xuXG4gICAgb3JnYW5pemF0aW9uLnJvd1dpZHRoW2xvbmdlc3RdID0gb3JnYW5pemF0aW9uLnJvd1dpZHRoW2xvbmdlc3RdIC0gZGlmZjtcbiAgICBvcmdhbml6YXRpb24ucm93V2lkdGhbbGFzdF0gPSBvcmdhbml6YXRpb24ucm93V2lkdGhbbGFzdF0gKyBkaWZmO1xuICAgIG9yZ2FuaXphdGlvbi53aWR0aCA9IG9yZ2FuaXphdGlvbi5yb3dXaWR0aFtpbnN0YW5jZS5nZXRMb25nZXN0Um93SW5kZXgob3JnYW5pemF0aW9uKV07XG5cbiAgICAvLyBVcGRhdGUgaGVpZ2h0cyBvZiB0aGUgb3JnYW5pemF0aW9uXG4gICAgdmFyIG1heEhlaWdodCA9IE51bWJlci5NSU5fVkFMVUU7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCByb3cubGVuZ3RoOyBpKyspIHtcbiAgICAgIGlmIChyb3dbaV0uaGVpZ2h0ID4gbWF4SGVpZ2h0KVxuICAgICAgICBtYXhIZWlnaHQgPSByb3dbaV0uaGVpZ2h0O1xuICAgIH1cbiAgICBpZiAobG9uZ2VzdCA+IDApXG4gICAgICBtYXhIZWlnaHQgKz0gb3JnYW5pemF0aW9uLnZlcnRpY2FsUGFkZGluZztcblxuICAgIHZhciBwcmV2VG90YWwgPSBvcmdhbml6YXRpb24ucm93SGVpZ2h0W2xvbmdlc3RdICsgb3JnYW5pemF0aW9uLnJvd0hlaWdodFtsYXN0XTtcblxuICAgIG9yZ2FuaXphdGlvbi5yb3dIZWlnaHRbbG9uZ2VzdF0gPSBtYXhIZWlnaHQ7XG4gICAgaWYgKG9yZ2FuaXphdGlvbi5yb3dIZWlnaHRbbGFzdF0gPCBub2RlLmhlaWdodCArIG9yZ2FuaXphdGlvbi52ZXJ0aWNhbFBhZGRpbmcpXG4gICAgICBvcmdhbml6YXRpb24ucm93SGVpZ2h0W2xhc3RdID0gbm9kZS5oZWlnaHQgKyBvcmdhbml6YXRpb24udmVydGljYWxQYWRkaW5nO1xuXG4gICAgdmFyIGZpbmFsVG90YWwgPSBvcmdhbml6YXRpb24ucm93SGVpZ2h0W2xvbmdlc3RdICsgb3JnYW5pemF0aW9uLnJvd0hlaWdodFtsYXN0XTtcbiAgICBvcmdhbml6YXRpb24uaGVpZ2h0ICs9IChmaW5hbFRvdGFsIC0gcHJldlRvdGFsKTtcblxuICAgIHRoaXMuc2hpZnRUb0xhc3RSb3cob3JnYW5pemF0aW9uKTtcbiAgfVxufTtcblxuQ29TRUxheW91dC5wcm90b3R5cGUudGlsaW5nUHJlTGF5b3V0ID0gZnVuY3Rpb24oKSB7XG4gIGlmIChDb1NFQ29uc3RhbnRzLlRJTEUpIHtcbiAgICAvLyBGaW5kIHplcm8gZGVncmVlIG5vZGVzIGFuZCBjcmVhdGUgYSBjb21wb3VuZCBmb3IgZWFjaCBsZXZlbFxuICAgIHRoaXMuZ3JvdXBaZXJvRGVncmVlTWVtYmVycygpO1xuICAgIC8vIFRpbGUgYW5kIGNsZWFyIGNoaWxkcmVuIG9mIGVhY2ggY29tcG91bmRcbiAgICB0aGlzLmNsZWFyQ29tcG91bmRzKCk7XG4gICAgLy8gU2VwYXJhdGVseSB0aWxlIGFuZCBjbGVhciB6ZXJvIGRlZ3JlZSBub2RlcyBmb3IgZWFjaCBsZXZlbFxuICAgIHRoaXMuY2xlYXJaZXJvRGVncmVlTWVtYmVycygpO1xuICB9XG59O1xuXG5Db1NFTGF5b3V0LnByb3RvdHlwZS50aWxpbmdQb3N0TGF5b3V0ID0gZnVuY3Rpb24oKSB7XG4gIGlmIChDb1NFQ29uc3RhbnRzLlRJTEUpIHtcbiAgICB0aGlzLnJlcG9wdWxhdGVaZXJvRGVncmVlTWVtYmVycygpO1xuICAgIHRoaXMucmVwb3B1bGF0ZUNvbXBvdW5kcygpO1xuICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IENvU0VMYXlvdXQ7XG4iLCJ2YXIgRkRMYXlvdXROb2RlID0gcmVxdWlyZSgnLi9GRExheW91dE5vZGUnKTtcbnZhciBJTWF0aCA9IHJlcXVpcmUoJy4vSU1hdGgnKTtcblxuZnVuY3Rpb24gQ29TRU5vZGUoZ20sIGxvYywgc2l6ZSwgdk5vZGUpIHtcbiAgRkRMYXlvdXROb2RlLmNhbGwodGhpcywgZ20sIGxvYywgc2l6ZSwgdk5vZGUpO1xufVxuXG5cbkNvU0VOb2RlLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoRkRMYXlvdXROb2RlLnByb3RvdHlwZSk7XG5mb3IgKHZhciBwcm9wIGluIEZETGF5b3V0Tm9kZSkge1xuICBDb1NFTm9kZVtwcm9wXSA9IEZETGF5b3V0Tm9kZVtwcm9wXTtcbn1cblxuQ29TRU5vZGUucHJvdG90eXBlLm1vdmUgPSBmdW5jdGlvbiAoKVxue1xuICB2YXIgbGF5b3V0ID0gdGhpcy5ncmFwaE1hbmFnZXIuZ2V0TGF5b3V0KCk7XG4gIHRoaXMuZGlzcGxhY2VtZW50WCA9IGxheW91dC5jb29saW5nRmFjdG9yICpcbiAgICAgICAgICAodGhpcy5zcHJpbmdGb3JjZVggKyB0aGlzLnJlcHVsc2lvbkZvcmNlWCArIHRoaXMuZ3Jhdml0YXRpb25Gb3JjZVgpIC8gdGhpcy5ub09mQ2hpbGRyZW47XG4gIHRoaXMuZGlzcGxhY2VtZW50WSA9IGxheW91dC5jb29saW5nRmFjdG9yICpcbiAgICAgICAgICAodGhpcy5zcHJpbmdGb3JjZVkgKyB0aGlzLnJlcHVsc2lvbkZvcmNlWSArIHRoaXMuZ3Jhdml0YXRpb25Gb3JjZVkpIC8gdGhpcy5ub09mQ2hpbGRyZW47XG5cblxuICBpZiAoTWF0aC5hYnModGhpcy5kaXNwbGFjZW1lbnRYKSA+IGxheW91dC5jb29saW5nRmFjdG9yICogbGF5b3V0Lm1heE5vZGVEaXNwbGFjZW1lbnQpXG4gIHtcbiAgICB0aGlzLmRpc3BsYWNlbWVudFggPSBsYXlvdXQuY29vbGluZ0ZhY3RvciAqIGxheW91dC5tYXhOb2RlRGlzcGxhY2VtZW50ICpcbiAgICAgICAgICAgIElNYXRoLnNpZ24odGhpcy5kaXNwbGFjZW1lbnRYKTtcbiAgfVxuXG4gIGlmIChNYXRoLmFicyh0aGlzLmRpc3BsYWNlbWVudFkpID4gbGF5b3V0LmNvb2xpbmdGYWN0b3IgKiBsYXlvdXQubWF4Tm9kZURpc3BsYWNlbWVudClcbiAge1xuICAgIHRoaXMuZGlzcGxhY2VtZW50WSA9IGxheW91dC5jb29saW5nRmFjdG9yICogbGF5b3V0Lm1heE5vZGVEaXNwbGFjZW1lbnQgKlxuICAgICAgICAgICAgSU1hdGguc2lnbih0aGlzLmRpc3BsYWNlbWVudFkpO1xuICB9XG5cbiAgLy8gYSBzaW1wbGUgbm9kZSwganVzdCBtb3ZlIGl0XG4gIGlmICh0aGlzLmNoaWxkID09IG51bGwpXG4gIHtcbiAgICB0aGlzLm1vdmVCeSh0aGlzLmRpc3BsYWNlbWVudFgsIHRoaXMuZGlzcGxhY2VtZW50WSk7XG4gIH1cbiAgLy8gYW4gZW1wdHkgY29tcG91bmQgbm9kZSwgYWdhaW4ganVzdCBtb3ZlIGl0XG4gIGVsc2UgaWYgKHRoaXMuY2hpbGQuZ2V0Tm9kZXMoKS5sZW5ndGggPT0gMClcbiAge1xuICAgIHRoaXMubW92ZUJ5KHRoaXMuZGlzcGxhY2VtZW50WCwgdGhpcy5kaXNwbGFjZW1lbnRZKTtcbiAgfVxuICAvLyBub24tZW1wdHkgY29tcG91bmQgbm9kZSwgcHJvcG9nYXRlIG1vdmVtZW50IHRvIGNoaWxkcmVuIGFzIHdlbGxcbiAgZWxzZVxuICB7XG4gICAgdGhpcy5wcm9wb2dhdGVEaXNwbGFjZW1lbnRUb0NoaWxkcmVuKHRoaXMuZGlzcGxhY2VtZW50WCxcbiAgICAgICAgICAgIHRoaXMuZGlzcGxhY2VtZW50WSk7XG4gIH1cblxuICBsYXlvdXQudG90YWxEaXNwbGFjZW1lbnQgKz1cbiAgICAgICAgICBNYXRoLmFicyh0aGlzLmRpc3BsYWNlbWVudFgpICsgTWF0aC5hYnModGhpcy5kaXNwbGFjZW1lbnRZKTtcblxuICB0aGlzLnNwcmluZ0ZvcmNlWCA9IDA7XG4gIHRoaXMuc3ByaW5nRm9yY2VZID0gMDtcbiAgdGhpcy5yZXB1bHNpb25Gb3JjZVggPSAwO1xuICB0aGlzLnJlcHVsc2lvbkZvcmNlWSA9IDA7XG4gIHRoaXMuZ3Jhdml0YXRpb25Gb3JjZVggPSAwO1xuICB0aGlzLmdyYXZpdGF0aW9uRm9yY2VZID0gMDtcbiAgdGhpcy5kaXNwbGFjZW1lbnRYID0gMDtcbiAgdGhpcy5kaXNwbGFjZW1lbnRZID0gMDtcbn07XG5cbkNvU0VOb2RlLnByb3RvdHlwZS5wcm9wb2dhdGVEaXNwbGFjZW1lbnRUb0NoaWxkcmVuID0gZnVuY3Rpb24gKGRYLCBkWSlcbntcbiAgdmFyIG5vZGVzID0gdGhpcy5nZXRDaGlsZCgpLmdldE5vZGVzKCk7XG4gIHZhciBub2RlO1xuICBmb3IgKHZhciBpID0gMDsgaSA8IG5vZGVzLmxlbmd0aDsgaSsrKVxuICB7XG4gICAgbm9kZSA9IG5vZGVzW2ldO1xuICAgIGlmIChub2RlLmdldENoaWxkKCkgPT0gbnVsbClcbiAgICB7XG4gICAgICBub2RlLm1vdmVCeShkWCwgZFkpO1xuICAgICAgbm9kZS5kaXNwbGFjZW1lbnRYICs9IGRYO1xuICAgICAgbm9kZS5kaXNwbGFjZW1lbnRZICs9IGRZO1xuICAgIH1cbiAgICBlbHNlXG4gICAge1xuICAgICAgbm9kZS5wcm9wb2dhdGVEaXNwbGFjZW1lbnRUb0NoaWxkcmVuKGRYLCBkWSk7XG4gICAgfVxuICB9XG59O1xuXG5Db1NFTm9kZS5wcm90b3R5cGUuc2V0UHJlZDEgPSBmdW5jdGlvbiAocHJlZDEpXG57XG4gIHRoaXMucHJlZDEgPSBwcmVkMTtcbn07XG5cbkNvU0VOb2RlLnByb3RvdHlwZS5nZXRQcmVkMSA9IGZ1bmN0aW9uICgpXG57XG4gIHJldHVybiBwcmVkMTtcbn07XG5cbkNvU0VOb2RlLnByb3RvdHlwZS5nZXRQcmVkMiA9IGZ1bmN0aW9uICgpXG57XG4gIHJldHVybiBwcmVkMjtcbn07XG5cbkNvU0VOb2RlLnByb3RvdHlwZS5zZXROZXh0ID0gZnVuY3Rpb24gKG5leHQpXG57XG4gIHRoaXMubmV4dCA9IG5leHQ7XG59O1xuXG5Db1NFTm9kZS5wcm90b3R5cGUuZ2V0TmV4dCA9IGZ1bmN0aW9uICgpXG57XG4gIHJldHVybiBuZXh0O1xufTtcblxuQ29TRU5vZGUucHJvdG90eXBlLnNldFByb2Nlc3NlZCA9IGZ1bmN0aW9uIChwcm9jZXNzZWQpXG57XG4gIHRoaXMucHJvY2Vzc2VkID0gcHJvY2Vzc2VkO1xufTtcblxuQ29TRU5vZGUucHJvdG90eXBlLmlzUHJvY2Vzc2VkID0gZnVuY3Rpb24gKClcbntcbiAgcmV0dXJuIHByb2Nlc3NlZDtcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gQ29TRU5vZGU7XG4iLCJmdW5jdGlvbiBEaW1lbnNpb25EKHdpZHRoLCBoZWlnaHQpIHtcbiAgdGhpcy53aWR0aCA9IDA7XG4gIHRoaXMuaGVpZ2h0ID0gMDtcbiAgaWYgKHdpZHRoICE9PSBudWxsICYmIGhlaWdodCAhPT0gbnVsbCkge1xuICAgIHRoaXMuaGVpZ2h0ID0gaGVpZ2h0O1xuICAgIHRoaXMud2lkdGggPSB3aWR0aDtcbiAgfVxufVxuXG5EaW1lbnNpb25ELnByb3RvdHlwZS5nZXRXaWR0aCA9IGZ1bmN0aW9uICgpXG57XG4gIHJldHVybiB0aGlzLndpZHRoO1xufTtcblxuRGltZW5zaW9uRC5wcm90b3R5cGUuc2V0V2lkdGggPSBmdW5jdGlvbiAod2lkdGgpXG57XG4gIHRoaXMud2lkdGggPSB3aWR0aDtcbn07XG5cbkRpbWVuc2lvbkQucHJvdG90eXBlLmdldEhlaWdodCA9IGZ1bmN0aW9uICgpXG57XG4gIHJldHVybiB0aGlzLmhlaWdodDtcbn07XG5cbkRpbWVuc2lvbkQucHJvdG90eXBlLnNldEhlaWdodCA9IGZ1bmN0aW9uIChoZWlnaHQpXG57XG4gIHRoaXMuaGVpZ2h0ID0gaGVpZ2h0O1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSBEaW1lbnNpb25EO1xuIiwiZnVuY3Rpb24gRW1pdHRlcigpe1xuICB0aGlzLmxpc3RlbmVycyA9IFtdO1xufVxuXG52YXIgcCA9IEVtaXR0ZXIucHJvdG90eXBlO1xuXG5wLmFkZExpc3RlbmVyID0gZnVuY3Rpb24oIGV2ZW50LCBjYWxsYmFjayApe1xuICB0aGlzLmxpc3RlbmVycy5wdXNoKHtcbiAgICBldmVudDogZXZlbnQsXG4gICAgY2FsbGJhY2s6IGNhbGxiYWNrXG4gIH0pO1xufTtcblxucC5yZW1vdmVMaXN0ZW5lciA9IGZ1bmN0aW9uKCBldmVudCwgY2FsbGJhY2sgKXtcbiAgZm9yKCB2YXIgaSA9IHRoaXMubGlzdGVuZXJzLmxlbmd0aDsgaSA+PSAwOyBpLS0gKXtcbiAgICB2YXIgbCA9IHRoaXMubGlzdGVuZXJzW2ldO1xuXG4gICAgaWYoIGwuZXZlbnQgPT09IGV2ZW50ICYmIGwuY2FsbGJhY2sgPT09IGNhbGxiYWNrICl7XG4gICAgICB0aGlzLmxpc3RlbmVycy5zcGxpY2UoIGksIDEgKTtcbiAgICB9XG4gIH1cbn07XG5cbnAuZW1pdCA9IGZ1bmN0aW9uKCBldmVudCwgZGF0YSApe1xuICBmb3IoIHZhciBpID0gMDsgaSA8IHRoaXMubGlzdGVuZXJzLmxlbmd0aDsgaSsrICl7XG4gICAgdmFyIGwgPSB0aGlzLmxpc3RlbmVyc1tpXTtcblxuICAgIGlmKCBldmVudCA9PT0gbC5ldmVudCApe1xuICAgICAgbC5jYWxsYmFjayggZGF0YSApO1xuICAgIH1cbiAgfVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBFbWl0dGVyO1xuIiwidmFyIExheW91dCA9IHJlcXVpcmUoJy4vTGF5b3V0Jyk7XG52YXIgRkRMYXlvdXRDb25zdGFudHMgPSByZXF1aXJlKCcuL0ZETGF5b3V0Q29uc3RhbnRzJyk7XG52YXIgTGF5b3V0Q29uc3RhbnRzID0gcmVxdWlyZSgnLi9MYXlvdXRDb25zdGFudHMnKTtcbnZhciBJR2VvbWV0cnkgPSByZXF1aXJlKCcuL0lHZW9tZXRyeScpO1xudmFyIElNYXRoID0gcmVxdWlyZSgnLi9JTWF0aCcpO1xudmFyIEludGVnZXIgPSByZXF1aXJlKCcuL0ludGVnZXInKTtcblxuZnVuY3Rpb24gRkRMYXlvdXQoKSB7XG4gIExheW91dC5jYWxsKHRoaXMpO1xuXG4gIHRoaXMudXNlU21hcnRJZGVhbEVkZ2VMZW5ndGhDYWxjdWxhdGlvbiA9IEZETGF5b3V0Q29uc3RhbnRzLkRFRkFVTFRfVVNFX1NNQVJUX0lERUFMX0VER0VfTEVOR1RIX0NBTENVTEFUSU9OO1xuICB0aGlzLmlkZWFsRWRnZUxlbmd0aCA9IEZETGF5b3V0Q29uc3RhbnRzLkRFRkFVTFRfRURHRV9MRU5HVEg7XG4gIHRoaXMuc3ByaW5nQ29uc3RhbnQgPSBGRExheW91dENvbnN0YW50cy5ERUZBVUxUX1NQUklOR19TVFJFTkdUSDtcbiAgdGhpcy5yZXB1bHNpb25Db25zdGFudCA9IEZETGF5b3V0Q29uc3RhbnRzLkRFRkFVTFRfUkVQVUxTSU9OX1NUUkVOR1RIO1xuICB0aGlzLmdyYXZpdHlDb25zdGFudCA9IEZETGF5b3V0Q29uc3RhbnRzLkRFRkFVTFRfR1JBVklUWV9TVFJFTkdUSDtcbiAgdGhpcy5jb21wb3VuZEdyYXZpdHlDb25zdGFudCA9IEZETGF5b3V0Q29uc3RhbnRzLkRFRkFVTFRfQ09NUE9VTkRfR1JBVklUWV9TVFJFTkdUSDtcbiAgdGhpcy5ncmF2aXR5UmFuZ2VGYWN0b3IgPSBGRExheW91dENvbnN0YW50cy5ERUZBVUxUX0dSQVZJVFlfUkFOR0VfRkFDVE9SO1xuICB0aGlzLmNvbXBvdW5kR3Jhdml0eVJhbmdlRmFjdG9yID0gRkRMYXlvdXRDb25zdGFudHMuREVGQVVMVF9DT01QT1VORF9HUkFWSVRZX1JBTkdFX0ZBQ1RPUjtcbiAgdGhpcy5kaXNwbGFjZW1lbnRUaHJlc2hvbGRQZXJOb2RlID0gKDMuMCAqIEZETGF5b3V0Q29uc3RhbnRzLkRFRkFVTFRfRURHRV9MRU5HVEgpIC8gMTAwO1xuICB0aGlzLmNvb2xpbmdGYWN0b3IgPSBGRExheW91dENvbnN0YW50cy5ERUZBVUxUX0NPT0xJTkdfRkFDVE9SX0lOQ1JFTUVOVEFMO1xuICB0aGlzLmluaXRpYWxDb29saW5nRmFjdG9yID0gRkRMYXlvdXRDb25zdGFudHMuREVGQVVMVF9DT09MSU5HX0ZBQ1RPUl9JTkNSRU1FTlRBTDtcbiAgdGhpcy50b3RhbERpc3BsYWNlbWVudCA9IDAuMDtcbiAgdGhpcy5vbGRUb3RhbERpc3BsYWNlbWVudCA9IDAuMDtcbiAgdGhpcy5tYXhJdGVyYXRpb25zID0gRkRMYXlvdXRDb25zdGFudHMuTUFYX0lURVJBVElPTlM7XG59XG5cbkZETGF5b3V0LnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoTGF5b3V0LnByb3RvdHlwZSk7XG5cbmZvciAodmFyIHByb3AgaW4gTGF5b3V0KSB7XG4gIEZETGF5b3V0W3Byb3BdID0gTGF5b3V0W3Byb3BdO1xufVxuXG5GRExheW91dC5wcm90b3R5cGUuaW5pdFBhcmFtZXRlcnMgPSBmdW5jdGlvbiAoKSB7XG4gIExheW91dC5wcm90b3R5cGUuaW5pdFBhcmFtZXRlcnMuY2FsbCh0aGlzLCBhcmd1bWVudHMpO1xuXG4gIGlmICh0aGlzLmxheW91dFF1YWxpdHkgPT0gTGF5b3V0Q29uc3RhbnRzLkRSQUZUX1FVQUxJVFkpXG4gIHtcbiAgICB0aGlzLmRpc3BsYWNlbWVudFRocmVzaG9sZFBlck5vZGUgKz0gMC4zMDtcbiAgICB0aGlzLm1heEl0ZXJhdGlvbnMgKj0gMC44O1xuICB9XG4gIGVsc2UgaWYgKHRoaXMubGF5b3V0UXVhbGl0eSA9PSBMYXlvdXRDb25zdGFudHMuUFJPT0ZfUVVBTElUWSlcbiAge1xuICAgIHRoaXMuZGlzcGxhY2VtZW50VGhyZXNob2xkUGVyTm9kZSAtPSAwLjMwO1xuICAgIHRoaXMubWF4SXRlcmF0aW9ucyAqPSAxLjI7XG4gIH1cblxuICB0aGlzLnRvdGFsSXRlcmF0aW9ucyA9IDA7XG4gIHRoaXMubm90QW5pbWF0ZWRJdGVyYXRpb25zID0gMDtcblxuICB0aGlzLnVzZUZSR3JpZFZhcmlhbnQgPSBGRExheW91dENvbnN0YW50cy5ERUZBVUxUX1VTRV9TTUFSVF9SRVBVTFNJT05fUkFOR0VfQ0FMQ1VMQVRJT047XG4gIFxuICB0aGlzLmdyaWQgPSBbXTtcbiAgLy8gdmFyaWFibGVzIGZvciB0cmVlIHJlZHVjdGlvbiBzdXBwb3J0XG4gIHRoaXMucHJ1bmVkTm9kZXNBbGwgPSBbXTtcbiAgdGhpcy5ncm93VHJlZUl0ZXJhdGlvbnMgPSAwO1xuICB0aGlzLmFmdGVyR3Jvd3RoSXRlcmF0aW9ucyA9IDA7XG4gIHRoaXMuaXNUcmVlR3Jvd2luZyA9IGZhbHNlO1xuICB0aGlzLmlzR3Jvd3RoRmluaXNoZWQgPSBmYWxzZTtcbn07XG5cbkZETGF5b3V0LnByb3RvdHlwZS5jYWxjSWRlYWxFZGdlTGVuZ3RocyA9IGZ1bmN0aW9uICgpIHtcbiAgdmFyIGVkZ2U7XG4gIHZhciBsY2FEZXB0aDtcbiAgdmFyIHNvdXJjZTtcbiAgdmFyIHRhcmdldDtcbiAgdmFyIHNpemVPZlNvdXJjZUluTGNhO1xuICB2YXIgc2l6ZU9mVGFyZ2V0SW5MY2E7XG5cbiAgdmFyIGFsbEVkZ2VzID0gdGhpcy5nZXRHcmFwaE1hbmFnZXIoKS5nZXRBbGxFZGdlcygpO1xuICBmb3IgKHZhciBpID0gMDsgaSA8IGFsbEVkZ2VzLmxlbmd0aDsgaSsrKVxuICB7XG4gICAgZWRnZSA9IGFsbEVkZ2VzW2ldO1xuXG4gICAgZWRnZS5pZGVhbExlbmd0aCA9IHRoaXMuaWRlYWxFZGdlTGVuZ3RoO1xuXG4gICAgaWYgKGVkZ2UuaXNJbnRlckdyYXBoKVxuICAgIHtcbiAgICAgIHNvdXJjZSA9IGVkZ2UuZ2V0U291cmNlKCk7XG4gICAgICB0YXJnZXQgPSBlZGdlLmdldFRhcmdldCgpO1xuXG4gICAgICBzaXplT2ZTb3VyY2VJbkxjYSA9IGVkZ2UuZ2V0U291cmNlSW5MY2EoKS5nZXRFc3RpbWF0ZWRTaXplKCk7XG4gICAgICBzaXplT2ZUYXJnZXRJbkxjYSA9IGVkZ2UuZ2V0VGFyZ2V0SW5MY2EoKS5nZXRFc3RpbWF0ZWRTaXplKCk7XG5cbiAgICAgIGlmICh0aGlzLnVzZVNtYXJ0SWRlYWxFZGdlTGVuZ3RoQ2FsY3VsYXRpb24pXG4gICAgICB7XG4gICAgICAgIGVkZ2UuaWRlYWxMZW5ndGggKz0gc2l6ZU9mU291cmNlSW5MY2EgKyBzaXplT2ZUYXJnZXRJbkxjYSAtXG4gICAgICAgICAgICAgICAgMiAqIExheW91dENvbnN0YW50cy5TSU1QTEVfTk9ERV9TSVpFO1xuICAgICAgfVxuXG4gICAgICBsY2FEZXB0aCA9IGVkZ2UuZ2V0TGNhKCkuZ2V0SW5jbHVzaW9uVHJlZURlcHRoKCk7XG5cbiAgICAgIGVkZ2UuaWRlYWxMZW5ndGggKz0gRkRMYXlvdXRDb25zdGFudHMuREVGQVVMVF9FREdFX0xFTkdUSCAqXG4gICAgICAgICAgICAgIEZETGF5b3V0Q29uc3RhbnRzLlBFUl9MRVZFTF9JREVBTF9FREdFX0xFTkdUSF9GQUNUT1IgKlxuICAgICAgICAgICAgICAoc291cmNlLmdldEluY2x1c2lvblRyZWVEZXB0aCgpICtcbiAgICAgICAgICAgICAgICAgICAgICB0YXJnZXQuZ2V0SW5jbHVzaW9uVHJlZURlcHRoKCkgLSAyICogbGNhRGVwdGgpO1xuICAgIH1cbiAgfVxufTtcblxuRkRMYXlvdXQucHJvdG90eXBlLmluaXRTcHJpbmdFbWJlZGRlciA9IGZ1bmN0aW9uICgpIHtcblxuICBpZiAodGhpcy5pbmNyZW1lbnRhbClcbiAge1xuICAgIHRoaXMubWF4Tm9kZURpc3BsYWNlbWVudCA9XG4gICAgICAgICAgICBGRExheW91dENvbnN0YW50cy5NQVhfTk9ERV9ESVNQTEFDRU1FTlRfSU5DUkVNRU5UQUw7XG4gIH1cbiAgZWxzZVxuICB7XG4gICAgdGhpcy5jb29saW5nRmFjdG9yID0gMS4wO1xuICAgIHRoaXMuaW5pdGlhbENvb2xpbmdGYWN0b3IgPSAxLjA7XG4gICAgdGhpcy5tYXhOb2RlRGlzcGxhY2VtZW50ID1cbiAgICAgICAgICAgIEZETGF5b3V0Q29uc3RhbnRzLk1BWF9OT0RFX0RJU1BMQUNFTUVOVDtcbiAgfVxuXG4gIHRoaXMubWF4SXRlcmF0aW9ucyA9XG4gICAgICAgICAgTWF0aC5tYXgodGhpcy5nZXRBbGxOb2RlcygpLmxlbmd0aCAqIDUsIHRoaXMubWF4SXRlcmF0aW9ucyk7XG5cbiAgdGhpcy50b3RhbERpc3BsYWNlbWVudFRocmVzaG9sZCA9XG4gICAgICAgICAgdGhpcy5kaXNwbGFjZW1lbnRUaHJlc2hvbGRQZXJOb2RlICogdGhpcy5nZXRBbGxOb2RlcygpLmxlbmd0aDtcblxuICB0aGlzLnJlcHVsc2lvblJhbmdlID0gdGhpcy5jYWxjUmVwdWxzaW9uUmFuZ2UoKTtcbn07XG5cbkZETGF5b3V0LnByb3RvdHlwZS5jYWxjU3ByaW5nRm9yY2VzID0gZnVuY3Rpb24gKCkge1xuICB2YXIgbEVkZ2VzID0gdGhpcy5nZXRBbGxFZGdlcygpO1xuICB2YXIgZWRnZTtcblxuICBmb3IgKHZhciBpID0gMDsgaSA8IGxFZGdlcy5sZW5ndGg7IGkrKylcbiAge1xuICAgIGVkZ2UgPSBsRWRnZXNbaV07XG5cbiAgICB0aGlzLmNhbGNTcHJpbmdGb3JjZShlZGdlLCBlZGdlLmlkZWFsTGVuZ3RoKTtcbiAgfVxufTtcblxuRkRMYXlvdXQucHJvdG90eXBlLmNhbGNSZXB1bHNpb25Gb3JjZXMgPSBmdW5jdGlvbiAoKSB7XG4gIHZhciBpLCBqO1xuICB2YXIgbm9kZUEsIG5vZGVCO1xuICB2YXIgbE5vZGVzID0gdGhpcy5nZXRBbGxOb2RlcygpO1xuICB2YXIgcHJvY2Vzc2VkTm9kZVNldDtcblxuICBpZiAodGhpcy51c2VGUkdyaWRWYXJpYW50KVxuICB7ICAgICAgIFxuICAgIGlmICgodGhpcy50b3RhbEl0ZXJhdGlvbnMgJSBGRExheW91dENvbnN0YW50cy5HUklEX0NBTENVTEFUSU9OX0NIRUNLX1BFUklPRCA9PSAxICYmICF0aGlzLmlzVHJlZUdyb3dpbmcgJiYgIXRoaXMuaXNHcm93dGhGaW5pc2hlZCkpXG4gICAgeyAgICAgICBcbiAgICAgIHRoaXMudXBkYXRlR3JpZCgpOyAgXG4gICAgfVxuXG4gICAgcHJvY2Vzc2VkTm9kZVNldCA9IG5ldyBTZXQoKTtcbiAgICBcbiAgICAvLyBjYWxjdWxhdGUgcmVwdWxzaW9uIGZvcmNlcyBiZXR3ZWVuIGVhY2ggbm9kZXMgYW5kIGl0cyBzdXJyb3VuZGluZ1xuICAgIGZvciAoaSA9IDA7IGkgPCBsTm9kZXMubGVuZ3RoOyBpKyspXG4gICAge1xuICAgICAgbm9kZUEgPSBsTm9kZXNbaV07XG4gICAgICB0aGlzLmNhbGN1bGF0ZVJlcHVsc2lvbkZvcmNlT2ZBTm9kZShub2RlQSwgcHJvY2Vzc2VkTm9kZVNldCk7XG4gICAgICBwcm9jZXNzZWROb2RlU2V0LmFkZChub2RlQSk7XG4gICAgfVxuICB9XG4gIGVsc2VcbiAge1xuICAgIGZvciAoaSA9IDA7IGkgPCBsTm9kZXMubGVuZ3RoOyBpKyspXG4gICAge1xuICAgICAgbm9kZUEgPSBsTm9kZXNbaV07XG5cbiAgICAgIGZvciAoaiA9IGkgKyAxOyBqIDwgbE5vZGVzLmxlbmd0aDsgaisrKVxuICAgICAge1xuICAgICAgICBub2RlQiA9IGxOb2Rlc1tqXTtcblxuICAgICAgICAvLyBJZiBib3RoIG5vZGVzIGFyZSBub3QgbWVtYmVycyBvZiB0aGUgc2FtZSBncmFwaCwgc2tpcC5cbiAgICAgICAgaWYgKG5vZGVBLmdldE93bmVyKCkgIT0gbm9kZUIuZ2V0T3duZXIoKSlcbiAgICAgICAge1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5jYWxjUmVwdWxzaW9uRm9yY2Uobm9kZUEsIG5vZGVCKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cbn07XG5cbkZETGF5b3V0LnByb3RvdHlwZS5jYWxjR3Jhdml0YXRpb25hbEZvcmNlcyA9IGZ1bmN0aW9uICgpIHtcbiAgdmFyIG5vZGU7XG4gIHZhciBsTm9kZXMgPSB0aGlzLmdldEFsbE5vZGVzVG9BcHBseUdyYXZpdGF0aW9uKCk7XG5cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBsTm9kZXMubGVuZ3RoOyBpKyspXG4gIHtcbiAgICBub2RlID0gbE5vZGVzW2ldO1xuICAgIHRoaXMuY2FsY0dyYXZpdGF0aW9uYWxGb3JjZShub2RlKTtcbiAgfVxufTtcblxuRkRMYXlvdXQucHJvdG90eXBlLm1vdmVOb2RlcyA9IGZ1bmN0aW9uICgpIHtcbiAgdmFyIGxOb2RlcyA9IHRoaXMuZ2V0QWxsTm9kZXMoKTtcbiAgdmFyIG5vZGU7XG5cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBsTm9kZXMubGVuZ3RoOyBpKyspXG4gIHtcbiAgICBub2RlID0gbE5vZGVzW2ldO1xuICAgIG5vZGUubW92ZSgpO1xuICB9XG59XG5cbkZETGF5b3V0LnByb3RvdHlwZS5jYWxjU3ByaW5nRm9yY2UgPSBmdW5jdGlvbiAoZWRnZSwgaWRlYWxMZW5ndGgpIHtcbiAgdmFyIHNvdXJjZU5vZGUgPSBlZGdlLmdldFNvdXJjZSgpO1xuICB2YXIgdGFyZ2V0Tm9kZSA9IGVkZ2UuZ2V0VGFyZ2V0KCk7XG5cbiAgdmFyIGxlbmd0aDtcbiAgdmFyIHNwcmluZ0ZvcmNlO1xuICB2YXIgc3ByaW5nRm9yY2VYO1xuICB2YXIgc3ByaW5nRm9yY2VZO1xuXG4gIC8vIFVwZGF0ZSBlZGdlIGxlbmd0aFxuICBpZiAodGhpcy51bmlmb3JtTGVhZk5vZGVTaXplcyAmJlxuICAgICAgICAgIHNvdXJjZU5vZGUuZ2V0Q2hpbGQoKSA9PSBudWxsICYmIHRhcmdldE5vZGUuZ2V0Q2hpbGQoKSA9PSBudWxsKVxuICB7XG4gICAgZWRnZS51cGRhdGVMZW5ndGhTaW1wbGUoKTtcbiAgfVxuICBlbHNlXG4gIHtcbiAgICBlZGdlLnVwZGF0ZUxlbmd0aCgpO1xuXG4gICAgaWYgKGVkZ2UuaXNPdmVybGFwaW5nU291cmNlQW5kVGFyZ2V0KVxuICAgIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gIH1cblxuICBsZW5ndGggPSBlZGdlLmdldExlbmd0aCgpO1xuXG4gIC8vIENhbGN1bGF0ZSBzcHJpbmcgZm9yY2VzXG4gIHNwcmluZ0ZvcmNlID0gdGhpcy5zcHJpbmdDb25zdGFudCAqIChsZW5ndGggLSBpZGVhbExlbmd0aCk7XG5cbiAgLy8gUHJvamVjdCBmb3JjZSBvbnRvIHggYW5kIHkgYXhlc1xuICBzcHJpbmdGb3JjZVggPSBzcHJpbmdGb3JjZSAqIChlZGdlLmxlbmd0aFggLyBsZW5ndGgpO1xuICBzcHJpbmdGb3JjZVkgPSBzcHJpbmdGb3JjZSAqIChlZGdlLmxlbmd0aFkgLyBsZW5ndGgpO1xuXG4gIC8vIEFwcGx5IGZvcmNlcyBvbiB0aGUgZW5kIG5vZGVzXG4gIHNvdXJjZU5vZGUuc3ByaW5nRm9yY2VYICs9IHNwcmluZ0ZvcmNlWDtcbiAgc291cmNlTm9kZS5zcHJpbmdGb3JjZVkgKz0gc3ByaW5nRm9yY2VZO1xuICB0YXJnZXROb2RlLnNwcmluZ0ZvcmNlWCAtPSBzcHJpbmdGb3JjZVg7XG4gIHRhcmdldE5vZGUuc3ByaW5nRm9yY2VZIC09IHNwcmluZ0ZvcmNlWTtcbn07XG5cbkZETGF5b3V0LnByb3RvdHlwZS5jYWxjUmVwdWxzaW9uRm9yY2UgPSBmdW5jdGlvbiAobm9kZUEsIG5vZGVCKSB7XG4gIHZhciByZWN0QSA9IG5vZGVBLmdldFJlY3QoKTtcbiAgdmFyIHJlY3RCID0gbm9kZUIuZ2V0UmVjdCgpO1xuICB2YXIgb3ZlcmxhcEFtb3VudCA9IG5ldyBBcnJheSgyKTtcbiAgdmFyIGNsaXBQb2ludHMgPSBuZXcgQXJyYXkoNCk7XG4gIHZhciBkaXN0YW5jZVg7XG4gIHZhciBkaXN0YW5jZVk7XG4gIHZhciBkaXN0YW5jZVNxdWFyZWQ7XG4gIHZhciBkaXN0YW5jZTtcbiAgdmFyIHJlcHVsc2lvbkZvcmNlO1xuICB2YXIgcmVwdWxzaW9uRm9yY2VYO1xuICB2YXIgcmVwdWxzaW9uRm9yY2VZO1xuXG4gIGlmIChyZWN0QS5pbnRlcnNlY3RzKHJlY3RCKSkvLyB0d28gbm9kZXMgb3ZlcmxhcFxuICB7XG4gICAgLy8gY2FsY3VsYXRlIHNlcGFyYXRpb24gYW1vdW50IGluIHggYW5kIHkgZGlyZWN0aW9uc1xuICAgIElHZW9tZXRyeS5jYWxjU2VwYXJhdGlvbkFtb3VudChyZWN0QSxcbiAgICAgICAgICAgIHJlY3RCLFxuICAgICAgICAgICAgb3ZlcmxhcEFtb3VudCxcbiAgICAgICAgICAgIEZETGF5b3V0Q29uc3RhbnRzLkRFRkFVTFRfRURHRV9MRU5HVEggLyAyLjApO1xuXG4gICAgcmVwdWxzaW9uRm9yY2VYID0gMiAqIG92ZXJsYXBBbW91bnRbMF07XG4gICAgcmVwdWxzaW9uRm9yY2VZID0gMiAqIG92ZXJsYXBBbW91bnRbMV07XG4gICAgXG4gICAgdmFyIGNoaWxkcmVuQ29uc3RhbnQgPSBub2RlQS5ub09mQ2hpbGRyZW4gKiBub2RlQi5ub09mQ2hpbGRyZW4gLyAobm9kZUEubm9PZkNoaWxkcmVuICsgbm9kZUIubm9PZkNoaWxkcmVuKTtcbiAgICBcbiAgICAvLyBBcHBseSBmb3JjZXMgb24gdGhlIHR3byBub2Rlc1xuICAgIG5vZGVBLnJlcHVsc2lvbkZvcmNlWCAtPSBjaGlsZHJlbkNvbnN0YW50ICogcmVwdWxzaW9uRm9yY2VYO1xuICAgIG5vZGVBLnJlcHVsc2lvbkZvcmNlWSAtPSBjaGlsZHJlbkNvbnN0YW50ICogcmVwdWxzaW9uRm9yY2VZO1xuICAgIG5vZGVCLnJlcHVsc2lvbkZvcmNlWCArPSBjaGlsZHJlbkNvbnN0YW50ICogcmVwdWxzaW9uRm9yY2VYO1xuICAgIG5vZGVCLnJlcHVsc2lvbkZvcmNlWSArPSBjaGlsZHJlbkNvbnN0YW50ICogcmVwdWxzaW9uRm9yY2VZO1xuICB9XG4gIGVsc2UvLyBubyBvdmVybGFwXG4gIHtcbiAgICAvLyBjYWxjdWxhdGUgZGlzdGFuY2VcblxuICAgIGlmICh0aGlzLnVuaWZvcm1MZWFmTm9kZVNpemVzICYmXG4gICAgICAgICAgICBub2RlQS5nZXRDaGlsZCgpID09IG51bGwgJiYgbm9kZUIuZ2V0Q2hpbGQoKSA9PSBudWxsKS8vIHNpbXBseSBiYXNlIHJlcHVsc2lvbiBvbiBkaXN0YW5jZSBvZiBub2RlIGNlbnRlcnNcbiAgICB7XG4gICAgICBkaXN0YW5jZVggPSByZWN0Qi5nZXRDZW50ZXJYKCkgLSByZWN0QS5nZXRDZW50ZXJYKCk7XG4gICAgICBkaXN0YW5jZVkgPSByZWN0Qi5nZXRDZW50ZXJZKCkgLSByZWN0QS5nZXRDZW50ZXJZKCk7XG4gICAgfVxuICAgIGVsc2UvLyB1c2UgY2xpcHBpbmcgcG9pbnRzXG4gICAge1xuICAgICAgSUdlb21ldHJ5LmdldEludGVyc2VjdGlvbihyZWN0QSwgcmVjdEIsIGNsaXBQb2ludHMpO1xuXG4gICAgICBkaXN0YW5jZVggPSBjbGlwUG9pbnRzWzJdIC0gY2xpcFBvaW50c1swXTtcbiAgICAgIGRpc3RhbmNlWSA9IGNsaXBQb2ludHNbM10gLSBjbGlwUG9pbnRzWzFdO1xuICAgIH1cblxuICAgIC8vIE5vIHJlcHVsc2lvbiByYW5nZS4gRlIgZ3JpZCB2YXJpYW50IHNob3VsZCB0YWtlIGNhcmUgb2YgdGhpcy5cbiAgICBpZiAoTWF0aC5hYnMoZGlzdGFuY2VYKSA8IEZETGF5b3V0Q29uc3RhbnRzLk1JTl9SRVBVTFNJT05fRElTVClcbiAgICB7XG4gICAgICBkaXN0YW5jZVggPSBJTWF0aC5zaWduKGRpc3RhbmNlWCkgKlxuICAgICAgICAgICAgICBGRExheW91dENvbnN0YW50cy5NSU5fUkVQVUxTSU9OX0RJU1Q7XG4gICAgfVxuXG4gICAgaWYgKE1hdGguYWJzKGRpc3RhbmNlWSkgPCBGRExheW91dENvbnN0YW50cy5NSU5fUkVQVUxTSU9OX0RJU1QpXG4gICAge1xuICAgICAgZGlzdGFuY2VZID0gSU1hdGguc2lnbihkaXN0YW5jZVkpICpcbiAgICAgICAgICAgICAgRkRMYXlvdXRDb25zdGFudHMuTUlOX1JFUFVMU0lPTl9ESVNUO1xuICAgIH1cblxuICAgIGRpc3RhbmNlU3F1YXJlZCA9IGRpc3RhbmNlWCAqIGRpc3RhbmNlWCArIGRpc3RhbmNlWSAqIGRpc3RhbmNlWTtcbiAgICBkaXN0YW5jZSA9IE1hdGguc3FydChkaXN0YW5jZVNxdWFyZWQpO1xuXG4gICAgcmVwdWxzaW9uRm9yY2UgPSB0aGlzLnJlcHVsc2lvbkNvbnN0YW50ICogbm9kZUEubm9PZkNoaWxkcmVuICogbm9kZUIubm9PZkNoaWxkcmVuIC8gZGlzdGFuY2VTcXVhcmVkO1xuXG4gICAgLy8gUHJvamVjdCBmb3JjZSBvbnRvIHggYW5kIHkgYXhlc1xuICAgIHJlcHVsc2lvbkZvcmNlWCA9IHJlcHVsc2lvbkZvcmNlICogZGlzdGFuY2VYIC8gZGlzdGFuY2U7XG4gICAgcmVwdWxzaW9uRm9yY2VZID0gcmVwdWxzaW9uRm9yY2UgKiBkaXN0YW5jZVkgLyBkaXN0YW5jZTtcbiAgICAgXG4gICAgLy8gQXBwbHkgZm9yY2VzIG9uIHRoZSB0d28gbm9kZXMgICAgXG4gICAgbm9kZUEucmVwdWxzaW9uRm9yY2VYIC09IHJlcHVsc2lvbkZvcmNlWDtcbiAgICBub2RlQS5yZXB1bHNpb25Gb3JjZVkgLT0gcmVwdWxzaW9uRm9yY2VZO1xuICAgIG5vZGVCLnJlcHVsc2lvbkZvcmNlWCArPSByZXB1bHNpb25Gb3JjZVg7XG4gICAgbm9kZUIucmVwdWxzaW9uRm9yY2VZICs9IHJlcHVsc2lvbkZvcmNlWTtcbiAgfVxufTtcblxuRkRMYXlvdXQucHJvdG90eXBlLmNhbGNHcmF2aXRhdGlvbmFsRm9yY2UgPSBmdW5jdGlvbiAobm9kZSkge1xuICB2YXIgb3duZXJHcmFwaDtcbiAgdmFyIG93bmVyQ2VudGVyWDtcbiAgdmFyIG93bmVyQ2VudGVyWTtcbiAgdmFyIGRpc3RhbmNlWDtcbiAgdmFyIGRpc3RhbmNlWTtcbiAgdmFyIGFic0Rpc3RhbmNlWDtcbiAgdmFyIGFic0Rpc3RhbmNlWTtcbiAgdmFyIGVzdGltYXRlZFNpemU7XG4gIG93bmVyR3JhcGggPSBub2RlLmdldE93bmVyKCk7XG5cbiAgb3duZXJDZW50ZXJYID0gKG93bmVyR3JhcGguZ2V0UmlnaHQoKSArIG93bmVyR3JhcGguZ2V0TGVmdCgpKSAvIDI7XG4gIG93bmVyQ2VudGVyWSA9IChvd25lckdyYXBoLmdldFRvcCgpICsgb3duZXJHcmFwaC5nZXRCb3R0b20oKSkgLyAyO1xuICBkaXN0YW5jZVggPSBub2RlLmdldENlbnRlclgoKSAtIG93bmVyQ2VudGVyWDtcbiAgZGlzdGFuY2VZID0gbm9kZS5nZXRDZW50ZXJZKCkgLSBvd25lckNlbnRlclk7XG4gIGFic0Rpc3RhbmNlWCA9IE1hdGguYWJzKGRpc3RhbmNlWCkgKyBub2RlLmdldFdpZHRoKCkgLyAyO1xuICBhYnNEaXN0YW5jZVkgPSBNYXRoLmFicyhkaXN0YW5jZVkpICsgbm9kZS5nZXRIZWlnaHQoKSAvIDI7XG5cbiAgaWYgKG5vZGUuZ2V0T3duZXIoKSA9PSB0aGlzLmdyYXBoTWFuYWdlci5nZXRSb290KCkpLy8gaW4gdGhlIHJvb3QgZ3JhcGhcbiAge1xuICAgIGVzdGltYXRlZFNpemUgPSBvd25lckdyYXBoLmdldEVzdGltYXRlZFNpemUoKSAqIHRoaXMuZ3Jhdml0eVJhbmdlRmFjdG9yO1xuXG4gICAgaWYgKGFic0Rpc3RhbmNlWCA+IGVzdGltYXRlZFNpemUgfHwgYWJzRGlzdGFuY2VZID4gZXN0aW1hdGVkU2l6ZSlcbiAgICB7XG4gICAgICBub2RlLmdyYXZpdGF0aW9uRm9yY2VYID0gLXRoaXMuZ3Jhdml0eUNvbnN0YW50ICogZGlzdGFuY2VYO1xuICAgICAgbm9kZS5ncmF2aXRhdGlvbkZvcmNlWSA9IC10aGlzLmdyYXZpdHlDb25zdGFudCAqIGRpc3RhbmNlWTtcbiAgICB9XG4gIH1cbiAgZWxzZS8vIGluc2lkZSBhIGNvbXBvdW5kXG4gIHtcbiAgICBlc3RpbWF0ZWRTaXplID0gb3duZXJHcmFwaC5nZXRFc3RpbWF0ZWRTaXplKCkgKiB0aGlzLmNvbXBvdW5kR3Jhdml0eVJhbmdlRmFjdG9yO1xuXG4gICAgaWYgKGFic0Rpc3RhbmNlWCA+IGVzdGltYXRlZFNpemUgfHwgYWJzRGlzdGFuY2VZID4gZXN0aW1hdGVkU2l6ZSlcbiAgICB7XG4gICAgICBub2RlLmdyYXZpdGF0aW9uRm9yY2VYID0gLXRoaXMuZ3Jhdml0eUNvbnN0YW50ICogZGlzdGFuY2VYICpcbiAgICAgICAgICAgICAgdGhpcy5jb21wb3VuZEdyYXZpdHlDb25zdGFudDtcbiAgICAgIG5vZGUuZ3Jhdml0YXRpb25Gb3JjZVkgPSAtdGhpcy5ncmF2aXR5Q29uc3RhbnQgKiBkaXN0YW5jZVkgKlxuICAgICAgICAgICAgICB0aGlzLmNvbXBvdW5kR3Jhdml0eUNvbnN0YW50O1xuICAgIH1cbiAgfVxufTtcblxuRkRMYXlvdXQucHJvdG90eXBlLmlzQ29udmVyZ2VkID0gZnVuY3Rpb24gKCkge1xuICB2YXIgY29udmVyZ2VkO1xuICB2YXIgb3NjaWxhdGluZyA9IGZhbHNlO1xuXG4gIGlmICh0aGlzLnRvdGFsSXRlcmF0aW9ucyA+IHRoaXMubWF4SXRlcmF0aW9ucyAvIDMpXG4gIHtcbiAgICBvc2NpbGF0aW5nID1cbiAgICAgICAgICAgIE1hdGguYWJzKHRoaXMudG90YWxEaXNwbGFjZW1lbnQgLSB0aGlzLm9sZFRvdGFsRGlzcGxhY2VtZW50KSA8IDI7XG4gIH1cblxuICBjb252ZXJnZWQgPSB0aGlzLnRvdGFsRGlzcGxhY2VtZW50IDwgdGhpcy50b3RhbERpc3BsYWNlbWVudFRocmVzaG9sZDtcblxuICB0aGlzLm9sZFRvdGFsRGlzcGxhY2VtZW50ID0gdGhpcy50b3RhbERpc3BsYWNlbWVudDtcblxuICByZXR1cm4gY29udmVyZ2VkIHx8IG9zY2lsYXRpbmc7XG59O1xuXG5GRExheW91dC5wcm90b3R5cGUuYW5pbWF0ZSA9IGZ1bmN0aW9uICgpIHtcbiAgaWYgKHRoaXMuYW5pbWF0aW9uRHVyaW5nTGF5b3V0ICYmICF0aGlzLmlzU3ViTGF5b3V0KVxuICB7XG4gICAgaWYgKHRoaXMubm90QW5pbWF0ZWRJdGVyYXRpb25zID09IHRoaXMuYW5pbWF0aW9uUGVyaW9kKVxuICAgIHtcbiAgICAgIHRoaXMudXBkYXRlKCk7XG4gICAgICB0aGlzLm5vdEFuaW1hdGVkSXRlcmF0aW9ucyA9IDA7XG4gICAgfVxuICAgIGVsc2VcbiAgICB7XG4gICAgICB0aGlzLm5vdEFuaW1hdGVkSXRlcmF0aW9ucysrO1xuICAgIH1cbiAgfVxufTtcblxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIFNlY3Rpb246IEZSLUdyaWQgVmFyaWFudCBSZXB1bHNpb24gRm9yY2UgQ2FsY3VsYXRpb25cbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbkZETGF5b3V0LnByb3RvdHlwZS5jYWxjR3JpZCA9IGZ1bmN0aW9uIChncmFwaCl7XG5cbiAgdmFyIHNpemVYID0gMDsgXG4gIHZhciBzaXplWSA9IDA7XG4gIFxuICBzaXplWCA9IHBhcnNlSW50KE1hdGguY2VpbCgoZ3JhcGguZ2V0UmlnaHQoKSAtIGdyYXBoLmdldExlZnQoKSkgLyB0aGlzLnJlcHVsc2lvblJhbmdlKSk7XG4gIHNpemVZID0gcGFyc2VJbnQoTWF0aC5jZWlsKChncmFwaC5nZXRCb3R0b20oKSAtIGdyYXBoLmdldFRvcCgpKSAvIHRoaXMucmVwdWxzaW9uUmFuZ2UpKTtcbiAgXG4gIHZhciBncmlkID0gbmV3IEFycmF5KHNpemVYKTtcbiAgXG4gIGZvcih2YXIgaSA9IDA7IGkgPCBzaXplWDsgaSsrKXtcbiAgICBncmlkW2ldID0gbmV3IEFycmF5KHNpemVZKTsgICAgXG4gIH1cbiAgXG4gIGZvcih2YXIgaSA9IDA7IGkgPCBzaXplWDsgaSsrKXtcbiAgICBmb3IodmFyIGogPSAwOyBqIDwgc2l6ZVk7IGorKyl7XG4gICAgICBncmlkW2ldW2pdID0gbmV3IEFycmF5KCk7ICAgIFxuICAgIH1cbiAgfVxuICBcbiAgcmV0dXJuIGdyaWQ7XG59O1xuXG5GRExheW91dC5wcm90b3R5cGUuYWRkTm9kZVRvR3JpZCA9IGZ1bmN0aW9uICh2LCBsZWZ0LCB0b3Ape1xuICAgIFxuICB2YXIgc3RhcnRYID0gMDtcbiAgdmFyIGZpbmlzaFggPSAwO1xuICB2YXIgc3RhcnRZID0gMDtcbiAgdmFyIGZpbmlzaFkgPSAwO1xuICBcbiAgc3RhcnRYID0gcGFyc2VJbnQoTWF0aC5mbG9vcigodi5nZXRSZWN0KCkueCAtIGxlZnQpIC8gdGhpcy5yZXB1bHNpb25SYW5nZSkpO1xuICBmaW5pc2hYID0gcGFyc2VJbnQoTWF0aC5mbG9vcigodi5nZXRSZWN0KCkud2lkdGggKyB2LmdldFJlY3QoKS54IC0gbGVmdCkgLyB0aGlzLnJlcHVsc2lvblJhbmdlKSk7XG4gIHN0YXJ0WSA9IHBhcnNlSW50KE1hdGguZmxvb3IoKHYuZ2V0UmVjdCgpLnkgLSB0b3ApIC8gdGhpcy5yZXB1bHNpb25SYW5nZSkpO1xuICBmaW5pc2hZID0gcGFyc2VJbnQoTWF0aC5mbG9vcigodi5nZXRSZWN0KCkuaGVpZ2h0ICsgdi5nZXRSZWN0KCkueSAtIHRvcCkgLyB0aGlzLnJlcHVsc2lvblJhbmdlKSk7XG5cbiAgZm9yICh2YXIgaSA9IHN0YXJ0WDsgaSA8PSBmaW5pc2hYOyBpKyspXG4gIHtcbiAgICBmb3IgKHZhciBqID0gc3RhcnRZOyBqIDw9IGZpbmlzaFk7IGorKylcbiAgICB7XG4gICAgICB0aGlzLmdyaWRbaV1bal0ucHVzaCh2KTtcbiAgICAgIHYuc2V0R3JpZENvb3JkaW5hdGVzKHN0YXJ0WCwgZmluaXNoWCwgc3RhcnRZLCBmaW5pc2hZKTsgXG4gICAgfVxuICB9ICBcblxufTtcblxuRkRMYXlvdXQucHJvdG90eXBlLnVwZGF0ZUdyaWQgPSBmdW5jdGlvbigpIHtcbiAgdmFyIGk7XG4gIHZhciBub2RlQTtcbiAgdmFyIGxOb2RlcyA9IHRoaXMuZ2V0QWxsTm9kZXMoKTtcbiAgXG4gIHRoaXMuZ3JpZCA9IHRoaXMuY2FsY0dyaWQodGhpcy5ncmFwaE1hbmFnZXIuZ2V0Um9vdCgpKTsgICBcblxuICAvLyBwdXQgYWxsIG5vZGVzIHRvIHByb3BlciBncmlkIGNlbGxzXG4gIGZvciAoaSA9IDA7IGkgPCBsTm9kZXMubGVuZ3RoOyBpKyspXG4gIHtcbiAgICBub2RlQSA9IGxOb2Rlc1tpXTtcbiAgICB0aGlzLmFkZE5vZGVUb0dyaWQobm9kZUEsIHRoaXMuZ3JhcGhNYW5hZ2VyLmdldFJvb3QoKS5nZXRMZWZ0KCksIHRoaXMuZ3JhcGhNYW5hZ2VyLmdldFJvb3QoKS5nZXRUb3AoKSk7XG4gIH0gXG5cbn07XG5cbkZETGF5b3V0LnByb3RvdHlwZS5jYWxjdWxhdGVSZXB1bHNpb25Gb3JjZU9mQU5vZGUgPSBmdW5jdGlvbiAobm9kZUEsIHByb2Nlc3NlZE5vZGVTZXQpe1xuICBcbiAgaWYgKCh0aGlzLnRvdGFsSXRlcmF0aW9ucyAlIEZETGF5b3V0Q29uc3RhbnRzLkdSSURfQ0FMQ1VMQVRJT05fQ0hFQ0tfUEVSSU9EID09IDEgJiYgIXRoaXMuaXNUcmVlR3Jvd2luZyAmJiAhdGhpcy5pc0dyb3d0aEZpbmlzaGVkKSB8fCAodGhpcy5ncm93VHJlZUl0ZXJhdGlvbnMgJSAxMCA9PSAxICYmIHRoaXMuaXNUcmVlR3Jvd2luZykgfHwgKHRoaXMuYWZ0ZXJHcm93dGhJdGVyYXRpb25zICUgMTAgPT0gMSAmJiB0aGlzLmlzR3Jvd3RoRmluaXNoZWQpKVxuICB7XG4gICAgdmFyIHN1cnJvdW5kaW5nID0gbmV3IFNldCgpO1xuICAgIG5vZGVBLnN1cnJvdW5kaW5nID0gbmV3IEFycmF5KCk7XG4gICAgdmFyIG5vZGVCO1xuICAgIHZhciBncmlkID0gdGhpcy5ncmlkO1xuICAgIFxuICAgIGZvciAodmFyIGkgPSAobm9kZUEuc3RhcnRYIC0gMSk7IGkgPCAobm9kZUEuZmluaXNoWCArIDIpOyBpKyspXG4gICAge1xuICAgICAgZm9yICh2YXIgaiA9IChub2RlQS5zdGFydFkgLSAxKTsgaiA8IChub2RlQS5maW5pc2hZICsgMik7IGorKylcbiAgICAgIHtcbiAgICAgICAgaWYgKCEoKGkgPCAwKSB8fCAoaiA8IDApIHx8IChpID49IGdyaWQubGVuZ3RoKSB8fCAoaiA+PSBncmlkWzBdLmxlbmd0aCkpKVxuICAgICAgICB7ICBcbiAgICAgICAgICBmb3IgKHZhciBrID0gMDsgayA8IGdyaWRbaV1bal0ubGVuZ3RoOyBrKyspIHtcbiAgICAgICAgICAgIG5vZGVCID0gZ3JpZFtpXVtqXVtrXTtcblxuICAgICAgICAgICAgLy8gSWYgYm90aCBub2RlcyBhcmUgbm90IG1lbWJlcnMgb2YgdGhlIHNhbWUgZ3JhcGgsIFxuICAgICAgICAgICAgLy8gb3IgYm90aCBub2RlcyBhcmUgdGhlIHNhbWUsIHNraXAuXG4gICAgICAgICAgICBpZiAoKG5vZGVBLmdldE93bmVyKCkgIT0gbm9kZUIuZ2V0T3duZXIoKSkgfHwgKG5vZGVBID09IG5vZGVCKSlcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBcbiAgICAgICAgICAgIC8vIGNoZWNrIGlmIHRoZSByZXB1bHNpb24gZm9yY2UgYmV0d2VlblxuICAgICAgICAgICAgLy8gbm9kZUEgYW5kIG5vZGVCIGhhcyBhbHJlYWR5IGJlZW4gY2FsY3VsYXRlZFxuICAgICAgICAgICAgaWYgKCFwcm9jZXNzZWROb2RlU2V0Lmhhcyhub2RlQikgJiYgIXN1cnJvdW5kaW5nLmhhcyhub2RlQikpXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIHZhciBkaXN0YW5jZVggPSBNYXRoLmFicyhub2RlQS5nZXRDZW50ZXJYKCktbm9kZUIuZ2V0Q2VudGVyWCgpKSAtIFxuICAgICAgICAgICAgICAgICAgICAoKG5vZGVBLmdldFdpZHRoKCkvMikgKyAobm9kZUIuZ2V0V2lkdGgoKS8yKSk7XG4gICAgICAgICAgICAgIHZhciBkaXN0YW5jZVkgPSBNYXRoLmFicyhub2RlQS5nZXRDZW50ZXJZKCktbm9kZUIuZ2V0Q2VudGVyWSgpKSAtIFxuICAgICAgICAgICAgICAgICAgICAoKG5vZGVBLmdldEhlaWdodCgpLzIpICsgKG5vZGVCLmdldEhlaWdodCgpLzIpKTtcbiAgICAgICAgICAgIFxuICAgICAgICAgICAgICAvLyBpZiB0aGUgZGlzdGFuY2UgYmV0d2VlbiBub2RlQSBhbmQgbm9kZUIgXG4gICAgICAgICAgICAgIC8vIGlzIGxlc3MgdGhlbiBjYWxjdWxhdGlvbiByYW5nZVxuICAgICAgICAgICAgICBpZiAoKGRpc3RhbmNlWCA8PSB0aGlzLnJlcHVsc2lvblJhbmdlKSAmJiAoZGlzdGFuY2VZIDw9IHRoaXMucmVwdWxzaW9uUmFuZ2UpKVxuICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgLy90aGVuIGFkZCBub2RlQiB0byBzdXJyb3VuZGluZyBvZiBub2RlQVxuICAgICAgICAgICAgICAgIHN1cnJvdW5kaW5nLmFkZChub2RlQik7XG4gICAgICAgICAgICAgIH0gICAgICAgICAgICAgIFxuICAgICAgICAgICAgfSAgICBcbiAgICAgICAgICB9XG4gICAgICAgIH0gICAgICAgICAgXG4gICAgICB9XG4gICAgfVxuXG4gICAgbm9kZUEuc3Vycm91bmRpbmcgPSBbLi4uc3Vycm91bmRpbmddO1xuXHRcbiAgfVxuICBmb3IgKGkgPSAwOyBpIDwgbm9kZUEuc3Vycm91bmRpbmcubGVuZ3RoOyBpKyspXG4gIHtcbiAgICB0aGlzLmNhbGNSZXB1bHNpb25Gb3JjZShub2RlQSwgbm9kZUEuc3Vycm91bmRpbmdbaV0pO1xuICB9XHRcbn07XG5cbkZETGF5b3V0LnByb3RvdHlwZS5jYWxjUmVwdWxzaW9uUmFuZ2UgPSBmdW5jdGlvbiAoKSB7XG4gIHJldHVybiAwLjA7XG59O1xuXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuLy8gU2VjdGlvbjogVHJlZSBSZWR1Y3Rpb24gbWV0aG9kc1xuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIFJlZHVjZSB0cmVlcyBcbkZETGF5b3V0LnByb3RvdHlwZS5yZWR1Y2VUcmVlcyA9IGZ1bmN0aW9uICgpXG57XG4gIHZhciBwcnVuZWROb2Rlc0FsbCA9IFtdO1xuICB2YXIgY29udGFpbnNMZWFmID0gdHJ1ZTtcbiAgdmFyIG5vZGU7XG4gIFxuICB3aGlsZShjb250YWluc0xlYWYpIHtcbiAgICB2YXIgYWxsTm9kZXMgPSB0aGlzLmdyYXBoTWFuYWdlci5nZXRBbGxOb2RlcygpO1xuICAgIHZhciBwcnVuZWROb2Rlc0luU3RlcFRlbXAgPSBbXTtcbiAgICBjb250YWluc0xlYWYgPSBmYWxzZTtcbiAgICBcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGFsbE5vZGVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBub2RlID0gYWxsTm9kZXNbaV07XG4gICAgICBpZihub2RlLmdldEVkZ2VzKCkubGVuZ3RoID09IDEgJiYgIW5vZGUuZ2V0RWRnZXMoKVswXS5pc0ludGVyR3JhcGggJiYgbm9kZS5nZXRDaGlsZCgpID09IG51bGwpe1xuICAgICAgICBwcnVuZWROb2Rlc0luU3RlcFRlbXAucHVzaChbbm9kZSwgbm9kZS5nZXRFZGdlcygpWzBdLCBub2RlLmdldE93bmVyKCldKTtcbiAgICAgICAgY29udGFpbnNMZWFmID0gdHJ1ZTtcbiAgICAgIH0gIFxuICAgIH1cbiAgICBpZihjb250YWluc0xlYWYgPT0gdHJ1ZSl7XG4gICAgICB2YXIgcHJ1bmVkTm9kZXNJblN0ZXAgPSBbXTtcbiAgICAgIGZvcih2YXIgaiA9IDA7IGogPCBwcnVuZWROb2Rlc0luU3RlcFRlbXAubGVuZ3RoOyBqKyspe1xuICAgICAgICBpZihwcnVuZWROb2Rlc0luU3RlcFRlbXBbal1bMF0uZ2V0RWRnZXMoKS5sZW5ndGggPT0gMSl7XG4gICAgICAgICAgcHJ1bmVkTm9kZXNJblN0ZXAucHVzaChwcnVuZWROb2Rlc0luU3RlcFRlbXBbal0pOyAgXG4gICAgICAgICAgcHJ1bmVkTm9kZXNJblN0ZXBUZW1wW2pdWzBdLmdldE93bmVyKCkucmVtb3ZlKHBydW5lZE5vZGVzSW5TdGVwVGVtcFtqXVswXSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHBydW5lZE5vZGVzQWxsLnB1c2gocHJ1bmVkTm9kZXNJblN0ZXApO1xuICAgICAgdGhpcy5ncmFwaE1hbmFnZXIucmVzZXRBbGxOb2RlcygpO1xuICAgICAgdGhpcy5ncmFwaE1hbmFnZXIucmVzZXRBbGxFZGdlcygpO1xuICAgIH1cbiAgfVxuICB0aGlzLnBydW5lZE5vZGVzQWxsID0gcHJ1bmVkTm9kZXNBbGw7XG59O1xuXG4vLyBHcm93IHRyZWUgb25lIHN0ZXAgXG5GRExheW91dC5wcm90b3R5cGUuZ3Jvd1RyZWUgPSBmdW5jdGlvbihwcnVuZWROb2Rlc0FsbClcbntcbiAgdmFyIGxlbmd0aE9mUHJ1bmVkTm9kZXNJblN0ZXAgPSBwcnVuZWROb2Rlc0FsbC5sZW5ndGg7IFxuICB2YXIgcHJ1bmVkTm9kZXNJblN0ZXAgPSBwcnVuZWROb2Rlc0FsbFtsZW5ndGhPZlBydW5lZE5vZGVzSW5TdGVwIC0gMV07ICBcblxuICB2YXIgbm9kZURhdGE7ICBcbiAgZm9yKHZhciBpID0gMDsgaSA8IHBydW5lZE5vZGVzSW5TdGVwLmxlbmd0aDsgaSsrKXtcbiAgICBub2RlRGF0YSA9IHBydW5lZE5vZGVzSW5TdGVwW2ldO1xuXG4gICAgdGhpcy5maW5kUGxhY2Vmb3JQcnVuZWROb2RlKG5vZGVEYXRhKTtcbiAgICBcbiAgICBub2RlRGF0YVsyXS5hZGQobm9kZURhdGFbMF0pO1xuICAgIG5vZGVEYXRhWzJdLmFkZChub2RlRGF0YVsxXSwgbm9kZURhdGFbMV0uc291cmNlLCBub2RlRGF0YVsxXS50YXJnZXQpO1xuICB9XG5cbiAgcHJ1bmVkTm9kZXNBbGwuc3BsaWNlKHBydW5lZE5vZGVzQWxsLmxlbmd0aC0xLCAxKTtcbiAgdGhpcy5ncmFwaE1hbmFnZXIucmVzZXRBbGxOb2RlcygpO1xuICB0aGlzLmdyYXBoTWFuYWdlci5yZXNldEFsbEVkZ2VzKCk7XG59O1xuXG4vLyBGaW5kIGFuIGFwcHJvcHJpYXRlIHBvc2l0aW9uIHRvIHJlcGxhY2UgcHJ1bmVkIG5vZGUsIHRoaXMgbWV0aG9kIGNhbiBiZSBpbXByb3ZlZFxuRkRMYXlvdXQucHJvdG90eXBlLmZpbmRQbGFjZWZvclBydW5lZE5vZGUgPSBmdW5jdGlvbihub2RlRGF0YSl7XG4gIFxuICB2YXIgZ3JpZEZvclBydW5lZE5vZGU7ICBcbiAgdmFyIG5vZGVUb0Nvbm5lY3Q7XG4gIHZhciBwcnVuZWROb2RlID0gbm9kZURhdGFbMF07XG4gIGlmKHBydW5lZE5vZGUgPT0gbm9kZURhdGFbMV0uc291cmNlKXtcbiAgICBub2RlVG9Db25uZWN0ID0gbm9kZURhdGFbMV0udGFyZ2V0O1xuICB9XG4gIGVsc2Uge1xuICAgIG5vZGVUb0Nvbm5lY3QgPSBub2RlRGF0YVsxXS5zb3VyY2U7ICBcbiAgfVxuICB2YXIgc3RhcnRHcmlkWCA9IG5vZGVUb0Nvbm5lY3Quc3RhcnRYO1xuICB2YXIgZmluaXNoR3JpZFggPSBub2RlVG9Db25uZWN0LmZpbmlzaFg7XG4gIHZhciBzdGFydEdyaWRZID0gbm9kZVRvQ29ubmVjdC5zdGFydFk7XG4gIHZhciBmaW5pc2hHcmlkWSA9IG5vZGVUb0Nvbm5lY3QuZmluaXNoWTsgXG4gIFxuICB2YXIgdXBOb2RlQ291bnQgPSAwO1xuICB2YXIgZG93bk5vZGVDb3VudCA9IDA7XG4gIHZhciByaWdodE5vZGVDb3VudCA9IDA7XG4gIHZhciBsZWZ0Tm9kZUNvdW50ID0gMDtcbiAgdmFyIGNvbnRyb2xSZWdpb25zID0gW3VwTm9kZUNvdW50LCByaWdodE5vZGVDb3VudCwgZG93bk5vZGVDb3VudCwgbGVmdE5vZGVDb3VudF1cbiAgXG4gIGlmKHN0YXJ0R3JpZFkgPiAwKXtcbiAgICBmb3IodmFyIGkgPSBzdGFydEdyaWRYOyBpIDw9IGZpbmlzaEdyaWRYOyBpKysgKXtcbiAgICAgIGNvbnRyb2xSZWdpb25zWzBdICs9ICh0aGlzLmdyaWRbaV1bc3RhcnRHcmlkWSAtIDFdLmxlbmd0aCArIHRoaXMuZ3JpZFtpXVtzdGFydEdyaWRZXS5sZW5ndGggLSAxKTsgICBcbiAgICB9XG4gIH1cbiAgaWYoZmluaXNoR3JpZFggPCB0aGlzLmdyaWQubGVuZ3RoIC0gMSl7XG4gICAgZm9yKHZhciBpID0gc3RhcnRHcmlkWTsgaSA8PSBmaW5pc2hHcmlkWTsgaSsrICl7XG4gICAgICBjb250cm9sUmVnaW9uc1sxXSArPSAodGhpcy5ncmlkW2ZpbmlzaEdyaWRYICsgMV1baV0ubGVuZ3RoICsgdGhpcy5ncmlkW2ZpbmlzaEdyaWRYXVtpXS5sZW5ndGggLSAxKTsgICBcbiAgICB9XG4gIH1cbiAgaWYoZmluaXNoR3JpZFkgPCB0aGlzLmdyaWRbMF0ubGVuZ3RoIC0gMSl7XG4gICAgZm9yKHZhciBpID0gc3RhcnRHcmlkWDsgaSA8PSBmaW5pc2hHcmlkWDsgaSsrICl7XG4gICAgICBjb250cm9sUmVnaW9uc1syXSArPSAodGhpcy5ncmlkW2ldW2ZpbmlzaEdyaWRZICsgMV0ubGVuZ3RoICsgdGhpcy5ncmlkW2ldW2ZpbmlzaEdyaWRZXS5sZW5ndGggLSAxKTsgICBcbiAgICB9XG4gIH1cbiAgaWYoc3RhcnRHcmlkWCA+IDApe1xuICAgIGZvcih2YXIgaSA9IHN0YXJ0R3JpZFk7IGkgPD0gZmluaXNoR3JpZFk7IGkrKyApe1xuICAgICAgY29udHJvbFJlZ2lvbnNbM10gKz0gKHRoaXMuZ3JpZFtzdGFydEdyaWRYIC0gMV1baV0ubGVuZ3RoICsgdGhpcy5ncmlkW3N0YXJ0R3JpZFhdW2ldLmxlbmd0aCAtIDEpOyAgIFxuICAgIH1cbiAgfVxuICB2YXIgbWluID0gSW50ZWdlci5NQVhfVkFMVUU7XG4gIHZhciBtaW5Db3VudDtcbiAgdmFyIG1pbkluZGV4O1xuICBmb3IodmFyIGogPSAwOyBqIDwgY29udHJvbFJlZ2lvbnMubGVuZ3RoOyBqKyspe1xuICAgIGlmKGNvbnRyb2xSZWdpb25zW2pdIDwgbWluKXtcbiAgICAgIG1pbiA9IGNvbnRyb2xSZWdpb25zW2pdO1xuICAgICAgbWluQ291bnQgPSAxO1xuICAgICAgbWluSW5kZXggPSBqO1xuICAgIH0gIFxuICAgIGVsc2UgaWYoY29udHJvbFJlZ2lvbnNbal0gPT0gbWluKXtcbiAgICAgIG1pbkNvdW50Kys7ICBcbiAgICB9XG4gIH1cbiAgXG4gIGlmKG1pbkNvdW50ID09IDMgJiYgbWluID09IDApe1xuICAgIGlmKGNvbnRyb2xSZWdpb25zWzBdID09IDAgJiYgY29udHJvbFJlZ2lvbnNbMV0gPT0gMCAmJiBjb250cm9sUmVnaW9uc1syXSA9PSAwKXtcbiAgICAgIGdyaWRGb3JQcnVuZWROb2RlID0gMTsgICAgXG4gICAgfVxuICAgIGVsc2UgaWYoY29udHJvbFJlZ2lvbnNbMF0gPT0gMCAmJiBjb250cm9sUmVnaW9uc1sxXSA9PSAwICYmIGNvbnRyb2xSZWdpb25zWzNdID09IDApe1xuICAgICAgZ3JpZEZvclBydW5lZE5vZGUgPSAwOyAgXG4gICAgfVxuICAgIGVsc2UgaWYoY29udHJvbFJlZ2lvbnNbMF0gPT0gMCAmJiBjb250cm9sUmVnaW9uc1syXSA9PSAwICYmIGNvbnRyb2xSZWdpb25zWzNdID09IDApe1xuICAgICAgZ3JpZEZvclBydW5lZE5vZGUgPSAzOyAgXG4gICAgfVxuICAgIGVsc2UgaWYoY29udHJvbFJlZ2lvbnNbMV0gPT0gMCAmJiBjb250cm9sUmVnaW9uc1syXSA9PSAwICYmIGNvbnRyb2xSZWdpb25zWzNdID09IDApe1xuICAgICAgZ3JpZEZvclBydW5lZE5vZGUgPSAyOyAgXG4gICAgfVxuICB9XG4gIGVsc2UgaWYobWluQ291bnQgPT0gMiAmJiBtaW4gPT0gMCl7XG4gICAgdmFyIHJhbmRvbSA9IE1hdGguZmxvb3IoTWF0aC5yYW5kb20oKSAqIDIpO1xuICAgIGlmKGNvbnRyb2xSZWdpb25zWzBdID09IDAgJiYgY29udHJvbFJlZ2lvbnNbMV0gPT0gMCl7O1xuICAgICAgaWYocmFuZG9tID09IDApe1xuICAgICAgICBncmlkRm9yUHJ1bmVkTm9kZSA9IDA7XG4gICAgICB9XG4gICAgICBlbHNle1xuICAgICAgICBncmlkRm9yUHJ1bmVkTm9kZSA9IDE7XG4gICAgICB9XG4gICAgfVxuICAgIGVsc2UgaWYoY29udHJvbFJlZ2lvbnNbMF0gPT0gMCAmJiBjb250cm9sUmVnaW9uc1syXSA9PSAwKXtcbiAgICAgIGlmKHJhbmRvbSA9PSAwKXtcbiAgICAgICAgZ3JpZEZvclBydW5lZE5vZGUgPSAwO1xuICAgICAgfVxuICAgICAgZWxzZXtcbiAgICAgICAgZ3JpZEZvclBydW5lZE5vZGUgPSAyO1xuICAgICAgfVxuICAgIH1cbiAgICBlbHNlIGlmKGNvbnRyb2xSZWdpb25zWzBdID09IDAgJiYgY29udHJvbFJlZ2lvbnNbM10gPT0gMCl7XG4gICAgICBpZihyYW5kb20gPT0gMCl7XG4gICAgICAgIGdyaWRGb3JQcnVuZWROb2RlID0gMDtcbiAgICAgIH1cbiAgICAgIGVsc2V7XG4gICAgICAgIGdyaWRGb3JQcnVuZWROb2RlID0gMztcbiAgICAgIH1cbiAgICB9XG4gICAgZWxzZSBpZihjb250cm9sUmVnaW9uc1sxXSA9PSAwICYmIGNvbnRyb2xSZWdpb25zWzJdID09IDApe1xuICAgICAgaWYocmFuZG9tID09IDApe1xuICAgICAgICBncmlkRm9yUHJ1bmVkTm9kZSA9IDE7XG4gICAgICB9XG4gICAgICBlbHNle1xuICAgICAgICBncmlkRm9yUHJ1bmVkTm9kZSA9IDI7XG4gICAgICB9XG4gICAgfVxuICAgIGVsc2UgaWYoY29udHJvbFJlZ2lvbnNbMV0gPT0gMCAmJiBjb250cm9sUmVnaW9uc1szXSA9PSAwKXtcbiAgICAgIGlmKHJhbmRvbSA9PSAwKXtcbiAgICAgICAgZ3JpZEZvclBydW5lZE5vZGUgPSAxO1xuICAgICAgfVxuICAgICAgZWxzZXtcbiAgICAgICAgZ3JpZEZvclBydW5lZE5vZGUgPSAzO1xuICAgICAgfVxuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgIGlmKHJhbmRvbSA9PSAwKXtcbiAgICAgICAgZ3JpZEZvclBydW5lZE5vZGUgPSAyO1xuICAgICAgfVxuICAgICAgZWxzZXtcbiAgICAgICAgZ3JpZEZvclBydW5lZE5vZGUgPSAzO1xuICAgICAgfVxuICAgIH1cbiAgfVxuICBlbHNlIGlmKG1pbkNvdW50ID09IDQgJiYgbWluID09IDApe1xuICAgIHZhciByYW5kb20gPSBNYXRoLmZsb29yKE1hdGgucmFuZG9tKCkgKiA0KTtcbiAgICBncmlkRm9yUHJ1bmVkTm9kZSA9IHJhbmRvbTsgIFxuICB9XG4gIGVsc2Uge1xuICAgIGdyaWRGb3JQcnVuZWROb2RlID0gbWluSW5kZXg7XG4gIH1cbiAgXG4gIGlmKGdyaWRGb3JQcnVuZWROb2RlID09IDApIHtcbiAgICBwcnVuZWROb2RlLnNldENlbnRlcihub2RlVG9Db25uZWN0LmdldENlbnRlclgoKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICBub2RlVG9Db25uZWN0LmdldENlbnRlclkoKSAtIG5vZGVUb0Nvbm5lY3QuZ2V0SGVpZ2h0KCkvMiAtIEZETGF5b3V0Q29uc3RhbnRzLkRFRkFVTFRfRURHRV9MRU5HVEggLSBwcnVuZWROb2RlLmdldEhlaWdodCgpLzIpOyAgXG4gIH1cbiAgZWxzZSBpZihncmlkRm9yUHJ1bmVkTm9kZSA9PSAxKSB7XG4gICAgcHJ1bmVkTm9kZS5zZXRDZW50ZXIobm9kZVRvQ29ubmVjdC5nZXRDZW50ZXJYKCkgKyBub2RlVG9Db25uZWN0LmdldFdpZHRoKCkvMiArIEZETGF5b3V0Q29uc3RhbnRzLkRFRkFVTFRfRURHRV9MRU5HVEggKyBwcnVuZWROb2RlLmdldFdpZHRoKCkvMixcbiAgICAgICAgICAgICAgICAgICAgICAgICBub2RlVG9Db25uZWN0LmdldENlbnRlclkoKSk7ICBcbiAgfVxuICBlbHNlIGlmKGdyaWRGb3JQcnVuZWROb2RlID09IDIpIHtcbiAgICBwcnVuZWROb2RlLnNldENlbnRlcihub2RlVG9Db25uZWN0LmdldENlbnRlclgoKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICBub2RlVG9Db25uZWN0LmdldENlbnRlclkoKSArIG5vZGVUb0Nvbm5lY3QuZ2V0SGVpZ2h0KCkvMiArIEZETGF5b3V0Q29uc3RhbnRzLkRFRkFVTFRfRURHRV9MRU5HVEggKyBwcnVuZWROb2RlLmdldEhlaWdodCgpLzIpOyAgXG4gIH1cbiAgZWxzZSB7IFxuICAgIHBydW5lZE5vZGUuc2V0Q2VudGVyKG5vZGVUb0Nvbm5lY3QuZ2V0Q2VudGVyWCgpIC0gbm9kZVRvQ29ubmVjdC5nZXRXaWR0aCgpLzIgLSBGRExheW91dENvbnN0YW50cy5ERUZBVUxUX0VER0VfTEVOR1RIIC0gcHJ1bmVkTm9kZS5nZXRXaWR0aCgpLzIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgbm9kZVRvQ29ubmVjdC5nZXRDZW50ZXJZKCkpOyAgXG4gIH1cbiAgXG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IEZETGF5b3V0O1xuIiwidmFyIExheW91dENvbnN0YW50cyA9IHJlcXVpcmUoJy4vTGF5b3V0Q29uc3RhbnRzJyk7XG5cbmZ1bmN0aW9uIEZETGF5b3V0Q29uc3RhbnRzKCkge1xufVxuXG4vL0ZETGF5b3V0Q29uc3RhbnRzIGluaGVyaXRzIHN0YXRpYyBwcm9wcyBpbiBMYXlvdXRDb25zdGFudHNcbmZvciAodmFyIHByb3AgaW4gTGF5b3V0Q29uc3RhbnRzKSB7XG4gIEZETGF5b3V0Q29uc3RhbnRzW3Byb3BdID0gTGF5b3V0Q29uc3RhbnRzW3Byb3BdO1xufVxuXG5GRExheW91dENvbnN0YW50cy5NQVhfSVRFUkFUSU9OUyA9IDI1MDA7XG5cbkZETGF5b3V0Q29uc3RhbnRzLkRFRkFVTFRfRURHRV9MRU5HVEggPSA1MDtcbkZETGF5b3V0Q29uc3RhbnRzLkRFRkFVTFRfU1BSSU5HX1NUUkVOR1RIID0gMC40NTtcbkZETGF5b3V0Q29uc3RhbnRzLkRFRkFVTFRfUkVQVUxTSU9OX1NUUkVOR1RIID0gNDUwMC4wO1xuRkRMYXlvdXRDb25zdGFudHMuREVGQVVMVF9HUkFWSVRZX1NUUkVOR1RIID0gMC40O1xuRkRMYXlvdXRDb25zdGFudHMuREVGQVVMVF9DT01QT1VORF9HUkFWSVRZX1NUUkVOR1RIID0gMS4wO1xuRkRMYXlvdXRDb25zdGFudHMuREVGQVVMVF9HUkFWSVRZX1JBTkdFX0ZBQ1RPUiA9IDMuODtcbkZETGF5b3V0Q29uc3RhbnRzLkRFRkFVTFRfQ09NUE9VTkRfR1JBVklUWV9SQU5HRV9GQUNUT1IgPSAxLjU7XG5GRExheW91dENvbnN0YW50cy5ERUZBVUxUX1VTRV9TTUFSVF9JREVBTF9FREdFX0xFTkdUSF9DQUxDVUxBVElPTiA9IHRydWU7XG5GRExheW91dENvbnN0YW50cy5ERUZBVUxUX1VTRV9TTUFSVF9SRVBVTFNJT05fUkFOR0VfQ0FMQ1VMQVRJT04gPSB0cnVlO1xuRkRMYXlvdXRDb25zdGFudHMuREVGQVVMVF9DT09MSU5HX0ZBQ1RPUl9JTkNSRU1FTlRBTCA9IDAuNTtcbkZETGF5b3V0Q29uc3RhbnRzLk1BWF9OT0RFX0RJU1BMQUNFTUVOVF9JTkNSRU1FTlRBTCA9IDEwMC4wO1xuRkRMYXlvdXRDb25zdGFudHMuTUFYX05PREVfRElTUExBQ0VNRU5UID0gRkRMYXlvdXRDb25zdGFudHMuTUFYX05PREVfRElTUExBQ0VNRU5UX0lOQ1JFTUVOVEFMICogMztcbkZETGF5b3V0Q29uc3RhbnRzLk1JTl9SRVBVTFNJT05fRElTVCA9IEZETGF5b3V0Q29uc3RhbnRzLkRFRkFVTFRfRURHRV9MRU5HVEggLyAxMC4wO1xuRkRMYXlvdXRDb25zdGFudHMuQ09OVkVSR0VOQ0VfQ0hFQ0tfUEVSSU9EID0gMTAwO1xuRkRMYXlvdXRDb25zdGFudHMuUEVSX0xFVkVMX0lERUFMX0VER0VfTEVOR1RIX0ZBQ1RPUiA9IDAuMTtcbkZETGF5b3V0Q29uc3RhbnRzLk1JTl9FREdFX0xFTkdUSCA9IDE7XG5GRExheW91dENvbnN0YW50cy5HUklEX0NBTENVTEFUSU9OX0NIRUNLX1BFUklPRCA9IDEwO1xuXG5tb2R1bGUuZXhwb3J0cyA9IEZETGF5b3V0Q29uc3RhbnRzO1xuIiwidmFyIExFZGdlID0gcmVxdWlyZSgnLi9MRWRnZScpO1xudmFyIEZETGF5b3V0Q29uc3RhbnRzID0gcmVxdWlyZSgnLi9GRExheW91dENvbnN0YW50cycpO1xuXG5mdW5jdGlvbiBGRExheW91dEVkZ2Uoc291cmNlLCB0YXJnZXQsIHZFZGdlKSB7XG4gIExFZGdlLmNhbGwodGhpcywgc291cmNlLCB0YXJnZXQsIHZFZGdlKTtcbiAgdGhpcy5pZGVhbExlbmd0aCA9IEZETGF5b3V0Q29uc3RhbnRzLkRFRkFVTFRfRURHRV9MRU5HVEg7XG59XG5cbkZETGF5b3V0RWRnZS5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKExFZGdlLnByb3RvdHlwZSk7XG5cbmZvciAodmFyIHByb3AgaW4gTEVkZ2UpIHtcbiAgRkRMYXlvdXRFZGdlW3Byb3BdID0gTEVkZ2VbcHJvcF07XG59XG5cbm1vZHVsZS5leHBvcnRzID0gRkRMYXlvdXRFZGdlO1xuIiwidmFyIExOb2RlID0gcmVxdWlyZSgnLi9MTm9kZScpO1xuXG5mdW5jdGlvbiBGRExheW91dE5vZGUoZ20sIGxvYywgc2l6ZSwgdk5vZGUpIHtcbiAgLy8gYWx0ZXJuYXRpdmUgY29uc3RydWN0b3IgaXMgaGFuZGxlZCBpbnNpZGUgTE5vZGVcbiAgTE5vZGUuY2FsbCh0aGlzLCBnbSwgbG9jLCBzaXplLCB2Tm9kZSk7XG4gIC8vU3ByaW5nLCByZXB1bHNpb24gYW5kIGdyYXZpdGF0aW9uYWwgZm9yY2VzIGFjdGluZyBvbiB0aGlzIG5vZGVcbiAgdGhpcy5zcHJpbmdGb3JjZVggPSAwO1xuICB0aGlzLnNwcmluZ0ZvcmNlWSA9IDA7XG4gIHRoaXMucmVwdWxzaW9uRm9yY2VYID0gMDtcbiAgdGhpcy5yZXB1bHNpb25Gb3JjZVkgPSAwO1xuICB0aGlzLmdyYXZpdGF0aW9uRm9yY2VYID0gMDtcbiAgdGhpcy5ncmF2aXRhdGlvbkZvcmNlWSA9IDA7XG4gIC8vQW1vdW50IGJ5IHdoaWNoIHRoaXMgbm9kZSBpcyB0byBiZSBtb3ZlZCBpbiB0aGlzIGl0ZXJhdGlvblxuICB0aGlzLmRpc3BsYWNlbWVudFggPSAwO1xuICB0aGlzLmRpc3BsYWNlbWVudFkgPSAwO1xuXG4gIC8vU3RhcnQgYW5kIGZpbmlzaCBncmlkIGNvb3JkaW5hdGVzIHRoYXQgdGhpcyBub2RlIGlzIGZhbGxlbiBpbnRvXG4gIHRoaXMuc3RhcnRYID0gMDtcbiAgdGhpcy5maW5pc2hYID0gMDtcbiAgdGhpcy5zdGFydFkgPSAwO1xuICB0aGlzLmZpbmlzaFkgPSAwO1xuXG4gIC8vR2VvbWV0cmljIG5laWdoYm9ycyBvZiB0aGlzIG5vZGVcbiAgdGhpcy5zdXJyb3VuZGluZyA9IFtdO1xufVxuXG5GRExheW91dE5vZGUucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShMTm9kZS5wcm90b3R5cGUpO1xuXG5mb3IgKHZhciBwcm9wIGluIExOb2RlKSB7XG4gIEZETGF5b3V0Tm9kZVtwcm9wXSA9IExOb2RlW3Byb3BdO1xufVxuXG5GRExheW91dE5vZGUucHJvdG90eXBlLnNldEdyaWRDb29yZGluYXRlcyA9IGZ1bmN0aW9uIChfc3RhcnRYLCBfZmluaXNoWCwgX3N0YXJ0WSwgX2ZpbmlzaFkpXG57XG4gIHRoaXMuc3RhcnRYID0gX3N0YXJ0WDtcbiAgdGhpcy5maW5pc2hYID0gX2ZpbmlzaFg7XG4gIHRoaXMuc3RhcnRZID0gX3N0YXJ0WTtcbiAgdGhpcy5maW5pc2hZID0gX2ZpbmlzaFk7XG5cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gRkRMYXlvdXROb2RlO1xuIiwidmFyIFVuaXF1ZUlER2VuZXJldG9yID0gcmVxdWlyZSgnLi9VbmlxdWVJREdlbmVyZXRvcicpO1xuXG5mdW5jdGlvbiBIYXNoTWFwKCkge1xuICB0aGlzLm1hcCA9IHt9O1xuICB0aGlzLmtleXMgPSBbXTtcbn1cblxuSGFzaE1hcC5wcm90b3R5cGUucHV0ID0gZnVuY3Rpb24gKGtleSwgdmFsdWUpIHtcbiAgdmFyIHRoZUlkID0gVW5pcXVlSURHZW5lcmV0b3IuY3JlYXRlSUQoa2V5KTtcbiAgaWYgKCF0aGlzLmNvbnRhaW5zKHRoZUlkKSkge1xuICAgIHRoaXMubWFwW3RoZUlkXSA9IHZhbHVlO1xuICAgIHRoaXMua2V5cy5wdXNoKGtleSk7XG4gIH1cbn07XG5cbkhhc2hNYXAucHJvdG90eXBlLmNvbnRhaW5zID0gZnVuY3Rpb24gKGtleSkge1xuICB2YXIgdGhlSWQgPSBVbmlxdWVJREdlbmVyZXRvci5jcmVhdGVJRChrZXkpO1xuICByZXR1cm4gdGhpcy5tYXBba2V5XSAhPSBudWxsO1xufTtcblxuSGFzaE1hcC5wcm90b3R5cGUuZ2V0ID0gZnVuY3Rpb24gKGtleSkge1xuICB2YXIgdGhlSWQgPSBVbmlxdWVJREdlbmVyZXRvci5jcmVhdGVJRChrZXkpO1xuICByZXR1cm4gdGhpcy5tYXBbdGhlSWRdO1xufTtcblxuSGFzaE1hcC5wcm90b3R5cGUua2V5U2V0ID0gZnVuY3Rpb24gKCkge1xuICByZXR1cm4gdGhpcy5rZXlzO1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSBIYXNoTWFwO1xuIiwidmFyIFVuaXF1ZUlER2VuZXJldG9yID0gcmVxdWlyZSgnLi9VbmlxdWVJREdlbmVyZXRvcicpO1xuXG5mdW5jdGlvbiBIYXNoU2V0KCkge1xuICB0aGlzLnNldCA9IHt9O1xufVxuO1xuXG5IYXNoU2V0LnByb3RvdHlwZS5hZGQgPSBmdW5jdGlvbiAob2JqKSB7XG4gIHZhciB0aGVJZCA9IFVuaXF1ZUlER2VuZXJldG9yLmNyZWF0ZUlEKG9iaik7XG4gIGlmICghdGhpcy5jb250YWlucyh0aGVJZCkpXG4gICAgdGhpcy5zZXRbdGhlSWRdID0gb2JqO1xufTtcblxuSGFzaFNldC5wcm90b3R5cGUucmVtb3ZlID0gZnVuY3Rpb24gKG9iaikge1xuICBkZWxldGUgdGhpcy5zZXRbVW5pcXVlSURHZW5lcmV0b3IuY3JlYXRlSUQob2JqKV07XG59O1xuXG5IYXNoU2V0LnByb3RvdHlwZS5jbGVhciA9IGZ1bmN0aW9uICgpIHtcbiAgdGhpcy5zZXQgPSB7fTtcbn07XG5cbkhhc2hTZXQucHJvdG90eXBlLmNvbnRhaW5zID0gZnVuY3Rpb24gKG9iaikge1xuICByZXR1cm4gdGhpcy5zZXRbVW5pcXVlSURHZW5lcmV0b3IuY3JlYXRlSUQob2JqKV0gPT0gb2JqO1xufTtcblxuSGFzaFNldC5wcm90b3R5cGUuaXNFbXB0eSA9IGZ1bmN0aW9uICgpIHtcbiAgcmV0dXJuIHRoaXMuc2l6ZSgpID09PSAwO1xufTtcblxuSGFzaFNldC5wcm90b3R5cGUuc2l6ZSA9IGZ1bmN0aW9uICgpIHtcbiAgcmV0dXJuIE9iamVjdC5rZXlzKHRoaXMuc2V0KS5sZW5ndGg7XG59O1xuXG4vL2NvbmNhdHMgdGhpcy5zZXQgdG8gdGhlIGdpdmVuIGxpc3Rcbkhhc2hTZXQucHJvdG90eXBlLmFkZEFsbFRvID0gZnVuY3Rpb24gKGxpc3QpIHtcbiAgdmFyIGtleXMgPSBPYmplY3Qua2V5cyh0aGlzLnNldCk7XG4gIHZhciBsZW5ndGggPSBrZXlzLmxlbmd0aDtcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7IGkrKykge1xuICAgIGxpc3QucHVzaCh0aGlzLnNldFtrZXlzW2ldXSk7XG4gIH1cbn07XG5cbkhhc2hTZXQucHJvdG90eXBlLnNpemUgPSBmdW5jdGlvbiAoKSB7XG4gIHJldHVybiBPYmplY3Qua2V5cyh0aGlzLnNldCkubGVuZ3RoO1xufTtcblxuSGFzaFNldC5wcm90b3R5cGUuYWRkQWxsID0gZnVuY3Rpb24gKGxpc3QpIHtcbiAgdmFyIHMgPSBsaXN0Lmxlbmd0aDtcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBzOyBpKyspIHtcbiAgICB2YXIgdiA9IGxpc3RbaV07XG4gICAgdGhpcy5hZGQodik7XG4gIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gSGFzaFNldDtcbiIsImZ1bmN0aW9uIElHZW9tZXRyeSgpIHtcbn1cblxuSUdlb21ldHJ5LmNhbGNTZXBhcmF0aW9uQW1vdW50ID0gZnVuY3Rpb24gKHJlY3RBLCByZWN0Qiwgb3ZlcmxhcEFtb3VudCwgc2VwYXJhdGlvbkJ1ZmZlcilcbntcbiAgaWYgKCFyZWN0QS5pbnRlcnNlY3RzKHJlY3RCKSkge1xuICAgIHRocm93IFwiYXNzZXJ0IGZhaWxlZFwiO1xuICB9XG4gIHZhciBkaXJlY3Rpb25zID0gbmV3IEFycmF5KDIpO1xuICBJR2VvbWV0cnkuZGVjaWRlRGlyZWN0aW9uc0Zvck92ZXJsYXBwaW5nTm9kZXMocmVjdEEsIHJlY3RCLCBkaXJlY3Rpb25zKTtcbiAgb3ZlcmxhcEFtb3VudFswXSA9IE1hdGgubWluKHJlY3RBLmdldFJpZ2h0KCksIHJlY3RCLmdldFJpZ2h0KCkpIC1cbiAgICAgICAgICBNYXRoLm1heChyZWN0QS54LCByZWN0Qi54KTtcbiAgb3ZlcmxhcEFtb3VudFsxXSA9IE1hdGgubWluKHJlY3RBLmdldEJvdHRvbSgpLCByZWN0Qi5nZXRCb3R0b20oKSkgLVxuICAgICAgICAgIE1hdGgubWF4KHJlY3RBLnksIHJlY3RCLnkpO1xuICAvLyB1cGRhdGUgdGhlIG92ZXJsYXBwaW5nIGFtb3VudHMgZm9yIHRoZSBmb2xsb3dpbmcgY2FzZXM6XG4gIGlmICgocmVjdEEuZ2V0WCgpIDw9IHJlY3RCLmdldFgoKSkgJiYgKHJlY3RBLmdldFJpZ2h0KCkgPj0gcmVjdEIuZ2V0UmlnaHQoKSkpXG4gIHtcbiAgICBvdmVybGFwQW1vdW50WzBdICs9IE1hdGgubWluKChyZWN0Qi5nZXRYKCkgLSByZWN0QS5nZXRYKCkpLFxuICAgICAgICAgICAgKHJlY3RBLmdldFJpZ2h0KCkgLSByZWN0Qi5nZXRSaWdodCgpKSk7XG4gIH1cbiAgZWxzZSBpZiAoKHJlY3RCLmdldFgoKSA8PSByZWN0QS5nZXRYKCkpICYmIChyZWN0Qi5nZXRSaWdodCgpID49IHJlY3RBLmdldFJpZ2h0KCkpKVxuICB7XG4gICAgb3ZlcmxhcEFtb3VudFswXSArPSBNYXRoLm1pbigocmVjdEEuZ2V0WCgpIC0gcmVjdEIuZ2V0WCgpKSxcbiAgICAgICAgICAgIChyZWN0Qi5nZXRSaWdodCgpIC0gcmVjdEEuZ2V0UmlnaHQoKSkpO1xuICB9XG4gIGlmICgocmVjdEEuZ2V0WSgpIDw9IHJlY3RCLmdldFkoKSkgJiYgKHJlY3RBLmdldEJvdHRvbSgpID49IHJlY3RCLmdldEJvdHRvbSgpKSlcbiAge1xuICAgIG92ZXJsYXBBbW91bnRbMV0gKz0gTWF0aC5taW4oKHJlY3RCLmdldFkoKSAtIHJlY3RBLmdldFkoKSksXG4gICAgICAgICAgICAocmVjdEEuZ2V0Qm90dG9tKCkgLSByZWN0Qi5nZXRCb3R0b20oKSkpO1xuICB9XG4gIGVsc2UgaWYgKChyZWN0Qi5nZXRZKCkgPD0gcmVjdEEuZ2V0WSgpKSAmJiAocmVjdEIuZ2V0Qm90dG9tKCkgPj0gcmVjdEEuZ2V0Qm90dG9tKCkpKVxuICB7XG4gICAgb3ZlcmxhcEFtb3VudFsxXSArPSBNYXRoLm1pbigocmVjdEEuZ2V0WSgpIC0gcmVjdEIuZ2V0WSgpKSxcbiAgICAgICAgICAgIChyZWN0Qi5nZXRCb3R0b20oKSAtIHJlY3RBLmdldEJvdHRvbSgpKSk7XG4gIH1cblxuICAvLyBmaW5kIHNsb3BlIG9mIHRoZSBsaW5lIHBhc3NlcyB0d28gY2VudGVyc1xuICB2YXIgc2xvcGUgPSBNYXRoLmFicygocmVjdEIuZ2V0Q2VudGVyWSgpIC0gcmVjdEEuZ2V0Q2VudGVyWSgpKSAvXG4gICAgICAgICAgKHJlY3RCLmdldENlbnRlclgoKSAtIHJlY3RBLmdldENlbnRlclgoKSkpO1xuICAvLyBpZiBjZW50ZXJzIGFyZSBvdmVybGFwcGVkXG4gIGlmICgocmVjdEIuZ2V0Q2VudGVyWSgpID09IHJlY3RBLmdldENlbnRlclkoKSkgJiZcbiAgICAgICAgICAocmVjdEIuZ2V0Q2VudGVyWCgpID09IHJlY3RBLmdldENlbnRlclgoKSkpXG4gIHtcbiAgICAvLyBhc3N1bWUgdGhlIHNsb3BlIGlzIDEgKDQ1IGRlZ3JlZSlcbiAgICBzbG9wZSA9IDEuMDtcbiAgfVxuXG4gIHZhciBtb3ZlQnlZID0gc2xvcGUgKiBvdmVybGFwQW1vdW50WzBdO1xuICB2YXIgbW92ZUJ5WCA9IG92ZXJsYXBBbW91bnRbMV0gLyBzbG9wZTtcbiAgaWYgKG92ZXJsYXBBbW91bnRbMF0gPCBtb3ZlQnlYKVxuICB7XG4gICAgbW92ZUJ5WCA9IG92ZXJsYXBBbW91bnRbMF07XG4gIH1cbiAgZWxzZVxuICB7XG4gICAgbW92ZUJ5WSA9IG92ZXJsYXBBbW91bnRbMV07XG4gIH1cbiAgLy8gcmV0dXJuIGhhbGYgdGhlIGFtb3VudCBzbyB0aGF0IGlmIGVhY2ggcmVjdGFuZ2xlIGlzIG1vdmVkIGJ5IHRoZXNlXG4gIC8vIGFtb3VudHMgaW4gb3Bwb3NpdGUgZGlyZWN0aW9ucywgb3ZlcmxhcCB3aWxsIGJlIHJlc29sdmVkXG4gIG92ZXJsYXBBbW91bnRbMF0gPSAtMSAqIGRpcmVjdGlvbnNbMF0gKiAoKG1vdmVCeVggLyAyKSArIHNlcGFyYXRpb25CdWZmZXIpO1xuICBvdmVybGFwQW1vdW50WzFdID0gLTEgKiBkaXJlY3Rpb25zWzFdICogKChtb3ZlQnlZIC8gMikgKyBzZXBhcmF0aW9uQnVmZmVyKTtcbn1cblxuSUdlb21ldHJ5LmRlY2lkZURpcmVjdGlvbnNGb3JPdmVybGFwcGluZ05vZGVzID0gZnVuY3Rpb24gKHJlY3RBLCByZWN0QiwgZGlyZWN0aW9ucylcbntcbiAgaWYgKHJlY3RBLmdldENlbnRlclgoKSA8IHJlY3RCLmdldENlbnRlclgoKSlcbiAge1xuICAgIGRpcmVjdGlvbnNbMF0gPSAtMTtcbiAgfVxuICBlbHNlXG4gIHtcbiAgICBkaXJlY3Rpb25zWzBdID0gMTtcbiAgfVxuXG4gIGlmIChyZWN0QS5nZXRDZW50ZXJZKCkgPCByZWN0Qi5nZXRDZW50ZXJZKCkpXG4gIHtcbiAgICBkaXJlY3Rpb25zWzFdID0gLTE7XG4gIH1cbiAgZWxzZVxuICB7XG4gICAgZGlyZWN0aW9uc1sxXSA9IDE7XG4gIH1cbn1cblxuSUdlb21ldHJ5LmdldEludGVyc2VjdGlvbjIgPSBmdW5jdGlvbiAocmVjdEEsIHJlY3RCLCByZXN1bHQpXG57XG4gIC8vcmVzdWx0WzAtMV0gd2lsbCBjb250YWluIGNsaXBQb2ludCBvZiByZWN0QSwgcmVzdWx0WzItM10gd2lsbCBjb250YWluIGNsaXBQb2ludCBvZiByZWN0QlxuICB2YXIgcDF4ID0gcmVjdEEuZ2V0Q2VudGVyWCgpO1xuICB2YXIgcDF5ID0gcmVjdEEuZ2V0Q2VudGVyWSgpO1xuICB2YXIgcDJ4ID0gcmVjdEIuZ2V0Q2VudGVyWCgpO1xuICB2YXIgcDJ5ID0gcmVjdEIuZ2V0Q2VudGVyWSgpO1xuXG4gIC8vaWYgdHdvIHJlY3RhbmdsZXMgaW50ZXJzZWN0LCB0aGVuIGNsaXBwaW5nIHBvaW50cyBhcmUgY2VudGVyc1xuICBpZiAocmVjdEEuaW50ZXJzZWN0cyhyZWN0QikpXG4gIHtcbiAgICByZXN1bHRbMF0gPSBwMXg7XG4gICAgcmVzdWx0WzFdID0gcDF5O1xuICAgIHJlc3VsdFsyXSA9IHAyeDtcbiAgICByZXN1bHRbM10gPSBwMnk7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cbiAgLy92YXJpYWJsZXMgZm9yIHJlY3RBXG4gIHZhciB0b3BMZWZ0QXggPSByZWN0QS5nZXRYKCk7XG4gIHZhciB0b3BMZWZ0QXkgPSByZWN0QS5nZXRZKCk7XG4gIHZhciB0b3BSaWdodEF4ID0gcmVjdEEuZ2V0UmlnaHQoKTtcbiAgdmFyIGJvdHRvbUxlZnRBeCA9IHJlY3RBLmdldFgoKTtcbiAgdmFyIGJvdHRvbUxlZnRBeSA9IHJlY3RBLmdldEJvdHRvbSgpO1xuICB2YXIgYm90dG9tUmlnaHRBeCA9IHJlY3RBLmdldFJpZ2h0KCk7XG4gIHZhciBoYWxmV2lkdGhBID0gcmVjdEEuZ2V0V2lkdGhIYWxmKCk7XG4gIHZhciBoYWxmSGVpZ2h0QSA9IHJlY3RBLmdldEhlaWdodEhhbGYoKTtcbiAgLy92YXJpYWJsZXMgZm9yIHJlY3RCXG4gIHZhciB0b3BMZWZ0QnggPSByZWN0Qi5nZXRYKCk7XG4gIHZhciB0b3BMZWZ0QnkgPSByZWN0Qi5nZXRZKCk7XG4gIHZhciB0b3BSaWdodEJ4ID0gcmVjdEIuZ2V0UmlnaHQoKTtcbiAgdmFyIGJvdHRvbUxlZnRCeCA9IHJlY3RCLmdldFgoKTtcbiAgdmFyIGJvdHRvbUxlZnRCeSA9IHJlY3RCLmdldEJvdHRvbSgpO1xuICB2YXIgYm90dG9tUmlnaHRCeCA9IHJlY3RCLmdldFJpZ2h0KCk7XG4gIHZhciBoYWxmV2lkdGhCID0gcmVjdEIuZ2V0V2lkdGhIYWxmKCk7XG4gIHZhciBoYWxmSGVpZ2h0QiA9IHJlY3RCLmdldEhlaWdodEhhbGYoKTtcbiAgLy9mbGFnIHdoZXRoZXIgY2xpcHBpbmcgcG9pbnRzIGFyZSBmb3VuZFxuICB2YXIgY2xpcFBvaW50QUZvdW5kID0gZmFsc2U7XG4gIHZhciBjbGlwUG9pbnRCRm91bmQgPSBmYWxzZTtcblxuICAvLyBsaW5lIGlzIHZlcnRpY2FsXG4gIGlmIChwMXggPT0gcDJ4KVxuICB7XG4gICAgaWYgKHAxeSA+IHAyeSlcbiAgICB7XG4gICAgICByZXN1bHRbMF0gPSBwMXg7XG4gICAgICByZXN1bHRbMV0gPSB0b3BMZWZ0QXk7XG4gICAgICByZXN1bHRbMl0gPSBwMng7XG4gICAgICByZXN1bHRbM10gPSBib3R0b21MZWZ0Qnk7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGVsc2UgaWYgKHAxeSA8IHAyeSlcbiAgICB7XG4gICAgICByZXN1bHRbMF0gPSBwMXg7XG4gICAgICByZXN1bHRbMV0gPSBib3R0b21MZWZ0QXk7XG4gICAgICByZXN1bHRbMl0gPSBwMng7XG4gICAgICByZXN1bHRbM10gPSB0b3BMZWZ0Qnk7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGVsc2VcbiAgICB7XG4gICAgICAvL25vdCBsaW5lLCByZXR1cm4gbnVsbDtcbiAgICB9XG4gIH1cbiAgLy8gbGluZSBpcyBob3Jpem9udGFsXG4gIGVsc2UgaWYgKHAxeSA9PSBwMnkpXG4gIHtcbiAgICBpZiAocDF4ID4gcDJ4KVxuICAgIHtcbiAgICAgIHJlc3VsdFswXSA9IHRvcExlZnRBeDtcbiAgICAgIHJlc3VsdFsxXSA9IHAxeTtcbiAgICAgIHJlc3VsdFsyXSA9IHRvcFJpZ2h0Qng7XG4gICAgICByZXN1bHRbM10gPSBwMnk7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGVsc2UgaWYgKHAxeCA8IHAyeClcbiAgICB7XG4gICAgICByZXN1bHRbMF0gPSB0b3BSaWdodEF4O1xuICAgICAgcmVzdWx0WzFdID0gcDF5O1xuICAgICAgcmVzdWx0WzJdID0gdG9wTGVmdEJ4O1xuICAgICAgcmVzdWx0WzNdID0gcDJ5O1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBlbHNlXG4gICAge1xuICAgICAgLy9ub3QgdmFsaWQgbGluZSwgcmV0dXJuIG51bGw7XG4gICAgfVxuICB9XG4gIGVsc2VcbiAge1xuICAgIC8vc2xvcGVzIG9mIHJlY3RBJ3MgYW5kIHJlY3RCJ3MgZGlhZ29uYWxzXG4gICAgdmFyIHNsb3BlQSA9IHJlY3RBLmhlaWdodCAvIHJlY3RBLndpZHRoO1xuICAgIHZhciBzbG9wZUIgPSByZWN0Qi5oZWlnaHQgLyByZWN0Qi53aWR0aDtcblxuICAgIC8vc2xvcGUgb2YgbGluZSBiZXR3ZWVuIGNlbnRlciBvZiByZWN0QSBhbmQgY2VudGVyIG9mIHJlY3RCXG4gICAgdmFyIHNsb3BlUHJpbWUgPSAocDJ5IC0gcDF5KSAvIChwMnggLSBwMXgpO1xuICAgIHZhciBjYXJkaW5hbERpcmVjdGlvbkE7XG4gICAgdmFyIGNhcmRpbmFsRGlyZWN0aW9uQjtcbiAgICB2YXIgdGVtcFBvaW50QXg7XG4gICAgdmFyIHRlbXBQb2ludEF5O1xuICAgIHZhciB0ZW1wUG9pbnRCeDtcbiAgICB2YXIgdGVtcFBvaW50Qnk7XG5cbiAgICAvL2RldGVybWluZSB3aGV0aGVyIGNsaXBwaW5nIHBvaW50IGlzIHRoZSBjb3JuZXIgb2Ygbm9kZUFcbiAgICBpZiAoKC1zbG9wZUEpID09IHNsb3BlUHJpbWUpXG4gICAge1xuICAgICAgaWYgKHAxeCA+IHAyeClcbiAgICAgIHtcbiAgICAgICAgcmVzdWx0WzBdID0gYm90dG9tTGVmdEF4O1xuICAgICAgICByZXN1bHRbMV0gPSBib3R0b21MZWZ0QXk7XG4gICAgICAgIGNsaXBQb2ludEFGb3VuZCA9IHRydWU7XG4gICAgICB9XG4gICAgICBlbHNlXG4gICAgICB7XG4gICAgICAgIHJlc3VsdFswXSA9IHRvcFJpZ2h0QXg7XG4gICAgICAgIHJlc3VsdFsxXSA9IHRvcExlZnRBeTtcbiAgICAgICAgY2xpcFBvaW50QUZvdW5kID0gdHJ1ZTtcbiAgICAgIH1cbiAgICB9XG4gICAgZWxzZSBpZiAoc2xvcGVBID09IHNsb3BlUHJpbWUpXG4gICAge1xuICAgICAgaWYgKHAxeCA+IHAyeClcbiAgICAgIHtcbiAgICAgICAgcmVzdWx0WzBdID0gdG9wTGVmdEF4O1xuICAgICAgICByZXN1bHRbMV0gPSB0b3BMZWZ0QXk7XG4gICAgICAgIGNsaXBQb2ludEFGb3VuZCA9IHRydWU7XG4gICAgICB9XG4gICAgICBlbHNlXG4gICAgICB7XG4gICAgICAgIHJlc3VsdFswXSA9IGJvdHRvbVJpZ2h0QXg7XG4gICAgICAgIHJlc3VsdFsxXSA9IGJvdHRvbUxlZnRBeTtcbiAgICAgICAgY2xpcFBvaW50QUZvdW5kID0gdHJ1ZTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvL2RldGVybWluZSB3aGV0aGVyIGNsaXBwaW5nIHBvaW50IGlzIHRoZSBjb3JuZXIgb2Ygbm9kZUJcbiAgICBpZiAoKC1zbG9wZUIpID09IHNsb3BlUHJpbWUpXG4gICAge1xuICAgICAgaWYgKHAyeCA+IHAxeClcbiAgICAgIHtcbiAgICAgICAgcmVzdWx0WzJdID0gYm90dG9tTGVmdEJ4O1xuICAgICAgICByZXN1bHRbM10gPSBib3R0b21MZWZ0Qnk7XG4gICAgICAgIGNsaXBQb2ludEJGb3VuZCA9IHRydWU7XG4gICAgICB9XG4gICAgICBlbHNlXG4gICAgICB7XG4gICAgICAgIHJlc3VsdFsyXSA9IHRvcFJpZ2h0Qng7XG4gICAgICAgIHJlc3VsdFszXSA9IHRvcExlZnRCeTtcbiAgICAgICAgY2xpcFBvaW50QkZvdW5kID0gdHJ1ZTtcbiAgICAgIH1cbiAgICB9XG4gICAgZWxzZSBpZiAoc2xvcGVCID09IHNsb3BlUHJpbWUpXG4gICAge1xuICAgICAgaWYgKHAyeCA+IHAxeClcbiAgICAgIHtcbiAgICAgICAgcmVzdWx0WzJdID0gdG9wTGVmdEJ4O1xuICAgICAgICByZXN1bHRbM10gPSB0b3BMZWZ0Qnk7XG4gICAgICAgIGNsaXBQb2ludEJGb3VuZCA9IHRydWU7XG4gICAgICB9XG4gICAgICBlbHNlXG4gICAgICB7XG4gICAgICAgIHJlc3VsdFsyXSA9IGJvdHRvbVJpZ2h0Qng7XG4gICAgICAgIHJlc3VsdFszXSA9IGJvdHRvbUxlZnRCeTtcbiAgICAgICAgY2xpcFBvaW50QkZvdW5kID0gdHJ1ZTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvL2lmIGJvdGggY2xpcHBpbmcgcG9pbnRzIGFyZSBjb3JuZXJzXG4gICAgaWYgKGNsaXBQb2ludEFGb3VuZCAmJiBjbGlwUG9pbnRCRm91bmQpXG4gICAge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIC8vZGV0ZXJtaW5lIENhcmRpbmFsIERpcmVjdGlvbiBvZiByZWN0YW5nbGVzXG4gICAgaWYgKHAxeCA+IHAyeClcbiAgICB7XG4gICAgICBpZiAocDF5ID4gcDJ5KVxuICAgICAge1xuICAgICAgICBjYXJkaW5hbERpcmVjdGlvbkEgPSBJR2VvbWV0cnkuZ2V0Q2FyZGluYWxEaXJlY3Rpb24oc2xvcGVBLCBzbG9wZVByaW1lLCA0KTtcbiAgICAgICAgY2FyZGluYWxEaXJlY3Rpb25CID0gSUdlb21ldHJ5LmdldENhcmRpbmFsRGlyZWN0aW9uKHNsb3BlQiwgc2xvcGVQcmltZSwgMik7XG4gICAgICB9XG4gICAgICBlbHNlXG4gICAgICB7XG4gICAgICAgIGNhcmRpbmFsRGlyZWN0aW9uQSA9IElHZW9tZXRyeS5nZXRDYXJkaW5hbERpcmVjdGlvbigtc2xvcGVBLCBzbG9wZVByaW1lLCAzKTtcbiAgICAgICAgY2FyZGluYWxEaXJlY3Rpb25CID0gSUdlb21ldHJ5LmdldENhcmRpbmFsRGlyZWN0aW9uKC1zbG9wZUIsIHNsb3BlUHJpbWUsIDEpO1xuICAgICAgfVxuICAgIH1cbiAgICBlbHNlXG4gICAge1xuICAgICAgaWYgKHAxeSA+IHAyeSlcbiAgICAgIHtcbiAgICAgICAgY2FyZGluYWxEaXJlY3Rpb25BID0gSUdlb21ldHJ5LmdldENhcmRpbmFsRGlyZWN0aW9uKC1zbG9wZUEsIHNsb3BlUHJpbWUsIDEpO1xuICAgICAgICBjYXJkaW5hbERpcmVjdGlvbkIgPSBJR2VvbWV0cnkuZ2V0Q2FyZGluYWxEaXJlY3Rpb24oLXNsb3BlQiwgc2xvcGVQcmltZSwgMyk7XG4gICAgICB9XG4gICAgICBlbHNlXG4gICAgICB7XG4gICAgICAgIGNhcmRpbmFsRGlyZWN0aW9uQSA9IElHZW9tZXRyeS5nZXRDYXJkaW5hbERpcmVjdGlvbihzbG9wZUEsIHNsb3BlUHJpbWUsIDIpO1xuICAgICAgICBjYXJkaW5hbERpcmVjdGlvbkIgPSBJR2VvbWV0cnkuZ2V0Q2FyZGluYWxEaXJlY3Rpb24oc2xvcGVCLCBzbG9wZVByaW1lLCA0KTtcbiAgICAgIH1cbiAgICB9XG4gICAgLy9jYWxjdWxhdGUgY2xpcHBpbmcgUG9pbnQgaWYgaXQgaXMgbm90IGZvdW5kIGJlZm9yZVxuICAgIGlmICghY2xpcFBvaW50QUZvdW5kKVxuICAgIHtcbiAgICAgIHN3aXRjaCAoY2FyZGluYWxEaXJlY3Rpb25BKVxuICAgICAge1xuICAgICAgICBjYXNlIDE6XG4gICAgICAgICAgdGVtcFBvaW50QXkgPSB0b3BMZWZ0QXk7XG4gICAgICAgICAgdGVtcFBvaW50QXggPSBwMXggKyAoLWhhbGZIZWlnaHRBKSAvIHNsb3BlUHJpbWU7XG4gICAgICAgICAgcmVzdWx0WzBdID0gdGVtcFBvaW50QXg7XG4gICAgICAgICAgcmVzdWx0WzFdID0gdGVtcFBvaW50QXk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgMjpcbiAgICAgICAgICB0ZW1wUG9pbnRBeCA9IGJvdHRvbVJpZ2h0QXg7XG4gICAgICAgICAgdGVtcFBvaW50QXkgPSBwMXkgKyBoYWxmV2lkdGhBICogc2xvcGVQcmltZTtcbiAgICAgICAgICByZXN1bHRbMF0gPSB0ZW1wUG9pbnRBeDtcbiAgICAgICAgICByZXN1bHRbMV0gPSB0ZW1wUG9pbnRBeTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSAzOlxuICAgICAgICAgIHRlbXBQb2ludEF5ID0gYm90dG9tTGVmdEF5O1xuICAgICAgICAgIHRlbXBQb2ludEF4ID0gcDF4ICsgaGFsZkhlaWdodEEgLyBzbG9wZVByaW1lO1xuICAgICAgICAgIHJlc3VsdFswXSA9IHRlbXBQb2ludEF4O1xuICAgICAgICAgIHJlc3VsdFsxXSA9IHRlbXBQb2ludEF5O1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlIDQ6XG4gICAgICAgICAgdGVtcFBvaW50QXggPSBib3R0b21MZWZ0QXg7XG4gICAgICAgICAgdGVtcFBvaW50QXkgPSBwMXkgKyAoLWhhbGZXaWR0aEEpICogc2xvcGVQcmltZTtcbiAgICAgICAgICByZXN1bHRbMF0gPSB0ZW1wUG9pbnRBeDtcbiAgICAgICAgICByZXN1bHRbMV0gPSB0ZW1wUG9pbnRBeTtcbiAgICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9XG4gICAgaWYgKCFjbGlwUG9pbnRCRm91bmQpXG4gICAge1xuICAgICAgc3dpdGNoIChjYXJkaW5hbERpcmVjdGlvbkIpXG4gICAgICB7XG4gICAgICAgIGNhc2UgMTpcbiAgICAgICAgICB0ZW1wUG9pbnRCeSA9IHRvcExlZnRCeTtcbiAgICAgICAgICB0ZW1wUG9pbnRCeCA9IHAyeCArICgtaGFsZkhlaWdodEIpIC8gc2xvcGVQcmltZTtcbiAgICAgICAgICByZXN1bHRbMl0gPSB0ZW1wUG9pbnRCeDtcbiAgICAgICAgICByZXN1bHRbM10gPSB0ZW1wUG9pbnRCeTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSAyOlxuICAgICAgICAgIHRlbXBQb2ludEJ4ID0gYm90dG9tUmlnaHRCeDtcbiAgICAgICAgICB0ZW1wUG9pbnRCeSA9IHAyeSArIGhhbGZXaWR0aEIgKiBzbG9wZVByaW1lO1xuICAgICAgICAgIHJlc3VsdFsyXSA9IHRlbXBQb2ludEJ4O1xuICAgICAgICAgIHJlc3VsdFszXSA9IHRlbXBQb2ludEJ5O1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlIDM6XG4gICAgICAgICAgdGVtcFBvaW50QnkgPSBib3R0b21MZWZ0Qnk7XG4gICAgICAgICAgdGVtcFBvaW50QnggPSBwMnggKyBoYWxmSGVpZ2h0QiAvIHNsb3BlUHJpbWU7XG4gICAgICAgICAgcmVzdWx0WzJdID0gdGVtcFBvaW50Qng7XG4gICAgICAgICAgcmVzdWx0WzNdID0gdGVtcFBvaW50Qnk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgNDpcbiAgICAgICAgICB0ZW1wUG9pbnRCeCA9IGJvdHRvbUxlZnRCeDtcbiAgICAgICAgICB0ZW1wUG9pbnRCeSA9IHAyeSArICgtaGFsZldpZHRoQikgKiBzbG9wZVByaW1lO1xuICAgICAgICAgIHJlc3VsdFsyXSA9IHRlbXBQb2ludEJ4O1xuICAgICAgICAgIHJlc3VsdFszXSA9IHRlbXBQb2ludEJ5O1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cbiAgfVxuICByZXR1cm4gZmFsc2U7XG59XG5cbklHZW9tZXRyeS5nZXRDYXJkaW5hbERpcmVjdGlvbiA9IGZ1bmN0aW9uIChzbG9wZSwgc2xvcGVQcmltZSwgbGluZSlcbntcbiAgaWYgKHNsb3BlID4gc2xvcGVQcmltZSlcbiAge1xuICAgIHJldHVybiBsaW5lO1xuICB9XG4gIGVsc2VcbiAge1xuICAgIHJldHVybiAxICsgbGluZSAlIDQ7XG4gIH1cbn1cblxuSUdlb21ldHJ5LmdldEludGVyc2VjdGlvbiA9IGZ1bmN0aW9uIChzMSwgczIsIGYxLCBmMilcbntcbiAgaWYgKGYyID09IG51bGwpIHtcbiAgICByZXR1cm4gSUdlb21ldHJ5LmdldEludGVyc2VjdGlvbjIoczEsIHMyLCBmMSk7XG4gIH1cbiAgdmFyIHgxID0gczEueDtcbiAgdmFyIHkxID0gczEueTtcbiAgdmFyIHgyID0gczIueDtcbiAgdmFyIHkyID0gczIueTtcbiAgdmFyIHgzID0gZjEueDtcbiAgdmFyIHkzID0gZjEueTtcbiAgdmFyIHg0ID0gZjIueDtcbiAgdmFyIHk0ID0gZjIueTtcbiAgdmFyIHgsIHk7IC8vIGludGVyc2VjdGlvbiBwb2ludFxuICB2YXIgYTEsIGEyLCBiMSwgYjIsIGMxLCBjMjsgLy8gY29lZmZpY2llbnRzIG9mIGxpbmUgZXFucy5cbiAgdmFyIGRlbm9tO1xuXG4gIGExID0geTIgLSB5MTtcbiAgYjEgPSB4MSAtIHgyO1xuICBjMSA9IHgyICogeTEgLSB4MSAqIHkyOyAgLy8geyBhMSp4ICsgYjEqeSArIGMxID0gMCBpcyBsaW5lIDEgfVxuXG4gIGEyID0geTQgLSB5MztcbiAgYjIgPSB4MyAtIHg0O1xuICBjMiA9IHg0ICogeTMgLSB4MyAqIHk0OyAgLy8geyBhMip4ICsgYjIqeSArIGMyID0gMCBpcyBsaW5lIDIgfVxuXG4gIGRlbm9tID0gYTEgKiBiMiAtIGEyICogYjE7XG5cbiAgaWYgKGRlbm9tID09IDApXG4gIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIHggPSAoYjEgKiBjMiAtIGIyICogYzEpIC8gZGVub207XG4gIHkgPSAoYTIgKiBjMSAtIGExICogYzIpIC8gZGVub207XG5cbiAgcmV0dXJuIG5ldyBQb2ludCh4LCB5KTtcbn1cblxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIFNlY3Rpb246IENsYXNzIENvbnN0YW50c1xuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8qKlxuICogU29tZSB1c2VmdWwgcHJlLWNhbGN1bGF0ZWQgY29uc3RhbnRzXG4gKi9cbklHZW9tZXRyeS5IQUxGX1BJID0gMC41ICogTWF0aC5QSTtcbklHZW9tZXRyeS5PTkVfQU5EX0hBTEZfUEkgPSAxLjUgKiBNYXRoLlBJO1xuSUdlb21ldHJ5LlRXT19QSSA9IDIuMCAqIE1hdGguUEk7XG5JR2VvbWV0cnkuVEhSRUVfUEkgPSAzLjAgKiBNYXRoLlBJO1xuXG5tb2R1bGUuZXhwb3J0cyA9IElHZW9tZXRyeTtcbiIsImZ1bmN0aW9uIElNYXRoKCkge1xufVxuXG4vKipcbiAqIFRoaXMgbWV0aG9kIHJldHVybnMgdGhlIHNpZ24gb2YgdGhlIGlucHV0IHZhbHVlLlxuICovXG5JTWF0aC5zaWduID0gZnVuY3Rpb24gKHZhbHVlKSB7XG4gIGlmICh2YWx1ZSA+IDApXG4gIHtcbiAgICByZXR1cm4gMTtcbiAgfVxuICBlbHNlIGlmICh2YWx1ZSA8IDApXG4gIHtcbiAgICByZXR1cm4gLTE7XG4gIH1cbiAgZWxzZVxuICB7XG4gICAgcmV0dXJuIDA7XG4gIH1cbn1cblxuSU1hdGguZmxvb3IgPSBmdW5jdGlvbiAodmFsdWUpIHtcbiAgcmV0dXJuIHZhbHVlIDwgMCA/IE1hdGguY2VpbCh2YWx1ZSkgOiBNYXRoLmZsb29yKHZhbHVlKTtcbn1cblxuSU1hdGguY2VpbCA9IGZ1bmN0aW9uICh2YWx1ZSkge1xuICByZXR1cm4gdmFsdWUgPCAwID8gTWF0aC5mbG9vcih2YWx1ZSkgOiBNYXRoLmNlaWwodmFsdWUpO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IElNYXRoO1xuIiwiZnVuY3Rpb24gSW50ZWdlcigpIHtcbn1cblxuSW50ZWdlci5NQVhfVkFMVUUgPSAyMTQ3NDgzNjQ3O1xuSW50ZWdlci5NSU5fVkFMVUUgPSAtMjE0NzQ4MzY0ODtcblxubW9kdWxlLmV4cG9ydHMgPSBJbnRlZ2VyO1xuIiwidmFyIExHcmFwaE9iamVjdCA9IHJlcXVpcmUoJy4vTEdyYXBoT2JqZWN0Jyk7XG52YXIgSUdlb21ldHJ5ID0gcmVxdWlyZSgnLi9JR2VvbWV0cnknKTtcbnZhciBJTWF0aCA9IHJlcXVpcmUoJy4vSU1hdGgnKTtcblxuZnVuY3Rpb24gTEVkZ2Uoc291cmNlLCB0YXJnZXQsIHZFZGdlKSB7XG4gIExHcmFwaE9iamVjdC5jYWxsKHRoaXMsIHZFZGdlKTtcblxuICB0aGlzLmlzT3ZlcmxhcGluZ1NvdXJjZUFuZFRhcmdldCA9IGZhbHNlO1xuICB0aGlzLnZHcmFwaE9iamVjdCA9IHZFZGdlO1xuICB0aGlzLmJlbmRwb2ludHMgPSBbXTtcbiAgdGhpcy5zb3VyY2UgPSBzb3VyY2U7XG4gIHRoaXMudGFyZ2V0ID0gdGFyZ2V0O1xufVxuXG5MRWRnZS5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKExHcmFwaE9iamVjdC5wcm90b3R5cGUpO1xuXG5mb3IgKHZhciBwcm9wIGluIExHcmFwaE9iamVjdCkge1xuICBMRWRnZVtwcm9wXSA9IExHcmFwaE9iamVjdFtwcm9wXTtcbn1cblxuTEVkZ2UucHJvdG90eXBlLmdldFNvdXJjZSA9IGZ1bmN0aW9uICgpXG57XG4gIHJldHVybiB0aGlzLnNvdXJjZTtcbn07XG5cbkxFZGdlLnByb3RvdHlwZS5nZXRUYXJnZXQgPSBmdW5jdGlvbiAoKVxue1xuICByZXR1cm4gdGhpcy50YXJnZXQ7XG59O1xuXG5MRWRnZS5wcm90b3R5cGUuaXNJbnRlckdyYXBoID0gZnVuY3Rpb24gKClcbntcbiAgcmV0dXJuIHRoaXMuaXNJbnRlckdyYXBoO1xufTtcblxuTEVkZ2UucHJvdG90eXBlLmdldExlbmd0aCA9IGZ1bmN0aW9uICgpXG57XG4gIHJldHVybiB0aGlzLmxlbmd0aDtcbn07XG5cbkxFZGdlLnByb3RvdHlwZS5pc092ZXJsYXBpbmdTb3VyY2VBbmRUYXJnZXQgPSBmdW5jdGlvbiAoKVxue1xuICByZXR1cm4gdGhpcy5pc092ZXJsYXBpbmdTb3VyY2VBbmRUYXJnZXQ7XG59O1xuXG5MRWRnZS5wcm90b3R5cGUuZ2V0QmVuZHBvaW50cyA9IGZ1bmN0aW9uICgpXG57XG4gIHJldHVybiB0aGlzLmJlbmRwb2ludHM7XG59O1xuXG5MRWRnZS5wcm90b3R5cGUuZ2V0TGNhID0gZnVuY3Rpb24gKClcbntcbiAgcmV0dXJuIHRoaXMubGNhO1xufTtcblxuTEVkZ2UucHJvdG90eXBlLmdldFNvdXJjZUluTGNhID0gZnVuY3Rpb24gKClcbntcbiAgcmV0dXJuIHRoaXMuc291cmNlSW5MY2E7XG59O1xuXG5MRWRnZS5wcm90b3R5cGUuZ2V0VGFyZ2V0SW5MY2EgPSBmdW5jdGlvbiAoKVxue1xuICByZXR1cm4gdGhpcy50YXJnZXRJbkxjYTtcbn07XG5cbkxFZGdlLnByb3RvdHlwZS5nZXRPdGhlckVuZCA9IGZ1bmN0aW9uIChub2RlKVxue1xuICBpZiAodGhpcy5zb3VyY2UgPT09IG5vZGUpXG4gIHtcbiAgICByZXR1cm4gdGhpcy50YXJnZXQ7XG4gIH1cbiAgZWxzZSBpZiAodGhpcy50YXJnZXQgPT09IG5vZGUpXG4gIHtcbiAgICByZXR1cm4gdGhpcy5zb3VyY2U7XG4gIH1cbiAgZWxzZVxuICB7XG4gICAgdGhyb3cgXCJOb2RlIGlzIG5vdCBpbmNpZGVudCB3aXRoIHRoaXMgZWRnZVwiO1xuICB9XG59XG5cbkxFZGdlLnByb3RvdHlwZS5nZXRPdGhlckVuZEluR3JhcGggPSBmdW5jdGlvbiAobm9kZSwgZ3JhcGgpXG57XG4gIHZhciBvdGhlckVuZCA9IHRoaXMuZ2V0T3RoZXJFbmQobm9kZSk7XG4gIHZhciByb290ID0gZ3JhcGguZ2V0R3JhcGhNYW5hZ2VyKCkuZ2V0Um9vdCgpO1xuXG4gIHdoaWxlICh0cnVlKVxuICB7XG4gICAgaWYgKG90aGVyRW5kLmdldE93bmVyKCkgPT0gZ3JhcGgpXG4gICAge1xuICAgICAgcmV0dXJuIG90aGVyRW5kO1xuICAgIH1cblxuICAgIGlmIChvdGhlckVuZC5nZXRPd25lcigpID09IHJvb3QpXG4gICAge1xuICAgICAgYnJlYWs7XG4gICAgfVxuXG4gICAgb3RoZXJFbmQgPSBvdGhlckVuZC5nZXRPd25lcigpLmdldFBhcmVudCgpO1xuICB9XG5cbiAgcmV0dXJuIG51bGw7XG59O1xuXG5MRWRnZS5wcm90b3R5cGUudXBkYXRlTGVuZ3RoID0gZnVuY3Rpb24gKClcbntcbiAgdmFyIGNsaXBQb2ludENvb3JkaW5hdGVzID0gbmV3IEFycmF5KDQpO1xuXG4gIHRoaXMuaXNPdmVybGFwaW5nU291cmNlQW5kVGFyZ2V0ID1cbiAgICAgICAgICBJR2VvbWV0cnkuZ2V0SW50ZXJzZWN0aW9uKHRoaXMudGFyZ2V0LmdldFJlY3QoKSxcbiAgICAgICAgICAgICAgICAgIHRoaXMuc291cmNlLmdldFJlY3QoKSxcbiAgICAgICAgICAgICAgICAgIGNsaXBQb2ludENvb3JkaW5hdGVzKTtcblxuICBpZiAoIXRoaXMuaXNPdmVybGFwaW5nU291cmNlQW5kVGFyZ2V0KVxuICB7XG4gICAgdGhpcy5sZW5ndGhYID0gY2xpcFBvaW50Q29vcmRpbmF0ZXNbMF0gLSBjbGlwUG9pbnRDb29yZGluYXRlc1syXTtcbiAgICB0aGlzLmxlbmd0aFkgPSBjbGlwUG9pbnRDb29yZGluYXRlc1sxXSAtIGNsaXBQb2ludENvb3JkaW5hdGVzWzNdO1xuXG4gICAgaWYgKE1hdGguYWJzKHRoaXMubGVuZ3RoWCkgPCAxLjApXG4gICAge1xuICAgICAgdGhpcy5sZW5ndGhYID0gSU1hdGguc2lnbih0aGlzLmxlbmd0aFgpO1xuICAgIH1cblxuICAgIGlmIChNYXRoLmFicyh0aGlzLmxlbmd0aFkpIDwgMS4wKVxuICAgIHtcbiAgICAgIHRoaXMubGVuZ3RoWSA9IElNYXRoLnNpZ24odGhpcy5sZW5ndGhZKTtcbiAgICB9XG5cbiAgICB0aGlzLmxlbmd0aCA9IE1hdGguc3FydChcbiAgICAgICAgICAgIHRoaXMubGVuZ3RoWCAqIHRoaXMubGVuZ3RoWCArIHRoaXMubGVuZ3RoWSAqIHRoaXMubGVuZ3RoWSk7XG4gIH1cbn07XG5cbkxFZGdlLnByb3RvdHlwZS51cGRhdGVMZW5ndGhTaW1wbGUgPSBmdW5jdGlvbiAoKVxue1xuICB0aGlzLmxlbmd0aFggPSB0aGlzLnRhcmdldC5nZXRDZW50ZXJYKCkgLSB0aGlzLnNvdXJjZS5nZXRDZW50ZXJYKCk7XG4gIHRoaXMubGVuZ3RoWSA9IHRoaXMudGFyZ2V0LmdldENlbnRlclkoKSAtIHRoaXMuc291cmNlLmdldENlbnRlclkoKTtcblxuICBpZiAoTWF0aC5hYnModGhpcy5sZW5ndGhYKSA8IDEuMClcbiAge1xuICAgIHRoaXMubGVuZ3RoWCA9IElNYXRoLnNpZ24odGhpcy5sZW5ndGhYKTtcbiAgfVxuXG4gIGlmIChNYXRoLmFicyh0aGlzLmxlbmd0aFkpIDwgMS4wKVxuICB7XG4gICAgdGhpcy5sZW5ndGhZID0gSU1hdGguc2lnbih0aGlzLmxlbmd0aFkpO1xuICB9XG5cbiAgdGhpcy5sZW5ndGggPSBNYXRoLnNxcnQoXG4gICAgICAgICAgdGhpcy5sZW5ndGhYICogdGhpcy5sZW5ndGhYICsgdGhpcy5sZW5ndGhZICogdGhpcy5sZW5ndGhZKTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBMRWRnZTtcbiIsInZhciBMR3JhcGhPYmplY3QgPSByZXF1aXJlKCcuL0xHcmFwaE9iamVjdCcpO1xudmFyIEludGVnZXIgPSByZXF1aXJlKCcuL0ludGVnZXInKTtcbnZhciBMYXlvdXRDb25zdGFudHMgPSByZXF1aXJlKCcuL0xheW91dENvbnN0YW50cycpO1xudmFyIExHcmFwaE1hbmFnZXIgPSByZXF1aXJlKCcuL0xHcmFwaE1hbmFnZXInKTtcbnZhciBMTm9kZSA9IHJlcXVpcmUoJy4vTE5vZGUnKTtcbnZhciBMRWRnZSA9IHJlcXVpcmUoJy4vTEVkZ2UnKTtcbnZhciBIYXNoU2V0ID0gcmVxdWlyZSgnLi9IYXNoU2V0Jyk7XG52YXIgUmVjdGFuZ2xlRCA9IHJlcXVpcmUoJy4vUmVjdGFuZ2xlRCcpO1xudmFyIFBvaW50ID0gcmVxdWlyZSgnLi9Qb2ludCcpO1xudmFyIExpc3QgPSByZXF1aXJlKCdsaW5rZWRsaXN0LWpzJykuTGlzdDtcblxuZnVuY3Rpb24gTEdyYXBoKHBhcmVudCwgb2JqMiwgdkdyYXBoKSB7XG4gIExHcmFwaE9iamVjdC5jYWxsKHRoaXMsIHZHcmFwaCk7XG4gIHRoaXMuZXN0aW1hdGVkU2l6ZSA9IEludGVnZXIuTUlOX1ZBTFVFO1xuICB0aGlzLm1hcmdpbiA9IExheW91dENvbnN0YW50cy5ERUZBVUxUX0dSQVBIX01BUkdJTjtcbiAgdGhpcy5lZGdlcyA9IFtdO1xuICB0aGlzLm5vZGVzID0gW107XG4gIHRoaXMuaXNDb25uZWN0ZWQgPSBmYWxzZTtcbiAgdGhpcy5wYXJlbnQgPSBwYXJlbnQ7XG5cbiAgaWYgKG9iajIgIT0gbnVsbCAmJiBvYmoyIGluc3RhbmNlb2YgTEdyYXBoTWFuYWdlcikge1xuICAgIHRoaXMuZ3JhcGhNYW5hZ2VyID0gb2JqMjtcbiAgfVxuICBlbHNlIGlmIChvYmoyICE9IG51bGwgJiYgb2JqMiBpbnN0YW5jZW9mIExheW91dCkge1xuICAgIHRoaXMuZ3JhcGhNYW5hZ2VyID0gb2JqMi5ncmFwaE1hbmFnZXI7XG4gIH1cbn1cblxuTEdyYXBoLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoTEdyYXBoT2JqZWN0LnByb3RvdHlwZSk7XG5mb3IgKHZhciBwcm9wIGluIExHcmFwaE9iamVjdCkge1xuICBMR3JhcGhbcHJvcF0gPSBMR3JhcGhPYmplY3RbcHJvcF07XG59XG5cbkxHcmFwaC5wcm90b3R5cGUuZ2V0Tm9kZXMgPSBmdW5jdGlvbiAoKSB7XG4gIHJldHVybiB0aGlzLm5vZGVzO1xufTtcblxuTEdyYXBoLnByb3RvdHlwZS5nZXRFZGdlcyA9IGZ1bmN0aW9uICgpIHtcbiAgcmV0dXJuIHRoaXMuZWRnZXM7XG59O1xuXG5MR3JhcGgucHJvdG90eXBlLmdldEdyYXBoTWFuYWdlciA9IGZ1bmN0aW9uICgpXG57XG4gIHJldHVybiB0aGlzLmdyYXBoTWFuYWdlcjtcbn07XG5cbkxHcmFwaC5wcm90b3R5cGUuZ2V0UGFyZW50ID0gZnVuY3Rpb24gKClcbntcbiAgcmV0dXJuIHRoaXMucGFyZW50O1xufTtcblxuTEdyYXBoLnByb3RvdHlwZS5nZXRMZWZ0ID0gZnVuY3Rpb24gKClcbntcbiAgcmV0dXJuIHRoaXMubGVmdDtcbn07XG5cbkxHcmFwaC5wcm90b3R5cGUuZ2V0UmlnaHQgPSBmdW5jdGlvbiAoKVxue1xuICByZXR1cm4gdGhpcy5yaWdodDtcbn07XG5cbkxHcmFwaC5wcm90b3R5cGUuZ2V0VG9wID0gZnVuY3Rpb24gKClcbntcbiAgcmV0dXJuIHRoaXMudG9wO1xufTtcblxuTEdyYXBoLnByb3RvdHlwZS5nZXRCb3R0b20gPSBmdW5jdGlvbiAoKVxue1xuICByZXR1cm4gdGhpcy5ib3R0b207XG59O1xuXG5MR3JhcGgucHJvdG90eXBlLmlzQ29ubmVjdGVkID0gZnVuY3Rpb24gKClcbntcbiAgcmV0dXJuIHRoaXMuaXNDb25uZWN0ZWQ7XG59O1xuXG5MR3JhcGgucHJvdG90eXBlLmFkZCA9IGZ1bmN0aW9uIChvYmoxLCBzb3VyY2VOb2RlLCB0YXJnZXROb2RlKSB7XG4gIGlmIChzb3VyY2VOb2RlID09IG51bGwgJiYgdGFyZ2V0Tm9kZSA9PSBudWxsKSB7XG4gICAgdmFyIG5ld05vZGUgPSBvYmoxO1xuICAgIGlmICh0aGlzLmdyYXBoTWFuYWdlciA9PSBudWxsKSB7XG4gICAgICB0aHJvdyBcIkdyYXBoIGhhcyBubyBncmFwaCBtZ3IhXCI7XG4gICAgfVxuICAgIGlmICh0aGlzLmdldE5vZGVzKCkuaW5kZXhPZihuZXdOb2RlKSA+IC0xKSB7XG4gICAgICB0aHJvdyBcIk5vZGUgYWxyZWFkeSBpbiBncmFwaCFcIjtcbiAgICB9XG4gICAgbmV3Tm9kZS5vd25lciA9IHRoaXM7XG4gICAgdGhpcy5nZXROb2RlcygpLnB1c2gobmV3Tm9kZSk7XG5cbiAgICByZXR1cm4gbmV3Tm9kZTtcbiAgfVxuICBlbHNlIHtcbiAgICB2YXIgbmV3RWRnZSA9IG9iajE7XG4gICAgaWYgKCEodGhpcy5nZXROb2RlcygpLmluZGV4T2Yoc291cmNlTm9kZSkgPiAtMSAmJiAodGhpcy5nZXROb2RlcygpLmluZGV4T2YodGFyZ2V0Tm9kZSkpID4gLTEpKSB7XG4gICAgICB0aHJvdyBcIlNvdXJjZSBvciB0YXJnZXQgbm90IGluIGdyYXBoIVwiO1xuICAgIH1cblxuICAgIGlmICghKHNvdXJjZU5vZGUub3duZXIgPT0gdGFyZ2V0Tm9kZS5vd25lciAmJiBzb3VyY2VOb2RlLm93bmVyID09IHRoaXMpKSB7XG4gICAgICB0aHJvdyBcIkJvdGggb3duZXJzIG11c3QgYmUgdGhpcyBncmFwaCFcIjtcbiAgICB9XG5cbiAgICBpZiAoc291cmNlTm9kZS5vd25lciAhPSB0YXJnZXROb2RlLm93bmVyKVxuICAgIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIC8vIHNldCBzb3VyY2UgYW5kIHRhcmdldFxuICAgIG5ld0VkZ2Uuc291cmNlID0gc291cmNlTm9kZTtcbiAgICBuZXdFZGdlLnRhcmdldCA9IHRhcmdldE5vZGU7XG5cbiAgICAvLyBzZXQgYXMgaW50cmEtZ3JhcGggZWRnZVxuICAgIG5ld0VkZ2UuaXNJbnRlckdyYXBoID0gZmFsc2U7XG5cbiAgICAvLyBhZGQgdG8gZ3JhcGggZWRnZSBsaXN0XG4gICAgdGhpcy5nZXRFZGdlcygpLnB1c2gobmV3RWRnZSk7XG5cbiAgICAvLyBhZGQgdG8gaW5jaWRlbmN5IGxpc3RzXG4gICAgc291cmNlTm9kZS5lZGdlcy5wdXNoKG5ld0VkZ2UpO1xuXG4gICAgaWYgKHRhcmdldE5vZGUgIT0gc291cmNlTm9kZSlcbiAgICB7XG4gICAgICB0YXJnZXROb2RlLmVkZ2VzLnB1c2gobmV3RWRnZSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIG5ld0VkZ2U7XG4gIH1cbn07XG5cbkxHcmFwaC5wcm90b3R5cGUucmVtb3ZlID0gZnVuY3Rpb24gKG9iaikge1xuICB2YXIgbm9kZSA9IG9iajtcbiAgaWYgKG9iaiBpbnN0YW5jZW9mIExOb2RlKSB7XG4gICAgaWYgKG5vZGUgPT0gbnVsbCkge1xuICAgICAgdGhyb3cgXCJOb2RlIGlzIG51bGwhXCI7XG4gICAgfVxuICAgIGlmICghKG5vZGUub3duZXIgIT0gbnVsbCAmJiBub2RlLm93bmVyID09IHRoaXMpKSB7XG4gICAgICB0aHJvdyBcIk93bmVyIGdyYXBoIGlzIGludmFsaWQhXCI7XG4gICAgfVxuICAgIGlmICh0aGlzLmdyYXBoTWFuYWdlciA9PSBudWxsKSB7XG4gICAgICB0aHJvdyBcIk93bmVyIGdyYXBoIG1hbmFnZXIgaXMgaW52YWxpZCFcIjtcbiAgICB9XG4gICAgLy8gcmVtb3ZlIGluY2lkZW50IGVkZ2VzIGZpcnN0IChtYWtlIGEgY29weSB0byBkbyBpdCBzYWZlbHkpXG4gICAgdmFyIGVkZ2VzVG9CZVJlbW92ZWQgPSBub2RlLmVkZ2VzLnNsaWNlKCk7XG4gICAgdmFyIGVkZ2U7XG4gICAgdmFyIHMgPSBlZGdlc1RvQmVSZW1vdmVkLmxlbmd0aDtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHM7IGkrKylcbiAgICB7XG4gICAgICBlZGdlID0gZWRnZXNUb0JlUmVtb3ZlZFtpXTtcblxuICAgICAgaWYgKGVkZ2UuaXNJbnRlckdyYXBoKVxuICAgICAge1xuICAgICAgICB0aGlzLmdyYXBoTWFuYWdlci5yZW1vdmUoZWRnZSk7XG4gICAgICB9XG4gICAgICBlbHNlXG4gICAgICB7XG4gICAgICAgIGVkZ2Uuc291cmNlLm93bmVyLnJlbW92ZShlZGdlKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBub3cgdGhlIG5vZGUgaXRzZWxmXG4gICAgdmFyIGluZGV4ID0gdGhpcy5ub2Rlcy5pbmRleE9mKG5vZGUpO1xuICAgIGlmIChpbmRleCA9PSAtMSkge1xuICAgICAgdGhyb3cgXCJOb2RlIG5vdCBpbiBvd25lciBub2RlIGxpc3QhXCI7XG4gICAgfVxuXG4gICAgdGhpcy5ub2Rlcy5zcGxpY2UoaW5kZXgsIDEpO1xuICB9XG4gIGVsc2UgaWYgKG9iaiBpbnN0YW5jZW9mIExFZGdlKSB7XG4gICAgdmFyIGVkZ2UgPSBvYmo7XG4gICAgaWYgKGVkZ2UgPT0gbnVsbCkge1xuICAgICAgdGhyb3cgXCJFZGdlIGlzIG51bGwhXCI7XG4gICAgfVxuICAgIGlmICghKGVkZ2Uuc291cmNlICE9IG51bGwgJiYgZWRnZS50YXJnZXQgIT0gbnVsbCkpIHtcbiAgICAgIHRocm93IFwiU291cmNlIGFuZC9vciB0YXJnZXQgaXMgbnVsbCFcIjtcbiAgICB9XG4gICAgaWYgKCEoZWRnZS5zb3VyY2Uub3duZXIgIT0gbnVsbCAmJiBlZGdlLnRhcmdldC5vd25lciAhPSBudWxsICYmXG4gICAgICAgICAgICBlZGdlLnNvdXJjZS5vd25lciA9PSB0aGlzICYmIGVkZ2UudGFyZ2V0Lm93bmVyID09IHRoaXMpKSB7XG4gICAgICB0aHJvdyBcIlNvdXJjZSBhbmQvb3IgdGFyZ2V0IG93bmVyIGlzIGludmFsaWQhXCI7XG4gICAgfVxuXG4gICAgdmFyIHNvdXJjZUluZGV4ID0gZWRnZS5zb3VyY2UuZWRnZXMuaW5kZXhPZihlZGdlKTtcbiAgICB2YXIgdGFyZ2V0SW5kZXggPSBlZGdlLnRhcmdldC5lZGdlcy5pbmRleE9mKGVkZ2UpO1xuICAgIGlmICghKHNvdXJjZUluZGV4ID4gLTEgJiYgdGFyZ2V0SW5kZXggPiAtMSkpIHtcbiAgICAgIHRocm93IFwiU291cmNlIGFuZC9vciB0YXJnZXQgZG9lc24ndCBrbm93IHRoaXMgZWRnZSFcIjtcbiAgICB9XG5cbiAgICBlZGdlLnNvdXJjZS5lZGdlcy5zcGxpY2Uoc291cmNlSW5kZXgsIDEpO1xuXG4gICAgaWYgKGVkZ2UudGFyZ2V0ICE9IGVkZ2Uuc291cmNlKVxuICAgIHtcbiAgICAgIGVkZ2UudGFyZ2V0LmVkZ2VzLnNwbGljZSh0YXJnZXRJbmRleCwgMSk7XG4gICAgfVxuXG4gICAgdmFyIGluZGV4ID0gZWRnZS5zb3VyY2Uub3duZXIuZ2V0RWRnZXMoKS5pbmRleE9mKGVkZ2UpO1xuICAgIGlmIChpbmRleCA9PSAtMSkge1xuICAgICAgdGhyb3cgXCJOb3QgaW4gb3duZXIncyBlZGdlIGxpc3QhXCI7XG4gICAgfVxuXG4gICAgZWRnZS5zb3VyY2Uub3duZXIuZ2V0RWRnZXMoKS5zcGxpY2UoaW5kZXgsIDEpO1xuICB9XG59O1xuXG5MR3JhcGgucHJvdG90eXBlLnVwZGF0ZUxlZnRUb3AgPSBmdW5jdGlvbiAoKVxue1xuICB2YXIgdG9wID0gSW50ZWdlci5NQVhfVkFMVUU7XG4gIHZhciBsZWZ0ID0gSW50ZWdlci5NQVhfVkFMVUU7XG4gIHZhciBub2RlVG9wO1xuICB2YXIgbm9kZUxlZnQ7XG4gIHZhciBtYXJnaW47XG5cbiAgdmFyIG5vZGVzID0gdGhpcy5nZXROb2RlcygpO1xuICB2YXIgcyA9IG5vZGVzLmxlbmd0aDtcblxuICBmb3IgKHZhciBpID0gMDsgaSA8IHM7IGkrKylcbiAge1xuICAgIHZhciBsTm9kZSA9IG5vZGVzW2ldO1xuICAgIG5vZGVUb3AgPSBsTm9kZS5nZXRUb3AoKTtcbiAgICBub2RlTGVmdCA9IGxOb2RlLmdldExlZnQoKTtcblxuICAgIGlmICh0b3AgPiBub2RlVG9wKVxuICAgIHtcbiAgICAgIHRvcCA9IG5vZGVUb3A7XG4gICAgfVxuXG4gICAgaWYgKGxlZnQgPiBub2RlTGVmdClcbiAgICB7XG4gICAgICBsZWZ0ID0gbm9kZUxlZnQ7XG4gICAgfVxuICB9XG5cbiAgLy8gRG8gd2UgaGF2ZSBhbnkgbm9kZXMgaW4gdGhpcyBncmFwaD9cbiAgaWYgKHRvcCA9PSBJbnRlZ2VyLk1BWF9WQUxVRSlcbiAge1xuICAgIHJldHVybiBudWxsO1xuICB9XG4gIFxuICBpZihub2Rlc1swXS5nZXRQYXJlbnQoKS5wYWRkaW5nTGVmdCAhPSB1bmRlZmluZWQpe1xuICAgIG1hcmdpbiA9IG5vZGVzWzBdLmdldFBhcmVudCgpLnBhZGRpbmdMZWZ0O1xuICB9XG4gIGVsc2V7XG4gICAgbWFyZ2luID0gdGhpcy5tYXJnaW47XG4gIH1cblxuICB0aGlzLmxlZnQgPSBsZWZ0IC0gbWFyZ2luO1xuICB0aGlzLnRvcCA9IHRvcCAtIG1hcmdpbjtcblxuICAvLyBBcHBseSB0aGUgbWFyZ2lucyBhbmQgcmV0dXJuIHRoZSByZXN1bHRcbiAgcmV0dXJuIG5ldyBQb2ludCh0aGlzLmxlZnQsIHRoaXMudG9wKTtcbn07XG5cbkxHcmFwaC5wcm90b3R5cGUudXBkYXRlQm91bmRzID0gZnVuY3Rpb24gKHJlY3Vyc2l2ZSlcbntcbiAgLy8gY2FsY3VsYXRlIGJvdW5kc1xuICB2YXIgbGVmdCA9IEludGVnZXIuTUFYX1ZBTFVFO1xuICB2YXIgcmlnaHQgPSAtSW50ZWdlci5NQVhfVkFMVUU7XG4gIHZhciB0b3AgPSBJbnRlZ2VyLk1BWF9WQUxVRTtcbiAgdmFyIGJvdHRvbSA9IC1JbnRlZ2VyLk1BWF9WQUxVRTtcbiAgdmFyIG5vZGVMZWZ0O1xuICB2YXIgbm9kZVJpZ2h0O1xuICB2YXIgbm9kZVRvcDtcbiAgdmFyIG5vZGVCb3R0b207XG4gIHZhciBtYXJnaW47XG5cbiAgdmFyIG5vZGVzID0gdGhpcy5ub2RlcztcbiAgdmFyIHMgPSBub2Rlcy5sZW5ndGg7XG4gIGZvciAodmFyIGkgPSAwOyBpIDwgczsgaSsrKVxuICB7XG4gICAgdmFyIGxOb2RlID0gbm9kZXNbaV07XG5cbiAgICBpZiAocmVjdXJzaXZlICYmIGxOb2RlLmNoaWxkICE9IG51bGwpXG4gICAge1xuICAgICAgbE5vZGUudXBkYXRlQm91bmRzKCk7XG4gICAgfVxuICAgIG5vZGVMZWZ0ID0gbE5vZGUuZ2V0TGVmdCgpO1xuICAgIG5vZGVSaWdodCA9IGxOb2RlLmdldFJpZ2h0KCk7XG4gICAgbm9kZVRvcCA9IGxOb2RlLmdldFRvcCgpO1xuICAgIG5vZGVCb3R0b20gPSBsTm9kZS5nZXRCb3R0b20oKTtcblxuICAgIGlmIChsZWZ0ID4gbm9kZUxlZnQpXG4gICAge1xuICAgICAgbGVmdCA9IG5vZGVMZWZ0O1xuICAgIH1cblxuICAgIGlmIChyaWdodCA8IG5vZGVSaWdodClcbiAgICB7XG4gICAgICByaWdodCA9IG5vZGVSaWdodDtcbiAgICB9XG5cbiAgICBpZiAodG9wID4gbm9kZVRvcClcbiAgICB7XG4gICAgICB0b3AgPSBub2RlVG9wO1xuICAgIH1cblxuICAgIGlmIChib3R0b20gPCBub2RlQm90dG9tKVxuICAgIHtcbiAgICAgIGJvdHRvbSA9IG5vZGVCb3R0b207XG4gICAgfVxuICB9XG5cbiAgdmFyIGJvdW5kaW5nUmVjdCA9IG5ldyBSZWN0YW5nbGVEKGxlZnQsIHRvcCwgcmlnaHQgLSBsZWZ0LCBib3R0b20gLSB0b3ApO1xuICBpZiAobGVmdCA9PSBJbnRlZ2VyLk1BWF9WQUxVRSlcbiAge1xuICAgIHRoaXMubGVmdCA9IHRoaXMucGFyZW50LmdldExlZnQoKTtcbiAgICB0aGlzLnJpZ2h0ID0gdGhpcy5wYXJlbnQuZ2V0UmlnaHQoKTtcbiAgICB0aGlzLnRvcCA9IHRoaXMucGFyZW50LmdldFRvcCgpO1xuICAgIHRoaXMuYm90dG9tID0gdGhpcy5wYXJlbnQuZ2V0Qm90dG9tKCk7XG4gIH1cbiAgXG4gIGlmKG5vZGVzWzBdLmdldFBhcmVudCgpLnBhZGRpbmdMZWZ0ICE9IHVuZGVmaW5lZCl7XG4gICAgbWFyZ2luID0gbm9kZXNbMF0uZ2V0UGFyZW50KCkucGFkZGluZ0xlZnQ7XG4gIH1cbiAgZWxzZXtcbiAgICBtYXJnaW4gPSB0aGlzLm1hcmdpbjtcbiAgfVxuXG4gIHRoaXMubGVmdCA9IGJvdW5kaW5nUmVjdC54IC0gbWFyZ2luO1xuICB0aGlzLnJpZ2h0ID0gYm91bmRpbmdSZWN0LnggKyBib3VuZGluZ1JlY3Qud2lkdGggKyBtYXJnaW47XG4gIHRoaXMudG9wID0gYm91bmRpbmdSZWN0LnkgLSBtYXJnaW47XG4gIHRoaXMuYm90dG9tID0gYm91bmRpbmdSZWN0LnkgKyBib3VuZGluZ1JlY3QuaGVpZ2h0ICsgbWFyZ2luO1xufTtcblxuTEdyYXBoLmNhbGN1bGF0ZUJvdW5kcyA9IGZ1bmN0aW9uIChub2RlcylcbntcbiAgdmFyIGxlZnQgPSBJbnRlZ2VyLk1BWF9WQUxVRTtcbiAgdmFyIHJpZ2h0ID0gLUludGVnZXIuTUFYX1ZBTFVFO1xuICB2YXIgdG9wID0gSW50ZWdlci5NQVhfVkFMVUU7XG4gIHZhciBib3R0b20gPSAtSW50ZWdlci5NQVhfVkFMVUU7XG4gIHZhciBub2RlTGVmdDtcbiAgdmFyIG5vZGVSaWdodDtcbiAgdmFyIG5vZGVUb3A7XG4gIHZhciBub2RlQm90dG9tO1xuXG4gIHZhciBzID0gbm9kZXMubGVuZ3RoO1xuXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgczsgaSsrKVxuICB7XG4gICAgdmFyIGxOb2RlID0gbm9kZXNbaV07XG4gICAgbm9kZUxlZnQgPSBsTm9kZS5nZXRMZWZ0KCk7XG4gICAgbm9kZVJpZ2h0ID0gbE5vZGUuZ2V0UmlnaHQoKTtcbiAgICBub2RlVG9wID0gbE5vZGUuZ2V0VG9wKCk7XG4gICAgbm9kZUJvdHRvbSA9IGxOb2RlLmdldEJvdHRvbSgpO1xuXG4gICAgaWYgKGxlZnQgPiBub2RlTGVmdClcbiAgICB7XG4gICAgICBsZWZ0ID0gbm9kZUxlZnQ7XG4gICAgfVxuXG4gICAgaWYgKHJpZ2h0IDwgbm9kZVJpZ2h0KVxuICAgIHtcbiAgICAgIHJpZ2h0ID0gbm9kZVJpZ2h0O1xuICAgIH1cblxuICAgIGlmICh0b3AgPiBub2RlVG9wKVxuICAgIHtcbiAgICAgIHRvcCA9IG5vZGVUb3A7XG4gICAgfVxuXG4gICAgaWYgKGJvdHRvbSA8IG5vZGVCb3R0b20pXG4gICAge1xuICAgICAgYm90dG9tID0gbm9kZUJvdHRvbTtcbiAgICB9XG4gIH1cblxuICB2YXIgYm91bmRpbmdSZWN0ID0gbmV3IFJlY3RhbmdsZUQobGVmdCwgdG9wLCByaWdodCAtIGxlZnQsIGJvdHRvbSAtIHRvcCk7XG5cbiAgcmV0dXJuIGJvdW5kaW5nUmVjdDtcbn07XG5cbkxHcmFwaC5wcm90b3R5cGUuZ2V0SW5jbHVzaW9uVHJlZURlcHRoID0gZnVuY3Rpb24gKClcbntcbiAgaWYgKHRoaXMgPT0gdGhpcy5ncmFwaE1hbmFnZXIuZ2V0Um9vdCgpKVxuICB7XG4gICAgcmV0dXJuIDE7XG4gIH1cbiAgZWxzZVxuICB7XG4gICAgcmV0dXJuIHRoaXMucGFyZW50LmdldEluY2x1c2lvblRyZWVEZXB0aCgpO1xuICB9XG59O1xuXG5MR3JhcGgucHJvdG90eXBlLmdldEVzdGltYXRlZFNpemUgPSBmdW5jdGlvbiAoKVxue1xuICBpZiAodGhpcy5lc3RpbWF0ZWRTaXplID09IEludGVnZXIuTUlOX1ZBTFVFKSB7XG4gICAgdGhyb3cgXCJhc3NlcnQgZmFpbGVkXCI7XG4gIH1cbiAgcmV0dXJuIHRoaXMuZXN0aW1hdGVkU2l6ZTtcbn07XG5cbkxHcmFwaC5wcm90b3R5cGUuY2FsY0VzdGltYXRlZFNpemUgPSBmdW5jdGlvbiAoKVxue1xuICB2YXIgc2l6ZSA9IDA7XG4gIHZhciBub2RlcyA9IHRoaXMubm9kZXM7XG4gIHZhciBzID0gbm9kZXMubGVuZ3RoO1xuXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgczsgaSsrKVxuICB7XG4gICAgdmFyIGxOb2RlID0gbm9kZXNbaV07XG4gICAgc2l6ZSArPSBsTm9kZS5jYWxjRXN0aW1hdGVkU2l6ZSgpO1xuICB9XG5cbiAgaWYgKHNpemUgPT0gMClcbiAge1xuICAgIHRoaXMuZXN0aW1hdGVkU2l6ZSA9IExheW91dENvbnN0YW50cy5FTVBUWV9DT01QT1VORF9OT0RFX1NJWkU7XG4gIH1cbiAgZWxzZVxuICB7XG4gICAgdGhpcy5lc3RpbWF0ZWRTaXplID0gc2l6ZSAvIE1hdGguc3FydCh0aGlzLm5vZGVzLmxlbmd0aCk7XG4gIH1cblxuICByZXR1cm4gdGhpcy5lc3RpbWF0ZWRTaXplO1xufTtcblxuTEdyYXBoLnByb3RvdHlwZS51cGRhdGVDb25uZWN0ZWQgPSBmdW5jdGlvbiAoKVxue1xuICB2YXIgc2VsZiA9IHRoaXM7XG4gIGlmICh0aGlzLm5vZGVzLmxlbmd0aCA9PSAwKVxuICB7XG4gICAgdGhpcy5pc0Nvbm5lY3RlZCA9IHRydWU7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgdmFyIHRvQmVWaXNpdGVkID0gbmV3IExpc3QoKTtcbiAgdmFyIHZpc2l0ZWQgPSBuZXcgSGFzaFNldCgpO1xuICB2YXIgY3VycmVudE5vZGUgPSB0aGlzLm5vZGVzWzBdO1xuICB2YXIgbmVpZ2hib3JFZGdlcztcbiAgdmFyIGN1cnJlbnROZWlnaGJvcjtcbiAgdmFyIGNoaWxkcmVuT2ZOb2RlID0gY3VycmVudE5vZGUud2l0aENoaWxkcmVuKCk7XG4gIGNoaWxkcmVuT2ZOb2RlLmZvckVhY2goZnVuY3Rpb24obm9kZSkge1xuICAgIHRvQmVWaXNpdGVkLnB1c2gobm9kZSk7XG4gIH0pO1xuXG4gIHdoaWxlICghdG9CZVZpc2l0ZWQuaXNFbXB0eSgpKVxuICB7XG4gICAgY3VycmVudE5vZGUgPSB0b0JlVmlzaXRlZC5zaGlmdCgpLnZhbHVlKCk7XG4gICAgdmlzaXRlZC5hZGQoY3VycmVudE5vZGUpO1xuXG4gICAgLy8gVHJhdmVyc2UgYWxsIG5laWdoYm9ycyBvZiB0aGlzIG5vZGVcbiAgICBuZWlnaGJvckVkZ2VzID0gY3VycmVudE5vZGUuZ2V0RWRnZXMoKTtcbiAgICB2YXIgcyA9IG5laWdoYm9yRWRnZXMubGVuZ3RoO1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgczsgaSsrKVxuICAgIHtcbiAgICAgIHZhciBuZWlnaGJvckVkZ2UgPSBuZWlnaGJvckVkZ2VzW2ldO1xuICAgICAgY3VycmVudE5laWdoYm9yID1cbiAgICAgICAgICAgICAgbmVpZ2hib3JFZGdlLmdldE90aGVyRW5kSW5HcmFwaChjdXJyZW50Tm9kZSwgdGhpcyk7XG5cbiAgICAgIC8vIEFkZCB1bnZpc2l0ZWQgbmVpZ2hib3JzIHRvIHRoZSBsaXN0IHRvIHZpc2l0XG4gICAgICBpZiAoY3VycmVudE5laWdoYm9yICE9IG51bGwgJiZcbiAgICAgICAgICAgICAgIXZpc2l0ZWQuY29udGFpbnMoY3VycmVudE5laWdoYm9yKSlcbiAgICAgIHtcbiAgICAgICAgdmFyIGNoaWxkcmVuT2ZOZWlnaGJvciA9IGN1cnJlbnROZWlnaGJvci53aXRoQ2hpbGRyZW4oKTtcbiAgICAgICAgXG4gICAgICAgIGNoaWxkcmVuT2ZOZWlnaGJvci5mb3JFYWNoKGZ1bmN0aW9uKG5vZGUpIHtcbiAgICAgICAgICB0b0JlVmlzaXRlZC5wdXNoKG5vZGUpO1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICB0aGlzLmlzQ29ubmVjdGVkID0gZmFsc2U7XG5cbiAgaWYgKHZpc2l0ZWQuc2l6ZSgpID49IHRoaXMubm9kZXMubGVuZ3RoKVxuICB7XG4gICAgdmFyIG5vT2ZWaXNpdGVkSW5UaGlzR3JhcGggPSAwO1xuICAgIFxuICAgIHZhciBzID0gdmlzaXRlZC5zaXplKCk7XG4gICAgIE9iamVjdC5rZXlzKHZpc2l0ZWQuc2V0KS5mb3JFYWNoKGZ1bmN0aW9uKHZpc2l0ZWRJZCkge1xuICAgICAgdmFyIHZpc2l0ZWROb2RlID0gdmlzaXRlZC5zZXRbdmlzaXRlZElkXTtcbiAgICAgIGlmICh2aXNpdGVkTm9kZS5vd25lciA9PSBzZWxmKVxuICAgICAge1xuICAgICAgICBub09mVmlzaXRlZEluVGhpc0dyYXBoKys7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICBpZiAobm9PZlZpc2l0ZWRJblRoaXNHcmFwaCA9PSB0aGlzLm5vZGVzLmxlbmd0aClcbiAgICB7XG4gICAgICB0aGlzLmlzQ29ubmVjdGVkID0gdHJ1ZTtcbiAgICB9XG4gIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gTEdyYXBoO1xuIiwidmFyIExHcmFwaDtcbnZhciBMRWRnZSA9IHJlcXVpcmUoJy4vTEVkZ2UnKTtcblxuZnVuY3Rpb24gTEdyYXBoTWFuYWdlcihsYXlvdXQpIHtcbiAgTEdyYXBoID0gcmVxdWlyZSgnLi9MR3JhcGgnKTsgLy8gSXQgbWF5IGJlIGJldHRlciB0byBpbml0aWxpemUgdGhpcyBvdXQgb2YgdGhpcyBmdW5jdGlvbiBidXQgaXQgZ2l2ZXMgYW4gZXJyb3IgKFJpZ2h0LWhhbmQgc2lkZSBvZiAnaW5zdGFuY2VvZicgaXMgbm90IGNhbGxhYmxlKSBub3cuXG4gIHRoaXMubGF5b3V0ID0gbGF5b3V0O1xuXG4gIHRoaXMuZ3JhcGhzID0gW107XG4gIHRoaXMuZWRnZXMgPSBbXTtcbn1cblxuTEdyYXBoTWFuYWdlci5wcm90b3R5cGUuYWRkUm9vdCA9IGZ1bmN0aW9uICgpXG57XG4gIHZhciBuZ3JhcGggPSB0aGlzLmxheW91dC5uZXdHcmFwaCgpO1xuICB2YXIgbm5vZGUgPSB0aGlzLmxheW91dC5uZXdOb2RlKG51bGwpO1xuICB2YXIgcm9vdCA9IHRoaXMuYWRkKG5ncmFwaCwgbm5vZGUpO1xuICB0aGlzLnNldFJvb3RHcmFwaChyb290KTtcbiAgcmV0dXJuIHRoaXMucm9vdEdyYXBoO1xufTtcblxuTEdyYXBoTWFuYWdlci5wcm90b3R5cGUuYWRkID0gZnVuY3Rpb24gKG5ld0dyYXBoLCBwYXJlbnROb2RlLCBuZXdFZGdlLCBzb3VyY2VOb2RlLCB0YXJnZXROb2RlKVxue1xuICAvL3RoZXJlIGFyZSBqdXN0IDIgcGFyYW1ldGVycyBhcmUgcGFzc2VkIHRoZW4gaXQgYWRkcyBhbiBMR3JhcGggZWxzZSBpdCBhZGRzIGFuIExFZGdlXG4gIGlmIChuZXdFZGdlID09IG51bGwgJiYgc291cmNlTm9kZSA9PSBudWxsICYmIHRhcmdldE5vZGUgPT0gbnVsbCkge1xuICAgIGlmIChuZXdHcmFwaCA9PSBudWxsKSB7XG4gICAgICB0aHJvdyBcIkdyYXBoIGlzIG51bGwhXCI7XG4gICAgfVxuICAgIGlmIChwYXJlbnROb2RlID09IG51bGwpIHtcbiAgICAgIHRocm93IFwiUGFyZW50IG5vZGUgaXMgbnVsbCFcIjtcbiAgICB9XG4gICAgaWYgKHRoaXMuZ3JhcGhzLmluZGV4T2YobmV3R3JhcGgpID4gLTEpIHtcbiAgICAgIHRocm93IFwiR3JhcGggYWxyZWFkeSBpbiB0aGlzIGdyYXBoIG1nciFcIjtcbiAgICB9XG5cbiAgICB0aGlzLmdyYXBocy5wdXNoKG5ld0dyYXBoKTtcblxuICAgIGlmIChuZXdHcmFwaC5wYXJlbnQgIT0gbnVsbCkge1xuICAgICAgdGhyb3cgXCJBbHJlYWR5IGhhcyBhIHBhcmVudCFcIjtcbiAgICB9XG4gICAgaWYgKHBhcmVudE5vZGUuY2hpbGQgIT0gbnVsbCkge1xuICAgICAgdGhyb3cgIFwiQWxyZWFkeSBoYXMgYSBjaGlsZCFcIjtcbiAgICB9XG5cbiAgICBuZXdHcmFwaC5wYXJlbnQgPSBwYXJlbnROb2RlO1xuICAgIHBhcmVudE5vZGUuY2hpbGQgPSBuZXdHcmFwaDtcblxuICAgIHJldHVybiBuZXdHcmFwaDtcbiAgfVxuICBlbHNlIHtcbiAgICAvL2NoYW5nZSB0aGUgb3JkZXIgb2YgdGhlIHBhcmFtZXRlcnNcbiAgICB0YXJnZXROb2RlID0gbmV3RWRnZTtcbiAgICBzb3VyY2VOb2RlID0gcGFyZW50Tm9kZTtcbiAgICBuZXdFZGdlID0gbmV3R3JhcGg7XG4gICAgdmFyIHNvdXJjZUdyYXBoID0gc291cmNlTm9kZS5nZXRPd25lcigpO1xuICAgIHZhciB0YXJnZXRHcmFwaCA9IHRhcmdldE5vZGUuZ2V0T3duZXIoKTtcblxuICAgIGlmICghKHNvdXJjZUdyYXBoICE9IG51bGwgJiYgc291cmNlR3JhcGguZ2V0R3JhcGhNYW5hZ2VyKCkgPT0gdGhpcykpIHtcbiAgICAgIHRocm93IFwiU291cmNlIG5vdCBpbiB0aGlzIGdyYXBoIG1nciFcIjtcbiAgICB9XG4gICAgaWYgKCEodGFyZ2V0R3JhcGggIT0gbnVsbCAmJiB0YXJnZXRHcmFwaC5nZXRHcmFwaE1hbmFnZXIoKSA9PSB0aGlzKSkge1xuICAgICAgdGhyb3cgXCJUYXJnZXQgbm90IGluIHRoaXMgZ3JhcGggbWdyIVwiO1xuICAgIH1cblxuICAgIGlmIChzb3VyY2VHcmFwaCA9PSB0YXJnZXRHcmFwaClcbiAgICB7XG4gICAgICBuZXdFZGdlLmlzSW50ZXJHcmFwaCA9IGZhbHNlO1xuICAgICAgcmV0dXJuIHNvdXJjZUdyYXBoLmFkZChuZXdFZGdlLCBzb3VyY2VOb2RlLCB0YXJnZXROb2RlKTtcbiAgICB9XG4gICAgZWxzZVxuICAgIHtcbiAgICAgIG5ld0VkZ2UuaXNJbnRlckdyYXBoID0gdHJ1ZTtcblxuICAgICAgLy8gc2V0IHNvdXJjZSBhbmQgdGFyZ2V0XG4gICAgICBuZXdFZGdlLnNvdXJjZSA9IHNvdXJjZU5vZGU7XG4gICAgICBuZXdFZGdlLnRhcmdldCA9IHRhcmdldE5vZGU7XG5cbiAgICAgIC8vIGFkZCBlZGdlIHRvIGludGVyLWdyYXBoIGVkZ2UgbGlzdFxuICAgICAgaWYgKHRoaXMuZWRnZXMuaW5kZXhPZihuZXdFZGdlKSA+IC0xKSB7XG4gICAgICAgIHRocm93IFwiRWRnZSBhbHJlYWR5IGluIGludGVyLWdyYXBoIGVkZ2UgbGlzdCFcIjtcbiAgICAgIH1cblxuICAgICAgdGhpcy5lZGdlcy5wdXNoKG5ld0VkZ2UpO1xuXG4gICAgICAvLyBhZGQgZWRnZSB0byBzb3VyY2UgYW5kIHRhcmdldCBpbmNpZGVuY3kgbGlzdHNcbiAgICAgIGlmICghKG5ld0VkZ2Uuc291cmNlICE9IG51bGwgJiYgbmV3RWRnZS50YXJnZXQgIT0gbnVsbCkpIHtcbiAgICAgICAgdGhyb3cgXCJFZGdlIHNvdXJjZSBhbmQvb3IgdGFyZ2V0IGlzIG51bGwhXCI7XG4gICAgICB9XG5cbiAgICAgIGlmICghKG5ld0VkZ2Uuc291cmNlLmVkZ2VzLmluZGV4T2YobmV3RWRnZSkgPT0gLTEgJiYgbmV3RWRnZS50YXJnZXQuZWRnZXMuaW5kZXhPZihuZXdFZGdlKSA9PSAtMSkpIHtcbiAgICAgICAgdGhyb3cgXCJFZGdlIGFscmVhZHkgaW4gc291cmNlIGFuZC9vciB0YXJnZXQgaW5jaWRlbmN5IGxpc3QhXCI7XG4gICAgICB9XG5cbiAgICAgIG5ld0VkZ2Uuc291cmNlLmVkZ2VzLnB1c2gobmV3RWRnZSk7XG4gICAgICBuZXdFZGdlLnRhcmdldC5lZGdlcy5wdXNoKG5ld0VkZ2UpO1xuXG4gICAgICByZXR1cm4gbmV3RWRnZTtcbiAgICB9XG4gIH1cbn07XG5cbkxHcmFwaE1hbmFnZXIucHJvdG90eXBlLnJlbW92ZSA9IGZ1bmN0aW9uIChsT2JqKSB7XG4gIGlmIChsT2JqIGluc3RhbmNlb2YgTEdyYXBoKSB7XG4gICAgdmFyIGdyYXBoID0gbE9iajtcbiAgICBpZiAoZ3JhcGguZ2V0R3JhcGhNYW5hZ2VyKCkgIT0gdGhpcykge1xuICAgICAgdGhyb3cgXCJHcmFwaCBub3QgaW4gdGhpcyBncmFwaCBtZ3JcIjtcbiAgICB9XG4gICAgaWYgKCEoZ3JhcGggPT0gdGhpcy5yb290R3JhcGggfHwgKGdyYXBoLnBhcmVudCAhPSBudWxsICYmIGdyYXBoLnBhcmVudC5ncmFwaE1hbmFnZXIgPT0gdGhpcykpKSB7XG4gICAgICB0aHJvdyBcIkludmFsaWQgcGFyZW50IG5vZGUhXCI7XG4gICAgfVxuXG4gICAgLy8gZmlyc3QgdGhlIGVkZ2VzIChtYWtlIGEgY29weSB0byBkbyBpdCBzYWZlbHkpXG4gICAgdmFyIGVkZ2VzVG9CZVJlbW92ZWQgPSBbXTtcblxuICAgIGVkZ2VzVG9CZVJlbW92ZWQgPSBlZGdlc1RvQmVSZW1vdmVkLmNvbmNhdChncmFwaC5nZXRFZGdlcygpKTtcblxuICAgIHZhciBlZGdlO1xuICAgIHZhciBzID0gZWRnZXNUb0JlUmVtb3ZlZC5sZW5ndGg7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBzOyBpKyspXG4gICAge1xuICAgICAgZWRnZSA9IGVkZ2VzVG9CZVJlbW92ZWRbaV07XG4gICAgICBncmFwaC5yZW1vdmUoZWRnZSk7XG4gICAgfVxuXG4gICAgLy8gdGhlbiB0aGUgbm9kZXMgKG1ha2UgYSBjb3B5IHRvIGRvIGl0IHNhZmVseSlcbiAgICB2YXIgbm9kZXNUb0JlUmVtb3ZlZCA9IFtdO1xuXG4gICAgbm9kZXNUb0JlUmVtb3ZlZCA9IG5vZGVzVG9CZVJlbW92ZWQuY29uY2F0KGdyYXBoLmdldE5vZGVzKCkpO1xuXG4gICAgdmFyIG5vZGU7XG4gICAgcyA9IG5vZGVzVG9CZVJlbW92ZWQubGVuZ3RoO1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgczsgaSsrKVxuICAgIHtcbiAgICAgIG5vZGUgPSBub2Rlc1RvQmVSZW1vdmVkW2ldO1xuICAgICAgZ3JhcGgucmVtb3ZlKG5vZGUpO1xuICAgIH1cblxuICAgIC8vIGNoZWNrIGlmIGdyYXBoIGlzIHRoZSByb290XG4gICAgaWYgKGdyYXBoID09IHRoaXMucm9vdEdyYXBoKVxuICAgIHtcbiAgICAgIHRoaXMuc2V0Um9vdEdyYXBoKG51bGwpO1xuICAgIH1cblxuICAgIC8vIG5vdyByZW1vdmUgdGhlIGdyYXBoIGl0c2VsZlxuICAgIHZhciBpbmRleCA9IHRoaXMuZ3JhcGhzLmluZGV4T2YoZ3JhcGgpO1xuICAgIHRoaXMuZ3JhcGhzLnNwbGljZShpbmRleCwgMSk7XG5cbiAgICAvLyBhbHNvIHJlc2V0IHRoZSBwYXJlbnQgb2YgdGhlIGdyYXBoXG4gICAgZ3JhcGgucGFyZW50ID0gbnVsbDtcbiAgfVxuICBlbHNlIGlmIChsT2JqIGluc3RhbmNlb2YgTEVkZ2UpIHtcbiAgICBlZGdlID0gbE9iajtcbiAgICBpZiAoZWRnZSA9PSBudWxsKSB7XG4gICAgICB0aHJvdyBcIkVkZ2UgaXMgbnVsbCFcIjtcbiAgICB9XG4gICAgaWYgKCFlZGdlLmlzSW50ZXJHcmFwaCkge1xuICAgICAgdGhyb3cgXCJOb3QgYW4gaW50ZXItZ3JhcGggZWRnZSFcIjtcbiAgICB9XG4gICAgaWYgKCEoZWRnZS5zb3VyY2UgIT0gbnVsbCAmJiBlZGdlLnRhcmdldCAhPSBudWxsKSkge1xuICAgICAgdGhyb3cgXCJTb3VyY2UgYW5kL29yIHRhcmdldCBpcyBudWxsIVwiO1xuICAgIH1cblxuICAgIC8vIHJlbW92ZSBlZGdlIGZyb20gc291cmNlIGFuZCB0YXJnZXQgbm9kZXMnIGluY2lkZW5jeSBsaXN0c1xuXG4gICAgaWYgKCEoZWRnZS5zb3VyY2UuZWRnZXMuaW5kZXhPZihlZGdlKSAhPSAtMSAmJiBlZGdlLnRhcmdldC5lZGdlcy5pbmRleE9mKGVkZ2UpICE9IC0xKSkge1xuICAgICAgdGhyb3cgXCJTb3VyY2UgYW5kL29yIHRhcmdldCBkb2Vzbid0IGtub3cgdGhpcyBlZGdlIVwiO1xuICAgIH1cblxuICAgIHZhciBpbmRleCA9IGVkZ2Uuc291cmNlLmVkZ2VzLmluZGV4T2YoZWRnZSk7XG4gICAgZWRnZS5zb3VyY2UuZWRnZXMuc3BsaWNlKGluZGV4LCAxKTtcbiAgICBpbmRleCA9IGVkZ2UudGFyZ2V0LmVkZ2VzLmluZGV4T2YoZWRnZSk7XG4gICAgZWRnZS50YXJnZXQuZWRnZXMuc3BsaWNlKGluZGV4LCAxKTtcblxuICAgIC8vIHJlbW92ZSBlZGdlIGZyb20gb3duZXIgZ3JhcGggbWFuYWdlcidzIGludGVyLWdyYXBoIGVkZ2UgbGlzdFxuXG4gICAgaWYgKCEoZWRnZS5zb3VyY2Uub3duZXIgIT0gbnVsbCAmJiBlZGdlLnNvdXJjZS5vd25lci5nZXRHcmFwaE1hbmFnZXIoKSAhPSBudWxsKSkge1xuICAgICAgdGhyb3cgXCJFZGdlIG93bmVyIGdyYXBoIG9yIG93bmVyIGdyYXBoIG1hbmFnZXIgaXMgbnVsbCFcIjtcbiAgICB9XG4gICAgaWYgKGVkZ2Uuc291cmNlLm93bmVyLmdldEdyYXBoTWFuYWdlcigpLmVkZ2VzLmluZGV4T2YoZWRnZSkgPT0gLTEpIHtcbiAgICAgIHRocm93IFwiTm90IGluIG93bmVyIGdyYXBoIG1hbmFnZXIncyBlZGdlIGxpc3QhXCI7XG4gICAgfVxuXG4gICAgdmFyIGluZGV4ID0gZWRnZS5zb3VyY2Uub3duZXIuZ2V0R3JhcGhNYW5hZ2VyKCkuZWRnZXMuaW5kZXhPZihlZGdlKTtcbiAgICBlZGdlLnNvdXJjZS5vd25lci5nZXRHcmFwaE1hbmFnZXIoKS5lZGdlcy5zcGxpY2UoaW5kZXgsIDEpO1xuICB9XG59O1xuXG5MR3JhcGhNYW5hZ2VyLnByb3RvdHlwZS51cGRhdGVCb3VuZHMgPSBmdW5jdGlvbiAoKVxue1xuICB0aGlzLnJvb3RHcmFwaC51cGRhdGVCb3VuZHModHJ1ZSk7XG59O1xuXG5MR3JhcGhNYW5hZ2VyLnByb3RvdHlwZS5nZXRHcmFwaHMgPSBmdW5jdGlvbiAoKVxue1xuICByZXR1cm4gdGhpcy5ncmFwaHM7XG59O1xuXG5MR3JhcGhNYW5hZ2VyLnByb3RvdHlwZS5nZXRBbGxOb2RlcyA9IGZ1bmN0aW9uICgpXG57XG4gIGlmICh0aGlzLmFsbE5vZGVzID09IG51bGwpXG4gIHtcbiAgICB2YXIgbm9kZUxpc3QgPSBbXTtcbiAgICB2YXIgZ3JhcGhzID0gdGhpcy5nZXRHcmFwaHMoKTtcbiAgICB2YXIgcyA9IGdyYXBocy5sZW5ndGg7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBzOyBpKyspXG4gICAge1xuICAgICAgbm9kZUxpc3QgPSBub2RlTGlzdC5jb25jYXQoZ3JhcGhzW2ldLmdldE5vZGVzKCkpO1xuICAgIH1cbiAgICB0aGlzLmFsbE5vZGVzID0gbm9kZUxpc3Q7XG4gIH1cbiAgcmV0dXJuIHRoaXMuYWxsTm9kZXM7XG59O1xuXG5MR3JhcGhNYW5hZ2VyLnByb3RvdHlwZS5yZXNldEFsbE5vZGVzID0gZnVuY3Rpb24gKClcbntcbiAgdGhpcy5hbGxOb2RlcyA9IG51bGw7XG59O1xuXG5MR3JhcGhNYW5hZ2VyLnByb3RvdHlwZS5yZXNldEFsbEVkZ2VzID0gZnVuY3Rpb24gKClcbntcbiAgdGhpcy5hbGxFZGdlcyA9IG51bGw7XG59O1xuXG5MR3JhcGhNYW5hZ2VyLnByb3RvdHlwZS5yZXNldEFsbE5vZGVzVG9BcHBseUdyYXZpdGF0aW9uID0gZnVuY3Rpb24gKClcbntcbiAgdGhpcy5hbGxOb2Rlc1RvQXBwbHlHcmF2aXRhdGlvbiA9IG51bGw7XG59O1xuXG5MR3JhcGhNYW5hZ2VyLnByb3RvdHlwZS5nZXRBbGxFZGdlcyA9IGZ1bmN0aW9uICgpXG57XG4gIGlmICh0aGlzLmFsbEVkZ2VzID09IG51bGwpXG4gIHtcbiAgICB2YXIgZWRnZUxpc3QgPSBbXTtcbiAgICB2YXIgZ3JhcGhzID0gdGhpcy5nZXRHcmFwaHMoKTtcbiAgICB2YXIgcyA9IGdyYXBocy5sZW5ndGg7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBncmFwaHMubGVuZ3RoOyBpKyspXG4gICAge1xuICAgICAgZWRnZUxpc3QgPSBlZGdlTGlzdC5jb25jYXQoZ3JhcGhzW2ldLmdldEVkZ2VzKCkpO1xuICAgIH1cblxuICAgIGVkZ2VMaXN0ID0gZWRnZUxpc3QuY29uY2F0KHRoaXMuZWRnZXMpO1xuXG4gICAgdGhpcy5hbGxFZGdlcyA9IGVkZ2VMaXN0O1xuICB9XG4gIHJldHVybiB0aGlzLmFsbEVkZ2VzO1xufTtcblxuTEdyYXBoTWFuYWdlci5wcm90b3R5cGUuZ2V0QWxsTm9kZXNUb0FwcGx5R3Jhdml0YXRpb24gPSBmdW5jdGlvbiAoKVxue1xuICByZXR1cm4gdGhpcy5hbGxOb2Rlc1RvQXBwbHlHcmF2aXRhdGlvbjtcbn07XG5cbkxHcmFwaE1hbmFnZXIucHJvdG90eXBlLnNldEFsbE5vZGVzVG9BcHBseUdyYXZpdGF0aW9uID0gZnVuY3Rpb24gKG5vZGVMaXN0KVxue1xuICBpZiAodGhpcy5hbGxOb2Rlc1RvQXBwbHlHcmF2aXRhdGlvbiAhPSBudWxsKSB7XG4gICAgdGhyb3cgXCJhc3NlcnQgZmFpbGVkXCI7XG4gIH1cblxuICB0aGlzLmFsbE5vZGVzVG9BcHBseUdyYXZpdGF0aW9uID0gbm9kZUxpc3Q7XG59O1xuXG5MR3JhcGhNYW5hZ2VyLnByb3RvdHlwZS5nZXRSb290ID0gZnVuY3Rpb24gKClcbntcbiAgcmV0dXJuIHRoaXMucm9vdEdyYXBoO1xufTtcblxuTEdyYXBoTWFuYWdlci5wcm90b3R5cGUuc2V0Um9vdEdyYXBoID0gZnVuY3Rpb24gKGdyYXBoKVxue1xuICBpZiAoZ3JhcGguZ2V0R3JhcGhNYW5hZ2VyKCkgIT0gdGhpcykge1xuICAgIHRocm93IFwiUm9vdCBub3QgaW4gdGhpcyBncmFwaCBtZ3IhXCI7XG4gIH1cblxuICB0aGlzLnJvb3RHcmFwaCA9IGdyYXBoO1xuICAvLyByb290IGdyYXBoIG11c3QgaGF2ZSBhIHJvb3Qgbm9kZSBhc3NvY2lhdGVkIHdpdGggaXQgZm9yIGNvbnZlbmllbmNlXG4gIGlmIChncmFwaC5wYXJlbnQgPT0gbnVsbClcbiAge1xuICAgIGdyYXBoLnBhcmVudCA9IHRoaXMubGF5b3V0Lm5ld05vZGUoXCJSb290IG5vZGVcIik7XG4gIH1cbn07XG5cbkxHcmFwaE1hbmFnZXIucHJvdG90eXBlLmdldExheW91dCA9IGZ1bmN0aW9uICgpXG57XG4gIHJldHVybiB0aGlzLmxheW91dDtcbn07XG5cbkxHcmFwaE1hbmFnZXIucHJvdG90eXBlLmlzT25lQW5jZXN0b3JPZk90aGVyID0gZnVuY3Rpb24gKGZpcnN0Tm9kZSwgc2Vjb25kTm9kZSlcbntcbiAgaWYgKCEoZmlyc3ROb2RlICE9IG51bGwgJiYgc2Vjb25kTm9kZSAhPSBudWxsKSkge1xuICAgIHRocm93IFwiYXNzZXJ0IGZhaWxlZFwiO1xuICB9XG5cbiAgaWYgKGZpcnN0Tm9kZSA9PSBzZWNvbmROb2RlKVxuICB7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cbiAgLy8gSXMgc2Vjb25kIG5vZGUgYW4gYW5jZXN0b3Igb2YgdGhlIGZpcnN0IG9uZT9cbiAgdmFyIG93bmVyR3JhcGggPSBmaXJzdE5vZGUuZ2V0T3duZXIoKTtcbiAgdmFyIHBhcmVudE5vZGU7XG5cbiAgZG9cbiAge1xuICAgIHBhcmVudE5vZGUgPSBvd25lckdyYXBoLmdldFBhcmVudCgpO1xuXG4gICAgaWYgKHBhcmVudE5vZGUgPT0gbnVsbClcbiAgICB7XG4gICAgICBicmVhaztcbiAgICB9XG5cbiAgICBpZiAocGFyZW50Tm9kZSA9PSBzZWNvbmROb2RlKVxuICAgIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIG93bmVyR3JhcGggPSBwYXJlbnROb2RlLmdldE93bmVyKCk7XG4gICAgaWYgKG93bmVyR3JhcGggPT0gbnVsbClcbiAgICB7XG4gICAgICBicmVhaztcbiAgICB9XG4gIH0gd2hpbGUgKHRydWUpO1xuICAvLyBJcyBmaXJzdCBub2RlIGFuIGFuY2VzdG9yIG9mIHRoZSBzZWNvbmQgb25lP1xuICBvd25lckdyYXBoID0gc2Vjb25kTm9kZS5nZXRPd25lcigpO1xuXG4gIGRvXG4gIHtcbiAgICBwYXJlbnROb2RlID0gb3duZXJHcmFwaC5nZXRQYXJlbnQoKTtcblxuICAgIGlmIChwYXJlbnROb2RlID09IG51bGwpXG4gICAge1xuICAgICAgYnJlYWs7XG4gICAgfVxuXG4gICAgaWYgKHBhcmVudE5vZGUgPT0gZmlyc3ROb2RlKVxuICAgIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIG93bmVyR3JhcGggPSBwYXJlbnROb2RlLmdldE93bmVyKCk7XG4gICAgaWYgKG93bmVyR3JhcGggPT0gbnVsbClcbiAgICB7XG4gICAgICBicmVhaztcbiAgICB9XG4gIH0gd2hpbGUgKHRydWUpO1xuXG4gIHJldHVybiBmYWxzZTtcbn07XG5cbkxHcmFwaE1hbmFnZXIucHJvdG90eXBlLmNhbGNMb3dlc3RDb21tb25BbmNlc3RvcnMgPSBmdW5jdGlvbiAoKVxue1xuICB2YXIgZWRnZTtcbiAgdmFyIHNvdXJjZU5vZGU7XG4gIHZhciB0YXJnZXROb2RlO1xuICB2YXIgc291cmNlQW5jZXN0b3JHcmFwaDtcbiAgdmFyIHRhcmdldEFuY2VzdG9yR3JhcGg7XG5cbiAgdmFyIGVkZ2VzID0gdGhpcy5nZXRBbGxFZGdlcygpO1xuICB2YXIgcyA9IGVkZ2VzLmxlbmd0aDtcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBzOyBpKyspXG4gIHtcbiAgICBlZGdlID0gZWRnZXNbaV07XG5cbiAgICBzb3VyY2VOb2RlID0gZWRnZS5zb3VyY2U7XG4gICAgdGFyZ2V0Tm9kZSA9IGVkZ2UudGFyZ2V0O1xuICAgIGVkZ2UubGNhID0gbnVsbDtcbiAgICBlZGdlLnNvdXJjZUluTGNhID0gc291cmNlTm9kZTtcbiAgICBlZGdlLnRhcmdldEluTGNhID0gdGFyZ2V0Tm9kZTtcblxuICAgIGlmIChzb3VyY2VOb2RlID09IHRhcmdldE5vZGUpXG4gICAge1xuICAgICAgZWRnZS5sY2EgPSBzb3VyY2VOb2RlLmdldE93bmVyKCk7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG5cbiAgICBzb3VyY2VBbmNlc3RvckdyYXBoID0gc291cmNlTm9kZS5nZXRPd25lcigpO1xuXG4gICAgd2hpbGUgKGVkZ2UubGNhID09IG51bGwpXG4gICAge1xuICAgICAgZWRnZS50YXJnZXRJbkxjYSA9IHRhcmdldE5vZGU7ICBcbiAgICAgIHRhcmdldEFuY2VzdG9yR3JhcGggPSB0YXJnZXROb2RlLmdldE93bmVyKCk7XG5cbiAgICAgIHdoaWxlIChlZGdlLmxjYSA9PSBudWxsKVxuICAgICAge1xuICAgICAgICBpZiAodGFyZ2V0QW5jZXN0b3JHcmFwaCA9PSBzb3VyY2VBbmNlc3RvckdyYXBoKVxuICAgICAgICB7XG4gICAgICAgICAgZWRnZS5sY2EgPSB0YXJnZXRBbmNlc3RvckdyYXBoO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRhcmdldEFuY2VzdG9yR3JhcGggPT0gdGhpcy5yb290R3JhcGgpXG4gICAgICAgIHtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChlZGdlLmxjYSAhPSBudWxsKSB7XG4gICAgICAgICAgdGhyb3cgXCJhc3NlcnQgZmFpbGVkXCI7XG4gICAgICAgIH1cbiAgICAgICAgZWRnZS50YXJnZXRJbkxjYSA9IHRhcmdldEFuY2VzdG9yR3JhcGguZ2V0UGFyZW50KCk7XG4gICAgICAgIHRhcmdldEFuY2VzdG9yR3JhcGggPSBlZGdlLnRhcmdldEluTGNhLmdldE93bmVyKCk7XG4gICAgICB9XG5cbiAgICAgIGlmIChzb3VyY2VBbmNlc3RvckdyYXBoID09IHRoaXMucm9vdEdyYXBoKVxuICAgICAge1xuICAgICAgICBicmVhaztcbiAgICAgIH1cblxuICAgICAgaWYgKGVkZ2UubGNhID09IG51bGwpXG4gICAgICB7XG4gICAgICAgIGVkZ2Uuc291cmNlSW5MY2EgPSBzb3VyY2VBbmNlc3RvckdyYXBoLmdldFBhcmVudCgpO1xuICAgICAgICBzb3VyY2VBbmNlc3RvckdyYXBoID0gZWRnZS5zb3VyY2VJbkxjYS5nZXRPd25lcigpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChlZGdlLmxjYSA9PSBudWxsKSB7XG4gICAgICB0aHJvdyBcImFzc2VydCBmYWlsZWRcIjtcbiAgICB9XG4gIH1cbn07XG5cbkxHcmFwaE1hbmFnZXIucHJvdG90eXBlLmNhbGNMb3dlc3RDb21tb25BbmNlc3RvciA9IGZ1bmN0aW9uIChmaXJzdE5vZGUsIHNlY29uZE5vZGUpXG57XG4gIGlmIChmaXJzdE5vZGUgPT0gc2Vjb25kTm9kZSlcbiAge1xuICAgIHJldHVybiBmaXJzdE5vZGUuZ2V0T3duZXIoKTtcbiAgfVxuICB2YXIgZmlyc3RPd25lckdyYXBoID0gZmlyc3ROb2RlLmdldE93bmVyKCk7XG5cbiAgZG9cbiAge1xuICAgIGlmIChmaXJzdE93bmVyR3JhcGggPT0gbnVsbClcbiAgICB7XG4gICAgICBicmVhaztcbiAgICB9XG4gICAgdmFyIHNlY29uZE93bmVyR3JhcGggPSBzZWNvbmROb2RlLmdldE93bmVyKCk7XG5cbiAgICBkb1xuICAgIHtcbiAgICAgIGlmIChzZWNvbmRPd25lckdyYXBoID09IG51bGwpXG4gICAgICB7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuXG4gICAgICBpZiAoc2Vjb25kT3duZXJHcmFwaCA9PSBmaXJzdE93bmVyR3JhcGgpXG4gICAgICB7XG4gICAgICAgIHJldHVybiBzZWNvbmRPd25lckdyYXBoO1xuICAgICAgfVxuICAgICAgc2Vjb25kT3duZXJHcmFwaCA9IHNlY29uZE93bmVyR3JhcGguZ2V0UGFyZW50KCkuZ2V0T3duZXIoKTtcbiAgICB9IHdoaWxlICh0cnVlKTtcblxuICAgIGZpcnN0T3duZXJHcmFwaCA9IGZpcnN0T3duZXJHcmFwaC5nZXRQYXJlbnQoKS5nZXRPd25lcigpO1xuICB9IHdoaWxlICh0cnVlKTtcblxuICByZXR1cm4gZmlyc3RPd25lckdyYXBoO1xufTtcblxuTEdyYXBoTWFuYWdlci5wcm90b3R5cGUuY2FsY0luY2x1c2lvblRyZWVEZXB0aHMgPSBmdW5jdGlvbiAoZ3JhcGgsIGRlcHRoKSB7XG4gIGlmIChncmFwaCA9PSBudWxsICYmIGRlcHRoID09IG51bGwpIHtcbiAgICBncmFwaCA9IHRoaXMucm9vdEdyYXBoO1xuICAgIGRlcHRoID0gMTtcbiAgfVxuICB2YXIgbm9kZTtcblxuICB2YXIgbm9kZXMgPSBncmFwaC5nZXROb2RlcygpO1xuICB2YXIgcyA9IG5vZGVzLmxlbmd0aDtcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBzOyBpKyspXG4gIHtcbiAgICBub2RlID0gbm9kZXNbaV07XG4gICAgbm9kZS5pbmNsdXNpb25UcmVlRGVwdGggPSBkZXB0aDtcblxuICAgIGlmIChub2RlLmNoaWxkICE9IG51bGwpXG4gICAge1xuICAgICAgdGhpcy5jYWxjSW5jbHVzaW9uVHJlZURlcHRocyhub2RlLmNoaWxkLCBkZXB0aCArIDEpO1xuICAgIH1cbiAgfVxufTtcblxuTEdyYXBoTWFuYWdlci5wcm90b3R5cGUuaW5jbHVkZXNJbnZhbGlkRWRnZSA9IGZ1bmN0aW9uICgpXG57XG4gIHZhciBlZGdlO1xuXG4gIHZhciBzID0gdGhpcy5lZGdlcy5sZW5ndGg7XG4gIGZvciAodmFyIGkgPSAwOyBpIDwgczsgaSsrKVxuICB7XG4gICAgZWRnZSA9IHRoaXMuZWRnZXNbaV07XG5cbiAgICBpZiAodGhpcy5pc09uZUFuY2VzdG9yT2ZPdGhlcihlZGdlLnNvdXJjZSwgZWRnZS50YXJnZXQpKVxuICAgIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgfVxuICByZXR1cm4gZmFsc2U7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IExHcmFwaE1hbmFnZXI7XG4iLCJmdW5jdGlvbiBMR3JhcGhPYmplY3QodkdyYXBoT2JqZWN0KSB7XG4gIHRoaXMudkdyYXBoT2JqZWN0ID0gdkdyYXBoT2JqZWN0O1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IExHcmFwaE9iamVjdDtcbiIsInZhciBMR3JhcGhPYmplY3QgPSByZXF1aXJlKCcuL0xHcmFwaE9iamVjdCcpO1xudmFyIEludGVnZXIgPSByZXF1aXJlKCcuL0ludGVnZXInKTtcbnZhciBSZWN0YW5nbGVEID0gcmVxdWlyZSgnLi9SZWN0YW5nbGVEJyk7XG52YXIgTGF5b3V0Q29uc3RhbnRzID0gcmVxdWlyZSgnLi9MYXlvdXRDb25zdGFudHMnKTtcbnZhciBSYW5kb21TZWVkID0gcmVxdWlyZSgnLi9SYW5kb21TZWVkJyk7XG52YXIgUG9pbnREID0gcmVxdWlyZSgnLi9Qb2ludEQnKTtcbnZhciBIYXNoU2V0ID0gcmVxdWlyZSgnLi9IYXNoU2V0Jyk7XG5cbmZ1bmN0aW9uIExOb2RlKGdtLCBsb2MsIHNpemUsIHZOb2RlKSB7XG4gIC8vQWx0ZXJuYXRpdmUgY29uc3RydWN0b3IgMSA6IExOb2RlKExHcmFwaE1hbmFnZXIgZ20sIFBvaW50IGxvYywgRGltZW5zaW9uIHNpemUsIE9iamVjdCB2Tm9kZSlcbiAgaWYgKHNpemUgPT0gbnVsbCAmJiB2Tm9kZSA9PSBudWxsKSB7XG4gICAgdk5vZGUgPSBsb2M7XG4gIH1cblxuICBMR3JhcGhPYmplY3QuY2FsbCh0aGlzLCB2Tm9kZSk7XG5cbiAgLy9BbHRlcm5hdGl2ZSBjb25zdHJ1Y3RvciAyIDogTE5vZGUoTGF5b3V0IGxheW91dCwgT2JqZWN0IHZOb2RlKVxuICBpZiAoZ20uZ3JhcGhNYW5hZ2VyICE9IG51bGwpXG4gICAgZ20gPSBnbS5ncmFwaE1hbmFnZXI7XG5cbiAgdGhpcy5lc3RpbWF0ZWRTaXplID0gSW50ZWdlci5NSU5fVkFMVUU7XG4gIHRoaXMuaW5jbHVzaW9uVHJlZURlcHRoID0gSW50ZWdlci5NQVhfVkFMVUU7XG4gIHRoaXMudkdyYXBoT2JqZWN0ID0gdk5vZGU7XG4gIHRoaXMuZWRnZXMgPSBbXTtcbiAgdGhpcy5ncmFwaE1hbmFnZXIgPSBnbTtcblxuICBpZiAoc2l6ZSAhPSBudWxsICYmIGxvYyAhPSBudWxsKVxuICAgIHRoaXMucmVjdCA9IG5ldyBSZWN0YW5nbGVEKGxvYy54LCBsb2MueSwgc2l6ZS53aWR0aCwgc2l6ZS5oZWlnaHQpO1xuICBlbHNlXG4gICAgdGhpcy5yZWN0ID0gbmV3IFJlY3RhbmdsZUQoKTtcbn1cblxuTE5vZGUucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShMR3JhcGhPYmplY3QucHJvdG90eXBlKTtcbmZvciAodmFyIHByb3AgaW4gTEdyYXBoT2JqZWN0KSB7XG4gIExOb2RlW3Byb3BdID0gTEdyYXBoT2JqZWN0W3Byb3BdO1xufVxuXG5MTm9kZS5wcm90b3R5cGUuZ2V0RWRnZXMgPSBmdW5jdGlvbiAoKVxue1xuICByZXR1cm4gdGhpcy5lZGdlcztcbn07XG5cbkxOb2RlLnByb3RvdHlwZS5nZXRDaGlsZCA9IGZ1bmN0aW9uICgpXG57XG4gIHJldHVybiB0aGlzLmNoaWxkO1xufTtcblxuTE5vZGUucHJvdG90eXBlLmdldE93bmVyID0gZnVuY3Rpb24gKClcbntcbi8vICBpZiAodGhpcy5vd25lciAhPSBudWxsKSB7XG4vLyAgICBpZiAoISh0aGlzLm93bmVyID09IG51bGwgfHwgdGhpcy5vd25lci5nZXROb2RlcygpLmluZGV4T2YodGhpcykgPiAtMSkpIHtcbi8vICAgICAgdGhyb3cgXCJhc3NlcnQgZmFpbGVkXCI7XG4vLyAgICB9XG4vLyAgfVxuXG4gIHJldHVybiB0aGlzLm93bmVyO1xufTtcblxuTE5vZGUucHJvdG90eXBlLmdldFdpZHRoID0gZnVuY3Rpb24gKClcbntcbiAgcmV0dXJuIHRoaXMucmVjdC53aWR0aDtcbn07XG5cbkxOb2RlLnByb3RvdHlwZS5zZXRXaWR0aCA9IGZ1bmN0aW9uICh3aWR0aClcbntcbiAgdGhpcy5yZWN0LndpZHRoID0gd2lkdGg7XG59O1xuXG5MTm9kZS5wcm90b3R5cGUuZ2V0SGVpZ2h0ID0gZnVuY3Rpb24gKClcbntcbiAgcmV0dXJuIHRoaXMucmVjdC5oZWlnaHQ7XG59O1xuXG5MTm9kZS5wcm90b3R5cGUuc2V0SGVpZ2h0ID0gZnVuY3Rpb24gKGhlaWdodClcbntcbiAgdGhpcy5yZWN0LmhlaWdodCA9IGhlaWdodDtcbn07XG5cbkxOb2RlLnByb3RvdHlwZS5nZXRDZW50ZXJYID0gZnVuY3Rpb24gKClcbntcbiAgcmV0dXJuIHRoaXMucmVjdC54ICsgdGhpcy5yZWN0LndpZHRoIC8gMjtcbn07XG5cbkxOb2RlLnByb3RvdHlwZS5nZXRDZW50ZXJZID0gZnVuY3Rpb24gKClcbntcbiAgcmV0dXJuIHRoaXMucmVjdC55ICsgdGhpcy5yZWN0LmhlaWdodCAvIDI7XG59O1xuXG5MTm9kZS5wcm90b3R5cGUuZ2V0Q2VudGVyID0gZnVuY3Rpb24gKClcbntcbiAgcmV0dXJuIG5ldyBQb2ludEQodGhpcy5yZWN0LnggKyB0aGlzLnJlY3Qud2lkdGggLyAyLFxuICAgICAgICAgIHRoaXMucmVjdC55ICsgdGhpcy5yZWN0LmhlaWdodCAvIDIpO1xufTtcblxuTE5vZGUucHJvdG90eXBlLmdldExvY2F0aW9uID0gZnVuY3Rpb24gKClcbntcbiAgcmV0dXJuIG5ldyBQb2ludEQodGhpcy5yZWN0LngsIHRoaXMucmVjdC55KTtcbn07XG5cbkxOb2RlLnByb3RvdHlwZS5nZXRSZWN0ID0gZnVuY3Rpb24gKClcbntcbiAgcmV0dXJuIHRoaXMucmVjdDtcbn07XG5cbkxOb2RlLnByb3RvdHlwZS5nZXREaWFnb25hbCA9IGZ1bmN0aW9uICgpXG57XG4gIHJldHVybiBNYXRoLnNxcnQodGhpcy5yZWN0LndpZHRoICogdGhpcy5yZWN0LndpZHRoICtcbiAgICAgICAgICB0aGlzLnJlY3QuaGVpZ2h0ICogdGhpcy5yZWN0LmhlaWdodCk7XG59O1xuXG5MTm9kZS5wcm90b3R5cGUuc2V0UmVjdCA9IGZ1bmN0aW9uICh1cHBlckxlZnQsIGRpbWVuc2lvbilcbntcbiAgdGhpcy5yZWN0LnggPSB1cHBlckxlZnQueDtcbiAgdGhpcy5yZWN0LnkgPSB1cHBlckxlZnQueTtcbiAgdGhpcy5yZWN0LndpZHRoID0gZGltZW5zaW9uLndpZHRoO1xuICB0aGlzLnJlY3QuaGVpZ2h0ID0gZGltZW5zaW9uLmhlaWdodDtcbn07XG5cbkxOb2RlLnByb3RvdHlwZS5zZXRDZW50ZXIgPSBmdW5jdGlvbiAoY3gsIGN5KVxue1xuICB0aGlzLnJlY3QueCA9IGN4IC0gdGhpcy5yZWN0LndpZHRoIC8gMjtcbiAgdGhpcy5yZWN0LnkgPSBjeSAtIHRoaXMucmVjdC5oZWlnaHQgLyAyO1xufTtcblxuTE5vZGUucHJvdG90eXBlLnNldExvY2F0aW9uID0gZnVuY3Rpb24gKHgsIHkpXG57XG4gIHRoaXMucmVjdC54ID0geDtcbiAgdGhpcy5yZWN0LnkgPSB5O1xufTtcblxuTE5vZGUucHJvdG90eXBlLm1vdmVCeSA9IGZ1bmN0aW9uIChkeCwgZHkpXG57XG4gIHRoaXMucmVjdC54ICs9IGR4O1xuICB0aGlzLnJlY3QueSArPSBkeTtcbn07XG5cbkxOb2RlLnByb3RvdHlwZS5nZXRFZGdlTGlzdFRvTm9kZSA9IGZ1bmN0aW9uICh0bylcbntcbiAgdmFyIGVkZ2VMaXN0ID0gW107XG4gIHZhciBlZGdlO1xuICB2YXIgc2VsZiA9IHRoaXM7XG5cbiAgc2VsZi5lZGdlcy5mb3JFYWNoKGZ1bmN0aW9uKGVkZ2UpIHtcbiAgICBcbiAgICBpZiAoZWRnZS50YXJnZXQgPT0gdG8pXG4gICAge1xuICAgICAgaWYgKGVkZ2Uuc291cmNlICE9IHNlbGYpXG4gICAgICAgIHRocm93IFwiSW5jb3JyZWN0IGVkZ2Ugc291cmNlIVwiO1xuXG4gICAgICBlZGdlTGlzdC5wdXNoKGVkZ2UpO1xuICAgIH1cbiAgfSk7XG5cbiAgcmV0dXJuIGVkZ2VMaXN0O1xufTtcblxuTE5vZGUucHJvdG90eXBlLmdldEVkZ2VzQmV0d2VlbiA9IGZ1bmN0aW9uIChvdGhlcilcbntcbiAgdmFyIGVkZ2VMaXN0ID0gW107XG4gIHZhciBlZGdlO1xuICBcbiAgdmFyIHNlbGYgPSB0aGlzO1xuICBzZWxmLmVkZ2VzLmZvckVhY2goZnVuY3Rpb24oZWRnZSkge1xuXG4gICAgaWYgKCEoZWRnZS5zb3VyY2UgPT0gc2VsZiB8fCBlZGdlLnRhcmdldCA9PSBzZWxmKSlcbiAgICAgIHRocm93IFwiSW5jb3JyZWN0IGVkZ2Ugc291cmNlIGFuZC9vciB0YXJnZXRcIjtcblxuICAgIGlmICgoZWRnZS50YXJnZXQgPT0gb3RoZXIpIHx8IChlZGdlLnNvdXJjZSA9PSBvdGhlcikpXG4gICAge1xuICAgICAgZWRnZUxpc3QucHVzaChlZGdlKTtcbiAgICB9XG4gIH0pO1xuXG4gIHJldHVybiBlZGdlTGlzdDtcbn07XG5cbkxOb2RlLnByb3RvdHlwZS5nZXROZWlnaGJvcnNMaXN0ID0gZnVuY3Rpb24gKClcbntcbiAgdmFyIG5laWdoYm9ycyA9IG5ldyBIYXNoU2V0KCk7XG4gIHZhciBlZGdlO1xuICBcbiAgdmFyIHNlbGYgPSB0aGlzO1xuICBzZWxmLmVkZ2VzLmZvckVhY2goZnVuY3Rpb24oZWRnZSkge1xuXG4gICAgaWYgKGVkZ2Uuc291cmNlID09IHNlbGYpXG4gICAge1xuICAgICAgbmVpZ2hib3JzLmFkZChlZGdlLnRhcmdldCk7XG4gICAgfVxuICAgIGVsc2VcbiAgICB7XG4gICAgICBpZiAoZWRnZS50YXJnZXQgIT0gc2VsZikge1xuICAgICAgICB0aHJvdyBcIkluY29ycmVjdCBpbmNpZGVuY3khXCI7XG4gICAgICB9XG4gICAgXG4gICAgICBuZWlnaGJvcnMuYWRkKGVkZ2Uuc291cmNlKTtcbiAgICB9XG4gIH0pO1xuXG4gIHJldHVybiBuZWlnaGJvcnM7XG59O1xuXG5MTm9kZS5wcm90b3R5cGUud2l0aENoaWxkcmVuID0gZnVuY3Rpb24gKClcbntcbiAgdmFyIHdpdGhOZWlnaGJvcnNMaXN0ID0gbmV3IFNldCgpO1xuICB2YXIgY2hpbGROb2RlO1xuICB2YXIgY2hpbGRyZW47XG5cbiAgd2l0aE5laWdoYm9yc0xpc3QuYWRkKHRoaXMpO1xuXG4gIGlmICh0aGlzLmNoaWxkICE9IG51bGwpXG4gIHtcbiAgICB2YXIgbm9kZXMgPSB0aGlzLmNoaWxkLmdldE5vZGVzKCk7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBub2Rlcy5sZW5ndGg7IGkrKylcbiAgICB7XG4gICAgICBjaGlsZE5vZGUgPSBub2Rlc1tpXTtcbiAgICAgIGNoaWxkcmVuID0gY2hpbGROb2RlLndpdGhDaGlsZHJlbigpO1xuICAgICAgY2hpbGRyZW4uZm9yRWFjaChmdW5jdGlvbihub2RlKSB7XG4gICAgICAgIHdpdGhOZWlnaGJvcnNMaXN0LmFkZChub2RlKTtcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiB3aXRoTmVpZ2hib3JzTGlzdDtcbn07XG5cbkxOb2RlLnByb3RvdHlwZS5nZXROb09mQ2hpbGRyZW4gPSBmdW5jdGlvbiAoKVxue1xuICB2YXIgbm9PZkNoaWxkcmVuID0gMDtcbiAgdmFyIGNoaWxkTm9kZTtcblxuICBpZih0aGlzLmNoaWxkID09IG51bGwpe1xuICAgIG5vT2ZDaGlsZHJlbiA9IDE7XG4gIH1cbiAgZWxzZVxuICB7XG4gICAgdmFyIG5vZGVzID0gdGhpcy5jaGlsZC5nZXROb2RlcygpO1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbm9kZXMubGVuZ3RoOyBpKyspXG4gICAge1xuICAgICAgY2hpbGROb2RlID0gbm9kZXNbaV07XG5cbiAgICAgIG5vT2ZDaGlsZHJlbiArPSBjaGlsZE5vZGUuZ2V0Tm9PZkNoaWxkcmVuKCk7XG4gICAgfVxuICB9XG4gIFxuICBpZihub09mQ2hpbGRyZW4gPT0gMCl7XG4gICAgbm9PZkNoaWxkcmVuID0gMTtcbiAgfVxuICByZXR1cm4gbm9PZkNoaWxkcmVuO1xufTtcblxuTE5vZGUucHJvdG90eXBlLmdldEVzdGltYXRlZFNpemUgPSBmdW5jdGlvbiAoKSB7XG4gIGlmICh0aGlzLmVzdGltYXRlZFNpemUgPT0gSW50ZWdlci5NSU5fVkFMVUUpIHtcbiAgICB0aHJvdyBcImFzc2VydCBmYWlsZWRcIjtcbiAgfVxuICByZXR1cm4gdGhpcy5lc3RpbWF0ZWRTaXplO1xufTtcblxuTE5vZGUucHJvdG90eXBlLmNhbGNFc3RpbWF0ZWRTaXplID0gZnVuY3Rpb24gKCkge1xuICBpZiAodGhpcy5jaGlsZCA9PSBudWxsKVxuICB7XG4gICAgcmV0dXJuIHRoaXMuZXN0aW1hdGVkU2l6ZSA9ICh0aGlzLnJlY3Qud2lkdGggKyB0aGlzLnJlY3QuaGVpZ2h0KSAvIDI7XG4gIH1cbiAgZWxzZVxuICB7XG4gICAgdGhpcy5lc3RpbWF0ZWRTaXplID0gdGhpcy5jaGlsZC5jYWxjRXN0aW1hdGVkU2l6ZSgpO1xuICAgIHRoaXMucmVjdC53aWR0aCA9IHRoaXMuZXN0aW1hdGVkU2l6ZTtcbiAgICB0aGlzLnJlY3QuaGVpZ2h0ID0gdGhpcy5lc3RpbWF0ZWRTaXplO1xuXG4gICAgcmV0dXJuIHRoaXMuZXN0aW1hdGVkU2l6ZTtcbiAgfVxufTtcblxuTE5vZGUucHJvdG90eXBlLnNjYXR0ZXIgPSBmdW5jdGlvbiAoKSB7XG4gIHZhciByYW5kb21DZW50ZXJYO1xuICB2YXIgcmFuZG9tQ2VudGVyWTtcblxuICB2YXIgbWluWCA9IC1MYXlvdXRDb25zdGFudHMuSU5JVElBTF9XT1JMRF9CT1VOREFSWTtcbiAgdmFyIG1heFggPSBMYXlvdXRDb25zdGFudHMuSU5JVElBTF9XT1JMRF9CT1VOREFSWTtcbiAgcmFuZG9tQ2VudGVyWCA9IExheW91dENvbnN0YW50cy5XT1JMRF9DRU5URVJfWCArXG4gICAgICAgICAgKFJhbmRvbVNlZWQubmV4dERvdWJsZSgpICogKG1heFggLSBtaW5YKSkgKyBtaW5YO1xuXG4gIHZhciBtaW5ZID0gLUxheW91dENvbnN0YW50cy5JTklUSUFMX1dPUkxEX0JPVU5EQVJZO1xuICB2YXIgbWF4WSA9IExheW91dENvbnN0YW50cy5JTklUSUFMX1dPUkxEX0JPVU5EQVJZO1xuICByYW5kb21DZW50ZXJZID0gTGF5b3V0Q29uc3RhbnRzLldPUkxEX0NFTlRFUl9ZICtcbiAgICAgICAgICAoUmFuZG9tU2VlZC5uZXh0RG91YmxlKCkgKiAobWF4WSAtIG1pblkpKSArIG1pblk7XG5cbiAgdGhpcy5yZWN0LnggPSByYW5kb21DZW50ZXJYO1xuICB0aGlzLnJlY3QueSA9IHJhbmRvbUNlbnRlcllcbn07XG5cbkxOb2RlLnByb3RvdHlwZS51cGRhdGVCb3VuZHMgPSBmdW5jdGlvbiAoKSB7XG4gIGlmICh0aGlzLmdldENoaWxkKCkgPT0gbnVsbCkge1xuICAgIHRocm93IFwiYXNzZXJ0IGZhaWxlZFwiO1xuICB9XG4gIGlmICh0aGlzLmdldENoaWxkKCkuZ2V0Tm9kZXMoKS5sZW5ndGggIT0gMClcbiAge1xuICAgIC8vIHdyYXAgdGhlIGNoaWxkcmVuIG5vZGVzIGJ5IHJlLWFycmFuZ2luZyB0aGUgYm91bmRhcmllc1xuICAgIHZhciBjaGlsZEdyYXBoID0gdGhpcy5nZXRDaGlsZCgpO1xuICAgIGNoaWxkR3JhcGgudXBkYXRlQm91bmRzKHRydWUpO1xuXG4gICAgdGhpcy5yZWN0LnggPSBjaGlsZEdyYXBoLmdldExlZnQoKTtcbiAgICB0aGlzLnJlY3QueSA9IGNoaWxkR3JhcGguZ2V0VG9wKCk7XG5cbiAgICB0aGlzLnNldFdpZHRoKGNoaWxkR3JhcGguZ2V0UmlnaHQoKSAtIGNoaWxkR3JhcGguZ2V0TGVmdCgpKTtcbiAgICB0aGlzLnNldEhlaWdodChjaGlsZEdyYXBoLmdldEJvdHRvbSgpIC0gY2hpbGRHcmFwaC5nZXRUb3AoKSk7XG4gICAgXG4gICAgLy8gVXBkYXRlIGNvbXBvdW5kIGJvdW5kcyBjb25zaWRlcmluZyBpdHMgbGFiZWwgcHJvcGVydGllcyAgICBcbiAgICBpZihMYXlvdXRDb25zdGFudHMuTk9ERV9ESU1FTlNJT05TX0lOQ0xVREVfTEFCRUxTKXtcbiAgICAgICAgXG4gICAgICB2YXIgd2lkdGggPSBjaGlsZEdyYXBoLmdldFJpZ2h0KCkgLSBjaGlsZEdyYXBoLmdldExlZnQoKTtcbiAgICAgIHZhciBoZWlnaHQgPSBjaGlsZEdyYXBoLmdldEJvdHRvbSgpIC0gY2hpbGRHcmFwaC5nZXRUb3AoKTtcblxuICAgICAgaWYodGhpcy5sYWJlbFdpZHRoID4gd2lkdGgpe1xuICAgICAgICB0aGlzLnJlY3QueCAtPSAodGhpcy5sYWJlbFdpZHRoIC0gd2lkdGgpIC8gMjtcbiAgICAgICAgdGhpcy5zZXRXaWR0aCh0aGlzLmxhYmVsV2lkdGgpO1xuICAgICAgfVxuXG4gICAgICBpZih0aGlzLmxhYmVsSGVpZ2h0ID4gaGVpZ2h0KXtcbiAgICAgICAgaWYodGhpcy5sYWJlbFBvcyA9PSBcImNlbnRlclwiKXtcbiAgICAgICAgICB0aGlzLnJlY3QueSAtPSAodGhpcy5sYWJlbEhlaWdodCAtIGhlaWdodCkgLyAyO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYodGhpcy5sYWJlbFBvcyA9PSBcInRvcFwiKXtcbiAgICAgICAgICB0aGlzLnJlY3QueSAtPSAodGhpcy5sYWJlbEhlaWdodCAtIGhlaWdodCk7IFxuICAgICAgICB9XG4gICAgICAgIHRoaXMuc2V0SGVpZ2h0KHRoaXMubGFiZWxIZWlnaHQpO1xuICAgICAgfVxuICAgIH1cbiAgfVxufTtcblxuTE5vZGUucHJvdG90eXBlLmdldEluY2x1c2lvblRyZWVEZXB0aCA9IGZ1bmN0aW9uICgpXG57XG4gIGlmICh0aGlzLmluY2x1c2lvblRyZWVEZXB0aCA9PSBJbnRlZ2VyLk1BWF9WQUxVRSkge1xuICAgIHRocm93IFwiYXNzZXJ0IGZhaWxlZFwiO1xuICB9XG4gIHJldHVybiB0aGlzLmluY2x1c2lvblRyZWVEZXB0aDtcbn07XG5cbkxOb2RlLnByb3RvdHlwZS50cmFuc2Zvcm0gPSBmdW5jdGlvbiAodHJhbnMpXG57XG4gIHZhciBsZWZ0ID0gdGhpcy5yZWN0Lng7XG5cbiAgaWYgKGxlZnQgPiBMYXlvdXRDb25zdGFudHMuV09STERfQk9VTkRBUlkpXG4gIHtcbiAgICBsZWZ0ID0gTGF5b3V0Q29uc3RhbnRzLldPUkxEX0JPVU5EQVJZO1xuICB9XG4gIGVsc2UgaWYgKGxlZnQgPCAtTGF5b3V0Q29uc3RhbnRzLldPUkxEX0JPVU5EQVJZKVxuICB7XG4gICAgbGVmdCA9IC1MYXlvdXRDb25zdGFudHMuV09STERfQk9VTkRBUlk7XG4gIH1cblxuICB2YXIgdG9wID0gdGhpcy5yZWN0Lnk7XG5cbiAgaWYgKHRvcCA+IExheW91dENvbnN0YW50cy5XT1JMRF9CT1VOREFSWSlcbiAge1xuICAgIHRvcCA9IExheW91dENvbnN0YW50cy5XT1JMRF9CT1VOREFSWTtcbiAgfVxuICBlbHNlIGlmICh0b3AgPCAtTGF5b3V0Q29uc3RhbnRzLldPUkxEX0JPVU5EQVJZKVxuICB7XG4gICAgdG9wID0gLUxheW91dENvbnN0YW50cy5XT1JMRF9CT1VOREFSWTtcbiAgfVxuXG4gIHZhciBsZWZ0VG9wID0gbmV3IFBvaW50RChsZWZ0LCB0b3ApO1xuICB2YXIgdkxlZnRUb3AgPSB0cmFucy5pbnZlcnNlVHJhbnNmb3JtUG9pbnQobGVmdFRvcCk7XG5cbiAgdGhpcy5zZXRMb2NhdGlvbih2TGVmdFRvcC54LCB2TGVmdFRvcC55KTtcbn07XG5cbkxOb2RlLnByb3RvdHlwZS5nZXRMZWZ0ID0gZnVuY3Rpb24gKClcbntcbiAgcmV0dXJuIHRoaXMucmVjdC54O1xufTtcblxuTE5vZGUucHJvdG90eXBlLmdldFJpZ2h0ID0gZnVuY3Rpb24gKClcbntcbiAgcmV0dXJuIHRoaXMucmVjdC54ICsgdGhpcy5yZWN0LndpZHRoO1xufTtcblxuTE5vZGUucHJvdG90eXBlLmdldFRvcCA9IGZ1bmN0aW9uICgpXG57XG4gIHJldHVybiB0aGlzLnJlY3QueTtcbn07XG5cbkxOb2RlLnByb3RvdHlwZS5nZXRCb3R0b20gPSBmdW5jdGlvbiAoKVxue1xuICByZXR1cm4gdGhpcy5yZWN0LnkgKyB0aGlzLnJlY3QuaGVpZ2h0O1xufTtcblxuTE5vZGUucHJvdG90eXBlLmdldFBhcmVudCA9IGZ1bmN0aW9uICgpXG57XG4gIGlmICh0aGlzLm93bmVyID09IG51bGwpXG4gIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIHJldHVybiB0aGlzLm93bmVyLmdldFBhcmVudCgpO1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSBMTm9kZTtcbiIsInZhciBMYXlvdXRDb25zdGFudHMgPSByZXF1aXJlKCcuL0xheW91dENvbnN0YW50cycpO1xudmFyIEhhc2hNYXAgPSByZXF1aXJlKCcuL0hhc2hNYXAnKTtcbnZhciBMR3JhcGhNYW5hZ2VyID0gcmVxdWlyZSgnLi9MR3JhcGhNYW5hZ2VyJyk7XG52YXIgTE5vZGUgPSByZXF1aXJlKCcuL0xOb2RlJyk7XG52YXIgTEVkZ2UgPSByZXF1aXJlKCcuL0xFZGdlJyk7XG52YXIgTEdyYXBoID0gcmVxdWlyZSgnLi9MR3JhcGgnKTtcbnZhciBQb2ludEQgPSByZXF1aXJlKCcuL1BvaW50RCcpO1xudmFyIFRyYW5zZm9ybSA9IHJlcXVpcmUoJy4vVHJhbnNmb3JtJyk7XG52YXIgRW1pdHRlciA9IHJlcXVpcmUoJy4vRW1pdHRlcicpO1xudmFyIEhhc2hTZXQgPSByZXF1aXJlKCcuL0hhc2hTZXQnKTtcblxuZnVuY3Rpb24gTGF5b3V0KGlzUmVtb3RlVXNlKSB7XG4gIEVtaXR0ZXIuY2FsbCggdGhpcyApO1xuXG4gIC8vTGF5b3V0IFF1YWxpdHk6IDA6cHJvb2YsIDE6ZGVmYXVsdCwgMjpkcmFmdFxuICB0aGlzLmxheW91dFF1YWxpdHkgPSBMYXlvdXRDb25zdGFudHMuREVGQVVMVF9RVUFMSVRZO1xuICAvL1doZXRoZXIgbGF5b3V0IHNob3VsZCBjcmVhdGUgYmVuZHBvaW50cyBhcyBuZWVkZWQgb3Igbm90XG4gIHRoaXMuY3JlYXRlQmVuZHNBc05lZWRlZCA9XG4gICAgICAgICAgTGF5b3V0Q29uc3RhbnRzLkRFRkFVTFRfQ1JFQVRFX0JFTkRTX0FTX05FRURFRDtcbiAgLy9XaGV0aGVyIGxheW91dCBzaG91bGQgYmUgaW5jcmVtZW50YWwgb3Igbm90XG4gIHRoaXMuaW5jcmVtZW50YWwgPSBMYXlvdXRDb25zdGFudHMuREVGQVVMVF9JTkNSRU1FTlRBTDtcbiAgLy9XaGV0aGVyIHdlIGFuaW1hdGUgZnJvbSBiZWZvcmUgdG8gYWZ0ZXIgbGF5b3V0IG5vZGUgcG9zaXRpb25zXG4gIHRoaXMuYW5pbWF0aW9uT25MYXlvdXQgPVxuICAgICAgICAgIExheW91dENvbnN0YW50cy5ERUZBVUxUX0FOSU1BVElPTl9PTl9MQVlPVVQ7XG4gIC8vV2hldGhlciB3ZSBhbmltYXRlIHRoZSBsYXlvdXQgcHJvY2VzcyBvciBub3RcbiAgdGhpcy5hbmltYXRpb25EdXJpbmdMYXlvdXQgPSBMYXlvdXRDb25zdGFudHMuREVGQVVMVF9BTklNQVRJT05fRFVSSU5HX0xBWU9VVDtcbiAgLy9OdW1iZXIgaXRlcmF0aW9ucyB0aGF0IHNob3VsZCBiZSBkb25lIGJldHdlZW4gdHdvIHN1Y2Nlc3NpdmUgYW5pbWF0aW9uc1xuICB0aGlzLmFuaW1hdGlvblBlcmlvZCA9IExheW91dENvbnN0YW50cy5ERUZBVUxUX0FOSU1BVElPTl9QRVJJT0Q7XG4gIC8qKlxuICAgKiBXaGV0aGVyIG9yIG5vdCBsZWFmIG5vZGVzIChub24tY29tcG91bmQgbm9kZXMpIGFyZSBvZiB1bmlmb3JtIHNpemVzLiBXaGVuXG4gICAqIHRoZXkgYXJlLCBib3RoIHNwcmluZyBhbmQgcmVwdWxzaW9uIGZvcmNlcyBiZXR3ZWVuIHR3byBsZWFmIG5vZGVzIGNhbiBiZVxuICAgKiBjYWxjdWxhdGVkIHdpdGhvdXQgdGhlIGV4cGVuc2l2ZSBjbGlwcGluZyBwb2ludCBjYWxjdWxhdGlvbnMsIHJlc3VsdGluZ1xuICAgKiBpbiBtYWpvciBzcGVlZC11cC5cbiAgICovXG4gIHRoaXMudW5pZm9ybUxlYWZOb2RlU2l6ZXMgPVxuICAgICAgICAgIExheW91dENvbnN0YW50cy5ERUZBVUxUX1VOSUZPUk1fTEVBRl9OT0RFX1NJWkVTO1xuICAvKipcbiAgICogVGhpcyBpcyB1c2VkIGZvciBjcmVhdGlvbiBvZiBiZW5kcG9pbnRzIGJ5IHVzaW5nIGR1bW15IG5vZGVzIGFuZCBlZGdlcy5cbiAgICogTWFwcyBhbiBMRWRnZSB0byBpdHMgZHVtbXkgYmVuZHBvaW50IHBhdGguXG4gICAqL1xuICB0aGlzLmVkZ2VUb0R1bW15Tm9kZXMgPSBuZXcgSGFzaE1hcCgpO1xuICB0aGlzLmdyYXBoTWFuYWdlciA9IG5ldyBMR3JhcGhNYW5hZ2VyKHRoaXMpO1xuICB0aGlzLmlzTGF5b3V0RmluaXNoZWQgPSBmYWxzZTtcbiAgdGhpcy5pc1N1YkxheW91dCA9IGZhbHNlO1xuICB0aGlzLmlzUmVtb3RlVXNlID0gZmFsc2U7XG5cbiAgaWYgKGlzUmVtb3RlVXNlICE9IG51bGwpIHtcbiAgICB0aGlzLmlzUmVtb3RlVXNlID0gaXNSZW1vdGVVc2U7XG4gIH1cbn1cblxuTGF5b3V0LlJBTkRPTV9TRUVEID0gMTtcblxuTGF5b3V0LnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoIEVtaXR0ZXIucHJvdG90eXBlICk7XG5cbkxheW91dC5wcm90b3R5cGUuZ2V0R3JhcGhNYW5hZ2VyID0gZnVuY3Rpb24gKCkge1xuICByZXR1cm4gdGhpcy5ncmFwaE1hbmFnZXI7XG59O1xuXG5MYXlvdXQucHJvdG90eXBlLmdldEFsbE5vZGVzID0gZnVuY3Rpb24gKCkge1xuICByZXR1cm4gdGhpcy5ncmFwaE1hbmFnZXIuZ2V0QWxsTm9kZXMoKTtcbn07XG5cbkxheW91dC5wcm90b3R5cGUuZ2V0QWxsRWRnZXMgPSBmdW5jdGlvbiAoKSB7XG4gIHJldHVybiB0aGlzLmdyYXBoTWFuYWdlci5nZXRBbGxFZGdlcygpO1xufTtcblxuTGF5b3V0LnByb3RvdHlwZS5nZXRBbGxOb2Rlc1RvQXBwbHlHcmF2aXRhdGlvbiA9IGZ1bmN0aW9uICgpIHtcbiAgcmV0dXJuIHRoaXMuZ3JhcGhNYW5hZ2VyLmdldEFsbE5vZGVzVG9BcHBseUdyYXZpdGF0aW9uKCk7XG59O1xuXG5MYXlvdXQucHJvdG90eXBlLm5ld0dyYXBoTWFuYWdlciA9IGZ1bmN0aW9uICgpIHtcbiAgdmFyIGdtID0gbmV3IExHcmFwaE1hbmFnZXIodGhpcyk7XG4gIHRoaXMuZ3JhcGhNYW5hZ2VyID0gZ207XG4gIHJldHVybiBnbTtcbn07XG5cbkxheW91dC5wcm90b3R5cGUubmV3R3JhcGggPSBmdW5jdGlvbiAodkdyYXBoKVxue1xuICByZXR1cm4gbmV3IExHcmFwaChudWxsLCB0aGlzLmdyYXBoTWFuYWdlciwgdkdyYXBoKTtcbn07XG5cbkxheW91dC5wcm90b3R5cGUubmV3Tm9kZSA9IGZ1bmN0aW9uICh2Tm9kZSlcbntcbiAgcmV0dXJuIG5ldyBMTm9kZSh0aGlzLmdyYXBoTWFuYWdlciwgdk5vZGUpO1xufTtcblxuTGF5b3V0LnByb3RvdHlwZS5uZXdFZGdlID0gZnVuY3Rpb24gKHZFZGdlKVxue1xuICByZXR1cm4gbmV3IExFZGdlKG51bGwsIG51bGwsIHZFZGdlKTtcbn07XG5cbkxheW91dC5wcm90b3R5cGUuY2hlY2tMYXlvdXRTdWNjZXNzID0gZnVuY3Rpb24oKSB7XG4gIHJldHVybiAodGhpcy5ncmFwaE1hbmFnZXIuZ2V0Um9vdCgpID09IG51bGwpXG4gICAgICAgICAgfHwgdGhpcy5ncmFwaE1hbmFnZXIuZ2V0Um9vdCgpLmdldE5vZGVzKCkubGVuZ3RoID09IDBcbiAgICAgICAgICB8fCB0aGlzLmdyYXBoTWFuYWdlci5pbmNsdWRlc0ludmFsaWRFZGdlKCk7XG59O1xuXG5MYXlvdXQucHJvdG90eXBlLnJ1bkxheW91dCA9IGZ1bmN0aW9uICgpXG57XG4gIHRoaXMuaXNMYXlvdXRGaW5pc2hlZCA9IGZhbHNlO1xuICBcbiAgaWYgKHRoaXMudGlsaW5nUHJlTGF5b3V0KSB7XG4gICAgdGhpcy50aWxpbmdQcmVMYXlvdXQoKTtcbiAgfVxuXG4gIHRoaXMuaW5pdFBhcmFtZXRlcnMoKTtcbiAgdmFyIGlzTGF5b3V0U3VjY2Vzc2Z1bGw7XG5cbiAgaWYgKHRoaXMuY2hlY2tMYXlvdXRTdWNjZXNzKCkpXG4gIHtcbiAgICBpc0xheW91dFN1Y2Nlc3NmdWxsID0gZmFsc2U7XG4gIH1cbiAgZWxzZVxuICB7XG4gICAgaXNMYXlvdXRTdWNjZXNzZnVsbCA9IHRoaXMubGF5b3V0KCk7XG4gIH1cbiAgXG4gIGlmIChMYXlvdXRDb25zdGFudHMuQU5JTUFURSA9PT0gJ2R1cmluZycpIHtcbiAgICAvLyBJZiB0aGlzIGlzIGEgJ2R1cmluZycgbGF5b3V0IGFuaW1hdGlvbi4gTGF5b3V0IGlzIG5vdCBmaW5pc2hlZCB5ZXQuIFxuICAgIC8vIFdlIG5lZWQgdG8gcGVyZm9ybSB0aGVzZSBpbiBpbmRleC5qcyB3aGVuIGxheW91dCBpcyByZWFsbHkgZmluaXNoZWQuXG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG4gIFxuICBpZiAoaXNMYXlvdXRTdWNjZXNzZnVsbClcbiAge1xuICAgIGlmICghdGhpcy5pc1N1YkxheW91dClcbiAgICB7XG4gICAgICB0aGlzLmRvUG9zdExheW91dCgpO1xuICAgIH1cbiAgfVxuXG4gIGlmICh0aGlzLnRpbGluZ1Bvc3RMYXlvdXQpIHtcbiAgICB0aGlzLnRpbGluZ1Bvc3RMYXlvdXQoKTtcbiAgfVxuXG4gIHRoaXMuaXNMYXlvdXRGaW5pc2hlZCA9IHRydWU7XG5cbiAgcmV0dXJuIGlzTGF5b3V0U3VjY2Vzc2Z1bGw7XG59O1xuXG4vKipcbiAqIFRoaXMgbWV0aG9kIHBlcmZvcm1zIHRoZSBvcGVyYXRpb25zIHJlcXVpcmVkIGFmdGVyIGxheW91dC5cbiAqL1xuTGF5b3V0LnByb3RvdHlwZS5kb1Bvc3RMYXlvdXQgPSBmdW5jdGlvbiAoKVxue1xuICAvL2Fzc2VydCAhaXNTdWJMYXlvdXQgOiBcIlNob3VsZCBub3QgYmUgY2FsbGVkIG9uIHN1Yi1sYXlvdXQhXCI7XG4gIC8vIFByb3BhZ2F0ZSBnZW9tZXRyaWMgY2hhbmdlcyB0byB2LWxldmVsIG9iamVjdHNcbiAgaWYoIXRoaXMuaW5jcmVtZW50YWwpe1xuICAgIHRoaXMudHJhbnNmb3JtKCk7XG4gIH1cbiAgdGhpcy51cGRhdGUoKTtcbn07XG5cbi8qKlxuICogVGhpcyBtZXRob2QgdXBkYXRlcyB0aGUgZ2VvbWV0cnkgb2YgdGhlIHRhcmdldCBncmFwaCBhY2NvcmRpbmcgdG9cbiAqIGNhbGN1bGF0ZWQgbGF5b3V0LlxuICovXG5MYXlvdXQucHJvdG90eXBlLnVwZGF0ZTIgPSBmdW5jdGlvbiAoKSB7XG4gIC8vIHVwZGF0ZSBiZW5kIHBvaW50c1xuICBpZiAodGhpcy5jcmVhdGVCZW5kc0FzTmVlZGVkKVxuICB7XG4gICAgdGhpcy5jcmVhdGVCZW5kcG9pbnRzRnJvbUR1bW15Tm9kZXMoKTtcblxuICAgIC8vIHJlc2V0IGFsbCBlZGdlcywgc2luY2UgdGhlIHRvcG9sb2d5IGhhcyBjaGFuZ2VkXG4gICAgdGhpcy5ncmFwaE1hbmFnZXIucmVzZXRBbGxFZGdlcygpO1xuICB9XG5cbiAgLy8gcGVyZm9ybSBlZGdlLCBub2RlIGFuZCByb290IHVwZGF0ZXMgaWYgbGF5b3V0IGlzIG5vdCBjYWxsZWRcbiAgLy8gcmVtb3RlbHlcbiAgaWYgKCF0aGlzLmlzUmVtb3RlVXNlKVxuICB7XG4gICAgLy8gdXBkYXRlIGFsbCBlZGdlc1xuICAgIHZhciBlZGdlO1xuICAgIHZhciBhbGxFZGdlcyA9IHRoaXMuZ3JhcGhNYW5hZ2VyLmdldEFsbEVkZ2VzKCk7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBhbGxFZGdlcy5sZW5ndGg7IGkrKylcbiAgICB7XG4gICAgICBlZGdlID0gYWxsRWRnZXNbaV07XG4vLyAgICAgIHRoaXMudXBkYXRlKGVkZ2UpO1xuICAgIH1cblxuICAgIC8vIHJlY3Vyc2l2ZWx5IHVwZGF0ZSBub2Rlc1xuICAgIHZhciBub2RlO1xuICAgIHZhciBub2RlcyA9IHRoaXMuZ3JhcGhNYW5hZ2VyLmdldFJvb3QoKS5nZXROb2RlcygpO1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbm9kZXMubGVuZ3RoOyBpKyspXG4gICAge1xuICAgICAgbm9kZSA9IG5vZGVzW2ldO1xuLy8gICAgICB0aGlzLnVwZGF0ZShub2RlKTtcbiAgICB9XG5cbiAgICAvLyB1cGRhdGUgcm9vdCBncmFwaFxuICAgIHRoaXMudXBkYXRlKHRoaXMuZ3JhcGhNYW5hZ2VyLmdldFJvb3QoKSk7XG4gIH1cbn07XG5cbkxheW91dC5wcm90b3R5cGUudXBkYXRlID0gZnVuY3Rpb24gKG9iaikge1xuICBpZiAob2JqID09IG51bGwpIHtcbiAgICB0aGlzLnVwZGF0ZTIoKTtcbiAgfVxuICBlbHNlIGlmIChvYmogaW5zdGFuY2VvZiBMTm9kZSkge1xuICAgIHZhciBub2RlID0gb2JqO1xuICAgIGlmIChub2RlLmdldENoaWxkKCkgIT0gbnVsbClcbiAgICB7XG4gICAgICAvLyBzaW5jZSBub2RlIGlzIGNvbXBvdW5kLCByZWN1cnNpdmVseSB1cGRhdGUgY2hpbGQgbm9kZXNcbiAgICAgIHZhciBub2RlcyA9IG5vZGUuZ2V0Q2hpbGQoKS5nZXROb2RlcygpO1xuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBub2Rlcy5sZW5ndGg7IGkrKylcbiAgICAgIHtcbiAgICAgICAgdXBkYXRlKG5vZGVzW2ldKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBpZiB0aGUgbC1sZXZlbCBub2RlIGlzIGFzc29jaWF0ZWQgd2l0aCBhIHYtbGV2ZWwgZ3JhcGggb2JqZWN0LFxuICAgIC8vIHRoZW4gaXQgaXMgYXNzdW1lZCB0aGF0IHRoZSB2LWxldmVsIG5vZGUgaW1wbGVtZW50cyB0aGVcbiAgICAvLyBpbnRlcmZhY2UgVXBkYXRhYmxlLlxuICAgIGlmIChub2RlLnZHcmFwaE9iamVjdCAhPSBudWxsKVxuICAgIHtcbiAgICAgIC8vIGNhc3QgdG8gVXBkYXRhYmxlIHdpdGhvdXQgYW55IHR5cGUgY2hlY2tcbiAgICAgIHZhciB2Tm9kZSA9IG5vZGUudkdyYXBoT2JqZWN0O1xuXG4gICAgICAvLyBjYWxsIHRoZSB1cGRhdGUgbWV0aG9kIG9mIHRoZSBpbnRlcmZhY2VcbiAgICAgIHZOb2RlLnVwZGF0ZShub2RlKTtcbiAgICB9XG4gIH1cbiAgZWxzZSBpZiAob2JqIGluc3RhbmNlb2YgTEVkZ2UpIHtcbiAgICB2YXIgZWRnZSA9IG9iajtcbiAgICAvLyBpZiB0aGUgbC1sZXZlbCBlZGdlIGlzIGFzc29jaWF0ZWQgd2l0aCBhIHYtbGV2ZWwgZ3JhcGggb2JqZWN0LFxuICAgIC8vIHRoZW4gaXQgaXMgYXNzdW1lZCB0aGF0IHRoZSB2LWxldmVsIGVkZ2UgaW1wbGVtZW50cyB0aGVcbiAgICAvLyBpbnRlcmZhY2UgVXBkYXRhYmxlLlxuXG4gICAgaWYgKGVkZ2UudkdyYXBoT2JqZWN0ICE9IG51bGwpXG4gICAge1xuICAgICAgLy8gY2FzdCB0byBVcGRhdGFibGUgd2l0aG91dCBhbnkgdHlwZSBjaGVja1xuICAgICAgdmFyIHZFZGdlID0gZWRnZS52R3JhcGhPYmplY3Q7XG5cbiAgICAgIC8vIGNhbGwgdGhlIHVwZGF0ZSBtZXRob2Qgb2YgdGhlIGludGVyZmFjZVxuICAgICAgdkVkZ2UudXBkYXRlKGVkZ2UpO1xuICAgIH1cbiAgfVxuICBlbHNlIGlmIChvYmogaW5zdGFuY2VvZiBMR3JhcGgpIHtcbiAgICB2YXIgZ3JhcGggPSBvYmo7XG4gICAgLy8gaWYgdGhlIGwtbGV2ZWwgZ3JhcGggaXMgYXNzb2NpYXRlZCB3aXRoIGEgdi1sZXZlbCBncmFwaCBvYmplY3QsXG4gICAgLy8gdGhlbiBpdCBpcyBhc3N1bWVkIHRoYXQgdGhlIHYtbGV2ZWwgb2JqZWN0IGltcGxlbWVudHMgdGhlXG4gICAgLy8gaW50ZXJmYWNlIFVwZGF0YWJsZS5cblxuICAgIGlmIChncmFwaC52R3JhcGhPYmplY3QgIT0gbnVsbClcbiAgICB7XG4gICAgICAvLyBjYXN0IHRvIFVwZGF0YWJsZSB3aXRob3V0IGFueSB0eXBlIGNoZWNrXG4gICAgICB2YXIgdkdyYXBoID0gZ3JhcGgudkdyYXBoT2JqZWN0O1xuXG4gICAgICAvLyBjYWxsIHRoZSB1cGRhdGUgbWV0aG9kIG9mIHRoZSBpbnRlcmZhY2VcbiAgICAgIHZHcmFwaC51cGRhdGUoZ3JhcGgpO1xuICAgIH1cbiAgfVxufTtcblxuLyoqXG4gKiBUaGlzIG1ldGhvZCBpcyB1c2VkIHRvIHNldCBhbGwgbGF5b3V0IHBhcmFtZXRlcnMgdG8gZGVmYXVsdCB2YWx1ZXNcbiAqIGRldGVybWluZWQgYXQgY29tcGlsZSB0aW1lLlxuICovXG5MYXlvdXQucHJvdG90eXBlLmluaXRQYXJhbWV0ZXJzID0gZnVuY3Rpb24gKCkge1xuICBpZiAoIXRoaXMuaXNTdWJMYXlvdXQpXG4gIHtcbiAgICB0aGlzLmxheW91dFF1YWxpdHkgPSBMYXlvdXRDb25zdGFudHMuREVGQVVMVF9RVUFMSVRZO1xuICAgIHRoaXMuYW5pbWF0aW9uRHVyaW5nTGF5b3V0ID0gTGF5b3V0Q29uc3RhbnRzLkRFRkFVTFRfQU5JTUFUSU9OX0RVUklOR19MQVlPVVQ7XG4gICAgdGhpcy5hbmltYXRpb25QZXJpb2QgPSBMYXlvdXRDb25zdGFudHMuREVGQVVMVF9BTklNQVRJT05fUEVSSU9EO1xuICAgIHRoaXMuYW5pbWF0aW9uT25MYXlvdXQgPSBMYXlvdXRDb25zdGFudHMuREVGQVVMVF9BTklNQVRJT05fT05fTEFZT1VUO1xuICAgIHRoaXMuaW5jcmVtZW50YWwgPSBMYXlvdXRDb25zdGFudHMuREVGQVVMVF9JTkNSRU1FTlRBTDtcbiAgICB0aGlzLmNyZWF0ZUJlbmRzQXNOZWVkZWQgPSBMYXlvdXRDb25zdGFudHMuREVGQVVMVF9DUkVBVEVfQkVORFNfQVNfTkVFREVEO1xuICAgIHRoaXMudW5pZm9ybUxlYWZOb2RlU2l6ZXMgPSBMYXlvdXRDb25zdGFudHMuREVGQVVMVF9VTklGT1JNX0xFQUZfTk9ERV9TSVpFUztcbiAgfVxuXG4gIGlmICh0aGlzLmFuaW1hdGlvbkR1cmluZ0xheW91dClcbiAge1xuICAgIHRoaXMuYW5pbWF0aW9uT25MYXlvdXQgPSBmYWxzZTtcbiAgfVxufTtcblxuTGF5b3V0LnByb3RvdHlwZS50cmFuc2Zvcm0gPSBmdW5jdGlvbiAobmV3TGVmdFRvcCkge1xuICBpZiAobmV3TGVmdFRvcCA9PSB1bmRlZmluZWQpIHtcbiAgICB0aGlzLnRyYW5zZm9ybShuZXcgUG9pbnREKDAsIDApKTtcbiAgfVxuICBlbHNlIHtcbiAgICAvLyBjcmVhdGUgYSB0cmFuc2Zvcm1hdGlvbiBvYmplY3QgKGZyb20gRWNsaXBzZSB0byBsYXlvdXQpLiBXaGVuIGFuXG4gICAgLy8gaW52ZXJzZSB0cmFuc2Zvcm0gaXMgYXBwbGllZCwgd2UgZ2V0IHVwcGVyLWxlZnQgY29vcmRpbmF0ZSBvZiB0aGVcbiAgICAvLyBkcmF3aW5nIG9yIHRoZSByb290IGdyYXBoIGF0IGdpdmVuIGlucHV0IGNvb3JkaW5hdGUgKHNvbWUgbWFyZ2luc1xuICAgIC8vIGFscmVhZHkgaW5jbHVkZWQgaW4gY2FsY3VsYXRpb24gb2YgbGVmdC10b3ApLlxuXG4gICAgdmFyIHRyYW5zID0gbmV3IFRyYW5zZm9ybSgpO1xuICAgIHZhciBsZWZ0VG9wID0gdGhpcy5ncmFwaE1hbmFnZXIuZ2V0Um9vdCgpLnVwZGF0ZUxlZnRUb3AoKTtcblxuICAgIGlmIChsZWZ0VG9wICE9IG51bGwpXG4gICAge1xuICAgICAgdHJhbnMuc2V0V29ybGRPcmdYKG5ld0xlZnRUb3AueCk7XG4gICAgICB0cmFucy5zZXRXb3JsZE9yZ1kobmV3TGVmdFRvcC55KTtcblxuICAgICAgdHJhbnMuc2V0RGV2aWNlT3JnWChsZWZ0VG9wLngpO1xuICAgICAgdHJhbnMuc2V0RGV2aWNlT3JnWShsZWZ0VG9wLnkpO1xuXG4gICAgICB2YXIgbm9kZXMgPSB0aGlzLmdldEFsbE5vZGVzKCk7XG4gICAgICB2YXIgbm9kZTtcblxuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBub2Rlcy5sZW5ndGg7IGkrKylcbiAgICAgIHtcbiAgICAgICAgbm9kZSA9IG5vZGVzW2ldO1xuICAgICAgICBub2RlLnRyYW5zZm9ybSh0cmFucyk7XG4gICAgICB9XG4gICAgfVxuICB9XG59O1xuXG5MYXlvdXQucHJvdG90eXBlLnBvc2l0aW9uTm9kZXNSYW5kb21seSA9IGZ1bmN0aW9uIChncmFwaCkge1xuXG4gIGlmIChncmFwaCA9PSB1bmRlZmluZWQpIHtcbiAgICAvL2Fzc2VydCAhdGhpcy5pbmNyZW1lbnRhbDtcbiAgICB0aGlzLnBvc2l0aW9uTm9kZXNSYW5kb21seSh0aGlzLmdldEdyYXBoTWFuYWdlcigpLmdldFJvb3QoKSk7XG4gICAgdGhpcy5nZXRHcmFwaE1hbmFnZXIoKS5nZXRSb290KCkudXBkYXRlQm91bmRzKHRydWUpO1xuICB9XG4gIGVsc2Uge1xuICAgIHZhciBsTm9kZTtcbiAgICB2YXIgY2hpbGRHcmFwaDtcblxuICAgIHZhciBub2RlcyA9IGdyYXBoLmdldE5vZGVzKCk7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBub2Rlcy5sZW5ndGg7IGkrKylcbiAgICB7XG4gICAgICBsTm9kZSA9IG5vZGVzW2ldO1xuICAgICAgY2hpbGRHcmFwaCA9IGxOb2RlLmdldENoaWxkKCk7XG5cbiAgICAgIGlmIChjaGlsZEdyYXBoID09IG51bGwpXG4gICAgICB7XG4gICAgICAgIGxOb2RlLnNjYXR0ZXIoKTtcbiAgICAgIH1cbiAgICAgIGVsc2UgaWYgKGNoaWxkR3JhcGguZ2V0Tm9kZXMoKS5sZW5ndGggPT0gMClcbiAgICAgIHtcbiAgICAgICAgbE5vZGUuc2NhdHRlcigpO1xuICAgICAgfVxuICAgICAgZWxzZVxuICAgICAge1xuICAgICAgICB0aGlzLnBvc2l0aW9uTm9kZXNSYW5kb21seShjaGlsZEdyYXBoKTtcbiAgICAgICAgbE5vZGUudXBkYXRlQm91bmRzKCk7XG4gICAgICB9XG4gICAgfVxuICB9XG59O1xuXG4vKipcbiAqIFRoaXMgbWV0aG9kIHJldHVybnMgYSBsaXN0IG9mIHRyZWVzIHdoZXJlIGVhY2ggdHJlZSBpcyByZXByZXNlbnRlZCBhcyBhXG4gKiBsaXN0IG9mIGwtbm9kZXMuIFRoZSBtZXRob2QgcmV0dXJucyBhIGxpc3Qgb2Ygc2l6ZSAwIHdoZW46XG4gKiAtIFRoZSBncmFwaCBpcyBub3QgZmxhdCBvclxuICogLSBPbmUgb2YgdGhlIGNvbXBvbmVudChzKSBvZiB0aGUgZ3JhcGggaXMgbm90IGEgdHJlZS5cbiAqL1xuTGF5b3V0LnByb3RvdHlwZS5nZXRGbGF0Rm9yZXN0ID0gZnVuY3Rpb24gKClcbntcbiAgdmFyIGZsYXRGb3Jlc3QgPSBbXTtcbiAgdmFyIGlzRm9yZXN0ID0gdHJ1ZTtcblxuICAvLyBRdWljayByZWZlcmVuY2UgZm9yIGFsbCBub2RlcyBpbiB0aGUgZ3JhcGggbWFuYWdlciBhc3NvY2lhdGVkIHdpdGhcbiAgLy8gdGhpcyBsYXlvdXQuIFRoZSBsaXN0IHNob3VsZCBub3QgYmUgY2hhbmdlZC5cbiAgdmFyIGFsbE5vZGVzID0gdGhpcy5ncmFwaE1hbmFnZXIuZ2V0Um9vdCgpLmdldE5vZGVzKCk7XG5cbiAgLy8gRmlyc3QgYmUgc3VyZSB0aGF0IHRoZSBncmFwaCBpcyBmbGF0XG4gIHZhciBpc0ZsYXQgPSB0cnVlO1xuXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgYWxsTm9kZXMubGVuZ3RoOyBpKyspXG4gIHtcbiAgICBpZiAoYWxsTm9kZXNbaV0uZ2V0Q2hpbGQoKSAhPSBudWxsKVxuICAgIHtcbiAgICAgIGlzRmxhdCA9IGZhbHNlO1xuICAgIH1cbiAgfVxuXG4gIC8vIFJldHVybiBlbXB0eSBmb3Jlc3QgaWYgdGhlIGdyYXBoIGlzIG5vdCBmbGF0LlxuICBpZiAoIWlzRmxhdClcbiAge1xuICAgIHJldHVybiBmbGF0Rm9yZXN0O1xuICB9XG5cbiAgLy8gUnVuIEJGUyBmb3IgZWFjaCBjb21wb25lbnQgb2YgdGhlIGdyYXBoLlxuXG4gIHZhciB2aXNpdGVkID0gbmV3IEhhc2hTZXQoKTtcbiAgdmFyIHRvQmVWaXNpdGVkID0gW107XG4gIHZhciBwYXJlbnRzID0gbmV3IEhhc2hNYXAoKTtcbiAgdmFyIHVuUHJvY2Vzc2VkTm9kZXMgPSBbXTtcblxuICB1blByb2Nlc3NlZE5vZGVzID0gdW5Qcm9jZXNzZWROb2Rlcy5jb25jYXQoYWxsTm9kZXMpO1xuXG4gIC8vIEVhY2ggaXRlcmF0aW9uIG9mIHRoaXMgbG9vcCBmaW5kcyBhIGNvbXBvbmVudCBvZiB0aGUgZ3JhcGggYW5kXG4gIC8vIGRlY2lkZXMgd2hldGhlciBpdCBpcyBhIHRyZWUgb3Igbm90LiBJZiBpdCBpcyBhIHRyZWUsIGFkZHMgaXQgdG8gdGhlXG4gIC8vIGZvcmVzdCBhbmQgY29udGludWVkIHdpdGggdGhlIG5leHQgY29tcG9uZW50LlxuXG4gIHdoaWxlICh1blByb2Nlc3NlZE5vZGVzLmxlbmd0aCA+IDAgJiYgaXNGb3Jlc3QpXG4gIHtcbiAgICB0b0JlVmlzaXRlZC5wdXNoKHVuUHJvY2Vzc2VkTm9kZXNbMF0pO1xuXG4gICAgLy8gU3RhcnQgdGhlIEJGUy4gRWFjaCBpdGVyYXRpb24gb2YgdGhpcyBsb29wIHZpc2l0cyBhIG5vZGUgaW4gYVxuICAgIC8vIEJGUyBtYW5uZXIuXG4gICAgd2hpbGUgKHRvQmVWaXNpdGVkLmxlbmd0aCA+IDAgJiYgaXNGb3Jlc3QpXG4gICAge1xuICAgICAgLy9wb29sIG9wZXJhdGlvblxuICAgICAgdmFyIGN1cnJlbnROb2RlID0gdG9CZVZpc2l0ZWRbMF07XG4gICAgICB0b0JlVmlzaXRlZC5zcGxpY2UoMCwgMSk7XG4gICAgICB2aXNpdGVkLmFkZChjdXJyZW50Tm9kZSk7XG5cbiAgICAgIC8vIFRyYXZlcnNlIGFsbCBuZWlnaGJvcnMgb2YgdGhpcyBub2RlXG4gICAgICB2YXIgbmVpZ2hib3JFZGdlcyA9IGN1cnJlbnROb2RlLmdldEVkZ2VzKCk7XG5cbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbmVpZ2hib3JFZGdlcy5sZW5ndGg7IGkrKylcbiAgICAgIHtcbiAgICAgICAgdmFyIGN1cnJlbnROZWlnaGJvciA9XG4gICAgICAgICAgICAgICAgbmVpZ2hib3JFZGdlc1tpXS5nZXRPdGhlckVuZChjdXJyZW50Tm9kZSk7XG5cbiAgICAgICAgLy8gSWYgQkZTIGlzIG5vdCBncm93aW5nIGZyb20gdGhpcyBuZWlnaGJvci5cbiAgICAgICAgaWYgKHBhcmVudHMuZ2V0KGN1cnJlbnROb2RlKSAhPSBjdXJyZW50TmVpZ2hib3IpXG4gICAgICAgIHtcbiAgICAgICAgICAvLyBXZSBoYXZlbid0IHByZXZpb3VzbHkgdmlzaXRlZCB0aGlzIG5laWdoYm9yLlxuICAgICAgICAgIGlmICghdmlzaXRlZC5jb250YWlucyhjdXJyZW50TmVpZ2hib3IpKVxuICAgICAgICAgIHtcbiAgICAgICAgICAgIHRvQmVWaXNpdGVkLnB1c2goY3VycmVudE5laWdoYm9yKTtcbiAgICAgICAgICAgIHBhcmVudHMucHV0KGN1cnJlbnROZWlnaGJvciwgY3VycmVudE5vZGUpO1xuICAgICAgICAgIH1cbiAgICAgICAgICAvLyBTaW5jZSB3ZSBoYXZlIHByZXZpb3VzbHkgdmlzaXRlZCB0aGlzIG5laWdoYm9yIGFuZFxuICAgICAgICAgIC8vIHRoaXMgbmVpZ2hib3IgaXMgbm90IHBhcmVudCBvZiBjdXJyZW50Tm9kZSwgZ2l2ZW5cbiAgICAgICAgICAvLyBncmFwaCBjb250YWlucyBhIGNvbXBvbmVudCB0aGF0IGlzIG5vdCB0cmVlLCBoZW5jZVxuICAgICAgICAgIC8vIGl0IGlzIG5vdCBhIGZvcmVzdC5cbiAgICAgICAgICBlbHNlXG4gICAgICAgICAge1xuICAgICAgICAgICAgaXNGb3Jlc3QgPSBmYWxzZTtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIC8vIFRoZSBncmFwaCBjb250YWlucyBhIGNvbXBvbmVudCB0aGF0IGlzIG5vdCBhIHRyZWUuIEVtcHR5XG4gICAgLy8gcHJldmlvdXNseSBmb3VuZCB0cmVlcy4gVGhlIG1ldGhvZCB3aWxsIGVuZC5cbiAgICBpZiAoIWlzRm9yZXN0KVxuICAgIHtcbiAgICAgIGZsYXRGb3Jlc3QgPSBbXTtcbiAgICB9XG4gICAgLy8gU2F2ZSBjdXJyZW50bHkgdmlzaXRlZCBub2RlcyBhcyBhIHRyZWUgaW4gb3VyIGZvcmVzdC4gUmVzZXRcbiAgICAvLyB2aXNpdGVkIGFuZCBwYXJlbnRzIGxpc3RzLiBDb250aW51ZSB3aXRoIHRoZSBuZXh0IGNvbXBvbmVudCBvZlxuICAgIC8vIHRoZSBncmFwaCwgaWYgYW55LlxuICAgIGVsc2VcbiAgICB7XG4gICAgICB2YXIgdGVtcCA9IFtdO1xuICAgICAgdmlzaXRlZC5hZGRBbGxUbyh0ZW1wKTtcbiAgICAgIGZsYXRGb3Jlc3QucHVzaCh0ZW1wKTtcbiAgICAgIC8vZmxhdEZvcmVzdCA9IGZsYXRGb3Jlc3QuY29uY2F0KHRlbXApO1xuICAgICAgLy91blByb2Nlc3NlZE5vZGVzLnJlbW92ZUFsbCh2aXNpdGVkKTtcbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGVtcC5sZW5ndGg7IGkrKykge1xuICAgICAgICB2YXIgdmFsdWUgPSB0ZW1wW2ldO1xuICAgICAgICB2YXIgaW5kZXggPSB1blByb2Nlc3NlZE5vZGVzLmluZGV4T2YodmFsdWUpO1xuICAgICAgICBpZiAoaW5kZXggPiAtMSkge1xuICAgICAgICAgIHVuUHJvY2Vzc2VkTm9kZXMuc3BsaWNlKGluZGV4LCAxKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgdmlzaXRlZCA9IG5ldyBIYXNoU2V0KCk7XG4gICAgICBwYXJlbnRzID0gbmV3IEhhc2hNYXAoKTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gZmxhdEZvcmVzdDtcbn07XG5cbi8qKlxuICogVGhpcyBtZXRob2QgY3JlYXRlcyBkdW1teSBub2RlcyAoYW4gbC1sZXZlbCBub2RlIHdpdGggbWluaW1hbCBkaW1lbnNpb25zKVxuICogZm9yIHRoZSBnaXZlbiBlZGdlIChvbmUgcGVyIGJlbmRwb2ludCkuIFRoZSBleGlzdGluZyBsLWxldmVsIHN0cnVjdHVyZVxuICogaXMgdXBkYXRlZCBhY2NvcmRpbmdseS5cbiAqL1xuTGF5b3V0LnByb3RvdHlwZS5jcmVhdGVEdW1teU5vZGVzRm9yQmVuZHBvaW50cyA9IGZ1bmN0aW9uIChlZGdlKVxue1xuICB2YXIgZHVtbXlOb2RlcyA9IFtdO1xuICB2YXIgcHJldiA9IGVkZ2Uuc291cmNlO1xuXG4gIHZhciBncmFwaCA9IHRoaXMuZ3JhcGhNYW5hZ2VyLmNhbGNMb3dlc3RDb21tb25BbmNlc3RvcihlZGdlLnNvdXJjZSwgZWRnZS50YXJnZXQpO1xuXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgZWRnZS5iZW5kcG9pbnRzLmxlbmd0aDsgaSsrKVxuICB7XG4gICAgLy8gY3JlYXRlIG5ldyBkdW1teSBub2RlXG4gICAgdmFyIGR1bW15Tm9kZSA9IHRoaXMubmV3Tm9kZShudWxsKTtcbiAgICBkdW1teU5vZGUuc2V0UmVjdChuZXcgUG9pbnQoMCwgMCksIG5ldyBEaW1lbnNpb24oMSwgMSkpO1xuXG4gICAgZ3JhcGguYWRkKGR1bW15Tm9kZSk7XG5cbiAgICAvLyBjcmVhdGUgbmV3IGR1bW15IGVkZ2UgYmV0d2VlbiBwcmV2IGFuZCBkdW1teSBub2RlXG4gICAgdmFyIGR1bW15RWRnZSA9IHRoaXMubmV3RWRnZShudWxsKTtcbiAgICB0aGlzLmdyYXBoTWFuYWdlci5hZGQoZHVtbXlFZGdlLCBwcmV2LCBkdW1teU5vZGUpO1xuXG4gICAgZHVtbXlOb2Rlcy5hZGQoZHVtbXlOb2RlKTtcbiAgICBwcmV2ID0gZHVtbXlOb2RlO1xuICB9XG5cbiAgdmFyIGR1bW15RWRnZSA9IHRoaXMubmV3RWRnZShudWxsKTtcbiAgdGhpcy5ncmFwaE1hbmFnZXIuYWRkKGR1bW15RWRnZSwgcHJldiwgZWRnZS50YXJnZXQpO1xuXG4gIHRoaXMuZWRnZVRvRHVtbXlOb2Rlcy5wdXQoZWRnZSwgZHVtbXlOb2Rlcyk7XG5cbiAgLy8gcmVtb3ZlIHJlYWwgZWRnZSBmcm9tIGdyYXBoIG1hbmFnZXIgaWYgaXQgaXMgaW50ZXItZ3JhcGhcbiAgaWYgKGVkZ2UuaXNJbnRlckdyYXBoKCkpXG4gIHtcbiAgICB0aGlzLmdyYXBoTWFuYWdlci5yZW1vdmUoZWRnZSk7XG4gIH1cbiAgLy8gZWxzZSwgcmVtb3ZlIHRoZSBlZGdlIGZyb20gdGhlIGN1cnJlbnQgZ3JhcGhcbiAgZWxzZVxuICB7XG4gICAgZ3JhcGgucmVtb3ZlKGVkZ2UpO1xuICB9XG5cbiAgcmV0dXJuIGR1bW15Tm9kZXM7XG59O1xuXG4vKipcbiAqIFRoaXMgbWV0aG9kIGNyZWF0ZXMgYmVuZHBvaW50cyBmb3IgZWRnZXMgZnJvbSB0aGUgZHVtbXkgbm9kZXNcbiAqIGF0IGwtbGV2ZWwuXG4gKi9cbkxheW91dC5wcm90b3R5cGUuY3JlYXRlQmVuZHBvaW50c0Zyb21EdW1teU5vZGVzID0gZnVuY3Rpb24gKClcbntcbiAgdmFyIGVkZ2VzID0gW107XG4gIGVkZ2VzID0gZWRnZXMuY29uY2F0KHRoaXMuZ3JhcGhNYW5hZ2VyLmdldEFsbEVkZ2VzKCkpO1xuICBlZGdlcyA9IHRoaXMuZWRnZVRvRHVtbXlOb2Rlcy5rZXlTZXQoKS5jb25jYXQoZWRnZXMpO1xuXG4gIGZvciAodmFyIGsgPSAwOyBrIDwgZWRnZXMubGVuZ3RoOyBrKyspXG4gIHtcbiAgICB2YXIgbEVkZ2UgPSBlZGdlc1trXTtcblxuICAgIGlmIChsRWRnZS5iZW5kcG9pbnRzLmxlbmd0aCA+IDApXG4gICAge1xuICAgICAgdmFyIHBhdGggPSB0aGlzLmVkZ2VUb0R1bW15Tm9kZXMuZ2V0KGxFZGdlKTtcblxuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBwYXRoLmxlbmd0aDsgaSsrKVxuICAgICAge1xuICAgICAgICB2YXIgZHVtbXlOb2RlID0gcGF0aFtpXTtcbiAgICAgICAgdmFyIHAgPSBuZXcgUG9pbnREKGR1bW15Tm9kZS5nZXRDZW50ZXJYKCksXG4gICAgICAgICAgICAgICAgZHVtbXlOb2RlLmdldENlbnRlclkoKSk7XG5cbiAgICAgICAgLy8gdXBkYXRlIGJlbmRwb2ludCdzIGxvY2F0aW9uIGFjY29yZGluZyB0byBkdW1teSBub2RlXG4gICAgICAgIHZhciBlYnAgPSBsRWRnZS5iZW5kcG9pbnRzLmdldChpKTtcbiAgICAgICAgZWJwLnggPSBwLng7XG4gICAgICAgIGVicC55ID0gcC55O1xuXG4gICAgICAgIC8vIHJlbW92ZSB0aGUgZHVtbXkgbm9kZSwgZHVtbXkgZWRnZXMgaW5jaWRlbnQgd2l0aCB0aGlzXG4gICAgICAgIC8vIGR1bW15IG5vZGUgaXMgYWxzbyByZW1vdmVkICh3aXRoaW4gdGhlIHJlbW92ZSBtZXRob2QpXG4gICAgICAgIGR1bW15Tm9kZS5nZXRPd25lcigpLnJlbW92ZShkdW1teU5vZGUpO1xuICAgICAgfVxuXG4gICAgICAvLyBhZGQgdGhlIHJlYWwgZWRnZSB0byBncmFwaFxuICAgICAgdGhpcy5ncmFwaE1hbmFnZXIuYWRkKGxFZGdlLCBsRWRnZS5zb3VyY2UsIGxFZGdlLnRhcmdldCk7XG4gICAgfVxuICB9XG59O1xuXG5MYXlvdXQudHJhbnNmb3JtID0gZnVuY3Rpb24gKHNsaWRlclZhbHVlLCBkZWZhdWx0VmFsdWUsIG1pbkRpdiwgbWF4TXVsKSB7XG4gIGlmIChtaW5EaXYgIT0gdW5kZWZpbmVkICYmIG1heE11bCAhPSB1bmRlZmluZWQpIHtcbiAgICB2YXIgdmFsdWUgPSBkZWZhdWx0VmFsdWU7XG5cbiAgICBpZiAoc2xpZGVyVmFsdWUgPD0gNTApXG4gICAge1xuICAgICAgdmFyIG1pblZhbHVlID0gZGVmYXVsdFZhbHVlIC8gbWluRGl2O1xuICAgICAgdmFsdWUgLT0gKChkZWZhdWx0VmFsdWUgLSBtaW5WYWx1ZSkgLyA1MCkgKiAoNTAgLSBzbGlkZXJWYWx1ZSk7XG4gICAgfVxuICAgIGVsc2VcbiAgICB7XG4gICAgICB2YXIgbWF4VmFsdWUgPSBkZWZhdWx0VmFsdWUgKiBtYXhNdWw7XG4gICAgICB2YWx1ZSArPSAoKG1heFZhbHVlIC0gZGVmYXVsdFZhbHVlKSAvIDUwKSAqIChzbGlkZXJWYWx1ZSAtIDUwKTtcbiAgICB9XG5cbiAgICByZXR1cm4gdmFsdWU7XG4gIH1cbiAgZWxzZSB7XG4gICAgdmFyIGEsIGI7XG5cbiAgICBpZiAoc2xpZGVyVmFsdWUgPD0gNTApXG4gICAge1xuICAgICAgYSA9IDkuMCAqIGRlZmF1bHRWYWx1ZSAvIDUwMC4wO1xuICAgICAgYiA9IGRlZmF1bHRWYWx1ZSAvIDEwLjA7XG4gICAgfVxuICAgIGVsc2VcbiAgICB7XG4gICAgICBhID0gOS4wICogZGVmYXVsdFZhbHVlIC8gNTAuMDtcbiAgICAgIGIgPSAtOCAqIGRlZmF1bHRWYWx1ZTtcbiAgICB9XG5cbiAgICByZXR1cm4gKGEgKiBzbGlkZXJWYWx1ZSArIGIpO1xuICB9XG59O1xuXG4vKipcbiAqIFRoaXMgbWV0aG9kIGZpbmRzIGFuZCByZXR1cm5zIHRoZSBjZW50ZXIgb2YgdGhlIGdpdmVuIG5vZGVzLCBhc3N1bWluZ1xuICogdGhhdCB0aGUgZ2l2ZW4gbm9kZXMgZm9ybSBhIHRyZWUgaW4gdGhlbXNlbHZlcy5cbiAqL1xuTGF5b3V0LmZpbmRDZW50ZXJPZlRyZWUgPSBmdW5jdGlvbiAobm9kZXMpXG57XG4gIHZhciBsaXN0ID0gW107XG4gIGxpc3QgPSBsaXN0LmNvbmNhdChub2Rlcyk7XG5cbiAgdmFyIHJlbW92ZWROb2RlcyA9IFtdO1xuICB2YXIgcmVtYWluaW5nRGVncmVlcyA9IG5ldyBIYXNoTWFwKCk7XG4gIHZhciBmb3VuZENlbnRlciA9IGZhbHNlO1xuICB2YXIgY2VudGVyTm9kZSA9IG51bGw7XG5cbiAgaWYgKGxpc3QubGVuZ3RoID09IDEgfHwgbGlzdC5sZW5ndGggPT0gMilcbiAge1xuICAgIGZvdW5kQ2VudGVyID0gdHJ1ZTtcbiAgICBjZW50ZXJOb2RlID0gbGlzdFswXTtcbiAgfVxuXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbGlzdC5sZW5ndGg7IGkrKylcbiAge1xuICAgIHZhciBub2RlID0gbGlzdFtpXTtcbiAgICB2YXIgZGVncmVlID0gbm9kZS5nZXROZWlnaGJvcnNMaXN0KCkuc2l6ZSgpO1xuICAgIHJlbWFpbmluZ0RlZ3JlZXMucHV0KG5vZGUsIG5vZGUuZ2V0TmVpZ2hib3JzTGlzdCgpLnNpemUoKSk7XG5cbiAgICBpZiAoZGVncmVlID09IDEpXG4gICAge1xuICAgICAgcmVtb3ZlZE5vZGVzLnB1c2gobm9kZSk7XG4gICAgfVxuICB9XG5cbiAgdmFyIHRlbXBMaXN0ID0gW107XG4gIHRlbXBMaXN0ID0gdGVtcExpc3QuY29uY2F0KHJlbW92ZWROb2Rlcyk7XG5cbiAgd2hpbGUgKCFmb3VuZENlbnRlcilcbiAge1xuICAgIHZhciB0ZW1wTGlzdDIgPSBbXTtcbiAgICB0ZW1wTGlzdDIgPSB0ZW1wTGlzdDIuY29uY2F0KHRlbXBMaXN0KTtcbiAgICB0ZW1wTGlzdCA9IFtdO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBsaXN0Lmxlbmd0aDsgaSsrKVxuICAgIHtcbiAgICAgIHZhciBub2RlID0gbGlzdFtpXTtcblxuICAgICAgdmFyIGluZGV4ID0gbGlzdC5pbmRleE9mKG5vZGUpO1xuICAgICAgaWYgKGluZGV4ID49IDApIHtcbiAgICAgICAgbGlzdC5zcGxpY2UoaW5kZXgsIDEpO1xuICAgICAgfVxuXG4gICAgICB2YXIgbmVpZ2hib3VycyA9IG5vZGUuZ2V0TmVpZ2hib3JzTGlzdCgpO1xuXG4gICAgICBPYmplY3Qua2V5cyhuZWlnaGJvdXJzLnNldCkuZm9yRWFjaChmdW5jdGlvbihqKSB7XG4gICAgICAgIHZhciBuZWlnaGJvdXIgPSBuZWlnaGJvdXJzLnNldFtqXTtcbiAgICAgICAgaWYgKHJlbW92ZWROb2Rlcy5pbmRleE9mKG5laWdoYm91cikgPCAwKVxuICAgICAgICB7XG4gICAgICAgICAgdmFyIG90aGVyRGVncmVlID0gcmVtYWluaW5nRGVncmVlcy5nZXQobmVpZ2hib3VyKTtcbiAgICAgICAgICB2YXIgbmV3RGVncmVlID0gb3RoZXJEZWdyZWUgLSAxO1xuXG4gICAgICAgICAgaWYgKG5ld0RlZ3JlZSA9PSAxKVxuICAgICAgICAgIHtcbiAgICAgICAgICAgIHRlbXBMaXN0LnB1c2gobmVpZ2hib3VyKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZW1haW5pbmdEZWdyZWVzLnB1dChuZWlnaGJvdXIsIG5ld0RlZ3JlZSk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH1cblxuICAgIHJlbW92ZWROb2RlcyA9IHJlbW92ZWROb2Rlcy5jb25jYXQodGVtcExpc3QpO1xuXG4gICAgaWYgKGxpc3QubGVuZ3RoID09IDEgfHwgbGlzdC5sZW5ndGggPT0gMilcbiAgICB7XG4gICAgICBmb3VuZENlbnRlciA9IHRydWU7XG4gICAgICBjZW50ZXJOb2RlID0gbGlzdFswXTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gY2VudGVyTm9kZTtcbn07XG5cbi8qKlxuICogRHVyaW5nIHRoZSBjb2Fyc2VuaW5nIHByb2Nlc3MsIHRoaXMgbGF5b3V0IG1heSBiZSByZWZlcmVuY2VkIGJ5IHR3byBncmFwaCBtYW5hZ2Vyc1xuICogdGhpcyBzZXR0ZXIgZnVuY3Rpb24gZ3JhbnRzIGFjY2VzcyB0byBjaGFuZ2UgdGhlIGN1cnJlbnRseSBiZWluZyB1c2VkIGdyYXBoIG1hbmFnZXJcbiAqL1xuTGF5b3V0LnByb3RvdHlwZS5zZXRHcmFwaE1hbmFnZXIgPSBmdW5jdGlvbiAoZ20pXG57XG4gIHRoaXMuZ3JhcGhNYW5hZ2VyID0gZ207XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IExheW91dDtcbiIsImZ1bmN0aW9uIExheW91dENvbnN0YW50cygpIHtcbn1cblxuLyoqXG4gKiBMYXlvdXQgUXVhbGl0eVxuICovXG5MYXlvdXRDb25zdGFudHMuUFJPT0ZfUVVBTElUWSA9IDA7XG5MYXlvdXRDb25zdGFudHMuREVGQVVMVF9RVUFMSVRZID0gMTtcbkxheW91dENvbnN0YW50cy5EUkFGVF9RVUFMSVRZID0gMjtcblxuLyoqXG4gKiBEZWZhdWx0IHBhcmFtZXRlcnNcbiAqL1xuTGF5b3V0Q29uc3RhbnRzLkRFRkFVTFRfQ1JFQVRFX0JFTkRTX0FTX05FRURFRCA9IGZhbHNlO1xuLy9MYXlvdXRDb25zdGFudHMuREVGQVVMVF9JTkNSRU1FTlRBTCA9IHRydWU7XG5MYXlvdXRDb25zdGFudHMuREVGQVVMVF9JTkNSRU1FTlRBTCA9IGZhbHNlO1xuTGF5b3V0Q29uc3RhbnRzLkRFRkFVTFRfQU5JTUFUSU9OX09OX0xBWU9VVCA9IHRydWU7XG5MYXlvdXRDb25zdGFudHMuREVGQVVMVF9BTklNQVRJT05fRFVSSU5HX0xBWU9VVCA9IGZhbHNlO1xuTGF5b3V0Q29uc3RhbnRzLkRFRkFVTFRfQU5JTUFUSU9OX1BFUklPRCA9IDUwO1xuTGF5b3V0Q29uc3RhbnRzLkRFRkFVTFRfVU5JRk9STV9MRUFGX05PREVfU0laRVMgPSBmYWxzZTtcblxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIFNlY3Rpb246IEdlbmVyYWwgb3RoZXIgY29uc3RhbnRzXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuLypcbiAqIE1hcmdpbnMgb2YgYSBncmFwaCB0byBiZSBhcHBsaWVkIG9uIGJvdWRpbmcgcmVjdGFuZ2xlIG9mIGl0cyBjb250ZW50cy4gV2VcbiAqIGFzc3VtZSBtYXJnaW5zIG9uIGFsbCBmb3VyIHNpZGVzIHRvIGJlIHVuaWZvcm0uXG4gKi9cbkxheW91dENvbnN0YW50cy5ERUZBVUxUX0dSQVBIX01BUkdJTiA9IDE1O1xuXG4vKlxuICogV2hldGhlciB0byBjb25zaWRlciBsYWJlbHMgaW4gbm9kZSBkaW1lbnNpb25zIG9yIG5vdFxuICovXG5MYXlvdXRDb25zdGFudHMuTk9ERV9ESU1FTlNJT05TX0lOQ0xVREVfTEFCRUxTID0gZmFsc2U7XG5cbi8qXG4gKiBEZWZhdWx0IGRpbWVuc2lvbiBvZiBhIG5vbi1jb21wb3VuZCBub2RlLlxuICovXG5MYXlvdXRDb25zdGFudHMuU0lNUExFX05PREVfU0laRSA9IDQwO1xuXG4vKlxuICogRGVmYXVsdCBkaW1lbnNpb24gb2YgYSBub24tY29tcG91bmQgbm9kZS5cbiAqL1xuTGF5b3V0Q29uc3RhbnRzLlNJTVBMRV9OT0RFX0hBTEZfU0laRSA9IExheW91dENvbnN0YW50cy5TSU1QTEVfTk9ERV9TSVpFIC8gMjtcblxuLypcbiAqIEVtcHR5IGNvbXBvdW5kIG5vZGUgc2l6ZS4gV2hlbiBhIGNvbXBvdW5kIG5vZGUgaXMgZW1wdHksIGl0cyBib3RoXG4gKiBkaW1lbnNpb25zIHNob3VsZCBiZSBvZiB0aGlzIHZhbHVlLlxuICovXG5MYXlvdXRDb25zdGFudHMuRU1QVFlfQ09NUE9VTkRfTk9ERV9TSVpFID0gNDA7XG5cbi8qXG4gKiBNaW5pbXVtIGxlbmd0aCB0aGF0IGFuIGVkZ2Ugc2hvdWxkIHRha2UgZHVyaW5nIGxheW91dFxuICovXG5MYXlvdXRDb25zdGFudHMuTUlOX0VER0VfTEVOR1RIID0gMTtcblxuLypcbiAqIFdvcmxkIGJvdW5kYXJpZXMgdGhhdCBsYXlvdXQgb3BlcmF0ZXMgb25cbiAqL1xuTGF5b3V0Q29uc3RhbnRzLldPUkxEX0JPVU5EQVJZID0gMTAwMDAwMDtcblxuLypcbiAqIFdvcmxkIGJvdW5kYXJpZXMgdGhhdCByYW5kb20gcG9zaXRpb25pbmcgY2FuIGJlIHBlcmZvcm1lZCB3aXRoXG4gKi9cbkxheW91dENvbnN0YW50cy5JTklUSUFMX1dPUkxEX0JPVU5EQVJZID0gTGF5b3V0Q29uc3RhbnRzLldPUkxEX0JPVU5EQVJZIC8gMTAwMDtcblxuLypcbiAqIENvb3JkaW5hdGVzIG9mIHRoZSB3b3JsZCBjZW50ZXJcbiAqL1xuTGF5b3V0Q29uc3RhbnRzLldPUkxEX0NFTlRFUl9YID0gMTIwMDtcbkxheW91dENvbnN0YW50cy5XT1JMRF9DRU5URVJfWSA9IDkwMDtcblxubW9kdWxlLmV4cG9ydHMgPSBMYXlvdXRDb25zdGFudHM7XG4iLCIvKlxuICpUaGlzIGNsYXNzIGlzIHRoZSBqYXZhc2NyaXB0IGltcGxlbWVudGF0aW9uIG9mIHRoZSBQb2ludC5qYXZhIGNsYXNzIGluIGpka1xuICovXG5mdW5jdGlvbiBQb2ludCh4LCB5LCBwKSB7XG4gIHRoaXMueCA9IG51bGw7XG4gIHRoaXMueSA9IG51bGw7XG4gIGlmICh4ID09IG51bGwgJiYgeSA9PSBudWxsICYmIHAgPT0gbnVsbCkge1xuICAgIHRoaXMueCA9IDA7XG4gICAgdGhpcy55ID0gMDtcbiAgfVxuICBlbHNlIGlmICh0eXBlb2YgeCA9PSAnbnVtYmVyJyAmJiB0eXBlb2YgeSA9PSAnbnVtYmVyJyAmJiBwID09IG51bGwpIHtcbiAgICB0aGlzLnggPSB4O1xuICAgIHRoaXMueSA9IHk7XG4gIH1cbiAgZWxzZSBpZiAoeC5jb25zdHJ1Y3Rvci5uYW1lID09ICdQb2ludCcgJiYgeSA9PSBudWxsICYmIHAgPT0gbnVsbCkge1xuICAgIHAgPSB4O1xuICAgIHRoaXMueCA9IHAueDtcbiAgICB0aGlzLnkgPSBwLnk7XG4gIH1cbn1cblxuUG9pbnQucHJvdG90eXBlLmdldFggPSBmdW5jdGlvbiAoKSB7XG4gIHJldHVybiB0aGlzLng7XG59XG5cblBvaW50LnByb3RvdHlwZS5nZXRZID0gZnVuY3Rpb24gKCkge1xuICByZXR1cm4gdGhpcy55O1xufVxuXG5Qb2ludC5wcm90b3R5cGUuZ2V0TG9jYXRpb24gPSBmdW5jdGlvbiAoKSB7XG4gIHJldHVybiBuZXcgUG9pbnQodGhpcy54LCB0aGlzLnkpO1xufVxuXG5Qb2ludC5wcm90b3R5cGUuc2V0TG9jYXRpb24gPSBmdW5jdGlvbiAoeCwgeSwgcCkge1xuICBpZiAoeC5jb25zdHJ1Y3Rvci5uYW1lID09ICdQb2ludCcgJiYgeSA9PSBudWxsICYmIHAgPT0gbnVsbCkge1xuICAgIHAgPSB4O1xuICAgIHRoaXMuc2V0TG9jYXRpb24ocC54LCBwLnkpO1xuICB9XG4gIGVsc2UgaWYgKHR5cGVvZiB4ID09ICdudW1iZXInICYmIHR5cGVvZiB5ID09ICdudW1iZXInICYmIHAgPT0gbnVsbCkge1xuICAgIC8vaWYgYm90aCBwYXJhbWV0ZXJzIGFyZSBpbnRlZ2VyIGp1c3QgbW92ZSAoeCx5KSBsb2NhdGlvblxuICAgIGlmIChwYXJzZUludCh4KSA9PSB4ICYmIHBhcnNlSW50KHkpID09IHkpIHtcbiAgICAgIHRoaXMubW92ZSh4LCB5KTtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICB0aGlzLnggPSBNYXRoLmZsb29yKHggKyAwLjUpO1xuICAgICAgdGhpcy55ID0gTWF0aC5mbG9vcih5ICsgMC41KTtcbiAgICB9XG4gIH1cbn1cblxuUG9pbnQucHJvdG90eXBlLm1vdmUgPSBmdW5jdGlvbiAoeCwgeSkge1xuICB0aGlzLnggPSB4O1xuICB0aGlzLnkgPSB5O1xufVxuXG5Qb2ludC5wcm90b3R5cGUudHJhbnNsYXRlID0gZnVuY3Rpb24gKGR4LCBkeSkge1xuICB0aGlzLnggKz0gZHg7XG4gIHRoaXMueSArPSBkeTtcbn1cblxuUG9pbnQucHJvdG90eXBlLmVxdWFscyA9IGZ1bmN0aW9uIChvYmopIHtcbiAgaWYgKG9iai5jb25zdHJ1Y3Rvci5uYW1lID09IFwiUG9pbnRcIikge1xuICAgIHZhciBwdCA9IG9iajtcbiAgICByZXR1cm4gKHRoaXMueCA9PSBwdC54KSAmJiAodGhpcy55ID09IHB0LnkpO1xuICB9XG4gIHJldHVybiB0aGlzID09IG9iajtcbn1cblxuUG9pbnQucHJvdG90eXBlLnRvU3RyaW5nID0gZnVuY3Rpb24gKCkge1xuICByZXR1cm4gbmV3IFBvaW50KCkuY29uc3RydWN0b3IubmFtZSArIFwiW3g9XCIgKyB0aGlzLnggKyBcIix5PVwiICsgdGhpcy55ICsgXCJdXCI7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gUG9pbnQ7XG4iLCJmdW5jdGlvbiBQb2ludEQoeCwgeSkge1xuICBpZiAoeCA9PSBudWxsICYmIHkgPT0gbnVsbCkge1xuICAgIHRoaXMueCA9IDA7XG4gICAgdGhpcy55ID0gMDtcbiAgfSBlbHNlIHtcbiAgICB0aGlzLnggPSB4O1xuICAgIHRoaXMueSA9IHk7XG4gIH1cbn1cblxuUG9pbnRELnByb3RvdHlwZS5nZXRYID0gZnVuY3Rpb24gKClcbntcbiAgcmV0dXJuIHRoaXMueDtcbn07XG5cblBvaW50RC5wcm90b3R5cGUuZ2V0WSA9IGZ1bmN0aW9uICgpXG57XG4gIHJldHVybiB0aGlzLnk7XG59O1xuXG5Qb2ludEQucHJvdG90eXBlLnNldFggPSBmdW5jdGlvbiAoeClcbntcbiAgdGhpcy54ID0geDtcbn07XG5cblBvaW50RC5wcm90b3R5cGUuc2V0WSA9IGZ1bmN0aW9uICh5KVxue1xuICB0aGlzLnkgPSB5O1xufTtcblxuUG9pbnRELnByb3RvdHlwZS5nZXREaWZmZXJlbmNlID0gZnVuY3Rpb24gKHB0KVxue1xuICByZXR1cm4gbmV3IERpbWVuc2lvbkQodGhpcy54IC0gcHQueCwgdGhpcy55IC0gcHQueSk7XG59O1xuXG5Qb2ludEQucHJvdG90eXBlLmdldENvcHkgPSBmdW5jdGlvbiAoKVxue1xuICByZXR1cm4gbmV3IFBvaW50RCh0aGlzLngsIHRoaXMueSk7XG59O1xuXG5Qb2ludEQucHJvdG90eXBlLnRyYW5zbGF0ZSA9IGZ1bmN0aW9uIChkaW0pXG57XG4gIHRoaXMueCArPSBkaW0ud2lkdGg7XG4gIHRoaXMueSArPSBkaW0uaGVpZ2h0O1xuICByZXR1cm4gdGhpcztcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gUG9pbnREO1xuIiwiZnVuY3Rpb24gUmFuZG9tU2VlZCgpIHtcbn1cblJhbmRvbVNlZWQuc2VlZCA9IDE7XG5SYW5kb21TZWVkLnggPSAwO1xuXG5SYW5kb21TZWVkLm5leHREb3VibGUgPSBmdW5jdGlvbiAoKSB7XG4gIFJhbmRvbVNlZWQueCA9IE1hdGguc2luKFJhbmRvbVNlZWQuc2VlZCsrKSAqIDEwMDAwO1xuICByZXR1cm4gUmFuZG9tU2VlZC54IC0gTWF0aC5mbG9vcihSYW5kb21TZWVkLngpO1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSBSYW5kb21TZWVkO1xuIiwiZnVuY3Rpb24gUmVjdGFuZ2xlRCh4LCB5LCB3aWR0aCwgaGVpZ2h0KSB7XG4gIHRoaXMueCA9IDA7XG4gIHRoaXMueSA9IDA7XG4gIHRoaXMud2lkdGggPSAwO1xuICB0aGlzLmhlaWdodCA9IDA7XG5cbiAgaWYgKHggIT0gbnVsbCAmJiB5ICE9IG51bGwgJiYgd2lkdGggIT0gbnVsbCAmJiBoZWlnaHQgIT0gbnVsbCkge1xuICAgIHRoaXMueCA9IHg7XG4gICAgdGhpcy55ID0geTtcbiAgICB0aGlzLndpZHRoID0gd2lkdGg7XG4gICAgdGhpcy5oZWlnaHQgPSBoZWlnaHQ7XG4gIH1cbn1cblxuUmVjdGFuZ2xlRC5wcm90b3R5cGUuZ2V0WCA9IGZ1bmN0aW9uICgpXG57XG4gIHJldHVybiB0aGlzLng7XG59O1xuXG5SZWN0YW5nbGVELnByb3RvdHlwZS5zZXRYID0gZnVuY3Rpb24gKHgpXG57XG4gIHRoaXMueCA9IHg7XG59O1xuXG5SZWN0YW5nbGVELnByb3RvdHlwZS5nZXRZID0gZnVuY3Rpb24gKClcbntcbiAgcmV0dXJuIHRoaXMueTtcbn07XG5cblJlY3RhbmdsZUQucHJvdG90eXBlLnNldFkgPSBmdW5jdGlvbiAoeSlcbntcbiAgdGhpcy55ID0geTtcbn07XG5cblJlY3RhbmdsZUQucHJvdG90eXBlLmdldFdpZHRoID0gZnVuY3Rpb24gKClcbntcbiAgcmV0dXJuIHRoaXMud2lkdGg7XG59O1xuXG5SZWN0YW5nbGVELnByb3RvdHlwZS5zZXRXaWR0aCA9IGZ1bmN0aW9uICh3aWR0aClcbntcbiAgdGhpcy53aWR0aCA9IHdpZHRoO1xufTtcblxuUmVjdGFuZ2xlRC5wcm90b3R5cGUuZ2V0SGVpZ2h0ID0gZnVuY3Rpb24gKClcbntcbiAgcmV0dXJuIHRoaXMuaGVpZ2h0O1xufTtcblxuUmVjdGFuZ2xlRC5wcm90b3R5cGUuc2V0SGVpZ2h0ID0gZnVuY3Rpb24gKGhlaWdodClcbntcbiAgdGhpcy5oZWlnaHQgPSBoZWlnaHQ7XG59O1xuXG5SZWN0YW5nbGVELnByb3RvdHlwZS5nZXRSaWdodCA9IGZ1bmN0aW9uICgpXG57XG4gIHJldHVybiB0aGlzLnggKyB0aGlzLndpZHRoO1xufTtcblxuUmVjdGFuZ2xlRC5wcm90b3R5cGUuZ2V0Qm90dG9tID0gZnVuY3Rpb24gKClcbntcbiAgcmV0dXJuIHRoaXMueSArIHRoaXMuaGVpZ2h0O1xufTtcblxuUmVjdGFuZ2xlRC5wcm90b3R5cGUuaW50ZXJzZWN0cyA9IGZ1bmN0aW9uIChhKVxue1xuICBpZiAodGhpcy5nZXRSaWdodCgpIDwgYS54KVxuICB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgaWYgKHRoaXMuZ2V0Qm90dG9tKCkgPCBhLnkpXG4gIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICBpZiAoYS5nZXRSaWdodCgpIDwgdGhpcy54KVxuICB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgaWYgKGEuZ2V0Qm90dG9tKCkgPCB0aGlzLnkpXG4gIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICByZXR1cm4gdHJ1ZTtcbn07XG5cblJlY3RhbmdsZUQucHJvdG90eXBlLmdldENlbnRlclggPSBmdW5jdGlvbiAoKVxue1xuICByZXR1cm4gdGhpcy54ICsgdGhpcy53aWR0aCAvIDI7XG59O1xuXG5SZWN0YW5nbGVELnByb3RvdHlwZS5nZXRNaW5YID0gZnVuY3Rpb24gKClcbntcbiAgcmV0dXJuIHRoaXMuZ2V0WCgpO1xufTtcblxuUmVjdGFuZ2xlRC5wcm90b3R5cGUuZ2V0TWF4WCA9IGZ1bmN0aW9uICgpXG57XG4gIHJldHVybiB0aGlzLmdldFgoKSArIHRoaXMud2lkdGg7XG59O1xuXG5SZWN0YW5nbGVELnByb3RvdHlwZS5nZXRDZW50ZXJZID0gZnVuY3Rpb24gKClcbntcbiAgcmV0dXJuIHRoaXMueSArIHRoaXMuaGVpZ2h0IC8gMjtcbn07XG5cblJlY3RhbmdsZUQucHJvdG90eXBlLmdldE1pblkgPSBmdW5jdGlvbiAoKVxue1xuICByZXR1cm4gdGhpcy5nZXRZKCk7XG59O1xuXG5SZWN0YW5nbGVELnByb3RvdHlwZS5nZXRNYXhZID0gZnVuY3Rpb24gKClcbntcbiAgcmV0dXJuIHRoaXMuZ2V0WSgpICsgdGhpcy5oZWlnaHQ7XG59O1xuXG5SZWN0YW5nbGVELnByb3RvdHlwZS5nZXRXaWR0aEhhbGYgPSBmdW5jdGlvbiAoKVxue1xuICByZXR1cm4gdGhpcy53aWR0aCAvIDI7XG59O1xuXG5SZWN0YW5nbGVELnByb3RvdHlwZS5nZXRIZWlnaHRIYWxmID0gZnVuY3Rpb24gKClcbntcbiAgcmV0dXJuIHRoaXMuaGVpZ2h0IC8gMjtcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gUmVjdGFuZ2xlRDtcbiIsInZhciBQb2ludEQgPSByZXF1aXJlKCcuL1BvaW50RCcpO1xuXG5mdW5jdGlvbiBUcmFuc2Zvcm0oeCwgeSkge1xuICB0aGlzLmx3b3JsZE9yZ1ggPSAwLjA7XG4gIHRoaXMubHdvcmxkT3JnWSA9IDAuMDtcbiAgdGhpcy5sZGV2aWNlT3JnWCA9IDAuMDtcbiAgdGhpcy5sZGV2aWNlT3JnWSA9IDAuMDtcbiAgdGhpcy5sd29ybGRFeHRYID0gMS4wO1xuICB0aGlzLmx3b3JsZEV4dFkgPSAxLjA7XG4gIHRoaXMubGRldmljZUV4dFggPSAxLjA7XG4gIHRoaXMubGRldmljZUV4dFkgPSAxLjA7XG59XG5cblRyYW5zZm9ybS5wcm90b3R5cGUuZ2V0V29ybGRPcmdYID0gZnVuY3Rpb24gKClcbntcbiAgcmV0dXJuIHRoaXMubHdvcmxkT3JnWDtcbn1cblxuVHJhbnNmb3JtLnByb3RvdHlwZS5zZXRXb3JsZE9yZ1ggPSBmdW5jdGlvbiAod294KVxue1xuICB0aGlzLmx3b3JsZE9yZ1ggPSB3b3g7XG59XG5cblRyYW5zZm9ybS5wcm90b3R5cGUuZ2V0V29ybGRPcmdZID0gZnVuY3Rpb24gKClcbntcbiAgcmV0dXJuIHRoaXMubHdvcmxkT3JnWTtcbn1cblxuVHJhbnNmb3JtLnByb3RvdHlwZS5zZXRXb3JsZE9yZ1kgPSBmdW5jdGlvbiAod295KVxue1xuICB0aGlzLmx3b3JsZE9yZ1kgPSB3b3k7XG59XG5cblRyYW5zZm9ybS5wcm90b3R5cGUuZ2V0V29ybGRFeHRYID0gZnVuY3Rpb24gKClcbntcbiAgcmV0dXJuIHRoaXMubHdvcmxkRXh0WDtcbn1cblxuVHJhbnNmb3JtLnByb3RvdHlwZS5zZXRXb3JsZEV4dFggPSBmdW5jdGlvbiAod2V4KVxue1xuICB0aGlzLmx3b3JsZEV4dFggPSB3ZXg7XG59XG5cblRyYW5zZm9ybS5wcm90b3R5cGUuZ2V0V29ybGRFeHRZID0gZnVuY3Rpb24gKClcbntcbiAgcmV0dXJuIHRoaXMubHdvcmxkRXh0WTtcbn1cblxuVHJhbnNmb3JtLnByb3RvdHlwZS5zZXRXb3JsZEV4dFkgPSBmdW5jdGlvbiAod2V5KVxue1xuICB0aGlzLmx3b3JsZEV4dFkgPSB3ZXk7XG59XG5cbi8qIERldmljZSByZWxhdGVkICovXG5cblRyYW5zZm9ybS5wcm90b3R5cGUuZ2V0RGV2aWNlT3JnWCA9IGZ1bmN0aW9uICgpXG57XG4gIHJldHVybiB0aGlzLmxkZXZpY2VPcmdYO1xufVxuXG5UcmFuc2Zvcm0ucHJvdG90eXBlLnNldERldmljZU9yZ1ggPSBmdW5jdGlvbiAoZG94KVxue1xuICB0aGlzLmxkZXZpY2VPcmdYID0gZG94O1xufVxuXG5UcmFuc2Zvcm0ucHJvdG90eXBlLmdldERldmljZU9yZ1kgPSBmdW5jdGlvbiAoKVxue1xuICByZXR1cm4gdGhpcy5sZGV2aWNlT3JnWTtcbn1cblxuVHJhbnNmb3JtLnByb3RvdHlwZS5zZXREZXZpY2VPcmdZID0gZnVuY3Rpb24gKGRveSlcbntcbiAgdGhpcy5sZGV2aWNlT3JnWSA9IGRveTtcbn1cblxuVHJhbnNmb3JtLnByb3RvdHlwZS5nZXREZXZpY2VFeHRYID0gZnVuY3Rpb24gKClcbntcbiAgcmV0dXJuIHRoaXMubGRldmljZUV4dFg7XG59XG5cblRyYW5zZm9ybS5wcm90b3R5cGUuc2V0RGV2aWNlRXh0WCA9IGZ1bmN0aW9uIChkZXgpXG57XG4gIHRoaXMubGRldmljZUV4dFggPSBkZXg7XG59XG5cblRyYW5zZm9ybS5wcm90b3R5cGUuZ2V0RGV2aWNlRXh0WSA9IGZ1bmN0aW9uICgpXG57XG4gIHJldHVybiB0aGlzLmxkZXZpY2VFeHRZO1xufVxuXG5UcmFuc2Zvcm0ucHJvdG90eXBlLnNldERldmljZUV4dFkgPSBmdW5jdGlvbiAoZGV5KVxue1xuICB0aGlzLmxkZXZpY2VFeHRZID0gZGV5O1xufVxuXG5UcmFuc2Zvcm0ucHJvdG90eXBlLnRyYW5zZm9ybVggPSBmdW5jdGlvbiAoeClcbntcbiAgdmFyIHhEZXZpY2UgPSAwLjA7XG4gIHZhciB3b3JsZEV4dFggPSB0aGlzLmx3b3JsZEV4dFg7XG4gIGlmICh3b3JsZEV4dFggIT0gMC4wKVxuICB7XG4gICAgeERldmljZSA9IHRoaXMubGRldmljZU9yZ1ggK1xuICAgICAgICAgICAgKCh4IC0gdGhpcy5sd29ybGRPcmdYKSAqIHRoaXMubGRldmljZUV4dFggLyB3b3JsZEV4dFgpO1xuICB9XG5cbiAgcmV0dXJuIHhEZXZpY2U7XG59XG5cblRyYW5zZm9ybS5wcm90b3R5cGUudHJhbnNmb3JtWSA9IGZ1bmN0aW9uICh5KVxue1xuICB2YXIgeURldmljZSA9IDAuMDtcbiAgdmFyIHdvcmxkRXh0WSA9IHRoaXMubHdvcmxkRXh0WTtcbiAgaWYgKHdvcmxkRXh0WSAhPSAwLjApXG4gIHtcbiAgICB5RGV2aWNlID0gdGhpcy5sZGV2aWNlT3JnWSArXG4gICAgICAgICAgICAoKHkgLSB0aGlzLmx3b3JsZE9yZ1kpICogdGhpcy5sZGV2aWNlRXh0WSAvIHdvcmxkRXh0WSk7XG4gIH1cblxuXG4gIHJldHVybiB5RGV2aWNlO1xufVxuXG5UcmFuc2Zvcm0ucHJvdG90eXBlLmludmVyc2VUcmFuc2Zvcm1YID0gZnVuY3Rpb24gKHgpXG57XG4gIHZhciB4V29ybGQgPSAwLjA7XG4gIHZhciBkZXZpY2VFeHRYID0gdGhpcy5sZGV2aWNlRXh0WDtcbiAgaWYgKGRldmljZUV4dFggIT0gMC4wKVxuICB7XG4gICAgeFdvcmxkID0gdGhpcy5sd29ybGRPcmdYICtcbiAgICAgICAgICAgICgoeCAtIHRoaXMubGRldmljZU9yZ1gpICogdGhpcy5sd29ybGRFeHRYIC8gZGV2aWNlRXh0WCk7XG4gIH1cblxuXG4gIHJldHVybiB4V29ybGQ7XG59XG5cblRyYW5zZm9ybS5wcm90b3R5cGUuaW52ZXJzZVRyYW5zZm9ybVkgPSBmdW5jdGlvbiAoeSlcbntcbiAgdmFyIHlXb3JsZCA9IDAuMDtcbiAgdmFyIGRldmljZUV4dFkgPSB0aGlzLmxkZXZpY2VFeHRZO1xuICBpZiAoZGV2aWNlRXh0WSAhPSAwLjApXG4gIHtcbiAgICB5V29ybGQgPSB0aGlzLmx3b3JsZE9yZ1kgK1xuICAgICAgICAgICAgKCh5IC0gdGhpcy5sZGV2aWNlT3JnWSkgKiB0aGlzLmx3b3JsZEV4dFkgLyBkZXZpY2VFeHRZKTtcbiAgfVxuICByZXR1cm4geVdvcmxkO1xufVxuXG5UcmFuc2Zvcm0ucHJvdG90eXBlLmludmVyc2VUcmFuc2Zvcm1Qb2ludCA9IGZ1bmN0aW9uIChpblBvaW50KVxue1xuICB2YXIgb3V0UG9pbnQgPVxuICAgICAgICAgIG5ldyBQb2ludEQodGhpcy5pbnZlcnNlVHJhbnNmb3JtWChpblBvaW50LngpLFxuICAgICAgICAgICAgICAgICAgdGhpcy5pbnZlcnNlVHJhbnNmb3JtWShpblBvaW50LnkpKTtcbiAgcmV0dXJuIG91dFBvaW50O1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IFRyYW5zZm9ybTtcbiIsImZ1bmN0aW9uIFVuaXF1ZUlER2VuZXJldG9yKCkge1xufVxuXG5VbmlxdWVJREdlbmVyZXRvci5sYXN0SUQgPSAwO1xuXG5VbmlxdWVJREdlbmVyZXRvci5jcmVhdGVJRCA9IGZ1bmN0aW9uIChvYmopIHtcbiAgaWYgKFVuaXF1ZUlER2VuZXJldG9yLmlzUHJpbWl0aXZlKG9iaikpIHtcbiAgICByZXR1cm4gb2JqO1xuICB9XG4gIGlmIChvYmoudW5pcXVlSUQgIT0gbnVsbCkge1xuICAgIHJldHVybiBvYmoudW5pcXVlSUQ7XG4gIH1cbiAgb2JqLnVuaXF1ZUlEID0gVW5pcXVlSURHZW5lcmV0b3IuZ2V0U3RyaW5nKCk7XG4gIFVuaXF1ZUlER2VuZXJldG9yLmxhc3RJRCsrO1xuICByZXR1cm4gb2JqLnVuaXF1ZUlEO1xufVxuXG5VbmlxdWVJREdlbmVyZXRvci5nZXRTdHJpbmcgPSBmdW5jdGlvbiAoaWQpIHtcbiAgaWYgKGlkID09IG51bGwpXG4gICAgaWQgPSBVbmlxdWVJREdlbmVyZXRvci5sYXN0SUQ7XG4gIHJldHVybiBcIk9iamVjdCNcIiArIGlkICsgXCJcIjtcbn1cblxuVW5pcXVlSURHZW5lcmV0b3IuaXNQcmltaXRpdmUgPSBmdW5jdGlvbiAoYXJnKSB7XG4gIHZhciB0eXBlID0gdHlwZW9mIGFyZztcbiAgcmV0dXJuIGFyZyA9PSBudWxsIHx8ICh0eXBlICE9IFwib2JqZWN0XCIgJiYgdHlwZSAhPSBcImZ1bmN0aW9uXCIpO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IFVuaXF1ZUlER2VuZXJldG9yO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgRGltZW5zaW9uRCA9IHJlcXVpcmUoJy4vRGltZW5zaW9uRCcpO1xudmFyIEhhc2hNYXAgPSByZXF1aXJlKCcuL0hhc2hNYXAnKTtcbnZhciBIYXNoU2V0ID0gcmVxdWlyZSgnLi9IYXNoU2V0Jyk7XG52YXIgSUdlb21ldHJ5ID0gcmVxdWlyZSgnLi9JR2VvbWV0cnknKTtcbnZhciBJTWF0aCA9IHJlcXVpcmUoJy4vSU1hdGgnKTtcbnZhciBJbnRlZ2VyID0gcmVxdWlyZSgnLi9JbnRlZ2VyJyk7XG52YXIgUG9pbnQgPSByZXF1aXJlKCcuL1BvaW50Jyk7XG52YXIgUG9pbnREID0gcmVxdWlyZSgnLi9Qb2ludEQnKTtcbnZhciBSYW5kb21TZWVkID0gcmVxdWlyZSgnLi9SYW5kb21TZWVkJyk7XG52YXIgUmVjdGFuZ2xlRCA9IHJlcXVpcmUoJy4vUmVjdGFuZ2xlRCcpO1xudmFyIFRyYW5zZm9ybSA9IHJlcXVpcmUoJy4vVHJhbnNmb3JtJyk7XG52YXIgVW5pcXVlSURHZW5lcmV0b3IgPSByZXF1aXJlKCcuL1VuaXF1ZUlER2VuZXJldG9yJyk7XG52YXIgTEdyYXBoT2JqZWN0ID0gcmVxdWlyZSgnLi9MR3JhcGhPYmplY3QnKTtcbnZhciBMR3JhcGggPSByZXF1aXJlKCcuL0xHcmFwaCcpO1xudmFyIExFZGdlID0gcmVxdWlyZSgnLi9MRWRnZScpO1xudmFyIExHcmFwaE1hbmFnZXIgPSByZXF1aXJlKCcuL0xHcmFwaE1hbmFnZXInKTtcbnZhciBMTm9kZSA9IHJlcXVpcmUoJy4vTE5vZGUnKTtcbnZhciBMYXlvdXQgPSByZXF1aXJlKCcuL0xheW91dCcpO1xudmFyIExheW91dENvbnN0YW50cyA9IHJlcXVpcmUoJy4vTGF5b3V0Q29uc3RhbnRzJyk7XG52YXIgRkRMYXlvdXQgPSByZXF1aXJlKCcuL0ZETGF5b3V0Jyk7XG52YXIgRkRMYXlvdXRDb25zdGFudHMgPSByZXF1aXJlKCcuL0ZETGF5b3V0Q29uc3RhbnRzJyk7XG52YXIgRkRMYXlvdXRFZGdlID0gcmVxdWlyZSgnLi9GRExheW91dEVkZ2UnKTtcbnZhciBGRExheW91dE5vZGUgPSByZXF1aXJlKCcuL0ZETGF5b3V0Tm9kZScpO1xudmFyIENvU0VDb25zdGFudHMgPSByZXF1aXJlKCcuL0NvU0VDb25zdGFudHMnKTtcbnZhciBDb1NFRWRnZSA9IHJlcXVpcmUoJy4vQ29TRUVkZ2UnKTtcbnZhciBDb1NFR3JhcGggPSByZXF1aXJlKCcuL0NvU0VHcmFwaCcpO1xudmFyIENvU0VHcmFwaE1hbmFnZXIgPSByZXF1aXJlKCcuL0NvU0VHcmFwaE1hbmFnZXInKTtcbnZhciBDb1NFTGF5b3V0ID0gcmVxdWlyZSgnLi9Db1NFTGF5b3V0Jyk7XG52YXIgQ29TRU5vZGUgPSByZXF1aXJlKCcuL0NvU0VOb2RlJyk7XG5cbnZhciBkZWZhdWx0cyA9IHtcbiAgLy8gQ2FsbGVkIG9uIGBsYXlvdXRyZWFkeWBcbiAgcmVhZHk6IGZ1bmN0aW9uICgpIHtcbiAgfSxcbiAgLy8gQ2FsbGVkIG9uIGBsYXlvdXRzdG9wYFxuICBzdG9wOiBmdW5jdGlvbiAoKSB7XG4gIH0sXG4gIC8vIGluY2x1ZGUgbGFiZWxzIGluIG5vZGUgZGltZW5zaW9uc1xuICBub2RlRGltZW5zaW9uc0luY2x1ZGVMYWJlbHM6IGZhbHNlLFxuICAvLyBudW1iZXIgb2YgdGlja3MgcGVyIGZyYW1lOyBoaWdoZXIgaXMgZmFzdGVyIGJ1dCBtb3JlIGplcmt5XG4gIHJlZnJlc2g6IDMwLFxuICAvLyBXaGV0aGVyIHRvIGZpdCB0aGUgbmV0d29yayB2aWV3IGFmdGVyIHdoZW4gZG9uZVxuICBmaXQ6IHRydWUsXG4gIC8vIFBhZGRpbmcgb24gZml0XG4gIHBhZGRpbmc6IDEwLFxuICAvLyBXaGV0aGVyIHRvIGVuYWJsZSBpbmNyZW1lbnRhbCBtb2RlXG4gIHJhbmRvbWl6ZTogdHJ1ZSxcbiAgLy8gTm9kZSByZXB1bHNpb24gKG5vbiBvdmVybGFwcGluZykgbXVsdGlwbGllclxuICBub2RlUmVwdWxzaW9uOiA0NTAwLFxuICAvLyBJZGVhbCBlZGdlIChub24gbmVzdGVkKSBsZW5ndGhcbiAgaWRlYWxFZGdlTGVuZ3RoOiA1MCxcbiAgLy8gRGl2aXNvciB0byBjb21wdXRlIGVkZ2UgZm9yY2VzXG4gIGVkZ2VFbGFzdGljaXR5OiAwLjQ1LFxuICAvLyBOZXN0aW5nIGZhY3RvciAobXVsdGlwbGllcikgdG8gY29tcHV0ZSBpZGVhbCBlZGdlIGxlbmd0aCBmb3IgbmVzdGVkIGVkZ2VzXG4gIG5lc3RpbmdGYWN0b3I6IDAuMSxcbiAgLy8gR3Jhdml0eSBmb3JjZSAoY29uc3RhbnQpXG4gIGdyYXZpdHk6IDAuMjUsXG4gIC8vIE1heGltdW0gbnVtYmVyIG9mIGl0ZXJhdGlvbnMgdG8gcGVyZm9ybVxuICBudW1JdGVyOiAyNTAwLFxuICAvLyBGb3IgZW5hYmxpbmcgdGlsaW5nXG4gIHRpbGU6IHRydWUsXG4gIC8vIFR5cGUgb2YgbGF5b3V0IGFuaW1hdGlvbi4gVGhlIG9wdGlvbiBzZXQgaXMgeydkdXJpbmcnLCAnZW5kJywgZmFsc2V9XG4gIGFuaW1hdGU6ICdlbmQnLFxuICAvLyBEdXJhdGlvbiBmb3IgYW5pbWF0ZTplbmRcbiAgYW5pbWF0aW9uRHVyYXRpb246IDUwMCxcbiAgLy8gUmVwcmVzZW50cyB0aGUgYW1vdW50IG9mIHRoZSB2ZXJ0aWNhbCBzcGFjZSB0byBwdXQgYmV0d2VlbiB0aGUgemVybyBkZWdyZWUgbWVtYmVycyBkdXJpbmcgdGhlIHRpbGluZyBvcGVyYXRpb24oY2FuIGFsc28gYmUgYSBmdW5jdGlvbilcbiAgdGlsaW5nUGFkZGluZ1ZlcnRpY2FsOiAxMCxcbiAgLy8gUmVwcmVzZW50cyB0aGUgYW1vdW50IG9mIHRoZSBob3Jpem9udGFsIHNwYWNlIHRvIHB1dCBiZXR3ZWVuIHRoZSB6ZXJvIGRlZ3JlZSBtZW1iZXJzIGR1cmluZyB0aGUgdGlsaW5nIG9wZXJhdGlvbihjYW4gYWxzbyBiZSBhIGZ1bmN0aW9uKVxuICB0aWxpbmdQYWRkaW5nSG9yaXpvbnRhbDogMTAsXG4gIC8vIEdyYXZpdHkgcmFuZ2UgKGNvbnN0YW50KSBmb3IgY29tcG91bmRzXG4gIGdyYXZpdHlSYW5nZUNvbXBvdW5kOiAxLjUsXG4gIC8vIEdyYXZpdHkgZm9yY2UgKGNvbnN0YW50KSBmb3IgY29tcG91bmRzXG4gIGdyYXZpdHlDb21wb3VuZDogMS4wLFxuICAvLyBHcmF2aXR5IHJhbmdlIChjb25zdGFudClcbiAgZ3Jhdml0eVJhbmdlOiAzLjgsXG4gIC8vIEluaXRpYWwgY29vbGluZyBmYWN0b3IgZm9yIGluY3JlbWVudGFsIGxheW91dFxuICBpbml0aWFsRW5lcmd5T25JbmNyZW1lbnRhbDogMC41XG59O1xuXG5mdW5jdGlvbiBleHRlbmQoZGVmYXVsdHMsIG9wdGlvbnMpIHtcbiAgdmFyIG9iaiA9IHt9O1xuXG4gIGZvciAodmFyIGkgaW4gZGVmYXVsdHMpIHtcbiAgICBvYmpbaV0gPSBkZWZhdWx0c1tpXTtcbiAgfVxuXG4gIGZvciAodmFyIGkgaW4gb3B0aW9ucykge1xuICAgIG9ialtpXSA9IG9wdGlvbnNbaV07XG4gIH1cblxuICByZXR1cm4gb2JqO1xufTtcblxuZnVuY3Rpb24gX0NvU0VMYXlvdXQoX29wdGlvbnMpIHtcbiAgdGhpcy5vcHRpb25zID0gZXh0ZW5kKGRlZmF1bHRzLCBfb3B0aW9ucyk7XG4gIGdldFVzZXJPcHRpb25zKHRoaXMub3B0aW9ucyk7XG59XG5cbnZhciBnZXRVc2VyT3B0aW9ucyA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gIGlmIChvcHRpb25zLm5vZGVSZXB1bHNpb24gIT0gbnVsbClcbiAgICBDb1NFQ29uc3RhbnRzLkRFRkFVTFRfUkVQVUxTSU9OX1NUUkVOR1RIID0gRkRMYXlvdXRDb25zdGFudHMuREVGQVVMVF9SRVBVTFNJT05fU1RSRU5HVEggPSBvcHRpb25zLm5vZGVSZXB1bHNpb247XG4gIGlmIChvcHRpb25zLmlkZWFsRWRnZUxlbmd0aCAhPSBudWxsKVxuICAgIENvU0VDb25zdGFudHMuREVGQVVMVF9FREdFX0xFTkdUSCA9IEZETGF5b3V0Q29uc3RhbnRzLkRFRkFVTFRfRURHRV9MRU5HVEggPSBvcHRpb25zLmlkZWFsRWRnZUxlbmd0aDtcbiAgaWYgKG9wdGlvbnMuZWRnZUVsYXN0aWNpdHkgIT0gbnVsbClcbiAgICBDb1NFQ29uc3RhbnRzLkRFRkFVTFRfU1BSSU5HX1NUUkVOR1RIID0gRkRMYXlvdXRDb25zdGFudHMuREVGQVVMVF9TUFJJTkdfU1RSRU5HVEggPSBvcHRpb25zLmVkZ2VFbGFzdGljaXR5O1xuICBpZiAob3B0aW9ucy5uZXN0aW5nRmFjdG9yICE9IG51bGwpXG4gICAgQ29TRUNvbnN0YW50cy5QRVJfTEVWRUxfSURFQUxfRURHRV9MRU5HVEhfRkFDVE9SID0gRkRMYXlvdXRDb25zdGFudHMuUEVSX0xFVkVMX0lERUFMX0VER0VfTEVOR1RIX0ZBQ1RPUiA9IG9wdGlvbnMubmVzdGluZ0ZhY3RvcjtcbiAgaWYgKG9wdGlvbnMuZ3Jhdml0eSAhPSBudWxsKVxuICAgIENvU0VDb25zdGFudHMuREVGQVVMVF9HUkFWSVRZX1NUUkVOR1RIID0gRkRMYXlvdXRDb25zdGFudHMuREVGQVVMVF9HUkFWSVRZX1NUUkVOR1RIID0gb3B0aW9ucy5ncmF2aXR5O1xuICBpZiAob3B0aW9ucy5udW1JdGVyICE9IG51bGwpXG4gICAgQ29TRUNvbnN0YW50cy5NQVhfSVRFUkFUSU9OUyA9IEZETGF5b3V0Q29uc3RhbnRzLk1BWF9JVEVSQVRJT05TID0gb3B0aW9ucy5udW1JdGVyO1xuICBpZiAob3B0aW9ucy5ncmF2aXR5UmFuZ2UgIT0gbnVsbClcbiAgICBDb1NFQ29uc3RhbnRzLkRFRkFVTFRfR1JBVklUWV9SQU5HRV9GQUNUT1IgPSBGRExheW91dENvbnN0YW50cy5ERUZBVUxUX0dSQVZJVFlfUkFOR0VfRkFDVE9SID0gb3B0aW9ucy5ncmF2aXR5UmFuZ2U7XG4gIGlmKG9wdGlvbnMuZ3Jhdml0eUNvbXBvdW5kICE9IG51bGwpXG4gICAgQ29TRUNvbnN0YW50cy5ERUZBVUxUX0NPTVBPVU5EX0dSQVZJVFlfU1RSRU5HVEggPSBGRExheW91dENvbnN0YW50cy5ERUZBVUxUX0NPTVBPVU5EX0dSQVZJVFlfU1RSRU5HVEggPSBvcHRpb25zLmdyYXZpdHlDb21wb3VuZDtcbiAgaWYob3B0aW9ucy5ncmF2aXR5UmFuZ2VDb21wb3VuZCAhPSBudWxsKVxuICAgIENvU0VDb25zdGFudHMuREVGQVVMVF9DT01QT1VORF9HUkFWSVRZX1JBTkdFX0ZBQ1RPUiA9IEZETGF5b3V0Q29uc3RhbnRzLkRFRkFVTFRfQ09NUE9VTkRfR1JBVklUWV9SQU5HRV9GQUNUT1IgPSBvcHRpb25zLmdyYXZpdHlSYW5nZUNvbXBvdW5kO1xuICBpZiAob3B0aW9ucy5pbml0aWFsRW5lcmd5T25JbmNyZW1lbnRhbCAhPSBudWxsKVxuICAgIENvU0VDb25zdGFudHMuREVGQVVMVF9DT09MSU5HX0ZBQ1RPUl9JTkNSRU1FTlRBTCA9IEZETGF5b3V0Q29uc3RhbnRzLkRFRkFVTFRfQ09PTElOR19GQUNUT1JfSU5DUkVNRU5UQUwgPSBvcHRpb25zLmluaXRpYWxFbmVyZ3lPbkluY3JlbWVudGFsO1xuXG4gIENvU0VDb25zdGFudHMuTk9ERV9ESU1FTlNJT05TX0lOQ0xVREVfTEFCRUxTID0gRkRMYXlvdXRDb25zdGFudHMuTk9ERV9ESU1FTlNJT05TX0lOQ0xVREVfTEFCRUxTID0gTGF5b3V0Q29uc3RhbnRzLk5PREVfRElNRU5TSU9OU19JTkNMVURFX0xBQkVMUyA9IG9wdGlvbnMubm9kZURpbWVuc2lvbnNJbmNsdWRlTGFiZWxzO1xuICBDb1NFQ29uc3RhbnRzLkRFRkFVTFRfSU5DUkVNRU5UQUwgPSBGRExheW91dENvbnN0YW50cy5ERUZBVUxUX0lOQ1JFTUVOVEFMID0gTGF5b3V0Q29uc3RhbnRzLkRFRkFVTFRfSU5DUkVNRU5UQUwgPVxuICAgICAgICAgICEob3B0aW9ucy5yYW5kb21pemUpO1xuICBDb1NFQ29uc3RhbnRzLkFOSU1BVEUgPSBGRExheW91dENvbnN0YW50cy5BTklNQVRFID0gTGF5b3V0Q29uc3RhbnRzLkFOSU1BVEUgPSBvcHRpb25zLmFuaW1hdGU7XG4gIENvU0VDb25zdGFudHMuVElMRSA9IG9wdGlvbnMudGlsZTtcbiAgQ29TRUNvbnN0YW50cy5USUxJTkdfUEFERElOR19WRVJUSUNBTCA9IFxuICAgICAgICAgIHR5cGVvZiBvcHRpb25zLnRpbGluZ1BhZGRpbmdWZXJ0aWNhbCA9PT0gJ2Z1bmN0aW9uJyA/IG9wdGlvbnMudGlsaW5nUGFkZGluZ1ZlcnRpY2FsLmNhbGwoKSA6IG9wdGlvbnMudGlsaW5nUGFkZGluZ1ZlcnRpY2FsO1xuICBDb1NFQ29uc3RhbnRzLlRJTElOR19QQURESU5HX0hPUklaT05UQUwgPSBcbiAgICAgICAgICB0eXBlb2Ygb3B0aW9ucy50aWxpbmdQYWRkaW5nSG9yaXpvbnRhbCA9PT0gJ2Z1bmN0aW9uJyA/IG9wdGlvbnMudGlsaW5nUGFkZGluZ0hvcml6b250YWwuY2FsbCgpIDogb3B0aW9ucy50aWxpbmdQYWRkaW5nSG9yaXpvbnRhbDtcbn07XG5cbl9Db1NFTGF5b3V0LnByb3RvdHlwZS5ydW4gPSBmdW5jdGlvbiAoKSB7XG4gIHZhciByZWFkeTtcbiAgdmFyIGZyYW1lSWQ7XG4gIHZhciBvcHRpb25zID0gdGhpcy5vcHRpb25zO1xuICB2YXIgaWRUb0xOb2RlID0gdGhpcy5pZFRvTE5vZGUgPSB7fTtcbiAgdmFyIGxheW91dCA9IHRoaXMubGF5b3V0ID0gbmV3IENvU0VMYXlvdXQoKTtcbiAgdmFyIHNlbGYgPSB0aGlzO1xuICBcbiAgc2VsZi5zdG9wcGVkID0gZmFsc2U7XG5cbiAgdGhpcy5jeSA9IHRoaXMub3B0aW9ucy5jeTtcblxuICB0aGlzLmN5LnRyaWdnZXIoeyB0eXBlOiAnbGF5b3V0c3RhcnQnLCBsYXlvdXQ6IHRoaXMgfSk7XG5cbiAgdmFyIGdtID0gbGF5b3V0Lm5ld0dyYXBoTWFuYWdlcigpO1xuICB0aGlzLmdtID0gZ207XG5cbiAgdmFyIG5vZGVzID0gdGhpcy5vcHRpb25zLmVsZXMubm9kZXMoKTtcbiAgdmFyIGVkZ2VzID0gdGhpcy5vcHRpb25zLmVsZXMuZWRnZXMoKTtcblxuICB0aGlzLnJvb3QgPSBnbS5hZGRSb290KCk7XG4gIHRoaXMucHJvY2Vzc0NoaWxkcmVuTGlzdCh0aGlzLnJvb3QsIHRoaXMuZ2V0VG9wTW9zdE5vZGVzKG5vZGVzKSwgbGF5b3V0KTtcblxuXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgZWRnZXMubGVuZ3RoOyBpKyspIHtcbiAgICB2YXIgZWRnZSA9IGVkZ2VzW2ldO1xuICAgIHZhciBzb3VyY2VOb2RlID0gdGhpcy5pZFRvTE5vZGVbZWRnZS5kYXRhKFwic291cmNlXCIpXTtcbiAgICB2YXIgdGFyZ2V0Tm9kZSA9IHRoaXMuaWRUb0xOb2RlW2VkZ2UuZGF0YShcInRhcmdldFwiKV07XG4gICAgaWYoc291cmNlTm9kZS5nZXRFZGdlc0JldHdlZW4odGFyZ2V0Tm9kZSkubGVuZ3RoID09IDApe1xuICAgICAgdmFyIGUxID0gZ20uYWRkKGxheW91dC5uZXdFZGdlKCksIHNvdXJjZU5vZGUsIHRhcmdldE5vZGUpO1xuICAgICAgZTEuaWQgPSBlZGdlLmlkKCk7XG4gICAgfVxuICB9XG4gIFxuICAgdmFyIGdldFBvc2l0aW9ucyA9IGZ1bmN0aW9uKGVsZSwgaSl7XG4gICAgaWYodHlwZW9mIGVsZSA9PT0gXCJudW1iZXJcIikge1xuICAgICAgZWxlID0gaTtcbiAgICB9XG4gICAgdmFyIHRoZUlkID0gZWxlLmRhdGEoJ2lkJyk7XG4gICAgdmFyIGxOb2RlID0gc2VsZi5pZFRvTE5vZGVbdGhlSWRdO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIHg6IGxOb2RlLmdldFJlY3QoKS5nZXRDZW50ZXJYKCksXG4gICAgICB5OiBsTm9kZS5nZXRSZWN0KCkuZ2V0Q2VudGVyWSgpXG4gICAgfTtcbiAgfTtcbiAgXG4gIC8qXG4gICAqIFJlcG9zaXRpb24gbm9kZXMgaW4gaXRlcmF0aW9ucyBhbmltYXRlZGx5XG4gICAqL1xuICB2YXIgaXRlcmF0ZUFuaW1hdGVkID0gZnVuY3Rpb24gKCkge1xuICAgIC8vIFRoaWdzIHRvIHBlcmZvcm0gYWZ0ZXIgbm9kZXMgYXJlIHJlcG9zaXRpb25lZCBvbiBzY3JlZW5cbiAgICB2YXIgYWZ0ZXJSZXBvc2l0aW9uID0gZnVuY3Rpb24oKSB7XG4gICAgICBpZiAob3B0aW9ucy5maXQpIHtcbiAgICAgICAgb3B0aW9ucy5jeS5maXQob3B0aW9ucy5lbGVzLm5vZGVzKCksIG9wdGlvbnMucGFkZGluZyk7XG4gICAgICB9XG5cbiAgICAgIGlmICghcmVhZHkpIHtcbiAgICAgICAgcmVhZHkgPSB0cnVlO1xuICAgICAgICBzZWxmLmN5Lm9uZSgnbGF5b3V0cmVhZHknLCBvcHRpb25zLnJlYWR5KTtcbiAgICAgICAgc2VsZi5jeS50cmlnZ2VyKHt0eXBlOiAnbGF5b3V0cmVhZHknLCBsYXlvdXQ6IHNlbGZ9KTtcbiAgICAgIH1cbiAgICB9O1xuICAgIFxuICAgIHZhciB0aWNrc1BlckZyYW1lID0gc2VsZi5vcHRpb25zLnJlZnJlc2g7XG4gICAgdmFyIGlzRG9uZTtcblxuICAgIGZvciggdmFyIGkgPSAwOyBpIDwgdGlja3NQZXJGcmFtZSAmJiAhaXNEb25lOyBpKysgKXtcbiAgICAgIGlzRG9uZSA9IHNlbGYuc3RvcHBlZCB8fCBzZWxmLmxheW91dC50aWNrKCk7XG4gICAgfVxuICAgIFxuICAgIC8vIElmIGxheW91dCBpcyBkb25lXG4gICAgaWYgKGlzRG9uZSkge1xuICAgICAgLy8gSWYgdGhlIGxheW91dCBpcyBub3QgYSBzdWJsYXlvdXQgYW5kIGl0IGlzIHN1Y2Nlc3NmdWwgcGVyZm9ybSBwb3N0IGxheW91dC5cbiAgICAgIGlmIChsYXlvdXQuY2hlY2tMYXlvdXRTdWNjZXNzKCkgJiYgIWxheW91dC5pc1N1YkxheW91dCkge1xuICAgICAgICBsYXlvdXQuZG9Qb3N0TGF5b3V0KCk7XG4gICAgICB9XG4gICAgICBcbiAgICAgIC8vIElmIGxheW91dCBoYXMgYSB0aWxpbmdQb3N0TGF5b3V0IGZ1bmN0aW9uIHByb3BlcnR5IGNhbGwgaXQuXG4gICAgICBpZiAobGF5b3V0LnRpbGluZ1Bvc3RMYXlvdXQpIHtcbiAgICAgICAgbGF5b3V0LnRpbGluZ1Bvc3RMYXlvdXQoKTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgbGF5b3V0LmlzTGF5b3V0RmluaXNoZWQgPSB0cnVlO1xuICAgICAgXG4gICAgICBzZWxmLm9wdGlvbnMuZWxlcy5ub2RlcygpLnBvc2l0aW9ucyhnZXRQb3NpdGlvbnMpO1xuICAgICAgXG4gICAgICBhZnRlclJlcG9zaXRpb24oKTtcbiAgICAgIFxuICAgICAgLy8gdHJpZ2dlciBsYXlvdXRzdG9wIHdoZW4gdGhlIGxheW91dCBzdG9wcyAoZS5nLiBmaW5pc2hlcylcbiAgICAgIHNlbGYuY3kub25lKCdsYXlvdXRzdG9wJywgc2VsZi5vcHRpb25zLnN0b3ApO1xuICAgICAgc2VsZi5jeS50cmlnZ2VyKHsgdHlwZTogJ2xheW91dHN0b3AnLCBsYXlvdXQ6IHNlbGYgfSk7XG5cbiAgICAgIGlmIChmcmFtZUlkKSB7XG4gICAgICAgIGNhbmNlbEFuaW1hdGlvbkZyYW1lKGZyYW1lSWQpO1xuICAgICAgfVxuICAgICAgXG4gICAgICByZWFkeSA9IGZhbHNlO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBcbiAgICB2YXIgYW5pbWF0aW9uRGF0YSA9IHNlbGYubGF5b3V0LmdldFBvc2l0aW9uc0RhdGEoKTsgLy8gR2V0IHBvc2l0aW9ucyBvZiBsYXlvdXQgbm9kZXMgbm90ZSB0aGF0IGFsbCBub2RlcyBtYXkgbm90IGJlIGxheW91dCBub2RlcyBiZWNhdXNlIG9mIHRpbGluZ1xuICAgIFxuICAgIC8vIFBvc2l0aW9uIG5vZGVzLCBmb3IgdGhlIG5vZGVzIHdob3NlIGlkIGRvZXMgbm90IGluY2x1ZGVkIGluIGRhdGEgKGJlY2F1c2UgdGhleSBhcmUgcmVtb3ZlZCBmcm9tIHRoZWlyIHBhcmVudHMgYW5kIGluY2x1ZGVkIGluIGR1bW15IGNvbXBvdW5kcylcbiAgICAvLyB1c2UgcG9zaXRpb24gb2YgdGhlaXIgYW5jZXN0b3JzIG9yIGR1bW15IGFuY2VzdG9yc1xuICAgIG9wdGlvbnMuZWxlcy5ub2RlcygpLnBvc2l0aW9ucyhmdW5jdGlvbiAoZWxlLCBpKSB7XG4gICAgICBpZiAodHlwZW9mIGVsZSA9PT0gXCJudW1iZXJcIikge1xuICAgICAgICBlbGUgPSBpO1xuICAgICAgfVxuICAgICAgdmFyIHRoZUlkID0gZWxlLmlkKCk7XG4gICAgICB2YXIgcE5vZGUgPSBhbmltYXRpb25EYXRhW3RoZUlkXTtcbiAgICAgIHZhciB0ZW1wID0gZWxlO1xuICAgICAgLy8gSWYgcE5vZGUgaXMgdW5kZWZpbmVkIHNlYXJjaCB1bnRpbCBmaW5kaW5nIHBvc2l0aW9uIGRhdGEgb2YgaXRzIGZpcnN0IGFuY2VzdG9yIChJdCBtYXkgYmUgZHVtbXkgYXMgd2VsbClcbiAgICAgIHdoaWxlIChwTm9kZSA9PSBudWxsKSB7XG4gICAgICAgIHBOb2RlID0gYW5pbWF0aW9uRGF0YVt0ZW1wLmRhdGEoJ3BhcmVudCcpXSB8fCBhbmltYXRpb25EYXRhWydEdW1teUNvbXBvdW5kXycgKyB0ZW1wLmRhdGEoJ3BhcmVudCcpXTtcbiAgICAgICAgYW5pbWF0aW9uRGF0YVt0aGVJZF0gPSBwTm9kZTtcbiAgICAgICAgdGVtcCA9IHRlbXAucGFyZW50KClbMF07XG4gICAgICAgIGlmKHRlbXAgPT0gdW5kZWZpbmVkKXtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgaWYocE5vZGUgIT0gbnVsbCl7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgeDogcE5vZGUueCxcbiAgICAgICAgICB5OiBwTm9kZS55XG4gICAgICAgIH07XG4gICAgICB9XG4gICAgICBlbHNle1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIHg6IGVsZS54LFxuICAgICAgICAgIHk6IGVsZS55XG4gICAgICAgIH07XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICBhZnRlclJlcG9zaXRpb24oKTtcblxuICAgIGZyYW1lSWQgPSByZXF1ZXN0QW5pbWF0aW9uRnJhbWUoaXRlcmF0ZUFuaW1hdGVkKTtcbiAgfTtcbiAgXG4gIC8qXG4gICogTGlzdGVuICdsYXlvdXRzdGFydGVkJyBldmVudCBhbmQgc3RhcnQgYW5pbWF0ZWQgaXRlcmF0aW9uIGlmIGFuaW1hdGUgb3B0aW9uIGlzICdkdXJpbmcnXG4gICovXG4gIGxheW91dC5hZGRMaXN0ZW5lcignbGF5b3V0c3RhcnRlZCcsIGZ1bmN0aW9uICgpIHtcbiAgICBpZiAoc2VsZi5vcHRpb25zLmFuaW1hdGUgPT09ICdkdXJpbmcnKSB7XG4gICAgICBmcmFtZUlkID0gcmVxdWVzdEFuaW1hdGlvbkZyYW1lKGl0ZXJhdGVBbmltYXRlZCk7XG4gICAgfVxuICB9KTtcbiAgXG4gIGxheW91dC5ydW5MYXlvdXQoKTsgLy8gUnVuIGNvc2UgbGF5b3V0XG4gIFxuICAvKlxuICAgKiBJZiBhbmltYXRlIG9wdGlvbiBpcyBub3QgJ2R1cmluZycgKCdlbmQnIG9yIGZhbHNlKSBwZXJmb3JtIHRoZXNlIGhlcmUgKElmIGl0IGlzICdkdXJpbmcnIHNpbWlsYXIgdGhpbmdzIGFyZSBhbHJlYWR5IHBlcmZvcm1lZClcbiAgICovXG4gIGlmKHRoaXMub3B0aW9ucy5hbmltYXRlICE9PSBcImR1cmluZ1wiKXtcbiAgICBzZWxmLm9wdGlvbnMuZWxlcy5ub2RlcygpLm5vdChcIjpwYXJlbnRcIikubGF5b3V0UG9zaXRpb25zKHNlbGYsIHNlbGYub3B0aW9ucywgZ2V0UG9zaXRpb25zKTsgLy8gVXNlIGxheW91dCBwb3NpdGlvbnMgdG8gcmVwb3NpdGlvbiB0aGUgbm9kZXMgaXQgY29uc2lkZXJzIHRoZSBvcHRpb25zIHBhcmFtZXRlclxuICAgIHJlYWR5ID0gZmFsc2U7XG4gIH1cblxuICByZXR1cm4gdGhpczsgLy8gY2hhaW5pbmdcbn07XG5cbi8vR2V0IHRoZSB0b3AgbW9zdCBvbmVzIG9mIGEgbGlzdCBvZiBub2Rlc1xuX0NvU0VMYXlvdXQucHJvdG90eXBlLmdldFRvcE1vc3ROb2RlcyA9IGZ1bmN0aW9uKG5vZGVzKSB7XG4gIHZhciBub2Rlc01hcCA9IHt9O1xuICBmb3IgKHZhciBpID0gMDsgaSA8IG5vZGVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBub2Rlc01hcFtub2Rlc1tpXS5pZCgpXSA9IHRydWU7XG4gIH1cbiAgdmFyIHJvb3RzID0gbm9kZXMuZmlsdGVyKGZ1bmN0aW9uIChlbGUsIGkpIHtcbiAgICAgIGlmKHR5cGVvZiBlbGUgPT09IFwibnVtYmVyXCIpIHtcbiAgICAgICAgZWxlID0gaTtcbiAgICAgIH1cbiAgICAgIHZhciBwYXJlbnQgPSBlbGUucGFyZW50KClbMF07XG4gICAgICB3aGlsZShwYXJlbnQgIT0gbnVsbCl7XG4gICAgICAgIGlmKG5vZGVzTWFwW3BhcmVudC5pZCgpXSl7XG4gICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIHBhcmVudCA9IHBhcmVudC5wYXJlbnQoKVswXTtcbiAgICAgIH1cbiAgICAgIHJldHVybiB0cnVlO1xuICB9KTtcblxuICByZXR1cm4gcm9vdHM7XG59O1xuXG5fQ29TRUxheW91dC5wcm90b3R5cGUucHJvY2Vzc0NoaWxkcmVuTGlzdCA9IGZ1bmN0aW9uIChwYXJlbnQsIGNoaWxkcmVuLCBsYXlvdXQpIHtcbiAgdmFyIHNpemUgPSBjaGlsZHJlbi5sZW5ndGg7XG4gIGZvciAodmFyIGkgPSAwOyBpIDwgc2l6ZTsgaSsrKSB7XG4gICAgdmFyIHRoZUNoaWxkID0gY2hpbGRyZW5baV07XG4gICAgdmFyIGNoaWxkcmVuX29mX2NoaWxkcmVuID0gdGhlQ2hpbGQuY2hpbGRyZW4oKTtcbiAgICB2YXIgdGhlTm9kZTsgICAgXG5cbiAgICB2YXIgZGltZW5zaW9ucyA9IHRoZUNoaWxkLmxheW91dERpbWVuc2lvbnMoe1xuICAgICAgbm9kZURpbWVuc2lvbnNJbmNsdWRlTGFiZWxzOiB0aGlzLm9wdGlvbnMubm9kZURpbWVuc2lvbnNJbmNsdWRlTGFiZWxzXG4gICAgfSk7XG5cbiAgICBpZiAodGhlQ2hpbGQub3V0ZXJXaWR0aCgpICE9IG51bGxcbiAgICAgICAgICAgICYmIHRoZUNoaWxkLm91dGVySGVpZ2h0KCkgIT0gbnVsbCkge1xuICAgICAgdGhlTm9kZSA9IHBhcmVudC5hZGQobmV3IENvU0VOb2RlKGxheW91dC5ncmFwaE1hbmFnZXIsXG4gICAgICAgICAgICAgIG5ldyBQb2ludEQodGhlQ2hpbGQucG9zaXRpb24oJ3gnKSAtIGRpbWVuc2lvbnMudyAvIDIsIHRoZUNoaWxkLnBvc2l0aW9uKCd5JykgLSBkaW1lbnNpb25zLmggLyAyKSxcbiAgICAgICAgICAgICAgbmV3IERpbWVuc2lvbkQocGFyc2VGbG9hdChkaW1lbnNpb25zLncpLCBwYXJzZUZsb2F0KGRpbWVuc2lvbnMuaCkpKSk7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgdGhlTm9kZSA9IHBhcmVudC5hZGQobmV3IENvU0VOb2RlKHRoaXMuZ3JhcGhNYW5hZ2VyKSk7XG4gICAgfVxuICAgIC8vIEF0dGFjaCBpZCB0byB0aGUgbGF5b3V0IG5vZGVcbiAgICB0aGVOb2RlLmlkID0gdGhlQ2hpbGQuZGF0YShcImlkXCIpO1xuICAgIC8vIEF0dGFjaCB0aGUgcGFkZGluZ3Mgb2YgY3kgbm9kZSB0byBsYXlvdXQgbm9kZVxuICAgIHRoZU5vZGUucGFkZGluZ0xlZnQgPSBwYXJzZUludCggdGhlQ2hpbGQuY3NzKCdwYWRkaW5nJykgKTtcbiAgICB0aGVOb2RlLnBhZGRpbmdUb3AgPSBwYXJzZUludCggdGhlQ2hpbGQuY3NzKCdwYWRkaW5nJykgKTtcbiAgICB0aGVOb2RlLnBhZGRpbmdSaWdodCA9IHBhcnNlSW50KCB0aGVDaGlsZC5jc3MoJ3BhZGRpbmcnKSApO1xuICAgIHRoZU5vZGUucGFkZGluZ0JvdHRvbSA9IHBhcnNlSW50KCB0aGVDaGlsZC5jc3MoJ3BhZGRpbmcnKSApO1xuICAgIFxuICAgIC8vQXR0YWNoIHRoZSBsYWJlbCBwcm9wZXJ0aWVzIHRvIGNvbXBvdW5kIGlmIGxhYmVscyB3aWxsIGJlIGluY2x1ZGVkIGluIG5vZGUgZGltZW5zaW9ucyAgXG4gICAgaWYodGhpcy5vcHRpb25zLm5vZGVEaW1lbnNpb25zSW5jbHVkZUxhYmVscyl7XG4gICAgICBpZih0aGVDaGlsZC5pc1BhcmVudCgpKXtcbiAgICAgICAgICB2YXIgbGFiZWxXaWR0aCA9IHRoZUNoaWxkLmJvdW5kaW5nQm94KHsgaW5jbHVkZUxhYmVsczogdHJ1ZSwgaW5jbHVkZU5vZGVzOiBmYWxzZSB9KS53OyAgICAgICAgICBcbiAgICAgICAgICB2YXIgbGFiZWxIZWlnaHQgPSB0aGVDaGlsZC5ib3VuZGluZ0JveCh7IGluY2x1ZGVMYWJlbHM6IHRydWUsIGluY2x1ZGVOb2RlczogZmFsc2UgfSkuaDtcbiAgICAgICAgICB2YXIgbGFiZWxQb3MgPSB0aGVDaGlsZC5jc3MoXCJ0ZXh0LWhhbGlnblwiKTtcbiAgICAgICAgICB0aGVOb2RlLmxhYmVsV2lkdGggPSBsYWJlbFdpZHRoO1xuICAgICAgICAgIHRoZU5vZGUubGFiZWxIZWlnaHQgPSBsYWJlbEhlaWdodDtcbiAgICAgICAgICB0aGVOb2RlLmxhYmVsUG9zID0gbGFiZWxQb3M7XG4gICAgICB9XG4gICAgfVxuICAgIFxuICAgIC8vIE1hcCB0aGUgbGF5b3V0IG5vZGVcbiAgICB0aGlzLmlkVG9MTm9kZVt0aGVDaGlsZC5kYXRhKFwiaWRcIildID0gdGhlTm9kZTtcblxuICAgIGlmIChpc05hTih0aGVOb2RlLnJlY3QueCkpIHtcbiAgICAgIHRoZU5vZGUucmVjdC54ID0gMDtcbiAgICB9XG5cbiAgICBpZiAoaXNOYU4odGhlTm9kZS5yZWN0LnkpKSB7XG4gICAgICB0aGVOb2RlLnJlY3QueSA9IDA7XG4gICAgfVxuXG4gICAgaWYgKGNoaWxkcmVuX29mX2NoaWxkcmVuICE9IG51bGwgJiYgY2hpbGRyZW5fb2ZfY2hpbGRyZW4ubGVuZ3RoID4gMCkge1xuICAgICAgdmFyIHRoZU5ld0dyYXBoO1xuICAgICAgdGhlTmV3R3JhcGggPSBsYXlvdXQuZ2V0R3JhcGhNYW5hZ2VyKCkuYWRkKGxheW91dC5uZXdHcmFwaCgpLCB0aGVOb2RlKTtcbiAgICAgIHRoaXMucHJvY2Vzc0NoaWxkcmVuTGlzdCh0aGVOZXdHcmFwaCwgY2hpbGRyZW5fb2ZfY2hpbGRyZW4sIGxheW91dCk7XG4gICAgfVxuICB9XG59O1xuXG4vKipcbiAqIEBicmllZiA6IGNhbGxlZCBvbiBjb250aW51b3VzIGxheW91dHMgdG8gc3RvcCB0aGVtIGJlZm9yZSB0aGV5IGZpbmlzaFxuICovXG5fQ29TRUxheW91dC5wcm90b3R5cGUuc3RvcCA9IGZ1bmN0aW9uICgpIHtcbiAgdGhpcy5zdG9wcGVkID0gdHJ1ZTtcblxuICByZXR1cm4gdGhpczsgLy8gY2hhaW5pbmdcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gZ2V0KGN5dG9zY2FwZSkge1xuICByZXR1cm4gX0NvU0VMYXlvdXQ7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vLyByZWdpc3RlcnMgdGhlIGV4dGVuc2lvbiBvbiBhIGN5dG9zY2FwZSBsaWIgcmVmXG52YXIgZ2V0TGF5b3V0ID0gcmVxdWlyZSgnLi9MYXlvdXQnKTtcblxudmFyIHJlZ2lzdGVyID0gZnVuY3Rpb24oIGN5dG9zY2FwZSApe1xuICB2YXIgTGF5b3V0ID0gZ2V0TGF5b3V0KCBjeXRvc2NhcGUgKTtcblxuICBjeXRvc2NhcGUoJ2xheW91dCcsICdjb3NlLWJpbGtlbnQnLCBMYXlvdXQpO1xufTtcblxuLy8gYXV0byByZWcgZm9yIGdsb2JhbHNcbmlmKCB0eXBlb2YgY3l0b3NjYXBlICE9PSAndW5kZWZpbmVkJyApe1xuICByZWdpc3RlciggY3l0b3NjYXBlICk7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gcmVnaXN0ZXI7XG4iXX0= diff --git a/web/js/cytoscape-expand-collapse.js b/web/js/cytoscape-expand-collapse.js new file mode 100644 index 000000000..9bf52b0c6 --- /dev/null +++ b/web/js/cytoscape-expand-collapse.js @@ -0,0 +1,1677 @@ +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.cytoscapeExpandCollapse = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o'); + elementUtilities = _dereq_('./elementUtilities')(cy); + + $container.append($canvas); + + var _sizeCanvas = debounce(function () { + $canvas + .attr('height', $container.height()) + .attr('width', $container.width()) + .css({ + 'position': 'absolute', + 'top': 0, + 'left': 0, + 'z-index': '999' + }) + ; + + setTimeout(function () { + var canvasBb = $canvas.offset(); + var containerBb = $container.offset(); + + $canvas + .css({ + 'top': -(canvasBb.top - containerBb.top), + 'left': -(canvasBb.left - containerBb.left) + }) + ; + + // refresh the cues on canvas resize + if(cy){ + clearDraws(true); + } + }, 0); + + }, 250); + + function sizeCanvas() { + _sizeCanvas(); + } + + sizeCanvas(); + + $(window).bind('resize', function () { + sizeCanvas(); + }); + + var ctx = $canvas[0].getContext('2d'); + + // write options to data + var data = $container.data('cyexpandcollapse'); + if (data == null) { + data = {}; + } + data.options = opts; + + var optCache; + + function options() { + return optCache || (optCache = $container.data('cyexpandcollapse').options); + } + + function clearDraws() { + var w = $container.width(); + var h = $container.height(); + + ctx.clearRect(0, 0, w, h); + } + + function drawExpandCollapseCue(node) { + var children = node.children(); + var collapsedChildren = node._private.data.collapsedChildren; + var hasChildren = children != null && children.length > 0; + // If this is a simple node with no collapsed children return directly + if (!hasChildren && collapsedChildren == null) { + return; + } + + var isCollapsed = node.hasClass('cy-expand-collapse-collapsed-node'); + + //Draw expand-collapse rectangles + var rectSize = options().expandCollapseCueSize; + var lineSize = options().expandCollapseCueLineSize; + var diff; + + var expandcollapseStartX; + var expandcollapseStartY; + var expandcollapseEndX; + var expandcollapseEndY; + var expandcollapseRectSize; + + var expandcollapseCenterX; + var expandcollapseCenterY; + var cueCenter; + + if (options().expandCollapseCuePosition === 'top-left') { + var offset = 1; + var size = cy.zoom() < 1 ? rectSize / (2*cy.zoom()) : rectSize / 2; + + var x = node.position('x') - node.width() / 2 - parseFloat(node.css('padding-left')) + + parseFloat(node.css('border-width')) + size + offset; + var y = node.position('y') - node.height() / 2 - parseFloat(node.css('padding-top')) + + parseFloat(node.css('border-width')) + size + offset; + + cueCenter = { + x : x, + y : y + }; + } else { + var option = options().expandCollapseCuePosition; + cueCenter = typeof option === 'function' ? option.call(this, node) : option; + } + + var expandcollapseCenter = elementUtilities.convertToRenderedPosition(cueCenter); + + // convert to rendered sizes + rectSize = Math.max(rectSize, rectSize * cy.zoom()); + lineSize = Math.max(lineSize, lineSize * cy.zoom()); + diff = (rectSize - lineSize) / 2; + + expandcollapseCenterX = expandcollapseCenter.x; + expandcollapseCenterY = expandcollapseCenter.y; + + expandcollapseStartX = expandcollapseCenterX - rectSize / 2; + expandcollapseStartY = expandcollapseCenterY - rectSize / 2; + expandcollapseEndX = expandcollapseStartX + rectSize; + expandcollapseEndY = expandcollapseStartY + rectSize; + expandcollapseRectSize = rectSize; + + // Draw expand/collapse cue if specified use an image else render it in the default way + if (!isCollapsed && options().expandCueImage) { + var img=new Image(); + img.src = options().expandCueImage; + ctx.drawImage(img, expandcollapseCenterX, expandcollapseCenterY, rectSize, rectSize); + } + else if (isCollapsed && options().collapseCueImage) { + var img=new Image(); + img.src = options().collapseCueImage; + ctx.drawImage(img, expandcollapseCenterX, expandcollapseCenterY, rectSize, rectSize); + } + else { + var oldFillStyle = ctx.fillStyle; + var oldWidth = ctx.lineWidth; + var oldStrokeStyle = ctx.strokeStyle; + + ctx.fillStyle = "black"; + ctx.strokeStyle = "black"; + + ctx.ellipse(expandcollapseCenterX, expandcollapseCenterY, rectSize / 2, rectSize / 2, 0, 0, 2 * Math.PI); + ctx.fill(); + + ctx.beginPath(); + + ctx.strokeStyle = "white"; + ctx.lineWidth = Math.max(2.6, 2.6 * cy.zoom()); + + ctx.moveTo(expandcollapseStartX + diff, expandcollapseStartY + rectSize / 2); + ctx.lineTo(expandcollapseStartX + lineSize + diff, expandcollapseStartY + rectSize / 2); + + if (isCollapsed) { + ctx.moveTo(expandcollapseStartX + rectSize / 2, expandcollapseStartY + diff); + ctx.lineTo(expandcollapseStartX + rectSize / 2, expandcollapseStartY + lineSize + diff); + } + + ctx.closePath(); + ctx.stroke(); + + ctx.strokeStyle = oldStrokeStyle; + ctx.fillStyle = oldFillStyle; + ctx.lineWidth = oldWidth; + } + + node._private.data.expandcollapseRenderedStartX = expandcollapseStartX; + node._private.data.expandcollapseRenderedStartY = expandcollapseStartY; + node._private.data.expandcollapseRenderedCueSize = expandcollapseRectSize; + + nodeWithRenderedCue = node; + } + + { + cy.on('expandcollapse.clearvisualcue', function() { + + if ( nodeWithRenderedCue ) { + clearDraws(); + } + }); + + cy.bind('zoom pan', eZoom = function () { + if ( nodeWithRenderedCue ) { + clearDraws(); + } + }); + + // check if mouse is inside given node + var isInsideCompound = function(node, e){ + if (node){ + var currMousePos = e.position || e.cyPosition; + var topLeft = { + x: (node.position("x") - node.width() / 2 - parseFloat(node.css('padding-left'))), + y: (node.position("y") - node.height() / 2 - parseFloat(node.css('padding-top')))}; + var bottomRight = { + x: (node.position("x") + node.width() / 2 + parseFloat(node.css('padding-right'))), + y: (node.position("y") + node.height() / 2+ parseFloat(node.css('padding-bottom')))}; + + if (currMousePos.x >= topLeft.x && currMousePos.y >= topLeft.y && + currMousePos.x <= bottomRight.x && currMousePos.y <= bottomRight.y){ + return true; + } + } + return false; + }; + + cy.on('mousemove', function(e){ + if(!isInsideCompound(nodeWithRenderedCue, e)){ + clearDraws() + } + else if(nodeWithRenderedCue && !preventDrawing){ + drawExpandCollapseCue(nodeWithRenderedCue); + } + }); + + cy.on('mouseover', 'node', eMouseOver = function (e) { + var node = this; + // clear draws if any + if (api.isCollapsible(node) || api.isExpandable(node)){ + if ( nodeWithRenderedCue && nodeWithRenderedCue.id() != node.id() ) { + clearDraws(); + } + drawExpandCollapseCue(node); + } + }); + + var oldMousePos = null, currMousePos = null; + cy.on('mousedown', function(e){ + oldMousePos = e.renderedPosition || e.cyRenderedPosition + }); + cy.on('mouseup', function(e){ + currMousePos = e.renderedPosition || e.cyRenderedPosition + }); + + cy.on('grab', 'node', eMouseOut = function (e) { + preventDrawing = true; + }); + + cy.on('free', 'node', eMouseOut = function (e) { + preventDrawing = false; + }); + + cy.on('position', 'node', ePosition = function () { + if (nodeWithRenderedCue) + clearDraws(); + }); + + cy.on('remove', 'node', eRemove = function () { + clearDraws(); + nodeWithRenderedCue = null; + }); + + var ur; + cy.on('select', 'node', function(){ + if (this.length > cy.nodes(":selected").length) + this.unselect(); + }); + + cy.on('tap', Tap = function (event) { + var node = nodeWithRenderedCue; + if (node){ + var expandcollapseRenderedStartX = node._private.data.expandcollapseRenderedStartX; + var expandcollapseRenderedStartY = node._private.data.expandcollapseRenderedStartY; + var expandcollapseRenderedRectSize = node._private.data.expandcollapseRenderedCueSize; + var expandcollapseRenderedEndX = expandcollapseRenderedStartX + expandcollapseRenderedRectSize; + var expandcollapseRenderedEndY = expandcollapseRenderedStartY + expandcollapseRenderedRectSize; + + var cyRenderedPos = event.renderedPosition || event.cyRenderedPosition; + var cyRenderedPosX = cyRenderedPos.x; + var cyRenderedPosY = cyRenderedPos.y; + var factor = (options().expandCollapseCueSensitivity - 1) / 2; + + if ( (Math.abs(oldMousePos.x - currMousePos.x) < 5 && Math.abs(oldMousePos.y - currMousePos.y) < 5) + && cyRenderedPosX >= expandcollapseRenderedStartX - expandcollapseRenderedRectSize * factor + && cyRenderedPosX <= expandcollapseRenderedEndX + expandcollapseRenderedRectSize * factor + && cyRenderedPosY >= expandcollapseRenderedStartY - expandcollapseRenderedRectSize * factor + && cyRenderedPosY <= expandcollapseRenderedEndY + expandcollapseRenderedRectSize * factor) { + if(opts.undoable && !ur) + ur = cy.undoRedo({ + defaultActions: false + }); + if(api.isCollapsible(node)) + if (opts.undoable){ + ur.do("collapse", { + nodes: node, + options: opts + }); + } + else + api.collapse(node, opts); + else if(api.isExpandable(node)) + if (opts.undoable) + ur.do("expand", { + nodes: node, + options: opts + }); + else + api.expand(node, opts); + } + } + }); + } + + $container.data('cyexpandcollapse', data); + }, + unbind: function () { + var cy = this.cytoscape('get'); + cy.off('mouseover', 'node', eMouseOver) + .off('mouseout tapdragout', 'node', eMouseOut) + .off('position', 'node', ePosition) + .off('remove', 'node', eRemove) + .off('tap', 'node', eTap) + .off('add', 'node', eAdd) + .off('free', 'node', eFree); + + cy.unbind("zoom pan", eZoom); + } + }; + + if (functions[fn]) { + return functions[fn].apply($(cy.container()), Array.prototype.slice.call(arguments, 1)); + } else if (typeof fn == 'object' || !fn) { + return functions.init.apply($(cy.container()), arguments); + } else { + $.error('No such function `' + fn + '` for cytoscape.js-expand-collapse'); + } + + return $(this); +}; + +},{"./debounce":3,"./elementUtilities":4}],3:[function(_dereq_,module,exports){ +var debounce = (function () { + /** + * lodash 3.1.1 (Custom Build) + * Build: `lodash modern modularize exports="npm" -o ./` + * Copyright 2012-2015 The Dojo Foundation + * Based on Underscore.js 1.8.3 + * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ + /** Used as the `TypeError` message for "Functions" methods. */ + var FUNC_ERROR_TEXT = 'Expected a function'; + + /* Native method references for those with the same name as other `lodash` methods. */ + var nativeMax = Math.max, + nativeNow = Date.now; + + /** + * Gets the number of milliseconds that have elapsed since the Unix epoch + * (1 January 1970 00:00:00 UTC). + * + * @static + * @memberOf _ + * @category Date + * @example + * + * _.defer(function(stamp) { + * console.log(_.now() - stamp); + * }, _.now()); + * // => logs the number of milliseconds it took for the deferred function to be invoked + */ + var now = nativeNow || function () { + return new Date().getTime(); + }; + + /** + * Creates a debounced function that delays invoking `func` until after `wait` + * milliseconds have elapsed since the last time the debounced function was + * invoked. The debounced function comes with a `cancel` method to cancel + * delayed invocations. Provide an options object to indicate that `func` + * should be invoked on the leading and/or trailing edge of the `wait` timeout. + * Subsequent calls to the debounced function return the result of the last + * `func` invocation. + * + * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked + * on the trailing edge of the timeout only if the the debounced function is + * invoked more than once during the `wait` timeout. + * + * See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation) + * for details over the differences between `_.debounce` and `_.throttle`. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to debounce. + * @param {number} [wait=0] The number of milliseconds to delay. + * @param {Object} [options] The options object. + * @param {boolean} [options.leading=false] Specify invoking on the leading + * edge of the timeout. + * @param {number} [options.maxWait] The maximum time `func` is allowed to be + * delayed before it's invoked. + * @param {boolean} [options.trailing=true] Specify invoking on the trailing + * edge of the timeout. + * @returns {Function} Returns the new debounced function. + * @example + * + * // avoid costly calculations while the window size is in flux + * jQuery(window).on('resize', _.debounce(calculateLayout, 150)); + * + * // invoke `sendMail` when the click event is fired, debouncing subsequent calls + * jQuery('#postbox').on('click', _.debounce(sendMail, 300, { + * 'leading': true, + * 'trailing': false + * })); + * + * // ensure `batchLog` is invoked once after 1 second of debounced calls + * var source = new EventSource('/stream'); + * jQuery(source).on('message', _.debounce(batchLog, 250, { + * 'maxWait': 1000 + * })); + * + * // cancel a debounced call + * var todoChanges = _.debounce(batchLog, 1000); + * Object.observe(models.todo, todoChanges); + * + * Object.observe(models, function(changes) { + * if (_.find(changes, { 'user': 'todo', 'type': 'delete'})) { + * todoChanges.cancel(); + * } + * }, ['delete']); + * + * // ...at some point `models.todo` is changed + * models.todo.completed = true; + * + * // ...before 1 second has passed `models.todo` is deleted + * // which cancels the debounced `todoChanges` call + * delete models.todo; + */ + function debounce(func, wait, options) { + var args, + maxTimeoutId, + result, + stamp, + thisArg, + timeoutId, + trailingCall, + lastCalled = 0, + maxWait = false, + trailing = true; + + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + wait = wait < 0 ? 0 : (+wait || 0); + if (options === true) { + var leading = true; + trailing = false; + } else if (isObject(options)) { + leading = !!options.leading; + maxWait = 'maxWait' in options && nativeMax(+options.maxWait || 0, wait); + trailing = 'trailing' in options ? !!options.trailing : trailing; + } + + function cancel() { + if (timeoutId) { + clearTimeout(timeoutId); + } + if (maxTimeoutId) { + clearTimeout(maxTimeoutId); + } + lastCalled = 0; + maxTimeoutId = timeoutId = trailingCall = undefined; + } + + function complete(isCalled, id) { + if (id) { + clearTimeout(id); + } + maxTimeoutId = timeoutId = trailingCall = undefined; + if (isCalled) { + lastCalled = now(); + result = func.apply(thisArg, args); + if (!timeoutId && !maxTimeoutId) { + args = thisArg = undefined; + } + } + } + + function delayed() { + var remaining = wait - (now() - stamp); + if (remaining <= 0 || remaining > wait) { + complete(trailingCall, maxTimeoutId); + } else { + timeoutId = setTimeout(delayed, remaining); + } + } + + function maxDelayed() { + complete(trailing, timeoutId); + } + + function debounced() { + args = arguments; + stamp = now(); + thisArg = this; + trailingCall = trailing && (timeoutId || !leading); + + if (maxWait === false) { + var leadingCall = leading && !timeoutId; + } else { + if (!maxTimeoutId && !leading) { + lastCalled = stamp; + } + var remaining = maxWait - (stamp - lastCalled), + isCalled = remaining <= 0 || remaining > maxWait; + + if (isCalled) { + if (maxTimeoutId) { + maxTimeoutId = clearTimeout(maxTimeoutId); + } + lastCalled = stamp; + result = func.apply(thisArg, args); + } + else if (!maxTimeoutId) { + maxTimeoutId = setTimeout(maxDelayed, remaining); + } + } + if (isCalled && timeoutId) { + timeoutId = clearTimeout(timeoutId); + } + else if (!timeoutId && wait !== maxWait) { + timeoutId = setTimeout(delayed, wait); + } + if (leadingCall) { + isCalled = true; + result = func.apply(thisArg, args); + } + if (isCalled && !timeoutId && !maxTimeoutId) { + args = thisArg = undefined; + } + return result; + } + + debounced.cancel = cancel; + return debounced; + } + + /** + * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`. + * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(1); + * // => false + */ + function isObject(value) { + // Avoid a V8 JIT bug in Chrome 19-20. + // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. + var type = typeof value; + return !!value && (type == 'object' || type == 'function'); + } + + return debounce; + +})(); + +module.exports = debounce; +},{}],4:[function(_dereq_,module,exports){ +function elementUtilities(cy) { + return { + moveNodes: function (positionDiff, nodes, notCalcTopMostNodes) { + var topMostNodes = notCalcTopMostNodes ? nodes : this.getTopMostNodes(nodes); + for (var i = 0; i < topMostNodes.length; i++) { + var node = topMostNodes[i]; + var oldX = node.position("x"); + var oldY = node.position("y"); + node.position({ + x: oldX + positionDiff.x, + y: oldY + positionDiff.y + }); + var children = node.children(); + this.moveNodes(positionDiff, children, true); + } + }, + getTopMostNodes: function (nodes) {//*// + var nodesMap = {}; + for (var i = 0; i < nodes.length; i++) { + nodesMap[nodes[i].id()] = true; + } + var roots = nodes.filter(function (ele, i) { + if(typeof ele === "number") { + ele = i; + } + + var parent = ele.parent()[0]; + while (parent != null) { + if (nodesMap[parent.id()]) { + return false; + } + parent = parent.parent()[0]; + } + return true; + }); + + return roots; + }, + rearrange: function (layoutBy) { + if (typeof layoutBy === "function") { + layoutBy(); + } else if (layoutBy != null) { + var layout = cy.layout(layoutBy); + if (layout && layout.run) { + layout.run(); + } + } + }, + convertToRenderedPosition: function (modelPosition) { + var pan = cy.pan(); + var zoom = cy.zoom(); + + var x = modelPosition.x * zoom + pan.x; + var y = modelPosition.y * zoom + pan.y; + + return { + x: x, + y: y + }; + } + }; +} + +module.exports = elementUtilities; + +},{}],5:[function(_dereq_,module,exports){ +var boundingBoxUtilities = _dereq_('./boundingBoxUtilities'); + +// Expand collapse utilities +function expandCollapseUtilities(cy) { +var elementUtilities = _dereq_('./elementUtilities')(cy); +return { + //the number of nodes moving animatedly after expand operation + animatedlyMovingNodeCount: 0, + /* + * A funtion basicly expanding a node, it is to be called when a node is expanded anyway. + * Single parameter indicates if the node is expanded alone and if it is truthy then layoutBy parameter is considered to + * perform layout after expand. + */ + expandNodeBaseFunction: function (node, single, layoutBy) { + if (!node._private.data.collapsedChildren){ + return; + } + + //check how the position of the node is changed + var positionDiff = { + x: node._private.position.x - node._private.data['position-before-collapse'].x, + y: node._private.position.y - node._private.data['position-before-collapse'].y + }; + + node.removeData("infoLabel"); + node.removeClass('cy-expand-collapse-collapsed-node'); + + node.trigger("expandcollapse.beforeexpand"); + node._private.data.collapsedChildren.restore(); + this.repairEdges(node); + node._private.data.collapsedChildren = null; + + elementUtilities.moveNodes(positionDiff, node.children()); + node.removeData('position-before-collapse'); + + node.trigger("position"); // position not triggered by default when nodes are moved + node.trigger("expandcollapse.afterexpand"); + + // If expand is called just for one node then call end operation to perform layout + if (single) { + this.endOperation(layoutBy); + } + }, + /* + * A helper function to collapse given nodes in a simple way (Without performing layout afterward) + * It collapses all root nodes bottom up. + */ + simpleCollapseGivenNodes: function (nodes) {//*// + nodes.data("collapse", true); + var roots = elementUtilities.getTopMostNodes(nodes); + for (var i = 0; i < roots.length; i++) { + var root = roots[i]; + + // Collapse the nodes in bottom up order + this.collapseBottomUp(root); + } + + return nodes; + }, + /* + * A helper function to expand given nodes in a simple way (Without performing layout afterward) + * It expands all top most nodes top down. + */ + simpleExpandGivenNodes: function (nodes, applyFishEyeViewToEachNode) { + nodes.data("expand", true); // Mark that the nodes are still to be expanded + var roots = elementUtilities.getTopMostNodes(nodes); + for (var i = 0; i < roots.length; i++) { + var root = roots[i]; + this.expandTopDown(root, applyFishEyeViewToEachNode); // For each root node expand top down + } + return nodes; + }, + /* + * Expands all nodes by expanding all top most nodes top down with their descendants. + */ + simpleExpandAllNodes: function (nodes, applyFishEyeViewToEachNode) { + if (nodes === undefined) { + nodes = cy.nodes(); + } + var orphans; + orphans = elementUtilities.getTopMostNodes(nodes); + var expandStack = []; + for (var i = 0; i < orphans.length; i++) { + var root = orphans[i]; + this.expandAllTopDown(root, expandStack, applyFishEyeViewToEachNode); + } + return expandStack; + }, + /* + * The operation to be performed after expand/collapse. It rearrange nodes by layoutBy parameter. + */ + endOperation: function (layoutBy) { + var self = this; + cy.ready(function () { + setTimeout(function() { + elementUtilities.rearrange(layoutBy); + }, 0); + + }); + }, + /* + * Calls simple expandAllNodes. Then performs end operation. + */ + expandAllNodes: function (nodes, options) {//*// + var expandedStack = this.simpleExpandAllNodes(nodes, options.fisheye); + + this.endOperation(options.layoutBy); + + /* + * return the nodes to undo the operation + */ + return expandedStack; + }, + /* + * Expands the root and its collapsed descendents in top down order. + */ + expandAllTopDown: function (root, expandStack, applyFishEyeViewToEachNode) { + if (root._private.data.collapsedChildren != null) { + expandStack.push(root); + this.expandNode(root, applyFishEyeViewToEachNode); + } + var children = root.children(); + for (var i = 0; i < children.length; i++) { + var node = children[i]; + this.expandAllTopDown(node, expandStack, applyFishEyeViewToEachNode); + } + }, + //Expand the given nodes perform end operation after expandation + expandGivenNodes: function (nodes, options) { + // If there is just one node to expand we need to animate for fisheye view, but if there are more then one node we do not + if (nodes.length === 1) { + + var node = nodes[0]; + if (node._private.data.collapsedChildren != null) { + // Expand the given node the third parameter indicates that the node is simple which ensures that fisheye parameter will be considered + this.expandNode(node, options.fisheye, true, options.animate, options.layoutBy); + } + } + else { + // First expand given nodes and then perform layout according to the layoutBy parameter + this.simpleExpandGivenNodes(nodes, options.fisheye); + this.endOperation(options.layoutBy); + } + + /* + * return the nodes to undo the operation + */ + return nodes; + }, + //collapse the given nodes then perform end operation + collapseGivenNodes: function (nodes, options) { + /* + * In collapse operation there is no fisheye view to be applied so there is no animation to be destroyed here. We can do this + * in a batch. + */ + cy.startBatch(); + this.simpleCollapseGivenNodes(nodes, options); + cy.endBatch(); + + nodes.trigger("position"); // position not triggered by default when collapseNode is called + this.endOperation(options.layoutBy); + + // Update the style + cy.style().update(); + + /* + * return the nodes to undo the operation + */ + return nodes; + }, + //collapse the nodes in bottom up order starting from the root + collapseBottomUp: function (root) { + var children = root.children(); + for (var i = 0; i < children.length; i++) { + var node = children[i]; + this.collapseBottomUp(node); + } + //If the root is a compound node to be collapsed then collapse it + if (root.data("collapse") && root.children().length > 0) { + this.collapseNode(root); + root.removeData("collapse"); + } + }, + //expand the nodes in top down order starting from the root + expandTopDown: function (root, applyFishEyeViewToEachNode) { + if (root.data("expand") && root._private.data.collapsedChildren != null) { + // Expand the root and unmark its expand data to specify that it is no more to be expanded + this.expandNode(root, applyFishEyeViewToEachNode); + root.removeData("expand"); + } + // Make a recursive call for children of root + var children = root.children(); + for (var i = 0; i < children.length; i++) { + var node = children[i]; + this.expandTopDown(node); + } + }, + // Converst the rendered position to model position according to global pan and zoom values + convertToModelPosition: function (renderedPosition) { + var pan = cy.pan(); + var zoom = cy.zoom(); + + var x = (renderedPosition.x - pan.x) / zoom; + var y = (renderedPosition.y - pan.y) / zoom; + + return { + x: x, + y: y + }; + }, + /* + * This method expands the given node. It considers applyFishEyeView, animate and layoutBy parameters. + * It also considers single parameter which indicates if this node is expanded alone. If this parameter is truthy along with + * applyFishEyeView parameter then the state of view port is to be changed to have extra space on the screen (if needed) before appliying the + * fisheye view. + */ + expandNode: function (node, applyFishEyeView, single, animate, layoutBy) { + var self = this; + + var commonExpandOperation = function (node, applyFishEyeView, single, animate, layoutBy) { + if (applyFishEyeView) { + + node._private.data['width-before-fisheye'] = node._private.data['size-before-collapse'].w; + node._private.data['height-before-fisheye'] = node._private.data['size-before-collapse'].h; + + // Fisheye view expand the node. + // The first paramter indicates the node to apply fisheye view, the third parameter indicates the node + // to be expanded after fisheye view is applied. + self.fishEyeViewExpandGivenNode(node, single, node, animate, layoutBy); + } + + // If one of these parameters is truthy it means that expandNodeBaseFunction is already to be called. + // However if none of them is truthy we need to call it here. + if (!single || !applyFishEyeView || !animate) { + self.expandNodeBaseFunction(node, single, layoutBy); + } + }; + + if (node._private.data.collapsedChildren != null) { + this.storeWidthHeight(node); + var animating = false; // Variable to check if there is a current animation, if there is commonExpandOperation will be called after animation + + // If the node is the only node to expand and fisheye view should be applied, then change the state of viewport + // to create more space on screen (If needed) + if (applyFishEyeView && single) { + var topLeftPosition = this.convertToModelPosition({x: 0, y: 0}); + var bottomRightPosition = this.convertToModelPosition({x: cy.width(), y: cy.height()}); + var padding = 80; + var bb = { + x1: topLeftPosition.x, + x2: bottomRightPosition.x, + y1: topLeftPosition.y, + y2: bottomRightPosition.y + }; + + var nodeBB = { + x1: node._private.position.x - node._private.data['size-before-collapse'].w / 2 - padding, + x2: node._private.position.x + node._private.data['size-before-collapse'].w / 2 + padding, + y1: node._private.position.y - node._private.data['size-before-collapse'].h / 2 - padding, + y2: node._private.position.y + node._private.data['size-before-collapse'].h / 2 + padding + }; + + var unionBB = boundingBoxUtilities.getUnion(nodeBB, bb); + + // If these bboxes are not equal then we need to change the viewport state (by pan and zoom) + if (!boundingBoxUtilities.equalBoundingBoxes(unionBB, bb)) { + var viewPort = cy.getFitViewport(unionBB, 10); + var self = this; + animating = animate; // Signal that there is an animation now and commonExpandOperation will be called after animation + // Check if we need to animate during pan and zoom + if (animate) { + cy.animate({ + pan: viewPort.pan, + zoom: viewPort.zoom, + complete: function () { + commonExpandOperation(node, applyFishEyeView, single, animate, layoutBy); + } + }, { + duration: 1000 + }); + } + else { + cy.zoom(viewPort.zoom); + cy.pan(viewPort.pan); + } + } + } + + // If animating is not true we need to call commonExpandOperation here + if (!animating) { + commonExpandOperation(node, applyFishEyeView, single, animate, layoutBy); + } + + //return the node to undo the operation + return node; + } + }, + //collapse the given node without performing end operation + collapseNode: function (node) { + if (node._private.data.collapsedChildren == null) { + node.data('position-before-collapse', { + x: node.position().x, + y: node.position().y + }); + + node.data('size-before-collapse', { + w: node.outerWidth(), + h: node.outerHeight() + }); + + var children = node.children(); + + children.unselect(); + children.connectedEdges().unselect(); + + node.trigger("expandcollapse.beforecollapse"); + + this.barrowEdgesOfcollapsedChildren(node); + this.removeChildren(node, node); + node.addClass('cy-expand-collapse-collapsed-node'); + + node.trigger("expandcollapse.aftercollapse"); + + node.position(node.data('position-before-collapse')); + + //return the node to undo the operation + return node; + } + }, + storeWidthHeight: function (node) {//*// + if (node != null) { + node._private.data['x-before-fisheye'] = this.xPositionInParent(node); + node._private.data['y-before-fisheye'] = this.yPositionInParent(node); + node._private.data['width-before-fisheye'] = node.outerWidth(); + node._private.data['height-before-fisheye'] = node.outerHeight(); + + if (node.parent()[0] != null) { + this.storeWidthHeight(node.parent()[0]); + } + } + + }, + /* + * Apply fisheye view to the given node. nodeToExpand will be expanded after the operation. + * The other parameter are to be passed by parameters directly in internal function calls. + */ + fishEyeViewExpandGivenNode: function (node, single, nodeToExpand, animate, layoutBy) { + var siblings = this.getSiblings(node); + + var x_a = this.xPositionInParent(node); + var y_a = this.yPositionInParent(node); + + var d_x_left = Math.abs((node._private.data['width-before-fisheye'] - node.outerWidth()) / 2); + var d_x_right = Math.abs((node._private.data['width-before-fisheye'] - node.outerWidth()) / 2); + var d_y_upper = Math.abs((node._private.data['height-before-fisheye'] - node.outerHeight()) / 2); + var d_y_lower = Math.abs((node._private.data['height-before-fisheye'] - node.outerHeight()) / 2); + + var abs_diff_on_x = Math.abs(node._private.data['x-before-fisheye'] - x_a); + var abs_diff_on_y = Math.abs(node._private.data['y-before-fisheye'] - y_a); + + // Center went to LEFT + if (node._private.data['x-before-fisheye'] > x_a) { + d_x_left = d_x_left + abs_diff_on_x; + d_x_right = d_x_right - abs_diff_on_x; + } + // Center went to RIGHT + else { + d_x_left = d_x_left - abs_diff_on_x; + d_x_right = d_x_right + abs_diff_on_x; + } + + // Center went to UP + if (node._private.data['y-before-fisheye'] > y_a) { + d_y_upper = d_y_upper + abs_diff_on_y; + d_y_lower = d_y_lower - abs_diff_on_y; + } + // Center went to DOWN + else { + d_y_upper = d_y_upper - abs_diff_on_y; + d_y_lower = d_y_lower + abs_diff_on_y; + } + + var xPosInParentSibling = []; + var yPosInParentSibling = []; + + for (var i = 0; i < siblings.length; i++) { + xPosInParentSibling.push(this.xPositionInParent(siblings[i])); + yPosInParentSibling.push(this.yPositionInParent(siblings[i])); + } + + for (var i = 0; i < siblings.length; i++) { + var sibling = siblings[i]; + + var x_b = xPosInParentSibling[i]; + var y_b = yPosInParentSibling[i]; + + var slope = (y_b - y_a) / (x_b - x_a); + + var d_x = 0; + var d_y = 0; + var T_x = 0; + var T_y = 0; + + // Current sibling is on the LEFT + if (x_a > x_b) { + d_x = d_x_left; + } + // Current sibling is on the RIGHT + else { + d_x = d_x_right; + } + // Current sibling is on the UPPER side + if (y_a > y_b) { + d_y = d_y_upper; + } + // Current sibling is on the LOWER side + else { + d_y = d_y_lower; + } + + if (isFinite(slope)) { + T_x = Math.min(d_x, (d_y / Math.abs(slope))); + } + + if (slope !== 0) { + T_y = Math.min(d_y, (d_x * Math.abs(slope))); + } + + if (x_a > x_b) { + T_x = -1 * T_x; + } + + if (y_a > y_b) { + T_y = -1 * T_y; + } + + // Move the sibling in the special way + this.fishEyeViewMoveNode(sibling, T_x, T_y, nodeToExpand, single, animate, layoutBy); + } + + // If there is no sibling call expand node base function here else it is to be called one of fishEyeViewMoveNode() calls + if (siblings.length == 0) { + this.expandNodeBaseFunction(nodeToExpand, single, layoutBy); + } + + if (node.parent()[0] != null) { + // Apply fisheye view to the parent node as well ( If exists ) + this.fishEyeViewExpandGivenNode(node.parent()[0], single, nodeToExpand, animate, layoutBy); + } + + return node; + }, + getSiblings: function (node) { + var siblings; + + if (node.parent()[0] == null) { + siblings = cy.collection(); + var orphans = cy.nodes(":visible").orphans(); + + for (var i = 0; i < orphans.length; i++) { + if (orphans[i] != node) { + siblings = siblings.add(orphans[i]); + } + } + } else { + siblings = node.siblings(":visible"); + } + + return siblings; + }, + /* + * Move node operation specialized for fish eye view expand operation + * Moves the node by moving its descandents. Movement is animated if both single and animate flags are truthy. + */ + fishEyeViewMoveNode: function (node, T_x, T_y, nodeToExpand, single, animate, layoutBy) { + var childrenList = node.children(":visible"); + var self = this; + + /* + * If the node is simple move itself directly else move it by moving its children by a self recursive call + */ + if (childrenList.length == 0) { + var newPosition = {x: node._private.position.x + T_x, y: node._private.position.y + T_y}; + if (!single || !animate) { + node._private.position.x = newPosition.x; + node._private.position.y = newPosition.y; + } + else { + this.animatedlyMovingNodeCount++; + node.animate({ + position: newPosition, + complete: function () { + self.animatedlyMovingNodeCount--; + if (self.animatedlyMovingNodeCount > 0 || !nodeToExpand.hasClass('cy-expand-collapse-collapsed-node')) { + + return; + } + + // If all nodes are moved we are ready to expand so call expand node base function + self.expandNodeBaseFunction(nodeToExpand, single, layoutBy); + + } + }, { + duration: 1000 + }); + } + } + else { + for (var i = 0; i < childrenList.length; i++) { + this.fishEyeViewMoveNode(childrenList[i], T_x, T_y, nodeToExpand, single, animate, layoutBy); + } + } + }, + xPositionInParent: function (node) {//*// + var parent = node.parent()[0]; + var x_a = 0.0; + + // Given node is not a direct child of the the root graph + if (parent != null) { + x_a = node.relativePosition('x') + (parent.width() / 2); + } + // Given node is a direct child of the the root graph + + else { + x_a = node.position('x'); + } + + return x_a; + }, + yPositionInParent: function (node) {//*// + var parent = node.parent()[0]; + + var y_a = 0.0; + + // Given node is not a direct child of the the root graph + if (parent != null) { + y_a = node.relativePosition('y') + (parent.height() / 2); + } + // Given node is a direct child of the the root graph + + else { + y_a = node.position('y'); + } + + return y_a; + }, + /* + * for all children of the node parameter call this method + * with the same root parameter, + * remove the child and add the removed child to the collapsedchildren data + * of the root to restore them in the case of expandation + * root._private.data.collapsedChildren keeps the nodes to restore when the + * root is expanded + */ + removeChildren: function (node, root) { + var children = node.children(); + for (var i = 0; i < children.length; i++) { + var child = children[i]; + this.removeChildren(child, root); + var removedChild = child.remove(); + if (root._private.data.collapsedChildren == null) { + root._private.data.collapsedChildren = removedChild; + } + else { + root._private.data.collapsedChildren = root._private.data.collapsedChildren.union(removedChild); + } + } + }, + isMetaEdge: function(edge) { + return edge.hasClass("cy-expand-collapse-meta-edge"); + }, + barrowEdgesOfcollapsedChildren: function(node) { + var relatedNodes = node.descendants(); + var edges = relatedNodes.edgesWith(cy.nodes().not(relatedNodes.union(node))); + + var relatedNodeMap = {}; + + relatedNodes.each(function(ele, i) { + if(typeof ele === "number") { + ele = i; + } + relatedNodeMap[ele.id()] = true; + }); + + for (var i = 0; i < edges.length; i++) { + var edge = edges[i]; + var source = edge.source(); + var target = edge.target(); + + if (!this.isMetaEdge(edge)) { // is original + var originalEndsData = { + source: source, + target: target + }; + + edge.addClass("cy-expand-collapse-meta-edge"); + edge.data('originalEnds', originalEndsData); + } + + edge.move({ + target: !relatedNodeMap[target.id()] ? target.id() : node.id(), + source: !relatedNodeMap[source.id()] ? source.id() : node.id() + }); + } + }, + findNewEnd: function(node) { + var current = node; + + while( !current.inside() ) { + current = current.parent(); + } + + return current; + }, + repairEdges: function(node) { + var connectedMetaEdges = node.connectedEdges('.cy-expand-collapse-meta-edge'); + + for (var i = 0; i < connectedMetaEdges.length; i++) { + var edge = connectedMetaEdges[i]; + var originalEnds = edge.data('originalEnds'); + var currentSrcId = edge.data('source'); + var currentTgtId = edge.data('target'); + + if ( currentSrcId === node.id() ) { + edge = edge.move({ + source: this.findNewEnd(originalEnds.source).id() + }); + } else { + edge = edge.move({ + target: this.findNewEnd(originalEnds.target).id() + }); + } + + if ( edge.data('source') === originalEnds.source.id() && edge.data('target') === originalEnds.target.id() ) { + edge.removeClass('cy-expand-collapse-meta-edge'); + edge.removeData('originalEnds'); + } + } + }, + /*node is an outer node of root + if root is not it's anchestor + and it is not the root itself*/ + isOuterNode: function (node, root) {//*// + var temp = node; + while (temp != null) { + if (temp == root) { + return false; + } + temp = temp.parent()[0]; + } + return true; + }, + /** + * Get all collapsed children - including nested ones + * @param node : a collapsed node + * @param collapsedChildren : a collection to store the result + * @return : collapsed children + */ + getCollapsedChildrenRecursively: function(node, collapsedChildren){ + var children = node.data('collapsedChildren'); + var i; + for (i=0; i < children.length; i++){ + if (children[i].data('collapsedChildren')){ + collapsedChildren = collapsedChildren.union(this.getCollapsedChildrenRecursively(children[i], collapsedChildren)); + } + collapsedChildren = collapsedChildren.union(children[i]); + } + return collapsedChildren; + } +} +}; + +module.exports = expandCollapseUtilities; + +},{"./boundingBoxUtilities":1,"./elementUtilities":4}],6:[function(_dereq_,module,exports){ +; +(function () { + 'use strict'; + + // registers the extension on a cytoscape lib ref + var register = function (cytoscape, $) { + + if (!cytoscape) { + return; + } // can't register if cytoscape unspecified + + var expandCollapseUtilities; + var undoRedoUtilities = _dereq_('./undoRedoUtilities'); + var cueUtilities = _dereq_("./cueUtilities"); + + var options = { + layoutBy: null, // for rearrange after expand/collapse. It's just layout options or whole layout function. Choose your side! + fisheye: true, // whether to perform fisheye view after expand/collapse you can specify a function too + animate: true, // whether to animate on drawing changes you can specify a function too + ready: function () { }, // callback when expand/collapse initialized + undoable: true, // and if undoRedoExtension exists, + + cueEnabled: true, // Whether cues are enabled + expandCollapseCuePosition: 'top-left', // default cue position is top left you can specify a function per node too + expandCollapseCueSize: 12, // size of expand-collapse cue + expandCollapseCueLineSize: 8, // size of lines used for drawing plus-minus icons + expandCueImage: undefined, // image of expand icon if undefined draw regular expand cue + collapseCueImage: undefined, // image of collapse icon if undefined draw regular collapse cue + expandCollapseCueSensitivity: 1 // sensitivity of expand-collapse cues + }; + + function setOptions(from) { + var tempOpts = {}; + for (var key in options) + tempOpts[key] = options[key]; + + for (var key in from) + if (tempOpts.hasOwnProperty(key)) + tempOpts[key] = from[key]; + return tempOpts; + } + + // evaluate some specific options in case of they are specified as functions to be dynamically changed + function evalOptions(options) { + var animate = typeof options.animate === 'function' ? options.animate.call() : options.animate; + var fisheye = typeof options.fisheye === 'function' ? options.fisheye.call() : options.fisheye; + + options.animate = animate; + options.fisheye = fisheye; + } + + // creates and returns the API instance for the extension + function createExtensionAPI(cy) { + var api = {}; // API to be returned + // set functions + + // set all options at once + api.setOptions = function(opts) { + options = opts; + }; + + // set the option whose name is given + api.setOption = function (name, value) { + options[name] = value; + }; + + // Collection functions + + // collapse given eles extend options with given param + api.collapse = function (_eles, opts) { + var eles = this.collapsibleNodes(_eles); + var tempOptions = setOptions(opts); + evalOptions(tempOptions); + + return expandCollapseUtilities.collapseGivenNodes(eles, tempOptions); + }; + + // collapse given eles recursively extend options with given param + api.collapseRecursively = function (_eles, opts) { + var eles = this.collapsibleNodes(_eles); + var tempOptions = setOptions(opts); + evalOptions(tempOptions); + + return this.collapse(eles.union(eles.descendants()), tempOptions); + }; + + // expand given eles extend options with given param + api.expand = function (_eles, opts) { + var eles = this.expandableNodes(_eles); + var tempOptions = setOptions(opts); + evalOptions(tempOptions); + + return expandCollapseUtilities.expandGivenNodes(eles, tempOptions); + }; + + // expand given eles recusively extend options with given param + api.expandRecursively = function (_eles, opts) { + var eles = this.expandableNodes(_eles); + var tempOptions = setOptions(opts); + evalOptions(tempOptions); + + return expandCollapseUtilities.expandAllNodes(eles, tempOptions); + }; + + + // Core functions + + // collapse all collapsible nodes + api.collapseAll = function (opts) { + var tempOptions = setOptions(opts); + evalOptions(tempOptions); + + return this.collapseRecursively(this.collapsibleNodes(), tempOptions); + }; + + // expand all expandable nodes + api.expandAll = function (opts) { + var tempOptions = setOptions(opts); + evalOptions(tempOptions); + + return this.expandRecursively(this.expandableNodes(), tempOptions); + }; + + + // Utility functions + + // returns if the given node is expandable + api.isExpandable = function (node) { + return node.hasClass('cy-expand-collapse-collapsed-node'); + }; + + // returns if the given node is collapsible + api.isCollapsible = function (node) { + return !this.isExpandable(node) && node.isParent(); + }; + + // get collapsible ones inside given nodes if nodes parameter is not specified consider all nodes + api.collapsibleNodes = function (_nodes) { + var self = this; + var nodes = _nodes ? _nodes : cy.nodes(); + return nodes.filter(function (ele, i) { + if(typeof ele === "number") { + ele = i; + } + return self.isCollapsible(ele); + }); + }; + + // get expandable ones inside given nodes if nodes parameter is not specified consider all nodes + api.expandableNodes = function (_nodes) { + var self = this; + var nodes = _nodes ? _nodes : cy.nodes(); + return nodes.filter(function (ele, i) { + if(typeof ele === "number") { + ele = i; + } + return self.isExpandable(ele); + }); + }; + + // Get the children of the given collapsed node which are removed during collapse operation + api.getCollapsedChildren = function (node) { + return node.data('collapsedChildren'); + }; + + /** Get collapsed children recursively including nested collapsed children + * Returned value includes edges and nodes, use selector to get edges or nodes + * @param node : a collapsed node + * @return all collapsed children + */ + api.getCollapsedChildrenRecursively = function(node) { + var collapsedChildren = cy.collection(); + return expandCollapseUtilities.getCollapsedChildrenRecursively(node, collapsedChildren); + }; + + /** Get collapsed children of all collapsed nodes recursively including nested collapsed children + * Returned value includes edges and nodes, use selector to get edges or nodes + * @return all collapsed children + */ + api.getAllCollapsedChildrenRecursively = function(){ + var collapsedChildren = cy.collection(); + var collapsedNodes = cy.nodes(".cy-expand-collapse-collapsed-node"); + var j; + for (j=0; j < collapsedNodes.length; j++){ + collapsedChildren = collapsedChildren.union(this.getCollapsedChildrenRecursively(collapsedNodes[j])); + } + return collapsedChildren; + }; + // This method forces the visual cue to be cleared. It is to be called in extreme cases + api.clearVisualCue = function(node) { + cy.trigger('expandcollapse.clearvisualcue'); + }; + + // This method works problematic TODO fix related bugs and expose it + // Unbinds cue events +// api.disableCue = function() { +// if (options.cueEnabled) { +// cueUtilities('unbind', cy); +// options.cueEnabled = false; +// } +// } + + return api; // Return the API instance + } + + var api; // Define the api instance + + // register the extension cy.expandCollapse() + cytoscape("core", "expandCollapse", function (opts) { + // If opts is not 'get' that is it is a real options object then initilize the extension + if (opts !== 'get') { + var cy = this; + options = setOptions(opts); + + expandCollapseUtilities = _dereq_('./expandCollapseUtilities')(cy); + api = createExtensionAPI(cy); // creates and returns the API instance for the extension + undoRedoUtilities(cy, api); + + if(options.cueEnabled) + cueUtilities(options, cy, api, $); + + + options.ready(); + } + + return api; // Expose the API to the users + }); + }; + + + if (typeof module !== 'undefined' && module.exports) { // expose as a commonjs module + module.exports = register; + } + + if (typeof define !== 'undefined' && define.amd) { // expose as an amd/requirejs module + define('cytoscape-expand-collapse', function () { + return register; + }); + } + + if (typeof cytoscape !== 'undefined' && typeof jQuery !== 'undefined') { // expose to global cytoscape (i.e. window.cytoscape) + register(cytoscape, jQuery); + } + +})(); + +},{"./cueUtilities":2,"./expandCollapseUtilities":5,"./undoRedoUtilities":7}],7:[function(_dereq_,module,exports){ +module.exports = function (cy, api) { + if (cy.undoRedo == null) + return; + + var ur = cy.undoRedo({}, true); + + function getEles(_eles) { + return (typeof _eles === "string") ? cy.$(_eles) : _eles; + } + + function getNodePositions() { + var positions = {}; + var nodes = cy.nodes(); + + for (var i = 0; i < nodes.length; i++) { + var ele = nodes[i]; + positions[ele.id()] = { + x: ele.position("x"), + y: ele.position("y") + }; + } + + return positions; + } + + function returnToPositions(positions) { + var currentPositions = {}; + cy.nodes().positions(function (ele, i) { + if(typeof ele === "number") { + ele = i; + } + currentPositions[ele.id()] = { + x: ele.position("x"), + y: ele.position("y") + }; + var pos = positions[ele.id()]; + return { + x: pos.x, + y: pos.y + }; + }); + + return currentPositions; + } + + var secondTimeOpts = { + layoutBy: null, + animate: false, + fisheye: false + }; + + function doIt(func) { + return function (args) { + var result = {}; + var nodes = getEles(args.nodes); + if (args.firstTime) { + result.oldData = getNodePositions(); + result.nodes = func.indexOf("All") > 0 ? api[func](args.options) : api[func](nodes, args.options); + } else { + result.oldData = getNodePositions(); + result.nodes = func.indexOf("All") > 0 ? api[func](secondTimeOpts) : api[func](cy.collection(nodes), secondTimeOpts); + returnToPositions(args.oldData); + } + + return result; + }; + } + + var actions = ["collapse", "collapseRecursively", "collapseAll", "expand", "expandRecursively", "expandAll"]; + + for (var i = 0; i < actions.length; i++) { + ur.action(actions[i], doIt(actions[i]), doIt(actions[(i + 3) % 6])); + } + +}; + +},{}]},{},[6])(6) +}); diff --git a/web/js/cytoscape-grid-guide.js b/web/js/cytoscape-grid-guide.js new file mode 100644 index 000000000..cb3874380 --- /dev/null +++ b/web/js/cytoscape-grid-guide.js @@ -0,0 +1,3185 @@ +(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o=0; --s) { + var n = n_stack[s] + if(d_stack[s] <= 0) { + n_stack[s] = new RBNode(n._color, n.key, n.value, n_stack[s+1], n.right, n._count+1) + } else { + n_stack[s] = new RBNode(n._color, n.key, n.value, n.left, n_stack[s+1], n._count+1) + } + } + //Rebalance tree using rotations + //console.log("start insert", key, d_stack) + for(var s=n_stack.length-1; s>1; --s) { + var p = n_stack[s-1] + var n = n_stack[s] + if(p._color === BLACK || n._color === BLACK) { + break + } + var pp = n_stack[s-2] + if(pp.left === p) { + if(p.left === n) { + var y = pp.right + if(y && y._color === RED) { + //console.log("LLr") + p._color = BLACK + pp.right = repaint(BLACK, y) + pp._color = RED + s -= 1 + } else { + //console.log("LLb") + pp._color = RED + pp.left = p.right + p._color = BLACK + p.right = pp + n_stack[s-2] = p + n_stack[s-1] = n + recount(pp) + recount(p) + if(s >= 3) { + var ppp = n_stack[s-3] + if(ppp.left === pp) { + ppp.left = p + } else { + ppp.right = p + } + } + break + } + } else { + var y = pp.right + if(y && y._color === RED) { + //console.log("LRr") + p._color = BLACK + pp.right = repaint(BLACK, y) + pp._color = RED + s -= 1 + } else { + //console.log("LRb") + p.right = n.left + pp._color = RED + pp.left = n.right + n._color = BLACK + n.left = p + n.right = pp + n_stack[s-2] = n + n_stack[s-1] = p + recount(pp) + recount(p) + recount(n) + if(s >= 3) { + var ppp = n_stack[s-3] + if(ppp.left === pp) { + ppp.left = n + } else { + ppp.right = n + } + } + break + } + } + } else { + if(p.right === n) { + var y = pp.left + if(y && y._color === RED) { + //console.log("RRr", y.key) + p._color = BLACK + pp.left = repaint(BLACK, y) + pp._color = RED + s -= 1 + } else { + //console.log("RRb") + pp._color = RED + pp.right = p.left + p._color = BLACK + p.left = pp + n_stack[s-2] = p + n_stack[s-1] = n + recount(pp) + recount(p) + if(s >= 3) { + var ppp = n_stack[s-3] + if(ppp.right === pp) { + ppp.right = p + } else { + ppp.left = p + } + } + break + } + } else { + var y = pp.left + if(y && y._color === RED) { + //console.log("RLr") + p._color = BLACK + pp.left = repaint(BLACK, y) + pp._color = RED + s -= 1 + } else { + //console.log("RLb") + p.left = n.right + pp._color = RED + pp.right = n.left + n._color = BLACK + n.right = p + n.left = pp + n_stack[s-2] = n + n_stack[s-1] = p + recount(pp) + recount(p) + recount(n) + if(s >= 3) { + var ppp = n_stack[s-3] + if(ppp.right === pp) { + ppp.right = n + } else { + ppp.left = n + } + } + break + } + } + } + } + //Return new tree + n_stack[0]._color = BLACK + return new RedBlackTree(cmp, n_stack[0]) +} + + +//Visit all nodes inorder +function doVisitFull(visit, node) { + if(node.left) { + var v = doVisitFull(visit, node.left) + if(v) { return v } + } + var v = visit(node.key, node.value) + if(v) { return v } + if(node.right) { + return doVisitFull(visit, node.right) + } +} + +//Visit half nodes in order +function doVisitHalf(lo, compare, visit, node) { + var l = compare(lo, node.key) + if(l <= 0) { + if(node.left) { + var v = doVisitHalf(lo, compare, visit, node.left) + if(v) { return v } + } + var v = visit(node.key, node.value) + if(v) { return v } + } + if(node.right) { + return doVisitHalf(lo, compare, visit, node.right) + } +} + +//Visit all nodes within a range +function doVisit(lo, hi, compare, visit, node) { + var l = compare(lo, node.key) + var h = compare(hi, node.key) + var v + if(l <= 0) { + if(node.left) { + v = doVisit(lo, hi, compare, visit, node.left) + if(v) { return v } + } + if(h > 0) { + v = visit(node.key, node.value) + if(v) { return v } + } + } + if(h > 0 && node.right) { + return doVisit(lo, hi, compare, visit, node.right) + } +} + + +proto.forEach = function rbTreeForEach(visit, lo, hi) { + if(!this.root) { + return + } + switch(arguments.length) { + case 1: + return doVisitFull(visit, this.root) + break + + case 2: + return doVisitHalf(lo, this._compare, visit, this.root) + break + + case 3: + if(this._compare(lo, hi) >= 0) { + return + } + return doVisit(lo, hi, this._compare, visit, this.root) + break + } +} + +//First item in list +Object.defineProperty(proto, "begin", { + get: function() { + var stack = [] + var n = this.root + while(n) { + stack.push(n) + n = n.left + } + return new RedBlackTreeIterator(this, stack) + } +}) + +//Last item in list +Object.defineProperty(proto, "end", { + get: function() { + var stack = [] + var n = this.root + while(n) { + stack.push(n) + n = n.right + } + return new RedBlackTreeIterator(this, stack) + } +}) + +//Find the ith item in the tree +proto.at = function(idx) { + if(idx < 0) { + return new RedBlackTreeIterator(this, []) + } + var n = this.root + var stack = [] + while(true) { + stack.push(n) + if(n.left) { + if(idx < n.left._count) { + n = n.left + continue + } + idx -= n.left._count + } + if(!idx) { + return new RedBlackTreeIterator(this, stack) + } + idx -= 1 + if(n.right) { + if(idx >= n.right._count) { + break + } + n = n.right + } else { + break + } + } + return new RedBlackTreeIterator(this, []) +} + +proto.ge = function(key) { + var cmp = this._compare + var n = this.root + var stack = [] + var last_ptr = 0 + while(n) { + var d = cmp(key, n.key) + stack.push(n) + if(d <= 0) { + last_ptr = stack.length + } + if(d <= 0) { + n = n.left + } else { + n = n.right + } + } + stack.length = last_ptr + return new RedBlackTreeIterator(this, stack) +} + +proto.gt = function(key) { + var cmp = this._compare + var n = this.root + var stack = [] + var last_ptr = 0 + while(n) { + var d = cmp(key, n.key) + stack.push(n) + if(d < 0) { + last_ptr = stack.length + } + if(d < 0) { + n = n.left + } else { + n = n.right + } + } + stack.length = last_ptr + return new RedBlackTreeIterator(this, stack) +} + +proto.lt = function(key) { + var cmp = this._compare + var n = this.root + var stack = [] + var last_ptr = 0 + while(n) { + var d = cmp(key, n.key) + stack.push(n) + if(d > 0) { + last_ptr = stack.length + } + if(d <= 0) { + n = n.left + } else { + n = n.right + } + } + stack.length = last_ptr + return new RedBlackTreeIterator(this, stack) +} + +proto.le = function(key) { + var cmp = this._compare + var n = this.root + var stack = [] + var last_ptr = 0 + while(n) { + var d = cmp(key, n.key) + stack.push(n) + if(d >= 0) { + last_ptr = stack.length + } + if(d < 0) { + n = n.left + } else { + n = n.right + } + } + stack.length = last_ptr + return new RedBlackTreeIterator(this, stack) +} + +//Finds the item with key if it exists +proto.find = function(key) { + var cmp = this._compare + var n = this.root + var stack = [] + while(n) { + var d = cmp(key, n.key) + stack.push(n) + if(d === 0) { + return new RedBlackTreeIterator(this, stack) + } + if(d <= 0) { + n = n.left + } else { + n = n.right + } + } + return new RedBlackTreeIterator(this, []) +} + +//Removes item with key from tree +proto.remove = function(key) { + var iter = this.find(key) + if(iter) { + return iter.remove() + } + return this +} + +//Returns the item at `key` +proto.get = function(key) { + var cmp = this._compare + var n = this.root + while(n) { + var d = cmp(key, n.key) + if(d === 0) { + return n.value + } + if(d <= 0) { + n = n.left + } else { + n = n.right + } + } + return +} + +//Iterator for red black tree +function RedBlackTreeIterator(tree, stack) { + this.tree = tree + this._stack = stack +} + +var iproto = RedBlackTreeIterator.prototype + +//Test if iterator is valid +Object.defineProperty(iproto, "valid", { + get: function() { + return this._stack.length > 0 + } +}) + +//Node of the iterator +Object.defineProperty(iproto, "node", { + get: function() { + if(this._stack.length > 0) { + return this._stack[this._stack.length-1] + } + return null + }, + enumerable: true +}) + +//Makes a copy of an iterator +iproto.clone = function() { + return new RedBlackTreeIterator(this.tree, this._stack.slice()) +} + +//Swaps two nodes +function swapNode(n, v) { + n.key = v.key + n.value = v.value + n.left = v.left + n.right = v.right + n._color = v._color + n._count = v._count +} + +//Fix up a double black node in a tree +function fixDoubleBlack(stack) { + var n, p, s, z + for(var i=stack.length-1; i>=0; --i) { + n = stack[i] + if(i === 0) { + n._color = BLACK + return + } + //console.log("visit node:", n.key, i, stack[i].key, stack[i-1].key) + p = stack[i-1] + if(p.left === n) { + //console.log("left child") + s = p.right + if(s.right && s.right._color === RED) { + //console.log("case 1: right sibling child red") + s = p.right = cloneNode(s) + z = s.right = cloneNode(s.right) + p.right = s.left + s.left = p + s.right = z + s._color = p._color + n._color = BLACK + p._color = BLACK + z._color = BLACK + recount(p) + recount(s) + if(i > 1) { + var pp = stack[i-2] + if(pp.left === p) { + pp.left = s + } else { + pp.right = s + } + } + stack[i-1] = s + return + } else if(s.left && s.left._color === RED) { + //console.log("case 1: left sibling child red") + s = p.right = cloneNode(s) + z = s.left = cloneNode(s.left) + p.right = z.left + s.left = z.right + z.left = p + z.right = s + z._color = p._color + p._color = BLACK + s._color = BLACK + n._color = BLACK + recount(p) + recount(s) + recount(z) + if(i > 1) { + var pp = stack[i-2] + if(pp.left === p) { + pp.left = z + } else { + pp.right = z + } + } + stack[i-1] = z + return + } + if(s._color === BLACK) { + if(p._color === RED) { + //console.log("case 2: black sibling, red parent", p.right.value) + p._color = BLACK + p.right = repaint(RED, s) + return + } else { + //console.log("case 2: black sibling, black parent", p.right.value) + p.right = repaint(RED, s) + continue + } + } else { + //console.log("case 3: red sibling") + s = cloneNode(s) + p.right = s.left + s.left = p + s._color = p._color + p._color = RED + recount(p) + recount(s) + if(i > 1) { + var pp = stack[i-2] + if(pp.left === p) { + pp.left = s + } else { + pp.right = s + } + } + stack[i-1] = s + stack[i] = p + if(i+1 < stack.length) { + stack[i+1] = n + } else { + stack.push(n) + } + i = i+2 + } + } else { + //console.log("right child") + s = p.left + if(s.left && s.left._color === RED) { + //console.log("case 1: left sibling child red", p.value, p._color) + s = p.left = cloneNode(s) + z = s.left = cloneNode(s.left) + p.left = s.right + s.right = p + s.left = z + s._color = p._color + n._color = BLACK + p._color = BLACK + z._color = BLACK + recount(p) + recount(s) + if(i > 1) { + var pp = stack[i-2] + if(pp.right === p) { + pp.right = s + } else { + pp.left = s + } + } + stack[i-1] = s + return + } else if(s.right && s.right._color === RED) { + //console.log("case 1: right sibling child red") + s = p.left = cloneNode(s) + z = s.right = cloneNode(s.right) + p.left = z.right + s.right = z.left + z.right = p + z.left = s + z._color = p._color + p._color = BLACK + s._color = BLACK + n._color = BLACK + recount(p) + recount(s) + recount(z) + if(i > 1) { + var pp = stack[i-2] + if(pp.right === p) { + pp.right = z + } else { + pp.left = z + } + } + stack[i-1] = z + return + } + if(s._color === BLACK) { + if(p._color === RED) { + //console.log("case 2: black sibling, red parent") + p._color = BLACK + p.left = repaint(RED, s) + return + } else { + //console.log("case 2: black sibling, black parent") + p.left = repaint(RED, s) + continue + } + } else { + //console.log("case 3: red sibling") + s = cloneNode(s) + p.left = s.right + s.right = p + s._color = p._color + p._color = RED + recount(p) + recount(s) + if(i > 1) { + var pp = stack[i-2] + if(pp.right === p) { + pp.right = s + } else { + pp.left = s + } + } + stack[i-1] = s + stack[i] = p + if(i+1 < stack.length) { + stack[i+1] = n + } else { + stack.push(n) + } + i = i+2 + } + } + } +} + +//Removes item at iterator from tree +iproto.remove = function() { + var stack = this._stack + if(stack.length === 0) { + return this.tree + } + //First copy path to node + var cstack = new Array(stack.length) + var n = stack[stack.length-1] + cstack[cstack.length-1] = new RBNode(n._color, n.key, n.value, n.left, n.right, n._count) + for(var i=stack.length-2; i>=0; --i) { + var n = stack[i] + if(n.left === stack[i+1]) { + cstack[i] = new RBNode(n._color, n.key, n.value, cstack[i+1], n.right, n._count) + } else { + cstack[i] = new RBNode(n._color, n.key, n.value, n.left, cstack[i+1], n._count) + } + } + + //Get node + n = cstack[cstack.length-1] + //console.log("start remove: ", n.value) + + //If not leaf, then swap with previous node + if(n.left && n.right) { + //console.log("moving to leaf") + + //First walk to previous leaf + var split = cstack.length + n = n.left + while(n.right) { + cstack.push(n) + n = n.right + } + //Copy path to leaf + var v = cstack[split-1] + cstack.push(new RBNode(n._color, v.key, v.value, n.left, n.right, n._count)) + cstack[split-1].key = n.key + cstack[split-1].value = n.value + + //Fix up stack + for(var i=cstack.length-2; i>=split; --i) { + n = cstack[i] + cstack[i] = new RBNode(n._color, n.key, n.value, n.left, cstack[i+1], n._count) + } + cstack[split-1].left = cstack[split] + } + //console.log("stack=", cstack.map(function(v) { return v.value })) + + //Remove leaf node + n = cstack[cstack.length-1] + if(n._color === RED) { + //Easy case: removing red leaf + //console.log("RED leaf") + var p = cstack[cstack.length-2] + if(p.left === n) { + p.left = null + } else if(p.right === n) { + p.right = null + } + cstack.pop() + for(var i=0; i 0) { + return this._stack[this._stack.length-1].key + } + return + }, + enumerable: true +}) + +//Returns value +Object.defineProperty(iproto, "value", { + get: function() { + if(this._stack.length > 0) { + return this._stack[this._stack.length-1].value + } + return + }, + enumerable: true +}) + + +//Returns the position of this iterator in the sorted list +Object.defineProperty(iproto, "index", { + get: function() { + var idx = 0 + var stack = this._stack + if(stack.length === 0) { + var r = this.tree.root + if(r) { + return r._count + } + return 0 + } else if(stack[stack.length-1].left) { + idx = stack[stack.length-1].left._count + } + for(var s=stack.length-2; s>=0; --s) { + if(stack[s+1] === stack[s].right) { + ++idx + if(stack[s].left) { + idx += stack[s].left._count + } + } + } + return idx + }, + enumerable: true +}) + +//Advances iterator to next element in list +iproto.next = function() { + var stack = this._stack + if(stack.length === 0) { + return + } + var n = stack[stack.length-1] + if(n.right) { + n = n.right + while(n) { + stack.push(n) + n = n.left + } + } else { + stack.pop() + while(stack.length > 0 && stack[stack.length-1].right === n) { + n = stack[stack.length-1] + stack.pop() + } + } +} + +//Checks if iterator is at end of tree +Object.defineProperty(iproto, "hasNext", { + get: function() { + var stack = this._stack + if(stack.length === 0) { + return false + } + if(stack[stack.length-1].right) { + return true + } + for(var s=stack.length-1; s>0; --s) { + if(stack[s-1].left === stack[s]) { + return true + } + } + return false + } +}) + +//Update value +iproto.update = function(value) { + var stack = this._stack + if(stack.length === 0) { + throw new Error("Can't update empty node!") + } + var cstack = new Array(stack.length) + var n = stack[stack.length-1] + cstack[cstack.length-1] = new RBNode(n._color, n.key, value, n.left, n.right, n._count) + for(var i=stack.length-2; i>=0; --i) { + n = stack[i] + if(n.left === stack[i+1]) { + cstack[i] = new RBNode(n._color, n.key, n.value, cstack[i+1], n.right, n._count) + } else { + cstack[i] = new RBNode(n._color, n.key, n.value, n.left, cstack[i+1], n._count) + } + } + return new RedBlackTree(this.tree._compare, cstack[0]) +} + +//Moves iterator backward one element +iproto.prev = function() { + var stack = this._stack + if(stack.length === 0) { + return + } + var n = stack[stack.length-1] + if(n.left) { + n = n.left + while(n) { + stack.push(n) + n = n.right + } + } else { + stack.pop() + while(stack.length > 0 && stack[stack.length-1].left === n) { + n = stack[stack.length-1] + stack.pop() + } + } +} + +//Checks if iterator is at start of tree +Object.defineProperty(iproto, "hasPrev", { + get: function() { + var stack = this._stack + if(stack.length === 0) { + return false + } + if(stack[stack.length-1].left) { + return true + } + for(var s=stack.length-1; s>0; --s) { + if(stack[s-1].right === stack[s]) { + return true + } + } + return false + } +}) + +//Default comparison function +function defaultCompare(a, b) { + if(a < b) { + return -1 + } + if(a > b) { + return 1 + } + return 0 +} + +//Build a tree +function createRBTree(compare) { + return new RedBlackTree(compare || defaultCompare, null) +} +},{}],2:[function(require,module,exports){ +module.exports = function (cytoscape, cy, $) { + + // Needed because parent nodes cannot be moved! + function moveTopDown(node, dx, dy) { + var nodes = node.union(node.descendants()); + + nodes.positions(function (node, i) { + if(typeof node === "number") { + node = i; + } + var pos = node.position(); + return { + x: pos.x + dx, + y: pos.y + dy + }; + }); + } + + function getTopMostNodes(nodes) { + var nodesMap = {}; + for (var i = 0; i < nodes.length; i++) { + nodesMap[nodes[i].id()] = true; + } + var roots = nodes.filter(function (ele, i) { + if(typeof ele === "number") { + ele = i; + } + + var parent = ele.parent()[0]; + while(parent != null){ + if(nodesMap[parent.id()]){ + return false; + } + parent = parent.parent()[0]; + } + return true; + }); + + return roots; + } + + + cytoscape( "collection", "align", function (horizontal, vertical, alignTo) { + + var eles = getTopMostNodes(this.nodes(":visible")); + + var modelNode = alignTo ? alignTo : eles[0]; + + eles = eles.not(modelNode); + + horizontal = horizontal ? horizontal : "none"; + vertical = vertical ? vertical : "none"; + + + // 0 for center + var xFactor = 0; + var yFactor = 0; + + if (vertical == "left") + xFactor = -1; + else if (vertical == "right") + xFactor = 1; + + if (horizontal == "top") + yFactor = -1; + else if (horizontal == "bottom") + yFactor = 1; + + + for (var i = 0; i < eles.length; i++) { + var node = eles[i]; + var oldPos = $.extend({}, node.position()); + var newPos = $.extend({}, node.position()); + + if (vertical != "none") + newPos.x = modelNode.position("x") + xFactor * (modelNode.outerWidth() - node.outerWidth()) / 2; + + + if (horizontal != "none") + newPos.y = modelNode.position("y") + yFactor * (modelNode.outerHeight() - node.outerHeight()) / 2; + + moveTopDown(node, newPos.x - oldPos.x, newPos.y - oldPos.y); + } + + return this; + }); + + if (cy.undoRedo) { + function getNodePositions() { + var positionsAndSizes = {}; + var nodes = cy.nodes(); + + for (var i = 0; i < nodes.length; i++) { + var ele = nodes[i]; + positionsAndSizes[ele.id()] = { + x: ele.position("x"), + y: ele.position("y") + }; + } + + return positionsAndSizes; + } + + function returnToPositions(nodesData) { + var currentPositions = {}; + cy.nodes().positions(function (ele, i) { + if(typeof ele === "number") { + ele = i; + } + currentPositions[ele.id()] = { + x: ele.position("x"), + y: ele.position("y") + }; + var data = nodesData[ele.id()]; + return { + x: data.x, + y: data.y + }; + }); + + return currentPositions + } + + var ur = cy.undoRedo(null, true); + + ur.action("align", function (args) { + + var nodesData; + if (args.firstTime){ + nodesData = getNodePositions(); + args.nodes.align(args.horizontal, args.vertical, args.alignTo); + } + else + nodesData = returnToPositions(args); + + return nodesData; + + }, function (nodesData) { + return returnToPositions(nodesData); + }); + + } + + + +}; + +},{}],3:[function(require,module,exports){ + +var debounce = (function(){ + /** + * lodash 3.1.1 (Custom Build) + * Build: `lodash modern modularize exports="npm" -o ./` + * Copyright 2012-2015 The Dojo Foundation + * Based on Underscore.js 1.8.3 + * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ + /** Used as the `TypeError` message for "Functions" methods. */ + var FUNC_ERROR_TEXT = 'Expected a function'; + + /* Native method references for those with the same name as other `lodash` methods. */ + var nativeMax = Math.max, + nativeNow = Date.now; + + /** + * Gets the number of milliseconds that have elapsed since the Unix epoch + * (1 January 1970 00:00:00 UTC). + * + * @static + * @memberOf _ + * @category Date + * @example + * + * _.defer(function(stamp) { + * console.log(_.now() - stamp); + * }, _.now()); + * // => logs the number of milliseconds it took for the deferred function to be invoked + */ + var now = nativeNow || function() { + return new Date().getTime(); + }; + + /** + * Creates a debounced function that delays invoking `func` until after `wait` + * milliseconds have elapsed since the last time the debounced function was + * invoked. The debounced function comes with a `cancel` method to cancel + * delayed invocations. Provide an options object to indicate that `func` + * should be invoked on the leading and/or trailing edge of the `wait` timeout. + * Subsequent calls to the debounced function return the result of the last + * `func` invocation. + * + * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked + * on the trailing edge of the timeout only if the the debounced function is + * invoked more than once during the `wait` timeout. + * + * See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation) + * for details over the differences between `_.debounce` and `_.throttle`. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to debounce. + * @param {number} [wait=0] The number of milliseconds to delay. + * @param {Object} [options] The options object. + * @param {boolean} [options.leading=false] Specify invoking on the leading + * edge of the timeout. + * @param {number} [options.maxWait] The maximum time `func` is allowed to be + * delayed before it's invoked. + * @param {boolean} [options.trailing=true] Specify invoking on the trailing + * edge of the timeout. + * @returns {Function} Returns the new debounced function. + * @example + * + * // avoid costly calculations while the window size is in flux + * jQuery(window).on('resize', _.debounce(calculateLayout, 150)); + * + * // invoke `sendMail` when the click event is fired, debouncing subsequent calls + * jQuery('#postbox').on('click', _.debounce(sendMail, 300, { + * 'leading': true, + * 'trailing': false + * })); + * + * // ensure `batchLog` is invoked once after 1 second of debounced calls + * var source = new EventSource('/stream'); + * jQuery(source).on('message', _.debounce(batchLog, 250, { + * 'maxWait': 1000 + * })); + * + * // cancel a debounced call + * var todoChanges = _.debounce(batchLog, 1000); + * Object.observe(models.todo, todoChanges); + * + * Object.observe(models, function(changes) { + * if (_.find(changes, { 'user': 'todo', 'type': 'delete'})) { + * todoChanges.cancel(); + * } + * }, ['delete']); + * + * // ...at some point `models.todo` is changed + * models.todo.completed = true; + * + * // ...before 1 second has passed `models.todo` is deleted + * // which cancels the debounced `todoChanges` call + * delete models.todo; + */ + function debounce(func, wait, options) { + var args, + maxTimeoutId, + result, + stamp, + thisArg, + timeoutId, + trailingCall, + lastCalled = 0, + maxWait = false, + trailing = true; + + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + wait = wait < 0 ? 0 : (+wait || 0); + if (options === true) { + var leading = true; + trailing = false; + } else if (isObject(options)) { + leading = !!options.leading; + maxWait = 'maxWait' in options && nativeMax(+options.maxWait || 0, wait); + trailing = 'trailing' in options ? !!options.trailing : trailing; + } + + function cancel() { + if (timeoutId) { + clearTimeout(timeoutId); + } + if (maxTimeoutId) { + clearTimeout(maxTimeoutId); + } + lastCalled = 0; + maxTimeoutId = timeoutId = trailingCall = undefined; + } + + function complete(isCalled, id) { + if (id) { + clearTimeout(id); + } + maxTimeoutId = timeoutId = trailingCall = undefined; + if (isCalled) { + lastCalled = now(); + result = func.apply(thisArg, args); + if (!timeoutId && !maxTimeoutId) { + args = thisArg = undefined; + } + } + } + + function delayed() { + var remaining = wait - (now() - stamp); + if (remaining <= 0 || remaining > wait) { + complete(trailingCall, maxTimeoutId); + } else { + timeoutId = setTimeout(delayed, remaining); + } + } + + function maxDelayed() { + complete(trailing, timeoutId); + } + + function debounced() { + args = arguments; + stamp = now(); + thisArg = this; + trailingCall = trailing && (timeoutId || !leading); + + if (maxWait === false) { + var leadingCall = leading && !timeoutId; + } else { + if (!maxTimeoutId && !leading) { + lastCalled = stamp; + } + var remaining = maxWait - (stamp - lastCalled), + isCalled = remaining <= 0 || remaining > maxWait; + + if (isCalled) { + if (maxTimeoutId) { + maxTimeoutId = clearTimeout(maxTimeoutId); + } + lastCalled = stamp; + result = func.apply(thisArg, args); + } + else if (!maxTimeoutId) { + maxTimeoutId = setTimeout(maxDelayed, remaining); + } + } + if (isCalled && timeoutId) { + timeoutId = clearTimeout(timeoutId); + } + else if (!timeoutId && wait !== maxWait) { + timeoutId = setTimeout(delayed, wait); + } + if (leadingCall) { + isCalled = true; + result = func.apply(thisArg, args); + } + if (isCalled && !timeoutId && !maxTimeoutId) { + args = thisArg = undefined; + } + return result; + } + debounced.cancel = cancel; + return debounced; + } + + /** + * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`. + * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(1); + * // => false + */ + function isObject(value) { + // Avoid a V8 JIT bug in Chrome 19-20. + // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. + var type = typeof value; + return !!value && (type == 'object' || type == 'function'); + } + + return debounce; + +})(); + +module.exports = debounce; +},{}],4:[function(require,module,exports){ +module.exports = function (opts, cy, $, debounce) { + + var options = opts; + + var changeOptions = function (opts) { + options = opts; + }; + + + var $canvas = $( '' ); + var $container = $( cy.container() ); + var ctx = $canvas[ 0 ].getContext( '2d' ); + $container.append( $canvas ); + + var drawGrid = function() { + var zoom = cy.zoom(); + var canvasWidth = $container.width(); + var canvasHeight = $container.height(); + var increment = options.gridSpacing*zoom; + var pan = cy.pan(); + var initialValueX = pan.x%increment; + var initialValueY = pan.y%increment; + + ctx.strokeStyle = options.gridColor; + ctx.lineWidth = options.lineWidth; + + var data = '\t\n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n'; + + var DOMURL = window.URL || window.webkitURL || window; + var img = new Image(); + var svg = new Blob([data], {type: 'image/svg+xml'}); + var url = DOMURL.createObjectURL(svg); + + img.onload = function () { + clearDrawing(); + ctx.drawImage(img, 0, 0); + DOMURL.revokeObjectURL(url); + }; + + img.src = url; + }; + + var clearDrawing = function() { + var width = $container.width(); + var height = $container.height(); + + ctx.clearRect( 0, 0, width, height ); + }; + + var resizeCanvas = debounce(function() { + $canvas + .attr( 'height', $container.height() ) + .attr( 'width', $container.width() ) + .css( { + 'position': 'absolute', + 'top': 0, + 'left': 0, + 'z-index': options.gridStackOrder + } ); + + setTimeout( function() { + var canvasBb = $canvas.offset(); + var containerBb = $container.offset(); + + $canvas + .attr( 'height', $container.height() ) + .attr( 'width', $container.width() ) + .css( { + 'top': -( canvasBb.top - containerBb.top ), + 'left': -( canvasBb.left - containerBb.left ) + } ); + drawGrid(); + }, 0 ); + + }, 250); + + + + + return { + initCanvas: resizeCanvas, + resizeCanvas: resizeCanvas, + clearCanvas: clearDrawing, + drawGrid: drawGrid, + changeOptions: changeOptions, + sizeCanvas: drawGrid + }; +}; + +},{}],5:[function(require,module,exports){ +module.exports = function (cy, snap, resize, snapToGridDuringDrag, drawGrid, guidelines, parentPadding, $, opts) { + + var feature = function (func) { + return function (enable) { + func(enable); + }; + }; + + var controller = { + snapToGridDuringDrag: new feature(setDiscreteDrag), + resize: new feature(setResize), + snapToGridOnRelease: new feature(setSnapToGrid), + drawGrid: new feature(setDrawGrid), + guidelines: new feature(setGuidelines), + parentPadding: new feature(setParentPadding) + }; + + function applyToCyTarget(func, allowParent) { + return function (e) { + var cyTarget = e.target || e.cyTarget; + if (!cyTarget.is(":parent") || allowParent) + func(cyTarget); + } + } + + function applyToAllNodesButNoParent(func) { + return function () { + cy.nodes().not(":parent").each(function (ele, i) { + if(typeof ele === "number") { + ele = i; + } + + func(ele); + }); + }; + } + function applyToAllNodes(func) { + return function () { + cy.nodes().each(function (ele, i) { + if(typeof ele === "number") { + ele = i; + } + + func(ele); + }); + }; + } + + function eventStatus(enable) { + return enable ? "on" : "off"; + } + + + // Discrete Drag + function setDiscreteDrag(enable) { + cy[eventStatus(enable)]("tapstart", "node", snapToGridDuringDrag.onTapStartNode); + } + + // Resize + var resizeAllNodes = applyToAllNodesButNoParent(resize.resizeNode); + var resizeNode = applyToCyTarget(resize.resizeNode); + var recoverAllNodeDimensions = applyToAllNodesButNoParent(resize.recoverNodeDimensions); + + function setResize(enable) { + cy[eventStatus(enable)]("ready", resizeAllNodes); + // cy[eventStatus(enable)]("style", "node", resizeNode); + enable ? resizeAllNodes() : recoverAllNodeDimensions(); + } + + // Snap To Grid + var snapAllNodes = applyToAllNodes(snap.snapNodesTopDown); + var recoverSnapAllNodes = applyToAllNodes(snap.recoverSnapNode); + var snapCyTarget = applyToCyTarget(snap.snapNode, true); + + function setSnapToGrid(enable) { + cy[eventStatus(enable)]("add", "node", snapCyTarget); + cy[eventStatus(enable)]("ready", snapAllNodes); + + cy[eventStatus(enable)]("free", "node", snap.onFreeNode); + + if (enable) { + snapAllNodes(); + } else { + recoverSnapAllNodes(); + } + } + + // Draw Grid + var drawGridOnZoom = function () { + if (currentOptions.zoomDash) drawGrid.drawGrid() + }; + var drawGridOnPan = function () { + if (currentOptions.panGrid) drawGrid.drawGrid() + }; + + function setDrawGrid(enable) { + cy[eventStatus(enable)]('zoom', drawGridOnZoom); + cy[eventStatus(enable)]('pan', drawGridOnPan); + cy[eventStatus(enable)]('ready', drawGrid.resizeCanvas); + + if (enable) { + drawGrid.initCanvas(); + $(window).on('resize', drawGrid.resizeCanvas); + } else { + drawGrid.clearCanvas(); + $(window).off('resize', drawGrid.resizeCanvas); + } + } + + // Guidelines + var activeTopMostNodes = null; + var guidelinesGrabHandler = function(e){ + var cyTarget = e.target || e.cyTarget; + var nodes = cyTarget.selected() ? e.cy.$(":selected") : cyTarget; + activeTopMostNodes = guidelines.getTopMostNodes(nodes.nodes()); + guidelines.lines.init(activeTopMostNodes); + } + var guidelinesDragHandler = function(e){ + if (this.id() == activeTopMostNodes.id()){ + guidelines.lines.update(activeTopMostNodes); + + if (opts.snapToAlignmentLocationDuringDrag) + guidelines.lines.snapToAlignmentLocation(activeTopMostNodes); + } + }; + var guidelinesFreeHandler = function(e){ + if (opts.snapToAlignmentLocationOnRelease) + guidelines.lines.snapToAlignmentLocation(activeTopMostNodes); + + guidelines.lines.destroy(); + activeTopMostNodes = null; + }; + var guidelinesWindowResizeHandler = function(e){ + guidelines.lines.resize(); + }; + var guidelinesTapHandler = function(e){ + guidelines.getMousePos(e); + }; + var guidelinesPanHandler = function(e){ + if (activeTopMostNodes){ + guidelines.setMousePos(cy.pan()); + guidelines.lines.init(activeTopMostNodes); + } + } + function setGuidelines(enable) { + if (enable){ + guidelines.resizeCanvas(); + cy.on("tapstart", "node", guidelinesTapHandler); + cy.on("grab", guidelinesGrabHandler); + cy.on("pan", guidelinesPanHandler); + cy.on("drag", "node", guidelinesDragHandler); + cy.on("free", guidelinesFreeHandler); + $(window).on("resize", guidelinesWindowResizeHandler); + } + else{ + cy.off("tapstart", "node", guidelinesTapHandler); + cy.off("grab", guidelinesGrabHandler); + cy.off("pan", guidelinesPanHandler); + cy.off("drag", "node", guidelinesDragHandler); + cy.off("free", guidelinesFreeHandler); + $(window).off("resize", guidelinesWindowResizeHandler); + } + } + + // Parent Padding + var setAllParentPaddings = function (enable) { + parentPadding.setPaddingOfParent(cy.nodes(":parent"), enable); + }; + var enableParentPadding = function (node) { + parentPadding.setPaddingOfParent(node, true); + }; + + + function setParentPadding(enable) { + + setAllParentPaddings(enable); + + cy[eventStatus(enable)]('ready', setAllParentPaddings); + cy[eventStatus(enable)]("add", "node:parent", applyToCyTarget(enableParentPadding, true)); + } + + // Sync with options: Enables/disables changed via options. + var latestOptions = {}; + var currentOptions; + + var specialOpts = { + drawGrid: ["gridSpacing", "zoomDash", "panGrid", "gridStackOrder", "gridColor", "lineWidth", "lineDash"], + guidelines: ["gridSpacing", "guidelinesStackOrder", "guidelinesTolerance", "guidelinesStyle", "distributionGuidelines", "range", "minDistRange", "geometricGuidelineRange"], + resize: ["gridSpacing"], + parentPadding: ["gridSpacing", "parentSpacing"], + snapToGridOnRelease: ["gridSpacing"] + }; + + function syncWithOptions(options) { + currentOptions = $.extend(true, {}, options); + options.guidelines = options.initPosAlignment || options.distributionGuidelines || options.geometricGuideline; + for (var key in options) + if (latestOptions[key] != options[key]) + if (controller.hasOwnProperty(key)) { + controller[key](options[key]); + } else { + for (var optsKey in specialOpts) { + var opts = specialOpts[optsKey]; + if (opts.indexOf(key) >= 0) { + if(optsKey == "drawGrid") { + drawGrid.changeOptions(options); + if (options.drawGrid) + drawGrid.resizeCanvas(); + } + + if (optsKey == "snapToGridOnRelease"){ + snap.changeOptions(options); + if (options.snapToGridOnRelease) + snapAllNodes(); + } + + if(optsKey == "guidelines") + guidelines.changeOptions(options); + + if (optsKey == "resize") { + resize.changeOptions(options); + if (options.resize) + resizeAllNodes(); + } + + if (optsKey == "parentPadding") + parentPadding.changeOptions(options); + + + } + } + } + latestOptions = $.extend(true, latestOptions, options); + } + + return { + init: syncWithOptions, + syncWithOptions: syncWithOptions + }; + +}; + +},{}],6:[function(require,module,exports){ +module.exports = function (opts, cy, $, debounce) { + + + var RBTree = require("functional-red-black-tree"); + + var options = opts; + + var changeOptions = function (opts) { + options = opts; + + // RBTree always returns null, when low == high + // to avoid this: + if (options.guidelinesTolerance == 0) + options.guidelinesTolerance = 0.001; + }; + + var getCyScratch = function () { + var sc = cy.scratch("_guidelines"); + if (!sc) + sc = cy.scratch("_guidelines", {}); + + return sc; + }; + + /* Resize canvas */ + var resizeCanvas = debounce(function () { + clearDrawing(); + $canvas + .attr('height', $container.height()) + .attr('width', $container.width()) + .css({ + 'position': 'absolute', + 'top': 0, + 'left': 0, + 'z-index': options.guidelinesStackOrder + }); + setTimeout(function () { + var canvasBb = $canvas.offset(); + var containerBb = $container.offset(); + + $canvas + .attr('height', $container.height()) + .attr('width', $container.width()) + .css({ + 'top': -( canvasBb.top - containerBb.top ), + 'left': -( canvasBb.left - containerBb.left ) + }); + }, 0); + }, 250); + + /* Clear canvas */ + var clearDrawing = function () { + var width = $container.width(); + var height = $container.height(); + ctx.clearRect(0, 0, width, height); + }; + + /* Create a canvas */ + var $canvas = $(''); + var $container = $(cy.container()); + var ctx = $canvas[0].getContext('2d'); + $container.append($canvas); + resizeCanvas(); + + /* Global variables */ + var VTree = null; + var HTree = null; + var nodeInitPos; + var excludedNodes; + var lines = {}; + var panInitPos = {}; + var alignedLocations = {"h" : null, "v" : null}; + + /** + * Get positions of sides of a node + * @param node : a node + * @return : object of positions + */ + lines.getDims = function (node) { + var pos = node.renderedPosition(); + var width = node.renderedWidth(); + var height = node.renderedHeight(); + var padding = { + left: Number(node.renderedStyle("padding-left").replace("px", "")), + right: Number(node.renderedStyle("padding-right").replace("px", "")), + top: Number(node.renderedStyle("padding-top").replace("px", "")), + bottom: Number(node.renderedStyle("padding-bottom").replace("px", "")) + }; + + return { + horizontal: { + center: (pos.x), + left: Math.round(pos.x - (padding.left + width / 2)), + right: Math.round(pos.x + (padding.right + width / 2)) + }, + vertical: { + center: (pos.y), + top: Math.round(pos.y - (padding.top + height / 2)), + bottom: Math.round(pos.y + (padding.bottom + height / 2)) + } + }; + }; + + /** + * Initialize trees and initial position of node + * @param activeNodes : top most active nodes + */ + lines.init = function (activeNodes) { + VTree = RBTree(); + HTree = RBTree(); + // TODO: seperate initialization of nodeInitPos + // not necessary to init trees when geometric and distribution alignments are disabled, + // but reference guideline is enables + if (!nodeInitPos){ + panInitPos.x = cy.pan("x"); panInitPos.y = cy.pan("y"); + nodeInitPos = activeNodes.renderedPosition(); + } + + var nodes = cy.nodes(":visible"); + excludedNodes = activeNodes.union(activeNodes.ancestors()); + excludedNodes = excludedNodes.union(activeNodes.descendants()); + nodes.not(excludedNodes).each(function (node, i) { + if(typeof node === "number") { + node = i; + } + var dims = lines.getDims(node); + + ["left", "center", "right"].forEach(function (val) { + var hKey = dims.horizontal[val]; + if (HTree.get(hKey)) + HTree.get(hKey).push(node); + else + HTree = HTree.insert(hKey, [node]); + }); + + ["top", "center", "bottom"].forEach(function (val) { + var vKey = dims.vertical[val]; + if (VTree.get(vKey)) + VTree.get(vKey).push(node); + else + VTree = VTree.insert(vKey, [node]); + }); + + }); + ctx.lineWidth=options.lineWidth; + lines.update(activeNodes); + }; + + /* Destroy gobal variables */ + lines.destroy = function () { + lines.clear(); + VTree = null; HTree = null; + nodeInitPos = null; + mouseInitPos = {}; + alignedLocations = {"h" : null, "v" : null}; + if (nodeToAlign){ + nodeToAlign.unlock(); + nodeToAlign = undefined; + } + }; + + lines.clear = clearDrawing; + + /** + * Draw straight line + * @param from : initial position + * @param to : final position + * @param color : color of the line + * @param lineStyle : whether line is solid or dashed + */ + lines.drawLine = function (from, to, color, lineStyle) { + ctx.setLineDash(lineStyle); + ctx.beginPath(); + ctx.moveTo(from.x, from.y); + ctx.lineTo(to.x, to.y); + ctx.strokeStyle = color; + ctx.stroke(); + }; + + /** + * Draw an arrow + * @param position : position of the arrow + * @param type : type/directşon of the arrow + */ + lines.drawArrow = function(position, type){ + if (type == "right"){ + // right arrow + ctx.setLineDash([]); + ctx.beginPath(); + ctx.moveTo(position.x-5, position.y-5); + ctx.lineTo(position.x, position.y); + ctx.lineTo(position.x-5, position.y+5); + ctx.stroke(); + } + else if (type == "left"){ + // left arrow + ctx.setLineDash([]); + ctx.beginPath(); + ctx.moveTo(position.x+5, position.y-5); + ctx.lineTo(position.x, position.y); + ctx.lineTo(position.x+5, position.y+5); + ctx.stroke(); + } + else if (type == "top"){ + // up arrow + ctx.setLineDash([]); + ctx.beginPath(); + ctx.moveTo(position.x-5, position.y+5); + ctx.lineTo(position.x, position.y); + ctx.lineTo(position.x+5, position.y+5); + ctx.stroke(); + } + else if (type == "bottom"){ + // down arrow + ctx.setLineDash([]); + ctx.beginPath(); + ctx.moveTo(position.x-5, position.y-5); + ctx.lineTo(position.x, position.y); + ctx.lineTo(position.x+5, position.y-5); + ctx.stroke(); + } + + } + + /** + * Draw a cross - x + * @param position : position of the cross + */ + lines.drawCross = function(position){ + ctx.setLineDash([]); + ctx.beginPath(); + ctx.moveTo(position.x - 5, position.y + 5); + ctx.lineTo(position.x + 5, position.y - 5); + ctx.moveTo(position.x - 5, position.y - 5); + ctx.lineTo(position.x + 5, position.y + 5); + ctx.stroke(); + }; + + /** + * Calculate the amount of offset for distribution guidelines + * @param nodes - list of nodes + * @param type - horizontal or vertical + */ + calculateOffset = function(nodes, type){ + var minNode = nodes[0], min = lines.getDims(minNode)[type]["center"]; + var maxNode = nodes[0], max = lines.getDims(maxNode)[type]["center"]; + + for (node of nodes){ + if (lines.getDims(node)[type]["center"] < min){ + min = lines.getDims(node)[type]["center"]; minNode = node; + } + if (lines.getDims(node)[type]["center"] > max){ + max = lines.getDims(node)[type]["center"]; maxNode = node; + } + } + + if (type == "horizontal") + var offset = (min + max) / 2 < lines.getDims(nodes[1])[type]["center"] ? max + (0.5*maxNode.width() + options.guidelinesStyle.distGuidelineOffset)*cy.zoom() : min - (0.5*minNode.width() + options.guidelinesStyle.distGuidelineOffset)*cy.zoom(); + else + var offset = (min + max) / 2 < lines.getDims(nodes[1])[type]["center"] ? max + (0.5*maxNode.height() + options.guidelinesStyle.distGuidelineOffset)*cy.zoom() : min - (0.5*minNode.height() + options.guidelinesStyle.distGuidelineOffset)*cy.zoom(); + + return offset; + } + /** Guidelines for horizontally distributed alignment + * @param: node the node to be aligned + */ + lines.horizontalDistribution = function(node){ + // variables + var leftNode = null, rightNode = null; + var nodeDim = lines.getDims(node); + var Xcenter = nodeDim["horizontal"]["center"]; + var Ycenter = nodeDim["vertical"]["center"]; + // Find nodes in range and check if they align + HTree.forEach(function(key, nodes){ + + for (left of nodes){ + var leftDim = lines.getDims(left); + if (Math.abs(leftDim["vertical"]["center"] - nodeDim["vertical"]["center"]) < options.guidelinesStyle.range*cy.zoom()){ + if ((leftDim["horizontal"]["right"]) == key && + nodeDim["horizontal"]["left"] - leftDim["horizontal"]["right"] > options.guidelinesStyle.minDistRange){ + var ripo = Math.round(2*Xcenter)-key; + HTree.forEach(function($, rightNodes){ + for (right of rightNodes){ + if (Math.abs(lines.getDims(right)["vertical"]["center"] - Ycenter) < options.guidelinesStyle.range*cy.zoom()){ + if (Math.abs(ripo - lines.getDims(right)["horizontal"]["left"]) < 2*options.guidelinesTolerance){ + leftNode = left; rightNode = right; + } + } + } + }, ripo - options.guidelinesTolerance, ripo + options.guidelinesTolerance); + } + } + } + }, Xcenter - options.guidelinesStyle.range*cy.zoom(), Xcenter); + + // Draw the lines + if (leftNode){ + alignedLocations.hd = Xcenter - (lines.getDims(rightNode)["horizontal"]["left"] + lines.getDims(leftNode)["horizontal"]["right"]) / 2.0; + if (!options.geometricGuideline || alignedLocations.h == null || Math.abs(alignedLocations.h) > Math.abs(alignedLocations.hd)){ + alignedLocations.h = alignedLocations.hd; + } + var offset = calculateOffset([leftNode, node, rightNode], "vertical"); + + lines.drawLine({ + x: lines.getDims(leftNode)["horizontal"]["right"], + y: offset + }, { + x: nodeDim["horizontal"]["left"], + y: offset + }, options.guidelinesStyle.horizontalDistColor, options.guidelinesStyle.horizontalDistLine); + + lines.drawLine({ + x: lines.getDims(rightNode)["horizontal"]["left"], + y: offset + }, { + x: nodeDim["horizontal"]["right"], + y: offset + }, options.guidelinesStyle.horizontalDistColor, options.guidelinesStyle.horizontalDistLine); + + lines.drawLine({ + x: lines.getDims(leftNode)["horizontal"]["right"], + y: offset + }, { + x: lines.getDims(leftNode)["horizontal"]["right"], + y: lines.getDims(leftNode)["vertical"]["center"] + }, options.guidelinesStyle.horizontalDistColor, options.guidelinesStyle.horizontalDistLine); + + lines.drawLine({ + x: lines.getDims(rightNode)["horizontal"]["left"], + y: offset + }, { + x: lines.getDims(rightNode)["horizontal"]["left"], + y: lines.getDims(rightNode)["vertical"]["center"] + }, options.guidelinesStyle.horizontalDistColor, options.guidelinesStyle.horizontalDistLine); + + lines.drawLine({ + x: nodeDim["horizontal"]["left"], + y: offset + }, { + x: nodeDim["horizontal"]["left"], + y: Ycenter + }, options.guidelinesStyle.horizontalDistColor, options.guidelinesStyle.horizontalDistLine); + + lines.drawLine({ + x: nodeDim["horizontal"]["right"], + y: offset + }, { + x: nodeDim["horizontal"]["right"], + y: Ycenter + }, options.guidelinesStyle.horizontalDistColor, options.guidelinesStyle.horizontalDistLine); + + lines.drawArrow({ + x: lines.getDims(leftNode)["horizontal"]["right"], + y: offset}, "left"); + + lines.drawArrow({ + x: nodeDim["horizontal"]["left"], + y: offset}, "right"); + + lines.drawArrow({ + x: nodeDim["horizontal"]["right"], + y: offset}, "left"); + + lines.drawArrow({ + x: lines.getDims(rightNode)["horizontal"]["left"], + y: offset}, "right"); + + } + else{ + var state = lines.horizontalDistributionNext(node,"left" ); + + if (!state) + lines.horizontalDistributionNext(node,"right" ); + } + } + + /** Guidelines for horizontally distributed alignment + * @param: node the node to be aligned + */ + lines.verticalDistribution = function(node){ + // variables + var belowNode = null, aboveNode = null; + var nodeDim = lines.getDims(node); + var Xcenter = nodeDim["horizontal"]["center"]; + var Ycenter = nodeDim["vertical"]["center"]; + // Find nodes in range and check if they align + VTree.forEach(function(key, nodes){ + + for (below of nodes){ + var belowDim = lines.getDims(below); + if (Math.abs(belowDim["horizontal"]["center"] - nodeDim["horizontal"]["center"]) < options.guidelinesStyle.range*cy.zoom()){ + if (belowDim["vertical"]["bottom"] == key && + nodeDim["vertical"]["top"] - belowDim["vertical"]["bottom"] > options.guidelinesStyle.minDistRange){ + var abpo = Math.round((2*Ycenter)-key); + VTree.forEach(function($, aboveNodes){ + //if (aboveNodes){ + for (above of aboveNodes){ + if (Math.abs(lines.getDims(above)["horizontal"]["center"] - Xcenter) < options.guidelinesStyle.range*cy.zoom()){ + if (Math.abs(abpo - lines.getDims(above)["vertical"]["top"]) < 2*options.guidelinesTolerance){ + belowNode = below; aboveNode = above; + } + } + } + //} + }, abpo - options.guidelinesTolerance, abpo + options.guidelinesTolerance); + } + } + } + }, Ycenter - options.guidelinesStyle.range*cy.zoom(), Ycenter); + + if (belowNode){ + alignedLocations.vd = Ycenter - (lines.getDims(belowNode)["vertical"]["bottom"] + lines.getDims(aboveNode)["vertical"]["top"]) / 2.0; + if (!options.geometricGuideline || alignedLocations.v == null || Math.abs(alignedLocations.v) > Math.abs(alignedLocations.vd)){ + alignedLocations.v = alignedLocations.vd; + } + var offset = calculateOffset([belowNode, node, aboveNode], "horizontal"); + lines.drawLine({ + y: lines.getDims(belowNode)["vertical"]["bottom"],//renderedPosition("x"), + x: offset + }, { + y: nodeDim["vertical"]["top"], + x: offset + }, options.guidelinesStyle.verticalDistColor, options.guidelinesStyle.verticalDistLine); + + lines.drawLine({ + y: lines.getDims(aboveNode)["vertical"]["top"],//renderedPosition("x"), + x: offset + }, { + y: nodeDim["vertical"]["bottom"], + x: offset + }, options.guidelinesStyle.verticalDistColor, options.guidelinesStyle.verticalDistLine); + + lines.drawLine({ + y: lines.getDims(belowNode)["vertical"]["bottom"],//renderedPosition("x"), + x: offset + }, { + y: lines.getDims(belowNode)["vertical"]["bottom"], + x: lines.getDims(belowNode)["horizontal"]["center"] + }, options.guidelinesStyle.verticalDistColor, options.guidelinesStyle.verticalDistLine); + + lines.drawLine({ + y: lines.getDims(aboveNode)["vertical"]["top"],//renderedPosition("x"), + x: offset + }, { + y: lines.getDims(aboveNode)["vertical"]["top"], + x: lines.getDims(aboveNode)["horizontal"]["center"] + }, options.guidelinesStyle.verticalDistColor, options.guidelinesStyle.verticalDistLine); + + lines.drawLine({ + y: nodeDim["vertical"]["bottom"],//renderedPosition("x"), + x: offset + }, { + y: nodeDim["vertical"]["bottom"],//renderedPosition("x"), + x: Xcenter + }, options.guidelinesStyle.verticalDistColor, options.guidelinesStyle.verticalDistLine); + + lines.drawLine({ + y: nodeDim["vertical"]["top"],//renderedPosition("x"), + x: offset + }, { + y: nodeDim["vertical"]["top"],//renderedPosition("x"), + x: Xcenter + }, options.guidelinesStyle.verticalDistColor, options.guidelinesStyle.verticalDistLine); + + lines.drawArrow({ + x: offset, + y: lines.getDims(belowNode)["vertical"]["bottom"]}, "top"); + + lines.drawArrow({ + x: offset, + y: nodeDim["vertical"]["top"]}, "bottom"); + + lines.drawArrow({ + x: offset, + y: lines.getDims(aboveNode)["vertical"]["top"]}, "bottom"); + + lines.drawArrow({ + x: offset, + y: nodeDim["vertical"]["bottom"]}, "top"); + } + else{ + var state = lines.verticalDistributionNext(node,"below" ); + + if (!state) + lines.verticalDistributionNext(node,"above" ); + } + } + + /** + * Find geometric alignment lines and draw them + * @param type: horizontal or vertical + * @param node: the node to be aligned + */ + lines.searchForLine = function (type, node) { + + // variables + var position, target, center, axis, otherAxis, Tree, closestKey; + var dims = lines.getDims(node)[type]; + var targetKey = Number.MAX_SAFE_INTEGER; + + // initialize Tree + if ( type == "horizontal"){ + Tree = HTree; + axis = "y"; + otherAxis = "x"; + alignedLocations.h = null; + } else{ + Tree = VTree; + axis = "x"; + otherAxis = "y"; + alignedLocations.v = null; + } + + center = node.renderedPosition(axis); + // check if node aligned in any dimension: + // {center, left, right} or {center, top, bottom} + for (var dimKey in dims) { + position = dims[dimKey]; + + // find the closest alignment in range of tolerance + Tree.forEach(function (exKey, nodes) { + for (n of nodes){ + if (options.centerToEdgeAlignment || (dimKey != "center" && n.renderedPosition(otherAxis) != exKey) || (dimKey == "center" && n.renderedPosition(otherAxis) == exKey)){ + var dif = Math.abs(center - n.renderedPosition(axis)); + if ( dif < targetKey && dif < options.guidelinesStyle.geometricGuidelineRange*cy.zoom()){ + target = n; + targetKey = dif; + closestKey = exKey; + } + } + } + }, position - Number(options.guidelinesTolerance), position + Number(options.guidelinesTolerance)); + + // if alignment found, draw lines and break + if (target) { + targetKey = lines.getDims(node)[type][dimKey]; + + // Draw horizontal or vertical alignment line + if (type == "horizontal") { + alignedLocations.h = targetKey - closestKey; + lines.drawLine({ + x: targetKey, + y: node.renderedPosition("y") + }, { + x: targetKey, + y: target.renderedPosition("y") + }, options.guidelinesStyle.strokeStyle, options.guidelinesStyle.lineDash); + } else { + alignedLocations.v = targetKey - closestKey; + lines.drawLine({ + x: node.renderedPosition("x"), + y: targetKey + }, { + x: target.renderedPosition("x"), + y: targetKey + }, options.guidelinesStyle.strokeStyle, options.guidelinesStyle.lineDash); + } + break; + } + } + }; + + lines.horizontalDistributionNext = function(node, type){ + + // variables + var leftNode = null, rightNode = null; + var nodeDim = lines.getDims(node); + var Xcenter = nodeDim["horizontal"]["center"]; + var Ycenter = nodeDim["vertical"]["center"]; + var side = "right", otherSide = "left"; + var lowerBound = Xcenter; + if (type == "left"){ + side = "left"; otherSide = "right"; + var lowerBound = Xcenter - options.guidelinesStyle.range*cy.zoom(); + } + + var compare = { + "left": function (x, y) { return y - x > options.guidelinesStyle.minDistRange}, + "right": function (x, y) { return x - y > options.guidelinesStyle.minDistRange} + } + + // Find nodes in range and check if they align + HTree.forEach(function(key, nodes){ + for (left of nodes){ + var leftDim = lines.getDims(left); + if (Math.abs(leftDim["vertical"]["center"] - nodeDim["vertical"]["center"]) < options.guidelinesStyle.range*cy.zoom()){ + if ((leftDim["horizontal"][otherSide]) == key && + compare[type](leftDim["horizontal"][otherSide], nodeDim["horizontal"][side])){ + var ll = leftDim["horizontal"][side]-(nodeDim["horizontal"][side] - key); + HTree.forEach(function($, rightNodes){ + for (right of rightNodes){ + if (Math.abs(lines.getDims(right)["vertical"]["center"] - Ycenter) < options.guidelinesStyle.range*cy.zoom()){ + if (Math.abs(ll - lines.getDims(right)["horizontal"][otherSide]) < 2*options.guidelinesTolerance){ + leftNode = left; rightNode = right; + } + } + } + }, ll - options.guidelinesTolerance, ll + options.guidelinesTolerance); + } + } + } + }, lowerBound, lowerBound + options.guidelinesStyle.range*cy.zoom()); + + // Draw the lines + if (leftNode){ + alignedLocations.hd =(lines.getDims(node)["horizontal"][side] - lines.getDims(leftNode)["horizontal"][otherSide]) - (lines.getDims(leftNode)["horizontal"][side] - lines.getDims(rightNode)["horizontal"][otherSide]); + if (!options.geometricGuideline || alignedLocations.h == null || Math.abs(alignedLocations.h) > Math.abs(alignedLocations.hd)){ + alignedLocations.h = alignedLocations.hd; + } + + lines.drawDH(node, leftNode, rightNode, type); + return true; + } + else if (!options.geometricGuideline){ + alignedLocations.h = null; + } + return false; + + } + + lines.drawDH = function(node, leftNode, rightNode, type){ + var Ycenter = lines.getDims(node)["vertical"]["center"]; + var side = "right", otherSide = "left"; + if (type == "left"){ + side = "left"; otherSide = "right"; + } + var offset = calculateOffset([leftNode, node, rightNode], "vertical"); + + lines.drawLine({ + x: lines.getDims(leftNode)["horizontal"][otherSide], + y: offset + }, { + x: lines.getDims(node)["horizontal"][side], + y: offset + }, options.guidelinesStyle.horizontalDistColor, options.guidelinesStyle.horizontalDistLine); + + lines.drawLine({ + x: lines.getDims(node)["horizontal"][side], + y: offset + }, { + x: lines.getDims(node)["horizontal"][side], + y: Ycenter,//lines.getDims(leftNode)["vertical"]["center"] + }, options.guidelinesStyle.horizontalDistColor, options.guidelinesStyle.horizontalDistLine); + + lines.drawLine({ + x: lines.getDims(rightNode)["horizontal"][otherSide], + y: offset + }, { + x: lines.getDims(leftNode)["horizontal"][side], + y: offset + }, options.guidelinesStyle.horizontalDistColor, options.guidelinesStyle.horizontalDistLine); + lines.drawLine({ + x: lines.getDims(rightNode)["horizontal"][otherSide], + y: offset + }, { + x: lines.getDims(rightNode)["horizontal"][otherSide], + y: lines.getDims(rightNode)["vertical"]["center"] + }, options.guidelinesStyle.horizontalDistColor, options.guidelinesStyle.horizontalDistLine); + + lines.drawLine({ + x: lines.getDims(leftNode)["horizontal"][otherSide], + y: offset + }, { + x: lines.getDims(leftNode)["horizontal"][otherSide], + y: lines.getDims(leftNode)["vertical"]["center"] + }, options.guidelinesStyle.horizontalDistColor, options.guidelinesStyle.horizontalDistLine); + + lines.drawLine({ + x: lines.getDims(leftNode)["horizontal"][side], + y: offset + }, { + x: lines.getDims(leftNode)["horizontal"][side], + y: lines.getDims(leftNode)["vertical"]["center"] + }, options.guidelinesStyle.horizontalDistColor, options.guidelinesStyle.horizontalDistLine); + + + lines.drawArrow({ + x: lines.getDims(node)["horizontal"][side], + y: offset}, otherSide); + + lines.drawArrow({ + x: lines.getDims(leftNode)["horizontal"][otherSide], + y: offset}, side); + + lines.drawArrow({ + x: lines.getDims(leftNode)["horizontal"][side], + y: offset}, otherSide); + + lines.drawArrow({ + x: lines.getDims(rightNode)["horizontal"][otherSide], + y: offset}, side); + + } + + lines.verticalDistributionNext = function(node, type){ + // variables + var belowNode = null, aboveNode = null; + var nodeDim = lines.getDims(node); + var Xcenter = nodeDim["horizontal"]["center"]; + var Ycenter = nodeDim["vertical"]["center"]; + var side = "top", otherSide = "bottom"; + var lowerBound = Ycenter - options.guidelinesStyle.range*cy.zoom(); + if (type == "above"){ + side = "bottom"; otherSide = "top"; + lowerBound = Ycenter; + } + + var compare = { + "below": function (x, y) { return y - x > options.guidelinesStyle.minDistRange}, + "above": function (x, y) { return x - y > options.guidelinesStyle.minDistRange} + } + // Find nodes in range and check if they align + VTree.forEach(function(key, nodes){ + + for (below of nodes){ + var belowDim = lines.getDims(below); + if (Math.abs(belowDim["horizontal"]["center"] - nodeDim["horizontal"]["center"]) < options.guidelinesStyle.range*cy.zoom()){ + if (belowDim["vertical"][otherSide] == key && + compare[type](belowDim["vertical"][otherSide], nodeDim["vertical"][side])){ + var ll = belowDim["vertical"][side]-(nodeDim["vertical"][side]-key); + VTree.forEach(function($, aboveNodes){ + for (above of aboveNodes){ + if (Math.abs(lines.getDims(above)["horizontal"]["center"] - Xcenter) < options.guidelinesStyle.range*cy.zoom()){ + if (Math.abs(ll - lines.getDims(above)["vertical"][otherSide]) < 2*options.guidelinesTolerance){ + belowNode = below; aboveNode = above; + } + } + } + }, ll - options.guidelinesTolerance, ll + options.guidelinesTolerance); + } + } + } + }, lowerBound, lowerBound+options.guidelinesStyle.range*cy.zoom()); + + if (belowNode){ + alignedLocations.vd =(lines.getDims(node)["vertical"][side] - lines.getDims(belowNode)["vertical"][otherSide]) - (lines.getDims(belowNode)["vertical"][side] - lines.getDims(aboveNode)["vertical"][otherSide]); + if (!options.geometricGuideline || alignedLocations.v == null || Math.abs(alignedLocations.v) > Math.abs(alignedLocations.vd)){ + alignedLocations.v = alignedLocations.vd; + } + lines.drawDV(node, belowNode, aboveNode, type); + return true; + } + else if (!options.geometricGuideline){ + alignedLocations.v = null; + } + return false; + } + + + + lines.drawDV = function(node, belowNode, aboveNode, type){ + var nodeDim = lines.getDims(node); + var Xcenter = nodeDim["horizontal"]["center"]; + var side = "top", otherSide = "bottom"; + if (type == "above"){ + side = "bottom"; otherSide = "top"; + } + + var offset = calculateOffset([belowNode, node, aboveNode], "horizontal"); + lines.drawLine({ + x: offset, + y: nodeDim["vertical"][side] + }, { + x: offset, + y: lines.getDims(belowNode)["vertical"][otherSide] + }, options.guidelinesStyle.verticalDistColor, options.guidelinesStyle.verticalDistLine); + + lines.drawLine({ + x: offset, + y: lines.getDims(belowNode)["vertical"][side] + }, { + x: offset, + y: lines.getDims(aboveNode)["vertical"][otherSide] + }, options.guidelinesStyle.verticalDistColor, options.guidelinesStyle.verticalDistLine); + + lines.drawLine({ + x: Xcenter, + y: nodeDim["vertical"][side] + }, { + x: offset, + y: nodeDim["vertical"][side] + }, options.guidelinesStyle.verticalDistColor, options.guidelinesStyle.verticalDistLine); + + lines.drawLine({ + x: lines.getDims(belowNode)["horizontal"]["center"], + y: lines.getDims(belowNode)["vertical"][otherSide] + }, { + x: offset, + y: lines.getDims(belowNode)["vertical"][otherSide] + }, options.guidelinesStyle.verticalDistColor, options.guidelinesStyle.verticalDistLine); + + lines.drawLine({ + x: lines.getDims(belowNode)["horizontal"]["center"], + y: lines.getDims(belowNode)["vertical"][side] + }, { + x: offset, + y: lines.getDims(belowNode)["vertical"][side] + }, options.guidelinesStyle.verticalDistColor, options.guidelinesStyle.verticalDistLine); + + lines.drawLine({ + x: offset,//lines.getDims(aboveNode)["horizontal"]["center"], + y: lines.getDims(aboveNode)["vertical"][otherSide] + }, { + x: lines.getDims(aboveNode)["horizontal"]["center"], + y: lines.getDims(aboveNode)["vertical"][otherSide] + }, options.guidelinesStyle.verticalDistColor, options.guidelinesStyle.verticalDistLine); + + lines.drawArrow({ + x: offset, + y: nodeDim["vertical"][side]}, otherSide); + + lines.drawArrow({ + x: offset, + y: lines.getDims(belowNode)["vertical"][otherSide]}, side); + + lines.drawArrow({ + x: offset, + y: lines.getDims(belowNode)["vertical"][side]}, otherSide); + + lines.drawArrow({ + x: offset, + y: lines.getDims(aboveNode)["vertical"][otherSide]}, side); + + } + lines.update = function (activeNodes) { + lines.clear(); + + if (options.initPosAlignment){ + mouseLine(activeNodes); + } + + activeNodes.each(function (node, i) { + if(typeof node === "number") { + node = i; + } + if (options.geometricGuideline){ + lines.searchForLine("horizontal", node); + lines.searchForLine("vertical", node); + } + + if (options.distributionGuidelines){ + lines.horizontalDistribution(node); + lines.verticalDistribution(node); + } + }); + + }; + + lines.resize = function () { + resizeCanvas(); + }; + + function getTopMostNodes(nodes) { + var nodesMap = {}; + + for (var i = 0; i < nodes.length; i++) { + nodesMap[nodes[i].id()] = true; + } + + var roots = nodes.filter(function (ele, i) { + if(typeof ele === "number") { + ele = i; + } + + var parent = ele.parent()[0]; + while (parent != null) { + if (nodesMap[parent.id()]) { + return false; + } + parent = parent.parent()[0]; + } + return true; + }); + + return roots; + } + + var mouseInitPos = {}; + var mouseRelativePos = {}; + var getMousePos = function(e){ + mouseInitPos = e.renderedPosition || e.cyRenderedPosition; + mouseRelativePos.x = mouseInitPos.x; + mouseRelativePos.y = mouseInitPos.y; + } + var setMousePos = function(panCurrPos){ + mouseRelativePos.x += (panCurrPos.x - panInitPos.x); + mouseRelativePos.y += (panCurrPos.y - panInitPos.y); + panInitPos.x = panCurrPos.x; panInitPos.y = panCurrPos.y; + }; + var mouseLine = function(node){ + var nodeCurrentPos = node.renderedPosition(); + if (Math.abs(nodeInitPos.y - nodeCurrentPos.y) < options.guidelinesTolerance){ + lines.drawLine({ + "x" : mouseRelativePos.x, + "y" : mouseInitPos.y + }, { + "x" : nodeCurrentPos.x, + "y" : mouseInitPos.y + }, options.guidelinesStyle.initPosAlignmentColor, options.guidelinesStyle.initPosAlignmentLine); + if (mouseInitPos.y == mouseRelativePos.y){ + lines.drawCross(mouseRelativePos); + } + else{ + lines.drawCross(mouseInitPos); + } + } + else if (Math.abs(nodeInitPos.x - nodeCurrentPos.x) < options.guidelinesTolerance){ + lines.drawLine({ + "x" : mouseInitPos.x, + "y" : mouseRelativePos.y + }, { + "x" : mouseInitPos.x, + "y" : nodeCurrentPos.y + }, options.guidelinesStyle.initPosAlignmentColor, options.guidelinesStyle.initPosAlignmentLine); + if (mouseInitPos.x == mouseRelativePos.x){ + lines.drawCross(mouseRelativePos); + } + else{ + lines.drawCross(mouseInitPos); + } + } + } + + function moveNodes(positionDiff, nodes) { + // Get the descendants of top most nodes. Note that node.position() can move just the simple nodes. + var topMostNodes = getTopMostNodes(nodes); + var nodesToMove = topMostNodes.union(topMostNodes.descendants()); + + nodesToMove.forEach(function(node, i) { + if(typeof node === "number") { + node = i; + } + var newPos = {x: positionDiff.x + node.renderedPosition("x"), + y: positionDiff.y + node.renderedPosition("y")}; + + node.renderedPosition(newPos); + }); + } + + var tappedNode; + cy.on("tapstart", "node", function(){tappedNode = this}); + + var currMousePos, oldMousePos = {"x": 0, "y": 0}; + cy.on("mousemove", function(e){ + currMousePos = e.renderedPosition || e.cyRenderedPosition; + if (nodeToAlign) + nodeToAlign.each(function (node, i){ + if(typeof node === "number") { + node = i; + } + if (node.locked() && (Math.abs(currMousePos.x - oldMousePos.x) > 2*options.guidelinesTolerance + || Math.abs(currMousePos.y - oldMousePos.y) > 2*options.guidelinesTolerance)){ + + node.unlock(); + var diff = {}; + diff.x = currMousePos.x - tappedNode.renderedPosition("x"); + diff.y = currMousePos.y - tappedNode.renderedPosition("y");; + moveNodes(diff, node); + }; + }); + + }); + var nodeToAlign; + lines.snapToAlignmentLocation = function(activeNodes){ + nodeToAlign = activeNodes; + activeNodes.each(function (node, i){ + if(typeof node === "number") { + node = i; + } + var newPos = node.renderedPosition(); + if (alignedLocations.h){ + oldMousePos = currMousePos; + newPos.x -= alignedLocations.h; + node.renderedPosition(newPos); + } + if (alignedLocations.v){ + oldMousePos = currMousePos; + newPos.y -= alignedLocations.v; + node.renderedPosition(newPos); + }; + if (alignedLocations.v || alignedLocations.h){ + alignedLocations.h = null; + alignedLocations.v = null; + nodeToAlign.lock(); + } + }); + lines.update(activeNodes); + } + + return { + changeOptions: changeOptions, + lines: lines, + getTopMostNodes: getTopMostNodes, + getMousePos: getMousePos, + setMousePos: setMousePos, + resizeCanvas: resizeCanvas, + } +}; + +},{"functional-red-black-tree":1}],7:[function(require,module,exports){ +;(function(){ 'use strict'; + + // registers the extension on a cytoscape lib ref + var register = function( cytoscape ){ + + if( !cytoscape ){ return; } // can't register if cytoscape unspecified + + var options = { + // On/Off Modules + /* From the following four snap options, at most one should be true at a given time */ + snapToGridOnRelease: true, // Snap to grid on release + snapToGridDuringDrag: false, // Snap to grid during drag + snapToAlignmentLocationOnRelease: false, // Snap to alignment location on release + snapToAlignmentLocationDuringDrag: false, // Snap to alignment location during drag + distributionGuidelines: false, //Distribution guidelines + geometricGuideline: false, // Geometric guidelines + initPosAlignment: false, // Guideline to initial mouse position + centerToEdgeAlignment: false, // Center tı edge alignment + resize: false, // Adjust node sizes to cell sizes + parentPadding: false, // Adjust parent sizes to cell sizes by padding + drawGrid: true, // Draw grid background + + // General + gridSpacing: 20, // Distance between the lines of the grid. + zoomDash: true, // Determines whether the size of the dashes should change when the drawing is zoomed in and out if grid is drawn. + panGrid: false, // Determines whether the grid should move then the user moves the graph if grid is drawn. + gridStackOrder: -1, // Namely z-index + gridColor: '#dedede', // Color of grid lines + lineWidth: 1.0, // Width of grid lines + guidelinesStackOrder: 4, // z-index of guidelines + guidelinesTolerance: 2.00, // Tolerance distance for rendered positions of nodes' interaction. + guidelinesStyle: { // Set ctx properties of line. Properties are here: + strokeStyle: "#8b7d6b", // color of geometric guidelines + geometricGuidelineRange: 400, // range of geometric guidelines + range: 100, // max range of distribution guidelines + minDistRange: 10, // min range for distribution guidelines + distGuidelineOffset: 10, // shift amount of distribution guidelines + horizontalDistColor: "#ff0000", // color of horizontal distribution alignment + verticalDistColor: "#00ff00", // color of vertical distribution alignment + initPosAlignmentColor: "#0000ff", // color of alignment to initial location + lineDash: [0, 0], // line style of geometric guidelines + horizontalDistLine: [0, 0], // line style of horizontal distribıtion guidelines + verticalDistLine: [0, 0], // line style of vertical distribıtion guidelines + initPosAlignmentLine: [0, 0], // line style of alignment to initial mouse position + }, + + // Parent Padding + parentSpacing: -1 // -1 to set paddings of parents to gridSpacing + }; + var _snapOnRelease = require("./snap_on_release"); + var _snapToGridDuringDrag = require("./snap_during_drag"); + var _drawGrid = require("./draw_grid"); + var _resize = require("./resize"); + var _eventsController = require("./events_controller"); + var _guidelines = require("./guidelines"); + var _parentPadding = require("./parentPadding"); + var _alignment = require("./alignment"); + var debounce = require("./debounce"); + var snap, resize, snapToGridDuringDrag, drawGrid, eventsController, guidelines, parentPadding, alignment; + + function getScratch(cy) { + if (!cy.scratch("_gridGuide")) { + cy.scratch("_gridGuide", { }); + } + + return cy.scratch("_gridGuide"); + } + + cytoscape( 'core', 'gridGuide', function(opts){ + var cy = this; + $.extend(true, options, opts); + + if (!getScratch(cy).initialized) { + snap = _snapOnRelease(cy, options.gridSpacing); + resize = _resize(options.gridSpacing); + snapToGridDuringDrag = _snapToGridDuringDrag(cy, snap); + drawGrid = _drawGrid(options, cy, $, debounce); + guidelines = _guidelines(options, cy, $, debounce); + parentPadding = _parentPadding(options, cy); + + eventsController = _eventsController(cy, snap, resize, snapToGridDuringDrag, drawGrid, guidelines, parentPadding, $, options); + + alignment = _alignment(cytoscape, cy, $); + + eventsController.init(options); + getScratch(cy).initialized = true; + } else + eventsController.syncWithOptions(options); + + return this; // chainability + } ) ; + + }; + + if( typeof module !== 'undefined' && module.exports ){ // expose as a commonjs module + module.exports = register; + } + + if( typeof define !== 'undefined' && define.amd ){ // expose as an amd/requirejs module + define('cytoscape-grid-guide', function(){ + return register; + }); + } + + if( typeof cytoscape !== 'undefined' ){ // expose to global cytoscape (i.e. window.cytoscape) + register( cytoscape ); + } + +})(); + +},{"./alignment":2,"./debounce":3,"./draw_grid":4,"./events_controller":5,"./guidelines":6,"./parentPadding":8,"./resize":9,"./snap_during_drag":10,"./snap_on_release":11}],8:[function(require,module,exports){ +module.exports = function (opts, cy) { + + var options = opts; + var ppClass = "_gridParentPadding"; + + function initPadding() { + var padding = options.parentSpacing < 0 ? options.gridSpacing : options.parentSpacing; + cy.style() + .selector('.' + ppClass) + .style("compound-sizing-wrt-labels", "exclude") + .style("padding-left", padding) + .style("padding-right", padding) + .style("padding-top", padding) + .style("padding-bottom", padding) + .update(); + + } + + function changeOptions(opts) { + options = opts; + padding = options.parentSpacing < 0 ? options.gridSpacing : options.parentSpacing; + initPadding(); + } + + function setPaddingOfParent(node, enable) { + if (enable) + node.addClass(ppClass); + else + node.removeClass(ppClass); + } + + return { + changeOptions: changeOptions, + setPaddingOfParent: setPaddingOfParent + }; +}; +},{}],9:[function(require,module,exports){ +module.exports = function (gridSpacing) { + + + var changeOptions = function (opts) { + gridSpacing = Number(opts.gridSpacing); + }; + + var getScratch = function (node) { + if (!node.scratch("_gridGuide")) + node.scratch("_gridGuide", {}); + + return node.scratch("_gridGuide"); + }; + + function resizeNode(node) { + var width = node.width(); + var height = node.height(); + + var newWidth = Math.round((width - gridSpacing) / (gridSpacing * 2)) * (gridSpacing * 2); + var newHeight = Math.round((height - gridSpacing) / (gridSpacing * 2)) * (gridSpacing * 2); + newWidth = newWidth > 0 ? newWidth + gridSpacing : gridSpacing; + newHeight = newHeight > 0 ? newHeight + gridSpacing : gridSpacing; + + if (width != newWidth || height != newHeight) { + node.style({ + "width": newWidth, + "height": newHeight + }); + getScratch(node).resize = { + oldWidth: width, + oldHeight: height + }; + } + } + + function recoverNodeDimensions(node) { + var oldSizes = getScratch(node).resize; + if (oldSizes) + node.style({ + "width": oldSizes.oldWidth, + "height": oldSizes.oldHeight + }); + + + } + + + return { + resizeNode: resizeNode, + recoverNodeDimensions: recoverNodeDimensions, + changeOptions: changeOptions + }; + +}; +},{}],10:[function(require,module,exports){ +module.exports = function (cy, snap) { + + var snapToGridDuringDrag = {}; + + var attachedNode; + var draggedNodes; + + var startPos; + var endPos; + + + snapToGridDuringDrag.onTapStartNode = function (e) { + // If user intends to do box selection, then return. Related issue #28 + if (e.originalEvent.altKey || e.originalEvent.ctrlKey + || e.originalEvent.metaKey || e.originalEvent.shiftKey){ + return; + } + + var cyTarget = e.target || e.cyTarget; + if (cyTarget.selected()) + draggedNodes = e.cy.$(":selected"); + else + draggedNodes = cyTarget; + + startPos = e.position || e.cyPosition; + + if (cyTarget.grabbable() && !cyTarget.locked()){ + attachedNode = cyTarget; + attachedNode.lock(); + //attachedNode.trigger("grab"); + cy.on("tapdrag", onTapDrag); + cy.on("tapend", onTapEndNode); + } + }; + + var onTapEndNode = function (e) { + //attachedNode.trigger("free"); + cy.off("tapdrag", onTapDrag); + cy.off("tapend", onTapEndNode); + attachedNode.unlock(); + e.preventDefault(); + }; + + var getDist = function () { + return { + x: endPos.x - startPos.x, + y: endPos.y - startPos.y + } + }; + + function getTopMostNodes(nodes) { + var nodesMap = {}; + + for (var i = 0; i < nodes.length; i++) { + nodesMap[nodes[i].id()] = true; + } + + var roots = nodes.filter(function (ele, i) { + if(typeof ele === "number") { + ele = i; + } + + var parent = ele.parent()[0]; + while (parent != null) { + if (nodesMap[parent.id()]) { + return false; + } + parent = parent.parent()[0]; + } + return true; + }); + + return roots; + } + + var moveNodesTopDown = function (nodes, dx, dy) { + +/* + console.log(nodes.map(function (e) { + return e.id(); + })); + for (var i = 0; i < nodes.length; i++) { + var node = nodes[i]; + var pos = node.position(); + + if (!node.isParent()) { + node.position({ + x: pos.x + dx, + y: pos.y + dy + }); + console.log(node.id() + " " + dx + " " + dy); + } + + moveNodesTopDown(nodes.children(), dx, dy); + } +*/ + }; + + var onTapDrag = function (e) { + + var nodePos = attachedNode.position(); + endPos = e.position || e.cyPosition; + endPos = snap.snapPos(endPos); + var dist = getDist(); + if (dist.x != 0 || dist.y != 0) { + attachedNode.unlock(); + //var topMostNodes = getTopMostNodes(draggedNodes); + var nodes = draggedNodes.union(draggedNodes.descendants()); + + nodes.positions(function (node, i) { + if(typeof node === "number") { + node = i; + } + var pos = node.position(); + return snap.snapPos({ + x: pos.x + dist.x, + y: pos.y + dist.y + }); + }); + + startPos = endPos; + attachedNode.lock(); + attachedNode.trigger("drag"); + } + + }; + + return snapToGridDuringDrag; + + +}; + +},{}],11:[function(require,module,exports){ +module.exports = function (cy, gridSpacing) { + + var snap = { }; + + snap.changeOptions = function (opts) { + gridSpacing = opts.gridSpacing; + }; + + var getScratch = function (node) { + if (!node.scratch("_gridGuide")) + node.scratch("_gridGuide", {}); + + return node.scratch("_gridGuide"); + }; + + + function getTopMostNodes(nodes) { + var nodesMap = {}; + + for (var i = 0; i < nodes.length; i++) { + nodesMap[nodes[i].id()] = true; + } + + var roots = nodes.filter(function (ele, i) { + if(typeof ele === "number") { + ele = i; + } + + var parent = ele.parent()[0]; + while(parent != null){ + if(nodesMap[parent.id()]){ + return false; + } + parent = parent.parent()[0]; + } + return true; + }); + + return roots; + } + + snap.snapPos = function (pos) { + var newPos = { + x: (Math.floor(pos.x / gridSpacing) + 0.5) * gridSpacing, + y: (Math.floor(pos.y / gridSpacing) + 0.5) * gridSpacing + }; + + return newPos; + }; + + snap.snapNode = function (node) { + + var pos = node.position(); + var newPos = snap.snapPos(pos); + + node.position(newPos); + }; + + function snapTopDown(nodes) { + + nodes.union(nodes.descendants()).positions(function (node, i) { + if(typeof node === "number") { + node = i; + } + var pos = node.position(); + return snap.snapPos(pos); + }); + /* + for (var i = 0; i < nodes.length; i++) { + + if (!nodes[i].isParent()) + snap.snapNode(nodes[i]); + + snapTopDown(nodes.children()); + }*/ + + } + + snap.snapNodesTopDown = function (nodes) { + // getTOpMostNodes -> nodes + cy.startBatch(); + nodes.union(nodes.descendants()).positions(function (node, i) { + if(typeof node === "number") { + node = i; + } + var pos = node.position(); + return snap.snapPos(pos); + }); + cy.endBatch(); + }; + + snap.onFreeNode = function (e) { + var nodes; + var cyTarget = e.target || e.cyTarget; + if (cyTarget.selected()) + nodes = e.cy.$(":selected"); + else + nodes = cyTarget; + + snap.snapNodesTopDown(nodes); + + }; + + + snap.recoverSnapNode = function (node) { + var snapScratch = getScratch(node).snap; + if (snapScratch) { + node.position(snapScratch.oldPos); + } + }; + + return snap; + + + + + +}; + +},{}]},{},[7]); diff --git a/web/js/cytoscape-navigator.js b/web/js/cytoscape-navigator.js new file mode 100644 index 000000000..3b9c05caf --- /dev/null +++ b/web/js/cytoscape-navigator.js @@ -0,0 +1,871 @@ +;(function(){ 'use strict'; + + var $; + + var defaults = { + container: false // can be a HTML or jQuery element or jQuery selector + , viewLiveFramerate: 0 // set false to update graph pan only on drag end; set 0 to do it instantly; set a number (frames per second) to update not more than N times per second + , dblClickDelay: 200 // milliseconds + , removeCustomContainer: true // destroy the container specified by user on plugin destroy + , rerenderDelay: 500 // ms to throttle rerender updates to the panzoom for performance + }; + + var debounce = (function(){ + /** + * lodash 3.1.1 (Custom Build) + * Build: `lodash modern modularize exports="npm" -o ./` + * Copyright 2012-2015 The Dojo Foundation + * Based on Underscore.js 1.8.3 + * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ + /** Used as the `TypeError` message for "Functions" methods. */ + var FUNC_ERROR_TEXT = 'Expected a function'; + + /* Native method references for those with the same name as other `lodash` methods. */ + var nativeMax = Math.max, + nativeNow = Date.now; + + /** + * Gets the number of milliseconds that have elapsed since the Unix epoch + * (1 January 1970 00:00:00 UTC). + * + * @static + * @memberOf _ + * @category Date + * @example + * + * _.defer(function(stamp) { + * console.log(_.now() - stamp); + * }, _.now()); + * // => logs the number of milliseconds it took for the deferred function to be invoked + */ + var now = nativeNow || function() { + return new Date().getTime(); + }; + + /** + * Creates a debounced function that delays invoking `func` until after `wait` + * milliseconds have elapsed since the last time the debounced function was + * invoked. The debounced function comes with a `cancel` method to cancel + * delayed invocations. Provide an options object to indicate that `func` + * should be invoked on the leading and/or trailing edge of the `wait` timeout. + * Subsequent calls to the debounced function return the result of the last + * `func` invocation. + * + * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked + * on the trailing edge of the timeout only if the the debounced function is + * invoked more than once during the `wait` timeout. + * + * See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation) + * for details over the differences between `_.debounce` and `_.throttle`. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to debounce. + * @param {number} [wait=0] The number of milliseconds to delay. + * @param {Object} [options] The options object. + * @param {boolean} [options.leading=false] Specify invoking on the leading + * edge of the timeout. + * @param {number} [options.maxWait] The maximum time `func` is allowed to be + * delayed before it's invoked. + * @param {boolean} [options.trailing=true] Specify invoking on the trailing + * edge of the timeout. + * @returns {Function} Returns the new debounced function. + * @example + * + * // avoid costly calculations while the window size is in flux + * jQuery(window).on('resize', _.debounce(calculateLayout, 150)); + * + * // invoke `sendMail` when the click event is fired, debouncing subsequent calls + * jQuery('#postbox').on('click', _.debounce(sendMail, 300, { + * 'leading': true, + * 'trailing': false + * })); + * + * // ensure `batchLog` is invoked once after 1 second of debounced calls + * var source = new EventSource('/stream'); + * jQuery(source).on('message', _.debounce(batchLog, 250, { + * 'maxWait': 1000 + * })); + * + * // cancel a debounced call + * var todoChanges = _.debounce(batchLog, 1000); + * Object.observe(models.todo, todoChanges); + * + * Object.observe(models, function(changes) { + * if (_.find(changes, { 'user': 'todo', 'type': 'delete'})) { + * todoChanges.cancel(); + * } + * }, ['delete']); + * + * // ...at some point `models.todo` is changed + * models.todo.completed = true; + * + * // ...before 1 second has passed `models.todo` is deleted + * // which cancels the debounced `todoChanges` call + * delete models.todo; + */ + function debounce(func, wait, options) { + var args, + maxTimeoutId, + result, + stamp, + thisArg, + timeoutId, + trailingCall, + lastCalled = 0, + maxWait = false, + trailing = true; + + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + wait = wait < 0 ? 0 : (+wait || 0); + if (options === true) { + var leading = true; + trailing = false; + } else if (isObject(options)) { + leading = !!options.leading; + maxWait = 'maxWait' in options && nativeMax(+options.maxWait || 0, wait); + trailing = 'trailing' in options ? !!options.trailing : trailing; + } + + function cancel() { + if (timeoutId) { + clearTimeout(timeoutId); + } + if (maxTimeoutId) { + clearTimeout(maxTimeoutId); + } + lastCalled = 0; + maxTimeoutId = timeoutId = trailingCall = undefined; + } + + function complete(isCalled, id) { + if (id) { + clearTimeout(id); + } + maxTimeoutId = timeoutId = trailingCall = undefined; + if (isCalled) { + lastCalled = now(); + result = func.apply(thisArg, args); + if (!timeoutId && !maxTimeoutId) { + args = thisArg = undefined; + } + } + } + + function delayed() { + var remaining = wait - (now() - stamp); + if (remaining <= 0 || remaining > wait) { + complete(trailingCall, maxTimeoutId); + } else { + timeoutId = setTimeout(delayed, remaining); + } + } + + function maxDelayed() { + complete(trailing, timeoutId); + } + + function debounced() { + args = arguments; + stamp = now(); + thisArg = this; + trailingCall = trailing && (timeoutId || !leading); + + if (maxWait === false) { + var leadingCall = leading && !timeoutId; + } else { + if (!maxTimeoutId && !leading) { + lastCalled = stamp; + } + var remaining = maxWait - (stamp - lastCalled), + isCalled = remaining <= 0 || remaining > maxWait; + + if (isCalled) { + if (maxTimeoutId) { + maxTimeoutId = clearTimeout(maxTimeoutId); + } + lastCalled = stamp; + result = func.apply(thisArg, args); + } + else if (!maxTimeoutId) { + maxTimeoutId = setTimeout(maxDelayed, remaining); + } + } + if (isCalled && timeoutId) { + timeoutId = clearTimeout(timeoutId); + } + else if (!timeoutId && wait !== maxWait) { + timeoutId = setTimeout(delayed, wait); + } + if (leadingCall) { + isCalled = true; + result = func.apply(thisArg, args); + } + if (isCalled && !timeoutId && !maxTimeoutId) { + args = thisArg = undefined; + } + return result; + } + debounced.cancel = cancel; + return debounced; + } + + /** + * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`. + * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(1); + * // => false + */ + function isObject(value) { + // Avoid a V8 JIT bug in Chrome 19-20. + // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. + var type = typeof value; + return !!value && (type == 'object' || type == 'function'); + } + + return debounce; + + })(); + + // ported lodash throttle function + var throttle = function( func, wait, options ){ + var leading = true, + trailing = true; + + if( options === false ){ + leading = false; + } else if( typeof options === typeof {} ){ + leading = 'leading' in options ? options.leading : leading; + trailing = 'trailing' in options ? options.trailing : trailing; + } + options = options || {}; + options.leading = leading; + options.maxWait = wait; + options.trailing = trailing; + + return debounce( func, wait, options ); + }; + + var Navigator = function ( element, options ) { + this._init(element, options) + } + + Navigator.prototype = { + + constructor: Navigator + + /**************************** + Main functions + ****************************/ + + , bb: function(){ + var bb = this.cy.elements().boundingBox() + + if( bb.w === 0 || bb.h === 0 ){ + return { + x1: 0, + x2: Infinity, + y1: 0, + y2: Infinity, + w: Infinity, + h: Infinity + } // => hide interactive overlay + } + + return bb + } + + , _init: function ( cy, options ) { + this.$element = $( cy.container() ) + this.options = $.extend({}, defaults, options) + + this.cy = cy + + // Cache bounding box + this.boundingBox = this.bb() + + // Cache sizes + this.width = this.$element.width() + this.height = this.$element.height() + + // Init components + this._initPanel() + this._initThumbnail() + this._initView() + this._initOverlay() + } + + , destroy: function () { + this._removeEventsHandling(); + + // If container is not created by navigator and its removal is prohibited + if (this.options.container && !this.options.removeCustomContainer) { + this.$panel.empty() + } else { + this.$panel.remove() + } + this.$element.removeData('navigator') + } + + /**************************** + Navigator elements functions + ****************************/ + + /* + * Used inner attributes + * + * w {number} width + * h {number} height + */ + , _initPanel: function () { + var options = this.options + + if( options.container ) { + if( options.container instanceof jQuery ){ + if( options.container.length > 0 ){ + this.$panel = options.container.first() + } else { + $.error("Container for jquery.cyNavigator is empty") + return + } + } else if ( $(options.container).length > 0 ) { + this.$panel = $(options.container).first() + } else { + $.error("There is no any element matching your selector for jquery.cyNavigator") + return + } + } else { + this.$panel = $('
') + $('body').append(this.$panel) + } + + this._setupPanel() + + this.cy.on('resize', $.proxy(this.resize, this)) + } + + , _setupPanel: function () { + var options = this.options + + // Cache sizes + this.panelWidth = this.$panel.width() + this.panelHeight = this.$panel.height() + } + + /* + * Used inner attributes + * + * zoom {number} + * pan {object} - {x: 0, y: 0} + */ + , _initThumbnail: function () { + // Create thumbnail + this.$thumbnail = $('') + + // Add thumbnail canvas to the DOM + this.$panel.append(this.$thumbnail) + + // Setup thumbnail + this._setupThumbnailSizes() + this._setupThumbnail() + } + + , _setupThumbnail: function () { + this._updateThumbnailImage() + } + + , _setupThumbnailSizes: function () { + // Update bounding box cache + this.boundingBox = this.bb() + + this.thumbnailZoom = Math.min(this.panelHeight / this.boundingBox.h, this.panelWidth / this.boundingBox.w) + + // Used on thumbnail generation + this.thumbnailPan = { + x: (this.panelWidth - this.thumbnailZoom * (this.boundingBox.x1 + this.boundingBox.x2))/2 + , y: (this.panelHeight - this.thumbnailZoom * (this.boundingBox.y1 + this.boundingBox.y2))/2 + } + } + + // If bounding box has changed then update sizes + // Otherwise just update the thumbnail + , _checkThumbnailSizesAndUpdate: function () { + // Cache previous values + var _zoom = this.thumbnailZoom + , _pan_x = this.thumbnailPan.x + , _pan_y = this.thumbnailPan.y + + this._setupThumbnailSizes() + + if (_zoom != this.thumbnailZoom || _pan_x != this.thumbnailPan.x || _pan_y != this.thumbnailPan.y) { + this._setupThumbnail() + this._setupView() + } else { + this._updateThumbnailImage() + } + } + + /* + * Used inner attributes + * + * w {number} width + * h {number} height + * x {number} + * y {number} + * borderWidth {number} + * locked {boolean} + */ + , _initView: function () { + var that = this + + this.$view = $('
') + this.$panel.append(this.$view) + + // Compute borders + this.viewBorderTop = parseInt(this.$view.css('border-top-width'), 10) + this.viewBorderRight = parseInt(this.$view.css('border-right-width'), 10) + this.viewBorderBottom = parseInt(this.$view.css('border-bottom-width'), 10) + this.viewBorderLeft = parseInt(this.$view.css('border-left-width'), 10) + + // Abstract borders + this.viewBorderHorizontal = this.viewBorderLeft + this.viewBorderRight + this.viewBorderVertical = this.viewBorderTop + this.viewBorderBottom + + this._setupView() + + // Hook graph zoom and pan + this.cy.on('zoom pan', $.proxy(this._setupView, this)) + } + + , _setupView: function () { + if (this.viewLocked) + return + + var cyZoom = this.cy.zoom() + , cyPan = this.cy.pan() + + // Horizontal computation + this.viewW = this.width / cyZoom * this.thumbnailZoom + this.viewX = -cyPan.x * this.viewW / this.width + this.thumbnailPan.x - this.viewBorderLeft + + // Vertical computation + this.viewH = this.height / cyZoom * this.thumbnailZoom + this.viewY = -cyPan.y * this.viewH / this.height + this.thumbnailPan.y - this.viewBorderTop + + // CSS view + this.$view + .width(this.viewW) + .height(this.viewH) + .css({ + position: 'absolute', + left: this.viewX + , top: this.viewY + }) + } + + /* + * Used inner attributes + * + * timeout {number} used to keep stable frame rate + * lastMoveStartTime {number} + * inMovement {boolean} + * hookPoint {object} {x: 0, y: 0} + */ + , _initOverlay: function () { + // Used to capture mouse events + this.$overlay = $('
') + + // Add overlay to the DOM + this.$panel.append(this.$overlay) + + // Init some attributes + this.overlayHookPointX = 0; + this.overlayHookPointY = 0; + + // Listen for events + this._initEventsHandling() + } + + /**************************** + Event handling functions + ****************************/ + + , resize: function () { + // Cache sizes + this.width = this.$element.width() + this.height = this.$element.height() + + this._thumbnailSetup = false + this._setupPanel() + this._checkThumbnailSizesAndUpdate() + this._setupView() + } + + , _initEventsHandling: function () { + var that = this + , eventsLocal = [ + // Mouse events + 'mousedown' + , 'mousewheel' + , 'DOMMouseScroll' // Mozilla specific event + // Touch events + , 'touchstart' + ] + , eventsGlobal = [ + 'mouseup' + , 'mouseout' + , 'mousemove' + // Touch events + , 'touchmove' + , 'touchend' + ] + + // handle events and stop their propagation + var overlayListener; + this.$overlay.on(eventsLocal.join(' '), overlayListener = function (ev) { + // Touch events + if (ev.type == 'touchstart') { + // Will count as middle of View + ev.offsetX = that.viewX + that.viewW / 2 + ev.offsetY = that.viewY + that.viewH / 2 + } + + // Normalize offset for browsers which do not provide that value + if (ev.offsetX === undefined || ev.offsetY === undefined) { + var targetOffset = $(ev.target).offset() + ev.offsetX = ev.pageX - targetOffset.left + ev.offsetY = ev.pageY - targetOffset.top + } + + if (ev.type == 'mousedown' || ev.type == 'touchstart') { + that._eventMoveStart(ev) + } else if (ev.type == 'mousewheel' || ev.type == 'DOMMouseScroll') { + that._eventZoom(ev) + } + + // Prevent default and propagation + // Don't use peventPropagation as it breaks mouse events + return false; + }) + + // Hook global events + var globalListener; + $(window).on(eventsGlobal.join(' '), globalListener = function (ev) { + // Do not make any computations if it is has no effect on Navigator + if (!that.overlayInMovement) + return; + + // Touch events + if (ev.type == 'touchend') { + // Will count as middle of View + ev.offsetX = that.viewX + that.viewW / 2 + ev.offsetY = that.viewY + that.viewH / 2 + } else if (ev.type == 'touchmove') { + // Hack - we take in account only first touch + ev.pageX = ev.originalEvent.touches[0].pageX + ev.pageY = ev.originalEvent.touches[0].pageY + } + + // Normalize offset for browsers which do not provide that value + if (ev.offsetX === undefined || ev.offsetY === undefined) { + var targetOffset = $(ev.target).offset() + ev.offsetX = ev.pageX - targetOffset.left + ev.offsetY = ev.pageY - targetOffset.top + } + + // Translate global events into local coordinates + if (ev.target !== that.$overlay[0]) { + var targetOffset = $(ev.target).offset() + , overlayOffset = that.$overlay.offset() + + ev.offsetX = ev.offsetX - overlayOffset.left + targetOffset.left + ev.offsetY = ev.offsetY - overlayOffset.top + targetOffset.top + } + + if (ev.type == 'mousemove' || ev.type == 'touchmove') { + that._eventMove(ev) + } else if (ev.type == 'mouseup' || ev.type == 'touchend') { + that._eventMoveEnd(ev) + } + + // Prevent default and propagation + // Don't use peventPropagation as it breaks mouse events + return false; + }) + + this._removeEventsHandling = function(){ + + this.$overlay.off( eventsLocal.join(' '), overlayListener ) + $(window).off( eventsGlobal.join(' '), globalListener ) + } + } + + , _eventMoveStart: function (ev) { + var now = new Date().getTime() + + // Check if it was double click + if (this.overlayLastMoveStartTime + && this.overlayLastMoveStartTime + this.options.dblClickDelay > now) { + // Reset lastMoveStartTime + this.overlayLastMoveStartTime = 0 + // Enable View in order to move it to the center + this.overlayInMovement = true + + // Set hook point as View center + this.overlayHookPointX = this.viewW / 2 + this.overlayHookPointY = this.viewH / 2 + + // Move View to start point + if (this.options.viewLiveFramerate !== false) { + this._eventMove({ + offsetX: this.panelWidth / 2 + , offsetY: this.panelHeight / 2 + }) + } else { + this._eventMoveEnd({ + offsetX: this.panelWidth / 2 + , offsetY: this.panelHeight / 2 + }) + } + + // View should be inactive as we don't want to move it right after double click + this.overlayInMovement = false + } + // This is a single click + // Take care as single click happens before double click 2 times + else { + this.overlayLastMoveStartTime = now + this.overlayInMovement = true + // Lock view moving caused by cy events + this.viewLocked = true + + // if event started in View + if (ev.offsetX >= this.viewX && ev.offsetX <= this.viewX + this.viewW + && ev.offsetY >= this.viewY && ev.offsetY <= this.viewY + this.viewH + ) { + this.overlayHookPointX = ev.offsetX - this.viewX + this.overlayHookPointY = ev.offsetY - this.viewY + } + // if event started in Thumbnail (outside of View) + else { + // Set hook point as View center + this.overlayHookPointX = this.viewW / 2 + this.overlayHookPointY = this.viewH / 2 + + // Move View to start point + this._eventMove(ev) + } + } + } + + , _eventMove: function (ev) { + var that = this + + this._checkMousePosition(ev) + + // break if it is useless event + if (!this.overlayInMovement) { + return; + } + + // Update cache + this.viewX = ev.offsetX - this.overlayHookPointX + this.viewY = ev.offsetY - this.overlayHookPointY + + // Update view position + this.$view.css('left', this.viewX) + this.$view.css('top', this.viewY) + + // Move Cy + if (this.options.viewLiveFramerate !== false) { + // trigger instantly + if (this.options.viewLiveFramerate == 0) { + this._moveCy() + } + // trigger less often than frame rate + else if (!this.overlayTimeout) { + // Set a timeout for graph movement + this.overlayTimeout = setTimeout(function () { + that._moveCy() + that.overlayTimeout = false + }, 1000/this.options.viewLiveFramerate) + } + } + } + + , _checkMousePosition: function (ev) { + // If mouse in over View + if(ev.offsetX > this.viewX && ev.offsetX < this.viewX + this.viewBorderHorizontal + this.viewW + && ev.offsetY > this.viewY && ev.offsetY < this.viewY + this.viewBorderVertical + this.viewH) { + this.$panel.addClass('mouseover-view') + } else { + this.$panel.removeClass('mouseover-view') + } + } + + , _eventMoveEnd: function (ev) { + // Unlock view changing caused by graph events + this.viewLocked = false + + // Remove class when mouse is not over Navigator + this.$panel.removeClass('mouseover-view') + + if (!this.overlayInMovement) { + return; + } + + // Trigger one last move + this._eventMove(ev) + + // If mode is not live then move graph on drag end + if (this.options.viewLiveFramerate === false) { + this._moveCy() + } + + // Stop movement permission + this.overlayInMovement = false + } + + , _eventZoom: function (ev) { + var zoomRate = Math.pow(10, ev.originalEvent.wheelDeltaY / 1000 || ev.originalEvent.wheelDelta / 1000 || ev.originalEvent.detail / -32) + , mousePosition = { + left: ev.offsetX + , top: ev.offsetY + } + + if (this.cy.zoomingEnabled()) { + this._zoomCy(zoomRate, mousePosition) + } + } + + , _updateThumbnailImage: function () { + var that = this; + + if( this._thumbnailUpdating ){ + return; + } + + this._thumbnailUpdating = true; + + var render = function(){ + that._checkThumbnailSizesAndUpdate(); + that._setupView(); + + var $img = that.$thumbnail; + var img = $img[0]; + + var w = that.panelWidth; + var h = that.panelHeight; + var bb = that.boundingBox; + var zoom = Math.min( w/bb.w, h/bb.h ); + + var pxRatio = 1; + + var translate = { + x: (w - zoom*( bb.w ))/2, + y: (h - zoom*( bb.h ))/2 + }; + + var png = that.cy.png({ + full: true, + scale: zoom + }); + + if( png.indexOf('image/png') < 0 ){ + img.removeAttribute( 'src' ); + } else { + img.setAttribute( 'src', png ); + } + + $img.css({ + 'position': 'absolute', + 'left': translate.x + 'px', + 'top': translate.y + 'px' + }); + } + + this.cy.onRender( throttle(render, that.options.rerenderDelay) ); + } + + /**************************** + Navigator view moving + ****************************/ + + , _moveCy: function () { + this.cy.pan({ + x: -(this.viewX + this.viewBorderLeft - this.thumbnailPan.x) * this.width / this.viewW + , y: -(this.viewY + this.viewBorderLeft - this.thumbnailPan.y) * this.height / this.viewH + }) + } + + /** + * Zooms graph. + * + * @this {cytoscapeNavigator} + * @param {number} zoomRate The zoom rate value. 1 is 100%. + */ + , _zoomCy: function (zoomRate, zoomCenterRaw) { + var zoomCenter + , isZoomCenterInView = false + + zoomCenter = { + x: this.width / 2 + , y: this.height / 2 + }; + + this.cy.zoom({ + level: this.cy.zoom() * zoomRate + , renderedPosition: zoomCenter + }) + } + } + + // registers the extension on a cytoscape lib ref + var register = function( cytoscape, jq ){ + + if( !cytoscape || !jq ){ return; } // can't register if cytoscape unspecified + + $ = jq; + + cytoscape( 'core', 'navigator', function( options ){ + var cy = this; + + return new Navigator( cy, options ); + } ); + + }; + + if( typeof module !== 'undefined' && module.exports ){ // expose as a commonjs module + module.exports = function( cytoscape, jq ){ + register( cytoscape, jq || require('jquery') ); + }; + } else if( typeof define !== 'undefined' && define.amd ){ // expose as an amd/requirejs module + define('cytoscape-navigator', function(){ + return register; + }); + } + + if( typeof cytoscape !== 'undefined' && typeof jQuery !== 'undefined' ){ // expose to global cytoscape (i.e. window.cytoscape) + register( cytoscape, jQuery ); + } + +})(); diff --git a/web/js/cytoscape-panzoom.js b/web/js/cytoscape-panzoom.js new file mode 100644 index 000000000..77ac7355c --- /dev/null +++ b/web/js/cytoscape-panzoom.js @@ -0,0 +1,587 @@ +/*! +Copyright (c) The Cytoscape Consortium + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the “Software”), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +;(function(){ 'use strict'; + + // registers the extension on a cytoscape lib ref + var register = function( cytoscape, $ ){ + if( !cytoscape || !$ ){ return; } // can't register if cytoscape or jquery unspecified + + $.fn.cyPanzoom = $.fn.cytoscapePanzoom = function( options ){ + panzoom.apply( this, [ options, cytoscape, $ ] ); + + return this; // chainability + }; + + // if you want a core extension + cytoscape('core', 'panzoom', function( options ){ // could use options object, but args are up to you + panzoom.apply( this, [ options, cytoscape, $ ] ); + + return this; // chainability + }); + + }; + + var defaults = { + zoomFactor: 0.05, // zoom factor per zoom tick + zoomDelay: 45, // how many ms between zoom ticks + minZoom: 0.1, // min zoom level + maxZoom: 10, // max zoom level + fitPadding: 50, // padding when fitting + panSpeed: 10, // how many ms in between pan ticks + panDistance: 10, // max pan distance per tick + panDragAreaSize: 75, // the length of the pan drag box in which the vector for panning is calculated (bigger = finer control of pan speed and direction) + panMinPercentSpeed: 0.25, // the slowest speed we can pan by (as a percent of panSpeed) + panInactiveArea: 8, // radius of inactive area in pan drag box + panIndicatorMinOpacity: 0.5, // min opacity of pan indicator (the draggable nib); scales from this to 1.0 + zoomOnly: false, // a minimal version of the ui only with zooming (useful on systems with bad mousewheel resolution) + fitSelector: undefined, // selector of elements to fit + animateOnFit: function(){ // whether to animate on fit + return false; + }, + fitAnimationDuration: 1000, // duration of animation on fit + + // icon class names + sliderHandleIcon: 'fa fa-minus', + zoomInIcon: 'fa fa-plus', + zoomOutIcon: 'fa fa-minus', + resetIcon: 'fa fa-expand' + }; + + var panzoom = function( params, cytoscape, $ ){ + var cyRef = this; + var options = $.extend(true, {}, defaults, params); + var fn = params; + + var functions = { + destroy: function(){ + var $this = $(cyRef.container()); + var $pz = $this.find(".cy-panzoom"); + + $pz.data('winbdgs').forEach(function( l ){ + $(window).unbind( l.evt, l.fn ); + }); + + $pz.data('cybdgs').forEach(function( l ){ + cyRef.off( l.evt, l.fn ); + }); + + $pz.remove(); + }, + + init: function(){ + var browserIsMobile = 'ontouchstart' in window; + + return $(cyRef.container()).each(function(){ + var $container = $(this); + $container.cytoscape = cytoscape; + + var winbdgs = []; + var $win = $(window); + + var windowBind = function( evt, fn ){ + winbdgs.push({ evt: evt, fn: fn }); + + $win.bind( evt, fn ); + }; + + var windowUnbind = function( evt, fn ){ + for( var i = 0; i < winbdgs.length; i++ ){ + var l = winbdgs[i]; + + if( l.evt === evt && l.fn === fn ){ + winbdgs.splice( i, 1 ); + break; + } + } + + $win.unbind( evt, fn ); + }; + + var cybdgs = []; + + var cyOn = function( evt, fn ){ + cybdgs.push({ evt: evt, fn: fn }); + + cyRef.on( evt, fn ); + }; + + var cyOff = function( evt, fn ){ + for( var i = 0; i < cybdgs.length; i++ ){ + var l = cybdgs[i]; + + if( l.evt === evt && l.fn === fn ){ + cybdgs.splice( i, 1 ); + break; + } + } + + cyRef.off( evt, fn ); + }; + + var $panzoom = $('
'); + $container.prepend( $panzoom ); + + $panzoom.css('position', 'absolute'); // must be absolute regardless of stylesheet + + $panzoom.data('winbdgs', winbdgs); + $panzoom.data('cybdgs', cybdgs); + + if( options.zoomOnly ){ + $panzoom.addClass("cy-panzoom-zoom-only"); + } + + // add base html elements + ///////////////////////// + + var $zoomIn = $('
'); + $panzoom.append( $zoomIn ); + + var $zoomOut = $('
'); + $panzoom.append( $zoomOut ); + + var $reset = $('
'); + $panzoom.append( $reset ); + + var $slider = $('
'); + $panzoom.append( $slider ); + + $slider.append('
'); + + var $sliderHandle = $('
'); + $slider.append( $sliderHandle ); + + var $noZoomTick = $('
'); + $slider.append( $noZoomTick ); + + var $panner = $('
'); + $panzoom.append( $panner ); + + var $pHandle = $('
'); + $panner.append( $pHandle ); + + var $pUp = $('
'); + var $pDown = $('
'); + var $pLeft = $('
'); + var $pRight = $('
'); + $panner.append( $pUp ).append( $pDown ).append( $pLeft ).append( $pRight ); + + var $pIndicator = $('
'); + $panner.append( $pIndicator ); + + // functions for calculating panning + //////////////////////////////////// + + function handle2pan(e){ + var v = { + x: e.originalEvent.pageX - $panner.offset().left - $panner.width()/2, + y: e.originalEvent.pageY - $panner.offset().top - $panner.height()/2 + } + + var r = options.panDragAreaSize; + var d = Math.sqrt( v.x*v.x + v.y*v.y ); + var percent = Math.min( d/r, 1 ); + + if( d < options.panInactiveArea ){ + return { + x: NaN, + y: NaN + }; + } + + v = { + x: v.x/d, + y: v.y/d + }; + + percent = Math.max( options.panMinPercentSpeed, percent ); + + var vnorm = { + x: -1 * v.x * (percent * options.panDistance), + y: -1 * v.y * (percent * options.panDistance) + }; + + return vnorm; + } + + function donePanning(){ + clearInterval(panInterval); + windowUnbind("mousemove", handler); + + $pIndicator.hide(); + } + + function positionIndicator(pan){ + var v = pan; + var d = Math.sqrt( v.x*v.x + v.y*v.y ); + var vnorm = { + x: -1 * v.x/d, + y: -1 * v.y/d + }; + + var w = $panner.width(); + var h = $panner.height(); + var percent = d/options.panDistance; + var opacity = Math.max( options.panIndicatorMinOpacity, percent ); + var color = 255 - Math.round( opacity * 255 ); + + $pIndicator.show().css({ + left: w/2 * vnorm.x + w/2, + top: h/2 * vnorm.y + h/2, + background: "rgb(" + color + ", " + color + ", " + color + ")" + }); + } + + function calculateZoomCenterPoint(){ + var pan = cyRef.pan(); + var zoom = cyRef.zoom(); + + zx = $container.width()/2; + zy = $container.height()/2; + } + + var zooming = false; + function startZooming(){ + zooming = true; + + calculateZoomCenterPoint(); + } + + + function endZooming(){ + zooming = false; + } + + var zx, zy; + function zoomTo(level){ + if( !zooming ){ // for non-continuous zooming (e.g. click slider at pt) + calculateZoomCenterPoint(); + } + + cyRef.zoom({ + level: level, + renderedPosition: { x: zx, y: zy } + }); + } + + var panInterval; + + var handler = function(e){ + e.stopPropagation(); // don't trigger dragging of panzoom + e.preventDefault(); // don't cause text selection + clearInterval(panInterval); + + var pan = handle2pan(e); + + if( isNaN(pan.x) || isNaN(pan.y) ){ + $pIndicator.hide(); + return; + } + + positionIndicator(pan); + panInterval = setInterval(function(){ + cyRef.panBy(pan); + }, options.panSpeed); + }; + + $pHandle.bind("mousedown", function(e){ + // handle click of icon + handler(e); + + // update on mousemove + windowBind("mousemove", handler); + }); + + $pHandle.bind("mouseup", function(){ + donePanning(); + }); + + windowBind("mouseup blur", function(){ + donePanning(); + }); + + + + // set up slider behaviour + ////////////////////////// + + $slider.bind('mousedown', function(){ + return false; // so we don't pan close to the slider handle + }); + + var sliderVal; + var sliding = false; + var sliderPadding = 2; + + function setSliderFromMouse(evt, handleOffset){ + if( handleOffset === undefined ){ + handleOffset = 0; + } + + var padding = sliderPadding; + var min = 0 + padding; + var max = $slider.height() - $sliderHandle.height() - 2*padding; + var top = evt.pageY - $slider.offset().top - handleOffset; + + // constrain to slider bounds + if( top < min ){ top = min } + if( top > max ){ top = max } + + var percent = 1 - (top - min) / ( max - min ); + + // move the handle + $sliderHandle.css('top', top); + + var zmin = options.minZoom; + var zmax = options.maxZoom; + + // assume (zoom = zmax ^ p) where p ranges on (x, 1) with x negative + var x = Math.log(zmin) / Math.log(zmax); + var p = (1 - x)*percent + x; + + // change the zoom level + var z = Math.pow( zmax, p ); + + // bound the zoom value in case of floating pt rounding error + if( z < zmin ){ + z = zmin; + } else if( z > zmax ){ + z = zmax; + } + + zoomTo( z ); + } + + var sliderMdownHandler, sliderMmoveHandler; + $sliderHandle.bind('mousedown', sliderMdownHandler = function( mdEvt ){ + var handleOffset = mdEvt.target === $sliderHandle[0] ? mdEvt.offsetY : 0; + sliding = true; + + startZooming(); + $sliderHandle.addClass("active"); + + var lastMove = 0; + windowBind('mousemove', sliderMmoveHandler = function( mmEvt ){ + var now = +new Date; + + // throttle the zooms every 10 ms so we don't call zoom too often and cause lag + if( now > lastMove + 10 ){ + lastMove = now; + } else { + return false; + } + + setSliderFromMouse(mmEvt, handleOffset); + + return false; + }); + + // unbind when + windowBind('mouseup', function(){ + windowUnbind('mousemove', sliderMmoveHandler); + sliding = false; + + $sliderHandle.removeClass("active"); + endZooming(); + }); + + return false; + }); + + $slider.bind('mousedown', function(e){ + if( e.target !== $sliderHandle[0] ){ + sliderMdownHandler(e); + setSliderFromMouse(e); + } + }); + + function positionSliderFromZoom(){ + var z = cyRef.zoom(); + var zmin = options.minZoom; + var zmax = options.maxZoom; + + // assume (zoom = zmax ^ p) where p ranges on (x, 1) with x negative + var x = Math.log(zmin) / Math.log(zmax); + var p = Math.log(z) / Math.log(zmax); + var percent = 1 - (p - x) / (1 - x); // the 1- bit at the front b/c up is in the -ve y direction + + var min = sliderPadding; + var max = $slider.height() - $sliderHandle.height() - 2*sliderPadding; + var top = percent * ( max - min ); + + // constrain to slider bounds + if( top < min ){ top = min } + if( top > max ){ top = max } + + // move the handle + $sliderHandle.css('top', top); + } + + positionSliderFromZoom(); + + cyOn('zoom', function(){ + if( !sliding ){ + positionSliderFromZoom(); + } + }); + + // set the position of the zoom=1 tick + (function(){ + var z = 1; + var zmin = options.minZoom; + var zmax = options.maxZoom; + + // assume (zoom = zmax ^ p) where p ranges on (x, 1) with x negative + var x = Math.log(zmin) / Math.log(zmax); + var p = Math.log(z) / Math.log(zmax); + var percent = 1 - (p - x) / (1 - x); // the 1- bit at the front b/c up is in the -ve y direction + + if( percent > 1 || percent < 0 ){ + $noZoomTick.hide(); + return; + } + + var min = sliderPadding; + var max = $slider.height() - $sliderHandle.height() - 2*sliderPadding; + var top = percent * ( max - min ); + + // constrain to slider bounds + if( top < min ){ top = min } + if( top > max ){ top = max } + + $noZoomTick.css('top', top); + })(); + + // set up zoom in/out buttons + ///////////////////////////// + + function bindButton($button, factor){ + var zoomInterval; + + $button.bind("mousedown", function(e){ + e.preventDefault(); + e.stopPropagation(); + + if( e.button != 0 ){ + return; + } + + var doZoom = function(){ + var zoom = cyRef.zoom(); + var lvl = cyRef.zoom() * factor; + + if( lvl < options.minZoom ){ + lvl = options.minZoom; + } + + if( lvl > options.maxZoom ){ + lvl = options.maxZoom; + } + + if( (lvl == options.maxZoom && zoom == options.maxZoom) || + (lvl == options.minZoom && zoom == options.minZoom) + ){ + return; + } + + zoomTo(lvl); + }; + + startZooming(); + doZoom(); + zoomInterval = setInterval(doZoom, options.zoomDelay); + + return false; + }); + + windowBind("mouseup blur", function(){ + clearInterval(zoomInterval); + endZooming(); + }); + } + + bindButton( $zoomIn, (1 + options.zoomFactor) ); + bindButton( $zoomOut, (1 - options.zoomFactor) ); + + $reset.bind("mousedown", function(e){ + if( e.button != 0 ){ + return; + } + + var elesToFit = options.fitSelector?cyRef.elements(options.fitSelector):cyRef.elements(); + + if( elesToFit.size() === 0 ){ + cyRef.reset(); + } else { + var animateOnFit = typeof options.animateOnFit === 'function' ? options.animateOnFit.call() : options.animateOnFit; + if(animateOnFit){ + cyRef.animate({ + fit: { + eles: elesToFit, + padding: options.fitPadding + } + }, { + duration: options.fitAnimationDuration + }); + } + else{ + cyRef.fit( elesToFit, options.fitPadding ); + } + + } + + return false; + }); + + + + }); + } + }; + + if( functions[fn] ){ + return functions[fn].apply(this, Array.prototype.slice.call( arguments, 1 )); + } else if( typeof fn == 'object' || !fn ) { + return functions.init.apply( this, arguments ); + } else { + $.error("No such function `"+ fn +"` for jquery.cytoscapePanzoom"); + } + + return $(this); + }; + + + if( typeof module !== 'undefined' && module.exports ){ // expose as a commonjs module + module.exports = function( cytoscape, jquery ){ + register( cytoscape, jquery || require('jquery') ); + } + } else if( typeof define !== 'undefined' && define.amd ){ // expose as an amd/requirejs module + define('cytoscape-panzoom', function(){ + return register; + }); + } + + if( typeof cytoscape !== 'undefined' && typeof jQuery !== 'undefined' ){ // expose to global cytoscape (i.e. window.cytoscape) + register( cytoscape, jQuery ); + } + +})(); diff --git a/web/js/cytoscape-qtip.js b/web/js/cytoscape-qtip.js new file mode 100644 index 000000000..6f1a01635 --- /dev/null +++ b/web/js/cytoscape-qtip.js @@ -0,0 +1,409 @@ +/*! +Copyright (c) The Cytoscape Consortium + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the “Software”), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +;(function( $, $$ ){ 'use strict'; + + var isObject = function(o){ + return o != null && typeof o === 'object'; + }; + + var isFunction = function(o){ + return o != null && typeof o === 'function'; + }; + + var isNumber = function(o){ + return o != null && typeof o === 'number'; + }; + + var isString = function(o){ + return o != null && typeof o === 'string'; + }; + + var isUndef = function(o){ + return o === undefined; + }; + + var wrap = function(obj, target) { + if( isFunction(obj) ) { + return function(event, api){ + return obj.apply( target, [event, api] ); + }; + } else { + return obj; + } + }; + + var throttle = function(func, wait, options) { + var leading = true, + trailing = true; + + if (options === false) { + leading = false; + } else if (isObject(options)) { + leading = 'leading' in options ? options.leading : leading; + trailing = 'trailing' in options ? options.trailing : trailing; + } + options = options || {}; + options.leading = leading; + options.maxWait = wait; + options.trailing = trailing; + + return debounce(func, wait, options); + }; + + var debounce = function(func, wait, options) { // ported lodash debounce function + var args, + maxTimeoutId, + result, + stamp, + thisArg, + timeoutId, + trailingCall, + lastCalled = 0, + maxWait = false, + trailing = true; + + if (!isFunction(func)) { + return; + } + wait = Math.max(0, wait) || 0; + if (options === true) { + var leading = true; + trailing = false; + } else if (isObject(options)) { + leading = options.leading; + maxWait = 'maxWait' in options && (Math.max(wait, options.maxWait) || 0); + trailing = 'trailing' in options ? options.trailing : trailing; + } + var delayed = function() { + var remaining = wait - (Date.now() - stamp); + if (remaining <= 0) { + if (maxTimeoutId) { + clearTimeout(maxTimeoutId); + } + var isCalled = trailingCall; + maxTimeoutId = timeoutId = trailingCall = undefined; + if (isCalled) { + lastCalled = Date.now(); + result = func.apply(thisArg, args); + if (!timeoutId && !maxTimeoutId) { + args = thisArg = null; + } + } + } else { + timeoutId = setTimeout(delayed, remaining); + } + }; + + var maxDelayed = function() { + if (timeoutId) { + clearTimeout(timeoutId); + } + maxTimeoutId = timeoutId = trailingCall = undefined; + if (trailing || (maxWait !== wait)) { + lastCalled = Date.now(); + result = func.apply(thisArg, args); + if (!timeoutId && !maxTimeoutId) { + args = thisArg = null; + } + } + }; + + return function() { + args = arguments; + stamp = Date.now(); + thisArg = this; + trailingCall = trailing && (timeoutId || !leading); + + if (maxWait === false) { + var leadingCall = leading && !timeoutId; + } else { + if (!maxTimeoutId && !leading) { + lastCalled = stamp; + } + var remaining = maxWait - (stamp - lastCalled), + isCalled = remaining <= 0; + + if (isCalled) { + if (maxTimeoutId) { + maxTimeoutId = clearTimeout(maxTimeoutId); + } + lastCalled = stamp; + result = func.apply(thisArg, args); + } + else if (!maxTimeoutId) { + maxTimeoutId = setTimeout(maxDelayed, remaining); + } + } + if (isCalled && timeoutId) { + timeoutId = clearTimeout(timeoutId); + } + else if (!timeoutId && wait !== maxWait) { + timeoutId = setTimeout(delayed, wait); + } + if (leadingCall) { + isCalled = true; + result = func.apply(thisArg, args); + } + if (isCalled && !timeoutId && !maxTimeoutId) { + args = thisArg = null; + } + return result; + }; + }; + + function register( $$, $ ){ + + // use a single dummy dom ele as target for every qtip + var $qtipContainer = $('
'); + var viewportDebounceRate = 250; + + $qtipContainer.css({ + 'z-index': -1, + 'position': 'absolute' + }); + + function generateOpts( target, passedOpts ){ + var qtip = target.scratch().qtip; + var opts = $.extend( {}, passedOpts ); + + if( !opts.id ){ + opts.id = 'cy-qtip-target-' + ( Date.now() + Math.round( Math.random() * 10000) ); + } + + if( !qtip.$domEle ){ + qtip.$domEle = $qtipContainer; + } + + // qtip should be positioned relative to cy dom container + opts.position = opts.position || {}; + opts.position.container = opts.position.container || $( document.body ); + opts.position.viewport = opts.position.viewport || $( document.body ); + opts.position.target = [0, 0]; + opts.position.my = opts.position.my || 'top center'; + opts.position.at = opts.position.at || 'bottom center'; + + // adjust + var adjust = opts.position.adjust = opts.position.adjust || {}; + adjust.method = adjust.method || 'flip'; + adjust.mouse = false; + + // default show event + opts.show = opts.show || {}; + + if( isUndef(opts.show.event) ){ + opts.show.event = 'tap'; + } + + // default hide event + opts.hide = opts.hide || {}; + opts.hide.cyViewport = opts.hide.cyViewport === undefined ? true : opts.hide.cyViewport; + + if( isUndef(opts.hide.event) ){ + opts.hide.event = 'unfocus'; + } + + // so multiple qtips can exist at once (only works on recent qtip2 versions) + opts.overwrite = false; + + if( opts.content ){ + if ( isFunction(opts.content) || isString(opts.content) ){ + opts.content = wrap( opts.content, target ); + } else { + opts.content = { + text: wrap( opts.content.text, target ), + title: wrap( opts.content.title, target ) + }; + } + } + + return opts; + } + + function updatePosition(ele, qtip, evt){ + var e = evt; + var isCy = isFunction( ele.pan ); + var isEle = !isCy; + var isNode = isEle && ele.isNode(); + var cy = isCy ? ele : ele.cy(); + var cOff = cy.container().getBoundingClientRect(); + var pos = isNode ? ele.renderedPosition() : ( e ? e.renderedPosition || e.cyRenderedPosition : undefined ); + if( !pos || pos.x == null || isNaN(pos.x) ){ return; } + + var bb = isNode ? ele.renderedBoundingBox({ + includeNodes: true, + includeEdges: false, + includeLabels: false, + includeShadows: false + }) : { + x1: pos.x - 1, + x2: pos.x + 1, + w: 3, + y1: pos.y - 1, + y2: pos.y + 1, + h: 3 + }; + + if( qtip.$domEle.parent().length === 0 ){ + qtip.$domEle.appendTo(document.body); + } + + qtip.$domEle.css({ + 'width': bb.w, + 'height': bb.h, + 'top': bb.y1 + cOff.top + window.pageYOffset, + 'left': bb.x1 + cOff.left + window.pageXOffset, + 'position': 'absolute', + 'pointer-events': 'none', + 'background': 'red', + 'z-index': 99999999, + 'opacity': 0.5, + 'visibility': 'hidden' + }); + + qtip.api.set('position.target', qtip.$domEle); + } + + $$('collection', 'qtip', function( passedOpts ){ + var eles = this; + var cy = this.cy(); + var container = cy.container(); + + if( passedOpts === 'api' ){ + return this.scratch().qtip.api; + } + + eles.each(function(ele, i){ + // Perform 2.x and 1.x backwards compatibility check + if(isNumber(ele)){ + ele = i; + } + var scratch = ele.scratch(); + var qtip = scratch.qtip = scratch.qtip || {}; + var opts = generateOpts( ele, passedOpts ); + var adjNums = opts.position.adjust; + + qtip.$domEle.qtip( opts ); + var qtipApi = qtip.api = qtip.$domEle.qtip('api'); // save api ref + qtip.$domEle.removeData('qtip'); // remove qtip dom/api ref to be safe + + updatePosition(ele, qtip); + + ele.on( opts.show.event, function(e){ + updatePosition(ele, qtip, e); + qtipApi.show(); + } ); + + ele.on( opts.hide.event, function(e){ + qtipApi.hide(); + } ); + + if( opts.hide.cyViewport ){ + cy.on('viewport', debounce(function(){ + qtipApi.hide(); + }, viewportDebounceRate, { leading: true }) ); + } + + if( opts.position.adjust.cyViewport ){ + cy.on('pan zoom', debounce(function(e){ + updatePosition(ele, qtip, e); + + qtipApi.reposition(); + }, viewportDebounceRate, { trailing: true }) ); + } + + }); + + return this; // chainability + + }); + + $$('core', 'qtip', function( passedOpts ){ + var cy = this; + var container = cy.container(); + + if( passedOpts === 'api' ){ + return this.scratch().qtip.api; + } + + var scratch = cy.scratch(); + var qtip = scratch.qtip = scratch.qtip || {}; + var opts = generateOpts( cy, passedOpts ); + + + qtip.$domEle.qtip( opts ); + var qtipApi = qtip.api = qtip.$domEle.qtip('api'); // save api ref + qtip.$domEle.removeData('qtip'); // remove qtip dom/api ref to be safe + + cy.on( opts.show.event, function(e){ + if( !opts.show.cyBgOnly || (opts.show.cyBgOnly && (e.target === cy || e.cyTarget === cy)) ){ + updatePosition(cy, qtip, e); + + qtipApi.show(); + } + } ); + + cy.on( opts.hide.event, function(e){ + if( !opts.hide.cyBgOnly || (opts.hide.cyBgOnly && (e.target === cy || e.cyTarget === cy)) ){ + qtipApi.hide(); + } + } ); + + if( opts.hide.cyViewport ){ + cy.on('viewport', debounce(function(){ + qtipApi.hide(); + }, viewportDebounceRate, { leading: true }) ); + } + + return this; // chainability + + }); + + } + + if( typeof module !== 'undefined' && module.exports ){ // expose as a commonjs module + module.exports = function( cytoscape ){ + var oldJq = window.jQuery; + var old$ = window.$; + + var jQuery = window.jQuery = window.$ = require('jquery'); // qtip requires global jquery + var qtip = require('qtip2'); + + register( cytoscape, jQuery ); + + window.jQuery = oldJq; + window.$ = old$; + }; + } else if( typeof define !== 'undefined' && define.amd ){ // expose as an amd/requirejs module + define('cytoscape-qtip', function(){ + return register; + }); + } + + if( $ && $$ ){ + register( $$, $ ); + } + +})( + typeof jQuery !== 'undefined' ? jQuery : null, + typeof cytoscape !== 'undefined' ? cytoscape : null +); diff --git a/web/js/cytoscape-undo-redo.js b/web/js/cytoscape-undo-redo.js new file mode 100644 index 000000000..d9506edf1 --- /dev/null +++ b/web/js/cytoscape-undo-redo.js @@ -0,0 +1,570 @@ +;(function () { + 'use strict'; + +// registers the extension on a cytoscape lib ref + var register = function (cytoscape) { + + if (!cytoscape) { + return; + } // can't register if cytoscape unspecified + + var cy; + var actions = {}; + var undoStack = []; + var redoStack = []; + + var _instance = { + options: { + isDebug: false, // Debug mode for console messages + actions: {},// actions to be added + undoableDrag: true, // Whether dragging nodes are undoable can be a function as well + stackSizeLimit: undefined, // Size limit of undo stack, note that the size of redo stack cannot exceed size of undo stack + beforeUndo: function () { // callback before undo is triggered. + + }, + afterUndo: function () { // callback after undo is triggered. + + }, + beforeRedo: function () { // callback before redo is triggered. + + }, + afterRedo: function () { // callback after redo is triggered. + + }, + ready: function () { + + } + } + }; + + + // design implementation + cytoscape("core", "undoRedo", function (options, dontInit) { + cy = this; + + + + function getScratch() { + if (!cy.scratch("_undoRedo")) { + cy.scratch("_undoRedo", { }); + + } + return cy.scratch("_undoRedo"); + } + + if (options) { + for (var key in options) + if (_instance.options.hasOwnProperty(key)) + _instance.options[key] = options[key]; + + if (options.actions) + for (var key in options.actions) + actions[key] = options.actions[key]; + + + } + + if (!getScratch().isInitialized && !dontInit) { + + var defActions = defaultActions(); + for (var key in defActions) + actions[key] = defActions[key]; + + + setDragUndo(_instance.options.undoableDrag); + getScratch().isInitialized = true; + } + + _instance.options.ready(); + return _instance; + + }); + + //resets undo and redo stacks + _instance.reset = function() + { + undoStack = []; + redoStack = []; + } + + // Undo last action + _instance.undo = function () { + if (!this.isUndoStackEmpty()) { + + var action = undoStack.pop(); + cy.trigger("beforeUndo", [action.name, action.args]); + + var res = actions[action.name]._undo(action.args); + + redoStack.push({ + name: action.name, + args: res + }); + + cy.trigger("afterUndo", [action.name, action.args, res]); + return res; + } else if (_instance.options.isDebug) { + console.log("Undoing cannot be done because undo stack is empty!"); + } + }; + + // Redo last action + _instance.redo = function () { + + if (!this.isRedoStackEmpty()) { + var action = redoStack.pop(); + + cy.trigger(action.firstTime ? "beforeDo" : "beforeRedo", [action.name, action.args]); + + if (!action.args) + action.args = {}; + action.args.firstTime = action.firstTime ? true : false; + + var res = actions[action.name]._do(action.args); + + undoStack.push({ + name: action.name, + args: res + }); + + if (_instance.options.stackSizeLimit != undefined && undoStack.length > _instance.options.stackSizeLimit ) { + undoStack.shift(); + } + + cy.trigger(action.firstTime ? "afterDo" : "afterRedo", [action.name, action.args, res]); + return res; + } else if (_instance.options.isDebug) { + console.log("Redoing cannot be done because redo stack is empty!"); + } + + }; + + // Calls registered function with action name actionName via actionFunction(args) + _instance.do = function (actionName, args) { + + redoStack = []; + redoStack.push({ + name: actionName, + args: args, + firstTime: true + }); + + return this.redo(); + }; + + // Undo all actions in undo stack + _instance.undoAll = function() { + + while( !this.isUndoStackEmpty() ) { + this.undo(); + } + }; + + // Redo all actions in redo stack + _instance.redoAll = function() { + + while( !this.isRedoStackEmpty() ) { + this.redo(); + } + }; + + // Register action with its undo function & action name. + _instance.action = function (actionName, _do, _undo) { + + actions[actionName] = { + _do: _do, + _undo: _undo + }; + + + return _instance; + }; + + // Removes action stated with actionName param + _instance.removeAction = function (actionName) { + delete actions[actionName]; + }; + + // Gets whether undo stack is empty + _instance.isUndoStackEmpty = function () { + return (undoStack.length === 0); + }; + + // Gets whether redo stack is empty + _instance.isRedoStackEmpty = function () { + return (redoStack.length === 0); + }; + + // Gets actions (with their args) in undo stack + _instance.getUndoStack = function () { + return undoStack; + }; + + // Gets actions (with their args) in redo stack + _instance.getRedoStack = function () { + return redoStack; + }; + + + var lastMouseDownNodeInfo = null; + var isDragDropSet = false; + + function setDragUndo(undoable) { + isDragDropSet = true; + cy.on("grab", "node", function () { + if (typeof undoable === 'function' ? undoable.call(this) : undoable) { + lastMouseDownNodeInfo = {}; + lastMouseDownNodeInfo.lastMouseDownPosition = { + x: this.position("x"), + y: this.position("y") + }; + lastMouseDownNodeInfo.node = this; + } + }); + cy.on("free", "node", function () { + if (typeof undoable === 'function' ? undoable.call(this) : undoable) { + if (lastMouseDownNodeInfo == null) { + return; + } + var node = lastMouseDownNodeInfo.node; + var lastMouseDownPosition = lastMouseDownNodeInfo.lastMouseDownPosition; + var mouseUpPosition = { + x: node.position("x"), + y: node.position("y") + }; + if (mouseUpPosition.x != lastMouseDownPosition.x || + mouseUpPosition.y != lastMouseDownPosition.y) { + var positionDiff = { + x: mouseUpPosition.x - lastMouseDownPosition.x, + y: mouseUpPosition.y - lastMouseDownPosition.y + }; + + var nodes; + if (node.selected()) { + nodes = cy.nodes(":visible").filter(":selected"); + } + else { + nodes = cy.collection([node]); + } + + var param = { + positionDiff: positionDiff, + nodes: nodes, move: false + }; + _instance.do("drag", param); + + lastMouseDownNodeInfo = null; + } + } + }); + } + + function getTopMostNodes(nodes) { + var nodesMap = {}; + for (var i = 0; i < nodes.length; i++) { + nodesMap[nodes[i].id()] = true; + } + var roots = nodes.filter(function (ele, i) { + if(typeof ele === "number") { + ele = i; + } + var parent = ele.parent()[0]; + while(parent != null){ + if(nodesMap[parent.id()]){ + return false; + } + parent = parent.parent()[0]; + } + return true; + }); + + return roots; + } + + function moveNodes(positionDiff, nodes, notCalcTopMostNodes) { + var topMostNodes = notCalcTopMostNodes?nodes:getTopMostNodes(nodes); + for (var i = 0; i < topMostNodes.length; i++) { + var node = topMostNodes[i]; + var oldX = node.position("x"); + var oldY = node.position("y"); + node.position({ + x: oldX + positionDiff.x, + y: oldY + positionDiff.y + }); + var children = node.children(); + moveNodes(positionDiff, children, true); + } + } + + function getEles(_eles) { + return (typeof _eles === "string") ? cy.$(_eles) : _eles; + } + + function restoreEles(_eles) { + return getEles(_eles).restore(); + } + + + function returnToPositions(positions) { + var currentPositions = {}; + cy.nodes().positions(function (ele, i) { + if(typeof ele === "number") { + ele = i; + } + + currentPositions[ele.id()] = { + x: ele.position("x"), + y: ele.position("y") + }; + var pos = positions[ele.id()]; + return { + x: pos.x, + y: pos.y + }; + }); + + return currentPositions; + } + + function getNodePositions() { + var positions = {}; + var nodes = cy.nodes(); + for (var i = 0; i < nodes.length; i++) { + var node = nodes[i]; + positions[node.id()] = { + x: node.position("x"), + y: node.position("y") + }; + } + return positions; + } + + function changeParent(param) { + var result = { + }; + // If this is first time we should move the node to its new parent and relocate it by given posDiff params + // else we should remove the moved eles and restore the eles to restore + if (param.firstTime) { + var newParentId = param.parentData == undefined ? null : param.parentData; + // These eles includes the nodes and their connected edges and will be removed in nodes.move(). + // They should be restored in undo + var withDescendant = param.nodes.union(param.nodes.descendants()); + result.elesToRestore = withDescendant.union(withDescendant.connectedEdges()); + // These are the eles created by nodes.move(), they should be removed in undo. + result.movedEles = param.nodes.move({"parent": newParentId}); + + var posDiff = { + x: param.posDiffX, + y: param.posDiffY + }; + + moveNodes(posDiff, result.movedEles); + } + else { + result.elesToRestore = param.movedEles.remove(); + result.movedEles = param.elesToRestore.restore(); + } + + if (param.callback) { + result.callback = param.callback; // keep the provided callback so it can be reused after undo/redo + param.callback(result.movedEles); // apply the callback on newly created elements + } + + return result; + } + + // function registered in the defaultActions below + // to be used like .do('batch', actionList) + // allows to apply any quantity of registered action in one go + // the whole batch can be undone/redone with one key press + function batch (actionList, doOrUndo) { + var tempStack = []; // corresponds to the results of every action queued in actionList + + // here we need to check in advance if all the actions provided really correspond to available functions + // if one of the action cannot be executed, the whole batch is corrupted because we can't go back after + for (var i = 0; i < actionList.length; i++) { + var action = actionList[i]; + if (!actions.hasOwnProperty(action.name)) { + throw "Action " + action.name + " does not exist as an undoable function"; + } + } + + for (var i = 0; i < actionList.length; i++) { + var action = actionList[i]; + // firstTime property is automatically injected into actionList by the do() function + // we use that to pass it down to the actions in the batch + action.param.firstTime = actionList.firstTime; + var actionResult; + if (doOrUndo == "undo") { + actionResult = actions[action.name]._undo(action.param); + } + else { + actionResult = actions[action.name]._do(action.param); + } + + tempStack.unshift({ + name: action.name, + param: actionResult + }); + } + + return tempStack; + }; + + // Default actions + function defaultActions() { + return { + "add": { + _do: function (eles) { + return eles.firstTime ? cy.add(eles) : restoreEles(eles); + }, + _undo: cy.remove + }, + "remove": { + _do: cy.remove, + _undo: restoreEles + }, + "restore": { + _do: restoreEles, + _undo: cy.remove + }, + "select": { + _do: function (_eles) { + return getEles(_eles).select(); + }, + _undo: function (_eles) { + return getEles(_eles).unselect(); + } + }, + "unselect": { + _do: function (_eles) { + return getEles(_eles).unselect(); + }, + _undo: function (_eles) { + return getEles(_eles).select(); + } + }, + "move": { + _do: function (args) { + var eles = getEles(args.eles); + var nodes = eles.nodes(); + var edges = eles.edges(); + + return { + oldNodes: nodes, + newNodes: nodes.move(args.location), + oldEdges: edges, + newEdges: edges.move(args.location) + }; + }, + _undo: function (eles) { + var newEles = cy.collection(); + var location = {}; + if (eles.newNodes.length > 0) { + location.parent = eles.newNodes[0].parent(); + + for (var i = 0; i < eles.newNodes.length; i++) { + var newNode = eles.newNodes[i].move({ + parent: eles.oldNodes[i].parent() + }); + newEles.union(newNode); + } + } else { + location.source = location.newEdges[0].source(); + location.target = location.newEdges[0].target(); + + for (var i = 0; i < eles.newEdges.length; i++) { + var newEdge = eles.newEdges[i].move({ + source: eles.oldEdges[i].source(), + target: eles.oldEdges[i].target() + }); + newEles.union(newEdge); + } + } + return { + eles: newEles, + location: location + }; + } + }, + "drag": { + _do: function (args) { + if (args.move) + moveNodes(args.positionDiff, args.nodes); + return args; + }, + _undo: function (args) { + var diff = { + x: -1 * args.positionDiff.x, + y: -1 * args.positionDiff.y + }; + var result = { + positionDiff: args.positionDiff, + nodes: args.nodes, + move: true + }; + moveNodes(diff, args.nodes); + return result; + } + }, + "layout": { + _do: function (args) { + if (args.firstTime){ + var positions = getNodePositions(); + var layout; + if(args.eles) { + layout = getEles(args.eles).layout(args.options); + } + else { + layout = cy.layout(args.options); + } + + // Do this check for cytoscape.js backward compatibility + if (layout && layout.run) { + layout.run(); + } + + return positions; + } else + return returnToPositions(args); + }, + _undo: function (nodesData) { + return returnToPositions(nodesData); + } + }, + "changeParent": { + _do: function (args) { + return changeParent(args); + }, + _undo: function (args) { + return changeParent(args); + } + }, + "batch": { + _do: function (args) { + return batch(args, "do"); + }, + _undo: function (args) { + return batch(args, "undo"); + } + } + }; + } + + }; + + if (typeof module !== 'undefined' && module.exports) { // expose as a commonjs module + module.exports = register; + } + + if (typeof define !== 'undefined' && define.amd) { // expose as an amd/requirejs module + define('cytoscape.js-undo-redo', function () { + return register; + }); + } + + if (typeof cytoscape !== 'undefined') { // expose to global cytoscape (i.e. window.cytoscape) + register(cytoscape); + } + +})(); diff --git a/web/js/cytoscape-view-utilities.js b/web/js/cytoscape-view-utilities.js new file mode 100644 index 000000000..0ad04fc06 --- /dev/null +++ b/web/js/cytoscape-view-utilities.js @@ -0,0 +1,1405 @@ +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.cytoscapeViewUtilities = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o': '.', + '?': '/', + '|': '\\' + }; + + /** + * this is a list of special strings you can use to map + * to modifier keys when you specify your keyboard shortcuts + * + * @type {Object} + */ + var _SPECIAL_ALIASES = { + 'option': 'alt', + 'command': 'meta', + 'return': 'enter', + 'escape': 'esc', + 'plus': '+', + 'mod': /Mac|iPod|iPhone|iPad/.test(navigator.platform) ? 'meta' : 'ctrl' + }; + + /** + * variable to store the flipped version of _MAP from above + * needed to check if we should use keypress or not when no action + * is specified + * + * @type {Object|undefined} + */ + var _REVERSE_MAP; + + /** + * loop through the f keys, f1 to f19 and add them to the map + * programatically + */ + for (var i = 1; i < 20; ++i) { + _MAP[111 + i] = 'f' + i; + } + + /** + * loop through to map numbers on the numeric keypad + */ + for (i = 0; i <= 9; ++i) { + + // This needs to use a string cause otherwise since 0 is falsey + // mousetrap will never fire for numpad 0 pressed as part of a keydown + // event. + // + // @see https://github.com/ccampbell/mousetrap/pull/258 + _MAP[i + 96] = i.toString(); + } + + /** + * cross browser add event method + * + * @param {Element|HTMLDocument} object + * @param {string} type + * @param {Function} callback + * @returns void + */ + function _addEvent(object, type, callback) { + if (object.addEventListener) { + object.addEventListener(type, callback, false); + return; + } + + object.attachEvent('on' + type, callback); + } + + /** + * takes the event and returns the key character + * + * @param {Event} e + * @return {string} + */ + function _characterFromEvent(e) { + + // for keypress events we should return the character as is + if (e.type == 'keypress') { + var character = String.fromCharCode(e.which); + + // if the shift key is not pressed then it is safe to assume + // that we want the character to be lowercase. this means if + // you accidentally have caps lock on then your key bindings + // will continue to work + // + // the only side effect that might not be desired is if you + // bind something like 'A' cause you want to trigger an + // event when capital A is pressed caps lock will no longer + // trigger the event. shift+a will though. + if (!e.shiftKey) { + character = character.toLowerCase(); + } + + return character; + } + + // for non keypress events the special maps are needed + if (_MAP[e.which]) { + return _MAP[e.which]; + } + + if (_KEYCODE_MAP[e.which]) { + return _KEYCODE_MAP[e.which]; + } + + // if it is not in the special map + + // with keydown and keyup events the character seems to always + // come in as an uppercase character whether you are pressing shift + // or not. we should make sure it is always lowercase for comparisons + return String.fromCharCode(e.which).toLowerCase(); + } + + /** + * checks if two arrays are equal + * + * @param {Array} modifiers1 + * @param {Array} modifiers2 + * @returns {boolean} + */ + function _modifiersMatch(modifiers1, modifiers2) { + return modifiers1.sort().join(',') === modifiers2.sort().join(','); + } + + /** + * takes a key event and figures out what the modifiers are + * + * @param {Event} e + * @returns {Array} + */ + function _eventModifiers(e) { + var modifiers = []; + + if (e.shiftKey) { + modifiers.push('shift'); + } + + if (e.altKey) { + modifiers.push('alt'); + } + + if (e.ctrlKey) { + modifiers.push('ctrl'); + } + + if (e.metaKey) { + modifiers.push('meta'); + } + + return modifiers; + } + + /** + * prevents default for this event + * + * @param {Event} e + * @returns void + */ + function _preventDefault(e) { + if (e.preventDefault) { + e.preventDefault(); + return; + } + + e.returnValue = false; + } + + /** + * stops propogation for this event + * + * @param {Event} e + * @returns void + */ + function _stopPropagation(e) { + if (e.stopPropagation) { + e.stopPropagation(); + return; + } + + e.cancelBubble = true; + } + + /** + * determines if the keycode specified is a modifier key or not + * + * @param {string} key + * @returns {boolean} + */ + function _isModifier(key) { + return key == 'shift' || key == 'ctrl' || key == 'alt' || key == 'meta'; + } + + /** + * reverses the map lookup so that we can look for specific keys + * to see what can and can't use keypress + * + * @return {Object} + */ + function _getReverseMap() { + if (!_REVERSE_MAP) { + _REVERSE_MAP = {}; + for (var key in _MAP) { + + // pull out the numeric keypad from here cause keypress should + // be able to detect the keys from the character + if (key > 95 && key < 112) { + continue; + } + + if (_MAP.hasOwnProperty(key)) { + _REVERSE_MAP[_MAP[key]] = key; + } + } + } + return _REVERSE_MAP; + } + + /** + * picks the best action based on the key combination + * + * @param {string} key - character for key + * @param {Array} modifiers + * @param {string=} action passed in + */ + function _pickBestAction(key, modifiers, action) { + + // if no action was picked in we should try to pick the one + // that we think would work best for this key + if (!action) { + action = _getReverseMap()[key] ? 'keydown' : 'keypress'; + } + + // modifier keys don't work as expected with keypress, + // switch to keydown + if (action == 'keypress' && modifiers.length) { + action = 'keydown'; + } + + return action; + } + + /** + * Converts from a string key combination to an array + * + * @param {string} combination like "command+shift+l" + * @return {Array} + */ + function _keysFromString(combination) { + if (combination === '+') { + return ['+']; + } + + combination = combination.replace(/\+{2}/g, '+plus'); + return combination.split('+'); + } + + /** + * Gets info for a specific key combination + * + * @param {string} combination key combination ("command+s" or "a" or "*") + * @param {string=} action + * @returns {Object} + */ + function _getKeyInfo(combination, action) { + var keys; + var key; + var i; + var modifiers = []; + + // take the keys from this pattern and figure out what the actual + // pattern is all about + keys = _keysFromString(combination); + + for (i = 0; i < keys.length; ++i) { + key = keys[i]; + + // normalize key names + if (_SPECIAL_ALIASES[key]) { + key = _SPECIAL_ALIASES[key]; + } + + // if this is not a keypress event then we should + // be smart about using shift keys + // this will only work for US keyboards however + if (action && action != 'keypress' && _SHIFT_MAP[key]) { + key = _SHIFT_MAP[key]; + modifiers.push('shift'); + } + + // if this key is a modifier then add it to the list of modifiers + if (_isModifier(key)) { + modifiers.push(key); + } + } + + // depending on what the key combination is + // we will try to pick the best event for it + action = _pickBestAction(key, modifiers, action); + + return { + key: key, + modifiers: modifiers, + action: action + }; + } + + function _belongsTo(element, ancestor) { + if (element === null || element === document) { + return false; + } + + if (element === ancestor) { + return true; + } + + return _belongsTo(element.parentNode, ancestor); + } + + function Mousetrap(targetElement) { + var self = this; + + targetElement = targetElement || document; + + if (!(self instanceof Mousetrap)) { + return new Mousetrap(targetElement); + } + + /** + * element to attach key events to + * + * @type {Element} + */ + self.target = targetElement; + + /** + * a list of all the callbacks setup via Mousetrap.bind() + * + * @type {Object} + */ + self._callbacks = {}; + + /** + * direct map of string combinations to callbacks used for trigger() + * + * @type {Object} + */ + self._directMap = {}; + + /** + * keeps track of what level each sequence is at since multiple + * sequences can start out with the same sequence + * + * @type {Object} + */ + var _sequenceLevels = {}; + + /** + * variable to store the setTimeout call + * + * @type {null|number} + */ + var _resetTimer; + + /** + * temporary state where we will ignore the next keyup + * + * @type {boolean|string} + */ + var _ignoreNextKeyup = false; + + /** + * temporary state where we will ignore the next keypress + * + * @type {boolean} + */ + var _ignoreNextKeypress = false; + + /** + * are we currently inside of a sequence? + * type of action ("keyup" or "keydown" or "keypress") or false + * + * @type {boolean|string} + */ + var _nextExpectedAction = false; + + /** + * resets all sequence counters except for the ones passed in + * + * @param {Object} doNotReset + * @returns void + */ + function _resetSequences(doNotReset) { + doNotReset = doNotReset || {}; + + var activeSequences = false, + key; + + for (key in _sequenceLevels) { + if (doNotReset[key]) { + activeSequences = true; + continue; + } + _sequenceLevels[key] = 0; + } + + if (!activeSequences) { + _nextExpectedAction = false; + } + } + + /** + * finds all callbacks that match based on the keycode, modifiers, + * and action + * + * @param {string} character + * @param {Array} modifiers + * @param {Event|Object} e + * @param {string=} sequenceName - name of the sequence we are looking for + * @param {string=} combination + * @param {number=} level + * @returns {Array} + */ + function _getMatches(character, modifiers, e, sequenceName, combination, level) { + var i; + var callback; + var matches = []; + var action = e.type; + + // if there are no events related to this keycode + if (!self._callbacks[character]) { + return []; + } + + // if a modifier key is coming up on its own we should allow it + if (action == 'keyup' && _isModifier(character)) { + modifiers = [character]; + } + + // loop through all callbacks for the key that was pressed + // and see if any of them match + for (i = 0; i < self._callbacks[character].length; ++i) { + callback = self._callbacks[character][i]; + + // if a sequence name is not specified, but this is a sequence at + // the wrong level then move onto the next match + if (!sequenceName && callback.seq && _sequenceLevels[callback.seq] != callback.level) { + continue; + } + + // if the action we are looking for doesn't match the action we got + // then we should keep going + if (action != callback.action) { + continue; + } + + // if this is a keypress event and the meta key and control key + // are not pressed that means that we need to only look at the + // character, otherwise check the modifiers as well + // + // chrome will not fire a keypress if meta or control is down + // safari will fire a keypress if meta or meta+shift is down + // firefox will fire a keypress if meta or control is down + if ((action == 'keypress' && !e.metaKey && !e.ctrlKey) || _modifiersMatch(modifiers, callback.modifiers)) { + + // when you bind a combination or sequence a second time it + // should overwrite the first one. if a sequenceName or + // combination is specified in this call it does just that + // + // @todo make deleting its own method? + var deleteCombo = !sequenceName && callback.combo == combination; + var deleteSequence = sequenceName && callback.seq == sequenceName && callback.level == level; + if (deleteCombo || deleteSequence) { + self._callbacks[character].splice(i, 1); + } + + matches.push(callback); + } + } + + return matches; + } + + /** + * actually calls the callback function + * + * if your callback function returns false this will use the jquery + * convention - prevent default and stop propogation on the event + * + * @param {Function} callback + * @param {Event} e + * @returns void + */ + function _fireCallback(callback, e, combo, sequence) { + + // if this event should not happen stop here + if (self.stopCallback(e, e.target || e.srcElement, combo, sequence)) { + return; + } + + if (callback(e, combo) === false) { + _preventDefault(e); + _stopPropagation(e); + } + } + + /** + * handles a character key event + * + * @param {string} character + * @param {Array} modifiers + * @param {Event} e + * @returns void + */ + self._handleKey = function(character, modifiers, e) { + var callbacks = _getMatches(character, modifiers, e); + var i; + var doNotReset = {}; + var maxLevel = 0; + var processedSequenceCallback = false; + + // Calculate the maxLevel for sequences so we can only execute the longest callback sequence + for (i = 0; i < callbacks.length; ++i) { + if (callbacks[i].seq) { + maxLevel = Math.max(maxLevel, callbacks[i].level); + } + } + + // loop through matching callbacks for this key event + for (i = 0; i < callbacks.length; ++i) { + + // fire for all sequence callbacks + // this is because if for example you have multiple sequences + // bound such as "g i" and "g t" they both need to fire the + // callback for matching g cause otherwise you can only ever + // match the first one + if (callbacks[i].seq) { + + // only fire callbacks for the maxLevel to prevent + // subsequences from also firing + // + // for example 'a option b' should not cause 'option b' to fire + // even though 'option b' is part of the other sequence + // + // any sequences that do not match here will be discarded + // below by the _resetSequences call + if (callbacks[i].level != maxLevel) { + continue; + } + + processedSequenceCallback = true; + + // keep a list of which sequences were matches for later + doNotReset[callbacks[i].seq] = 1; + _fireCallback(callbacks[i].callback, e, callbacks[i].combo, callbacks[i].seq); + continue; + } + + // if there were no sequence matches but we are still here + // that means this is a regular match so we should fire that + if (!processedSequenceCallback) { + _fireCallback(callbacks[i].callback, e, callbacks[i].combo); + } + } + + // if the key you pressed matches the type of sequence without + // being a modifier (ie "keyup" or "keypress") then we should + // reset all sequences that were not matched by this event + // + // this is so, for example, if you have the sequence "h a t" and you + // type "h e a r t" it does not match. in this case the "e" will + // cause the sequence to reset + // + // modifier keys are ignored because you can have a sequence + // that contains modifiers such as "enter ctrl+space" and in most + // cases the modifier key will be pressed before the next key + // + // also if you have a sequence such as "ctrl+b a" then pressing the + // "b" key will trigger a "keypress" and a "keydown" + // + // the "keydown" is expected when there is a modifier, but the + // "keypress" ends up matching the _nextExpectedAction since it occurs + // after and that causes the sequence to reset + // + // we ignore keypresses in a sequence that directly follow a keydown + // for the same character + var ignoreThisKeypress = e.type == 'keypress' && _ignoreNextKeypress; + if (e.type == _nextExpectedAction && !_isModifier(character) && !ignoreThisKeypress) { + _resetSequences(doNotReset); + } + + _ignoreNextKeypress = processedSequenceCallback && e.type == 'keydown'; + }; + + /** + * handles a keydown event + * + * @param {Event} e + * @returns void + */ + function _handleKeyEvent(e) { + + // normalize e.which for key events + // @see http://stackoverflow.com/questions/4285627/javascript-keycode-vs-charcode-utter-confusion + if (typeof e.which !== 'number') { + e.which = e.keyCode; + } + + var character = _characterFromEvent(e); + + // no character found then stop + if (!character) { + return; + } + + // need to use === for the character check because the character can be 0 + if (e.type == 'keyup' && _ignoreNextKeyup === character) { + _ignoreNextKeyup = false; + return; + } + + self.handleKey(character, _eventModifiers(e), e); + } + + /** + * called to set a 1 second timeout on the specified sequence + * + * this is so after each key press in the sequence you have 1 second + * to press the next key before you have to start over + * + * @returns void + */ + function _resetSequenceTimer() { + clearTimeout(_resetTimer); + _resetTimer = setTimeout(_resetSequences, 1000); + } + + /** + * binds a key sequence to an event + * + * @param {string} combo - combo specified in bind call + * @param {Array} keys + * @param {Function} callback + * @param {string=} action + * @returns void + */ + function _bindSequence(combo, keys, callback, action) { + + // start off by adding a sequence level record for this combination + // and setting the level to 0 + _sequenceLevels[combo] = 0; + + /** + * callback to increase the sequence level for this sequence and reset + * all other sequences that were active + * + * @param {string} nextAction + * @returns {Function} + */ + function _increaseSequence(nextAction) { + return function() { + _nextExpectedAction = nextAction; + ++_sequenceLevels[combo]; + _resetSequenceTimer(); + }; + } + + /** + * wraps the specified callback inside of another function in order + * to reset all sequence counters as soon as this sequence is done + * + * @param {Event} e + * @returns void + */ + function _callbackAndReset(e) { + _fireCallback(callback, e, combo); + + // we should ignore the next key up if the action is key down + // or keypress. this is so if you finish a sequence and + // release the key the final key will not trigger a keyup + if (action !== 'keyup') { + _ignoreNextKeyup = _characterFromEvent(e); + } + + // weird race condition if a sequence ends with the key + // another sequence begins with + setTimeout(_resetSequences, 10); + } + + // loop through keys one at a time and bind the appropriate callback + // function. for any key leading up to the final one it should + // increase the sequence. after the final, it should reset all sequences + // + // if an action is specified in the original bind call then that will + // be used throughout. otherwise we will pass the action that the + // next key in the sequence should match. this allows a sequence + // to mix and match keypress and keydown events depending on which + // ones are better suited to the key provided + for (var i = 0; i < keys.length; ++i) { + var isFinal = i + 1 === keys.length; + var wrappedCallback = isFinal ? _callbackAndReset : _increaseSequence(action || _getKeyInfo(keys[i + 1]).action); + _bindSingle(keys[i], wrappedCallback, action, combo, i); + } + } + + /** + * binds a single keyboard combination + * + * @param {string} combination + * @param {Function} callback + * @param {string=} action + * @param {string=} sequenceName - name of sequence if part of sequence + * @param {number=} level - what part of the sequence the command is + * @returns void + */ + function _bindSingle(combination, callback, action, sequenceName, level) { + + // store a direct mapped reference for use with Mousetrap.trigger + self._directMap[combination + ':' + action] = callback; + + // make sure multiple spaces in a row become a single space + combination = combination.replace(/\s+/g, ' '); + + var sequence = combination.split(' '); + var info; + + // if this pattern is a sequence of keys then run through this method + // to reprocess each pattern one key at a time + if (sequence.length > 1) { + _bindSequence(combination, sequence, callback, action); + return; + } + + info = _getKeyInfo(combination, action); + + // make sure to initialize array if this is the first time + // a callback is added for this key + self._callbacks[info.key] = self._callbacks[info.key] || []; + + // remove an existing match if there is one + _getMatches(info.key, info.modifiers, {type: info.action}, sequenceName, combination, level); + + // add this call back to the array + // if it is a sequence put it at the beginning + // if not put it at the end + // + // this is important because the way these are processed expects + // the sequence ones to come first + self._callbacks[info.key][sequenceName ? 'unshift' : 'push']({ + callback: callback, + modifiers: info.modifiers, + action: info.action, + seq: sequenceName, + level: level, + combo: combination + }); + } + + /** + * binds multiple combinations to the same callback + * + * @param {Array} combinations + * @param {Function} callback + * @param {string|undefined} action + * @returns void + */ + self._bindMultiple = function(combinations, callback, action) { + for (var i = 0; i < combinations.length; ++i) { + _bindSingle(combinations[i], callback, action); + } + }; + + // start! + _addEvent(targetElement, 'keypress', _handleKeyEvent); + _addEvent(targetElement, 'keydown', _handleKeyEvent); + _addEvent(targetElement, 'keyup', _handleKeyEvent); + } + + /** + * binds an event to mousetrap + * + * can be a single key, a combination of keys separated with +, + * an array of keys, or a sequence of keys separated by spaces + * + * be sure to list the modifier keys first to make sure that the + * correct key ends up getting bound (the last key in the pattern) + * + * @param {string|Array} keys + * @param {Function} callback + * @param {string=} action - 'keypress', 'keydown', or 'keyup' + * @returns void + */ + Mousetrap.prototype.bind = function(keys, callback, action) { + var self = this; + keys = keys instanceof Array ? keys : [keys]; + self._bindMultiple.call(self, keys, callback, action); + return self; + }; + + /** + * unbinds an event to mousetrap + * + * the unbinding sets the callback function of the specified key combo + * to an empty function and deletes the corresponding key in the + * _directMap dict. + * + * TODO: actually remove this from the _callbacks dictionary instead + * of binding an empty function + * + * the keycombo+action has to be exactly the same as + * it was defined in the bind method + * + * @param {string|Array} keys + * @param {string} action + * @returns void + */ + Mousetrap.prototype.unbind = function(keys, action) { + var self = this; + return self.bind.call(self, keys, function() {}, action); + }; + + /** + * triggers an event that has already been bound + * + * @param {string} keys + * @param {string=} action + * @returns void + */ + Mousetrap.prototype.trigger = function(keys, action) { + var self = this; + if (self._directMap[keys + ':' + action]) { + self._directMap[keys + ':' + action]({}, keys); + } + return self; + }; + + /** + * resets the library back to its initial state. this is useful + * if you want to clear out the current keyboard shortcuts and bind + * new ones - for example if you switch to another page + * + * @returns void + */ + Mousetrap.prototype.reset = function() { + var self = this; + self._callbacks = {}; + self._directMap = {}; + return self; + }; + + /** + * should we stop this event before firing off callbacks + * + * @param {Event} e + * @param {Element} element + * @return {boolean} + */ + Mousetrap.prototype.stopCallback = function(e, element) { + var self = this; + + // if the element has the class "mousetrap" then no need to stop + if ((' ' + element.className + ' ').indexOf(' mousetrap ') > -1) { + return false; + } + + if (_belongsTo(element, self.target)) { + return false; + } + + // stop for input, select, and textarea + return element.tagName == 'INPUT' || element.tagName == 'SELECT' || element.tagName == 'TEXTAREA' || element.isContentEditable; + }; + + /** + * exposes _handleKey publicly so it can be overwritten by extensions + */ + Mousetrap.prototype.handleKey = function() { + var self = this; + return self._handleKey.apply(self, arguments); + }; + + /** + * allow custom key mappings + */ + Mousetrap.addKeycodes = function(object) { + for (var key in object) { + if (object.hasOwnProperty(key)) { + _MAP[key] = object[key]; + } + } + _REVERSE_MAP = null; + }; + + /** + * Init the global mousetrap functions + * + * This method is needed to allow the global mousetrap functions to work + * now that mousetrap is a constructor function. + */ + Mousetrap.init = function() { + var documentMousetrap = Mousetrap(document); + for (var method in documentMousetrap) { + if (method.charAt(0) !== '_') { + Mousetrap[method] = (function(method) { + return function() { + return documentMousetrap[method].apply(documentMousetrap, arguments); + }; + } (method)); + } + } + }; + + Mousetrap.init(); + + // expose mousetrap to the global object + window.Mousetrap = Mousetrap; + + // expose as a common js module + if (typeof module !== 'undefined' && module.exports) { + module.exports = Mousetrap; + } + + // expose mousetrap as an AMD module + if (typeof define === 'function' && define.amd) { + define(function() { + return Mousetrap; + }); + } +}) (typeof window !== 'undefined' ? window : null, typeof window !== 'undefined' ? document : null); + +},{}],2:[function(_dereq_,module,exports){ +; +(function () { + 'use strict'; + + // registers the extension on a cytoscape lib ref + var register = function (cytoscape, $) { + + if (!cytoscape || !$) { + return; + } // can't register if cytoscape unspecified + + var options = { + node: { + highlighted: {}, // styles for when nodes are highlighted. + unhighlighted: {// styles for when nodes are unhighlighted. + 'opacity': 0.3 + } + }, + edge: { + highlighted: {}, // styles for when edges are highlighted. + unhighlighted: {// styles for when edges are unhighlighted. + 'opacity': 0.3 + } + }, + setVisibilityOnHide: false, // whether to set visibility on hide/show + setDisplayOnHide: true, // whether to set display on hide/show + neighbor: function(node){ // return desired neighbors of tapheld node + return false; + }, + neighborSelectTime: 500 //ms, time to taphold to select desired neighbors + }; + + + var undoRedo = _dereq_("./undo-redo"); + var viewUtilities = _dereq_("./view-utilities"); + var Mousetrap = _dereq_('mousetrap'); + + cytoscape('core', 'viewUtilities', function (opts) { + var cy = this; + + if (opts === 'get') { + return viewUtilities; + } + + $.extend(true, options, opts); + + function getScratch(eleOrCy) { + if (!eleOrCy.scratch("_viewUtilities")) { + eleOrCy.scratch("_viewUtilities", {}); + } + + return eleOrCy.scratch("_viewUtilities"); + } + + if (!getScratch(cy).initialized) { + getScratch(cy).initialized = true; + + viewUtilities(cy, options); + + if (cy.undoRedo) { + var ur = cy.undoRedo(null, true); + undoRedo(cy, ur, viewUtilities); + } + + var mt = new Mousetrap(); + var shiftKeyDown = false; + mt.bind(["shift"], function () { + shiftKeyDown = true; + }, "keydown"); + mt.bind(["shift"], function () { + shiftKeyDown = false; + }, "keyup"); + //Select the desired neighbors after taphold-and-free + cy.on('taphold', 'node', function(event){ + var target = event.target || event.cyTarget; + var tapheld = false; + var neighborhood; + var timeout = setTimeout(function(){ + if(shiftKeyDown == true){ + cy.elements().unselect(); + neighborhood = options.neighbor(target); + neighborhood.select(); + target.lock(); + tapheld = true; + } + }, options.neighborSelectTime - 500); + cy.on('free', 'node', function(){ + var targetTapheld = event.target || event.cyTarget; + if(target == targetTapheld && tapheld === true){ + tapheld = false; + neighborhood.select(); + target.unlock(); + } + else{ + clearTimeout(timeout); + } + }); + cy.on('drag', 'node', function(){ + var targetDragged = event.target || event.cyTarget; + if(target == targetDragged && tapheld === false){ + clearTimeout(timeout); + } + }) + }); + } + return viewUtilities; + }); + + }; + + if (typeof module !== 'undefined' && module.exports) { // expose as a commonjs module + module.exports = register; + } + + if (typeof define !== 'undefined' && define.amd) { // expose as an amd/requirejs module + define('cytoscape-view-utilities', function () { + return register; + }); + } + + if (typeof cytoscape !== 'undefined' && typeof $ !== "undefined") { // expose to global cytoscape (i.e. window.cytoscape) + register(cytoscape, $); + } + +})(); + +},{"./undo-redo":3,"./view-utilities":4,"mousetrap":1}],3:[function(_dereq_,module,exports){ +// Registers ur actions related to highlight +function highlightUR(cy, ur, viewUtilities) { + function getStatus(eles) { + eles = eles ? eles : cy.elements(); + return { + highlighteds: eles.filter(".highlighted:visible"), + unhighlighteds: eles.filter(".unhighlighted:visible"), + notHighlighteds: eles.filter(":visible").not(".highlighted, .unhighlighted") + }; + } + + function generalUndo(args) { + + var current = args.current; + var highlighteds = viewUtilities.highlight(args.highlighteds); + var unhighlighteds = viewUtilities.unhighlight(args.unhighlighteds); + var notHighlighteds = viewUtilities.removeHighlights(args.notHighlighteds); + + + return { + highlighteds: highlighteds, + unhighlighteds: unhighlighteds, + notHighlighteds: notHighlighteds, + current: current + }; + } + + function generalRedo(args) { + + var current = args.current; + var highlighteds = viewUtilities.highlight(args.current.highlighteds); + var unhighlighteds = viewUtilities.unhighlight(args.current.unhighlighteds); + var notHighlighteds = viewUtilities.removeHighlights(args.current.notHighlighteds); + + return { + highlighteds: highlighteds, + unhighlighteds: unhighlighteds, + notHighlighteds: notHighlighteds, + current: current + }; + } + + function generateDoFunc(func) { + return function (eles) { + var res = getStatus(); + + if (eles.firstTime) + viewUtilities[func](eles); + else + generalRedo(eles); + + res.current = getStatus(); + + return res; + }; + } + + function urRemoveHighlights(args) { + var res = getStatus(); + + if (args.firstTime) + viewUtilities.removeHighlights(); + else + generalRedo(args); + + res.current = getStatus(); + + return res; + } + + ur.action("highlightNeighbors", generateDoFunc("highlightNeighbors"), generalUndo); + ur.action("highlightNeighbours", generateDoFunc("highlightNeighbours"), generalUndo); + ur.action("highlight", generateDoFunc("highlight"), generalUndo); + ur.action("unhighlight", generateDoFunc("unhighlight"), generalUndo); + ur.action("unhighlightNeighbors", generateDoFunc("unhighlightNeighbors"), generalUndo); + ur.action("unhighlightNeighbours", generateDoFunc("unhighlightNeighbours"), generalUndo); + ur.action("removeHighlights", urRemoveHighlights, generalUndo); +} + +// Registers ur actions related to hide/show +function hideShowUR(cy, ur, viewUtilities) { + function urShow(eles) { + return viewUtilities.show(eles); + } + + function urHide(eles) { + return viewUtilities.hide(eles); + } + + ur.action("show", urShow, urHide); + ur.action("hide", urHide, urShow); +} + +module.exports = function (cy, ur, viewUtilities) { + highlightUR(cy, ur, viewUtilities); + hideShowUR(cy, ur, viewUtilities); +}; +},{}],4:[function(_dereq_,module,exports){ +var cy, options; +var viewUtilities = function (_cy, _options) { + cy = _cy; + options = _options; + + // Set style for highlighted and unhighligthed eles + cy + .style() + .selector("node.highlighted") + .css(options.node.highlighted) + .selector("node.unhighlighted") + .css(options.node.unhighlighted) + .selector("edge.highlighted") + .css(options.edge.highlighted) + .selector("edge.unhighlighted") + .css(options.edge.unhighlighted) + .update(); +}; + +// Helper functions for internal usage (not to be exposed) +function highlight(eles) { + eles.removeClass("unhighlighted").addClass("highlighted"); +} + +function getWithNeighbors(eles) { + return eles.add(eles.descendants()).closedNeighborhood(); +} + +// Section hide-show + +// hide given eles +viewUtilities.hide = function (eles) { + eles = eles.filter(":visible"); + eles = eles.union(eles.connectedEdges()); + + eles.unselect(); + + if (options.setVisibilityOnHide) { + eles.css('visibility', 'hidden'); + } + + if (options.setDisplayOnHide) { + eles.css('display', 'none'); + } + + return eles; +}; + +// unhide given eles +viewUtilities.show = function (eles) { + eles = eles.not(":visible"); + eles = eles.union(eles.connectedEdges()); + + eles.unselect(); + + if (options.setVisibilityOnHide) { + eles.css('visibility', 'visible'); + } + + if (options.setDisplayOnHide) { + eles.css('display', 'element'); + } + + return eles; +}; + +// Section highlight + +// Highlights eles & unhighlights others at first use. +viewUtilities.highlight = function (eles) { + var others = cy.elements().difference(eles.union(eles.ancestors())); + + if (cy.$(".highlighted:visible").length == 0) + this.unhighlight(others); + + highlight(eles); // Use the helper here + + return eles; +}; + +// Just unighlights eles. +viewUtilities.unhighlight = function (eles) { + eles.removeClass("highlighted").addClass("unhighlighted"); +}; + +// Highlights eles' neighborhood & unhighlights others' neighborhood at first use. +viewUtilities.highlightNeighbors = function (eles) { + var allEles = getWithNeighbors(eles); + + return this.highlight(allEles); +}; + +// Aliases: this.highlightNeighbours() +viewUtilities.highlightNeighbours = function (eles) { + return this.highlightNeighbors(eles); +}; + +// Just unhighlights eles and their neighbors. +viewUtilities.unhighlightNeighbors = function (eles) { + var allEles = getWithNeighbors(eles); + + return this.unhighlight(allEles); +}; + +// Aliases: this.unhighlightNeighbours() +viewUtilities.unhighlightNeighbours = function (eles) { + this.unhighlightNeighbors(eles); +}; + +// Remove highlights & unhighlights from eles. +// If eles is not defined considers cy.elements() +viewUtilities.removeHighlights = function (eles) { + if (!eles) { + eles = cy.elements(); + } + + return eles + .removeClass("highlighted") + .removeClass("unhighlighted") + .removeData("highlighted"); // TODO check if remove data is needed here +}; + +// Indicates if the ele is highlighted +viewUtilities.isHighlighted = function (ele) { + return ele.is(".highlighted:visible") ? true : false; +}; + +module.exports = viewUtilities; + + +},{}]},{},[2])(2) +}); +//# sourceMappingURL=data:application/json;charset:utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJub2RlX21vZHVsZXMvbW91c2V0cmFwL21vdXNldHJhcC5qcyIsInNyYy9pbmRleC5qcyIsInNyYy91bmRvLXJlZG8uanMiLCJzcmMvdmlldy11dGlsaXRpZXMuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwaENBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM3SEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaEdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIoZnVuY3Rpb24gZSh0LG4scil7ZnVuY3Rpb24gcyhvLHUpe2lmKCFuW29dKXtpZighdFtvXSl7dmFyIGE9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtpZighdSYmYSlyZXR1cm4gYShvLCEwKTtpZihpKXJldHVybiBpKG8sITApO3ZhciBmPW5ldyBFcnJvcihcIkNhbm5vdCBmaW5kIG1vZHVsZSAnXCIrbytcIidcIik7dGhyb3cgZi5jb2RlPVwiTU9EVUxFX05PVF9GT1VORFwiLGZ9dmFyIGw9bltvXT17ZXhwb3J0czp7fX07dFtvXVswXS5jYWxsKGwuZXhwb3J0cyxmdW5jdGlvbihlKXt2YXIgbj10W29dWzFdW2VdO3JldHVybiBzKG4/bjplKX0sbCxsLmV4cG9ydHMsZSx0LG4scil9cmV0dXJuIG5bb10uZXhwb3J0c312YXIgaT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2Zvcih2YXIgbz0wO288ci5sZW5ndGg7bysrKXMocltvXSk7cmV0dXJuIHN9KSIsIi8qZ2xvYmFsIGRlZmluZTpmYWxzZSAqL1xuLyoqXG4gKiBDb3B5cmlnaHQgMjAxMi0yMDE3IENyYWlnIENhbXBiZWxsXG4gKlxuICogTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKTtcbiAqIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS5cbiAqIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdFxuICpcbiAqIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuICpcbiAqIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmVcbiAqIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUyxcbiAqIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLlxuICogU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZFxuICogbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG4gKlxuICogTW91c2V0cmFwIGlzIGEgc2ltcGxlIGtleWJvYXJkIHNob3J0Y3V0IGxpYnJhcnkgZm9yIEphdmFzY3JpcHQgd2l0aFxuICogbm8gZXh0ZXJuYWwgZGVwZW5kZW5jaWVzXG4gKlxuICogQHZlcnNpb24gMS42LjFcbiAqIEB1cmwgY3JhaWcuaXMva2lsbGluZy9taWNlXG4gKi9cbihmdW5jdGlvbih3aW5kb3csIGRvY3VtZW50LCB1bmRlZmluZWQpIHtcblxuICAgIC8vIENoZWNrIGlmIG1vdXNldHJhcCBpcyB1c2VkIGluc2lkZSBicm93c2VyLCBpZiBub3QsIHJldHVyblxuICAgIGlmICghd2luZG93KSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBtYXBwaW5nIG9mIHNwZWNpYWwga2V5Y29kZXMgdG8gdGhlaXIgY29ycmVzcG9uZGluZyBrZXlzXG4gICAgICpcbiAgICAgKiBldmVyeXRoaW5nIGluIHRoaXMgZGljdGlvbmFyeSBjYW5ub3QgdXNlIGtleXByZXNzIGV2ZW50c1xuICAgICAqIHNvIGl0IGhhcyB0byBiZSBoZXJlIHRvIG1hcCB0byB0aGUgY29ycmVjdCBrZXljb2RlcyBmb3JcbiAgICAgKiBrZXl1cC9rZXlkb3duIGV2ZW50c1xuICAgICAqXG4gICAgICogQHR5cGUge09iamVjdH1cbiAgICAgKi9cbiAgICB2YXIgX01BUCA9IHtcbiAgICAgICAgODogJ2JhY2tzcGFjZScsXG4gICAgICAgIDk6ICd0YWInLFxuICAgICAgICAxMzogJ2VudGVyJyxcbiAgICAgICAgMTY6ICdzaGlmdCcsXG4gICAgICAgIDE3OiAnY3RybCcsXG4gICAgICAgIDE4OiAnYWx0JyxcbiAgICAgICAgMjA6ICdjYXBzbG9jaycsXG4gICAgICAgIDI3OiAnZXNjJyxcbiAgICAgICAgMzI6ICdzcGFjZScsXG4gICAgICAgIDMzOiAncGFnZXVwJyxcbiAgICAgICAgMzQ6ICdwYWdlZG93bicsXG4gICAgICAgIDM1OiAnZW5kJyxcbiAgICAgICAgMzY6ICdob21lJyxcbiAgICAgICAgMzc6ICdsZWZ0JyxcbiAgICAgICAgMzg6ICd1cCcsXG4gICAgICAgIDM5OiAncmlnaHQnLFxuICAgICAgICA0MDogJ2Rvd24nLFxuICAgICAgICA0NTogJ2lucycsXG4gICAgICAgIDQ2OiAnZGVsJyxcbiAgICAgICAgOTE6ICdtZXRhJyxcbiAgICAgICAgOTM6ICdtZXRhJyxcbiAgICAgICAgMjI0OiAnbWV0YSdcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogbWFwcGluZyBmb3Igc3BlY2lhbCBjaGFyYWN0ZXJzIHNvIHRoZXkgY2FuIHN1cHBvcnRcbiAgICAgKlxuICAgICAqIHRoaXMgZGljdGlvbmFyeSBpcyBvbmx5IHVzZWQgaW5jYXNlIHlvdSB3YW50IHRvIGJpbmQgYVxuICAgICAqIGtleXVwIG9yIGtleWRvd24gZXZlbnQgdG8gb25lIG9mIHRoZXNlIGtleXNcbiAgICAgKlxuICAgICAqIEB0eXBlIHtPYmplY3R9XG4gICAgICovXG4gICAgdmFyIF9LRVlDT0RFX01BUCA9IHtcbiAgICAgICAgMTA2OiAnKicsXG4gICAgICAgIDEwNzogJysnLFxuICAgICAgICAxMDk6ICctJyxcbiAgICAgICAgMTEwOiAnLicsXG4gICAgICAgIDExMSA6ICcvJyxcbiAgICAgICAgMTg2OiAnOycsXG4gICAgICAgIDE4NzogJz0nLFxuICAgICAgICAxODg6ICcsJyxcbiAgICAgICAgMTg5OiAnLScsXG4gICAgICAgIDE5MDogJy4nLFxuICAgICAgICAxOTE6ICcvJyxcbiAgICAgICAgMTkyOiAnYCcsXG4gICAgICAgIDIxOTogJ1snLFxuICAgICAgICAyMjA6ICdcXFxcJyxcbiAgICAgICAgMjIxOiAnXScsXG4gICAgICAgIDIyMjogJ1xcJydcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogdGhpcyBpcyBhIG1hcHBpbmcgb2Yga2V5cyB0aGF0IHJlcXVpcmUgc2hpZnQgb24gYSBVUyBrZXlwYWRcbiAgICAgKiBiYWNrIHRvIHRoZSBub24gc2hpZnQgZXF1aXZlbGVudHNcbiAgICAgKlxuICAgICAqIHRoaXMgaXMgc28geW91IGNhbiB1c2Uga2V5dXAgZXZlbnRzIHdpdGggdGhlc2Uga2V5c1xuICAgICAqXG4gICAgICogbm90ZSB0aGF0IHRoaXMgd2lsbCBvbmx5IHdvcmsgcmVsaWFibHkgb24gVVMga2V5Ym9hcmRzXG4gICAgICpcbiAgICAgKiBAdHlwZSB7T2JqZWN0fVxuICAgICAqL1xuICAgIHZhciBfU0hJRlRfTUFQID0ge1xuICAgICAgICAnfic6ICdgJyxcbiAgICAgICAgJyEnOiAnMScsXG4gICAgICAgICdAJzogJzInLFxuICAgICAgICAnIyc6ICczJyxcbiAgICAgICAgJyQnOiAnNCcsXG4gICAgICAgICclJzogJzUnLFxuICAgICAgICAnXic6ICc2JyxcbiAgICAgICAgJyYnOiAnNycsXG4gICAgICAgICcqJzogJzgnLFxuICAgICAgICAnKCc6ICc5JyxcbiAgICAgICAgJyknOiAnMCcsXG4gICAgICAgICdfJzogJy0nLFxuICAgICAgICAnKyc6ICc9JyxcbiAgICAgICAgJzonOiAnOycsXG4gICAgICAgICdcXFwiJzogJ1xcJycsXG4gICAgICAgICc8JzogJywnLFxuICAgICAgICAnPic6ICcuJyxcbiAgICAgICAgJz8nOiAnLycsXG4gICAgICAgICd8JzogJ1xcXFwnXG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIHRoaXMgaXMgYSBsaXN0IG9mIHNwZWNpYWwgc3RyaW5ncyB5b3UgY2FuIHVzZSB0byBtYXBcbiAgICAgKiB0byBtb2RpZmllciBrZXlzIHdoZW4geW91IHNwZWNpZnkgeW91ciBrZXlib2FyZCBzaG9ydGN1dHNcbiAgICAgKlxuICAgICAqIEB0eXBlIHtPYmplY3R9XG4gICAgICovXG4gICAgdmFyIF9TUEVDSUFMX0FMSUFTRVMgPSB7XG4gICAgICAgICdvcHRpb24nOiAnYWx0JyxcbiAgICAgICAgJ2NvbW1hbmQnOiAnbWV0YScsXG4gICAgICAgICdyZXR1cm4nOiAnZW50ZXInLFxuICAgICAgICAnZXNjYXBlJzogJ2VzYycsXG4gICAgICAgICdwbHVzJzogJysnLFxuICAgICAgICAnbW9kJzogL01hY3xpUG9kfGlQaG9uZXxpUGFkLy50ZXN0KG5hdmlnYXRvci5wbGF0Zm9ybSkgPyAnbWV0YScgOiAnY3RybCdcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogdmFyaWFibGUgdG8gc3RvcmUgdGhlIGZsaXBwZWQgdmVyc2lvbiBvZiBfTUFQIGZyb20gYWJvdmVcbiAgICAgKiBuZWVkZWQgdG8gY2hlY2sgaWYgd2Ugc2hvdWxkIHVzZSBrZXlwcmVzcyBvciBub3Qgd2hlbiBubyBhY3Rpb25cbiAgICAgKiBpcyBzcGVjaWZpZWRcbiAgICAgKlxuICAgICAqIEB0eXBlIHtPYmplY3R8dW5kZWZpbmVkfVxuICAgICAqL1xuICAgIHZhciBfUkVWRVJTRV9NQVA7XG5cbiAgICAvKipcbiAgICAgKiBsb29wIHRocm91Z2ggdGhlIGYga2V5cywgZjEgdG8gZjE5IGFuZCBhZGQgdGhlbSB0byB0aGUgbWFwXG4gICAgICogcHJvZ3JhbWF0aWNhbGx5XG4gICAgICovXG4gICAgZm9yICh2YXIgaSA9IDE7IGkgPCAyMDsgKytpKSB7XG4gICAgICAgIF9NQVBbMTExICsgaV0gPSAnZicgKyBpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIGxvb3AgdGhyb3VnaCB0byBtYXAgbnVtYmVycyBvbiB0aGUgbnVtZXJpYyBrZXlwYWRcbiAgICAgKi9cbiAgICBmb3IgKGkgPSAwOyBpIDw9IDk7ICsraSkge1xuXG4gICAgICAgIC8vIFRoaXMgbmVlZHMgdG8gdXNlIGEgc3RyaW5nIGNhdXNlIG90aGVyd2lzZSBzaW5jZSAwIGlzIGZhbHNleVxuICAgICAgICAvLyBtb3VzZXRyYXAgd2lsbCBuZXZlciBmaXJlIGZvciBudW1wYWQgMCBwcmVzc2VkIGFzIHBhcnQgb2YgYSBrZXlkb3duXG4gICAgICAgIC8vIGV2ZW50LlxuICAgICAgICAvL1xuICAgICAgICAvLyBAc2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9jY2FtcGJlbGwvbW91c2V0cmFwL3B1bGwvMjU4XG4gICAgICAgIF9NQVBbaSArIDk2XSA9IGkudG9TdHJpbmcoKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBjcm9zcyBicm93c2VyIGFkZCBldmVudCBtZXRob2RcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7RWxlbWVudHxIVE1MRG9jdW1lbnR9IG9iamVjdFxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2tcbiAgICAgKiBAcmV0dXJucyB2b2lkXG4gICAgICovXG4gICAgZnVuY3Rpb24gX2FkZEV2ZW50KG9iamVjdCwgdHlwZSwgY2FsbGJhY2spIHtcbiAgICAgICAgaWYgKG9iamVjdC5hZGRFdmVudExpc3RlbmVyKSB7XG4gICAgICAgICAgICBvYmplY3QuYWRkRXZlbnRMaXN0ZW5lcih0eXBlLCBjYWxsYmFjaywgZmFsc2UpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgb2JqZWN0LmF0dGFjaEV2ZW50KCdvbicgKyB0eXBlLCBjYWxsYmFjayk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogdGFrZXMgdGhlIGV2ZW50IGFuZCByZXR1cm5zIHRoZSBrZXkgY2hhcmFjdGVyXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge0V2ZW50fSBlXG4gICAgICogQHJldHVybiB7c3RyaW5nfVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIF9jaGFyYWN0ZXJGcm9tRXZlbnQoZSkge1xuXG4gICAgICAgIC8vIGZvciBrZXlwcmVzcyBldmVudHMgd2Ugc2hvdWxkIHJldHVybiB0aGUgY2hhcmFjdGVyIGFzIGlzXG4gICAgICAgIGlmIChlLnR5cGUgPT0gJ2tleXByZXNzJykge1xuICAgICAgICAgICAgdmFyIGNoYXJhY3RlciA9IFN0cmluZy5mcm9tQ2hhckNvZGUoZS53aGljaCk7XG5cbiAgICAgICAgICAgIC8vIGlmIHRoZSBzaGlmdCBrZXkgaXMgbm90IHByZXNzZWQgdGhlbiBpdCBpcyBzYWZlIHRvIGFzc3VtZVxuICAgICAgICAgICAgLy8gdGhhdCB3ZSB3YW50IHRoZSBjaGFyYWN0ZXIgdG8gYmUgbG93ZXJjYXNlLiAgdGhpcyBtZWFucyBpZlxuICAgICAgICAgICAgLy8geW91IGFjY2lkZW50YWxseSBoYXZlIGNhcHMgbG9jayBvbiB0aGVuIHlvdXIga2V5IGJpbmRpbmdzXG4gICAgICAgICAgICAvLyB3aWxsIGNvbnRpbnVlIHRvIHdvcmtcbiAgICAgICAgICAgIC8vXG4gICAgICAgICAgICAvLyB0aGUgb25seSBzaWRlIGVmZmVjdCB0aGF0IG1pZ2h0IG5vdCBiZSBkZXNpcmVkIGlzIGlmIHlvdVxuICAgICAgICAgICAgLy8gYmluZCBzb21ldGhpbmcgbGlrZSAnQScgY2F1c2UgeW91IHdhbnQgdG8gdHJpZ2dlciBhblxuICAgICAgICAgICAgLy8gZXZlbnQgd2hlbiBjYXBpdGFsIEEgaXMgcHJlc3NlZCBjYXBzIGxvY2sgd2lsbCBubyBsb25nZXJcbiAgICAgICAgICAgIC8vIHRyaWdnZXIgdGhlIGV2ZW50LiAgc2hpZnQrYSB3aWxsIHRob3VnaC5cbiAgICAgICAgICAgIGlmICghZS5zaGlmdEtleSkge1xuICAgICAgICAgICAgICAgIGNoYXJhY3RlciA9IGNoYXJhY3Rlci50b0xvd2VyQ2FzZSgpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gY2hhcmFjdGVyO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gZm9yIG5vbiBrZXlwcmVzcyBldmVudHMgdGhlIHNwZWNpYWwgbWFwcyBhcmUgbmVlZGVkXG4gICAgICAgIGlmIChfTUFQW2Uud2hpY2hdKSB7XG4gICAgICAgICAgICByZXR1cm4gX01BUFtlLndoaWNoXTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChfS0VZQ09ERV9NQVBbZS53aGljaF0pIHtcbiAgICAgICAgICAgIHJldHVybiBfS0VZQ09ERV9NQVBbZS53aGljaF07XG4gICAgICAgIH1cblxuICAgICAgICAvLyBpZiBpdCBpcyBub3QgaW4gdGhlIHNwZWNpYWwgbWFwXG5cbiAgICAgICAgLy8gd2l0aCBrZXlkb3duIGFuZCBrZXl1cCBldmVudHMgdGhlIGNoYXJhY3RlciBzZWVtcyB0byBhbHdheXNcbiAgICAgICAgLy8gY29tZSBpbiBhcyBhbiB1cHBlcmNhc2UgY2hhcmFjdGVyIHdoZXRoZXIgeW91IGFyZSBwcmVzc2luZyBzaGlmdFxuICAgICAgICAvLyBvciBub3QuICB3ZSBzaG91bGQgbWFrZSBzdXJlIGl0IGlzIGFsd2F5cyBsb3dlcmNhc2UgZm9yIGNvbXBhcmlzb25zXG4gICAgICAgIHJldHVybiBTdHJpbmcuZnJvbUNoYXJDb2RlKGUud2hpY2gpLnRvTG93ZXJDYXNlKCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogY2hlY2tzIGlmIHR3byBhcnJheXMgYXJlIGVxdWFsXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge0FycmF5fSBtb2RpZmllcnMxXG4gICAgICogQHBhcmFtIHtBcnJheX0gbW9kaWZpZXJzMlxuICAgICAqIEByZXR1cm5zIHtib29sZWFufVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIF9tb2RpZmllcnNNYXRjaChtb2RpZmllcnMxLCBtb2RpZmllcnMyKSB7XG4gICAgICAgIHJldHVybiBtb2RpZmllcnMxLnNvcnQoKS5qb2luKCcsJykgPT09IG1vZGlmaWVyczIuc29ydCgpLmpvaW4oJywnKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiB0YWtlcyBhIGtleSBldmVudCBhbmQgZmlndXJlcyBvdXQgd2hhdCB0aGUgbW9kaWZpZXJzIGFyZVxuICAgICAqXG4gICAgICogQHBhcmFtIHtFdmVudH0gZVxuICAgICAqIEByZXR1cm5zIHtBcnJheX1cbiAgICAgKi9cbiAgICBmdW5jdGlvbiBfZXZlbnRNb2RpZmllcnMoZSkge1xuICAgICAgICB2YXIgbW9kaWZpZXJzID0gW107XG5cbiAgICAgICAgaWYgKGUuc2hpZnRLZXkpIHtcbiAgICAgICAgICAgIG1vZGlmaWVycy5wdXNoKCdzaGlmdCcpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGUuYWx0S2V5KSB7XG4gICAgICAgICAgICBtb2RpZmllcnMucHVzaCgnYWx0Jyk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoZS5jdHJsS2V5KSB7XG4gICAgICAgICAgICBtb2RpZmllcnMucHVzaCgnY3RybCcpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGUubWV0YUtleSkge1xuICAgICAgICAgICAgbW9kaWZpZXJzLnB1c2goJ21ldGEnKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBtb2RpZmllcnM7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogcHJldmVudHMgZGVmYXVsdCBmb3IgdGhpcyBldmVudFxuICAgICAqXG4gICAgICogQHBhcmFtIHtFdmVudH0gZVxuICAgICAqIEByZXR1cm5zIHZvaWRcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBfcHJldmVudERlZmF1bHQoZSkge1xuICAgICAgICBpZiAoZS5wcmV2ZW50RGVmYXVsdCkge1xuICAgICAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgZS5yZXR1cm5WYWx1ZSA9IGZhbHNlO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIHN0b3BzIHByb3BvZ2F0aW9uIGZvciB0aGlzIGV2ZW50XG4gICAgICpcbiAgICAgKiBAcGFyYW0ge0V2ZW50fSBlXG4gICAgICogQHJldHVybnMgdm9pZFxuICAgICAqL1xuICAgIGZ1bmN0aW9uIF9zdG9wUHJvcGFnYXRpb24oZSkge1xuICAgICAgICBpZiAoZS5zdG9wUHJvcGFnYXRpb24pIHtcbiAgICAgICAgICAgIGUuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBlLmNhbmNlbEJ1YmJsZSA9IHRydWU7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogZGV0ZXJtaW5lcyBpZiB0aGUga2V5Y29kZSBzcGVjaWZpZWQgaXMgYSBtb2RpZmllciBrZXkgb3Igbm90XG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30ga2V5XG4gICAgICogQHJldHVybnMge2Jvb2xlYW59XG4gICAgICovXG4gICAgZnVuY3Rpb24gX2lzTW9kaWZpZXIoa2V5KSB7XG4gICAgICAgIHJldHVybiBrZXkgPT0gJ3NoaWZ0JyB8fCBrZXkgPT0gJ2N0cmwnIHx8IGtleSA9PSAnYWx0JyB8fCBrZXkgPT0gJ21ldGEnO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIHJldmVyc2VzIHRoZSBtYXAgbG9va3VwIHNvIHRoYXQgd2UgY2FuIGxvb2sgZm9yIHNwZWNpZmljIGtleXNcbiAgICAgKiB0byBzZWUgd2hhdCBjYW4gYW5kIGNhbid0IHVzZSBrZXlwcmVzc1xuICAgICAqXG4gICAgICogQHJldHVybiB7T2JqZWN0fVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIF9nZXRSZXZlcnNlTWFwKCkge1xuICAgICAgICBpZiAoIV9SRVZFUlNFX01BUCkge1xuICAgICAgICAgICAgX1JFVkVSU0VfTUFQID0ge307XG4gICAgICAgICAgICBmb3IgKHZhciBrZXkgaW4gX01BUCkge1xuXG4gICAgICAgICAgICAgICAgLy8gcHVsbCBvdXQgdGhlIG51bWVyaWMga2V5cGFkIGZyb20gaGVyZSBjYXVzZSBrZXlwcmVzcyBzaG91bGRcbiAgICAgICAgICAgICAgICAvLyBiZSBhYmxlIHRvIGRldGVjdCB0aGUga2V5cyBmcm9tIHRoZSBjaGFyYWN0ZXJcbiAgICAgICAgICAgICAgICBpZiAoa2V5ID4gOTUgJiYga2V5IDwgMTEyKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlmIChfTUFQLmhhc093blByb3BlcnR5KGtleSkpIHtcbiAgICAgICAgICAgICAgICAgICAgX1JFVkVSU0VfTUFQW19NQVBba2V5XV0gPSBrZXk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBfUkVWRVJTRV9NQVA7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogcGlja3MgdGhlIGJlc3QgYWN0aW9uIGJhc2VkIG9uIHRoZSBrZXkgY29tYmluYXRpb25cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBrZXkgLSBjaGFyYWN0ZXIgZm9yIGtleVxuICAgICAqIEBwYXJhbSB7QXJyYXl9IG1vZGlmaWVyc1xuICAgICAqIEBwYXJhbSB7c3RyaW5nPX0gYWN0aW9uIHBhc3NlZCBpblxuICAgICAqL1xuICAgIGZ1bmN0aW9uIF9waWNrQmVzdEFjdGlvbihrZXksIG1vZGlmaWVycywgYWN0aW9uKSB7XG5cbiAgICAgICAgLy8gaWYgbm8gYWN0aW9uIHdhcyBwaWNrZWQgaW4gd2Ugc2hvdWxkIHRyeSB0byBwaWNrIHRoZSBvbmVcbiAgICAgICAgLy8gdGhhdCB3ZSB0aGluayB3b3VsZCB3b3JrIGJlc3QgZm9yIHRoaXMga2V5XG4gICAgICAgIGlmICghYWN0aW9uKSB7XG4gICAgICAgICAgICBhY3Rpb24gPSBfZ2V0UmV2ZXJzZU1hcCgpW2tleV0gPyAna2V5ZG93bicgOiAna2V5cHJlc3MnO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gbW9kaWZpZXIga2V5cyBkb24ndCB3b3JrIGFzIGV4cGVjdGVkIHdpdGgga2V5cHJlc3MsXG4gICAgICAgIC8vIHN3aXRjaCB0byBrZXlkb3duXG4gICAgICAgIGlmIChhY3Rpb24gPT0gJ2tleXByZXNzJyAmJiBtb2RpZmllcnMubGVuZ3RoKSB7XG4gICAgICAgICAgICBhY3Rpb24gPSAna2V5ZG93bic7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gYWN0aW9uO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENvbnZlcnRzIGZyb20gYSBzdHJpbmcga2V5IGNvbWJpbmF0aW9uIHRvIGFuIGFycmF5XG4gICAgICpcbiAgICAgKiBAcGFyYW0gIHtzdHJpbmd9IGNvbWJpbmF0aW9uIGxpa2UgXCJjb21tYW5kK3NoaWZ0K2xcIlxuICAgICAqIEByZXR1cm4ge0FycmF5fVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIF9rZXlzRnJvbVN0cmluZyhjb21iaW5hdGlvbikge1xuICAgICAgICBpZiAoY29tYmluYXRpb24gPT09ICcrJykge1xuICAgICAgICAgICAgcmV0dXJuIFsnKyddO1xuICAgICAgICB9XG5cbiAgICAgICAgY29tYmluYXRpb24gPSBjb21iaW5hdGlvbi5yZXBsYWNlKC9cXCt7Mn0vZywgJytwbHVzJyk7XG4gICAgICAgIHJldHVybiBjb21iaW5hdGlvbi5zcGxpdCgnKycpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdldHMgaW5mbyBmb3IgYSBzcGVjaWZpYyBrZXkgY29tYmluYXRpb25cbiAgICAgKlxuICAgICAqIEBwYXJhbSAge3N0cmluZ30gY29tYmluYXRpb24ga2V5IGNvbWJpbmF0aW9uIChcImNvbW1hbmQrc1wiIG9yIFwiYVwiIG9yIFwiKlwiKVxuICAgICAqIEBwYXJhbSAge3N0cmluZz19IGFjdGlvblxuICAgICAqIEByZXR1cm5zIHtPYmplY3R9XG4gICAgICovXG4gICAgZnVuY3Rpb24gX2dldEtleUluZm8oY29tYmluYXRpb24sIGFjdGlvbikge1xuICAgICAgICB2YXIga2V5cztcbiAgICAgICAgdmFyIGtleTtcbiAgICAgICAgdmFyIGk7XG4gICAgICAgIHZhciBtb2RpZmllcnMgPSBbXTtcblxuICAgICAgICAvLyB0YWtlIHRoZSBrZXlzIGZyb20gdGhpcyBwYXR0ZXJuIGFuZCBmaWd1cmUgb3V0IHdoYXQgdGhlIGFjdHVhbFxuICAgICAgICAvLyBwYXR0ZXJuIGlzIGFsbCBhYm91dFxuICAgICAgICBrZXlzID0gX2tleXNGcm9tU3RyaW5nKGNvbWJpbmF0aW9uKTtcblxuICAgICAgICBmb3IgKGkgPSAwOyBpIDwga2V5cy5sZW5ndGg7ICsraSkge1xuICAgICAgICAgICAga2V5ID0ga2V5c1tpXTtcblxuICAgICAgICAgICAgLy8gbm9ybWFsaXplIGtleSBuYW1lc1xuICAgICAgICAgICAgaWYgKF9TUEVDSUFMX0FMSUFTRVNba2V5XSkge1xuICAgICAgICAgICAgICAgIGtleSA9IF9TUEVDSUFMX0FMSUFTRVNba2V5XTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gaWYgdGhpcyBpcyBub3QgYSBrZXlwcmVzcyBldmVudCB0aGVuIHdlIHNob3VsZFxuICAgICAgICAgICAgLy8gYmUgc21hcnQgYWJvdXQgdXNpbmcgc2hpZnQga2V5c1xuICAgICAgICAgICAgLy8gdGhpcyB3aWxsIG9ubHkgd29yayBmb3IgVVMga2V5Ym9hcmRzIGhvd2V2ZXJcbiAgICAgICAgICAgIGlmIChhY3Rpb24gJiYgYWN0aW9uICE9ICdrZXlwcmVzcycgJiYgX1NISUZUX01BUFtrZXldKSB7XG4gICAgICAgICAgICAgICAga2V5ID0gX1NISUZUX01BUFtrZXldO1xuICAgICAgICAgICAgICAgIG1vZGlmaWVycy5wdXNoKCdzaGlmdCcpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBpZiB0aGlzIGtleSBpcyBhIG1vZGlmaWVyIHRoZW4gYWRkIGl0IHRvIHRoZSBsaXN0IG9mIG1vZGlmaWVyc1xuICAgICAgICAgICAgaWYgKF9pc01vZGlmaWVyKGtleSkpIHtcbiAgICAgICAgICAgICAgICBtb2RpZmllcnMucHVzaChrZXkpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gZGVwZW5kaW5nIG9uIHdoYXQgdGhlIGtleSBjb21iaW5hdGlvbiBpc1xuICAgICAgICAvLyB3ZSB3aWxsIHRyeSB0byBwaWNrIHRoZSBiZXN0IGV2ZW50IGZvciBpdFxuICAgICAgICBhY3Rpb24gPSBfcGlja0Jlc3RBY3Rpb24oa2V5LCBtb2RpZmllcnMsIGFjdGlvbik7XG5cbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIGtleToga2V5LFxuICAgICAgICAgICAgbW9kaWZpZXJzOiBtb2RpZmllcnMsXG4gICAgICAgICAgICBhY3Rpb246IGFjdGlvblxuICAgICAgICB9O1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIF9iZWxvbmdzVG8oZWxlbWVudCwgYW5jZXN0b3IpIHtcbiAgICAgICAgaWYgKGVsZW1lbnQgPT09IG51bGwgfHwgZWxlbWVudCA9PT0gZG9jdW1lbnQpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChlbGVtZW50ID09PSBhbmNlc3Rvcikge1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gX2JlbG9uZ3NUbyhlbGVtZW50LnBhcmVudE5vZGUsIGFuY2VzdG9yKTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBNb3VzZXRyYXAodGFyZ2V0RWxlbWVudCkge1xuICAgICAgICB2YXIgc2VsZiA9IHRoaXM7XG5cbiAgICAgICAgdGFyZ2V0RWxlbWVudCA9IHRhcmdldEVsZW1lbnQgfHwgZG9jdW1lbnQ7XG5cbiAgICAgICAgaWYgKCEoc2VsZiBpbnN0YW5jZW9mIE1vdXNldHJhcCkpIHtcbiAgICAgICAgICAgIHJldHVybiBuZXcgTW91c2V0cmFwKHRhcmdldEVsZW1lbnQpO1xuICAgICAgICB9XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIGVsZW1lbnQgdG8gYXR0YWNoIGtleSBldmVudHMgdG9cbiAgICAgICAgICpcbiAgICAgICAgICogQHR5cGUge0VsZW1lbnR9XG4gICAgICAgICAqL1xuICAgICAgICBzZWxmLnRhcmdldCA9IHRhcmdldEVsZW1lbnQ7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIGEgbGlzdCBvZiBhbGwgdGhlIGNhbGxiYWNrcyBzZXR1cCB2aWEgTW91c2V0cmFwLmJpbmQoKVxuICAgICAgICAgKlxuICAgICAgICAgKiBAdHlwZSB7T2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgc2VsZi5fY2FsbGJhY2tzID0ge307XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIGRpcmVjdCBtYXAgb2Ygc3RyaW5nIGNvbWJpbmF0aW9ucyB0byBjYWxsYmFja3MgdXNlZCBmb3IgdHJpZ2dlcigpXG4gICAgICAgICAqXG4gICAgICAgICAqIEB0eXBlIHtPYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICBzZWxmLl9kaXJlY3RNYXAgPSB7fTtcblxuICAgICAgICAvKipcbiAgICAgICAgICoga2VlcHMgdHJhY2sgb2Ygd2hhdCBsZXZlbCBlYWNoIHNlcXVlbmNlIGlzIGF0IHNpbmNlIG11bHRpcGxlXG4gICAgICAgICAqIHNlcXVlbmNlcyBjYW4gc3RhcnQgb3V0IHdpdGggdGhlIHNhbWUgc2VxdWVuY2VcbiAgICAgICAgICpcbiAgICAgICAgICogQHR5cGUge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHZhciBfc2VxdWVuY2VMZXZlbHMgPSB7fTtcblxuICAgICAgICAvKipcbiAgICAgICAgICogdmFyaWFibGUgdG8gc3RvcmUgdGhlIHNldFRpbWVvdXQgY2FsbFxuICAgICAgICAgKlxuICAgICAgICAgKiBAdHlwZSB7bnVsbHxudW1iZXJ9XG4gICAgICAgICAqL1xuICAgICAgICB2YXIgX3Jlc2V0VGltZXI7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIHRlbXBvcmFyeSBzdGF0ZSB3aGVyZSB3ZSB3aWxsIGlnbm9yZSB0aGUgbmV4dCBrZXl1cFxuICAgICAgICAgKlxuICAgICAgICAgKiBAdHlwZSB7Ym9vbGVhbnxzdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB2YXIgX2lnbm9yZU5leHRLZXl1cCA9IGZhbHNlO1xuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiB0ZW1wb3Jhcnkgc3RhdGUgd2hlcmUgd2Ugd2lsbCBpZ25vcmUgdGhlIG5leHQga2V5cHJlc3NcbiAgICAgICAgICpcbiAgICAgICAgICogQHR5cGUge2Jvb2xlYW59XG4gICAgICAgICAqL1xuICAgICAgICB2YXIgX2lnbm9yZU5leHRLZXlwcmVzcyA9IGZhbHNlO1xuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBhcmUgd2UgY3VycmVudGx5IGluc2lkZSBvZiBhIHNlcXVlbmNlP1xuICAgICAgICAgKiB0eXBlIG9mIGFjdGlvbiAoXCJrZXl1cFwiIG9yIFwia2V5ZG93blwiIG9yIFwia2V5cHJlc3NcIikgb3IgZmFsc2VcbiAgICAgICAgICpcbiAgICAgICAgICogQHR5cGUge2Jvb2xlYW58c3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgdmFyIF9uZXh0RXhwZWN0ZWRBY3Rpb24gPSBmYWxzZTtcblxuICAgICAgICAvKipcbiAgICAgICAgICogcmVzZXRzIGFsbCBzZXF1ZW5jZSBjb3VudGVycyBleGNlcHQgZm9yIHRoZSBvbmVzIHBhc3NlZCBpblxuICAgICAgICAgKlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gZG9Ob3RSZXNldFxuICAgICAgICAgKiBAcmV0dXJucyB2b2lkXG4gICAgICAgICAqL1xuICAgICAgICBmdW5jdGlvbiBfcmVzZXRTZXF1ZW5jZXMoZG9Ob3RSZXNldCkge1xuICAgICAgICAgICAgZG9Ob3RSZXNldCA9IGRvTm90UmVzZXQgfHwge307XG5cbiAgICAgICAgICAgIHZhciBhY3RpdmVTZXF1ZW5jZXMgPSBmYWxzZSxcbiAgICAgICAgICAgICAgICBrZXk7XG5cbiAgICAgICAgICAgIGZvciAoa2V5IGluIF9zZXF1ZW5jZUxldmVscykge1xuICAgICAgICAgICAgICAgIGlmIChkb05vdFJlc2V0W2tleV0pIHtcbiAgICAgICAgICAgICAgICAgICAgYWN0aXZlU2VxdWVuY2VzID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIF9zZXF1ZW5jZUxldmVsc1trZXldID0gMDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKCFhY3RpdmVTZXF1ZW5jZXMpIHtcbiAgICAgICAgICAgICAgICBfbmV4dEV4cGVjdGVkQWN0aW9uID0gZmFsc2U7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvKipcbiAgICAgICAgICogZmluZHMgYWxsIGNhbGxiYWNrcyB0aGF0IG1hdGNoIGJhc2VkIG9uIHRoZSBrZXljb2RlLCBtb2RpZmllcnMsXG4gICAgICAgICAqIGFuZCBhY3Rpb25cbiAgICAgICAgICpcbiAgICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGNoYXJhY3RlclxuICAgICAgICAgKiBAcGFyYW0ge0FycmF5fSBtb2RpZmllcnNcbiAgICAgICAgICogQHBhcmFtIHtFdmVudHxPYmplY3R9IGVcbiAgICAgICAgICogQHBhcmFtIHtzdHJpbmc9fSBzZXF1ZW5jZU5hbWUgLSBuYW1lIG9mIHRoZSBzZXF1ZW5jZSB3ZSBhcmUgbG9va2luZyBmb3JcbiAgICAgICAgICogQHBhcmFtIHtzdHJpbmc9fSBjb21iaW5hdGlvblxuICAgICAgICAgKiBAcGFyYW0ge251bWJlcj19IGxldmVsXG4gICAgICAgICAqIEByZXR1cm5zIHtBcnJheX1cbiAgICAgICAgICovXG4gICAgICAgIGZ1bmN0aW9uIF9nZXRNYXRjaGVzKGNoYXJhY3RlciwgbW9kaWZpZXJzLCBlLCBzZXF1ZW5jZU5hbWUsIGNvbWJpbmF0aW9uLCBsZXZlbCkge1xuICAgICAgICAgICAgdmFyIGk7XG4gICAgICAgICAgICB2YXIgY2FsbGJhY2s7XG4gICAgICAgICAgICB2YXIgbWF0Y2hlcyA9IFtdO1xuICAgICAgICAgICAgdmFyIGFjdGlvbiA9IGUudHlwZTtcblxuICAgICAgICAgICAgLy8gaWYgdGhlcmUgYXJlIG5vIGV2ZW50cyByZWxhdGVkIHRvIHRoaXMga2V5Y29kZVxuICAgICAgICAgICAgaWYgKCFzZWxmLl9jYWxsYmFja3NbY2hhcmFjdGVyXSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBbXTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gaWYgYSBtb2RpZmllciBrZXkgaXMgY29taW5nIHVwIG9uIGl0cyBvd24gd2Ugc2hvdWxkIGFsbG93IGl0XG4gICAgICAgICAgICBpZiAoYWN0aW9uID09ICdrZXl1cCcgJiYgX2lzTW9kaWZpZXIoY2hhcmFjdGVyKSkge1xuICAgICAgICAgICAgICAgIG1vZGlmaWVycyA9IFtjaGFyYWN0ZXJdO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBsb29wIHRocm91Z2ggYWxsIGNhbGxiYWNrcyBmb3IgdGhlIGtleSB0aGF0IHdhcyBwcmVzc2VkXG4gICAgICAgICAgICAvLyBhbmQgc2VlIGlmIGFueSBvZiB0aGVtIG1hdGNoXG4gICAgICAgICAgICBmb3IgKGkgPSAwOyBpIDwgc2VsZi5fY2FsbGJhY2tzW2NoYXJhY3Rlcl0ubGVuZ3RoOyArK2kpIHtcbiAgICAgICAgICAgICAgICBjYWxsYmFjayA9IHNlbGYuX2NhbGxiYWNrc1tjaGFyYWN0ZXJdW2ldO1xuXG4gICAgICAgICAgICAgICAgLy8gaWYgYSBzZXF1ZW5jZSBuYW1lIGlzIG5vdCBzcGVjaWZpZWQsIGJ1dCB0aGlzIGlzIGEgc2VxdWVuY2UgYXRcbiAgICAgICAgICAgICAgICAvLyB0aGUgd3JvbmcgbGV2ZWwgdGhlbiBtb3ZlIG9udG8gdGhlIG5leHQgbWF0Y2hcbiAgICAgICAgICAgICAgICBpZiAoIXNlcXVlbmNlTmFtZSAmJiBjYWxsYmFjay5zZXEgJiYgX3NlcXVlbmNlTGV2ZWxzW2NhbGxiYWNrLnNlcV0gIT0gY2FsbGJhY2subGV2ZWwpIHtcbiAgICAgICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgLy8gaWYgdGhlIGFjdGlvbiB3ZSBhcmUgbG9va2luZyBmb3IgZG9lc24ndCBtYXRjaCB0aGUgYWN0aW9uIHdlIGdvdFxuICAgICAgICAgICAgICAgIC8vIHRoZW4gd2Ugc2hvdWxkIGtlZXAgZ29pbmdcbiAgICAgICAgICAgICAgICBpZiAoYWN0aW9uICE9IGNhbGxiYWNrLmFjdGlvbikge1xuICAgICAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAvLyBpZiB0aGlzIGlzIGEga2V5cHJlc3MgZXZlbnQgYW5kIHRoZSBtZXRhIGtleSBhbmQgY29udHJvbCBrZXlcbiAgICAgICAgICAgICAgICAvLyBhcmUgbm90IHByZXNzZWQgdGhhdCBtZWFucyB0aGF0IHdlIG5lZWQgdG8gb25seSBsb29rIGF0IHRoZVxuICAgICAgICAgICAgICAgIC8vIGNoYXJhY3Rlciwgb3RoZXJ3aXNlIGNoZWNrIHRoZSBtb2RpZmllcnMgYXMgd2VsbFxuICAgICAgICAgICAgICAgIC8vXG4gICAgICAgICAgICAgICAgLy8gY2hyb21lIHdpbGwgbm90IGZpcmUgYSBrZXlwcmVzcyBpZiBtZXRhIG9yIGNvbnRyb2wgaXMgZG93blxuICAgICAgICAgICAgICAgIC8vIHNhZmFyaSB3aWxsIGZpcmUgYSBrZXlwcmVzcyBpZiBtZXRhIG9yIG1ldGErc2hpZnQgaXMgZG93blxuICAgICAgICAgICAgICAgIC8vIGZpcmVmb3ggd2lsbCBmaXJlIGEga2V5cHJlc3MgaWYgbWV0YSBvciBjb250cm9sIGlzIGRvd25cbiAgICAgICAgICAgICAgICBpZiAoKGFjdGlvbiA9PSAna2V5cHJlc3MnICYmICFlLm1ldGFLZXkgJiYgIWUuY3RybEtleSkgfHwgX21vZGlmaWVyc01hdGNoKG1vZGlmaWVycywgY2FsbGJhY2subW9kaWZpZXJzKSkge1xuXG4gICAgICAgICAgICAgICAgICAgIC8vIHdoZW4geW91IGJpbmQgYSBjb21iaW5hdGlvbiBvciBzZXF1ZW5jZSBhIHNlY29uZCB0aW1lIGl0XG4gICAgICAgICAgICAgICAgICAgIC8vIHNob3VsZCBvdmVyd3JpdGUgdGhlIGZpcnN0IG9uZS4gIGlmIGEgc2VxdWVuY2VOYW1lIG9yXG4gICAgICAgICAgICAgICAgICAgIC8vIGNvbWJpbmF0aW9uIGlzIHNwZWNpZmllZCBpbiB0aGlzIGNhbGwgaXQgZG9lcyBqdXN0IHRoYXRcbiAgICAgICAgICAgICAgICAgICAgLy9cbiAgICAgICAgICAgICAgICAgICAgLy8gQHRvZG8gbWFrZSBkZWxldGluZyBpdHMgb3duIG1ldGhvZD9cbiAgICAgICAgICAgICAgICAgICAgdmFyIGRlbGV0ZUNvbWJvID0gIXNlcXVlbmNlTmFtZSAmJiBjYWxsYmFjay5jb21ibyA9PSBjb21iaW5hdGlvbjtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGRlbGV0ZVNlcXVlbmNlID0gc2VxdWVuY2VOYW1lICYmIGNhbGxiYWNrLnNlcSA9PSBzZXF1ZW5jZU5hbWUgJiYgY2FsbGJhY2subGV2ZWwgPT0gbGV2ZWw7XG4gICAgICAgICAgICAgICAgICAgIGlmIChkZWxldGVDb21ibyB8fCBkZWxldGVTZXF1ZW5jZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5fY2FsbGJhY2tzW2NoYXJhY3Rlcl0uc3BsaWNlKGksIDEpO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgbWF0Y2hlcy5wdXNoKGNhbGxiYWNrKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiBtYXRjaGVzO1xuICAgICAgICB9XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIGFjdHVhbGx5IGNhbGxzIHRoZSBjYWxsYmFjayBmdW5jdGlvblxuICAgICAgICAgKlxuICAgICAgICAgKiBpZiB5b3VyIGNhbGxiYWNrIGZ1bmN0aW9uIHJldHVybnMgZmFsc2UgdGhpcyB3aWxsIHVzZSB0aGUganF1ZXJ5XG4gICAgICAgICAqIGNvbnZlbnRpb24gLSBwcmV2ZW50IGRlZmF1bHQgYW5kIHN0b3AgcHJvcG9nYXRpb24gb24gdGhlIGV2ZW50XG4gICAgICAgICAqXG4gICAgICAgICAqIEBwYXJhbSB7RnVuY3Rpb259IGNhbGxiYWNrXG4gICAgICAgICAqIEBwYXJhbSB7RXZlbnR9IGVcbiAgICAgICAgICogQHJldHVybnMgdm9pZFxuICAgICAgICAgKi9cbiAgICAgICAgZnVuY3Rpb24gX2ZpcmVDYWxsYmFjayhjYWxsYmFjaywgZSwgY29tYm8sIHNlcXVlbmNlKSB7XG5cbiAgICAgICAgICAgIC8vIGlmIHRoaXMgZXZlbnQgc2hvdWxkIG5vdCBoYXBwZW4gc3RvcCBoZXJlXG4gICAgICAgICAgICBpZiAoc2VsZi5zdG9wQ2FsbGJhY2soZSwgZS50YXJnZXQgfHwgZS5zcmNFbGVtZW50LCBjb21ibywgc2VxdWVuY2UpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoY2FsbGJhY2soZSwgY29tYm8pID09PSBmYWxzZSkge1xuICAgICAgICAgICAgICAgIF9wcmV2ZW50RGVmYXVsdChlKTtcbiAgICAgICAgICAgICAgICBfc3RvcFByb3BhZ2F0aW9uKGUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIGhhbmRsZXMgYSBjaGFyYWN0ZXIga2V5IGV2ZW50XG4gICAgICAgICAqXG4gICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBjaGFyYWN0ZXJcbiAgICAgICAgICogQHBhcmFtIHtBcnJheX0gbW9kaWZpZXJzXG4gICAgICAgICAqIEBwYXJhbSB7RXZlbnR9IGVcbiAgICAgICAgICogQHJldHVybnMgdm9pZFxuICAgICAgICAgKi9cbiAgICAgICAgc2VsZi5faGFuZGxlS2V5ID0gZnVuY3Rpb24oY2hhcmFjdGVyLCBtb2RpZmllcnMsIGUpIHtcbiAgICAgICAgICAgIHZhciBjYWxsYmFja3MgPSBfZ2V0TWF0Y2hlcyhjaGFyYWN0ZXIsIG1vZGlmaWVycywgZSk7XG4gICAgICAgICAgICB2YXIgaTtcbiAgICAgICAgICAgIHZhciBkb05vdFJlc2V0ID0ge307XG4gICAgICAgICAgICB2YXIgbWF4TGV2ZWwgPSAwO1xuICAgICAgICAgICAgdmFyIHByb2Nlc3NlZFNlcXVlbmNlQ2FsbGJhY2sgPSBmYWxzZTtcblxuICAgICAgICAgICAgLy8gQ2FsY3VsYXRlIHRoZSBtYXhMZXZlbCBmb3Igc2VxdWVuY2VzIHNvIHdlIGNhbiBvbmx5IGV4ZWN1dGUgdGhlIGxvbmdlc3QgY2FsbGJhY2sgc2VxdWVuY2VcbiAgICAgICAgICAgIGZvciAoaSA9IDA7IGkgPCBjYWxsYmFja3MubGVuZ3RoOyArK2kpIHtcbiAgICAgICAgICAgICAgICBpZiAoY2FsbGJhY2tzW2ldLnNlcSkge1xuICAgICAgICAgICAgICAgICAgICBtYXhMZXZlbCA9IE1hdGgubWF4KG1heExldmVsLCBjYWxsYmFja3NbaV0ubGV2ZWwpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gbG9vcCB0aHJvdWdoIG1hdGNoaW5nIGNhbGxiYWNrcyBmb3IgdGhpcyBrZXkgZXZlbnRcbiAgICAgICAgICAgIGZvciAoaSA9IDA7IGkgPCBjYWxsYmFja3MubGVuZ3RoOyArK2kpIHtcblxuICAgICAgICAgICAgICAgIC8vIGZpcmUgZm9yIGFsbCBzZXF1ZW5jZSBjYWxsYmFja3NcbiAgICAgICAgICAgICAgICAvLyB0aGlzIGlzIGJlY2F1c2UgaWYgZm9yIGV4YW1wbGUgeW91IGhhdmUgbXVsdGlwbGUgc2VxdWVuY2VzXG4gICAgICAgICAgICAgICAgLy8gYm91bmQgc3VjaCBhcyBcImcgaVwiIGFuZCBcImcgdFwiIHRoZXkgYm90aCBuZWVkIHRvIGZpcmUgdGhlXG4gICAgICAgICAgICAgICAgLy8gY2FsbGJhY2sgZm9yIG1hdGNoaW5nIGcgY2F1c2Ugb3RoZXJ3aXNlIHlvdSBjYW4gb25seSBldmVyXG4gICAgICAgICAgICAgICAgLy8gbWF0Y2ggdGhlIGZpcnN0IG9uZVxuICAgICAgICAgICAgICAgIGlmIChjYWxsYmFja3NbaV0uc2VxKSB7XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gb25seSBmaXJlIGNhbGxiYWNrcyBmb3IgdGhlIG1heExldmVsIHRvIHByZXZlbnRcbiAgICAgICAgICAgICAgICAgICAgLy8gc3Vic2VxdWVuY2VzIGZyb20gYWxzbyBmaXJpbmdcbiAgICAgICAgICAgICAgICAgICAgLy9cbiAgICAgICAgICAgICAgICAgICAgLy8gZm9yIGV4YW1wbGUgJ2Egb3B0aW9uIGInIHNob3VsZCBub3QgY2F1c2UgJ29wdGlvbiBiJyB0byBmaXJlXG4gICAgICAgICAgICAgICAgICAgIC8vIGV2ZW4gdGhvdWdoICdvcHRpb24gYicgaXMgcGFydCBvZiB0aGUgb3RoZXIgc2VxdWVuY2VcbiAgICAgICAgICAgICAgICAgICAgLy9cbiAgICAgICAgICAgICAgICAgICAgLy8gYW55IHNlcXVlbmNlcyB0aGF0IGRvIG5vdCBtYXRjaCBoZXJlIHdpbGwgYmUgZGlzY2FyZGVkXG4gICAgICAgICAgICAgICAgICAgIC8vIGJlbG93IGJ5IHRoZSBfcmVzZXRTZXF1ZW5jZXMgY2FsbFxuICAgICAgICAgICAgICAgICAgICBpZiAoY2FsbGJhY2tzW2ldLmxldmVsICE9IG1heExldmVsKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIHByb2Nlc3NlZFNlcXVlbmNlQ2FsbGJhY2sgPSB0cnVlO1xuXG4gICAgICAgICAgICAgICAgICAgIC8vIGtlZXAgYSBsaXN0IG9mIHdoaWNoIHNlcXVlbmNlcyB3ZXJlIG1hdGNoZXMgZm9yIGxhdGVyXG4gICAgICAgICAgICAgICAgICAgIGRvTm90UmVzZXRbY2FsbGJhY2tzW2ldLnNlcV0gPSAxO1xuICAgICAgICAgICAgICAgICAgICBfZmlyZUNhbGxiYWNrKGNhbGxiYWNrc1tpXS5jYWxsYmFjaywgZSwgY2FsbGJhY2tzW2ldLmNvbWJvLCBjYWxsYmFja3NbaV0uc2VxKTtcbiAgICAgICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgLy8gaWYgdGhlcmUgd2VyZSBubyBzZXF1ZW5jZSBtYXRjaGVzIGJ1dCB3ZSBhcmUgc3RpbGwgaGVyZVxuICAgICAgICAgICAgICAgIC8vIHRoYXQgbWVhbnMgdGhpcyBpcyBhIHJlZ3VsYXIgbWF0Y2ggc28gd2Ugc2hvdWxkIGZpcmUgdGhhdFxuICAgICAgICAgICAgICAgIGlmICghcHJvY2Vzc2VkU2VxdWVuY2VDYWxsYmFjaykge1xuICAgICAgICAgICAgICAgICAgICBfZmlyZUNhbGxiYWNrKGNhbGxiYWNrc1tpXS5jYWxsYmFjaywgZSwgY2FsbGJhY2tzW2ldLmNvbWJvKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIGlmIHRoZSBrZXkgeW91IHByZXNzZWQgbWF0Y2hlcyB0aGUgdHlwZSBvZiBzZXF1ZW5jZSB3aXRob3V0XG4gICAgICAgICAgICAvLyBiZWluZyBhIG1vZGlmaWVyIChpZSBcImtleXVwXCIgb3IgXCJrZXlwcmVzc1wiKSB0aGVuIHdlIHNob3VsZFxuICAgICAgICAgICAgLy8gcmVzZXQgYWxsIHNlcXVlbmNlcyB0aGF0IHdlcmUgbm90IG1hdGNoZWQgYnkgdGhpcyBldmVudFxuICAgICAgICAgICAgLy9cbiAgICAgICAgICAgIC8vIHRoaXMgaXMgc28sIGZvciBleGFtcGxlLCBpZiB5b3UgaGF2ZSB0aGUgc2VxdWVuY2UgXCJoIGEgdFwiIGFuZCB5b3VcbiAgICAgICAgICAgIC8vIHR5cGUgXCJoIGUgYSByIHRcIiBpdCBkb2VzIG5vdCBtYXRjaC4gIGluIHRoaXMgY2FzZSB0aGUgXCJlXCIgd2lsbFxuICAgICAgICAgICAgLy8gY2F1c2UgdGhlIHNlcXVlbmNlIHRvIHJlc2V0XG4gICAgICAgICAgICAvL1xuICAgICAgICAgICAgLy8gbW9kaWZpZXIga2V5cyBhcmUgaWdub3JlZCBiZWNhdXNlIHlvdSBjYW4gaGF2ZSBhIHNlcXVlbmNlXG4gICAgICAgICAgICAvLyB0aGF0IGNvbnRhaW5zIG1vZGlmaWVycyBzdWNoIGFzIFwiZW50ZXIgY3RybCtzcGFjZVwiIGFuZCBpbiBtb3N0XG4gICAgICAgICAgICAvLyBjYXNlcyB0aGUgbW9kaWZpZXIga2V5IHdpbGwgYmUgcHJlc3NlZCBiZWZvcmUgdGhlIG5leHQga2V5XG4gICAgICAgICAgICAvL1xuICAgICAgICAgICAgLy8gYWxzbyBpZiB5b3UgaGF2ZSBhIHNlcXVlbmNlIHN1Y2ggYXMgXCJjdHJsK2IgYVwiIHRoZW4gcHJlc3NpbmcgdGhlXG4gICAgICAgICAgICAvLyBcImJcIiBrZXkgd2lsbCB0cmlnZ2VyIGEgXCJrZXlwcmVzc1wiIGFuZCBhIFwia2V5ZG93blwiXG4gICAgICAgICAgICAvL1xuICAgICAgICAgICAgLy8gdGhlIFwia2V5ZG93blwiIGlzIGV4cGVjdGVkIHdoZW4gdGhlcmUgaXMgYSBtb2RpZmllciwgYnV0IHRoZVxuICAgICAgICAgICAgLy8gXCJrZXlwcmVzc1wiIGVuZHMgdXAgbWF0Y2hpbmcgdGhlIF9uZXh0RXhwZWN0ZWRBY3Rpb24gc2luY2UgaXQgb2NjdXJzXG4gICAgICAgICAgICAvLyBhZnRlciBhbmQgdGhhdCBjYXVzZXMgdGhlIHNlcXVlbmNlIHRvIHJlc2V0XG4gICAgICAgICAgICAvL1xuICAgICAgICAgICAgLy8gd2UgaWdub3JlIGtleXByZXNzZXMgaW4gYSBzZXF1ZW5jZSB0aGF0IGRpcmVjdGx5IGZvbGxvdyBhIGtleWRvd25cbiAgICAgICAgICAgIC8vIGZvciB0aGUgc2FtZSBjaGFyYWN0ZXJcbiAgICAgICAgICAgIHZhciBpZ25vcmVUaGlzS2V5cHJlc3MgPSBlLnR5cGUgPT0gJ2tleXByZXNzJyAmJiBfaWdub3JlTmV4dEtleXByZXNzO1xuICAgICAgICAgICAgaWYgKGUudHlwZSA9PSBfbmV4dEV4cGVjdGVkQWN0aW9uICYmICFfaXNNb2RpZmllcihjaGFyYWN0ZXIpICYmICFpZ25vcmVUaGlzS2V5cHJlc3MpIHtcbiAgICAgICAgICAgICAgICBfcmVzZXRTZXF1ZW5jZXMoZG9Ob3RSZXNldCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIF9pZ25vcmVOZXh0S2V5cHJlc3MgPSBwcm9jZXNzZWRTZXF1ZW5jZUNhbGxiYWNrICYmIGUudHlwZSA9PSAna2V5ZG93bic7XG4gICAgICAgIH07XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIGhhbmRsZXMgYSBrZXlkb3duIGV2ZW50XG4gICAgICAgICAqXG4gICAgICAgICAqIEBwYXJhbSB7RXZlbnR9IGVcbiAgICAgICAgICogQHJldHVybnMgdm9pZFxuICAgICAgICAgKi9cbiAgICAgICAgZnVuY3Rpb24gX2hhbmRsZUtleUV2ZW50KGUpIHtcblxuICAgICAgICAgICAgLy8gbm9ybWFsaXplIGUud2hpY2ggZm9yIGtleSBldmVudHNcbiAgICAgICAgICAgIC8vIEBzZWUgaHR0cDovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy80Mjg1NjI3L2phdmFzY3JpcHQta2V5Y29kZS12cy1jaGFyY29kZS11dHRlci1jb25mdXNpb25cbiAgICAgICAgICAgIGlmICh0eXBlb2YgZS53aGljaCAhPT0gJ251bWJlcicpIHtcbiAgICAgICAgICAgICAgICBlLndoaWNoID0gZS5rZXlDb2RlO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgY2hhcmFjdGVyID0gX2NoYXJhY3RlckZyb21FdmVudChlKTtcblxuICAgICAgICAgICAgLy8gbm8gY2hhcmFjdGVyIGZvdW5kIHRoZW4gc3RvcFxuICAgICAgICAgICAgaWYgKCFjaGFyYWN0ZXIpIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIG5lZWQgdG8gdXNlID09PSBmb3IgdGhlIGNoYXJhY3RlciBjaGVjayBiZWNhdXNlIHRoZSBjaGFyYWN0ZXIgY2FuIGJlIDBcbiAgICAgICAgICAgIGlmIChlLnR5cGUgPT0gJ2tleXVwJyAmJiBfaWdub3JlTmV4dEtleXVwID09PSBjaGFyYWN0ZXIpIHtcbiAgICAgICAgICAgICAgICBfaWdub3JlTmV4dEtleXVwID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBzZWxmLmhhbmRsZUtleShjaGFyYWN0ZXIsIF9ldmVudE1vZGlmaWVycyhlKSwgZSk7XG4gICAgICAgIH1cblxuICAgICAgICAvKipcbiAgICAgICAgICogY2FsbGVkIHRvIHNldCBhIDEgc2Vjb25kIHRpbWVvdXQgb24gdGhlIHNwZWNpZmllZCBzZXF1ZW5jZVxuICAgICAgICAgKlxuICAgICAgICAgKiB0aGlzIGlzIHNvIGFmdGVyIGVhY2gga2V5IHByZXNzIGluIHRoZSBzZXF1ZW5jZSB5b3UgaGF2ZSAxIHNlY29uZFxuICAgICAgICAgKiB0byBwcmVzcyB0aGUgbmV4dCBrZXkgYmVmb3JlIHlvdSBoYXZlIHRvIHN0YXJ0IG92ZXJcbiAgICAgICAgICpcbiAgICAgICAgICogQHJldHVybnMgdm9pZFxuICAgICAgICAgKi9cbiAgICAgICAgZnVuY3Rpb24gX3Jlc2V0U2VxdWVuY2VUaW1lcigpIHtcbiAgICAgICAgICAgIGNsZWFyVGltZW91dChfcmVzZXRUaW1lcik7XG4gICAgICAgICAgICBfcmVzZXRUaW1lciA9IHNldFRpbWVvdXQoX3Jlc2V0U2VxdWVuY2VzLCAxMDAwKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBiaW5kcyBhIGtleSBzZXF1ZW5jZSB0byBhbiBldmVudFxuICAgICAgICAgKlxuICAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gY29tYm8gLSBjb21ibyBzcGVjaWZpZWQgaW4gYmluZCBjYWxsXG4gICAgICAgICAqIEBwYXJhbSB7QXJyYXl9IGtleXNcbiAgICAgICAgICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2tcbiAgICAgICAgICogQHBhcmFtIHtzdHJpbmc9fSBhY3Rpb25cbiAgICAgICAgICogQHJldHVybnMgdm9pZFxuICAgICAgICAgKi9cbiAgICAgICAgZnVuY3Rpb24gX2JpbmRTZXF1ZW5jZShjb21ibywga2V5cywgY2FsbGJhY2ssIGFjdGlvbikge1xuXG4gICAgICAgICAgICAvLyBzdGFydCBvZmYgYnkgYWRkaW5nIGEgc2VxdWVuY2UgbGV2ZWwgcmVjb3JkIGZvciB0aGlzIGNvbWJpbmF0aW9uXG4gICAgICAgICAgICAvLyBhbmQgc2V0dGluZyB0aGUgbGV2ZWwgdG8gMFxuICAgICAgICAgICAgX3NlcXVlbmNlTGV2ZWxzW2NvbWJvXSA9IDA7XG5cbiAgICAgICAgICAgIC8qKlxuICAgICAgICAgICAgICogY2FsbGJhY2sgdG8gaW5jcmVhc2UgdGhlIHNlcXVlbmNlIGxldmVsIGZvciB0aGlzIHNlcXVlbmNlIGFuZCByZXNldFxuICAgICAgICAgICAgICogYWxsIG90aGVyIHNlcXVlbmNlcyB0aGF0IHdlcmUgYWN0aXZlXG4gICAgICAgICAgICAgKlxuICAgICAgICAgICAgICogQHBhcmFtIHtzdHJpbmd9IG5leHRBY3Rpb25cbiAgICAgICAgICAgICAqIEByZXR1cm5zIHtGdW5jdGlvbn1cbiAgICAgICAgICAgICAqL1xuICAgICAgICAgICAgZnVuY3Rpb24gX2luY3JlYXNlU2VxdWVuY2UobmV4dEFjdGlvbikge1xuICAgICAgICAgICAgICAgIHJldHVybiBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgICAgICAgICAgX25leHRFeHBlY3RlZEFjdGlvbiA9IG5leHRBY3Rpb247XG4gICAgICAgICAgICAgICAgICAgICsrX3NlcXVlbmNlTGV2ZWxzW2NvbWJvXTtcbiAgICAgICAgICAgICAgICAgICAgX3Jlc2V0U2VxdWVuY2VUaW1lcigpO1xuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8qKlxuICAgICAgICAgICAgICogd3JhcHMgdGhlIHNwZWNpZmllZCBjYWxsYmFjayBpbnNpZGUgb2YgYW5vdGhlciBmdW5jdGlvbiBpbiBvcmRlclxuICAgICAgICAgICAgICogdG8gcmVzZXQgYWxsIHNlcXVlbmNlIGNvdW50ZXJzIGFzIHNvb24gYXMgdGhpcyBzZXF1ZW5jZSBpcyBkb25lXG4gICAgICAgICAgICAgKlxuICAgICAgICAgICAgICogQHBhcmFtIHtFdmVudH0gZVxuICAgICAgICAgICAgICogQHJldHVybnMgdm9pZFxuICAgICAgICAgICAgICovXG4gICAgICAgICAgICBmdW5jdGlvbiBfY2FsbGJhY2tBbmRSZXNldChlKSB7XG4gICAgICAgICAgICAgICAgX2ZpcmVDYWxsYmFjayhjYWxsYmFjaywgZSwgY29tYm8pO1xuXG4gICAgICAgICAgICAgICAgLy8gd2Ugc2hvdWxkIGlnbm9yZSB0aGUgbmV4dCBrZXkgdXAgaWYgdGhlIGFjdGlvbiBpcyBrZXkgZG93blxuICAgICAgICAgICAgICAgIC8vIG9yIGtleXByZXNzLiAgdGhpcyBpcyBzbyBpZiB5b3UgZmluaXNoIGEgc2VxdWVuY2UgYW5kXG4gICAgICAgICAgICAgICAgLy8gcmVsZWFzZSB0aGUga2V5IHRoZSBmaW5hbCBrZXkgd2lsbCBub3QgdHJpZ2dlciBhIGtleXVwXG4gICAgICAgICAgICAgICAgaWYgKGFjdGlvbiAhPT0gJ2tleXVwJykge1xuICAgICAgICAgICAgICAgICAgICBfaWdub3JlTmV4dEtleXVwID0gX2NoYXJhY3RlckZyb21FdmVudChlKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAvLyB3ZWlyZCByYWNlIGNvbmRpdGlvbiBpZiBhIHNlcXVlbmNlIGVuZHMgd2l0aCB0aGUga2V5XG4gICAgICAgICAgICAgICAgLy8gYW5vdGhlciBzZXF1ZW5jZSBiZWdpbnMgd2l0aFxuICAgICAgICAgICAgICAgIHNldFRpbWVvdXQoX3Jlc2V0U2VxdWVuY2VzLCAxMCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIGxvb3AgdGhyb3VnaCBrZXlzIG9uZSBhdCBhIHRpbWUgYW5kIGJpbmQgdGhlIGFwcHJvcHJpYXRlIGNhbGxiYWNrXG4gICAgICAgICAgICAvLyBmdW5jdGlvbi4gIGZvciBhbnkga2V5IGxlYWRpbmcgdXAgdG8gdGhlIGZpbmFsIG9uZSBpdCBzaG91bGRcbiAgICAgICAgICAgIC8vIGluY3JlYXNlIHRoZSBzZXF1ZW5jZS4gYWZ0ZXIgdGhlIGZpbmFsLCBpdCBzaG91bGQgcmVzZXQgYWxsIHNlcXVlbmNlc1xuICAgICAgICAgICAgLy9cbiAgICAgICAgICAgIC8vIGlmIGFuIGFjdGlvbiBpcyBzcGVjaWZpZWQgaW4gdGhlIG9yaWdpbmFsIGJpbmQgY2FsbCB0aGVuIHRoYXQgd2lsbFxuICAgICAgICAgICAgLy8gYmUgdXNlZCB0aHJvdWdob3V0LiAgb3RoZXJ3aXNlIHdlIHdpbGwgcGFzcyB0aGUgYWN0aW9uIHRoYXQgdGhlXG4gICAgICAgICAgICAvLyBuZXh0IGtleSBpbiB0aGUgc2VxdWVuY2Ugc2hvdWxkIG1hdGNoLiAgdGhpcyBhbGxvd3MgYSBzZXF1ZW5jZVxuICAgICAgICAgICAgLy8gdG8gbWl4IGFuZCBtYXRjaCBrZXlwcmVzcyBhbmQga2V5ZG93biBldmVudHMgZGVwZW5kaW5nIG9uIHdoaWNoXG4gICAgICAgICAgICAvLyBvbmVzIGFyZSBiZXR0ZXIgc3VpdGVkIHRvIHRoZSBrZXkgcHJvdmlkZWRcbiAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwga2V5cy5sZW5ndGg7ICsraSkge1xuICAgICAgICAgICAgICAgIHZhciBpc0ZpbmFsID0gaSArIDEgPT09IGtleXMubGVuZ3RoO1xuICAgICAgICAgICAgICAgIHZhciB3cmFwcGVkQ2FsbGJhY2sgPSBpc0ZpbmFsID8gX2NhbGxiYWNrQW5kUmVzZXQgOiBfaW5jcmVhc2VTZXF1ZW5jZShhY3Rpb24gfHwgX2dldEtleUluZm8oa2V5c1tpICsgMV0pLmFjdGlvbik7XG4gICAgICAgICAgICAgICAgX2JpbmRTaW5nbGUoa2V5c1tpXSwgd3JhcHBlZENhbGxiYWNrLCBhY3Rpb24sIGNvbWJvLCBpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBiaW5kcyBhIHNpbmdsZSBrZXlib2FyZCBjb21iaW5hdGlvblxuICAgICAgICAgKlxuICAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gY29tYmluYXRpb25cbiAgICAgICAgICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2tcbiAgICAgICAgICogQHBhcmFtIHtzdHJpbmc9fSBhY3Rpb25cbiAgICAgICAgICogQHBhcmFtIHtzdHJpbmc9fSBzZXF1ZW5jZU5hbWUgLSBuYW1lIG9mIHNlcXVlbmNlIGlmIHBhcnQgb2Ygc2VxdWVuY2VcbiAgICAgICAgICogQHBhcmFtIHtudW1iZXI9fSBsZXZlbCAtIHdoYXQgcGFydCBvZiB0aGUgc2VxdWVuY2UgdGhlIGNvbW1hbmQgaXNcbiAgICAgICAgICogQHJldHVybnMgdm9pZFxuICAgICAgICAgKi9cbiAgICAgICAgZnVuY3Rpb24gX2JpbmRTaW5nbGUoY29tYmluYXRpb24sIGNhbGxiYWNrLCBhY3Rpb24sIHNlcXVlbmNlTmFtZSwgbGV2ZWwpIHtcblxuICAgICAgICAgICAgLy8gc3RvcmUgYSBkaXJlY3QgbWFwcGVkIHJlZmVyZW5jZSBmb3IgdXNlIHdpdGggTW91c2V0cmFwLnRyaWdnZXJcbiAgICAgICAgICAgIHNlbGYuX2RpcmVjdE1hcFtjb21iaW5hdGlvbiArICc6JyArIGFjdGlvbl0gPSBjYWxsYmFjaztcblxuICAgICAgICAgICAgLy8gbWFrZSBzdXJlIG11bHRpcGxlIHNwYWNlcyBpbiBhIHJvdyBiZWNvbWUgYSBzaW5nbGUgc3BhY2VcbiAgICAgICAgICAgIGNvbWJpbmF0aW9uID0gY29tYmluYXRpb24ucmVwbGFjZSgvXFxzKy9nLCAnICcpO1xuXG4gICAgICAgICAgICB2YXIgc2VxdWVuY2UgPSBjb21iaW5hdGlvbi5zcGxpdCgnICcpO1xuICAgICAgICAgICAgdmFyIGluZm87XG5cbiAgICAgICAgICAgIC8vIGlmIHRoaXMgcGF0dGVybiBpcyBhIHNlcXVlbmNlIG9mIGtleXMgdGhlbiBydW4gdGhyb3VnaCB0aGlzIG1ldGhvZFxuICAgICAgICAgICAgLy8gdG8gcmVwcm9jZXNzIGVhY2ggcGF0dGVybiBvbmUga2V5IGF0IGEgdGltZVxuICAgICAgICAgICAgaWYgKHNlcXVlbmNlLmxlbmd0aCA+IDEpIHtcbiAgICAgICAgICAgICAgICBfYmluZFNlcXVlbmNlKGNvbWJpbmF0aW9uLCBzZXF1ZW5jZSwgY2FsbGJhY2ssIGFjdGlvbik7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpbmZvID0gX2dldEtleUluZm8oY29tYmluYXRpb24sIGFjdGlvbik7XG5cbiAgICAgICAgICAgIC8vIG1ha2Ugc3VyZSB0byBpbml0aWFsaXplIGFycmF5IGlmIHRoaXMgaXMgdGhlIGZpcnN0IHRpbWVcbiAgICAgICAgICAgIC8vIGEgY2FsbGJhY2sgaXMgYWRkZWQgZm9yIHRoaXMga2V5XG4gICAgICAgICAgICBzZWxmLl9jYWxsYmFja3NbaW5mby5rZXldID0gc2VsZi5fY2FsbGJhY2tzW2luZm8ua2V5XSB8fCBbXTtcblxuICAgICAgICAgICAgLy8gcmVtb3ZlIGFuIGV4aXN0aW5nIG1hdGNoIGlmIHRoZXJlIGlzIG9uZVxuICAgICAgICAgICAgX2dldE1hdGNoZXMoaW5mby5rZXksIGluZm8ubW9kaWZpZXJzLCB7dHlwZTogaW5mby5hY3Rpb259LCBzZXF1ZW5jZU5hbWUsIGNvbWJpbmF0aW9uLCBsZXZlbCk7XG5cbiAgICAgICAgICAgIC8vIGFkZCB0aGlzIGNhbGwgYmFjayB0byB0aGUgYXJyYXlcbiAgICAgICAgICAgIC8vIGlmIGl0IGlzIGEgc2VxdWVuY2UgcHV0IGl0IGF0IHRoZSBiZWdpbm5pbmdcbiAgICAgICAgICAgIC8vIGlmIG5vdCBwdXQgaXQgYXQgdGhlIGVuZFxuICAgICAgICAgICAgLy9cbiAgICAgICAgICAgIC8vIHRoaXMgaXMgaW1wb3J0YW50IGJlY2F1c2UgdGhlIHdheSB0aGVzZSBhcmUgcHJvY2Vzc2VkIGV4cGVjdHNcbiAgICAgICAgICAgIC8vIHRoZSBzZXF1ZW5jZSBvbmVzIHRvIGNvbWUgZmlyc3RcbiAgICAgICAgICAgIHNlbGYuX2NhbGxiYWNrc1tpbmZvLmtleV1bc2VxdWVuY2VOYW1lID8gJ3Vuc2hpZnQnIDogJ3B1c2gnXSh7XG4gICAgICAgICAgICAgICAgY2FsbGJhY2s6IGNhbGxiYWNrLFxuICAgICAgICAgICAgICAgIG1vZGlmaWVyczogaW5mby5tb2RpZmllcnMsXG4gICAgICAgICAgICAgICAgYWN0aW9uOiBpbmZvLmFjdGlvbixcbiAgICAgICAgICAgICAgICBzZXE6IHNlcXVlbmNlTmFtZSxcbiAgICAgICAgICAgICAgICBsZXZlbDogbGV2ZWwsXG4gICAgICAgICAgICAgICAgY29tYm86IGNvbWJpbmF0aW9uXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBiaW5kcyBtdWx0aXBsZSBjb21iaW5hdGlvbnMgdG8gdGhlIHNhbWUgY2FsbGJhY2tcbiAgICAgICAgICpcbiAgICAgICAgICogQHBhcmFtIHtBcnJheX0gY29tYmluYXRpb25zXG4gICAgICAgICAqIEBwYXJhbSB7RnVuY3Rpb259IGNhbGxiYWNrXG4gICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfHVuZGVmaW5lZH0gYWN0aW9uXG4gICAgICAgICAqIEByZXR1cm5zIHZvaWRcbiAgICAgICAgICovXG4gICAgICAgIHNlbGYuX2JpbmRNdWx0aXBsZSA9IGZ1bmN0aW9uKGNvbWJpbmF0aW9ucywgY2FsbGJhY2ssIGFjdGlvbikge1xuICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBjb21iaW5hdGlvbnMubGVuZ3RoOyArK2kpIHtcbiAgICAgICAgICAgICAgICBfYmluZFNpbmdsZShjb21iaW5hdGlvbnNbaV0sIGNhbGxiYWNrLCBhY3Rpb24pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuXG4gICAgICAgIC8vIHN0YXJ0IVxuICAgICAgICBfYWRkRXZlbnQodGFyZ2V0RWxlbWVudCwgJ2tleXByZXNzJywgX2hhbmRsZUtleUV2ZW50KTtcbiAgICAgICAgX2FkZEV2ZW50KHRhcmdldEVsZW1lbnQsICdrZXlkb3duJywgX2hhbmRsZUtleUV2ZW50KTtcbiAgICAgICAgX2FkZEV2ZW50KHRhcmdldEVsZW1lbnQsICdrZXl1cCcsIF9oYW5kbGVLZXlFdmVudCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogYmluZHMgYW4gZXZlbnQgdG8gbW91c2V0cmFwXG4gICAgICpcbiAgICAgKiBjYW4gYmUgYSBzaW5nbGUga2V5LCBhIGNvbWJpbmF0aW9uIG9mIGtleXMgc2VwYXJhdGVkIHdpdGggKyxcbiAgICAgKiBhbiBhcnJheSBvZiBrZXlzLCBvciBhIHNlcXVlbmNlIG9mIGtleXMgc2VwYXJhdGVkIGJ5IHNwYWNlc1xuICAgICAqXG4gICAgICogYmUgc3VyZSB0byBsaXN0IHRoZSBtb2RpZmllciBrZXlzIGZpcnN0IHRvIG1ha2Ugc3VyZSB0aGF0IHRoZVxuICAgICAqIGNvcnJlY3Qga2V5IGVuZHMgdXAgZ2V0dGluZyBib3VuZCAodGhlIGxhc3Qga2V5IGluIHRoZSBwYXR0ZXJuKVxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd8QXJyYXl9IGtleXNcbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBjYWxsYmFja1xuICAgICAqIEBwYXJhbSB7c3RyaW5nPX0gYWN0aW9uIC0gJ2tleXByZXNzJywgJ2tleWRvd24nLCBvciAna2V5dXAnXG4gICAgICogQHJldHVybnMgdm9pZFxuICAgICAqL1xuICAgIE1vdXNldHJhcC5wcm90b3R5cGUuYmluZCA9IGZ1bmN0aW9uKGtleXMsIGNhbGxiYWNrLCBhY3Rpb24pIHtcbiAgICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgICAgICBrZXlzID0ga2V5cyBpbnN0YW5jZW9mIEFycmF5ID8ga2V5cyA6IFtrZXlzXTtcbiAgICAgICAgc2VsZi5fYmluZE11bHRpcGxlLmNhbGwoc2VsZiwga2V5cywgY2FsbGJhY2ssIGFjdGlvbik7XG4gICAgICAgIHJldHVybiBzZWxmO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiB1bmJpbmRzIGFuIGV2ZW50IHRvIG1vdXNldHJhcFxuICAgICAqXG4gICAgICogdGhlIHVuYmluZGluZyBzZXRzIHRoZSBjYWxsYmFjayBmdW5jdGlvbiBvZiB0aGUgc3BlY2lmaWVkIGtleSBjb21ib1xuICAgICAqIHRvIGFuIGVtcHR5IGZ1bmN0aW9uIGFuZCBkZWxldGVzIHRoZSBjb3JyZXNwb25kaW5nIGtleSBpbiB0aGVcbiAgICAgKiBfZGlyZWN0TWFwIGRpY3QuXG4gICAgICpcbiAgICAgKiBUT0RPOiBhY3R1YWxseSByZW1vdmUgdGhpcyBmcm9tIHRoZSBfY2FsbGJhY2tzIGRpY3Rpb25hcnkgaW5zdGVhZFxuICAgICAqIG9mIGJpbmRpbmcgYW4gZW1wdHkgZnVuY3Rpb25cbiAgICAgKlxuICAgICAqIHRoZSBrZXljb21ibythY3Rpb24gaGFzIHRvIGJlIGV4YWN0bHkgdGhlIHNhbWUgYXNcbiAgICAgKiBpdCB3YXMgZGVmaW5lZCBpbiB0aGUgYmluZCBtZXRob2RcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfEFycmF5fSBrZXlzXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGFjdGlvblxuICAgICAqIEByZXR1cm5zIHZvaWRcbiAgICAgKi9cbiAgICBNb3VzZXRyYXAucHJvdG90eXBlLnVuYmluZCA9IGZ1bmN0aW9uKGtleXMsIGFjdGlvbikge1xuICAgICAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgICAgIHJldHVybiBzZWxmLmJpbmQuY2FsbChzZWxmLCBrZXlzLCBmdW5jdGlvbigpIHt9LCBhY3Rpb24pO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiB0cmlnZ2VycyBhbiBldmVudCB0aGF0IGhhcyBhbHJlYWR5IGJlZW4gYm91bmRcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBrZXlzXG4gICAgICogQHBhcmFtIHtzdHJpbmc9fSBhY3Rpb25cbiAgICAgKiBAcmV0dXJucyB2b2lkXG4gICAgICovXG4gICAgTW91c2V0cmFwLnByb3RvdHlwZS50cmlnZ2VyID0gZnVuY3Rpb24oa2V5cywgYWN0aW9uKSB7XG4gICAgICAgIHZhciBzZWxmID0gdGhpcztcbiAgICAgICAgaWYgKHNlbGYuX2RpcmVjdE1hcFtrZXlzICsgJzonICsgYWN0aW9uXSkge1xuICAgICAgICAgICAgc2VsZi5fZGlyZWN0TWFwW2tleXMgKyAnOicgKyBhY3Rpb25dKHt9LCBrZXlzKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gc2VsZjtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogcmVzZXRzIHRoZSBsaWJyYXJ5IGJhY2sgdG8gaXRzIGluaXRpYWwgc3RhdGUuICB0aGlzIGlzIHVzZWZ1bFxuICAgICAqIGlmIHlvdSB3YW50IHRvIGNsZWFyIG91dCB0aGUgY3VycmVudCBrZXlib2FyZCBzaG9ydGN1dHMgYW5kIGJpbmRcbiAgICAgKiBuZXcgb25lcyAtIGZvciBleGFtcGxlIGlmIHlvdSBzd2l0Y2ggdG8gYW5vdGhlciBwYWdlXG4gICAgICpcbiAgICAgKiBAcmV0dXJucyB2b2lkXG4gICAgICovXG4gICAgTW91c2V0cmFwLnByb3RvdHlwZS5yZXNldCA9IGZ1bmN0aW9uKCkge1xuICAgICAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgICAgIHNlbGYuX2NhbGxiYWNrcyA9IHt9O1xuICAgICAgICBzZWxmLl9kaXJlY3RNYXAgPSB7fTtcbiAgICAgICAgcmV0dXJuIHNlbGY7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIHNob3VsZCB3ZSBzdG9wIHRoaXMgZXZlbnQgYmVmb3JlIGZpcmluZyBvZmYgY2FsbGJhY2tzXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge0V2ZW50fSBlXG4gICAgICogQHBhcmFtIHtFbGVtZW50fSBlbGVtZW50XG4gICAgICogQHJldHVybiB7Ym9vbGVhbn1cbiAgICAgKi9cbiAgICBNb3VzZXRyYXAucHJvdG90eXBlLnN0b3BDYWxsYmFjayA9IGZ1bmN0aW9uKGUsIGVsZW1lbnQpIHtcbiAgICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuXG4gICAgICAgIC8vIGlmIHRoZSBlbGVtZW50IGhhcyB0aGUgY2xhc3MgXCJtb3VzZXRyYXBcIiB0aGVuIG5vIG5lZWQgdG8gc3RvcFxuICAgICAgICBpZiAoKCcgJyArIGVsZW1lbnQuY2xhc3NOYW1lICsgJyAnKS5pbmRleE9mKCcgbW91c2V0cmFwICcpID4gLTEpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChfYmVsb25nc1RvKGVsZW1lbnQsIHNlbGYudGFyZ2V0KSkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gc3RvcCBmb3IgaW5wdXQsIHNlbGVjdCwgYW5kIHRleHRhcmVhXG4gICAgICAgIHJldHVybiBlbGVtZW50LnRhZ05hbWUgPT0gJ0lOUFVUJyB8fCBlbGVtZW50LnRhZ05hbWUgPT0gJ1NFTEVDVCcgfHwgZWxlbWVudC50YWdOYW1lID09ICdURVhUQVJFQScgfHwgZWxlbWVudC5pc0NvbnRlbnRFZGl0YWJsZTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogZXhwb3NlcyBfaGFuZGxlS2V5IHB1YmxpY2x5IHNvIGl0IGNhbiBiZSBvdmVyd3JpdHRlbiBieSBleHRlbnNpb25zXG4gICAgICovXG4gICAgTW91c2V0cmFwLnByb3RvdHlwZS5oYW5kbGVLZXkgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgICAgICByZXR1cm4gc2VsZi5faGFuZGxlS2V5LmFwcGx5KHNlbGYsIGFyZ3VtZW50cyk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIGFsbG93IGN1c3RvbSBrZXkgbWFwcGluZ3NcbiAgICAgKi9cbiAgICBNb3VzZXRyYXAuYWRkS2V5Y29kZXMgPSBmdW5jdGlvbihvYmplY3QpIHtcbiAgICAgICAgZm9yICh2YXIga2V5IGluIG9iamVjdCkge1xuICAgICAgICAgICAgaWYgKG9iamVjdC5oYXNPd25Qcm9wZXJ0eShrZXkpKSB7XG4gICAgICAgICAgICAgICAgX01BUFtrZXldID0gb2JqZWN0W2tleV07XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgX1JFVkVSU0VfTUFQID0gbnVsbDtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogSW5pdCB0aGUgZ2xvYmFsIG1vdXNldHJhcCBmdW5jdGlvbnNcbiAgICAgKlxuICAgICAqIFRoaXMgbWV0aG9kIGlzIG5lZWRlZCB0byBhbGxvdyB0aGUgZ2xvYmFsIG1vdXNldHJhcCBmdW5jdGlvbnMgdG8gd29ya1xuICAgICAqIG5vdyB0aGF0IG1vdXNldHJhcCBpcyBhIGNvbnN0cnVjdG9yIGZ1bmN0aW9uLlxuICAgICAqL1xuICAgIE1vdXNldHJhcC5pbml0ID0gZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciBkb2N1bWVudE1vdXNldHJhcCA9IE1vdXNldHJhcChkb2N1bWVudCk7XG4gICAgICAgIGZvciAodmFyIG1ldGhvZCBpbiBkb2N1bWVudE1vdXNldHJhcCkge1xuICAgICAgICAgICAgaWYgKG1ldGhvZC5jaGFyQXQoMCkgIT09ICdfJykge1xuICAgICAgICAgICAgICAgIE1vdXNldHJhcFttZXRob2RdID0gKGZ1bmN0aW9uKG1ldGhvZCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZG9jdW1lbnRNb3VzZXRyYXBbbWV0aG9kXS5hcHBseShkb2N1bWVudE1vdXNldHJhcCwgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICB9IChtZXRob2QpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBNb3VzZXRyYXAuaW5pdCgpO1xuXG4gICAgLy8gZXhwb3NlIG1vdXNldHJhcCB0byB0aGUgZ2xvYmFsIG9iamVjdFxuICAgIHdpbmRvdy5Nb3VzZXRyYXAgPSBNb3VzZXRyYXA7XG5cbiAgICAvLyBleHBvc2UgYXMgYSBjb21tb24ganMgbW9kdWxlXG4gICAgaWYgKHR5cGVvZiBtb2R1bGUgIT09ICd1bmRlZmluZWQnICYmIG1vZHVsZS5leHBvcnRzKSB7XG4gICAgICAgIG1vZHVsZS5leHBvcnRzID0gTW91c2V0cmFwO1xuICAgIH1cblxuICAgIC8vIGV4cG9zZSBtb3VzZXRyYXAgYXMgYW4gQU1EIG1vZHVsZVxuICAgIGlmICh0eXBlb2YgZGVmaW5lID09PSAnZnVuY3Rpb24nICYmIGRlZmluZS5hbWQpIHtcbiAgICAgICAgZGVmaW5lKGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgcmV0dXJuIE1vdXNldHJhcDtcbiAgICAgICAgfSk7XG4gICAgfVxufSkgKHR5cGVvZiB3aW5kb3cgIT09ICd1bmRlZmluZWQnID8gd2luZG93IDogbnVsbCwgdHlwZW9mICB3aW5kb3cgIT09ICd1bmRlZmluZWQnID8gZG9jdW1lbnQgOiBudWxsKTtcbiIsIjtcbihmdW5jdGlvbiAoKSB7XG4gICd1c2Ugc3RyaWN0JztcblxuICAvLyByZWdpc3RlcnMgdGhlIGV4dGVuc2lvbiBvbiBhIGN5dG9zY2FwZSBsaWIgcmVmXG4gIHZhciByZWdpc3RlciA9IGZ1bmN0aW9uIChjeXRvc2NhcGUsICQpIHtcblxuICAgIGlmICghY3l0b3NjYXBlIHx8ICEkKSB7XG4gICAgICByZXR1cm47XG4gICAgfSAvLyBjYW4ndCByZWdpc3RlciBpZiBjeXRvc2NhcGUgdW5zcGVjaWZpZWRcblxuICAgIHZhciBvcHRpb25zID0ge1xuICAgICAgbm9kZToge1xuICAgICAgICBoaWdobGlnaHRlZDoge30sIC8vIHN0eWxlcyBmb3Igd2hlbiBub2RlcyBhcmUgaGlnaGxpZ2h0ZWQuXG4gICAgICAgIHVuaGlnaGxpZ2h0ZWQ6IHsvLyBzdHlsZXMgZm9yIHdoZW4gbm9kZXMgYXJlIHVuaGlnaGxpZ2h0ZWQuXG4gICAgICAgICAgJ29wYWNpdHknOiAwLjNcbiAgICAgICAgfVxuICAgICAgfSxcbiAgICAgIGVkZ2U6IHtcbiAgICAgICAgaGlnaGxpZ2h0ZWQ6IHt9LCAvLyBzdHlsZXMgZm9yIHdoZW4gZWRnZXMgYXJlIGhpZ2hsaWdodGVkLlxuICAgICAgICB1bmhpZ2hsaWdodGVkOiB7Ly8gc3R5bGVzIGZvciB3aGVuIGVkZ2VzIGFyZSB1bmhpZ2hsaWdodGVkLlxuICAgICAgICAgICdvcGFjaXR5JzogMC4zXG4gICAgICAgIH1cbiAgICAgIH0sXG4gICAgICBzZXRWaXNpYmlsaXR5T25IaWRlOiBmYWxzZSwgLy8gd2hldGhlciB0byBzZXQgdmlzaWJpbGl0eSBvbiBoaWRlL3Nob3dcbiAgICAgIHNldERpc3BsYXlPbkhpZGU6IHRydWUsIC8vIHdoZXRoZXIgdG8gc2V0IGRpc3BsYXkgb24gaGlkZS9zaG93XG4gICAgICBuZWlnaGJvcjogZnVuY3Rpb24obm9kZSl7IC8vIHJldHVybiBkZXNpcmVkIG5laWdoYm9ycyBvZiB0YXBoZWxkIG5vZGVcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgfSxcbiAgICAgIG5laWdoYm9yU2VsZWN0VGltZTogNTAwIC8vbXMsIHRpbWUgdG8gdGFwaG9sZCB0byBzZWxlY3QgZGVzaXJlZCBuZWlnaGJvcnMgXG4gICAgfTtcblxuXG4gICAgdmFyIHVuZG9SZWRvID0gcmVxdWlyZShcIi4vdW5kby1yZWRvXCIpO1xuICAgIHZhciB2aWV3VXRpbGl0aWVzID0gcmVxdWlyZShcIi4vdmlldy11dGlsaXRpZXNcIik7XG4gICAgdmFyIE1vdXNldHJhcCA9IHJlcXVpcmUoJ21vdXNldHJhcCcpO1xuICAgIFxuICAgIGN5dG9zY2FwZSgnY29yZScsICd2aWV3VXRpbGl0aWVzJywgZnVuY3Rpb24gKG9wdHMpIHtcbiAgICAgIHZhciBjeSA9IHRoaXM7XG5cbiAgICAgIGlmIChvcHRzID09PSAnZ2V0Jykge1xuICAgICAgICByZXR1cm4gdmlld1V0aWxpdGllcztcbiAgICAgIH1cblxuICAgICAgJC5leHRlbmQodHJ1ZSwgb3B0aW9ucywgb3B0cyk7XG5cbiAgICAgIGZ1bmN0aW9uIGdldFNjcmF0Y2goZWxlT3JDeSkge1xuICAgICAgICBpZiAoIWVsZU9yQ3kuc2NyYXRjaChcIl92aWV3VXRpbGl0aWVzXCIpKSB7XG4gICAgICAgICAgZWxlT3JDeS5zY3JhdGNoKFwiX3ZpZXdVdGlsaXRpZXNcIiwge30pO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGVsZU9yQ3kuc2NyYXRjaChcIl92aWV3VXRpbGl0aWVzXCIpO1xuICAgICAgfVxuXG4gICAgICBpZiAoIWdldFNjcmF0Y2goY3kpLmluaXRpYWxpemVkKSB7XG4gICAgICAgIGdldFNjcmF0Y2goY3kpLmluaXRpYWxpemVkID0gdHJ1ZTsgIFxuXG4gICAgICAgIHZpZXdVdGlsaXRpZXMoY3ksIG9wdGlvbnMpO1xuICAgICAgICBcbiAgICAgICAgaWYgKGN5LnVuZG9SZWRvKSB7XG4gICAgICAgICAgdmFyIHVyID0gY3kudW5kb1JlZG8obnVsbCwgdHJ1ZSk7XG4gICAgICAgICAgdW5kb1JlZG8oY3ksIHVyLCB2aWV3VXRpbGl0aWVzKTtcbiAgICAgICAgfVxuICAgICAgICBcbiAgICAgICAgdmFyIG10ID0gbmV3IE1vdXNldHJhcCgpO1xuICAgICAgICB2YXIgc2hpZnRLZXlEb3duID0gZmFsc2U7XG4gICAgICAgIG10LmJpbmQoW1wic2hpZnRcIl0sIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHNoaWZ0S2V5RG93biA9IHRydWU7XG4gICAgICAgIH0sIFwia2V5ZG93blwiKTtcbiAgICAgICAgbXQuYmluZChbXCJzaGlmdFwiXSwgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgc2hpZnRLZXlEb3duID0gZmFsc2U7XG4gICAgICAgIH0sIFwia2V5dXBcIik7XG4gICAgICAgIC8vU2VsZWN0IHRoZSBkZXNpcmVkIG5laWdoYm9ycyBhZnRlciB0YXBob2xkLWFuZC1mcmVlIFxuICAgICAgICBjeS5vbigndGFwaG9sZCcsICdub2RlJywgZnVuY3Rpb24oZXZlbnQpeyAgICAgICAgXG4gICAgICAgICAgdmFyIHRhcmdldCA9IGV2ZW50LnRhcmdldCB8fCBldmVudC5jeVRhcmdldDtcbiAgICAgICAgICB2YXIgdGFwaGVsZCA9IGZhbHNlO1xuICAgICAgICAgIHZhciBuZWlnaGJvcmhvb2Q7XG4gICAgICAgICAgdmFyIHRpbWVvdXQgPSBzZXRUaW1lb3V0KGZ1bmN0aW9uKCl7IFxuICAgICAgICAgICAgaWYoc2hpZnRLZXlEb3duID09IHRydWUpe1xuICAgICAgICAgICAgICBjeS5lbGVtZW50cygpLnVuc2VsZWN0KCk7XG4gICAgICAgICAgICAgIG5laWdoYm9yaG9vZCA9IG9wdGlvbnMubmVpZ2hib3IodGFyZ2V0KTtcbiAgICAgICAgICAgICAgbmVpZ2hib3Job29kLnNlbGVjdCgpO1xuICAgICAgICAgICAgICB0YXJnZXQubG9jaygpO1xuICAgICAgICAgICAgICB0YXBoZWxkID0gdHJ1ZTsgICBcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LCBvcHRpb25zLm5laWdoYm9yU2VsZWN0VGltZSAtIDUwMCk7XG4gICAgICAgICAgY3kub24oJ2ZyZWUnLCAnbm9kZScsIGZ1bmN0aW9uKCl7XG4gICAgICAgICAgICB2YXIgdGFyZ2V0VGFwaGVsZCA9IGV2ZW50LnRhcmdldCB8fCBldmVudC5jeVRhcmdldDtcbiAgICAgICAgICAgIGlmKHRhcmdldCA9PSB0YXJnZXRUYXBoZWxkICYmIHRhcGhlbGQgPT09IHRydWUpe1xuICAgICAgICAgICAgICB0YXBoZWxkID0gZmFsc2U7XG4gICAgICAgICAgICAgIG5laWdoYm9yaG9vZC5zZWxlY3QoKTtcbiAgICAgICAgICAgICAgdGFyZ2V0LnVubG9jaygpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZXtcbiAgICAgICAgICAgICAgICBjbGVhclRpbWVvdXQodGltZW91dCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSk7XG4gICAgICAgICAgY3kub24oJ2RyYWcnLCAnbm9kZScsIGZ1bmN0aW9uKCl7XG4gICAgICAgICAgICB2YXIgdGFyZ2V0RHJhZ2dlZCA9IGV2ZW50LnRhcmdldCB8fCBldmVudC5jeVRhcmdldDsgIFxuICAgICAgICAgICAgaWYodGFyZ2V0ID09IHRhcmdldERyYWdnZWQgJiYgdGFwaGVsZCA9PT0gZmFsc2Upe1xuICAgICAgICAgICAgICAgIGNsZWFyVGltZW91dCh0aW1lb3V0KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICAgIHJldHVybiB2aWV3VXRpbGl0aWVzO1xuICAgIH0pO1xuXG4gIH07XG5cbiAgaWYgKHR5cGVvZiBtb2R1bGUgIT09ICd1bmRlZmluZWQnICYmIG1vZHVsZS5leHBvcnRzKSB7IC8vIGV4cG9zZSBhcyBhIGNvbW1vbmpzIG1vZHVsZVxuICAgIG1vZHVsZS5leHBvcnRzID0gcmVnaXN0ZXI7XG4gIH1cblxuICBpZiAodHlwZW9mIGRlZmluZSAhPT0gJ3VuZGVmaW5lZCcgJiYgZGVmaW5lLmFtZCkgeyAvLyBleHBvc2UgYXMgYW4gYW1kL3JlcXVpcmVqcyBtb2R1bGVcbiAgICBkZWZpbmUoJ2N5dG9zY2FwZS12aWV3LXV0aWxpdGllcycsIGZ1bmN0aW9uICgpIHtcbiAgICAgIHJldHVybiByZWdpc3RlcjtcbiAgICB9KTtcbiAgfVxuXG4gIGlmICh0eXBlb2YgY3l0b3NjYXBlICE9PSAndW5kZWZpbmVkJyAmJiB0eXBlb2YgJCAhPT0gXCJ1bmRlZmluZWRcIikgeyAvLyBleHBvc2UgdG8gZ2xvYmFsIGN5dG9zY2FwZSAoaS5lLiB3aW5kb3cuY3l0b3NjYXBlKVxuICAgIHJlZ2lzdGVyKGN5dG9zY2FwZSwgJCk7XG4gIH1cblxufSkoKTtcbiIsIi8vIFJlZ2lzdGVycyB1ciBhY3Rpb25zIHJlbGF0ZWQgdG8gaGlnaGxpZ2h0XG5mdW5jdGlvbiBoaWdobGlnaHRVUihjeSwgdXIsIHZpZXdVdGlsaXRpZXMpIHtcbiAgZnVuY3Rpb24gZ2V0U3RhdHVzKGVsZXMpIHtcbiAgICBlbGVzID0gZWxlcyA/IGVsZXMgOiBjeS5lbGVtZW50cygpO1xuICAgIHJldHVybiB7XG4gICAgICBoaWdobGlnaHRlZHM6IGVsZXMuZmlsdGVyKFwiLmhpZ2hsaWdodGVkOnZpc2libGVcIiksXG4gICAgICB1bmhpZ2hsaWdodGVkczogZWxlcy5maWx0ZXIoXCIudW5oaWdobGlnaHRlZDp2aXNpYmxlXCIpLFxuICAgICAgbm90SGlnaGxpZ2h0ZWRzOiBlbGVzLmZpbHRlcihcIjp2aXNpYmxlXCIpLm5vdChcIi5oaWdobGlnaHRlZCwgLnVuaGlnaGxpZ2h0ZWRcIilcbiAgICB9O1xuICB9XG5cbiAgZnVuY3Rpb24gZ2VuZXJhbFVuZG8oYXJncykge1xuXG4gICAgdmFyIGN1cnJlbnQgPSBhcmdzLmN1cnJlbnQ7XG4gICAgdmFyIGhpZ2hsaWdodGVkcyA9IHZpZXdVdGlsaXRpZXMuaGlnaGxpZ2h0KGFyZ3MuaGlnaGxpZ2h0ZWRzKTtcbiAgICB2YXIgdW5oaWdobGlnaHRlZHMgPSB2aWV3VXRpbGl0aWVzLnVuaGlnaGxpZ2h0KGFyZ3MudW5oaWdobGlnaHRlZHMpO1xuICAgIHZhciBub3RIaWdobGlnaHRlZHMgPSB2aWV3VXRpbGl0aWVzLnJlbW92ZUhpZ2hsaWdodHMoYXJncy5ub3RIaWdobGlnaHRlZHMpO1xuXG5cbiAgICByZXR1cm4ge1xuICAgICAgaGlnaGxpZ2h0ZWRzOiBoaWdobGlnaHRlZHMsXG4gICAgICB1bmhpZ2hsaWdodGVkczogdW5oaWdobGlnaHRlZHMsXG4gICAgICBub3RIaWdobGlnaHRlZHM6IG5vdEhpZ2hsaWdodGVkcyxcbiAgICAgIGN1cnJlbnQ6IGN1cnJlbnRcbiAgICB9O1xuICB9XG5cbiAgZnVuY3Rpb24gZ2VuZXJhbFJlZG8oYXJncykge1xuXG4gICAgdmFyIGN1cnJlbnQgPSBhcmdzLmN1cnJlbnQ7XG4gICAgdmFyIGhpZ2hsaWdodGVkcyA9IHZpZXdVdGlsaXRpZXMuaGlnaGxpZ2h0KGFyZ3MuY3VycmVudC5oaWdobGlnaHRlZHMpO1xuICAgIHZhciB1bmhpZ2hsaWdodGVkcyA9IHZpZXdVdGlsaXRpZXMudW5oaWdobGlnaHQoYXJncy5jdXJyZW50LnVuaGlnaGxpZ2h0ZWRzKTtcbiAgICB2YXIgbm90SGlnaGxpZ2h0ZWRzID0gdmlld1V0aWxpdGllcy5yZW1vdmVIaWdobGlnaHRzKGFyZ3MuY3VycmVudC5ub3RIaWdobGlnaHRlZHMpO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIGhpZ2hsaWdodGVkczogaGlnaGxpZ2h0ZWRzLFxuICAgICAgdW5oaWdobGlnaHRlZHM6IHVuaGlnaGxpZ2h0ZWRzLFxuICAgICAgbm90SGlnaGxpZ2h0ZWRzOiBub3RIaWdobGlnaHRlZHMsXG4gICAgICBjdXJyZW50OiBjdXJyZW50XG4gICAgfTtcbiAgfVxuXG4gIGZ1bmN0aW9uIGdlbmVyYXRlRG9GdW5jKGZ1bmMpIHtcbiAgICByZXR1cm4gZnVuY3Rpb24gKGVsZXMpIHtcbiAgICAgIHZhciByZXMgPSBnZXRTdGF0dXMoKTtcblxuICAgICAgaWYgKGVsZXMuZmlyc3RUaW1lKVxuICAgICAgICB2aWV3VXRpbGl0aWVzW2Z1bmNdKGVsZXMpO1xuICAgICAgZWxzZVxuICAgICAgICBnZW5lcmFsUmVkbyhlbGVzKTtcblxuICAgICAgcmVzLmN1cnJlbnQgPSBnZXRTdGF0dXMoKTtcblxuICAgICAgcmV0dXJuIHJlcztcbiAgICB9O1xuICB9XG5cbiAgZnVuY3Rpb24gdXJSZW1vdmVIaWdobGlnaHRzKGFyZ3MpIHtcbiAgICB2YXIgcmVzID0gZ2V0U3RhdHVzKCk7XG5cbiAgICBpZiAoYXJncy5maXJzdFRpbWUpXG4gICAgICB2aWV3VXRpbGl0aWVzLnJlbW92ZUhpZ2hsaWdodHMoKTtcbiAgICBlbHNlXG4gICAgICBnZW5lcmFsUmVkbyhhcmdzKTtcblxuICAgIHJlcy5jdXJyZW50ID0gZ2V0U3RhdHVzKCk7XG5cbiAgICByZXR1cm4gcmVzO1xuICB9XG5cbiAgdXIuYWN0aW9uKFwiaGlnaGxpZ2h0TmVpZ2hib3JzXCIsIGdlbmVyYXRlRG9GdW5jKFwiaGlnaGxpZ2h0TmVpZ2hib3JzXCIpLCBnZW5lcmFsVW5kbyk7XG4gIHVyLmFjdGlvbihcImhpZ2hsaWdodE5laWdoYm91cnNcIiwgZ2VuZXJhdGVEb0Z1bmMoXCJoaWdobGlnaHROZWlnaGJvdXJzXCIpLCBnZW5lcmFsVW5kbyk7XG4gIHVyLmFjdGlvbihcImhpZ2hsaWdodFwiLCBnZW5lcmF0ZURvRnVuYyhcImhpZ2hsaWdodFwiKSwgZ2VuZXJhbFVuZG8pO1xuICB1ci5hY3Rpb24oXCJ1bmhpZ2hsaWdodFwiLCBnZW5lcmF0ZURvRnVuYyhcInVuaGlnaGxpZ2h0XCIpLCBnZW5lcmFsVW5kbyk7XG4gIHVyLmFjdGlvbihcInVuaGlnaGxpZ2h0TmVpZ2hib3JzXCIsIGdlbmVyYXRlRG9GdW5jKFwidW5oaWdobGlnaHROZWlnaGJvcnNcIiksIGdlbmVyYWxVbmRvKTtcbiAgdXIuYWN0aW9uKFwidW5oaWdobGlnaHROZWlnaGJvdXJzXCIsIGdlbmVyYXRlRG9GdW5jKFwidW5oaWdobGlnaHROZWlnaGJvdXJzXCIpLCBnZW5lcmFsVW5kbyk7XG4gIHVyLmFjdGlvbihcInJlbW92ZUhpZ2hsaWdodHNcIiwgdXJSZW1vdmVIaWdobGlnaHRzLCBnZW5lcmFsVW5kbyk7XG59XG5cbi8vIFJlZ2lzdGVycyB1ciBhY3Rpb25zIHJlbGF0ZWQgdG8gaGlkZS9zaG93XG5mdW5jdGlvbiBoaWRlU2hvd1VSKGN5LCB1ciwgdmlld1V0aWxpdGllcykge1xuICBmdW5jdGlvbiB1clNob3coZWxlcykge1xuICAgIHJldHVybiB2aWV3VXRpbGl0aWVzLnNob3coZWxlcyk7XG4gIH1cblxuICBmdW5jdGlvbiB1ckhpZGUoZWxlcykge1xuICAgIHJldHVybiB2aWV3VXRpbGl0aWVzLmhpZGUoZWxlcyk7XG4gIH1cblxuICB1ci5hY3Rpb24oXCJzaG93XCIsIHVyU2hvdywgdXJIaWRlKTtcbiAgdXIuYWN0aW9uKFwiaGlkZVwiLCB1ckhpZGUsIHVyU2hvdyk7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGN5LCB1ciwgdmlld1V0aWxpdGllcykge1xuICBoaWdobGlnaHRVUihjeSwgdXIsIHZpZXdVdGlsaXRpZXMpO1xuICBoaWRlU2hvd1VSKGN5LCB1ciwgdmlld1V0aWxpdGllcyk7XG59OyIsInZhciBjeSwgb3B0aW9ucztcbnZhciB2aWV3VXRpbGl0aWVzID0gZnVuY3Rpb24gKF9jeSwgX29wdGlvbnMpIHtcbiAgY3kgPSBfY3k7XG4gIG9wdGlvbnMgPSBfb3B0aW9ucztcbiAgXG4gIC8vIFNldCBzdHlsZSBmb3IgaGlnaGxpZ2h0ZWQgYW5kIHVuaGlnaGxpZ3RoZWQgZWxlc1xuICBjeVxuICAgICAgICAuc3R5bGUoKVxuICAgICAgICAuc2VsZWN0b3IoXCJub2RlLmhpZ2hsaWdodGVkXCIpXG4gICAgICAgIC5jc3Mob3B0aW9ucy5ub2RlLmhpZ2hsaWdodGVkKVxuICAgICAgICAuc2VsZWN0b3IoXCJub2RlLnVuaGlnaGxpZ2h0ZWRcIilcbiAgICAgICAgLmNzcyhvcHRpb25zLm5vZGUudW5oaWdobGlnaHRlZClcbiAgICAgICAgLnNlbGVjdG9yKFwiZWRnZS5oaWdobGlnaHRlZFwiKVxuICAgICAgICAuY3NzKG9wdGlvbnMuZWRnZS5oaWdobGlnaHRlZClcbiAgICAgICAgLnNlbGVjdG9yKFwiZWRnZS51bmhpZ2hsaWdodGVkXCIpXG4gICAgICAgIC5jc3Mob3B0aW9ucy5lZGdlLnVuaGlnaGxpZ2h0ZWQpXG4gICAgICAgIC51cGRhdGUoKTtcbn07XG5cbi8vIEhlbHBlciBmdW5jdGlvbnMgZm9yIGludGVybmFsIHVzYWdlIChub3QgdG8gYmUgZXhwb3NlZClcbmZ1bmN0aW9uIGhpZ2hsaWdodChlbGVzKSB7XG4gIGVsZXMucmVtb3ZlQ2xhc3MoXCJ1bmhpZ2hsaWdodGVkXCIpLmFkZENsYXNzKFwiaGlnaGxpZ2h0ZWRcIik7XG59XG5cbmZ1bmN0aW9uIGdldFdpdGhOZWlnaGJvcnMoZWxlcykge1xuICByZXR1cm4gZWxlcy5hZGQoZWxlcy5kZXNjZW5kYW50cygpKS5jbG9zZWROZWlnaGJvcmhvb2QoKTtcbn1cblxuLy8gU2VjdGlvbiBoaWRlLXNob3dcblxuLy8gaGlkZSBnaXZlbiBlbGVzXG52aWV3VXRpbGl0aWVzLmhpZGUgPSBmdW5jdGlvbiAoZWxlcykge1xuICBlbGVzID0gZWxlcy5maWx0ZXIoXCI6dmlzaWJsZVwiKTtcbiAgZWxlcyA9IGVsZXMudW5pb24oZWxlcy5jb25uZWN0ZWRFZGdlcygpKTtcblxuICBlbGVzLnVuc2VsZWN0KCk7XG5cbiAgaWYgKG9wdGlvbnMuc2V0VmlzaWJpbGl0eU9uSGlkZSkge1xuICAgIGVsZXMuY3NzKCd2aXNpYmlsaXR5JywgJ2hpZGRlbicpO1xuICB9XG5cbiAgaWYgKG9wdGlvbnMuc2V0RGlzcGxheU9uSGlkZSkge1xuICAgIGVsZXMuY3NzKCdkaXNwbGF5JywgJ25vbmUnKTtcbiAgfVxuXG4gIHJldHVybiBlbGVzO1xufTtcblxuLy8gdW5oaWRlIGdpdmVuIGVsZXNcbnZpZXdVdGlsaXRpZXMuc2hvdyA9IGZ1bmN0aW9uIChlbGVzKSB7XG4gIGVsZXMgPSBlbGVzLm5vdChcIjp2aXNpYmxlXCIpO1xuICBlbGVzID0gZWxlcy51bmlvbihlbGVzLmNvbm5lY3RlZEVkZ2VzKCkpO1xuXG4gIGVsZXMudW5zZWxlY3QoKTtcblxuICBpZiAob3B0aW9ucy5zZXRWaXNpYmlsaXR5T25IaWRlKSB7XG4gICAgZWxlcy5jc3MoJ3Zpc2liaWxpdHknLCAndmlzaWJsZScpO1xuICB9XG5cbiAgaWYgKG9wdGlvbnMuc2V0RGlzcGxheU9uSGlkZSkge1xuICAgIGVsZXMuY3NzKCdkaXNwbGF5JywgJ2VsZW1lbnQnKTtcbiAgfVxuXG4gIHJldHVybiBlbGVzO1xufTtcblxuLy8gU2VjdGlvbiBoaWdobGlnaHRcblxuLy8gSGlnaGxpZ2h0cyBlbGVzICYgdW5oaWdobGlnaHRzIG90aGVycyBhdCBmaXJzdCB1c2UuXG52aWV3VXRpbGl0aWVzLmhpZ2hsaWdodCA9IGZ1bmN0aW9uIChlbGVzKSB7XG4gIHZhciBvdGhlcnMgPSBjeS5lbGVtZW50cygpLmRpZmZlcmVuY2UoZWxlcy51bmlvbihlbGVzLmFuY2VzdG9ycygpKSk7XG5cbiAgaWYgKGN5LiQoXCIuaGlnaGxpZ2h0ZWQ6dmlzaWJsZVwiKS5sZW5ndGggPT0gMClcbiAgICB0aGlzLnVuaGlnaGxpZ2h0KG90aGVycyk7XG5cbiAgaGlnaGxpZ2h0KGVsZXMpOyAvLyBVc2UgdGhlIGhlbHBlciBoZXJlXG5cbiAgcmV0dXJuIGVsZXM7XG59O1xuXG4vLyBKdXN0IHVuaWdobGlnaHRzIGVsZXMuXG52aWV3VXRpbGl0aWVzLnVuaGlnaGxpZ2h0ID0gZnVuY3Rpb24gKGVsZXMpIHtcbiAgZWxlcy5yZW1vdmVDbGFzcyhcImhpZ2hsaWdodGVkXCIpLmFkZENsYXNzKFwidW5oaWdobGlnaHRlZFwiKTtcbn07XG5cbi8vIEhpZ2hsaWdodHMgZWxlcycgbmVpZ2hib3Job29kICYgdW5oaWdobGlnaHRzIG90aGVycycgbmVpZ2hib3Job29kIGF0IGZpcnN0IHVzZS5cbnZpZXdVdGlsaXRpZXMuaGlnaGxpZ2h0TmVpZ2hib3JzID0gZnVuY3Rpb24gKGVsZXMpIHtcbiAgdmFyIGFsbEVsZXMgPSBnZXRXaXRoTmVpZ2hib3JzKGVsZXMpO1xuXG4gIHJldHVybiB0aGlzLmhpZ2hsaWdodChhbGxFbGVzKTtcbn07XG5cbi8vIEFsaWFzZXM6IHRoaXMuaGlnaGxpZ2h0TmVpZ2hib3VycygpXG52aWV3VXRpbGl0aWVzLmhpZ2hsaWdodE5laWdoYm91cnMgPSBmdW5jdGlvbiAoZWxlcykge1xuICByZXR1cm4gdGhpcy5oaWdobGlnaHROZWlnaGJvcnMoZWxlcyk7XG59O1xuXG4vLyBKdXN0IHVuaGlnaGxpZ2h0cyBlbGVzIGFuZCB0aGVpciBuZWlnaGJvcnMuXG52aWV3VXRpbGl0aWVzLnVuaGlnaGxpZ2h0TmVpZ2hib3JzID0gZnVuY3Rpb24gKGVsZXMpIHtcbiAgdmFyIGFsbEVsZXMgPSBnZXRXaXRoTmVpZ2hib3JzKGVsZXMpO1xuXG4gIHJldHVybiB0aGlzLnVuaGlnaGxpZ2h0KGFsbEVsZXMpO1xufTtcblxuLy8gQWxpYXNlczogdGhpcy51bmhpZ2hsaWdodE5laWdoYm91cnMoKVxudmlld1V0aWxpdGllcy51bmhpZ2hsaWdodE5laWdoYm91cnMgPSBmdW5jdGlvbiAoZWxlcykge1xuICB0aGlzLnVuaGlnaGxpZ2h0TmVpZ2hib3JzKGVsZXMpO1xufTtcblxuLy8gUmVtb3ZlIGhpZ2hsaWdodHMgJiB1bmhpZ2hsaWdodHMgZnJvbSBlbGVzLlxuLy8gSWYgZWxlcyBpcyBub3QgZGVmaW5lZCBjb25zaWRlcnMgY3kuZWxlbWVudHMoKVxudmlld1V0aWxpdGllcy5yZW1vdmVIaWdobGlnaHRzID0gZnVuY3Rpb24gKGVsZXMpIHtcbiAgaWYgKCFlbGVzKSB7XG4gICAgZWxlcyA9IGN5LmVsZW1lbnRzKCk7XG4gIH1cblxuICByZXR1cm4gZWxlc1xuICAgICAgICAgIC5yZW1vdmVDbGFzcyhcImhpZ2hsaWdodGVkXCIpXG4gICAgICAgICAgLnJlbW92ZUNsYXNzKFwidW5oaWdobGlnaHRlZFwiKVxuICAgICAgICAgIC5yZW1vdmVEYXRhKFwiaGlnaGxpZ2h0ZWRcIik7IC8vIFRPRE8gY2hlY2sgaWYgcmVtb3ZlIGRhdGEgaXMgbmVlZGVkIGhlcmVcbn07XG5cbi8vIEluZGljYXRlcyBpZiB0aGUgZWxlIGlzIGhpZ2hsaWdodGVkXG52aWV3VXRpbGl0aWVzLmlzSGlnaGxpZ2h0ZWQgPSBmdW5jdGlvbiAoZWxlKSB7XG4gIHJldHVybiBlbGUuaXMoXCIuaGlnaGxpZ2h0ZWQ6dmlzaWJsZVwiKSA/IHRydWUgOiBmYWxzZTtcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gdmlld1V0aWxpdGllcztcblxuIl19 diff --git a/web/js/cytoscape.min.js b/web/js/cytoscape.min.js new file mode 100644 index 000000000..2b35cfc19 --- /dev/null +++ b/web/js/cytoscape.min.js @@ -0,0 +1,10 @@ +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.cytoscape=t():e.cytoscape=t()}(this,function(){return function(e){function t(r){if(n[r])return n[r].exports;var i=n[r]={i:r,l:!1,exports:{}};return e[r].call(i.exports,i,i.exports,t),i.l=!0,i.exports}var n={};return t.m=e,t.c=n,t.i=function(e){return e},t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=117)}([function(e,t,n){"use strict";var r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},i=n(4),a=i?i.navigator:null,o=i?i.document:null,s=r(""),l=r({}),u=r(function(){}),c="undefined"==typeof HTMLElement?"undefined":r(HTMLElement),d=function(e){return e&&e.instanceString&&h.fn(e.instanceString)?e.instanceString():null},h={defined:function(e){return null!=e},string:function(e){return null!=e&&(void 0===e?"undefined":r(e))==s},fn:function(e){return null!=e&&(void 0===e?"undefined":r(e))===u},array:function(e){return Array.isArray?Array.isArray(e):null!=e&&e instanceof Array},plainObject:function(e){return null!=e&&(void 0===e?"undefined":r(e))===l&&!h.array(e)&&e.constructor===Object},object:function(e){return null!=e&&(void 0===e?"undefined":r(e))===l},number:function(e){return null!=e&&(void 0===e?"undefined":r(e))===r(1)&&!isNaN(e)},integer:function(e){return h.number(e)&&Math.floor(e)===e},bool:function(e){return null!=e&&(void 0===e?"undefined":r(e))===r(!0)},htmlElement:function(e){return"undefined"===c?void 0:null!=e&&e instanceof HTMLElement},elementOrCollection:function(e){return h.element(e)||h.collection(e)},element:function(e){return"collection"===d(e)&&e._private.single},collection:function(e){return"collection"===d(e)&&!e._private.single},core:function(e){return"core"===d(e)},style:function(e){return"style"===d(e)},stylesheet:function(e){return"stylesheet"===d(e)},event:function(e){return"event"===d(e)},thread:function(e){return"thread"===d(e)},fabric:function(e){return"fabric"===d(e)},emptyString:function(e){return void 0===e||null===e||!(""!==e&&!e.match(/^\s+$/))},nonemptyString:function(e){return!(!e||!h.string(e)||""===e||e.match(/^\s+$/))},domElement:function(e){return"undefined"!=typeof HTMLElement&&e instanceof HTMLElement},boundingBox:function(e){return h.plainObject(e)&&h.number(e.x1)&&h.number(e.x2)&&h.number(e.y1)&&h.number(e.y2)},promise:function(e){return h.object(e)&&h.fn(e.then)},touch:function(){return i&&("ontouchstart"in i||i.DocumentTouch&&o instanceof DocumentTouch)},gecko:function(){return i&&("undefined"!=typeof InstallTrigger||"MozAppearance"in o.documentElement.style)},webkit:function(){return i&&("undefined"!=typeof webkitURL||"WebkitAppearance"in o.documentElement.style)},chromium:function(){return i&&"undefined"!=typeof chrome},khtml:function(){return a&&a.vendor.match(/kde/i)},khtmlEtc:function(){return h.khtml()||h.webkit()||h.chromium()},ms:function(){return a&&a.userAgent.match(/msie|trident|edge/i)},windows:function(){return a&&a.appVersion.match(/Win/i)},mac:function(){return a&&a.appVersion.match(/Mac/i)},linux:function(){return a&&a.appVersion.match(/Linux/i)},unix:function(){return a&&a.appVersion.match(/X11/i)}};e.exports=h},function(e,t,n){"use strict";var r=n(0),i=n(2),a={MAX_INT:Number.MAX_SAFE_INTEGER||9007199254740991,trueify:function(){return!0},falsify:function(){return!1},zeroify:function(){return 0},noop:function(){},error:function(e){console.error?(console.error.apply(console,arguments),console.trace&&console.trace()):(console.log.apply(console,arguments),console.trace&&console.trace())},clone:function(e){return this.extend({},e)},copy:function(e){return null==e?e:r.array(e)?e.slice():r.plainObject(e)?this.clone(e):e},clonePosition:function(e){return{x:e.x,y:e.y}},uuid:function(e,t){for(t=e="";e++<36;t+=51*e&52?(15^e?8^Math.random()*(20^e?16:4):4).toString(16):"-");return t}};a.makeBoundingBox=i.makeBoundingBox.bind(i),a._staticEmptyObject={},a.staticEmptyObject=function(){return a._staticEmptyObject},a.extend=null!=Object.assign?Object.assign.bind(Object):function(e){for(var t=arguments,n=1;n=0&&(e[r]!==t||(e.splice(r,1),n));r--);},a.clearArray=function(e){e.splice(0,e.length)},a.push=function(e,t){for(var n=0;n0?1:e<0?-1:0},r.dist=function(e,t){return Math.sqrt(r.sqdist(e,t))},r.sqdist=function(e,t){var n=t.x-e.x,r=t.y-e.y;return n*n+r*r},r.qbezierAt=function(e,t,n,r){return(1-r)*(1-r)*e+2*(1-r)*r*t+r*r*n},r.qbezierPtAt=function(e,t,n,i){return{x:r.qbezierAt(e.x,t.x,n.x,i),y:r.qbezierAt(e.y,t.y,n.y,i)}},r.lineAt=function(e,t,n,i){var a={x:t.x-e.x,y:t.y-e.y},o=r.dist(e,t),s={x:a.x/o,y:a.y/o};return n=null==n?0:n,i=null!=i?i:n*o,{x:e.x+s.x*i,y:e.y+s.y*i}},r.lineAtDist=function(e,t,n){return r.lineAt(e,t,void 0,n)},r.triangleAngle=function(e,t,n){var i=r.dist(t,n),a=r.dist(e,n),o=r.dist(e,t);return Math.acos((i*i+a*a-o*o)/(2*i*a))},r.bound=function(e,t,n){return Math.max(e,Math.min(n,t))},r.makeBoundingBox=function(e){if(null==e)return{x1:1/0,y1:1/0,x2:-1/0,y2:-1/0,w:0,h:0};if(null!=e.x1&&null!=e.y1){if(null!=e.x2&&null!=e.y2&&e.x2>=e.x1&&e.y2>=e.y1)return{x1:e.x1,y1:e.y1,x2:e.x2,y2:e.y2,w:e.x2-e.x1,h:e.y2-e.y1};if(null!=e.w&&null!=e.h&&e.w>=0&&e.h>=0)return{x1:e.x1,y1:e.y1,x2:e.x1+e.w,y2:e.y1+e.h,w:e.w,h:e.h}}},r.updateBoundingBox=function(e,t){e.x1=Math.min(e.x1,t.x1),e.x2=Math.max(e.x2,t.x2),e.w=e.x2-e.x1,e.y1=Math.min(e.y1,t.y1),e.y2=Math.max(e.y2,t.y2),e.h=e.y2-e.y1},r.expandBoundingBoxByPoint=function(e,t,n){e.x1=Math.min(e.x1,t),e.x2=Math.max(e.x2,t),e.w=e.x2-e.x1,e.y1=Math.min(e.y1,n),e.y2=Math.max(e.y2,n),e.h=e.y2-e.y1},r.expandBoundingBox=function(e,t){return e.x1-=t,e.x2+=t,e.y1-=t,e.y2+=t,e.w=e.x2-e.x1,e.h=e.y2-e.y1,e},r.boundingBoxesIntersect=function(e,t){return!(e.x1>t.x2)&&(!(t.x1>e.x2)&&(!(e.x2t.y2)&&!(t.y1>e.y2)))))))},r.inBoundingBox=function(e,t,n){return e.x1<=t&&t<=e.x2&&e.y1<=n&&n<=e.y2},r.pointInBoundingBox=function(e,t){return this.inBoundingBox(e,t.x,t.y)},r.boundingBoxInBoundingBox=function(e,t){return r.inBoundingBox(e,t.x1,t.y1)&&r.inBoundingBox(e,t.x2,t.y2)},r.roundRectangleIntersectLine=function(e,t,n,r,i,a,o){var s=this.getRoundRectangleRadius(i,a),l=i/2,u=a/2,c=void 0,d=n-l+s-o,h=r-u-o,p=n+l-s+o,f=h;if(c=this.finiteLinesIntersect(e,t,n,r,d,h,p,f,!1),c.length>0)return c;var v=n+l+o,g=r-u+s-o,m=v,y=r+u-s+o;if(c=this.finiteLinesIntersect(e,t,n,r,v,g,m,y,!1),c.length>0)return c;var b=n-l+s-o,x=r+u+o,w=n+l-s+o,E=x;if(c=this.finiteLinesIntersect(e,t,n,r,b,x,w,E,!1),c.length>0)return c;var P=n-l-o,C=r-u+s-o,T=P,S=r+u-s+o;if(c=this.finiteLinesIntersect(e,t,n,r,P,C,T,S,!1),c.length>0)return c;var D=void 0,k=n-l+s,_=r-u+s;if(D=this.intersectLineCircle(e,t,n,r,k,_,s+o),D.length>0&&D[0]<=k&&D[1]<=_)return[D[0],D[1]];var M=n+l-s,I=r-u+s;if(D=this.intersectLineCircle(e,t,n,r,M,I,s+o),D.length>0&&D[0]>=M&&D[1]<=I)return[D[0],D[1]];var N=n+l-s,B=r+u-s;if(D=this.intersectLineCircle(e,t,n,r,N,B,s+o),D.length>0&&D[0]>=N&&D[1]>=B)return[D[0],D[1]];var L=n-l+s,z=r+u-s;return D=this.intersectLineCircle(e,t,n,r,L,z,s+o),D.length>0&&D[0]<=L&&D[1]>=z?[D[0],D[1]]:[]},r.inLineVicinity=function(e,t,n,r,i,a,o){var s=o,l=Math.min(n,i),u=Math.max(n,i),c=Math.min(r,a),d=Math.max(r,a);return l-s<=e&&e<=u+s&&c-s<=t&&t<=d+s},r.inBezierVicinity=function(e,t,n,r,i,a,o,s,l){var u={x1:Math.min(n,o,i)-l,x2:Math.max(n,o,i)+l,y1:Math.min(r,s,a)-l,y2:Math.max(r,s,a)+l};return!(eu.x2||tu.y2)},r.solveQuadratic=function(e,t,n,r){n-=r;var i=t*t-4*e*n;if(i<0)return[];var a=Math.sqrt(i),o=2*e;return[(-t+a)/o,(-t-a)/o]},r.solveCubic=function(e,t,n,r,i){t/=e,n/=e,r/=e;var a=void 0,o=void 0,s=void 0,l=void 0,u=void 0,c=void 0,d=void 0,h=void 0;return o=(3*n-t*t)/9,s=-27*r+t*(9*n-t*t*2),s/=54,a=o*o*o+s*s,i[1]=0,d=t/3,a>0?(u=s+Math.sqrt(a),u=u<0?-Math.pow(-u,1/3):Math.pow(u,1/3),c=s-Math.sqrt(a),c=c<0?-Math.pow(-c,1/3):Math.pow(c,1/3),i[0]=-d+u+c,d+=(u+c)/2,i[4]=i[2]=-d,d=Math.sqrt(3)*(-c+u)/2,i[3]=d,void(i[5]=-d)):(i[5]=i[3]=0,0===a?(h=s<0?-Math.pow(-s,1/3):Math.pow(s,1/3),i[0]=2*h-d,void(i[4]=i[2]=-(h+d))):(o=-o,l=o*o*o,l=Math.acos(s/Math.sqrt(l)),h=2*Math.sqrt(o),i[0]=-d+h*Math.cos(l/3),i[2]=-d+h*Math.cos((l+2*Math.PI)/3),void(i[4]=-d+h*Math.cos((l+4*Math.PI)/3))))},r.sqdistToQuadraticBezier=function(e,t,n,r,i,a,o,s){var l=1*n*n-4*n*i+2*n*o+4*i*i-4*i*o+o*o+r*r-4*r*a+2*r*s+4*a*a-4*a*s+s*s,u=9*n*i-3*n*n-3*n*o-6*i*i+3*i*o+9*r*a-3*r*r-3*r*s-6*a*a+3*a*s,c=3*n*n-6*n*i+n*o-n*e+2*i*i+2*i*e-o*e+3*r*r-6*r*a+r*s-r*t+2*a*a+2*a*t-s*t,d=1*n*i-n*n+n*e-i*e+r*a-r*r+r*t-a*t,h=[];this.solveCubic(l,u,c,d,h);for(var p=[],f=0;f<6;f+=2)Math.abs(h[f+1])<1e-7&&h[f]>=0&&h[f]<=1&&p.push(h[f]);p.push(1),p.push(0);for(var v=-1,g=void 0,m=void 0,y=void 0,b=0;b=0?yl?(e-i)*(e-i)+(t-a)*(t-a):u-d},r.pointInsidePolygonPoints=function(e,t,n){for(var r=void 0,i=void 0,a=void 0,o=void 0,s=0,l=0;l=e&&e>=a||r<=e&&e<=a))continue;(e-r)/(a-r)*(o-i)+i>t&&s++}return s%2!=0},r.pointInsidePolygon=function(e,t,n,i,a,o,s,l,u){var c=new Array(n.length),d=void 0;null!=l[0]?(d=Math.atan(l[1]/l[0]),l[0]<0?d+=Math.PI/2:d=-d-Math.PI/2):d=l;for(var h=Math.cos(-d),p=Math.sin(-d),f=0;f0){var g=this.expandPolygon(c,-u);v=this.joinLines(g)}else v=c;return r.pointInsidePolygonPoints(e,t,v)},r.joinLines=function(e){for(var t=new Array(e.length/2),n=void 0,r=void 0,i=void 0,a=void 0,o=void 0,s=void 0,l=void 0,u=void 0,c=0;c=0&&v<=1&&m.push(v),g>=0&&g<=1&&m.push(g),0===m.length)return[];var y=m[0]*s[0]+e,b=m[0]*s[1]+t;if(m.length>1){if(m[0]==m[1])return[y,b];return[y,b,m[1]*s[0]+e,m[1]*s[1]+t]}return[y,b]},r.findCircleNearPoint=function(e,t,n,r,i){var a=r-e,o=i-t,s=Math.sqrt(a*a+o*o);return[e+a/s*n,t+o/s*n]},r.findMaxSqDistanceToOrigin=function(e){for(var t=1e-6,n=void 0,r=0;rt&&(t=n);return t},r.midOfThree=function(e,t,n){return t<=e&&e<=n||n<=e&&e<=t?e:e<=t&&t<=n||n<=t&&t<=e?t:n},r.finiteLinesIntersect=function(e,t,n,r,i,a,o,s,l){var u=e-i,c=n-e,d=o-i,h=t-a,p=r-t,f=s-a,v=d*h-f*u,g=c*h-p*u,m=f*c-d*p;if(0!==m){var y=v/m,b=g/m;return-.001<=y&&y<=1.001&&-.001<=b&&b<=1.001?[e+y*c,t+y*p]:l?[e+y*c,t+y*p]:[]}return 0===v||0===g?this.midOfThree(e,n,o)===o?[o,s]:this.midOfThree(e,n,i)===i?[i,a]:this.midOfThree(i,o,n)===n?[n,r]:[]:[]},r.polygonIntersectLine=function(e,t,n,i,a,o,s,l){var u=[],c=void 0,d=new Array(n.length),h=!0;5===arguments.length&&(h=!1);var p=void 0;if(h){for(var f=0;f0){var v=r.expandPolygon(d,-l);p=r.joinLines(v)}else p=d}else p=n;for(var g=void 0,m=void 0,y=void 0,b=void 0,x=0;x "+t(r.target)),null!=r.connectedNodes){var h=r.connectedNodes;o=t(h[0])+" <-> "+t(h[1])}return null!=r.parent&&(o=t(r.parent)+" > "+o),null!=r.ancestor&&(o=t(r.ancestor)+" "+o),null!=r.child&&(o+=" > "+t(r.child)),null!=r.descendant&&(o+=" "+t(r.descendant)),o}(o),this.length>1&&e0&&i.plainObject(t[0])&&!i.element(t[0])){c=!0;for(var d=[],h=new o,p=0,f=t.length;p0){for(var R=new u(n,d),V=0;V0&&(e&&this.cy().notify({type:"remove",eles:E}),E.emit("remove"));for(var P=0;P=0;o--)!function(o){var s=a[o];c(i,function(e,t,n,r,i,l){s.type!==n||r&&s.namespace!==r||i&&!e.qualifierCompare(s.qualifier,i)||l&&s.callback!==l||a.splice(o,1)},e,t,n,r)}(o);return this},u.emit=u.trigger=function(e,t,n){var r=this.listeners;return a.array(t)||(t=[t]),h(this,function(e,a){null!=n&&(r=[{event:a.event,type:a.type,namespace:a.namespace,callback:n}]);for(var o=0;o0?d.wheelSensitivity:1,motionBlur:void 0!==d.motionBlur&&d.motionBlur,motionBlurOpacity:void 0===d.motionBlurOpacity?.05:d.motionBlurOpacity,pixelRatio:o.number(d.pixelRatio)&&d.pixelRatio>0?d.pixelRatio:void 0,desktopTapThreshold:void 0===d.desktopTapThreshold?4:d.desktopTapThreshold,touchTapThreshold:void 0===d.touchTapThreshold?8:d.touchTapThreshold},d.renderer));var v=function(e,n,r){t.notifications(!1);var a=t.mutableElements();a.length>0&&a.remove(),null!=e&&(o.plainObject(e)||o.array(e))&&t.add(e),t.one("layoutready",function(e){t.notifications(!0),t.emit(e),t.notify({type:"load",eles:t.mutableElements()}),t.one("load",n),t.emit("load")}).one("layoutstop",function(){t.one("done",r),t.emit("done")});var s=i.extend({},t._private.options.layout);s.eles=t.elements(),t.layout(s).run()};!function(e,t){if(e.some(o.promise))return s.all(e).then(t);t(e)}([d.style,d.elements],function(e){var n=e[0],r=e[1];p.styleEnabled&&t.setStyle(n),v(r,function(){t.startAnimationLoop(),p.ready=!0,o.fn(d.ready)&&t.on("ready",d.ready);for(var e=0;e=e.deqFastCost*g)break}else if(a){if(f>=e.deqCost*u||f>=e.deqAvgCost*l)break}else if(v>=e.deqNoDrawCost*(1e3/60))break;var m=e.deq(t,h,d);if(!(m.length>0))break;for(var y=0;y0&&(e.onDeqd(t,c),!a&&e.shouldRedraw(t,c,h,d)&&i())},o=e.priority||r.noop;n.beforeRender(a,o(t))}}}}},function(e,t,n){"use strict";var r=n(1),i=[{selector:":selected",matches:function(e){return e.selected()}},{selector:":unselected",matches:function(e){return!e.selected()}},{selector:":selectable",matches:function(e){return e.selectable()}},{selector:":unselectable",matches:function(e){return!e.selectable()}},{selector:":locked",matches:function(e){return e.locked()}},{selector:":unlocked",matches:function(e){return!e.locked()}},{selector:":visible",matches:function(e){return e.visible()}},{selector:":hidden",matches:function(e){return!e.visible()}},{selector:":transparent",matches:function(e){return e.transparent()}},{selector:":grabbed",matches:function(e){return e.grabbed()}},{selector:":free",matches:function(e){return!e.grabbed()}},{selector:":removed",matches:function(e){return e.removed()}},{selector:":inside",matches:function(e){return!e.removed()}},{selector:":grabbable",matches:function(e){return e.grabbable()}},{selector:":ungrabbable",matches:function(e){return!e.grabbable()}},{selector:":animated",matches:function(e){return e.animated()}},{selector:":unanimated",matches:function(e){return!e.animated()}},{selector:":parent",matches:function(e){return e.isParent()}},{selector:":childless",matches:function(e){return e.isChildless()}},{selector:":child",matches:function(e){return e.isChild()}},{selector:":orphan",matches:function(e){return e.isOrphan()}},{selector:":nonorphan",matches:function(e){return e.isChild()}},{selector:":loop",matches:function(e){return e.isLoop()}},{selector:":simple",matches:function(e){return e.isSimple()}},{selector:":active",matches:function(e){return e.active()}},{selector:":inactive",matches:function(e){return!e.active()}},{selector:":backgrounding",matches:function(e){return e.backgrounding()}},{selector:":nonbackgrounding",matches:function(e){return!e.backgrounding()}}].sort(function(e,t){return r.sort.descending(e.selector,t.selector)}),a=function e(t,n){return(e.lookup=e.lookup||function(){for(var e={},t=void 0,n=0;n0;){var y=function(e,t){if(0!==e.length){for(var n=0,r=t[e[0]],i=1;ic&&(c=t)},get:function(e){return u[e]}},h=0;h0?T.edgesTo(C)[0]:C.edgesTo(T)[0];var S=n(P);C=C.id(),x[C]>x[p]+S&&(x[C]=x[p]+S,w.nodes.indexOf(C)<0?w.push(C):w.updateItem(C),b[C]=0,y[C]=[]),x[C]==x[p]+S&&(b[C]=b[C]+b[p],y[C].push(p))}else for(var E=0;E0;)for(var C=m.pop(),E=0;E0;){var m=f.pop(),y=p(m),b=m.id();if(c[b]=y,y!==1/0)for(var x=m.neighborhood().intersect(h),v=0;v0)for(n.unshift(t);u[i.id()];){var a=u[i.id()];n.unshift(a.edge),n.unshift(a.node),i=a.node}return o.collection(n)}}}};e.exports=a},function(e,t,n){"use strict";var r=n(0),i={floydWarshall:function(e){e=e||{};var t=this.cy();if(null!=e.weight&&r.fn(e.weight))var n=e.weight;else var n=function(e){return 1};if(null!=e.directed)var i=e.directed;else var i=!1;for(var a=this.edges().stdFilter(function(e){return!e.isLoop()}),o=this.nodes(),s=o.length,l={},u=0;uy&&(c[g][m]=y,p[g][m]=m,f[g][m]=a[u])}if(!i)for(var u=0;uy&&(c[g][m]=y,p[g][m]=m,f[g][m]=a[u])}for(var b=0;b0&&this.spawn(n).updateStyle().emit("class"),t},addClass:function(e){return this.toggleClass(e,!0)},hasClass:function(e){var t=this[0];return null!=t&&t._private.classes.has(e)},toggleClass:function(e,t){for(var n=e.match(/\S+/g)||[],r=this,i=[],a=0,o=r.length;a0&&this.spawn(i).updateStyle().emit("class"),r},removeClass:function(e){return this.toggleClass(e,!1)},flashClass:function(e,t){var n=this;if(null==t)t=250;else if(0===t)return n;return n.addClass(e),setTimeout(function(){n.removeClass(e)},t),n}};e.exports=i},function(e,t,n){"use strict";var r=(n(0),n(6)),i={allAre:function(e){var t=new r(e);return this.every(function(e){return t.matches(e)})},is:function(e){var t=new r(e);return this.some(function(e){return t.matches(e)})},some:function(e,t){for(var n=0;n0;){var d=i.shift();t(d),a.add(d.id()),l&&r(i,a,d)}return e}function i(e,t,n){if(n.isParent())for(var r=n._private.children,i=0;i1&&void 0!==arguments[1])||arguments[1],i)},l.forEachUp=function(e){return r(this,e,!(arguments.length>1&&void 0!==arguments[1])||arguments[1],a)},l.forEachUpAndDown=function(e){return r(this,e,!(arguments.length>1&&void 0!==arguments[1])||arguments[1],o)},l.ancestors=l.parents,e.exports=l},function(e,t,n){"use strict";var r=n(3),i=void 0,a=void 0;i=a={data:r.data({field:"data",bindingEvent:"data",allowBinding:!0,allowSetting:!0,settingEvent:"data",settingTriggersEvent:!0,triggerFnName:"trigger",allowGetting:!0,immutableKeys:{id:!0,source:!0,target:!0,parent:!0},updateStyle:!0}),removeData:r.removeData({field:"data",event:"data",triggerFnName:"trigger",triggerEvent:!0,immutableKeys:{id:!0,source:!0,target:!0,parent:!0},updateStyle:!0}),scratch:r.data({field:"scratch",bindingEvent:"scratch",allowBinding:!0,allowSetting:!0,settingEvent:"scratch",settingTriggersEvent:!0,triggerFnName:"trigger",allowGetting:!0,updateStyle:!0}),removeScratch:r.removeData({field:"scratch",event:"scratch",triggerFnName:"trigger",triggerEvent:!0,updateStyle:!0}),rscratch:r.data({field:"rscratch",allowBinding:!1,allowSetting:!0,settingTriggersEvent:!1,allowGetting:!0}),removeRscratch:r.removeData({field:"rscratch",triggerEvent:!1}),id:function(){var e=this[0];if(e)return e._private.data.id}},i.attr=i.data,i.removeAttr=i.removeData,e.exports=a},function(e,t,n){"use strict";function r(e){return function(t){var n=this;if(void 0===t&&(t=!0),0!==n.length&&n.isNode()&&!n.removed()){for(var r=0,i=n[0],a=i._private.edges,o=0;ot}),minIndegree:i("indegree",function(e,t){return et}),minOutdegree:i("outdegree",function(e,t){return et})}),a.extend(o,{totalDegree:function(e){for(var t=0,n=this.nodes(),r=0;r0&&a>0&&(r=t/a*e,i=n/a*e),{biasDiff:r,biasComplementDiff:i}}if(e.isParent()){var r=e._private,i=e.children(),a="include"===e.pstyle("compound-sizing-wrt-labels").value,o={width:{val:e.pstyle("min-width").pfValue,left:e.pstyle("min-width-bias-left"),right:e.pstyle("min-width-bias-right")},height:{val:e.pstyle("min-height").pfValue,top:e.pstyle("min-height-bias-top"),bottom:e.pstyle("min-height-bias-bottom")}},s=i.boundingBox({includeLabels:a,includeOverlays:!1,useCache:!1}),l=r.position;0!==s.w&&0!==s.h||(s={w:e.pstyle("width").pfValue,h:e.pstyle("height").pfValue},s.x1=l.x-s.w/2,s.x2=l.x+s.w/2,s.y1=l.y-s.h/2,s.y2=l.y+s.h/2);var u=o.width.left.value;"px"===o.width.left.units&&o.width.val>0&&(u=100*u/o.width.val);var c=o.width.right.value;"px"===o.width.right.units&&o.width.val>0&&(c=100*c/o.width.val);var d=o.height.top.value;"px"===o.height.top.units&&o.height.val>0&&(d=100*d/o.height.val);var h=o.height.bottom.value;"px"===o.height.bottom.units&&o.height.val>0&&(h=100*h/o.height.val);var p=n(o.width.val-s.w,u,c),f=p.biasDiff,v=p.biasComplementDiff,g=n(o.height.val-s.h,d,h),m=g.biasDiff,y=g.biasComplementDiff;r.autoPadding=function(e,t,n,r){if("%"!==n.units)return"px"===n.units?n.pfValue:0;switch(r){case"width":return e>0?n.pfValue*e:0;case"height":return t>0?n.pfValue*t:0;case"average":return e>0&&t>0?n.pfValue*(e+t)/2:0;case"min":return e>0&&t>0?e>t?n.pfValue*t:n.pfValue*e:0;case"max":return e>0&&t>0?e>t?n.pfValue*e:n.pfValue*t:0;default:return 0}}(s.w,s.h,e.pstyle("padding"),e.pstyle("padding-relative-to").value),r.autoWidth=Math.max(s.w,o.width.val),l.x=(-f+s.x1+s.x2+v)/2,r.autoHeight=Math.max(s.h,o.height.val),l.y=(-m+s.y1+s.y2+y)/2,t.push(e)}}(r),e._private.batchingStyle||(i.compoundBoundsClean=!0))}return this};var u=function(e){return e===1/0||e===-1/0?0:e},c=function(e,t,n,r,i){r-t!=0&&i-n!=0&&(e.x1=te.x2?r:e.x2,e.y1=ne.y2?i:e.y2)},d=function(e,t){return c(e,t.x1,t.y1,t.x2,t.y2)},h=function(e,t,n){return a.getPrefixedProperty(e,t,n)},p=function(e,t,n){var r=t._private,i=r.rstyle,a=i.arrowWidth/2,o=t.pstyle(n+"-arrow-shape").value,s=void 0,l=void 0;"none"!==o&&("source"===n?(s=i.srcX,l=i.srcY):"target"===n?(s=i.tgtX,l=i.tgtY):(s=i.midX,l=i.midY),c(e,s-a,l-a,s+a,l+a))},f=function(e,t,n){var r=void 0;r=n?n+"-":"";var i=t._private,a=i.rstyle;if(t.pstyle(r+"label").strValue){var o=t.pstyle("text-halign"),s=t.pstyle("text-valign"),l=h(a,"labelWidth",n),u=h(a,"labelHeight",n),d=h(a,"labelX",n),p=h(a,"labelY",n),f=t.pstyle(r+"text-margin-x").pfValue,v=t.pstyle(r+"text-margin-y").pfValue,g=t.isEdge(),m=t.pstyle(r+"text-rotation"),y=t.pstyle("text-outline-width").pfValue,b=t.pstyle("text-border-width").pfValue,x=b/2,w=t.pstyle("text-background-padding").pfValue,E=u+2*w,P=l+2*w,C=P/2,T=E/2,S=void 0,D=void 0,k=void 0,_=void 0;if(g)S=d-C,D=d+C,k=p-T,_=p+T;else{switch(o.value){case"left":S=d-P,D=d;break;case"center":S=d-C,D=d+C;break;case"right":S=d,D=d+P}switch(s.value){case"top":k=p-E,_=p;break;case"center":k=p-T,_=p+T;break;case"bottom":k=p,_=p+E}}var M=g&&"autorotate"===m.strValue,I=null!=m.pfValue&&0!==m.pfValue;if(M||I){var N=M?h(i.rstyle,"labelAngle",n):m.pfValue,B=Math.cos(N),L=Math.sin(N),z=function(e,t){return e-=d,t-=p,{x:e*B-t*L+d,y:e*L+t*B+p}},O=z(S,k),A=z(S,_),R=z(D,k),V=z(D,_);S=Math.min(O.x,A.x,R.x,V.x),D=Math.max(O.x,A.x,R.x,V.x),k=Math.min(O.y,A.y,R.y,V.y),_=Math.max(O.y,A.y,R.y,V.y)}S+=f-Math.max(y,x),D+=f+Math.max(y,x),k+=v-Math.max(y,x),_+=v+Math.max(y,x),c(e,S,k,D,_)}return e},v=function(e,t){var n=e._private.cy,r=n._private,i=r.styleEnabled,a={x1:1/0,y1:1/0,x2:-1/0,y2:-1/0},s=e._private,l=i?e.pstyle("display").value:"element",d=e.isNode(),h=e.isEdge(),v=void 0,g=void 0,m=void 0,y=void 0,b=void 0,x=void 0,w="none"!==l;if(w){var E=0;i&&t.includeOverlays&&0!==e.pstyle("overlay-opacity").value&&(E=e.pstyle("overlay-padding").value);var P=0,C=0;if(i&&(P=e.pstyle("width").pfValue,C=P/2),d&&t.includeNodes){var T=e.position();b=T.x,x=T.y;var S=e.outerWidth(),D=S/2,k=e.outerHeight(),_=k/2;v=b-D-E,g=b+D+E,m=x-_-E,y=x+_+E,c(a,v,m,g,y)}else if(h&&t.includeEdges){var M=s.rstyle||{};if(i&&(v=Math.min(M.srcX,M.midX,M.tgtX),g=Math.max(M.srcX,M.midX,M.tgtX),m=Math.min(M.srcY,M.midY,M.tgtY),y=Math.max(M.srcY,M.midY,M.tgtY),v-=C,g+=C,m-=C,y+=C,c(a,v,m,g,y)),i&&"haystack"===e.pstyle("curve-style").strValue){var I=M.haystackPts;if(v=I[0].x,m=I[0].y,g=I[1].x,y=I[1].y,v>g){var N=v;v=g,g=N}if(m>y){var B=m;m=y,y=B}c(a,v-C,m-C,g+C,y+C)}else{for(var L=M.bezierPts||M.linePts||[],z=0;zg){var F=v;v=g,g=F}if(m>y){var j=m;m=y,y=j}v-=C,g+=C,m-=C,y+=C,c(a,v,m,g,y)}}}if(i&&t.includeEdges&&h&&(p(a,e,"mid-source"),p(a,e,"mid-target"),p(a,e,"source"),p(a,e,"target")),i){if("yes"===e.pstyle("ghost").value){var X=e.pstyle("ghost-offset-x").pfValue,Y=e.pstyle("ghost-offset-y").pfValue;c(a,a.x1+X,a.y1+Y,a.x2+X,a.y2+Y)}}i&&(v=a.x1,g=a.x2,m=a.y1,y=a.y2,c(a,v-E,m-E,g+E,y+E)),i&&t.includeLabels&&(f(a,e,null),h&&(f(a,e,"source"),f(a,e,"target")))}return a.x1=u(a.x1),a.y1=u(a.y1),a.x2=u(a.x2),a.y2=u(a.y2),a.w=u(a.x2-a.x1),a.h=u(a.y2-a.y1),a.w>0&&a.h>0&&w&&o.expandBoundingBox(a,1),a},g=function(e){return e?"t":"f"},m=function(e){var t="";return t+=g(e.incudeNodes),t+=g(e.includeEdges),t+=g(e.includeLabels),t+=g(e.includeOverlays)},y=function(e,t){var n=e._private,r=void 0,i=e.cy().headless(),a=t===b?x:m(t);return t.useCache&&!i&&n.bbCache&&n.bbCache[a]?r=n.bbCache[a]:(r=v(e,t),i||(n.bbCache=n.bbCache||{},n.bbCache[a]=r)),r},b={includeNodes:!0,includeEdges:!0,includeLabels:!0,includeOverlays:!0,useCache:!0},x=m(b);l.boundingBox=function(e){if(1===this.length&&this[0]._private.bbCache&&(void 0===e||void 0===e.useCache||!0===e.useCache))return e=void 0===e?b:r(e),y(this[0],e);var t={x1:1/0,y1:1/0,x2:-1/0,y2:-1/0};e=e||a.staticEmptyObject();var n=r(e),i=this,o=i.cy(),s=o.styleEnabled();s&&this.recalculateRenderedStyle(n.useCache),this.updateCompoundBounds();for(var l={},c=0;c0,d=c;c&&(u=u[0]);var h=d?u.position():{x:0,y:0};return a={x:l.x-h.x,y:l.y-h.y},void 0===e?a:a[e]}for(var p=0;p0,m=g;g&&(v=v[0]);var y=m?v.position():{x:0,y:0};void 0!==t?f.position(e,t+y[e]):void 0!==a&&f.position({x:a.x+y.x,y:a.y+y.y})}}else if(!o)return;return this}},o.modelPosition=o.point=o.position,o.modelPositions=o.points=o.positions,o.renderedPoint=o.renderedPosition,o.relativePoint=o.relativePosition,e.exports=s},function(e,t,n){"use strict";var r=n(1),i=void 0,a=void 0;i=a={};var o=function(e){e.uppercaseName=r.capitalize(e.name),e.autoName="auto"+e.uppercaseName,e.labelName="label"+e.uppercaseName,e.outerName="outer"+e.uppercaseName,e.uppercaseOuterName=r.capitalize(e.outerName),i[e.name]=function(){var t=this[0],n=t._private,r=n.cy,i=r._private.styleEnabled;if(t){if(!i)return 1;if(t.isParent())return t.updateCompoundBounds(),n[e.autoName]||0;var a=t.pstyle(e.name);switch(a.strValue){case"label":return t.recalculateRenderedStyle(),n.rstyle[e.labelName]||0;default:return a.pfValue}}},i["outer"+e.uppercaseName]=function(){var t=this[0],n=t._private,r=n.cy,i=r._private.styleEnabled;if(t){if(i){return t[e.name]()+t.pstyle("border-width").pfValue+2*t.padding()}return 1}},i["rendered"+e.uppercaseName]=function(){var t=this[0];if(t){return t[e.name]()*this.cy().zoom()}},i["rendered"+e.uppercaseOuterName]=function(){var t=this[0];if(t){return t[e.outerName]()*this.cy().zoom()}}};o({name:"width"}),o({name:"height"}),a.padding=function(){var e=this[0],t=e._private;return e.isParent()?(e.updateCompoundBounds(),void 0!==t.autoPadding?t.autoPadding:e.pstyle("padding").pfValue):e.pstyle("padding").pfValue},e.exports=a},function(e,t,n){"use strict";var r=n(9),i=n(3),a=n(0),o=n(1),s=n(6),l={qualifierCompare:function(e,t){return e.sameText(t)},eventMatches:function(e,t,n){var r=t.qualifier;return null==r||e!==n.target&&a.element(n.target)&&r.matches(n.target)},eventFields:function(e){return{cy:e.cy(),target:e}},callbackContext:function(e,t,n){return null!=t.qualifier?n.target:e},beforeEmit:function(e,t){t.conf&&t.conf.once&&t.conf.onceCollection.removeListener(t.event,t.qualifier,t.callback)},bubble:function(){return!0},parent:function(e){return e.isChild()?e.parent():e.cy()}},u=function(e){return a.string(e)?new s(e):e},c={createEmitter:function(){for(var e=0;e1&&!o){var s=this.length-1,l=this[s],u=l._private.data.id;this[s]=void 0,this[a]=l,r.set(u,{ele:l,index:a})}return this.length--,this},unmerge:function(e){var t=this._private.cy;if(!e)return this;if(e&&r.string(e)){var n=e;e=t.mutableElements().filter(n)}for(var i=0;in&&(n=s,r=o)}return{value:n,ele:r}},min:function(e,t){for(var n=1/0,r=void 0,i=this,a=0;a=0&&i0&&t.push(c[0]),t.push(s[0])}return this.spawn(t,{unique:!0}).filter(e)},"neighborhood"),closedNeighborhood:function(e){return this.neighborhood().add(this).filter(e)},openNeighborhood:function(e){return this.neighborhood(e)}}),l.neighbourhood=l.neighborhood,l.closedNeighbourhood=l.closedNeighborhood,l.openNeighbourhood=l.openNeighborhood,o.extend(l,{source:u(function(e){var t=this[0],n=void 0;return t&&(n=t._private.source||t.cy().collection()),n&&e?n.filter(e):n},"source"),target:u(function(e){var t=this[0],n=void 0;return t&&(n=t._private.target||t.cy().collection()),n&&e?n.filter(e):n},"target"),sources:r({attr:"source"}),targets:r({attr:"target"})}),o.extend(l,{edgesWith:u(i(),"edgesWith"),edgesTo:u(i({thisIsSrc:!0}),"edgesTo")}),o.extend(l,{connectedEdges:u(function(e){for(var t=[],n=this,r=0;r0);return i.map(function(e){var t=e.connectedEdges().stdFilter(function(t){return e.anySame(t.source())&&e.anySame(t.target())});return e.union(t)})}}),e.exports=l},function(e,t,n){"use strict";var r=n(0),i=n(1),a=n(7),o=n(13),s={add:function(e){var t=void 0,n=this;if(r.elementOrCollection(e)){var s=e;if(s._private.cy===n)t=s.restore();else{for(var l=[],u=0;u0?i=o:r=o}while(Math.abs(a)>g&&++l=v?u(t,s):0===c?s:d(t,r,r+b)}function p(){P=!0,e===t&&n===r||c()}var f=4,v=.001,g=1e-7,m=10,y=11,b=1/(y-1),x="undefined"!=typeof Float32Array;if(4!==arguments.length)return!1;for(var w=0;w<4;++w)if("number"!=typeof arguments[w]||isNaN(arguments[w])||!isFinite(arguments[w]))return!1;e=Math.min(e,1),n=Math.min(n,1),e=Math.max(e,0),n=Math.max(n,0);var E=x?new Float32Array(y):new Array(y),P=!1,C=function(i){return P||p(),e===t&&n===r?i:0===i?0:1===i?1:s(h(i),t,r)};C.getControlPoints=function(){return[{x:e,y:t},{x:n,y:r}]};var T="generateBezier("+[e,t,n,r]+")";return C.toString=function(){return T},C}e.exports=r},function(e,t,n){"use strict";function r(e,t,n,r,i){if(1===r)return n;var a=i(t,n,r);return null==e?a:((e.roundValue||e.color)&&(a=Math.round(a)),void 0!==e.min&&(a=Math.max(a,e.min)),void 0!==e.max&&(a=Math.min(a,e.max)),a)}function i(e,t,n,i,o){var s=null!=o?o.type:null;n<0?n=0:n>1&&(n=1);var l=void 0,u=void 0;if(l=null!=e.pfValue||null!=e.value?null!=e.pfValue?e.pfValue:e.value:e,u=null!=t.pfValue||null!=t.value?null!=t.pfValue?t.pfValue:t.value:t,a.number(l)&&a.number(u))return r(s,l,u,n,i);if(a.array(l)&&a.array(u)){for(var c=[],d=0;d1e-4&&Math.abs(c.v)>1e-4;);return l?function(e){return o[e*(o.length-1)|0]}:s}}();e.exports=r},function(e,t,n){"use strict";function r(e,t,n,r){var i=!r,a=e,o=t._private,s=r?e:e.cy(),l=s.style();if(i){var u=a.position();o.startPosition=o.startPosition||{x:u.x,y:u.y},o.startStyle=o.startStyle||l.getAnimationStartStyle(a,o.style)}if(r){var c=s._private.pan;o.startPan=o.startPan||{x:c.x,y:c.y},o.startZoom=null!=o.startZoom?o.startZoom:s._private.zoom}o.started=!0,o.startTime=n-o.progress*o.duration}e.exports=r},function(e,t,n){"use strict";function r(e,t){function n(t,n){var r=t._private,s=r.animation.current,l=r.animation.queue,u=!1;if(!n&&"none"===t.pstyle("display").value){s=s.splice(0,s.length).concat(l.splice(0,l.length));for(var c=0;c=0;t--){(0,e[t])()}e.splice(0,e.length)},p=s.length-1;p>=0;p--){var f=s[p],v=f._private;v.stopped?(s.splice(p,1),v.hooked=!1,v.playing=!1,v.started=!1,h(v.frames)):(v.playing||v.applying)&&(v.playing&&v.applying&&(v.applying=!1),v.started||a(t,f,e,n),i(t,f,e,n),v.applying&&(v.applying=!1),h(v.frames),f.completed()&&(s.splice(p,1),v.hooked=!1,v.playing=!1,v.started=!1,h(v.completes)),u=!0)}return n||0!==s.length||0!==l.length||o.push(t),u}for(var r=t._private.aniEles,o=[],s=!1,l=0;l0?(r.dirtyCompoundBoundsCache(),t.notify({type:"draw",eles:r})):t.notify({type:"draw"})),r.unmerge(o),t.emit("step")}var i=n(64),a=n(62);e.exports=r},function(e,t,n){"use strict";function r(e,t,n,r){var l=!r,u=e._private,c=t._private,d=c.easing,h=c.startTime,p=r?e:e.cy(),f=p.style();if(!c.easingImpl)if(null==d)c.easingImpl=a.linear;else{var v=void 0;if(s.string(d)){var g=f.parse("transition-timing-function",d);v=g.value}else v=d;var m=void 0,y=void 0;s.string(v)?(m=v,y=[]):(m=v[1],y=v.slice(2).map(function(e){return+e})),y.length>0?("spring"===m&&y.push(c.duration),c.easingImpl=a[m].apply(null,y)):c.easingImpl=a[m]}var b=c.easingImpl,x=void 0;if(x=0===c.duration?1:(n-h)/c.duration,c.applying&&(x=c.progress),x<0?x=0:x>1&&(x=1),null==c.delay){var w=c.startPosition,E=c.position;if(E&&l&&!e.locked()){var P=e.position();i(w.x,E.x)&&(P.x=o(w.x,E.x,x,b)),i(w.y,E.y)&&(P.y=o(w.y,E.y,x,b)),e.emit("position")}var C=c.startPan,T=c.pan,S=u.pan,D=null!=T&&r;D&&(i(C.x,T.x)&&(S.x=o(C.x,T.x,x,b)),i(C.y,T.y)&&(S.y=o(C.y,T.y,x,b)),e.emit("pan"));var k=c.startZoom,_=c.zoom,M=null!=_&&r;M&&(i(k,_)&&(u.zoom=o(k,_,x,b)),e.emit("zoom")),(D||M)&&e.emit("viewport");var I=c.style;if(I&&I.length>0&&l){for(var N=0;N0;)t.removeChild(t.childNodes[0]);e._private.renderer=null},onRender:function(e){return this.on("render",e)},offRender:function(e){return this.off("render",e)}};i.invalidateDimensions=i.resize,e.exports=i},function(e,t,n){"use strict";var r=n(0),i=n(7),a={collection:function(e,t){return r.string(e)?this.$(e):r.elementOrCollection(e)?e.collection():r.array(e)?new i(this,e,t):new i(this)},nodes:function(e){var t=this.$(function(e){return e.isNode()});return e?t.filter(e):t},edges:function(e){var t=this.$(function(e){return e.isEdge()});return e?t.filter(e):t},$:function(e){var t=this._private.elements;return e?t.filter(e):t.spawnSelf()},mutableElements:function(){return this._private.elements}};a.elements=a.filter=a.$,e.exports=a},function(e,t,n){"use strict";var r=n(0),i=n(18),a={style:function(e){if(e){this.setStyle(e).update()}return this._private.style},setStyle:function(e){var t=this._private;return r.stylesheet(e)?t.style=e.generateStyle(this):r.array(e)?t.style=i.fromJson(this,e):r.string(e)?t.style=i.fromString(this,e):t.style=i(this),t.style}};e.exports=a},function(e,t,n){"use strict";var r=n(0),i=n(4),a=n(2),o={autolock:function(e){return void 0===e?this._private.autolock:(this._private.autolock=!!e,this)},autoungrabify:function(e){return void 0===e?this._private.autoungrabify:(this._private.autoungrabify=!!e,this)},autounselectify:function(e){return void 0===e?this._private.autounselectify:(this._private.autounselectify=!!e,this)},panningEnabled:function(e){return void 0===e?this._private.panningEnabled:(this._private.panningEnabled=!!e,this)},userPanningEnabled:function(e){return void 0===e?this._private.userPanningEnabled:(this._private.userPanningEnabled=!!e,this)},zoomingEnabled:function(e){return void 0===e?this._private.zoomingEnabled:(this._private.zoomingEnabled=!!e,this)},userZoomingEnabled:function(e){return void 0===e?this._private.userZoomingEnabled:(this._private.userZoomingEnabled=!!e,this)},boxSelectionEnabled:function(e){return void 0===e?this._private.boxSelectionEnabled:(this._private.boxSelectionEnabled=!!e,this)},pan:function(){var e=arguments,t=this._private.pan,n=void 0,i=void 0,a=void 0,o=void 0,s=void 0;switch(e.length){case 0:return t;case 1:if(r.string(e[0]))return n=e[0],t[n];if(r.plainObject(e[0])){if(!this._private.panningEnabled)return this;a=e[0],o=a.x,s=a.y,r.number(o)&&(t.x=o),r.number(s)&&(t.y=s),this.emit("pan viewport")}break;case 2:if(!this._private.panningEnabled)return this;n=e[0],i=e[1],"x"!==n&&"y"!==n||!r.number(i)||(t[n]=i),this.emit("pan viewport")}return this.notify({type:"viewport"}),this},panBy:function(e,t){var n=arguments,i=this._private.pan,a=void 0,o=void 0,s=void 0,l=void 0,u=void 0;if(!this._private.panningEnabled)return this;switch(n.length){case 1:r.plainObject(e)&&(s=n[0],l=s.x,u=s.y,r.number(l)&&(i.x+=l),r.number(u)&&(i.y+=u),this.emit("pan viewport"));break;case 2:a=e,o=t,"x"!==a&&"y"!==a||!r.number(o)||(i[a]+=o),this.emit("pan viewport")}return this.notify({type:"viewport"}),this},fit:function(e,t){var n=this.getFitViewport(e,t);if(n){var r=this._private;r.zoom=n.zoom,r.pan=n.pan,this.emit("pan zoom viewport"),this.notify({type:"viewport"})}return this},getFitViewport:function(e,t){if(r.number(e)&&void 0===t&&(t=e,e=void 0),this._private.panningEnabled&&this._private.zoomingEnabled){var n=void 0;if(r.string(e)){var i=e;e=this.$(i)}else if(r.boundingBox(e)){var a=e;n={x1:a.x1,y1:a.y1,x2:a.x2,y2:a.y2},n.w=n.x2-n.x1,n.h=n.y2-n.y1}else r.elementOrCollection(e)||(e=this.mutableElements());n=n||e.boundingBox();var o=this.width(),s=this.height(),l=void 0;if(t=r.number(t)?t:0,!isNaN(o)&&!isNaN(s)&&o>0&&s>0&&!isNaN(n.w)&&!isNaN(n.h)&&n.w>0&&n.h>0){l=Math.min((o-2*t)/n.w,(s-2*t)/n.h),l=l>this._private.maxZoom?this._private.maxZoom:l,l=lt.maxZoom?t.maxZoom:s,s=st.maxZoom||!t.zoomingEnabled?o=!0:(t.zoom=l,a.push("zoom"))}if(i&&(!o||!e.cancelOnFailedZoom)&&t.panningEnabled){var u=e.pan;r.number(u.x)&&(t.pan.x=u.x,s=!1),r.number(u.y)&&(t.pan.y=u.y,s=!1),s||a.push("pan")}return a.length>0&&(a.push("viewport"),this.emit(a.join(" ")),this.notify({type:"viewport"})),this},center:function(e){var t=this.getCenterPan(e);return t&&(this._private.pan=t,this.emit("pan viewport"),this.notify({type:"viewport"})),this},getCenterPan:function(e,t){if(this._private.panningEnabled){if(r.string(e)){var n=e;e=this.mutableElements().filter(n)}else r.elementOrCollection(e)||(e=this.mutableElements());var i=e.boundingBox(),a=this.width(),o=this.height();t=void 0===t?this._private.zoom:t;return{x:(a-t*(i.x1+i.x2))/2,y:(o-t*(i.y1+i.y2))/2}}},reset:function(){return this._private.panningEnabled&&this._private.zoomingEnabled?(this.viewport({pan:{x:0,y:0},zoom:1}),this):this},invalidateSize:function(){this._private.sizeCache=null},size:function(){var e=this._private,t=e.container;return e.sizeCache=e.sizeCache||(t?function(){var e=i.getComputedStyle(t),n=function(t){return parseFloat(e.getPropertyValue(t))};return{width:t.clientWidth-n("padding-left")-n("padding-right"),height:t.clientHeight-n("padding-top")-n("padding-bottom")}}():{width:1,height:1})},width:function(){return this.size().width},height:function(){return this.size().height},extent:function(){var e=this._private.pan,t=this._private.zoom,n=this.renderedExtent(),r={x1:(n.x1-e.x)/t,x2:(n.x2-e.x)/t,y1:(n.y1-e.y)/t,y2:(n.y2-e.y)/t};return r.w=r.x2-r.x1,r.h=r.y2-r.y1,r},renderedExtent:function(){var e=this.width(),t=this.height();return{x1:0,y1:0,x2:e,y2:t,w:e,h:t}}};o.centre=o.center,o.autolockNodes=o.autolock,o.autoungrabifyNodes=o.autoungrabify,e.exports=o},function(e,t,n){"use strict";var r=n(1),i=n(24),a=n(2),o=n(0),s={animated:function(){return function(){var e=this,t=void 0!==e.length,n=t?e:[e];if(!(this._private.cy||this).styleEnabled())return!1;var r=n[0];return r?r._private.animation.current.length>0:void 0}},clearQueue:function(){return function(){var e=this,t=void 0!==e.length,n=t?e:[e];if(!(this._private.cy||this).styleEnabled())return this;for(var r=0;r0;)!function(){var e=n.collection();r.bfs({roots:v[0],visit:function(t,n,r,i,a){e=e.add(t)},directed:!1}),v=v.not(e),f.push(e)}();u=n.collection();for(var g=0;gm.length-1;)m.push([]);m[G].push(H),Z.depth=G,Z.index=m[G].length-1}L()}var Q=0;if(t.avoidOverlap)for(var K=0;Kc||0===t)&&(r+=u/d,a++)}return a=Math.max(1,a),r/=a,0===a&&(r=void 0),re[e.id()]=r,r},ae=function(e,t){return ie(e)-ie(t)},oe=0;oe<3;oe++){for(var se=0;se=0;he--)for(var pe=m[he],fe=0;fe0&&m[0].length<=3?c/2:0),h=2*Math.PI/m[i].length*a;return 0===i&&1===m[0].length&&(d=1),{x:ce.x+d*Math.cos(h),y:ce.y+d*Math.sin(h)}}return{x:ce.x+(a+1-(o+1)/2)*s,y:(i+1)*u}}var p={x:ce.x+(a+1-(o+1)/2)*s,y:(i+1)*u};return p}(ve,m.length)}return i.layoutPositions(this,t,function(e){return de[e.id()]}),this},e.exports=r},function(e,t,n){"use strict";function r(e){this.options=i.extend({},s,e)}var i=n(1),a=n(2),o=n(0),s={fit:!0,padding:30,boundingBox:void 0,avoidOverlap:!0,nodeDimensionsIncludeLabels:!1,spacingFactor:void 0,radius:void 0,startAngle:1.5*Math.PI,sweep:void 0,clockwise:!0,sort:void 0,animate:!1,animationDuration:500,animationEasing:void 0,animateFilter:function(e,t){return!0},ready:void 0,stop:void 0,transform:function(e,t){return t}};r.prototype.run=function(){var e=this.options,t=e,n=e.cy,r=t.eles,i=void 0!==t.counterclockwise?!t.counterclockwise:t.clockwise,s=r.nodes().not(":parent");t.sort&&(s=s.sort(t.sort));for(var l=a.makeBoundingBox(t.boundingBox?t.boundingBox:{x1:0,y1:0,w:n.width(),h:n.height()}),u={x:l.x1+l.w/2,y:l.y1+l.h/2},c=void 0===t.sweep?2*Math.PI-2*Math.PI/s.length:t.sweep,d=c/Math.max(1,s.length-1),h=void 0,p=0,f=0;f1&&t.avoidOverlap){p*=1.75;var b=Math.cos(d)-Math.cos(0),x=Math.sin(d)-Math.sin(0),w=Math.sqrt(p*p/(b*b+x*x));h=Math.max(w,h)}var E=function(e,n){var r=t.startAngle+n*d*(i?1:-1),a=h*Math.cos(r),o=h*Math.sin(r);return{x:u.x+a,y:u.y+o}};return s.layoutPositions(this,t,E),this},e.exports=r},function(e,t,n){"use strict";function r(e){this.options=i.extend({},o,e)}var i=n(1),a=n(2),o={fit:!0,padding:30,startAngle:1.5*Math.PI,sweep:void 0,clockwise:!0,equidistant:!1,minNodeSpacing:10,boundingBox:void 0,avoidOverlap:!0,nodeDimensionsIncludeLabels:!1,height:void 0,width:void 0,spacingFactor:void 0,concentric:function(e){return e.degree()},levelWidth:function(e){return e.maxDegree()/4},animate:!1,animationDuration:500,animationEasing:void 0,animateFilter:function(e,t){return!0},ready:void 0,stop:void 0,transform:function(e,t){return t}};r.prototype.run=function(){for(var e=this.options,t=e,n=void 0!==t.counterclockwise?!t.counterclockwise:t.clockwise,r=e.cy,i=t.eles,o=i.nodes().not(":parent"),s=a.makeBoundingBox(t.boundingBox?t.boundingBox:{x1:0,y1:0,w:r.width(),h:r.height()}),l={x:s.x1+s.w/2,y:s.y1+s.h/2},u=[],c=(t.startAngle,0),d=0;d0){Math.abs(b[0].value-w.value)>=m&&(b=[],y.push(b))}b.push(w)}var E=c+t.minNodeSpacing;if(!t.avoidOverlap){var P=y.length>0&&y[0].length>1,C=Math.min(s.w,s.h)/2-E,T=C/(y.length+P?1:0);E=Math.min(E,T)}for(var S=0,D=0;D1&&t.avoidOverlap){var I=Math.cos(M)-Math.cos(0),N=Math.sin(M)-Math.sin(0),B=Math.sqrt(E*E/(I*I+N*N));S=Math.max(B,S)}k.r=S,S+=E}if(t.equidistant){for(var L=0,z=0,O=0;O0)var l=r.nodeOverlap*o,d=Math.sqrt(i*i+a*a),h=l*i/d,p=l*a/d;else var f=c(e,i,a),v=c(t,-1*i,-1*a),g=v.x-f.x,m=v.y-f.y,y=g*g+m*m,d=Math.sqrt(y),l=(e.nodeRepulsion+t.nodeRepulsion)/y,h=l*g/d,p=l*m/d;e.isLocked||(e.offsetX-=h,e.offsetY-=p),t.isLocked||(t.offsetX+=h,t.offsetY+=p)}},u=function(e,t,n,r){if(n>0)var i=e.maxX-t.minX;else var i=t.maxX-e.minX;if(r>0)var a=e.maxY-t.minY;else var a=t.maxY-e.minY;return i>=0&&a>=0?Math.sqrt(i*i+a*a):0},c=function(e,t,n){var r=e.positionX,i=e.positionY,a=e.height||1,o=e.width||1,s=n/t,l=a/o,u={};return 0===t&&0n?(u.x=r,u.y=i+a/2,u):0t&&-1*l<=s&&s<=l?(u.x=r-o/2,u.y=i-o*n/2/t,u):0=l)?(u.x=r+a*t/2/n,u.y=i+a/2,u):0>n&&(s<=-1*l||s>=l)?(u.x=r-a*t/2/n,u.y=i-a/2,u):u},d=function(e,t){for(var n=0;n1){var f=t.gravity*d/p,v=t.gravity*h/p;c.offsetX+=f,c.offsetY+=v}}}}},p=function(e,t){var n=[],r=0,i=-1;for(n.push.apply(n,e.graphSet[0]),i+=e.graphSet[0].length;r<=i;){var a=n[r++],o=e.idToIndex[a],s=e.layoutNodes[o],l=s.children;if(0n)var i={x:n*e/r,y:n*t/r};else var i={x:e,y:t};return i},g=function e(t,n){var r=t.parentId;if(null!=r){var i=n.layoutNodes[n.idToIndex[r]],a=!1;return(null==i.maxX||t.maxX+i.padRight>i.maxX)&&(i.maxX=t.maxX+i.padRight,a=!0),(null==i.minX||t.minX-i.padLefti.maxY)&&(i.maxY=t.maxY+i.padBottom,a=!0),(null==i.minY||t.minY-i.padTopg&&(p+=v+t.componentSpacing,h=0,f=0,v=0)}}}(0,i),r}).then(function(e){h.layoutNodes=e.layoutNodes,o.stop(),b()});var b=function(){!0===t.animate||!1===t.animate?y({force:!0,next:function(){r.one("layoutstop",t.stop),r.emit({type:"layoutstop",layout:r})}}):t.eles.nodes().layoutPositions(r,t,function(e){var t=h.layoutNodes[h.idToIndex[e.data("id")]];return{x:t.positionX,y:t.positionY}})};return this},r.prototype.stop=function(){return this.stopped=!0,this.thread&&this.thread.stop(),this.emit("layoutstop"),this},r.prototype.destroy=function(){return this.thread&&this.thread.stop(),this};var c=function(e,t,n){for(var r=n.eles.edges(),i=n.eles.nodes(),a={isCompound:e.hasCompoundNodes(),layoutNodes:[],idToIndex:{},nodeSize:i.size(),graphSet:[],indexToGraph:[],layoutEdges:[],edgeSize:r.size(),temperature:n.initialTemp,clientWidth:e.width(),clientHeight:e.width(),boundingBox:o.makeBoundingBox(n.boundingBox?n.boundingBox:{x1:0,y1:0,w:e.width(),h:e.height()})},l=n.eles.components(),u={},c=0;c0){a.graphSet.push(T);for(var c=0;cr.count?0:r.graph},h=function e(t,n,r,i){var a=i.graphSet[r];if(-1s){var v=d(),g=h();(v-1)*g>=s?d(v-1):(g-1)*v>=s&&h(g-1)}else for(;c*u=s?h(y+1):d(m+1)}var b=o.w/c,x=o.h/u;if(t.condense&&(b=0,x=0),t.avoidOverlap)for(var w=0;w=c&&(N=0,I++)},L={},z=0;z=0;E--){var P=f[E];P.isNode()?s(P)||u(P):function(n){var r,a=n._private,l=a.rscratch,u=n.pstyle("width").pfValue,c=n.pstyle("arrow-scale").value,d=u/2+y,f=d*d,g=2*d,b=a.source,x=a.target;if("segments"===l.edgeType||"straight"===l.edgeType||"haystack"===l.edgeType){for(var w=l.allpts,E=0;E+3(r=i.sqdistToFiniteLine(e,t,w[E],w[E+1],w[E+2],w[E+3])))return o(n,r),!0}else if("bezier"===l.edgeType||"multibezier"===l.edgeType||"self"===l.edgeType||"compound"===l.edgeType)for(var w=l.allpts,E=0;E+5(r=i.sqdistToQuadraticBezier(e,t,w[E],w[E+1],w[E+2],w[E+3],w[E+4],w[E+5])))return o(n,r),!0;for(var b=b||a.source,x=x||a.target,P=h.getArrowWidth(u,c),C=[{name:"source",x:l.arrowStartX,y:l.arrowStartY,angle:l.srcArrowAngle},{name:"target",x:l.arrowEndX,y:l.arrowEndY,angle:l.tgtArrowAngle},{name:"mid-source",x:l.midX,y:l.midY,angle:l.midsrcArrowAngle},{name:"mid-target",x:l.midX,y:l.midY,angle:l.midtgtArrowAngle}],E=0;E0&&(s(b),s(x))}(P)||u(P)||u(P,"source")||u(P,"target")}return v},o.getAllInBox=function(e,t,n,r){var a=this.getCachedZSortedEles().interactive,o=[],s=Math.min(e,n),l=Math.max(e,n),u=Math.min(t,r),c=Math.max(t,r);e=s,n=l,t=u,r=c;for(var d=i.makeBoundingBox({x1:e,y1:t,x2:n,y2:r}),h=0;hy?y+"$-$"+m:m+"$-$"+y,v&&(t="unbundled$-$"+p.id);var b=s[t];null==b&&(b=s[t]=[],l.push(t)),b.push(d),v&&(b.hasUnbundled=!0),g&&(b.hasBezier=!0)}else u.push(d)}for(var x,w,E,P,C,T,S,D,k,_,M,I,N=0;Nw.id()){var L=x;x=w,w=L}x._private,w._private,E=x.position(),P=w.position(),C=x.outerWidth(),T=x.outerHeight(),S=w.outerWidth(),D=w.outerHeight(),k=n.nodeShapes[this.getNodeShape(x)],_=n.nodeShapes[this.getNodeShape(w)],I=!1;for(var d,z,O,A={north:0,west:0,south:0,east:0,northwest:0,southwest:0,northeast:0,southeast:0},R=E.x,V=E.y,q=C,F=T,j=P.x,X=P.y,Y=S,W=D,H=B.length,c=0;c=c||x){h={cp:m,segment:b};break}}if(h)break}var m=h.cp,b=h.segment,w=(c-f)/b.length,E=b.t1-b.t0,P=o?b.t0+E*w:b.t1-E*w;P=r.bound(0,P,1),t=r.qbezierPtAt(m.p0,m.p1,m.p2,P),a=function(e,t,n,i){var a=r.bound(0,i-.001,1),o=r.bound(0,i+.001,1),s=r.qbezierPtAt(e,t,n,a),l=r.qbezierPtAt(e,t,n,o);return d(s,l)}(m.p0,m.p1,m.p2,P);break;case"straight":case"segments":case"haystack":for(var C,T,S,D,k=0,_=i.allpts.length,g=0;g+3<_&&(o?(S={x:i.allpts[g],y:i.allpts[g+1]},D={x:i.allpts[g+2],y:i.allpts[g+3]}):(S={x:i.allpts[_-2-g],y:i.allpts[_-1-g]},D={x:i.allpts[_-4-g],y:i.allpts[_-3-g]}),C=r.dist(S,D),T=k,!((k+=C)>=c));g+=2);var M=c-T,P=M/C;P=r.bound(0,P,1),t=r.lineAt(S,D,P),a=d(S,D)}l("labelX",n,t.x),l("labelY",n,t.y),l("labelAutoAngle",n,a)}};c("source"),c("target"),this.applyLabelDimensions(e)}},o.applyLabelDimensions=function(e){this.applyPrefixedLabelDimensions(e),e.isEdge()&&(this.applyPrefixedLabelDimensions(e,"source"),this.applyPrefixedLabelDimensions(e,"target"))},o.applyPrefixedLabelDimensions=function(e,t){var n=e._private,r=this.getLabelText(e,t),i=this.calculateLabelDimensions(e,r);a.setPrefixedProperty(n.rstyle,"labelWidth",t,i.width),a.setPrefixedProperty(n.rscratch,"labelWidth",t,i.width),a.setPrefixedProperty(n.rstyle,"labelHeight",t,i.height),a.setPrefixedProperty(n.rscratch,"labelHeight",t,i.height)},o.getLabelText=function(e,t){var n=e._private,r=t?t+"-":"",i=e.pstyle(r+"label").strValue,o=e.pstyle("text-transform").value,s=function(e,r){return r?(a.setPrefixedProperty(n.rscratch,e,t,r),r):a.getPrefixedProperty(n.rscratch,e,t)};"none"==o||("uppercase"==o?i=i.toUpperCase():"lowercase"==o&&(i=i.toLowerCase()));var l=e.pstyle("text-wrap").value;if("wrap"===l){var u=s("labelKey");if(u&&s("labelWrapKey")===u)return s("labelWrapCachedText");for(var c=i.split("\n"),d=e.pstyle("text-max-width").pfValue,h=[],p=0;pd){for(var v=f.split(/\s+/),g="",m=0;md)break;x+=i[E],E===i.length-1&&(w=!0)}return w||(x+="…"),x}return i},o.calculateLabelDimensions=function(e,t,n){var r=this,i=e._private.labelStyleKey+"$@$"+t;n&&(i+="$@$"+n);var a=r.labelDimCache||(r.labelDimCache={});if(a[i])return a[i];var o=e.pstyle("font-style").strValue,s=1*e.pstyle("font-size").pfValue+"px",l=e.pstyle("font-family").strValue,u=e.pstyle("font-weight").strValue,c=this.labelCalcDiv;c||(c=this.labelCalcDiv=document.createElement("div"),document.body.appendChild(c));var d=c.style;return d.fontFamily=l,d.fontStyle=o,d.fontSize=s,d.fontWeight=u,d.position="absolute",d.left="-9999px",d.top="-9999px",d.zIndex="-1",d.visibility="hidden",d.pointerEvents="none",d.padding="0",d.lineHeight="1","wrap"===e.pstyle("text-wrap").value?d.whiteSpace="pre":d.whiteSpace="normal",c.textContent=t,a[i]={width:Math.ceil(c.clientWidth/1),height:Math.ceil(c.clientHeight/1)},a[i]},o.calculateLabelAngles=function(e){var t=e._private,n=t.rscratch,r=e.isEdge(),i=e.pstyle("text-rotation"),a=i.strValue;"none"===a?n.labelAngle=n.sourceLabelAngle=n.targetLabelAngle=0:r&&"autorotate"===a?(n.labelAngle=Math.atan(n.midDispY/n.midDispX),n.sourceLabelAngle=n.sourceLabelAutoAngle,n.targetLabelAngle=n.targetLabelAutoAngle):n.labelAngle=n.sourceLabelAngle=n.targetLabelAngle="autorotate"===a?0:i.pfValue},e.exports=o},function(e,t,n){"use strict";var r={};r.getNodeShape=function(e){var t=this,n=e.pstyle("shape").value;if(e.isParent())return"rectangle"===n||"roundrectangle"===n||"cutrectangle"===n||"barrel"===n?n:"rectangle";if("polygon"===n){var r=e.pstyle("shape-polygon-points").value;return t.nodeShapes.makePolygon(r).name}return n},e.exports=r},function(e,t,n){"use strict";var r={};r.registerCalculationListeners=function(){var e=this.cy,t=e.collection(),n=this,r=function(e,n,r){if(t.merge(e),!0===r||void 0===r)for(var i=0;i=e.desktopTapThreshold2}var _=n(i);m&&(e.hoverData.tapholdCancelled=!0),s=!0,t(v,["mousemove","vmousemove","tapdrag"],i,{position:{x:d[0],y:d[1]}});var M=function(){e.data.bgActivePosistion=void 0,e.hoverData.selecting||l.emit("boxstart"),f[4]=1,e.hoverData.selecting=!0,e.redrawHint("select",!0),e.redraw()};if(3===e.hoverData.which){if(m){var I={originalEvent:i,type:"cxtdrag",position:{x:d[0],y:d[1]}};x?x.emit(I):l.emit(I),e.hoverData.cxtDragged=!0,e.hoverData.cxtOver&&v===e.hoverData.cxtOver||(e.hoverData.cxtOver&&e.hoverData.cxtOver.emit({originalEvent:i,type:"cxtdragout",position:{x:d[0],y:d[1]}}),e.hoverData.cxtOver=v,v&&v.emit({originalEvent:i,type:"cxtdragover",position:{x:d[0],y:d[1]}}))}}else if(e.hoverData.dragging){if(s=!0,l.panningEnabled()&&l.userPanningEnabled()){var N;if(e.hoverData.justStartedPan){var B=e.hoverData.mdownPos;N={x:(d[0]-B[0])*u,y:(d[1]-B[1])*u},e.hoverData.justStartedPan=!1}else N={x:w[0]*u,y:w[1]*u};l.panBy(N),e.hoverData.dragged=!0}d=e.projectIntoViewport(i.clientX,i.clientY)}else if(1!=f[4]||null!=x&&!x.isEdge()){if(x&&x.isEdge()&&x.active()&&x.unactivate(),x&&x.grabbed()||v==b||(b&&t(b,["mouseout","tapdragout"],i,{position:{x:d[0],y:d[1]}}),v&&t(v,["mouseover","tapdragover"],i,{position:{x:d[0],y:d[1]}}),e.hoverData.last=v),x&&e.nodeIsDraggable(x))if(m)if(l.boxSelectionEnabled()&&_)x&&x.grabbed()&&(y(E),x.emit("free")),M();else{var L=!e.dragData.didDrag;L&&e.redrawHint("eles",!0),e.dragData.didDrag=!0;var z=[];e.hoverData.draggingEles||g(l.collection(E),{inDragLayer:!0});for(var O=0;O0&&e.redrawHint("eles",!0),e.dragData.possibleDragElements=l=[]),t(s,["mouseup","tapend","vmouseup"],r,{position:{x:a[0],y:a[1]}}),e.dragData.didDrag||e.hoverData.dragged||e.hoverData.selecting||e.hoverData.isOverThresholdDrag||t(u,["click","tap","vclick"],r,{position:{x:a[0],y:a[1]}}),s!=u||e.dragData.didDrag||e.hoverData.selecting||null!=s&&s._private.selectable&&(e.hoverData.dragging||("additive"===i.selectionType()||c?s.selected()?s.unselect():s.select():c||(i.$(":selected").unmerge(s).unselect(),s.select())),e.redrawHint("eles",!0)),e.hoverData.selecting){var p=i.collection(e.getAllInBox(o[0],o[1],o[2],o[3]));e.redrawHint("select",!0),p.length>0&&e.redrawHint("eles",!0),i.emit("boxend");var f=function(e){return e.selectable()&&!e.selected()};"additive"===i.selectionType()?p.emit("box").stdFilter(f).select().emit("boxselect"):(c||i.$(":selected").unmerge(p).unselect(),p.emit("box").stdFilter(f).select().emit("boxselect")),e.redraw()}if(e.hoverData.dragging&&(e.hoverData.dragging=!1,e.redrawHint("select",!0),e.redrawHint("eles",!0),e.redraw()),!o[4]){e.redrawHint("drag",!0),e.redrawHint("eles",!0);var v=u&&u.grabbed();y(l),v&&u.emit("free")}}o[4]=0,e.hoverData.down=null,e.hoverData.cxtStarted=!1,e.hoverData.draggingEles=!1,e.hoverData.selecting=!1,e.hoverData.isOverThresholdDrag=!1,e.dragData.didDrag=!1,e.hoverData.dragged=!1,e.hoverData.dragDelta=[],e.hoverData.mdownPos=null,e.hoverData.mdownGPos=null}},!1);var T=function(t){if(!e.scrollingPage){var n=e.cy,r=e.projectIntoViewport(t.clientX,t.clientY),i=[r[0]*n.zoom()+n.pan().x,r[1]*n.zoom()+n.pan().y];if(e.hoverData.draggingEles||e.hoverData.dragging||e.hoverData.cxtStarted||P())return void t.preventDefault();if(n.panningEnabled()&&n.userPanningEnabled()&&n.zoomingEnabled()&&n.userZoomingEnabled()){t.preventDefault(),e.data.wheelZooming=!0,clearTimeout(e.data.wheelTimeout),e.data.wheelTimeout=setTimeout(function(){e.data.wheelZooming=!1,e.redrawHint("eles",!0),e.redraw()},150);var a;a=null!=t.deltaY?t.deltaY/-250:null!=t.wheelDeltaY?t.wheelDeltaY/1e3:t.wheelDelta/1e3,a*=e.wheelSensitivity;1===t.deltaMode&&(a*=33),n.zoom({level:n.zoom()*Math.pow(10,a),renderedPosition:{x:i[0],y:i[1]}})}}};e.registerBinding(e.container,"wheel",T,!0),e.registerBinding(window,"scroll",function(t){e.scrollingPage=!0,clearTimeout(e.scrollingPageTimeout),e.scrollingPageTimeout=setTimeout(function(){e.scrollingPage=!1},250)},!0),e.registerBinding(e.container,"mouseout",function(t){var n=e.projectIntoViewport(t.clientX,t.clientY);e.cy.emit({originalEvent:t,type:"mouseout",position:{x:n[0],y:n[1]}})},!1),e.registerBinding(e.container,"mouseover",function(t){var n=e.projectIntoViewport(t.clientX,t.clientY);e.cy.emit({originalEvent:t,type:"mouseover",position:{x:n[0],y:n[1]}})},!1);var S,D,k,_,M,I,N,B,L,z,O,A,R,V,q=function(e,t,n,r){return Math.sqrt((n-e)*(n-e)+(r-t)*(r-t))},F=function(e,t,n,r){return(n-e)*(n-e)+(r-t)*(r-t)};e.registerBinding(e.container,"touchstart",V=function(n){if(C(n)){e.touchData.capture=!0,e.data.bgActivePosistion=void 0;var r=e.cy,i=e.touchData.now,a=e.touchData.earlier;if(n.touches[0]){var o=e.projectIntoViewport(n.touches[0].clientX,n.touches[0].clientY);i[0]=o[0],i[1]=o[1]}if(n.touches[1]){var o=e.projectIntoViewport(n.touches[1].clientX,n.touches[1].clientY);i[2]=o[0],i[3]=o[1]}if(n.touches[2]){var o=e.projectIntoViewport(n.touches[2].clientX,n.touches[2].clientY);i[4]=o[0],i[5]=o[1]}if(n.touches[1]){y(e.dragData.touchDragEles);var s=e.findContainerClientCoords();L=s[0],z=s[1],O=s[2],A=s[3],S=n.touches[0].clientX-L,D=n.touches[0].clientY-z,k=n.touches[1].clientX-L,_=n.touches[1].clientY-z,R=0<=S&&S<=O&&0<=k&&k<=O&&0<=D&&D<=A&&0<=_&&_<=A;var l=r.pan(),u=r.zoom();M=q(S,D,k,_),I=F(S,D,k,_),N=[(S+k)/2,(D+_)/2],B=[(N[0]-l.x)/u,(N[1]-l.y)/u];if(I<4e4&&!n.touches[2]){var c=e.findNearestElement(i[0],i[1],!0,!0),d=e.findNearestElement(i[2],i[3],!0,!0);return c&&c.isNode()?(c.activate().emit({originalEvent:n,type:"cxttapstart",position:{x:i[0],y:i[1]}}),e.touchData.start=c):d&&d.isNode()?(d.activate().emit({originalEvent:n,type:"cxttapstart",position:{x:i[0],y:i[1]}}),e.touchData.start=d):r.emit({originalEvent:n,type:"cxttapstart",position:{x:i[0],y:i[1]}}),e.touchData.start&&(e.touchData.start._private.grabbed=!1),e.touchData.cxt=!0,e.touchData.cxtDragged=!1,e.data.bgActivePosistion=void 0,void e.redraw()}}if(n.touches[2]);else if(n.touches[1]);else if(n.touches[0]){var p=e.findNearestElements(i[0],i[1],!0,!0),f=p[0];if(null!=f&&(f.activate(),e.touchData.start=f,e.touchData.starts=p,e.nodeIsGrabbable(f))){var v=e.dragData.touchDragEles=[],b=null;e.redrawHint("eles",!0),e.redrawHint("drag",!0),f.selected()?(b=r.$(function(t){return t.selected()&&e.nodeIsGrabbable(t)}),g(b,{addToList:v})):m(f,{addToList:v}),h(f);var x=function(e){return{originalEvent:n,type:e,position:{x:i[0],y:i[1]}}};f.emit(x("grabon")),b?b.forEach(function(e){e.emit(x("grab"))}):f.emit(x("grab"))}t(f,["touchstart","tapstart","vmousedown"],n,{position:{x:i[0],y:i[1]}}),null==f&&(e.data.bgActivePosistion={x:o[0],y:o[1]},e.redrawHint("select",!0),e.redraw()),e.touchData.singleTouchMoved=!1,e.touchData.singleTouchStartTime=+new Date,clearTimeout(e.touchData.tapholdTimeout),e.touchData.tapholdTimeout=setTimeout(function(){!1!==e.touchData.singleTouchMoved||e.pinching||e.touchData.selecting||(t(e.touchData.start,["taphold"],n,{position:{x:i[0],y:i[1]}}),e.touchData.start||r.$(":selected").unselect())},e.tapholdDuration)}if(n.touches.length>=1){for(var w=e.touchData.startPosition=[],E=0;E=e.touchTapThreshold2}if(i&&e.touchData.cxt){n.preventDefault();var E=n.touches[0].clientX-L,P=n.touches[0].clientY-z,T=n.touches[1].clientX-L,N=n.touches[1].clientY-z,O=F(E,P,T,N),A=O/I;if(A>=2.25||O>=22500){e.touchData.cxt=!1,e.data.bgActivePosistion=void 0,e.redrawHint("select",!0);var V={originalEvent:n,type:"cxttapend",position:{x:u[0],y:u[1]}};e.touchData.start?(e.touchData.start.unactivate().emit(V),e.touchData.start=null):l.emit(V)}}if(i&&e.touchData.cxt){var V={originalEvent:n,type:"cxtdrag",position:{x:u[0],y:u[1]}};e.data.bgActivePosistion=void 0,e.redrawHint("select",!0),e.touchData.start?e.touchData.start.emit(V):l.emit(V),e.touchData.start&&(e.touchData.start._private.grabbed=!1),e.touchData.cxtDragged=!0;var j=e.findNearestElement(u[0],u[1],!0,!0);e.touchData.cxtOver&&j===e.touchData.cxtOver||(e.touchData.cxtOver&&e.touchData.cxtOver.emit({originalEvent:n,type:"cxtdragout",position:{x:u[0],y:u[1]}}),e.touchData.cxtOver=j,j&&j.emit({originalEvent:n,type:"cxtdragover",position:{x:u[0],y:u[1]}}))}else if(i&&n.touches[2]&&l.boxSelectionEnabled())n.preventDefault(),e.data.bgActivePosistion=void 0,this.lastThreeTouch=+new Date,e.touchData.selecting||l.emit("boxstart"),e.touchData.selecting=!0,e.redrawHint("select",!0),s&&0!==s.length&&void 0!==s[0]?(s[2]=(u[0]+u[2]+u[4])/3,s[3]=(u[1]+u[3]+u[5])/3):(s[0]=(u[0]+u[2]+u[4])/3,s[1]=(u[1]+u[3]+u[5])/3,s[2]=(u[0]+u[2]+u[4])/3+1,s[3]=(u[1]+u[3]+u[5])/3+1),s[4]=1,e.touchData.selecting=!0,e.redraw();else if(i&&n.touches[1]&&l.zoomingEnabled()&&l.panningEnabled()&&l.userZoomingEnabled()&&l.userPanningEnabled()){n.preventDefault(),e.data.bgActivePosistion=void 0,e.redrawHint("select",!0);var X=e.dragData.touchDragEles;if(X){e.redrawHint("drag",!0);for(var Y=0;Y0)return v[0]}return null}(e,t,v);if(null!=g){var m=v[5],y=v[3],b=v[1],x=r.qbezierAt(m,y,b,g);if(v.isTop&&x<=t)return!0;if(v.isBottom&&t<=x)return!0}}return!1}}},i.generateBottomRoundrectangle=function(){return this.nodeShapes.bottomroundrectangle={renderer:this,name:"bottomroundrectangle",points:r.generateUnitNgonPointsFitToSquare(4,0),draw:function(e,t,n,r,i){this.renderer.nodeShapeImpl(this.name,e,t,n,r,i)},intersectLine:function(e,t,n,i,a,o,s){var l=e-(n/2+s),u=t-(i/2+s),c=u,d=e+(n/2+s),h=r.finiteLinesIntersect(a,o,e,t,l,u,d,c,!1);return h.length>0?h:r.roundRectangleIntersectLine(a,o,e,t,n,i,s)},checkPoint:function(e,t,n,i,a,o,s){var l=r.getRoundRectangleRadius(i,a);if(r.pointInsidePolygon(e,t,this.points,o,s,i,a-2*l,[0,-1],n))return!0;if(r.pointInsidePolygon(e,t,this.points,o,s,i-2*l,a,[0,-1],n))return!0;var u=i/2+2*n,c=a/2+2*n,d=[o-u,s-c,o-u,s,o+u,s,o+u,s-c];return!!r.pointInsidePolygonPoints(e,t,d)||(!!r.checkInEllipse(e,t,o+i/2-l,s+a/2-l,2*l,2*l,n)||!!r.checkInEllipse(e,t,o-i/2+l,s+a/2-l,2*l,2*l,n))}}},i.registerNodeShapes=function(){var e=this.nodeShapes={},t=this;this.generateEllipse(),this.generatePolygon("triangle",r.generateUnitNgonPointsFitToSquare(3,0)),this.generatePolygon("rectangle",r.generateUnitNgonPointsFitToSquare(4,0)),e.square=e.rectangle,this.generateRoundRectangle(),this.generateCutRectangle(),this.generateBarrel(),this.generateBottomRoundrectangle(),this.generatePolygon("diamond",[0,1,1,0,0,-1,-1,0]),this.generatePolygon("pentagon",r.generateUnitNgonPointsFitToSquare(5,0)),this.generatePolygon("hexagon",r.generateUnitNgonPointsFitToSquare(6,0)),this.generatePolygon("heptagon",r.generateUnitNgonPointsFitToSquare(7,0)),this.generatePolygon("octagon",r.generateUnitNgonPointsFitToSquare(8,0));var n=new Array(20),i=r.generateUnitNgonPoints(5,0),a=r.generateUnitNgonPoints(5,Math.PI/5),o=.5*(3-Math.sqrt(5));o*=1.57;for(var s=0;s0&&void 0!==arguments[0]?arguments[0]:p;e.lineWidth=v,e.lineCap="butt",i.strokeStyle(e,h[0],h[1],h[2],n),i.drawEdgePath(t,e,a.allpts,f)},m=function(){var n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:p;i.drawArrowheads(e,t,n)};e.lineJoin="round";if("yes"===t.pstyle("ghost").value){var y=t.pstyle("ghost-offset-x").pfValue,b=t.pstyle("ghost-offset-y").pfValue,x=t.pstyle("ghost-opacity").value,w=p*x;e.translate(y,b),g(w),m(w),e.translate(-y,-b)}g(),m(),function(){var n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:c;e.lineWidth=u,"self"!==a.edgeType||o?e.lineCap="round":e.lineCap="butt",i.strokeStyle(e,d[0],d[1],d[2],n),i.drawEdgePath(t,e,a.allpts,"solid")}(),function(){i.drawElementText(e,t,r)}(),n&&e.translate(s.x1,s.y1)}},r.drawEdgePath=function(e,t,n,r){var i=e._private.rscratch,a=t,o=void 0,s=!1,l=this.usePaths();if(l){var u=n.join("$");i.pathCacheKey&&i.pathCacheKey===u?(o=t=i.pathCache,s=!0):(o=t=new Path2D,i.pathCacheKey=u,i.pathCache=o)}if(a.setLineDash)switch(r){case"dotted":a.setLineDash([1,1]);break;case"dashed":a.setLineDash([6,3]);break;case"solid":a.setLineDash([])}if(!s&&!i.badLine)switch(t.beginPath&&t.beginPath(),t.moveTo(n[0],n[1]),i.edgeType){case"bezier":case"self":case"compound":case"multibezier":for(var c=2;c+30||S>0&&T>0){var k=l-D;switch(y){case"left":k-=h;break;case"center":k-=h/2}var _=u-p-D,M=h+2*D,I=p+2*D;if(C>0){var N=e.fillStyle,B=t.pstyle("text-background-color").value;e.fillStyle="rgba("+B[0]+","+B[1]+","+B[2]+","+C*s+")";"roundrectangle"==t.pstyle("text-background-shape").strValue?r(e,k,_,M,I,2):e.fillRect(k,_,M,I),e.fillStyle=N}if(S>0&&T>0){var L=e.strokeStyle,z=e.lineWidth,O=t.pstyle("text-border-color").value,A=t.pstyle("text-border-style").value;if(e.strokeStyle="rgba("+O[0]+","+O[1]+","+O[2]+","+T*s+")",e.lineWidth=S,e.setLineDash)switch(A){case"dotted":e.setLineDash([1,1]);break;case"dashed":e.setLineDash([4,2]);break;case"double":e.lineWidth=S/4,e.setLineDash([]);break;case"solid":e.setLineDash([])}if(e.strokeRect(k,_,M,I),"double"===A){var R=S/2;e.strokeRect(k+R,_+R,M-2*R,I-2*R)}e.setLineDash&&e.setLineDash([]),e.lineWidth=z,e.strokeStyle=L}}var V=2*t.pstyle("text-outline-width").pfValue;if(V>0&&(e.lineWidth=V),"wrap"===t.pstyle("text-wrap").value){var q=i.getPrefixedProperty(o,"labelWrapCachedLines",n),F=p/q.length;switch(b){case"top":u-=(q.length-1)*F;break;case"center":case"bottom":u-=(q.length-1)*F}for(var j=0;j0&&e.strokeText(q[j],l,u),e.fillText(q[j],l,u),u+=F}else V>0&&e.strokeText(c,l,u),e.fillText(c,l,u);0!==x&&(e.rotate(-x),e.translate(-E,-P))}}},e.exports=o},function(e,t,n){"use strict";var r=n(0),i={};i.drawNode=function(e,t,n,i){var a=this,o=void 0,s=void 0,l=t._private,u=l.rscratch,c=t.position();if(r.number(c.x)&&r.number(c.y)&&t.visible()){var d=t.effectiveOpacity(),h=a.usePaths(),p=void 0,f=!1,v=t.padding();o=t.width()+2*v,s=t.height()+2*v,e.lineWidth=t.pstyle("border-width").pfValue;var g=void 0;n&&(g=n,e.translate(-g.x1,-g.y1));for(var m=t.pstyle("background-image"),y=m.value,b=void 0,x=[],w=[],E=y.length,P=0;P0&&void 0!==arguments[0]?arguments[0]:k;a.fillStyle(e,D[0],D[1],D[2],t)},B=function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:I;a.strokeStyle(e,_[0],_[1],_[2],t)},L=t.pstyle("shape").strValue,z=t.pstyle("shape-polygon-points").pfValue;if(h){var O=L+"$"+o+"$"+s+("polygon"===L?"$"+z.join("$"):"");e.translate(c.x,c.y),u.pathCacheKey===O?(p=u.pathCache,f=!0):(p=new Path2D,u.pathCacheKey=O,u.pathCache=p)}var A=function(){if(!f){var n=c;h&&(n={x:0,y:0}),a.nodeShapes[a.getNodeShape(t)].draw(p||e,n.x,n.y,o,s)}h?e.fill(p):e.fill()},R=function(){for(var n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:d,r=l.backgrounding,i=0,o=0;o0&&void 0!==arguments[0]&&arguments[0],r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:d;a.hasPie(t)&&(a.drawPie(e,t,r),n&&(h||a.nodeShapes[a.getNodeShape(t)].draw(e,c.x,c.y,o,s)))},q=function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:d,n=(T>0?T:-T)*t,r=T>0?0:255;0!==T&&(a.fillStyle(e,r,r,r,n),h?e.fill(p):e.fill())},F=function(){if(S>0&&(h?e.stroke(p):e.stroke(),"double"===M)){e.lineWidth=S/3;var t=e.globalCompositeOperation;e.globalCompositeOperation="destination-out",h?e.stroke(p):e.stroke(),e.globalCompositeOperation=t}};if("yes"===t.pstyle("ghost").value){var j=t.pstyle("ghost-offset-x").pfValue,X=t.pstyle("ghost-offset-y").pfValue,Y=t.pstyle("ghost-opacity").value,W=Y*d;e.translate(j,X),N(Y*k),A(),R(W),V(0!==T||0!==S),q(W),B(Y*I),F(),e.translate(-j,-X)}N(),A(),R(),V(0!==T||0!==S),q(),B(),F(),h&&e.translate(-c.x,-c.y),function(){a.drawElementText(e,t,i)}(),function(){var n=t.pstyle("overlay-padding").pfValue,r=t.pstyle("overlay-opacity").value,i=t.pstyle("overlay-color").value;r>0&&(a.fillStyle(e,i[0],i[1],i[2],r),a.nodeShapes.roundrectangle.draw(e,c.x,c.y,o+2*n,s+2*n),e.fill())}(),e.setLineDash&&e.setLineDash([]),n&&e.translate(g.x1,g.y1)}},i.hasPie=function(e){return e=e[0],e._private.hasPie},i.drawPie=function(e,t,n,r){t=t[0],r||t.position();var i=t.cy().style(),a=t.pstyle("pie-size"),o=r.x,s=r.y,l=t.width(),u=t.height(),c=Math.min(l,u)/2,d=0;this.usePaths()&&(o=0,s=0),"%"===a.units?c*=a.pfValue:void 0!==a.pfValue&&(c=a.pfValue/2);for(var h=1;h<=i.pieBackgroundN;h++){var p=t.pstyle("pie-"+h+"-background-size").value,f=t.pstyle("pie-"+h+"-background-color").value,v=t.pstyle("pie-"+h+"-background-opacity").value*n,g=p/100;g+d>1&&(g=1-d);var m=1.5*Math.PI+2*Math.PI*d,y=2*Math.PI*g,b=m+y;0===p||d>=1||d+g>1||(e.beginPath(),e.moveTo(o,s),e.arc(o,s,c,m,b),e.closePath(),this.fillStyle(e,f[0],f[1],f[2],v),e.fill(),d+=g)}},e.exports=i},function(e,t,n){"use strict";var r={},i=n(1);r.getPixelRatio=function(){var e=this.data.contexts[0];if(null!=this.forcedPixelRatio)return this.forcedPixelRatio;var t=e.backingStorePixelRatio||e.webkitBackingStorePixelRatio||e.mozBackingStorePixelRatio||e.msBackingStorePixelRatio||e.oBackingStorePixelRatio||e.backingStorePixelRatio||1;return(window.devicePixelRatio||1)/t},r.paintCache=function(e){for(var t,n=this.paintCaches=this.paintCaches||[],r=!0,i=0;iu.minMbLowQualFrames&&(u.motionBlurPxRatio=u.mbPxRBlurry)),u.clearingMotionBlur&&(u.motionBlurPxRatio=1),u.textureDrawLastFrame&&!f&&(p[u.NODE]=!0,p[u.SELECT_BOX]=!0);var w=d.style()._private.coreStyle,E=d.zoom(),P=void 0!==s?s:E,C=d.pan(),T={x:C.x,y:C.y},S={zoom:E,pan:{x:C.x,y:C.y}},D=u.prevViewport;void 0===D||S.zoom!==D.zoom||S.pan.x!==D.pan.x||S.pan.y!==D.pan.y||y&&!m||(u.motionBlurPxRatio=1),l&&(T=l),P*=c,T.x*=c,T.y*=c;var k=u.getCachedZSortedEles();if(f||(u.textureDrawLastFrame=!1),f){u.textureDrawLastFrame=!0;if(!u.textureCache){u.textureCache={},u.textureCache.bb=d.mutableElements().boundingBox(),u.textureCache.texture=u.data.bufferCanvases[u.TEXTURE_BUFFER];var _=u.data.bufferContexts[u.TEXTURE_BUFFER];_.setTransform(1,0,0,1,0,0),_.clearRect(0,0,u.canvasWidth*u.textureMult,u.canvasHeight*u.textureMult),u.render({forcedContext:_,drawOnlyNodeLayer:!0,forcedPxRatio:c*u.textureMult});var S=u.textureCache.viewport={zoom:d.zoom(),pan:d.pan(),width:u.canvasWidth,height:u.canvasHeight};S.mpan={x:(0-S.pan.x)/S.zoom,y:(0-S.pan.y)/S.zoom}}p[u.DRAG]=!1,p[u.NODE]=!1;var M=h.contexts[u.NODE],I=u.textureCache.texture,S=u.textureCache.viewport;u.textureCache.bb,M.setTransform(1,0,0,1,0,0),v?t(M,0,0,S.width,S.height):M.clearRect(0,0,S.width,S.height);var N=w["outside-texture-bg-color"].value,B=w["outside-texture-bg-opacity"].value;u.fillStyle(M,N[0],N[1],N[2],B),M.fillRect(0,0,S.width,S.height);var E=d.zoom();n(M,!1),M.clearRect(S.mpan.x,S.mpan.y,S.width/S.zoom/c,S.height/S.zoom/c),M.drawImage(I,S.mpan.x,S.mpan.y,S.width/S.zoom/c,S.height/S.zoom/c)}else u.textureOnViewport&&!r&&(u.textureCache=null);var L=d.extent(),z=u.pinching||u.hoverData.dragging||u.swipePanning||u.data.wheelZooming||u.hoverData.draggingEles,O=u.hideEdgesOnViewport&&z,A=[];if(A[u.NODE]=!p[u.NODE]&&v&&!u.clearedForMotionBlur[u.NODE]||u.clearingMotionBlur,A[u.NODE]&&(u.clearedForMotionBlur[u.NODE]=!0),A[u.DRAG]=!p[u.DRAG]&&v&&!u.clearedForMotionBlur[u.DRAG]||u.clearingMotionBlur,A[u.DRAG]&&(u.clearedForMotionBlur[u.DRAG]=!0),p[u.NODE]||a||o||A[u.NODE]){var R=v&&!A[u.NODE]&&1!==g,M=r||(R?u.data.bufferContexts[u.MOTIONBLUR_BUFFER_NODE]:h.contexts[u.NODE]);n(M,v&&!R?"motionBlur":void 0),O?u.drawCachedNodes(M,k.nondrag,c,L):u.drawLayeredElements(M,k.nondrag,c,L),u.debug&&u.drawDebugPoints(M,k.nondrag),a||v||(p[u.NODE]=!1)}if(!o&&(p[u.DRAG]||a||A[u.DRAG])){var R=v&&!A[u.DRAG]&&1!==g,M=r||(R?u.data.bufferContexts[u.MOTIONBLUR_BUFFER_DRAG]:h.contexts[u.DRAG]);n(M,v&&!R?"motionBlur":void 0),O?u.drawCachedNodes(M,k.drag,c,L):u.drawCachedElements(M,k.drag,c,L),u.debug&&u.drawDebugPoints(M,k.drag),a||v||(p[u.DRAG]=!1)}if(u.showFps||!o&&p[u.SELECT_BOX]&&!a){var M=r||h.contexts[u.SELECT_BOX];if(n(M),1==u.selection[4]&&(u.hoverData.selecting||u.touchData.selecting)){var E=u.cy.zoom(),V=w["selection-box-border-width"].value/E;M.lineWidth=V,M.fillStyle="rgba("+w["selection-box-color"].value[0]+","+w["selection-box-color"].value[1]+","+w["selection-box-color"].value[2]+","+w["selection-box-opacity"].value+")",M.fillRect(u.selection[0],u.selection[1],u.selection[2]-u.selection[0],u.selection[3]-u.selection[1]),V>0&&(M.strokeStyle="rgba("+w["selection-box-border-color"].value[0]+","+w["selection-box-border-color"].value[1]+","+w["selection-box-border-color"].value[2]+","+w["selection-box-opacity"].value+")",M.strokeRect(u.selection[0],u.selection[1],u.selection[2]-u.selection[0],u.selection[3]-u.selection[1]))}if(h.bgActivePosistion&&!u.hoverData.selecting){var E=u.cy.zoom(),q=h.bgActivePosistion;M.fillStyle="rgba("+w["active-bg-color"].value[0]+","+w["active-bg-color"].value[1]+","+w["active-bg-color"].value[2]+","+w["active-bg-opacity"].value+")",M.beginPath(),M.arc(q.x,q.y,w["active-bg-size"].pfValue/E,0,2*Math.PI),M.fill()}var F=u.lastRedrawTime;if(u.showFps&&F){F=Math.round(F);var j=Math.round(1e3/F);M.setTransform(1,0,0,1,0,0),M.fillStyle="rgba(255, 0, 0, 0.75)",M.strokeStyle="rgba(255, 0, 0, 0.75)",M.lineWidth=1,M.fillText("1 frame = "+F+" ms = "+j+" fps",0,20);M.strokeRect(0,30,250,20),M.fillRect(0,30,250*Math.min(j/60,1),20)}a||(p[u.SELECT_BOX]=!1)}if(v&&1!==g){var X=h.contexts[u.NODE],Y=u.data.bufferCanvases[u.MOTIONBLUR_BUFFER_NODE],W=h.contexts[u.DRAG],H=u.data.bufferCanvases[u.MOTIONBLUR_BUFFER_DRAG],Z=function(e,n,r){e.setTransform(1,0,0,1,0,0),r||!x?e.clearRect(0,0,u.canvasWidth,u.canvasHeight):t(e,0,0,u.canvasWidth,u.canvasHeight);var i=g;e.drawImage(n,0,0,u.canvasWidth*i,u.canvasHeight*i,0,0,u.canvasWidth,u.canvasHeight)};(p[u.NODE]||A[u.NODE])&&(Z(X,Y,A[u.NODE]),p[u.NODE]=!1),(p[u.DRAG]||A[u.DRAG])&&(Z(W,H,A[u.DRAG]),p[u.DRAG]=!1)}u.prevViewport=S,u.clearingMotionBlur&&(u.clearingMotionBlur=!1,u.motionBlurCleared=!0,u.motionBlur=!0),v&&(u.motionBlurTimeout=setTimeout(function(){u.motionBlurTimeout=null,u.clearedForMotionBlur[u.NODE]=!1,u.clearedForMotionBlur[u.DRAG]=!1,u.motionBlur=!1,u.clearingMotionBlur=!f,u.mbFrames=0,p[u.NODE]=!0,p[u.DRAG]=!0,u.redraw()},100)),r||d.emit("render")},e.exports=r},function(e,t,n){"use strict";var r=n(2),i={};i.drawPolygonPath=function(e,t,n,r,i,a){var o=r/2,s=i/2;e.beginPath&&e.beginPath(),e.moveTo(t+o*a[0],n+s*a[1]);for(var l=1;l=3.99||i>2)return null;var d=Math.pow(2,i),h=t.h*d,p=t.w*d,f=u.imgCaches=u.imgCaches||{},v=f[i];if(v)return v;var g;if(g=h<=25?25:h<=50?50:50*Math.ceil(h/50),h>1024||p>1024||e.isEdge()||e.isParent())return null;var m=o.getTextureQueue(g),y=m[m.length-2],b=function(){return o.recycleTexture(g,p)||o.addTexture(g,p)};y||(y=m[m.length-1]),y||(y=b()),y.width-y.usedWidthi;S--)k=o.getElement(e,t,n,S,s.downscale);_()}else{var M;if(!P&&!C&&!T)for(var S=i-1;S>=-4;S--){var D=f[S];if(D){M=D;break}}if(E(M))return o.queueElement(e,t,i),M;y.context.translate(y.usedWidth,0),y.context.scale(d,d),l.drawElement(y.context,e,t,w),y.context.scale(1/d,1/d),y.context.translate(-y.usedWidth,0)}return v=f[i]={ele:e,x:y.usedWidth,texture:y,level:i,scale:d,width:p,height:h,scaledLabelShown:w},y.usedWidth+=Math.ceil(p+8),y.eleCaches.push(v),o.checkTextureFullness(y),v},u.invalidateElement=function(e){var t=this,n=e._private.rscratch.imgCaches;if(n)for(var r=-4;r<=2;r++){var a=n[r];if(a){var o=a.texture;o.invalidatedWidth+=a.width,n[r]=null,i.removeFromArray(o.eleCaches,a),t.checkTextureUtility(o)}}},u.checkTextureUtility=function(e){e.invalidatedWidth>=.5*e.width&&this.retireTexture(e)},u.checkTextureFullness=function(e){var t=this,n=t.getTextureQueue(e.height);e.usedWidth/e.width>.8&&e.fullnessChecks>=10?i.removeFromArray(n,e):e.fullnessChecks++},u.retireTexture=function(e){var t=this,n=e.height,r=t.getTextureQueue(n);i.removeFromArray(r,e),e.retired=!0;for(var a=e.eleCaches,o=0;o=t)return s.retired=!1,s.usedWidth=0,s.invalidatedWidth=0,s.fullnessChecks=0,i.clearArray(s.eleCaches),s.context.setTransform(1,0,0,1,0,0),s.context.clearRect(0,0,s.width,s.height),i.removeFromArray(a,s),r.push(s),s}},u.queueElement=function(e,t,n){var i=this,a=i.getElementQueue(),o=i.getElementIdToQueue(),s=e.id(),l=o[s];if(l)l.level=Math.max(l.level,n),l.reqs++,a.updateItem(l);else{var u={ele:e,bb:t,position:r.copyPosition(e.position()),level:n,reqs:1};e.isEdge()&&(u.positions={source:r.copyPosition(e.source().position()),target:r.copyPosition(e.target().position())}),a.push(u),o[s]=u}},u.dequeue=function(e){for(var t=this,n=t.getElementQueue(),i=t.getElementIdToQueue(),a=[],o=0;o<1&&n.size()>0;o++){var l=n.pop();i[l.ele.id()]=null,a.push(l);var u,c=l.ele;u=(!c.isEdge()||r.arePositionsSame(c.source().position(),l.positions.source)&&r.arePositionsSame(c.target().position(),l.positions.target))&&r.arePositionsSame(c.position(),l.position)?l.bb:c.boundingBox(),t.getElement(l.ele,u,e,l.level,s.dequeue)}return a},u.onDequeue=function(e){this.onDequeues.push(e)},u.offDequeue=function(e){i.removeFromArray(this.onDequeues,e)},u.setupDequeueing=o.setupDequeueing({deqRedrawThreshold:100,deqCost:.15,deqAvgCost:.1,deqNoDrawCost:.9,deqFastCost:.9,deq:function(e,t,n){return e.dequeue(t,n)},onDeqd:function(e,t){for(var n=0;n0&&s>0){f.clearRect(0,0,a,s),f.globalCompositeOperation="source-over";var v=this.getCachedZSortedEles();if(e.full)f.translate(-r.x1*c,-r.y1*c),f.scale(c,c),this.drawElements(f,v),f.scale(1/c,1/c),f.translate(r.x1*c,r.y1*c);else{var g=t.pan(),m={x:g.x*c,y:g.y*c};c*=t.zoom(),f.translate(m.x,m.y),f.scale(c,c),this.drawElements(f,v),f.scale(1/c,1/c),f.translate(-m.x,-m.y)}e.bg&&(f.globalCompositeOperation="destination-over",f.fillStyle=e.bg,f.rect(0,0,a,s),f.fill())}return p},s.png=function(e){return a(e,this.bufferCanvasImage(e),"image/png")},s.jpg=function(e){return a(e,this.bufferCanvasImage(e),"image/jpeg")},e.exports=s},function(e,t,n){"use strict";function r(e){var t=this;t.data={canvases:new Array(u.CANVAS_LAYERS),contexts:new Array(u.CANVAS_LAYERS),canvasNeedsRedraw:new Array(u.CANVAS_LAYERS),bufferCanvases:new Array(u.BUFFER_COUNT),bufferContexts:new Array(u.CANVAS_LAYERS)},t.data.canvasContainer=document.createElement("div");var n=t.data.canvasContainer.style;t.data.canvasContainer.setAttribute("style","-webkit-tap-highlight-color: rgba(0,0,0,0);"),n.position="relative",n.zIndex="0",n.overflow="hidden";var r=e.cy.container();r.appendChild(t.data.canvasContainer),r.setAttribute("style",(r.getAttribute("style")||"")+"-webkit-tap-highlight-color: rgba(0,0,0,0);");for(var i=0;i0&&t.data.lyrTxrCache.invalidateElements(n)})}var i=n(1),a=n(0),o=n(110),s=n(113),l=r,u=r.prototype;u.CANVAS_LAYERS=3,u.SELECT_BOX=0,u.DRAG=1,u.NODE=2,u.BUFFER_COUNT=3,u.TEXTURE_BUFFER=0,u.MOTIONBLUR_BUFFER_NODE=1,u.MOTIONBLUR_BUFFER_DRAG=2,u.redrawHint=function(e,t){var n=this;switch(e){case"eles":n.data.canvasNeedsRedraw[u.NODE]=t;break;case"drag":n.data.canvasNeedsRedraw[u.DRAG]=t;break;case"select":n.data.canvasNeedsRedraw[u.SELECT_BOX]=t}};var c="undefined"!=typeof Path2D;u.path2dEnabled=function(e){if(void 0===e)return this.pathsEnabled;this.pathsEnabled=!!e},u.usePaths=function(){return c&&this.pathsEnabled},[n(102),n(104),n(103),n(105),n(106),n(107),n(108),n(109),n(111),n(114)].forEach(function(e){i.extend(u,e)}),e.exports=l},function(e,t,n){"use strict";function r(e,t){null!=e.imageSmoothingEnabled?e.imageSmoothingEnabled=t:(e.webkitImageSmoothingEnabled=t,e.mozImageSmoothingEnabled=t,e.msImageSmoothingEnabled=t)}var i=n(1),a=n(2),o=n(8),s=n(0),l=n(16),u=function(e,t){var n=this,r=n.renderer=e;n.layersByLevel={},n.firstGet=!0,n.lastInvalidationTime=i.performanceNow()-500,n.skipping=!1,r.beforeRender(function(e,t){t-n.lastInvalidationTime<=250?n.skipping=!0:n.skipping=!1});var a=function(e,t){return t.reqs-e.reqs};n.layersQueue=new o(a),n.eleTxrCache=t,n.setupEleCacheInvalidation(),n.setupDequeueing()},c=u.prototype,d=0,h=Math.pow(2,53)-1;c.makeLayer=function(e,t){var n=Math.pow(2,t),r=Math.ceil(e.w*n),i=Math.ceil(e.h*n),a=document.createElement("canvas");a.width=r,a.height=i;var o={id:d=++d%h,bb:e,level:t,width:r,height:i,canvas:a,context:a.getContext("2d"),eles:[],elesQueue:[],reqs:0},s=o.context,l=-o.bb.x1,u=-o.bb.y1;return s.scale(n,n),s.translate(l,u),o},c.getLayers=function(e,t,n){var r=this,o=r.renderer,s=o.cy,l=s.zoom(),u=r.firstGet;if(r.firstGet=!1,null==n)if((n=Math.ceil(a.log2(l*t)))<-4)n=-4;else if(l>=3.99||n>2)return null;r.validateLayersElesOrdering(n,e);var c,d,h=r.layersByLevel,p=Math.pow(2,n),f=h[n]=h[n]||[],v=r.levelIsComplete(n,e);if(v)return f;!function(){var t=function(t){if(r.validateLayersElesOrdering(t,e),r.levelIsComplete(t,e))return d=h[t],!0},a=function(e){if(!d)for(var r=n+e;-4<=r&&r<=2&&!t(r);r+=e);};a(1),a(-1);for(var o=f.length-1;o>=0;o--){var s=f[o];s.invalid&&i.removeFromArray(f,s)}}();var g=function(){if(!c){c=a.makeBoundingBox();for(var t=0;t=y||!a.boundingBoxInBoundingBox(m.bb,w.boundingBox()))&&!(m=function(e){e=e||{};var t=e.after;if(g(),c.w*p*(c.h*p)>16e6)return null;var i=r.makeLayer(c,n);if(null!=t){var a=f.indexOf(t)+1;f.splice(a,0,i)}else(void 0===e.insert||e.insert)&&f.unshift(i);return i}({insert:!0,after:m})))return null;d||b?r.queueLayer(m,w):r.drawEleInLayer(m,w,n,t),m.eles.push(w),P[n]=m}}return d||(b?null:f)},c.getEleLevelForLayerLevel=function(e,t){return e},c.drawEleInLayer=function(e,t,n,i){var a=this,o=this.renderer,s=e.context,l=t.boundingBox();if(0!==l.w&&0!==l.h&&t.visible()){var u=a.eleTxrCache,c=u.reasons.highQuality;n=a.getEleLevelForLayerLevel(n,i);var d=u.getElement(t,l,null,n,c);d?(r(s,!1),s.drawImage(d.texture.canvas,d.x,0,d.width,d.height,l.x1,l.y1,l.w,l.h),r(s,!0)):o.drawElement(s,t)}},c.levelIsComplete=function(e,t){var n=this,r=n.layersByLevel[e];if(!r||0===r.length)return!1;for(var i=0,a=0;a0)return!1;if(o.invalid)return!1;i+=o.eles.length}return i===t.length},c.validateLayersElesOrdering=function(e,t){var n=this.layersByLevel[e];if(n)for(var r=0;r0){t=!0;break}}return t},c.invalidateElements=function(e){var t=this;t.lastInvalidationTime=i.performanceNow(),0!==e.length&&t.haveLayers()&&t.updateElementsInLayers(e,function(e,n,r){t.invalidateLayer(e)})},c.invalidateLayer=function(e){if(this.lastInvalidationTime=i.performanceNow(),!e.invalid){var t=e.level,n=e.eles,r=this.layersByLevel[t];i.removeFromArray(r,e),e.elesQueue=[],e.invalid=!0,e.replacement&&(e.replacement.invalid=!0);for(var a=0;a=0&&(d=d.toLowerCase(),h=h.toLowerCase(),o=o.replace("@",""),p=!0);var f=!1;o.indexOf("!")>=0&&(o=o.replace("!",""),f=!0),p&&(s=h.toLowerCase(),c=d.toLowerCase());var v=!1;switch(o){case"*=":u=d.indexOf(h)>=0;break;case"$=":u=d.indexOf(h,d.length-h.length)>=0;break;case"^=":u=0===d.indexOf(h);break;case"=":u=c===s;break;case">":v=!0,u=c>s;break;case">=":v=!0,u=c>=s;break;case"<":v=!0,u=c\\?\\@\\[\\]\\^\\`\\{\\|\\}\\~]",comparatorOp:"=|\\!=|>|>=|<|<=|\\$=|\\^=|\\*=",boolOp:"\\?|\\!|\\^",string:'"(?:\\\\"|[^"])*"|'+"'(?:\\\\'|[^'])*'",number:r.regex.number,meta:"degree|indegree|outdegree",separator:"\\s*,\\s*",descendant:"\\s+",child:"\\s+>\\s+",subject:"\\$",group:"node|edge|\\*",directedEdge:"\\s+->\\s+",undirectedEdge:"\\s+<->\\s+"};i.variable="(?:[\\w-]|(?:\\\\"+i.metaChar+"))+",i.value=i.string+"|"+i.number,i.className=i.variable,i.id=i.variable,function(){var e=void 0,t=void 0,n=void 0;for(e=i.comparatorOp.split("|"),n=0;n=0||"="!==t&&(i.comparatorOp+="|\\!"+t)}(),e.exports=i},function(e,t,n){"use strict";var r=n(1),i=n(0),a=n(5),o={};o.apply=function(e){var t=this,n=t._private,r=n.cy,i=r.collection();n.newStyle&&(n.contextStyles={},n.propDiffs={},t.cleanElements(e,!0));for(var a=0;a0;if(h||p){var f=void 0;h&&p?f=u.properties:h?f=u.properties:p&&(f=u.mappedProperties);for(var v=0;v0){r=!0;break}}t.hasPie=r;var o=e.pstyle("text-transform").strValue,s=e.pstyle("label").strValue,l=e.pstyle("source-label").strValue,u=e.pstyle("target-label").strValue,c=e.pstyle("font-style").strValue,d=e.pstyle("font-size").pfValue+"px",h=e.pstyle("font-family").strValue,p=e.pstyle("font-weight").strValue,f=e.pstyle("text-valign").strValue,v=e.pstyle("text-valign").strValue,g=e.pstyle("text-outline-width").pfValue,m=e.pstyle("text-wrap").strValue,y=e.pstyle("text-max-width").pfValue,b=c+"$"+d+"$"+h+"$"+p+"$"+o+"$"+f+"$"+v+"$"+g+"$"+m+"$"+y;t.labelStyleKey=b,t.sourceLabelKey=b+"$"+l,t.targetLabelKey=b+"$"+u,t.labelKey=b+"$"+s,t.fontKey=c+"$"+p+"$"+d+"$"+h,t.styleKey=Date.now()}},o.applyParsedProperty=function(e,t){var n=this,a=t,o=e._private.style,s=void 0,l=n.types,u=n.properties[a.name].type,c=a.bypass,d=o[a.name],h=d&&d.bypass,p=e._private,f=function(){n.checkZOrderTrigger(e,a.name,d?d.value:null,a.value)};if("curve-style"===t.name&&"haystack"===t.value&&e.isEdge()&&(e.isLoop()||e.source().isParent()||e.target().isParent())&&(a=t=this.parse(t.name,"bezier",c)),a.delete)return o[a.name]=void 0,f(),!0;if(a.deleteBypassed)return d?!!d.bypass&&(d.bypassed=void 0,f(),!0):(f(),!0);if(a.deleteBypass)return d?!!d.bypass&&(o[a.name]=d.bypassed,f(),!0):(f(),!0);var v=function(){r.error("Do not assign mappings to elements without corresponding data (e.g. ele `"+e.id()+"` for property `"+a.name+"` with data field `"+a.field+"`); try a `["+a.field+"]` selector to limit scope to elements with `"+a.field+"` defined")};switch(a.mapped){case l.mapData:for(var g=a.field.split("."),m=p.data,y=0;y1&&(b=1),u.color){var x=a.valueMin[0],w=a.valueMax[0],E=a.valueMin[1],P=a.valueMax[1],C=a.valueMin[2],T=a.valueMax[2],S=null==a.valueMin[3]?1:a.valueMin[3],D=null==a.valueMax[3]?1:a.valueMax[3],k=[Math.round(x+(w-x)*b),Math.round(E+(P-E)*b),Math.round(C+(T-C)*b),Math.round(S+(D-S)*b)];s={bypass:a.bypass,name:a.name,value:k,strValue:"rgb("+k[0]+", "+k[1]+", "+k[2]+")"}}else{if(!u.number)return!1;var _=a.valueMin+(a.valueMax-a.valueMin)*b;s=this.parse(a.name,_,a.bypass,"mapping")}s||(s=this.parse(a.name,d.strValue,a.bypass,"mapping")),s||v(),s.mapping=a,a=s;break;case l.data:var M=a.field.split("."),I=p.data;if(I)for(var N=0;N0&&l>0){for(var c={},d=!1,h=0;h0?e.delayAnimation(u).play().promise().then(t):t()}).then(function(){return e.animation({style:c,duration:l,easing:e.pstyle("transition-timing-function").value,queue:!1}).play().promise()}).then(function(){r.removeBypasses(e,s),e.emitAndNotify("style"),o.transitioning=!1})}else o.transitioning&&(this.removeBypasses(e,s),e.emitAndNotify("style"),o.transitioning=!1)},o.checkZOrderTrigger=function(e,t,n,r){var i=this.properties[t];null==i.triggersZOrder||null!=n&&!i.triggersZOrder(n,r)||this._private.cy.notify({type:"zorder",eles:e})},e.exports=o},function(e,t,n){"use strict";var r=n(0),i=n(1),a={};a.applyBypass=function(e,t,n,a){var o=this,s=[];if("*"===t||"**"===t){if(void 0!==n)for(var l=0;lh.max||h.strictMax&&t===h.max))return null;var B={name:e,value:t,strValue:""+t+(_||""),units:_,bypass:n};return h.unitless||"px"!==_&&"em"!==_?B.pfValue=t:B.pfValue="px"!==_&&_?this.getEmSizeInPixels()*t:t,"ms"!==_&&"s"!==_||(B.pfValue="ms"===_?t:1e3*t),"deg"!==_&&"rad"!==_||(B.pfValue="rad"===_?t:a.deg2rad(t)),"%"===_&&(B.pfValue=t/100),B}if(h.propList){var L=[],z=""+t;if("none"===z);else{for(var O=z.split(","),A=0;A node").css({shape:"rectangle",padding:10,"background-color":"#eee","border-color":"#ccc","border-width":1}).selector("edge").css({width:3,"curve-style":"haystack"}).selector(":parent <-> node").css({"curve-style":"bezier","source-endpoint":"outside-to-line","target-endpoint":"outside-to-line"}).selector(":selected").css({"background-color":"#0169D9","line-color":"#0169D9","source-arrow-color":"#0169D9","target-arrow-color":"#0169D9","mid-source-arrow-color":"#0169D9","mid-target-arrow-color":"#0169D9"}).selector("node:parent:selected").css({"background-color":"#CCE1F9","border-color":"#aec8e5"}).selector(":active").css({"overlay-color":"black","overlay-padding":10,"overlay-opacity":.25}).selector("core").css({"selection-box-color":"#ddd","selection-box-opacity":.65,"selection-box-border-color":"#aaa","selection-box-border-width":1,"active-bg-color":"black","active-bg-opacity":.15,"active-bg-size":30,"outside-texture-bg-color":"#000","outside-texture-bg-opacity":.125}),this.defaultLength=this.length},e.exports=a},function(e,t,n){"use strict";var r=n(1),i=n(6),a={};a.applyFromString=function(e){function t(){s=s.length>l.length?s.substr(l.length):""}function n(){u=u.length>c.length?u.substr(c.length):""}var a=this,o=this,s=""+e,l=void 0,u=void 0,c=void 0;for(s=s.replace(/[\/][*](\s|.)+?[*][\/]/g,"");;){if(s.match(/^\s*$/))break;var d=s.match(/^\s*((?:.|\s)+?)\s*\{((?:.|\s)+?)\}/);if(!d){r.error("Halting stylesheet parsing: String stylesheet contains more to parse but no selector and block found in: "+s);break}l=d[0];var h=d[1];if("core"!==h){if(new i(h)._private.invalid){r.error("Skipping parsing of block: Invalid selector found in string stylesheet: "+h),t();continue}}var p=d[2],f=!1;u=p;for(var v=[];;){if(u.match(/^\s*$/))break;var g=u.match(/^\s*(.+?)\s*:\s*(.+?)\s*;/);if(!g){r.error("Skipping parsing of block: Invalid formatting of style property and value definitions found in:"+p),f=!0;break}c=g[0];var m=g[1],y=g[2];if(a.properties[m]){o.parse(m,y)?(v.push({name:m,val:y}),n()):(r.error("Skipping property: Invalid property definition in: "+c),n())}else r.error("Skipping property: Invalid property name in: "+c),n()}if(f){t();break}o.selector(h);for(var b=0;b1&&(n-=1),n<1/6?e+6*(t-e)*n:n<.5?t:n<2/3?e+(t-e)*(2/3-n)*6:e}var n=void 0,r=void 0,i=void 0,a=void 0,o=void 0,s=void 0,l=void 0,u=void 0,c=new RegExp("^"+this.regex.hsla+"$").exec(e);if(c){if(r=parseInt(c[1]),r<0?r=(360- -1*r%360)%360:r>360&&(r%=360),r/=360,(i=parseFloat(c[2]))<0||i>100)return;if(i/=100,(a=parseFloat(c[3]))<0||a>100)return;if(a/=100,void 0!==(o=c[4])&&((o=parseFloat(o))<0||o>1))return;if(0===i)s=l=u=Math.round(255*a);else{var d=a<.5?a*(1+i):a+i-a*i,h=2*a-d;s=Math.round(255*t(h,d,r+1/3)),l=Math.round(255*t(h,d,r)),u=Math.round(255*t(h,d,r-1/3))}n=[s,l,u,o]}return n},rgb2tuple:function(e){var t=void 0,n=new RegExp("^"+this.regex.rgba+"$").exec(e);if(n){t=[];for(var r=[],i=1;i<=3;i++){var a=n[i];if("%"===a[a.length-1]&&(r[i]=!0),a=parseFloat(a),r[i]&&(a=a/100*255),a<0||a>255)return;t.push(Math.floor(a))}var o=r[1]||r[2]||r[3],s=r[1]&&r[2]&&r[3];if(o&&!s)return;var l=n[4];if(void 0!==l){if((l=parseFloat(l))<0||l>1)return;t.push(l)}}return t},colorname2tuple:function(e){return this.colors[e.toLowerCase()]},color2tuple:function(e){return(r.array(e)?e:null)||this.colorname2tuple(e)||this.hex2tuple(e)||this.rgb2tuple(e)||this.hsl2tuple(e)},colors:{transparent:[0,0,0,0],aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],grey:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]}}},function(e,t,n){"use strict";var r=n(0);e.exports={mapEmpty:function(e){return null==e||0===Object.keys(e).length},pushMap:function(e){var t=this.getMap(e);null==t?this.setMap(this.extend({},e,{value:[e.value]})):t.push(e.value)},setMap:function(e){for(var t=e.map,n=e.keys,i=n.length,a=0;at?1:0}function i(e,t){return-1*r(e,t)}e.exports={sort:{ascending:r,descending:i}}},function(e,t,n){"use strict";var r=n(19),i=n(0);e.exports={camel2dash:r(function(e){return e.replace(/([A-Z])/g,function(e){return"-"+e.toLowerCase()})}),dash2camel:r(function(e){return e.replace(/(-\w)/g,function(e){return e[1].toUpperCase()})}),prependCamel:r(function(e,t){return e+t[0].toUpperCase()+t.substring(1)},function(e,t){return e+"$"+t}),capitalize:function(e){return i.emptyString(e)?e:e.charAt(0).toUpperCase()+e.substring(1)}}},function(e,t,n){"use strict";var r=n(4),i=r?r.performance:null,a={},o=i&&i.now?function(){return i.now()}:function(){return Date.now()},s=function(){if(r){if(r.requestAnimationFrame)return function(e){r.requestAnimationFrame(e)};if(r.mozRequestAnimationFrame)return function(e){r.mozRequestAnimationFrame(e)};if(r.webkitRequestAnimationFrame)return function(e){r.webkitRequestAnimationFrame(e)};if(r.msRequestAnimationFrame)return function(e){r.msRequestAnimationFrame(e)}}return function(e){e&&setTimeout(function(){e(o())},1e3/60)}}();a.requestAnimationFrame=function(e){s(e)},a.performanceNow=o,a.debounce=n(139),a.now=function(){return Date.now()},e.exports=a},function(e,t,n){e.exports=n(138)},function(e,t,n){var r,i,a;(function(){var n,o,s,l,u,c,d,h,p,f,v,g,m,y,b;s=Math.floor,f=Math.min,o=function(e,t){return et?1:0},p=function(e,t,n,r,i){var a;if(null==n&&(n=0),null==i&&(i=o),n<0)throw new Error("lo must be non-negative");for(null==r&&(r=e.length);nn;0<=n?t++:t--)u.push(t);return u}.apply(this).reverse(),l=[],r=0,i=a.length;rv;0<=v?++c:--c)g.push(u(e,n));return g},y=function(e,t,n,r){var i,a,s;for(null==r&&(r=o),i=e[n];n>t&&(s=n-1>>1,a=e[s],r(i,a)<0);)e[n]=a,n=s;return e[n]=i},b=function(e,t,n){var r,i,a,s,l;for(null==n&&(n=o),i=e.length,l=t,a=e[t],r=2*t+1;r=t||n<0||S&&r>=m}function c(){var e=E();if(u(e))return d(e);b=setTimeout(c,l(e))}function d(e){return b=void 0,D&&v?i(e):(v=g=void 0,y)}function h(){void 0!==b&&clearTimeout(b),C=0,v=P=g=b=void 0}function p(){return void 0===b?y:d(E())}function f(){var e=E(),n=u(e);if(v=arguments,g=this,P=e,n){if(void 0===b)return a(P);if(S)return b=setTimeout(c,t),i(P)}return void 0===b&&(b=setTimeout(c,t)),y}var v,g,m,y,b,P,C=0,T=!1,S=!1,D=!0;if("function"!=typeof e)throw new TypeError(s);return t=o(t)||0,r(n)&&(T=!!n.leading,S="maxWait"in n,m=S?x(o(n.maxWait)||0,t):m,D="trailing"in n?!!n.trailing:D),f.cancel=h,f.flush=p,f}function r(e){var t=typeof e;return!!e&&("object"==t||"function"==t)}function i(e){return!!e&&"object"==typeof e}function a(e){return"symbol"==typeof e||i(e)&&b.call(e)==u}function o(e){if("number"==typeof e)return e;if(a(e))return l;if(r(e)){var t="function"==typeof e.valueOf?e.valueOf():e;e=r(t)?t+"":t}if("string"!=typeof e)return 0===e?e:+e;e=e.replace(c,"");var n=h.test(e);return n||p.test(e)?f(e.slice(2),n?2:8):d.test(e)?l:+e}var s="Expected a function",l=NaN,u="[object Symbol]",c=/^\s+|\s+$/g,d=/^[-+]0x[0-9a-f]+$/i,h=/^0b[01]+$/i,p=/^0o[0-7]+$/i,f=parseInt,v="object"==typeof t&&t&&t.Object===Object&&t,g="object"==typeof self&&self&&self.Object===Object&&self,m=v||g||Function("return this")(),y=Object.prototype,b=y.toString,x=Math.max,w=Math.min,E=function(){return m.Date.now()};e.exports=n}).call(t,n(20))},function(e,t){function n(){throw new Error("setTimeout has not been defined")}function r(){throw new Error("clearTimeout has not been defined")}function i(e){if(c===setTimeout)return setTimeout(e,0);if((c===n||!c)&&setTimeout)return c=setTimeout,setTimeout(e,0);try{return c(e,0)}catch(t){try{return c.call(null,e,0)}catch(t){return c.call(this,e,0)}}}function a(e){if(d===clearTimeout)return clearTimeout(e);if((d===r||!d)&&clearTimeout)return d=clearTimeout,clearTimeout(e);try{return d(e)}catch(t){try{return d.call(null,e)}catch(t){return d.call(this,e)}}}function o(){v&&p&&(v=!1,p.length?f=p.concat(f):g=-1,f.length&&s())}function s(){if(!v){var e=i(o);v=!0;for(var t=f.length;t;){for(p=f,f=[];++g1)for(var n=1;n=0&&(e._idleTimeoutId=setTimeout(function(){e._onTimeout&&e._onTimeout()},t))},n(141),t.setImmediate=setImmediate,t.clearImmediate=clearImmediate}])}); \ No newline at end of file diff --git a/web/js/jquery.min.js b/web/js/jquery.min.js new file mode 100644 index 000000000..644d35e27 --- /dev/null +++ b/web/js/jquery.min.js @@ -0,0 +1,4 @@ +/*! jQuery v3.2.1 | (c) JS Foundation and other contributors | jquery.org/license */ +!function(a,b){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){"use strict";var c=[],d=a.document,e=Object.getPrototypeOf,f=c.slice,g=c.concat,h=c.push,i=c.indexOf,j={},k=j.toString,l=j.hasOwnProperty,m=l.toString,n=m.call(Object),o={};function p(a,b){b=b||d;var c=b.createElement("script");c.text=a,b.head.appendChild(c).parentNode.removeChild(c)}var q="3.2.1",r=function(a,b){return new r.fn.init(a,b)},s=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,t=/^-ms-/,u=/-([a-z])/g,v=function(a,b){return b.toUpperCase()};r.fn=r.prototype={jquery:q,constructor:r,length:0,toArray:function(){return f.call(this)},get:function(a){return null==a?f.call(this):a<0?this[a+this.length]:this[a]},pushStack:function(a){var b=r.merge(this.constructor(),a);return b.prevObject=this,b},each:function(a){return r.each(this,a)},map:function(a){return this.pushStack(r.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(f.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(a<0?b:0);return this.pushStack(c>=0&&c0&&b-1 in a)}var x=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ha(),z=ha(),A=ha(),B=function(a,b){return a===b&&(l=!0),0},C={}.hasOwnProperty,D=[],E=D.pop,F=D.push,G=D.push,H=D.slice,I=function(a,b){for(var c=0,d=a.length;c+~]|"+K+")"+K+"*"),S=new RegExp("="+K+"*([^\\]'\"]*?)"+K+"*\\]","g"),T=new RegExp(N),U=new RegExp("^"+L+"$"),V={ID:new RegExp("^#("+L+")"),CLASS:new RegExp("^\\.("+L+")"),TAG:new RegExp("^("+L+"|[*])"),ATTR:new RegExp("^"+M),PSEUDO:new RegExp("^"+N),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+K+"*(even|odd|(([+-]|)(\\d*)n|)"+K+"*(?:([+-]|)"+K+"*(\\d+)|))"+K+"*\\)|)","i"),bool:new RegExp("^(?:"+J+")$","i"),needsContext:new RegExp("^"+K+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+K+"*((?:-\\d)?\\d*)"+K+"*\\)|)(?=[^-]|$)","i")},W=/^(?:input|select|textarea|button)$/i,X=/^h\d$/i,Y=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,$=/[+~]/,_=new RegExp("\\\\([\\da-f]{1,6}"+K+"?|("+K+")|.)","ig"),aa=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:d<0?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},ba=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ca=function(a,b){return b?"\0"===a?"\ufffd":a.slice(0,-1)+"\\"+a.charCodeAt(a.length-1).toString(16)+" ":"\\"+a},da=function(){m()},ea=ta(function(a){return a.disabled===!0&&("form"in a||"label"in a)},{dir:"parentNode",next:"legend"});try{G.apply(D=H.call(v.childNodes),v.childNodes),D[v.childNodes.length].nodeType}catch(fa){G={apply:D.length?function(a,b){F.apply(a,H.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function ga(a,b,d,e){var f,h,j,k,l,o,r,s=b&&b.ownerDocument,w=b?b.nodeType:9;if(d=d||[],"string"!=typeof a||!a||1!==w&&9!==w&&11!==w)return d;if(!e&&((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,p)){if(11!==w&&(l=Z.exec(a)))if(f=l[1]){if(9===w){if(!(j=b.getElementById(f)))return d;if(j.id===f)return d.push(j),d}else if(s&&(j=s.getElementById(f))&&t(b,j)&&j.id===f)return d.push(j),d}else{if(l[2])return G.apply(d,b.getElementsByTagName(a)),d;if((f=l[3])&&c.getElementsByClassName&&b.getElementsByClassName)return G.apply(d,b.getElementsByClassName(f)),d}if(c.qsa&&!A[a+" "]&&(!q||!q.test(a))){if(1!==w)s=b,r=a;else if("object"!==b.nodeName.toLowerCase()){(k=b.getAttribute("id"))?k=k.replace(ba,ca):b.setAttribute("id",k=u),o=g(a),h=o.length;while(h--)o[h]="#"+k+" "+sa(o[h]);r=o.join(","),s=$.test(a)&&qa(b.parentNode)||b}if(r)try{return G.apply(d,s.querySelectorAll(r)),d}catch(x){}finally{k===u&&b.removeAttribute("id")}}}return i(a.replace(P,"$1"),b,d,e)}function ha(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ia(a){return a[u]=!0,a}function ja(a){var b=n.createElement("fieldset");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ka(a,b){var c=a.split("|"),e=c.length;while(e--)d.attrHandle[c[e]]=b}function la(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&a.sourceIndex-b.sourceIndex;if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function na(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function oa(a){return function(b){return"form"in b?b.parentNode&&b.disabled===!1?"label"in b?"label"in b.parentNode?b.parentNode.disabled===a:b.disabled===a:b.isDisabled===a||b.isDisabled!==!a&&ea(b)===a:b.disabled===a:"label"in b&&b.disabled===a}}function pa(a){return ia(function(b){return b=+b,ia(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function qa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=ga.support={},f=ga.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return!!b&&"HTML"!==b.nodeName},m=ga.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=n.documentElement,p=!f(n),v!==n&&(e=n.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener("unload",da,!1):e.attachEvent&&e.attachEvent("onunload",da)),c.attributes=ja(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ja(function(a){return a.appendChild(n.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Y.test(n.getElementsByClassName),c.getById=ja(function(a){return o.appendChild(a).id=u,!n.getElementsByName||!n.getElementsByName(u).length}),c.getById?(d.filter.ID=function(a){var b=a.replace(_,aa);return function(a){return a.getAttribute("id")===b}},d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c?[c]:[]}}):(d.filter.ID=function(a){var b=a.replace(_,aa);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}},d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c,d,e,f=b.getElementById(a);if(f){if(c=f.getAttributeNode("id"),c&&c.value===a)return[f];e=b.getElementsByName(a),d=0;while(f=e[d++])if(c=f.getAttributeNode("id"),c&&c.value===a)return[f]}return[]}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){if("undefined"!=typeof b.getElementsByClassName&&p)return b.getElementsByClassName(a)},r=[],q=[],(c.qsa=Y.test(n.querySelectorAll))&&(ja(function(a){o.appendChild(a).innerHTML="",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+K+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+K+"*(?:value|"+J+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ja(function(a){a.innerHTML="";var b=n.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+K+"*[*^$|!~]?="),2!==a.querySelectorAll(":enabled").length&&q.push(":enabled",":disabled"),o.appendChild(a).disabled=!0,2!==a.querySelectorAll(":disabled").length&&q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=Y.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ja(function(a){c.disconnectedMatch=s.call(a,"*"),s.call(a,"[s!='']:x"),r.push("!=",N)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=Y.test(o.compareDocumentPosition),t=b||Y.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===n||a.ownerDocument===v&&t(v,a)?-1:b===n||b.ownerDocument===v&&t(v,b)?1:k?I(k,a)-I(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,g=[a],h=[b];if(!e||!f)return a===n?-1:b===n?1:e?-1:f?1:k?I(k,a)-I(k,b):0;if(e===f)return la(a,b);c=a;while(c=c.parentNode)g.unshift(c);c=b;while(c=c.parentNode)h.unshift(c);while(g[d]===h[d])d++;return d?la(g[d],h[d]):g[d]===v?-1:h[d]===v?1:0},n):n},ga.matches=function(a,b){return ga(a,null,null,b)},ga.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(S,"='$1']"),c.matchesSelector&&p&&!A[b+" "]&&(!r||!r.test(b))&&(!q||!q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return ga(b,n,null,[a]).length>0},ga.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},ga.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&C.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},ga.escape=function(a){return(a+"").replace(ba,ca)},ga.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},ga.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=ga.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=ga.selectors={cacheLength:50,createPseudo:ia,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(_,aa),a[3]=(a[3]||a[4]||a[5]||"").replace(_,aa),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||ga.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&ga.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return V.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&T.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(_,aa).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+K+")"+a+"("+K+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=ga.attr(d,a);return null==e?"!="===b:!b||(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(O," ")+" ").indexOf(c)>-1:"|="===b&&(e===c||e.slice(0,c.length+1)===c+"-"))}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h,t=!1;if(q){if(f){while(p){m=b;while(m=m[p])if(h?m.nodeName.toLowerCase()===r:1===m.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){m=q,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n&&j[2],m=n&&q.childNodes[n];while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if(1===m.nodeType&&++t&&m===b){k[a]=[w,n,t];break}}else if(s&&(m=b,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n),t===!1)while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if((h?m.nodeName.toLowerCase()===r:1===m.nodeType)&&++t&&(s&&(l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),k[a]=[w,t]),m===b))break;return t-=e,t===d||t%d===0&&t/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||ga.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ia(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=I(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ia(function(a){var b=[],c=[],d=h(a.replace(P,"$1"));return d[u]?ia(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ia(function(a){return function(b){return ga(a,b).length>0}}),contains:ia(function(a){return a=a.replace(_,aa),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ia(function(a){return U.test(a||"")||ga.error("unsupported lang: "+a),a=a.replace(_,aa).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:oa(!1),disabled:oa(!0),checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return X.test(a.nodeName)},input:function(a){return W.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:pa(function(){return[0]}),last:pa(function(a,b){return[b-1]}),eq:pa(function(a,b,c){return[c<0?c+b:c]}),even:pa(function(a,b){for(var c=0;c=0;)a.push(d);return a}),gt:pa(function(a,b,c){for(var d=c<0?c+b:c;++d1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function va(a,b,c){for(var d=0,e=b.length;d-1&&(f[j]=!(g[j]=l))}}else r=wa(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):G.apply(g,r)})}function ya(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=ta(function(a){return a===b},h,!0),l=ta(function(a){return I(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];i1&&ua(m),i>1&&sa(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(P,"$1"),c,i0,e=a.length>0,f=function(f,g,h,i,k){var l,o,q,r=0,s="0",t=f&&[],u=[],v=j,x=f||e&&d.find.TAG("*",k),y=w+=null==v?1:Math.random()||.1,z=x.length;for(k&&(j=g===n||g||k);s!==z&&null!=(l=x[s]);s++){if(e&&l){o=0,g||l.ownerDocument===n||(m(l),h=!p);while(q=a[o++])if(q(l,g||n,h)){i.push(l);break}k&&(w=y)}c&&((l=!q&&l)&&r--,f&&t.push(l))}if(r+=s,c&&s!==r){o=0;while(q=b[o++])q(t,u,g,h);if(f){if(r>0)while(s--)t[s]||u[s]||(u[s]=E.call(i));u=wa(u)}G.apply(i,u),k&&!f&&u.length>0&&r+b.length>1&&ga.uniqueSort(i)}return k&&(w=y,j=v),t};return c?ia(f):f}return h=ga.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=ya(b[c]),f[u]?d.push(f):e.push(f);f=A(a,za(e,d)),f.selector=a}return f},i=ga.select=function(a,b,c,e){var f,i,j,k,l,m="function"==typeof a&&a,n=!e&&g(a=m.selector||a);if(c=c||[],1===n.length){if(i=n[0]=n[0].slice(0),i.length>2&&"ID"===(j=i[0]).type&&9===b.nodeType&&p&&d.relative[i[1].type]){if(b=(d.find.ID(j.matches[0].replace(_,aa),b)||[])[0],!b)return c;m&&(b=b.parentNode),a=a.slice(i.shift().value.length)}f=V.needsContext.test(a)?0:i.length;while(f--){if(j=i[f],d.relative[k=j.type])break;if((l=d.find[k])&&(e=l(j.matches[0].replace(_,aa),$.test(i[0].type)&&qa(b.parentNode)||b))){if(i.splice(f,1),a=e.length&&sa(i),!a)return G.apply(c,e),c;break}}}return(m||h(a,n))(e,b,!p,c,!b||$.test(a)&&qa(b.parentNode)||b),c},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ja(function(a){return 1&a.compareDocumentPosition(n.createElement("fieldset"))}),ja(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||ka("type|href|height|width",function(a,b,c){if(!c)return a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ja(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ka("value",function(a,b,c){if(!c&&"input"===a.nodeName.toLowerCase())return a.defaultValue}),ja(function(a){return null==a.getAttribute("disabled")})||ka(J,function(a,b,c){var d;if(!c)return a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),ga}(a);r.find=x,r.expr=x.selectors,r.expr[":"]=r.expr.pseudos,r.uniqueSort=r.unique=x.uniqueSort,r.text=x.getText,r.isXMLDoc=x.isXML,r.contains=x.contains,r.escapeSelector=x.escape;var y=function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&r(a).is(c))break;d.push(a)}return d},z=function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c},A=r.expr.match.needsContext;function B(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()}var C=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i,D=/^.[^:#\[\.,]*$/;function E(a,b,c){return r.isFunction(b)?r.grep(a,function(a,d){return!!b.call(a,d,a)!==c}):b.nodeType?r.grep(a,function(a){return a===b!==c}):"string"!=typeof b?r.grep(a,function(a){return i.call(b,a)>-1!==c}):D.test(b)?r.filter(b,a,c):(b=r.filter(b,a),r.grep(a,function(a){return i.call(b,a)>-1!==c&&1===a.nodeType}))}r.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?r.find.matchesSelector(d,a)?[d]:[]:r.find.matches(a,r.grep(b,function(a){return 1===a.nodeType}))},r.fn.extend({find:function(a){var b,c,d=this.length,e=this;if("string"!=typeof a)return this.pushStack(r(a).filter(function(){for(b=0;b1?r.uniqueSort(c):c},filter:function(a){return this.pushStack(E(this,a||[],!1))},not:function(a){return this.pushStack(E(this,a||[],!0))},is:function(a){return!!E(this,"string"==typeof a&&A.test(a)?r(a):a||[],!1).length}});var F,G=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/,H=r.fn.init=function(a,b,c){var e,f;if(!a)return this;if(c=c||F,"string"==typeof a){if(e="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:G.exec(a),!e||!e[1]&&b)return!b||b.jquery?(b||c).find(a):this.constructor(b).find(a);if(e[1]){if(b=b instanceof r?b[0]:b,r.merge(this,r.parseHTML(e[1],b&&b.nodeType?b.ownerDocument||b:d,!0)),C.test(e[1])&&r.isPlainObject(b))for(e in b)r.isFunction(this[e])?this[e](b[e]):this.attr(e,b[e]);return this}return f=d.getElementById(e[2]),f&&(this[0]=f,this.length=1),this}return a.nodeType?(this[0]=a,this.length=1,this):r.isFunction(a)?void 0!==c.ready?c.ready(a):a(r):r.makeArray(a,this)};H.prototype=r.fn,F=r(d);var I=/^(?:parents|prev(?:Until|All))/,J={children:!0,contents:!0,next:!0,prev:!0};r.fn.extend({has:function(a){var b=r(a,this),c=b.length;return this.filter(function(){for(var a=0;a-1:1===c.nodeType&&r.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?r.uniqueSort(f):f)},index:function(a){return a?"string"==typeof a?i.call(r(a),this[0]):i.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(r.uniqueSort(r.merge(this.get(),r(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function K(a,b){while((a=a[b])&&1!==a.nodeType);return a}r.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return y(a,"parentNode")},parentsUntil:function(a,b,c){return y(a,"parentNode",c)},next:function(a){return K(a,"nextSibling")},prev:function(a){return K(a,"previousSibling")},nextAll:function(a){return y(a,"nextSibling")},prevAll:function(a){return y(a,"previousSibling")},nextUntil:function(a,b,c){return y(a,"nextSibling",c)},prevUntil:function(a,b,c){return y(a,"previousSibling",c)},siblings:function(a){return z((a.parentNode||{}).firstChild,a)},children:function(a){return z(a.firstChild)},contents:function(a){return B(a,"iframe")?a.contentDocument:(B(a,"template")&&(a=a.content||a),r.merge([],a.childNodes))}},function(a,b){r.fn[a]=function(c,d){var e=r.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=r.filter(d,e)),this.length>1&&(J[a]||r.uniqueSort(e),I.test(a)&&e.reverse()),this.pushStack(e)}});var L=/[^\x20\t\r\n\f]+/g;function M(a){var b={};return r.each(a.match(L)||[],function(a,c){b[c]=!0}),b}r.Callbacks=function(a){a="string"==typeof a?M(a):r.extend({},a);var b,c,d,e,f=[],g=[],h=-1,i=function(){for(e=e||a.once,d=b=!0;g.length;h=-1){c=g.shift();while(++h-1)f.splice(c,1),c<=h&&h--}),this},has:function(a){return a?r.inArray(a,f)>-1:f.length>0},empty:function(){return f&&(f=[]),this},disable:function(){return e=g=[],f=c="",this},disabled:function(){return!f},lock:function(){return e=g=[],c||b||(f=c=""),this},locked:function(){return!!e},fireWith:function(a,c){return e||(c=c||[],c=[a,c.slice?c.slice():c],g.push(c),b||i()),this},fire:function(){return j.fireWith(this,arguments),this},fired:function(){return!!d}};return j};function N(a){return a}function O(a){throw a}function P(a,b,c,d){var e;try{a&&r.isFunction(e=a.promise)?e.call(a).done(b).fail(c):a&&r.isFunction(e=a.then)?e.call(a,b,c):b.apply(void 0,[a].slice(d))}catch(a){c.apply(void 0,[a])}}r.extend({Deferred:function(b){var c=[["notify","progress",r.Callbacks("memory"),r.Callbacks("memory"),2],["resolve","done",r.Callbacks("once memory"),r.Callbacks("once memory"),0,"resolved"],["reject","fail",r.Callbacks("once memory"),r.Callbacks("once memory"),1,"rejected"]],d="pending",e={state:function(){return d},always:function(){return f.done(arguments).fail(arguments),this},"catch":function(a){return e.then(null,a)},pipe:function(){var a=arguments;return r.Deferred(function(b){r.each(c,function(c,d){var e=r.isFunction(a[d[4]])&&a[d[4]];f[d[1]](function(){var a=e&&e.apply(this,arguments);a&&r.isFunction(a.promise)?a.promise().progress(b.notify).done(b.resolve).fail(b.reject):b[d[0]+"With"](this,e?[a]:arguments)})}),a=null}).promise()},then:function(b,d,e){var f=0;function g(b,c,d,e){return function(){var h=this,i=arguments,j=function(){var a,j;if(!(b=f&&(d!==O&&(h=void 0,i=[a]),c.rejectWith(h,i))}};b?k():(r.Deferred.getStackHook&&(k.stackTrace=r.Deferred.getStackHook()),a.setTimeout(k))}}return r.Deferred(function(a){c[0][3].add(g(0,a,r.isFunction(e)?e:N,a.notifyWith)),c[1][3].add(g(0,a,r.isFunction(b)?b:N)),c[2][3].add(g(0,a,r.isFunction(d)?d:O))}).promise()},promise:function(a){return null!=a?r.extend(a,e):e}},f={};return r.each(c,function(a,b){var g=b[2],h=b[5];e[b[1]]=g.add,h&&g.add(function(){d=h},c[3-a][2].disable,c[0][2].lock),g.add(b[3].fire),f[b[0]]=function(){return f[b[0]+"With"](this===f?void 0:this,arguments),this},f[b[0]+"With"]=g.fireWith}),e.promise(f),b&&b.call(f,f),f},when:function(a){var b=arguments.length,c=b,d=Array(c),e=f.call(arguments),g=r.Deferred(),h=function(a){return function(c){d[a]=this,e[a]=arguments.length>1?f.call(arguments):c,--b||g.resolveWith(d,e)}};if(b<=1&&(P(a,g.done(h(c)).resolve,g.reject,!b),"pending"===g.state()||r.isFunction(e[c]&&e[c].then)))return g.then();while(c--)P(e[c],h(c),g.reject);return g.promise()}});var Q=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;r.Deferred.exceptionHook=function(b,c){a.console&&a.console.warn&&b&&Q.test(b.name)&&a.console.warn("jQuery.Deferred exception: "+b.message,b.stack,c)},r.readyException=function(b){a.setTimeout(function(){throw b})};var R=r.Deferred();r.fn.ready=function(a){return R.then(a)["catch"](function(a){r.readyException(a)}),this},r.extend({isReady:!1,readyWait:1,ready:function(a){(a===!0?--r.readyWait:r.isReady)||(r.isReady=!0,a!==!0&&--r.readyWait>0||R.resolveWith(d,[r]))}}),r.ready.then=R.then;function S(){d.removeEventListener("DOMContentLoaded",S), +a.removeEventListener("load",S),r.ready()}"complete"===d.readyState||"loading"!==d.readyState&&!d.documentElement.doScroll?a.setTimeout(r.ready):(d.addEventListener("DOMContentLoaded",S),a.addEventListener("load",S));var T=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===r.type(c)){e=!0;for(h in c)T(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,r.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(r(a),c)})),b))for(;h1,null,!0)},removeData:function(a){return this.each(function(){X.remove(this,a)})}}),r.extend({queue:function(a,b,c){var d;if(a)return b=(b||"fx")+"queue",d=W.get(a,b),c&&(!d||Array.isArray(c)?d=W.access(a,b,r.makeArray(c)):d.push(c)),d||[]},dequeue:function(a,b){b=b||"fx";var c=r.queue(a,b),d=c.length,e=c.shift(),f=r._queueHooks(a,b),g=function(){r.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return W.get(a,c)||W.access(a,c,{empty:r.Callbacks("once memory").add(function(){W.remove(a,[b+"queue",c])})})}}),r.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length\x20\t\r\n\f]+)/i,la=/^$|\/(?:java|ecma)script/i,ma={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};ma.optgroup=ma.option,ma.tbody=ma.tfoot=ma.colgroup=ma.caption=ma.thead,ma.th=ma.td;function na(a,b){var c;return c="undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||"*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll(b||"*"):[],void 0===b||b&&B(a,b)?r.merge([a],c):c}function oa(a,b){for(var c=0,d=a.length;c-1)e&&e.push(f);else if(j=r.contains(f.ownerDocument,f),g=na(l.appendChild(f),"script"),j&&oa(g),c){k=0;while(f=g[k++])la.test(f.type||"")&&c.push(f)}return l}!function(){var a=d.createDocumentFragment(),b=a.appendChild(d.createElement("div")),c=d.createElement("input");c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),b.appendChild(c),o.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="",o.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var ra=d.documentElement,sa=/^key/,ta=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,ua=/^([^.]*)(?:\.(.+)|)/;function va(){return!0}function wa(){return!1}function xa(){try{return d.activeElement}catch(a){}}function ya(a,b,c,d,e,f){var g,h;if("object"==typeof b){"string"!=typeof c&&(d=d||c,c=void 0);for(h in b)ya(a,h,c,d,b[h],f);return a}if(null==d&&null==e?(e=c,d=c=void 0):null==e&&("string"==typeof c?(e=d,d=void 0):(e=d,d=c,c=void 0)),e===!1)e=wa;else if(!e)return a;return 1===f&&(g=e,e=function(a){return r().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=r.guid++)),a.each(function(){r.event.add(this,b,e,d,c)})}r.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q=W.get(a);if(q){c.handler&&(f=c,c=f.handler,e=f.selector),e&&r.find.matchesSelector(ra,e),c.guid||(c.guid=r.guid++),(i=q.events)||(i=q.events={}),(g=q.handle)||(g=q.handle=function(b){return"undefined"!=typeof r&&r.event.triggered!==b.type?r.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(L)||[""],j=b.length;while(j--)h=ua.exec(b[j])||[],n=p=h[1],o=(h[2]||"").split(".").sort(),n&&(l=r.event.special[n]||{},n=(e?l.delegateType:l.bindType)||n,l=r.event.special[n]||{},k=r.extend({type:n,origType:p,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&r.expr.match.needsContext.test(e),namespace:o.join(".")},f),(m=i[n])||(m=i[n]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,o,g)!==!1||a.addEventListener&&a.addEventListener(n,g)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),r.event.global[n]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q=W.hasData(a)&&W.get(a);if(q&&(i=q.events)){b=(b||"").match(L)||[""],j=b.length;while(j--)if(h=ua.exec(b[j])||[],n=p=h[1],o=(h[2]||"").split(".").sort(),n){l=r.event.special[n]||{},n=(d?l.delegateType:l.bindType)||n,m=i[n]||[],h=h[2]&&new RegExp("(^|\\.)"+o.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&p!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,o,q.handle)!==!1||r.removeEvent(a,n,q.handle),delete i[n])}else for(n in i)r.event.remove(a,n+b[j],c,d,!0);r.isEmptyObject(i)&&W.remove(a,"handle events")}},dispatch:function(a){var b=r.event.fix(a),c,d,e,f,g,h,i=new Array(arguments.length),j=(W.get(this,"events")||{})[b.type]||[],k=r.event.special[b.type]||{};for(i[0]=b,c=1;c=1))for(;j!==this;j=j.parentNode||this)if(1===j.nodeType&&("click"!==a.type||j.disabled!==!0)){for(f=[],g={},c=0;c-1:r.find(e,this,null,[j]).length),g[e]&&f.push(d);f.length&&h.push({elem:j,handlers:f})}return j=this,i\x20\t\r\n\f]*)[^>]*)\/>/gi,Aa=/\s*$/g;function Ea(a,b){return B(a,"table")&&B(11!==b.nodeType?b:b.firstChild,"tr")?r(">tbody",a)[0]||a:a}function Fa(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function Ga(a){var b=Ca.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function Ha(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(W.hasData(a)&&(f=W.access(a),g=W.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;c1&&"string"==typeof q&&!o.checkClone&&Ba.test(q))return a.each(function(e){var f=a.eq(e);s&&(b[0]=q.call(this,e,f.html())),Ja(f,b,c,d)});if(m&&(e=qa(b,a[0].ownerDocument,!1,a,d),f=e.firstChild,1===e.childNodes.length&&(e=f),f||d)){for(h=r.map(na(e,"script"),Fa),i=h.length;l")},clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=r.contains(a.ownerDocument,a);if(!(o.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||r.isXMLDoc(a)))for(g=na(h),f=na(a),d=0,e=f.length;d0&&oa(g,!i&&na(a,"script")),h},cleanData:function(a){for(var b,c,d,e=r.event.special,f=0;void 0!==(c=a[f]);f++)if(U(c)){if(b=c[W.expando]){if(b.events)for(d in b.events)e[d]?r.event.remove(c,d):r.removeEvent(c,d,b.handle);c[W.expando]=void 0}c[X.expando]&&(c[X.expando]=void 0)}}}),r.fn.extend({detach:function(a){return Ka(this,a,!0)},remove:function(a){return Ka(this,a)},text:function(a){return T(this,function(a){return void 0===a?r.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=a)})},null,a,arguments.length)},append:function(){return Ja(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ea(this,a);b.appendChild(a)}})},prepend:function(){return Ja(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ea(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return Ja(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return Ja(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(r.cleanData(na(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null!=a&&a,b=null==b?a:b,this.map(function(){return r.clone(this,a,b)})},html:function(a){return T(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!Aa.test(a)&&!ma[(ka.exec(a)||["",""])[1].toLowerCase()]){a=r.htmlPrefilter(a);try{for(;c1)}});function _a(a,b,c,d,e){return new _a.prototype.init(a,b,c,d,e)}r.Tween=_a,_a.prototype={constructor:_a,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||r.easing._default,this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(r.cssNumber[c]?"":"px")},cur:function(){var a=_a.propHooks[this.prop];return a&&a.get?a.get(this):_a.propHooks._default.get(this)},run:function(a){var b,c=_a.propHooks[this.prop];return this.options.duration?this.pos=b=r.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):_a.propHooks._default.set(this),this}},_a.prototype.init.prototype=_a.prototype,_a.propHooks={_default:{get:function(a){var b;return 1!==a.elem.nodeType||null!=a.elem[a.prop]&&null==a.elem.style[a.prop]?a.elem[a.prop]:(b=r.css(a.elem,a.prop,""),b&&"auto"!==b?b:0)},set:function(a){r.fx.step[a.prop]?r.fx.step[a.prop](a):1!==a.elem.nodeType||null==a.elem.style[r.cssProps[a.prop]]&&!r.cssHooks[a.prop]?a.elem[a.prop]=a.now:r.style(a.elem,a.prop,a.now+a.unit)}}},_a.propHooks.scrollTop=_a.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},r.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2},_default:"swing"},r.fx=_a.prototype.init,r.fx.step={};var ab,bb,cb=/^(?:toggle|show|hide)$/,db=/queueHooks$/;function eb(){bb&&(d.hidden===!1&&a.requestAnimationFrame?a.requestAnimationFrame(eb):a.setTimeout(eb,r.fx.interval),r.fx.tick())}function fb(){return a.setTimeout(function(){ab=void 0}),ab=r.now()}function gb(a,b){var c,d=0,e={height:a};for(b=b?1:0;d<4;d+=2-b)c=ca[d],e["margin"+c]=e["padding"+c]=a;return b&&(e.opacity=e.width=a),e}function hb(a,b,c){for(var d,e=(kb.tweeners[b]||[]).concat(kb.tweeners["*"]),f=0,g=e.length;f1)},removeAttr:function(a){return this.each(function(){r.removeAttr(this,a)})}}),r.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return"undefined"==typeof a.getAttribute?r.prop(a,b,c):(1===f&&r.isXMLDoc(a)||(e=r.attrHooks[b.toLowerCase()]||(r.expr.match.bool.test(b)?lb:void 0)),void 0!==c?null===c?void r.removeAttr(a,b):e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:(a.setAttribute(b,c+""),c):e&&"get"in e&&null!==(d=e.get(a,b))?d:(d=r.find.attr(a,b), +null==d?void 0:d))},attrHooks:{type:{set:function(a,b){if(!o.radioValue&&"radio"===b&&B(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}},removeAttr:function(a,b){var c,d=0,e=b&&b.match(L);if(e&&1===a.nodeType)while(c=e[d++])a.removeAttribute(c)}}),lb={set:function(a,b,c){return b===!1?r.removeAttr(a,c):a.setAttribute(c,c),c}},r.each(r.expr.match.bool.source.match(/\w+/g),function(a,b){var c=mb[b]||r.find.attr;mb[b]=function(a,b,d){var e,f,g=b.toLowerCase();return d||(f=mb[g],mb[g]=e,e=null!=c(a,b,d)?g:null,mb[g]=f),e}});var nb=/^(?:input|select|textarea|button)$/i,ob=/^(?:a|area)$/i;r.fn.extend({prop:function(a,b){return T(this,r.prop,a,b,arguments.length>1)},removeProp:function(a){return this.each(function(){delete this[r.propFix[a]||a]})}}),r.extend({prop:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return 1===f&&r.isXMLDoc(a)||(b=r.propFix[b]||b,e=r.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=r.find.attr(a,"tabindex");return b?parseInt(b,10):nb.test(a.nodeName)||ob.test(a.nodeName)&&a.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),o.optSelected||(r.propHooks.selected={get:function(a){var b=a.parentNode;return b&&b.parentNode&&b.parentNode.selectedIndex,null},set:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex)}}),r.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){r.propFix[this.toLowerCase()]=this});function pb(a){var b=a.match(L)||[];return b.join(" ")}function qb(a){return a.getAttribute&&a.getAttribute("class")||""}r.fn.extend({addClass:function(a){var b,c,d,e,f,g,h,i=0;if(r.isFunction(a))return this.each(function(b){r(this).addClass(a.call(this,b,qb(this)))});if("string"==typeof a&&a){b=a.match(L)||[];while(c=this[i++])if(e=qb(c),d=1===c.nodeType&&" "+pb(e)+" "){g=0;while(f=b[g++])d.indexOf(" "+f+" ")<0&&(d+=f+" ");h=pb(d),e!==h&&c.setAttribute("class",h)}}return this},removeClass:function(a){var b,c,d,e,f,g,h,i=0;if(r.isFunction(a))return this.each(function(b){r(this).removeClass(a.call(this,b,qb(this)))});if(!arguments.length)return this.attr("class","");if("string"==typeof a&&a){b=a.match(L)||[];while(c=this[i++])if(e=qb(c),d=1===c.nodeType&&" "+pb(e)+" "){g=0;while(f=b[g++])while(d.indexOf(" "+f+" ")>-1)d=d.replace(" "+f+" "," ");h=pb(d),e!==h&&c.setAttribute("class",h)}}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):r.isFunction(a)?this.each(function(c){r(this).toggleClass(a.call(this,c,qb(this),b),b)}):this.each(function(){var b,d,e,f;if("string"===c){d=0,e=r(this),f=a.match(L)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else void 0!==a&&"boolean"!==c||(b=qb(this),b&&W.set(this,"__className__",b),this.setAttribute&&this.setAttribute("class",b||a===!1?"":W.get(this,"__className__")||""))})},hasClass:function(a){var b,c,d=0;b=" "+a+" ";while(c=this[d++])if(1===c.nodeType&&(" "+pb(qb(c))+" ").indexOf(b)>-1)return!0;return!1}});var rb=/\r/g;r.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=r.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,r(this).val()):a,null==e?e="":"number"==typeof e?e+="":Array.isArray(e)&&(e=r.map(e,function(a){return null==a?"":a+""})),b=r.valHooks[this.type]||r.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=r.valHooks[e.type]||r.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(rb,""):null==c?"":c)}}}),r.extend({valHooks:{option:{get:function(a){var b=r.find.attr(a,"value");return null!=b?b:pb(r.text(a))}},select:{get:function(a){var b,c,d,e=a.options,f=a.selectedIndex,g="select-one"===a.type,h=g?null:[],i=g?f+1:e.length;for(d=f<0?i:g?f:0;d-1)&&(c=!0);return c||(a.selectedIndex=-1),f}}}}),r.each(["radio","checkbox"],function(){r.valHooks[this]={set:function(a,b){if(Array.isArray(b))return a.checked=r.inArray(r(a).val(),b)>-1}},o.checkOn||(r.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var sb=/^(?:focusinfocus|focusoutblur)$/;r.extend(r.event,{trigger:function(b,c,e,f){var g,h,i,j,k,m,n,o=[e||d],p=l.call(b,"type")?b.type:b,q=l.call(b,"namespace")?b.namespace.split("."):[];if(h=i=e=e||d,3!==e.nodeType&&8!==e.nodeType&&!sb.test(p+r.event.triggered)&&(p.indexOf(".")>-1&&(q=p.split("."),p=q.shift(),q.sort()),k=p.indexOf(":")<0&&"on"+p,b=b[r.expando]?b:new r.Event(p,"object"==typeof b&&b),b.isTrigger=f?2:3,b.namespace=q.join("."),b.rnamespace=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=e),c=null==c?[b]:r.makeArray(c,[b]),n=r.event.special[p]||{},f||!n.trigger||n.trigger.apply(e,c)!==!1)){if(!f&&!n.noBubble&&!r.isWindow(e)){for(j=n.delegateType||p,sb.test(j+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),i=h;i===(e.ownerDocument||d)&&o.push(i.defaultView||i.parentWindow||a)}g=0;while((h=o[g++])&&!b.isPropagationStopped())b.type=g>1?j:n.bindType||p,m=(W.get(h,"events")||{})[b.type]&&W.get(h,"handle"),m&&m.apply(h,c),m=k&&h[k],m&&m.apply&&U(h)&&(b.result=m.apply(h,c),b.result===!1&&b.preventDefault());return b.type=p,f||b.isDefaultPrevented()||n._default&&n._default.apply(o.pop(),c)!==!1||!U(e)||k&&r.isFunction(e[p])&&!r.isWindow(e)&&(i=e[k],i&&(e[k]=null),r.event.triggered=p,e[p](),r.event.triggered=void 0,i&&(e[k]=i)),b.result}},simulate:function(a,b,c){var d=r.extend(new r.Event,c,{type:a,isSimulated:!0});r.event.trigger(d,null,b)}}),r.fn.extend({trigger:function(a,b){return this.each(function(){r.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];if(c)return r.event.trigger(a,b,c,!0)}}),r.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(a,b){r.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),r.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),o.focusin="onfocusin"in a,o.focusin||r.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){r.event.simulate(b,a.target,r.event.fix(a))};r.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=W.access(d,b);e||d.addEventListener(a,c,!0),W.access(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=W.access(d,b)-1;e?W.access(d,b,e):(d.removeEventListener(a,c,!0),W.remove(d,b))}}});var tb=a.location,ub=r.now(),vb=/\?/;r.parseXML=function(b){var c;if(!b||"string"!=typeof b)return null;try{c=(new a.DOMParser).parseFromString(b,"text/xml")}catch(d){c=void 0}return c&&!c.getElementsByTagName("parsererror").length||r.error("Invalid XML: "+b),c};var wb=/\[\]$/,xb=/\r?\n/g,yb=/^(?:submit|button|image|reset|file)$/i,zb=/^(?:input|select|textarea|keygen)/i;function Ab(a,b,c,d){var e;if(Array.isArray(b))r.each(b,function(b,e){c||wb.test(a)?d(a,e):Ab(a+"["+("object"==typeof e&&null!=e?b:"")+"]",e,c,d)});else if(c||"object"!==r.type(b))d(a,b);else for(e in b)Ab(a+"["+e+"]",b[e],c,d)}r.param=function(a,b){var c,d=[],e=function(a,b){var c=r.isFunction(b)?b():b;d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(null==c?"":c)};if(Array.isArray(a)||a.jquery&&!r.isPlainObject(a))r.each(a,function(){e(this.name,this.value)});else for(c in a)Ab(c,a[c],b,e);return d.join("&")},r.fn.extend({serialize:function(){return r.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=r.prop(this,"elements");return a?r.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!r(this).is(":disabled")&&zb.test(this.nodeName)&&!yb.test(a)&&(this.checked||!ja.test(a))}).map(function(a,b){var c=r(this).val();return null==c?null:Array.isArray(c)?r.map(c,function(a){return{name:b.name,value:a.replace(xb,"\r\n")}}):{name:b.name,value:c.replace(xb,"\r\n")}}).get()}});var Bb=/%20/g,Cb=/#.*$/,Db=/([?&])_=[^&]*/,Eb=/^(.*?):[ \t]*([^\r\n]*)$/gm,Fb=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Gb=/^(?:GET|HEAD)$/,Hb=/^\/\//,Ib={},Jb={},Kb="*/".concat("*"),Lb=d.createElement("a");Lb.href=tb.href;function Mb(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(L)||[];if(r.isFunction(c))while(d=f[e++])"+"===d[0]?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Nb(a,b,c,d){var e={},f=a===Jb;function g(h){var i;return e[h]=!0,r.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function Ob(a,b){var c,d,e=r.ajaxSettings.flatOptions||{};for(c in b)void 0!==b[c]&&((e[c]?a:d||(d={}))[c]=b[c]);return d&&r.extend(!0,a,d),a}function Pb(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===d&&(d=a.mimeType||b.getResponseHeader("Content-Type"));if(d)for(e in h)if(h[e]&&h[e].test(d)){i.unshift(e);break}if(i[0]in c)f=i[0];else{for(e in c){if(!i[0]||a.converters[e+" "+i[0]]){f=e;break}g||(g=e)}f=f||g}if(f)return f!==i[0]&&i.unshift(f),c[f]}function Qb(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}r.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:tb.href,type:"GET",isLocal:Fb.test(tb.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Kb,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":r.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Ob(Ob(a,r.ajaxSettings),b):Ob(r.ajaxSettings,a)},ajaxPrefilter:Mb(Ib),ajaxTransport:Mb(Jb),ajax:function(b,c){"object"==typeof b&&(c=b,b=void 0),c=c||{};var e,f,g,h,i,j,k,l,m,n,o=r.ajaxSetup({},c),p=o.context||o,q=o.context&&(p.nodeType||p.jquery)?r(p):r.event,s=r.Deferred(),t=r.Callbacks("once memory"),u=o.statusCode||{},v={},w={},x="canceled",y={readyState:0,getResponseHeader:function(a){var b;if(k){if(!h){h={};while(b=Eb.exec(g))h[b[1].toLowerCase()]=b[2]}b=h[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return k?g:null},setRequestHeader:function(a,b){return null==k&&(a=w[a.toLowerCase()]=w[a.toLowerCase()]||a,v[a]=b),this},overrideMimeType:function(a){return null==k&&(o.mimeType=a),this},statusCode:function(a){var b;if(a)if(k)y.always(a[y.status]);else for(b in a)u[b]=[u[b],a[b]];return this},abort:function(a){var b=a||x;return e&&e.abort(b),A(0,b),this}};if(s.promise(y),o.url=((b||o.url||tb.href)+"").replace(Hb,tb.protocol+"//"),o.type=c.method||c.type||o.method||o.type,o.dataTypes=(o.dataType||"*").toLowerCase().match(L)||[""],null==o.crossDomain){j=d.createElement("a");try{j.href=o.url,j.href=j.href,o.crossDomain=Lb.protocol+"//"+Lb.host!=j.protocol+"//"+j.host}catch(z){o.crossDomain=!0}}if(o.data&&o.processData&&"string"!=typeof o.data&&(o.data=r.param(o.data,o.traditional)),Nb(Ib,o,c,y),k)return y;l=r.event&&o.global,l&&0===r.active++&&r.event.trigger("ajaxStart"),o.type=o.type.toUpperCase(),o.hasContent=!Gb.test(o.type),f=o.url.replace(Cb,""),o.hasContent?o.data&&o.processData&&0===(o.contentType||"").indexOf("application/x-www-form-urlencoded")&&(o.data=o.data.replace(Bb,"+")):(n=o.url.slice(f.length),o.data&&(f+=(vb.test(f)?"&":"?")+o.data,delete o.data),o.cache===!1&&(f=f.replace(Db,"$1"),n=(vb.test(f)?"&":"?")+"_="+ub++ +n),o.url=f+n),o.ifModified&&(r.lastModified[f]&&y.setRequestHeader("If-Modified-Since",r.lastModified[f]),r.etag[f]&&y.setRequestHeader("If-None-Match",r.etag[f])),(o.data&&o.hasContent&&o.contentType!==!1||c.contentType)&&y.setRequestHeader("Content-Type",o.contentType),y.setRequestHeader("Accept",o.dataTypes[0]&&o.accepts[o.dataTypes[0]]?o.accepts[o.dataTypes[0]]+("*"!==o.dataTypes[0]?", "+Kb+"; q=0.01":""):o.accepts["*"]);for(m in o.headers)y.setRequestHeader(m,o.headers[m]);if(o.beforeSend&&(o.beforeSend.call(p,y,o)===!1||k))return y.abort();if(x="abort",t.add(o.complete),y.done(o.success),y.fail(o.error),e=Nb(Jb,o,c,y)){if(y.readyState=1,l&&q.trigger("ajaxSend",[y,o]),k)return y;o.async&&o.timeout>0&&(i=a.setTimeout(function(){y.abort("timeout")},o.timeout));try{k=!1,e.send(v,A)}catch(z){if(k)throw z;A(-1,z)}}else A(-1,"No Transport");function A(b,c,d,h){var j,m,n,v,w,x=c;k||(k=!0,i&&a.clearTimeout(i),e=void 0,g=h||"",y.readyState=b>0?4:0,j=b>=200&&b<300||304===b,d&&(v=Pb(o,y,d)),v=Qb(o,v,y,j),j?(o.ifModified&&(w=y.getResponseHeader("Last-Modified"),w&&(r.lastModified[f]=w),w=y.getResponseHeader("etag"),w&&(r.etag[f]=w)),204===b||"HEAD"===o.type?x="nocontent":304===b?x="notmodified":(x=v.state,m=v.data,n=v.error,j=!n)):(n=x,!b&&x||(x="error",b<0&&(b=0))),y.status=b,y.statusText=(c||x)+"",j?s.resolveWith(p,[m,x,y]):s.rejectWith(p,[y,x,n]),y.statusCode(u),u=void 0,l&&q.trigger(j?"ajaxSuccess":"ajaxError",[y,o,j?m:n]),t.fireWith(p,[y,x]),l&&(q.trigger("ajaxComplete",[y,o]),--r.active||r.event.trigger("ajaxStop")))}return y},getJSON:function(a,b,c){return r.get(a,b,c,"json")},getScript:function(a,b){return r.get(a,void 0,b,"script")}}),r.each(["get","post"],function(a,b){r[b]=function(a,c,d,e){return r.isFunction(c)&&(e=e||d,d=c,c=void 0),r.ajax(r.extend({url:a,type:b,dataType:e,data:c,success:d},r.isPlainObject(a)&&a))}}),r._evalUrl=function(a){return r.ajax({url:a,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,"throws":!0})},r.fn.extend({wrapAll:function(a){var b;return this[0]&&(r.isFunction(a)&&(a=a.call(this[0])),b=r(a,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstElementChild)a=a.firstElementChild;return a}).append(this)),this},wrapInner:function(a){return r.isFunction(a)?this.each(function(b){r(this).wrapInner(a.call(this,b))}):this.each(function(){var b=r(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=r.isFunction(a);return this.each(function(c){r(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(a){return this.parent(a).not("body").each(function(){r(this).replaceWith(this.childNodes)}),this}}),r.expr.pseudos.hidden=function(a){return!r.expr.pseudos.visible(a)},r.expr.pseudos.visible=function(a){return!!(a.offsetWidth||a.offsetHeight||a.getClientRects().length)},r.ajaxSettings.xhr=function(){try{return new a.XMLHttpRequest}catch(b){}};var Rb={0:200,1223:204},Sb=r.ajaxSettings.xhr();o.cors=!!Sb&&"withCredentials"in Sb,o.ajax=Sb=!!Sb,r.ajaxTransport(function(b){var c,d;if(o.cors||Sb&&!b.crossDomain)return{send:function(e,f){var g,h=b.xhr();if(h.open(b.type,b.url,b.async,b.username,b.password),b.xhrFields)for(g in b.xhrFields)h[g]=b.xhrFields[g];b.mimeType&&h.overrideMimeType&&h.overrideMimeType(b.mimeType),b.crossDomain||e["X-Requested-With"]||(e["X-Requested-With"]="XMLHttpRequest");for(g in e)h.setRequestHeader(g,e[g]);c=function(a){return function(){c&&(c=d=h.onload=h.onerror=h.onabort=h.onreadystatechange=null,"abort"===a?h.abort():"error"===a?"number"!=typeof h.status?f(0,"error"):f(h.status,h.statusText):f(Rb[h.status]||h.status,h.statusText,"text"!==(h.responseType||"text")||"string"!=typeof h.responseText?{binary:h.response}:{text:h.responseText},h.getAllResponseHeaders()))}},h.onload=c(),d=h.onerror=c("error"),void 0!==h.onabort?h.onabort=d:h.onreadystatechange=function(){4===h.readyState&&a.setTimeout(function(){c&&d()})},c=c("abort");try{h.send(b.hasContent&&b.data||null)}catch(i){if(c)throw i}},abort:function(){c&&c()}}}),r.ajaxPrefilter(function(a){a.crossDomain&&(a.contents.script=!1)}),r.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(a){return r.globalEval(a),a}}}),r.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET")}),r.ajaxTransport("script",function(a){if(a.crossDomain){var b,c;return{send:function(e,f){b=r("